]> granicus.if.org Git - postgresql/blob - src/backend/utils/cache/lsyscache.c
573c21afd8d24e3882c997b3792a153ab6e2e51d
[postgresql] / src / backend / utils / cache / lsyscache.c
1 /*-------------------------------------------------------------------------
2  *
3  * lsyscache.c
4  *        Convenience routines for common queries in the system catalog cache.
5  *
6  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  * IDENTIFICATION
10  *        $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.55 2001/05/09 23:13:35 tgl Exp $
11  *
12  * NOTES
13  *        Eventually, the index information should go through here, too.
14  *-------------------------------------------------------------------------
15  */
16 #include "postgres.h"
17
18 #include "access/tupmacs.h"
19 #include "catalog/pg_operator.h"
20 #include "catalog/pg_proc.h"
21 #include "catalog/pg_statistic.h"
22 #include "catalog/pg_type.h"
23 #include "utils/array.h"
24 #include "utils/builtins.h"
25 #include "utils/lsyscache.h"
26 #include "utils/syscache.h"
27
28 /*                              ---------- AMOP CACHES ----------                                                */
29
30 /*
31  * op_class
32  *
33  *              Return t iff operator 'opno' is in operator class 'opclass' for
34  *              access method 'amopid'.
35  */
36 bool
37 op_class(Oid opno, Oid opclass, Oid amopid)
38 {
39         return SearchSysCacheExists(AMOPOPID,
40                                                                 ObjectIdGetDatum(opclass),
41                                                                 ObjectIdGetDatum(opno),
42                                                                 ObjectIdGetDatum(amopid),
43                                                                 0);
44 }
45
46 /*                              ---------- ATTRIBUTE CACHES ----------                                   */
47
48 /*
49  * get_attname
50  *
51  *              Given the relation id and the attribute number,
52  *              return the "attname" field from the attribute relation.
53  *
54  * Note: returns a palloc'd copy of the string, or NULL if no such operator.
55  */
56 char *
57 get_attname(Oid relid, AttrNumber attnum)
58 {
59         HeapTuple       tp;
60
61         tp = SearchSysCache(ATTNUM,
62                                                 ObjectIdGetDatum(relid),
63                                                 Int16GetDatum(attnum),
64                                                 0, 0);
65         if (HeapTupleIsValid(tp))
66         {
67                 Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
68                 char       *result;
69
70                 result = pstrdup(NameStr(att_tup->attname));
71                 ReleaseSysCache(tp);
72                 return result;
73         }
74         else
75                 return NULL;
76 }
77
78 /*
79  * get_attnum
80  *
81  *              Given the relation id and the attribute name,
82  *              return the "attnum" field from the attribute relation.
83  */
84 AttrNumber
85 get_attnum(Oid relid, char *attname)
86 {
87         HeapTuple       tp;
88
89         tp = SearchSysCache(ATTNAME,
90                                                 ObjectIdGetDatum(relid),
91                                                 PointerGetDatum(attname),
92                                                 0, 0);
93         if (HeapTupleIsValid(tp))
94         {
95                 Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
96                 AttrNumber      result;
97
98                 result = att_tup->attnum;
99                 ReleaseSysCache(tp);
100                 return result;
101         }
102         else
103                 return InvalidAttrNumber;
104 }
105
106 /*
107  * get_atttype
108  *
109  *              Given the relation OID and the attribute number with the relation,
110  *              return the attribute type OID.
111  */
112 Oid
113 get_atttype(Oid relid, AttrNumber attnum)
114 {
115         HeapTuple       tp;
116
117         tp = SearchSysCache(ATTNUM,
118                                                 ObjectIdGetDatum(relid),
119                                                 Int16GetDatum(attnum),
120                                                 0, 0);
121         if (HeapTupleIsValid(tp))
122         {
123                 Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
124                 Oid                     result;
125
126                 result = att_tup->atttypid;
127                 ReleaseSysCache(tp);
128                 return result;
129         }
130         else
131                 return InvalidOid;
132 }
133
134 /* This routine uses the attname instead of the attnum because it
135  * replaces the routine find_atttype, which is called sometimes when
136  * only the attname, not the attno, is available.
137  */
138 bool
139 get_attisset(Oid relid, char *attname)
140 {
141         HeapTuple       tp;
142
143         tp = SearchSysCache(ATTNAME,
144                                                 ObjectIdGetDatum(relid),
145                                                 PointerGetDatum(attname),
146                                                 0, 0);
147         if (HeapTupleIsValid(tp))
148         {
149                 Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
150                 bool            result;
151
152                 result = att_tup->attisset;
153                 ReleaseSysCache(tp);
154                 return result;
155         }
156         else
157                 return false;
158 }
159
160 /*
161  * get_atttypmod
162  *
163  *              Given the relation id and the attribute number,
164  *              return the "atttypmod" field from the attribute relation.
165  */
166 int32
167 get_atttypmod(Oid relid, AttrNumber attnum)
168 {
169         HeapTuple       tp;
170
171         tp = SearchSysCache(ATTNUM,
172                                                 ObjectIdGetDatum(relid),
173                                                 Int16GetDatum(attnum),
174                                                 0, 0);
175         if (HeapTupleIsValid(tp))
176         {
177                 Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
178                 int32           result;
179
180                 result = att_tup->atttypmod;
181                 ReleaseSysCache(tp);
182                 return result;
183         }
184         else
185                 return -1;
186 }
187
188 /*
189  * get_atttypetypmod
190  *
191  *              A two-fer: given the relation id and the attribute number,
192  *              fetch both type OID and atttypmod in a single cache lookup.
193  *
194  * Unlike the otherwise-similar get_atttype/get_atttypmod, this routine
195  * raises an error if it can't obtain the information.
196  */
197 void
198 get_atttypetypmod(Oid relid, AttrNumber attnum,
199                                   Oid *typid, int32 *typmod)
200 {
201         HeapTuple       tp;
202         Form_pg_attribute att_tup;
203
204         tp = SearchSysCache(ATTNUM,
205                                                 ObjectIdGetDatum(relid),
206                                                 Int16GetDatum(attnum),
207                                                 0, 0);
208         if (!HeapTupleIsValid(tp))
209                 elog(ERROR, "cache lookup failed for relation %u attribute %d",
210                          relid, attnum);
211         att_tup = (Form_pg_attribute) GETSTRUCT(tp);
212
213         *typid = att_tup->atttypid;
214         *typmod = att_tup->atttypmod;
215         ReleaseSysCache(tp);
216 }
217
218 /*                              ---------- INDEX CACHE ----------                                                */
219
220 /*              watch this space...
221  */
222
223 /*                              ---------- OPERATOR CACHE ----------                                     */
224
225 /*
226  * get_opcode
227  *
228  *              Returns the regproc id of the routine used to implement an
229  *              operator given the operator oid.
230  */
231 RegProcedure
232 get_opcode(Oid opno)
233 {
234         HeapTuple       tp;
235
236         tp = SearchSysCache(OPEROID,
237                                                 ObjectIdGetDatum(opno),
238                                                 0, 0, 0);
239         if (HeapTupleIsValid(tp))
240         {
241                 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
242                 RegProcedure result;
243
244                 result = optup->oprcode;
245                 ReleaseSysCache(tp);
246                 return result;
247         }
248         else
249                 return (RegProcedure) InvalidOid;
250 }
251
252 /*
253  * get_opname
254  *        returns the name of the operator with the given opno
255  *
256  * Note: returns a palloc'd copy of the string, or NULL if no such operator.
257  */
258 char *
259 get_opname(Oid opno)
260 {
261         HeapTuple       tp;
262
263         tp = SearchSysCache(OPEROID,
264                                                 ObjectIdGetDatum(opno),
265                                                 0, 0, 0);
266         if (HeapTupleIsValid(tp))
267         {
268                 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
269                 char       *result;
270
271                 result = pstrdup(NameStr(optup->oprname));
272                 ReleaseSysCache(tp);
273                 return result;
274         }
275         else
276                 return NULL;
277 }
278
279 /*
280  * op_mergejoinable
281  *
282  *              Returns the left and right sort operators and types corresponding to a
283  *              mergejoinable operator, or nil if the operator is not mergejoinable.
284  */
285 bool
286 op_mergejoinable(Oid opno, Oid ltype, Oid rtype, Oid *leftOp, Oid *rightOp)
287 {
288         HeapTuple       tp;
289         bool            result = false;
290
291         tp = SearchSysCache(OPEROID,
292                                                 ObjectIdGetDatum(opno),
293                                                 0, 0, 0);
294         if (HeapTupleIsValid(tp))
295         {
296                 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
297
298                 if (optup->oprlsortop &&
299                         optup->oprrsortop &&
300                         optup->oprleft == ltype &&
301                         optup->oprright == rtype)
302                 {
303                         *leftOp = optup->oprlsortop;
304                         *rightOp = optup->oprrsortop;
305                         result = true;
306                 }
307                 ReleaseSysCache(tp);
308         }
309         return result;
310 }
311
312 /*
313  * op_hashjoinable
314  *
315  * Returns the hash operator corresponding to a hashjoinable operator,
316  * or InvalidOid if the operator is not hashjoinable.
317  */
318 Oid
319 op_hashjoinable(Oid opno, Oid ltype, Oid rtype)
320 {
321         HeapTuple       tp;
322         Oid                     result = InvalidOid;
323
324         tp = SearchSysCache(OPEROID,
325                                                 ObjectIdGetDatum(opno),
326                                                 0, 0, 0);
327         if (HeapTupleIsValid(tp))
328         {
329                 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
330
331                 if (optup->oprcanhash &&
332                         optup->oprleft == ltype &&
333                         optup->oprright == rtype)
334                         result = opno;
335                 ReleaseSysCache(tp);
336         }
337         return result;
338 }
339
340 /*
341  * op_iscachable
342  *
343  * Get the proiscachable flag for the operator's underlying function.
344  */
345 bool
346 op_iscachable(Oid opno)
347 {
348         RegProcedure funcid = get_opcode(opno);
349
350         if (funcid == (RegProcedure) InvalidOid)
351                 elog(ERROR, "Operator OID %u does not exist", opno);
352
353         return func_iscachable((Oid) funcid);
354 }
355
356 /*
357  * get_commutator
358  *
359  *              Returns the corresponding commutator of an operator.
360  */
361 Oid
362 get_commutator(Oid opno)
363 {
364         HeapTuple       tp;
365
366         tp = SearchSysCache(OPEROID,
367                                                 ObjectIdGetDatum(opno),
368                                                 0, 0, 0);
369         if (HeapTupleIsValid(tp))
370         {
371                 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
372                 Oid                     result;
373
374                 result = optup->oprcom;
375                 ReleaseSysCache(tp);
376                 return result;
377         }
378         else
379                 return InvalidOid;
380 }
381
382 /*
383  * get_negator
384  *
385  *              Returns the corresponding negator of an operator.
386  */
387 Oid
388 get_negator(Oid opno)
389 {
390         HeapTuple       tp;
391
392         tp = SearchSysCache(OPEROID,
393                                                 ObjectIdGetDatum(opno),
394                                                 0, 0, 0);
395         if (HeapTupleIsValid(tp))
396         {
397                 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
398                 Oid                     result;
399
400                 result = optup->oprnegate;
401                 ReleaseSysCache(tp);
402                 return result;
403         }
404         else
405                 return InvalidOid;
406 }
407
408 /*
409  * get_oprrest
410  *
411  *              Returns procedure id for computing selectivity of an operator.
412  */
413 RegProcedure
414 get_oprrest(Oid opno)
415 {
416         HeapTuple       tp;
417
418         tp = SearchSysCache(OPEROID,
419                                                 ObjectIdGetDatum(opno),
420                                                 0, 0, 0);
421         if (HeapTupleIsValid(tp))
422         {
423                 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
424                 RegProcedure result;
425
426                 result = optup->oprrest;
427                 ReleaseSysCache(tp);
428                 return result;
429         }
430         else
431                 return (RegProcedure) InvalidOid;
432 }
433
434 /*
435  * get_oprjoin
436  *
437  *              Returns procedure id for computing selectivity of a join.
438  */
439 RegProcedure
440 get_oprjoin(Oid opno)
441 {
442         HeapTuple       tp;
443
444         tp = SearchSysCache(OPEROID,
445                                                 ObjectIdGetDatum(opno),
446                                                 0, 0, 0);
447         if (HeapTupleIsValid(tp))
448         {
449                 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
450                 RegProcedure result;
451
452                 result = optup->oprjoin;
453                 ReleaseSysCache(tp);
454                 return result;
455         }
456         else
457                 return (RegProcedure) InvalidOid;
458 }
459
460 /*                              ---------- FUNCTION CACHE ----------                                     */
461
462 /*
463  * get_func_rettype
464  *              Given procedure id, return the function's result type.
465  */
466 Oid
467 get_func_rettype(Oid funcid)
468 {
469         HeapTuple       tp;
470         Oid                     result;
471
472         tp = SearchSysCache(PROCOID,
473                                                 ObjectIdGetDatum(funcid),
474                                                 0, 0, 0);
475         if (!HeapTupleIsValid(tp))
476                 elog(ERROR, "Function OID %u does not exist", funcid);
477
478         result = ((Form_pg_proc) GETSTRUCT(tp))->prorettype;
479         ReleaseSysCache(tp);
480         return result;
481 }
482
483 /*
484  * func_iscachable
485  *              Given procedure id, return the function's proiscachable flag.
486  */
487 bool
488 func_iscachable(Oid funcid)
489 {
490         HeapTuple       tp;
491         bool            result;
492
493         tp = SearchSysCache(PROCOID,
494                                                 ObjectIdGetDatum(funcid),
495                                                 0, 0, 0);
496         if (!HeapTupleIsValid(tp))
497                 elog(ERROR, "Function OID %u does not exist", funcid);
498
499         result = ((Form_pg_proc) GETSTRUCT(tp))->proiscachable;
500         ReleaseSysCache(tp);
501         return result;
502 }
503
504 /*                              ---------- RELATION CACHE ----------                                     */
505
506 #ifdef NOT_USED
507 /*
508  * get_relnatts
509  *
510  *              Returns the number of attributes for a given relation.
511  */
512 int
513 get_relnatts(Oid relid)
514 {
515         HeapTuple       tp;
516
517         tp = SearchSysCache(RELOID,
518                                                 ObjectIdGetDatum(relid),
519                                                 0, 0, 0);
520         if (HeapTupleIsValid(tp))
521         {
522                 Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
523                 int                     result;
524
525                 result = reltup->relnatts;
526                 ReleaseSysCache(tp);
527                 return result;
528         }
529         else
530                 return InvalidAttrNumber;
531 }
532
533 #endif
534
535 /*
536  * get_rel_name
537  *
538  *              Returns the name of a given relation.
539  *
540  * Note: returns a palloc'd copy of the string, or NULL if no such operator.
541  */
542 char *
543 get_rel_name(Oid relid)
544 {
545         HeapTuple       tp;
546
547         tp = SearchSysCache(RELOID,
548                                                 ObjectIdGetDatum(relid),
549                                                 0, 0, 0);
550         if (HeapTupleIsValid(tp))
551         {
552                 Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
553                 char       *result;
554
555                 result = pstrdup(NameStr(reltup->relname));
556                 ReleaseSysCache(tp);
557                 return result;
558         }
559         else
560                 return NULL;
561 }
562
563 /*                              ---------- TYPE CACHE ----------                                                 */
564
565 /*
566  * get_typlen
567  *
568  *              Given the type OID, return the length of the type.
569  */
570 int16
571 get_typlen(Oid typid)
572 {
573         HeapTuple       tp;
574
575         tp = SearchSysCache(TYPEOID,
576                                                 ObjectIdGetDatum(typid),
577                                                 0, 0, 0);
578         if (HeapTupleIsValid(tp))
579         {
580                 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
581                 int16           result;
582
583                 result = typtup->typlen;
584                 ReleaseSysCache(tp);
585                 return result;
586         }
587         else
588                 return 0;
589 }
590
591 /*
592  * get_typbyval
593  *
594  *              Given the type OID, determine whether the type is returned by value or
595  *              not.  Returns true if by value, false if by reference.
596  */
597 bool
598 get_typbyval(Oid typid)
599 {
600         HeapTuple       tp;
601
602         tp = SearchSysCache(TYPEOID,
603                                                 ObjectIdGetDatum(typid),
604                                                 0, 0, 0);
605         if (HeapTupleIsValid(tp))
606         {
607                 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
608                 bool            result;
609
610                 result = typtup->typbyval;
611                 ReleaseSysCache(tp);
612                 return result;
613         }
614         else
615                 return false;
616 }
617
618 /*
619  * get_typlenbyval
620  *
621  *              A two-fer: given the type OID, return both typlen and typbyval.
622  *
623  *              Since both pieces of info are needed to know how to copy a Datum,
624  *              many places need both.  Might as well get them with one cache lookup
625  *              instead of two.  Also, this routine raises an error instead of
626  *              returning a bogus value when given a bad type OID.
627  */
628 void
629 get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
630 {
631         HeapTuple       tp;
632         Form_pg_type typtup;
633
634         tp = SearchSysCache(TYPEOID,
635                                                 ObjectIdGetDatum(typid),
636                                                 0, 0, 0);
637         if (!HeapTupleIsValid(tp))
638                 elog(ERROR, "cache lookup failed for type %u", typid);
639         typtup = (Form_pg_type) GETSTRUCT(tp);
640         *typlen = typtup->typlen;
641         *typbyval = typtup->typbyval;
642         ReleaseSysCache(tp);
643 }
644
645 #ifdef NOT_USED
646 char
647 get_typalign(Oid typid)
648 {
649         HeapTuple       tp;
650
651         tp = SearchSysCache(TYPEOID,
652                                                 ObjectIdGetDatum(typid),
653                                                 0, 0, 0);
654         if (HeapTupleIsValid(tp))
655         {
656                 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
657                 char            result;
658
659                 result = typtup->typalign;
660                 ReleaseSysCache(tp);
661                 return result;
662         }
663         else
664                 return 'i';
665 }
666
667 #endif
668
669 char
670 get_typstorage(Oid typid)
671 {
672         HeapTuple       tp;
673
674         tp = SearchSysCache(TYPEOID,
675                                                 ObjectIdGetDatum(typid),
676                                                 0, 0, 0);
677         if (HeapTupleIsValid(tp))
678         {
679                 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
680                 char            result;
681
682                 result = typtup->typstorage;
683                 ReleaseSysCache(tp);
684                 return result;
685         }
686         else
687                 return 'p';
688 }
689
690 /*
691  * get_typdefault
692  *
693  *        Given a type OID, return the typdefault field associated with that
694  *        type, or Datum(NULL) if there is no typdefault.  (This implies
695  *        that pass-by-value types can't have a default value that has
696  *        a representation of zero.  Not worth fixing now.)
697  *        The result points to palloc'd storage for non-pass-by-value types.
698  */
699 Datum
700 get_typdefault(Oid typid)
701 {
702         HeapTuple       typeTuple;
703         Form_pg_type type;
704         struct varlena *typDefault;
705         bool            isNull;
706         int32           dataSize;
707         int32           typLen;
708         bool            typByVal;
709         Datum           returnValue;
710
711         typeTuple = SearchSysCache(TYPEOID,
712                                                            ObjectIdGetDatum(typid),
713                                                            0, 0, 0);
714
715         if (!HeapTupleIsValid(typeTuple))
716                 elog(ERROR, "get_typdefault: failed to lookup type %u", typid);
717
718         type = (Form_pg_type) GETSTRUCT(typeTuple);
719
720         /*
721          * First, see if there is a non-null typdefault field (usually there
722          * isn't)
723          */
724         typDefault = (struct varlena *)
725                 DatumGetPointer(SysCacheGetAttr(TYPEOID,
726                                                                                 typeTuple,
727                                                                                 Anum_pg_type_typdefault,
728                                                                                 &isNull));
729
730         if (isNull)
731         {
732                 ReleaseSysCache(typeTuple);
733                 return PointerGetDatum(NULL);
734         }
735
736         /*
737          * Otherwise, extract/copy the value.
738          */
739         dataSize = VARSIZE(typDefault) - VARHDRSZ;
740         typLen = type->typlen;
741         typByVal = type->typbyval;
742
743         if (typByVal)
744         {
745                 if (dataSize == typLen)
746                         returnValue = fetch_att(VARDATA(typDefault), typByVal, typLen);
747                 else
748                         returnValue = PointerGetDatum(NULL);
749         }
750         else if (typLen < 0)
751         {
752                 /* variable-size type */
753                 if (dataSize < 0)
754                         returnValue = PointerGetDatum(NULL);
755                 else
756                 {
757                         returnValue = PointerGetDatum(palloc(VARSIZE(typDefault)));
758                         memcpy((char *) DatumGetPointer(returnValue),
759                                    (char *) typDefault,
760                                    (int) VARSIZE(typDefault));
761                 }
762         }
763         else
764         {
765                 /* fixed-size pass-by-ref type */
766                 if (dataSize != typLen)
767                         returnValue = PointerGetDatum(NULL);
768                 else
769                 {
770                         returnValue = PointerGetDatum(palloc(dataSize));
771                         memcpy((char *) DatumGetPointer(returnValue),
772                                    VARDATA(typDefault),
773                                    (int) dataSize);
774                 }
775         }
776
777         ReleaseSysCache(typeTuple);
778
779         return returnValue;
780 }
781
782 /*
783  * get_typavgwidth
784  *
785  *        Given a type OID and a typmod value (pass -1 if typmod is unknown),
786  *        estimate the average width of values of the type.  This is used by
787  *        the planner, which doesn't require absolutely correct results;
788  *        it's OK (and expected) to guess if we don't know for sure.
789  */
790 int32
791 get_typavgwidth(Oid typid, int32 typmod)
792 {
793         int                     typlen = get_typlen(typid);
794         int32           maxwidth;
795
796         /*
797          * Easy if it's a fixed-width type
798          */
799         if (typlen > 0)
800                 return typlen;
801         /*
802          * type_maximum_size knows the encoding of typmod for some datatypes;
803          * don't duplicate that knowledge here.
804          */
805         maxwidth = type_maximum_size(typid, typmod);
806         if (maxwidth > 0)
807         {
808                 /*
809                  * For BPCHAR, the max width is also the only width.  Otherwise
810                  * we need to guess about the typical data width given the max.
811                  * A sliding scale for percentage of max width seems reasonable.
812                  */
813                 if (typid == BPCHAROID)
814                         return maxwidth;
815                 if (maxwidth <= 32)
816                         return maxwidth;        /* assume full width */
817                 if (maxwidth < 1000)
818                         return 32 + (maxwidth - 32) / 2; /* assume 50% */
819                 /*
820                  * Beyond 1000, assume we're looking at something like
821                  * "varchar(10000)" where the limit isn't actually reached often,
822                  * and use a fixed estimate.
823                  */
824                 return 32 + (1000 - 32) / 2;
825         }
826         /*
827          * Ooops, we have no idea ... wild guess time.
828          */
829         return 32;
830 }
831
832 /*
833  * get_typtype
834  *
835  *              Given the type OID, find if it is a basic type, a named relation
836  *              or the generic type 'relation'.
837  *              It returns the null char if the cache lookup fails...
838  */
839 #ifdef NOT_USED
840 char
841 get_typtype(Oid typid)
842 {
843         HeapTuple       tp;
844
845         tp = SearchSysCache(TYPEOID,
846                                                 ObjectIdGetDatum(typid),
847                                                 0, 0, 0);
848         if (HeapTupleIsValid(tp))
849         {
850                 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
851                 char            result;
852
853                 result = typtup->typtype;
854                 ReleaseSysCache(tp);
855                 return result;
856         }
857         else
858                 return '\0';
859 }
860
861 #endif
862
863 /*                              ---------- STATISTICS CACHE ----------                                   */
864
865 /*
866  * get_attavgwidth
867  *
868  *        Given the table and attribute number of a column, get the average
869  *        width of entries in the column.  Return zero if no data available.
870  */
871 int32
872 get_attavgwidth(Oid relid, AttrNumber attnum)
873 {
874         HeapTuple       tp;
875
876         tp = SearchSysCache(STATRELATT,
877                                                 ObjectIdGetDatum(relid),
878                                                 Int16GetDatum(attnum),
879                                                 0, 0);
880         if (HeapTupleIsValid(tp))
881         {
882                 int32   stawidth = ((Form_pg_statistic) GETSTRUCT(tp))->stawidth;
883
884                 ReleaseSysCache(tp);
885                 if (stawidth > 0)
886                         return stawidth;
887         }
888         return 0;
889 }
890
891 /*
892  * get_attstatsslot
893  *
894  *              Extract the contents of a "slot" of a pg_statistic tuple.
895  *              Returns TRUE if requested slot type was found, else FALSE.
896  *
897  * Unlike other routines in this file, this takes a pointer to an
898  * already-looked-up tuple in the pg_statistic cache.  We do this since
899  * most callers will want to extract more than one value from the cache
900  * entry, and we don't want to repeat the cache lookup unnecessarily.
901  *
902  * statstuple: pg_statistics tuple to be examined.
903  * atttype: type OID of attribute.
904  * atttypmod: typmod of attribute.
905  * reqkind: STAKIND code for desired statistics slot kind.
906  * reqop: STAOP value wanted, or InvalidOid if don't care.
907  * values, nvalues: if not NULL, the slot's stavalues are extracted.
908  * numbers, nnumbers: if not NULL, the slot's stanumbers are extracted.
909  *
910  * If assigned, values and numbers are set to point to palloc'd arrays.
911  * If the attribute type is pass-by-reference, the values referenced by
912  * the values array are themselves palloc'd.  The palloc'd stuff can be
913  * freed by calling free_attstatsslot.
914  */
915 bool
916 get_attstatsslot(HeapTuple statstuple,
917                                  Oid atttype, int32 atttypmod,
918                                  int reqkind, Oid reqop,
919                                  Datum **values, int *nvalues,
920                                  float4 **numbers, int *nnumbers)
921 {
922         Form_pg_statistic stats = (Form_pg_statistic) GETSTRUCT(statstuple);
923         int                     i,
924                                 j;
925         Datum           val;
926         bool            isnull;
927         ArrayType  *statarray;
928         int                     narrayelem;
929         HeapTuple       typeTuple;
930         FmgrInfo        inputproc;
931         Oid                     typelem;
932
933         for (i = 0; i < STATISTIC_NUM_SLOTS; i++)
934         {
935                 if ((&stats->stakind1)[i] == reqkind &&
936                         (reqop == InvalidOid || (&stats->staop1)[i] == reqop))
937                         break;
938         }
939         if (i >= STATISTIC_NUM_SLOTS)
940                 return false;                   /* not there */
941
942         if (values)
943         {
944                 val = SysCacheGetAttr(STATRELATT, statstuple,
945                                                           Anum_pg_statistic_stavalues1 + i,
946                                                           &isnull);
947                 if (isnull)
948                         elog(ERROR, "get_attstatsslot: stavalues is null");
949                 statarray = DatumGetArrayTypeP(val);
950                 /*
951                  * Do initial examination of the array.  This produces a list
952                  * of text Datums --- ie, pointers into the text array value.
953                  */
954                 deconstruct_array(statarray, false, -1, 'i', values, nvalues);
955                 narrayelem = *nvalues;
956                 /*
957                  * We now need to replace each text Datum by its internal equivalent.
958                  *
959                  * Get the type input proc and typelem for the column datatype.
960                  */
961                 typeTuple = SearchSysCache(TYPEOID,
962                                                                    ObjectIdGetDatum(atttype),
963                                                                    0, 0, 0);
964                 if (!HeapTupleIsValid(typeTuple))
965                         elog(ERROR, "get_attstatsslot: Cache lookup failed for type %u",
966                                  atttype);
967                 fmgr_info(((Form_pg_type) GETSTRUCT(typeTuple))->typinput, &inputproc);
968                 typelem = ((Form_pg_type) GETSTRUCT(typeTuple))->typelem;
969                 ReleaseSysCache(typeTuple);
970                 /*
971                  * Do the conversions.  The palloc'd array of Datums is reused
972                  * in place.
973                  */
974                 for (j = 0; j < narrayelem; j++)
975                 {
976                         char       *strval;
977
978                         strval = DatumGetCString(DirectFunctionCall1(textout,
979                                                                                                                  (*values)[j]));
980                         (*values)[j] = FunctionCall3(&inputproc,
981                                                                                  CStringGetDatum(strval),
982                                                                                  ObjectIdGetDatum(typelem),
983                                                                                  Int32GetDatum(atttypmod));
984                         pfree(strval);
985                 }
986                 /*
987                  * Free statarray if it's a detoasted copy.
988                  */
989                 if ((Pointer) statarray != DatumGetPointer(val))
990                         pfree(statarray);
991         }
992
993         if (numbers)
994         {
995                 val = SysCacheGetAttr(STATRELATT, statstuple,
996                                                           Anum_pg_statistic_stanumbers1 + i,
997                                                           &isnull);
998                 if (isnull)
999                         elog(ERROR, "get_attstatsslot: stanumbers is null");
1000                 statarray = DatumGetArrayTypeP(val);
1001                 /*
1002                  * We expect the array to be a 1-D float4 array; verify that.
1003                  * We don't need to use deconstruct_array() since the array
1004                  * data is just going to look like a C array of float4 values.
1005                  */
1006                 narrayelem = ARR_DIMS(statarray)[0];
1007                 if (ARR_NDIM(statarray) != 1 || narrayelem <= 0 ||
1008                         ARR_SIZE(statarray) != (ARR_OVERHEAD(1) + narrayelem * sizeof(float4)))
1009                         elog(ERROR, "get_attstatsslot: stanumbers is bogus");
1010                 *numbers = (float4 *) palloc(narrayelem * sizeof(float4));
1011                 memcpy(*numbers, ARR_DATA_PTR(statarray), narrayelem * sizeof(float4));
1012                 *nnumbers = narrayelem;
1013                 /*
1014                  * Free statarray if it's a detoasted copy.
1015                  */
1016                 if ((Pointer) statarray != DatumGetPointer(val))
1017                         pfree(statarray);
1018         }
1019
1020         return true;
1021 }
1022
1023 void
1024 free_attstatsslot(Oid atttype,
1025                                   Datum *values, int nvalues,
1026                                   float4 *numbers, int nnumbers)
1027 {
1028         if (values)
1029         {
1030                 if (! get_typbyval(atttype))
1031                 {
1032                         int             i;
1033
1034                         for (i = 0; i < nvalues; i++)
1035                                 pfree(DatumGetPointer(values[i]));
1036                 }
1037                 pfree(values);
1038         }
1039         if (numbers)
1040                 pfree(numbers);
1041 }