1 /*-------------------------------------------------------------------------
4 * Convenience routines for common queries in the system catalog cache.
6 * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
10 * $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.55 2001/05/09 23:13:35 tgl Exp $
13 * Eventually, the index information should go through here, too.
14 *-------------------------------------------------------------------------
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"
28 /* ---------- AMOP CACHES ---------- */
33 * Return t iff operator 'opno' is in operator class 'opclass' for
34 * access method 'amopid'.
37 op_class(Oid opno, Oid opclass, Oid amopid)
39 return SearchSysCacheExists(AMOPOPID,
40 ObjectIdGetDatum(opclass),
41 ObjectIdGetDatum(opno),
42 ObjectIdGetDatum(amopid),
46 /* ---------- ATTRIBUTE CACHES ---------- */
51 * Given the relation id and the attribute number,
52 * return the "attname" field from the attribute relation.
54 * Note: returns a palloc'd copy of the string, or NULL if no such operator.
57 get_attname(Oid relid, AttrNumber attnum)
61 tp = SearchSysCache(ATTNUM,
62 ObjectIdGetDatum(relid),
63 Int16GetDatum(attnum),
65 if (HeapTupleIsValid(tp))
67 Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
70 result = pstrdup(NameStr(att_tup->attname));
81 * Given the relation id and the attribute name,
82 * return the "attnum" field from the attribute relation.
85 get_attnum(Oid relid, char *attname)
89 tp = SearchSysCache(ATTNAME,
90 ObjectIdGetDatum(relid),
91 PointerGetDatum(attname),
93 if (HeapTupleIsValid(tp))
95 Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
98 result = att_tup->attnum;
103 return InvalidAttrNumber;
109 * Given the relation OID and the attribute number with the relation,
110 * return the attribute type OID.
113 get_atttype(Oid relid, AttrNumber attnum)
117 tp = SearchSysCache(ATTNUM,
118 ObjectIdGetDatum(relid),
119 Int16GetDatum(attnum),
121 if (HeapTupleIsValid(tp))
123 Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
126 result = att_tup->atttypid;
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.
139 get_attisset(Oid relid, char *attname)
143 tp = SearchSysCache(ATTNAME,
144 ObjectIdGetDatum(relid),
145 PointerGetDatum(attname),
147 if (HeapTupleIsValid(tp))
149 Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
152 result = att_tup->attisset;
163 * Given the relation id and the attribute number,
164 * return the "atttypmod" field from the attribute relation.
167 get_atttypmod(Oid relid, AttrNumber attnum)
171 tp = SearchSysCache(ATTNUM,
172 ObjectIdGetDatum(relid),
173 Int16GetDatum(attnum),
175 if (HeapTupleIsValid(tp))
177 Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
180 result = att_tup->atttypmod;
191 * A two-fer: given the relation id and the attribute number,
192 * fetch both type OID and atttypmod in a single cache lookup.
194 * Unlike the otherwise-similar get_atttype/get_atttypmod, this routine
195 * raises an error if it can't obtain the information.
198 get_atttypetypmod(Oid relid, AttrNumber attnum,
199 Oid *typid, int32 *typmod)
202 Form_pg_attribute att_tup;
204 tp = SearchSysCache(ATTNUM,
205 ObjectIdGetDatum(relid),
206 Int16GetDatum(attnum),
208 if (!HeapTupleIsValid(tp))
209 elog(ERROR, "cache lookup failed for relation %u attribute %d",
211 att_tup = (Form_pg_attribute) GETSTRUCT(tp);
213 *typid = att_tup->atttypid;
214 *typmod = att_tup->atttypmod;
218 /* ---------- INDEX CACHE ---------- */
220 /* watch this space...
223 /* ---------- OPERATOR CACHE ---------- */
228 * Returns the regproc id of the routine used to implement an
229 * operator given the operator oid.
236 tp = SearchSysCache(OPEROID,
237 ObjectIdGetDatum(opno),
239 if (HeapTupleIsValid(tp))
241 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
244 result = optup->oprcode;
249 return (RegProcedure) InvalidOid;
254 * returns the name of the operator with the given opno
256 * Note: returns a palloc'd copy of the string, or NULL if no such operator.
263 tp = SearchSysCache(OPEROID,
264 ObjectIdGetDatum(opno),
266 if (HeapTupleIsValid(tp))
268 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
271 result = pstrdup(NameStr(optup->oprname));
282 * Returns the left and right sort operators and types corresponding to a
283 * mergejoinable operator, or nil if the operator is not mergejoinable.
286 op_mergejoinable(Oid opno, Oid ltype, Oid rtype, Oid *leftOp, Oid *rightOp)
291 tp = SearchSysCache(OPEROID,
292 ObjectIdGetDatum(opno),
294 if (HeapTupleIsValid(tp))
296 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
298 if (optup->oprlsortop &&
300 optup->oprleft == ltype &&
301 optup->oprright == rtype)
303 *leftOp = optup->oprlsortop;
304 *rightOp = optup->oprrsortop;
315 * Returns the hash operator corresponding to a hashjoinable operator,
316 * or InvalidOid if the operator is not hashjoinable.
319 op_hashjoinable(Oid opno, Oid ltype, Oid rtype)
322 Oid result = InvalidOid;
324 tp = SearchSysCache(OPEROID,
325 ObjectIdGetDatum(opno),
327 if (HeapTupleIsValid(tp))
329 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
331 if (optup->oprcanhash &&
332 optup->oprleft == ltype &&
333 optup->oprright == rtype)
343 * Get the proiscachable flag for the operator's underlying function.
346 op_iscachable(Oid opno)
348 RegProcedure funcid = get_opcode(opno);
350 if (funcid == (RegProcedure) InvalidOid)
351 elog(ERROR, "Operator OID %u does not exist", opno);
353 return func_iscachable((Oid) funcid);
359 * Returns the corresponding commutator of an operator.
362 get_commutator(Oid opno)
366 tp = SearchSysCache(OPEROID,
367 ObjectIdGetDatum(opno),
369 if (HeapTupleIsValid(tp))
371 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
374 result = optup->oprcom;
385 * Returns the corresponding negator of an operator.
388 get_negator(Oid opno)
392 tp = SearchSysCache(OPEROID,
393 ObjectIdGetDatum(opno),
395 if (HeapTupleIsValid(tp))
397 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
400 result = optup->oprnegate;
411 * Returns procedure id for computing selectivity of an operator.
414 get_oprrest(Oid opno)
418 tp = SearchSysCache(OPEROID,
419 ObjectIdGetDatum(opno),
421 if (HeapTupleIsValid(tp))
423 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
426 result = optup->oprrest;
431 return (RegProcedure) InvalidOid;
437 * Returns procedure id for computing selectivity of a join.
440 get_oprjoin(Oid opno)
444 tp = SearchSysCache(OPEROID,
445 ObjectIdGetDatum(opno),
447 if (HeapTupleIsValid(tp))
449 Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
452 result = optup->oprjoin;
457 return (RegProcedure) InvalidOid;
460 /* ---------- FUNCTION CACHE ---------- */
464 * Given procedure id, return the function's result type.
467 get_func_rettype(Oid funcid)
472 tp = SearchSysCache(PROCOID,
473 ObjectIdGetDatum(funcid),
475 if (!HeapTupleIsValid(tp))
476 elog(ERROR, "Function OID %u does not exist", funcid);
478 result = ((Form_pg_proc) GETSTRUCT(tp))->prorettype;
485 * Given procedure id, return the function's proiscachable flag.
488 func_iscachable(Oid funcid)
493 tp = SearchSysCache(PROCOID,
494 ObjectIdGetDatum(funcid),
496 if (!HeapTupleIsValid(tp))
497 elog(ERROR, "Function OID %u does not exist", funcid);
499 result = ((Form_pg_proc) GETSTRUCT(tp))->proiscachable;
504 /* ---------- RELATION CACHE ---------- */
510 * Returns the number of attributes for a given relation.
513 get_relnatts(Oid relid)
517 tp = SearchSysCache(RELOID,
518 ObjectIdGetDatum(relid),
520 if (HeapTupleIsValid(tp))
522 Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
525 result = reltup->relnatts;
530 return InvalidAttrNumber;
538 * Returns the name of a given relation.
540 * Note: returns a palloc'd copy of the string, or NULL if no such operator.
543 get_rel_name(Oid relid)
547 tp = SearchSysCache(RELOID,
548 ObjectIdGetDatum(relid),
550 if (HeapTupleIsValid(tp))
552 Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
555 result = pstrdup(NameStr(reltup->relname));
563 /* ---------- TYPE CACHE ---------- */
568 * Given the type OID, return the length of the type.
571 get_typlen(Oid typid)
575 tp = SearchSysCache(TYPEOID,
576 ObjectIdGetDatum(typid),
578 if (HeapTupleIsValid(tp))
580 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
583 result = typtup->typlen;
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.
598 get_typbyval(Oid typid)
602 tp = SearchSysCache(TYPEOID,
603 ObjectIdGetDatum(typid),
605 if (HeapTupleIsValid(tp))
607 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
610 result = typtup->typbyval;
621 * A two-fer: given the type OID, return both typlen and typbyval.
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.
629 get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
634 tp = SearchSysCache(TYPEOID,
635 ObjectIdGetDatum(typid),
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;
647 get_typalign(Oid typid)
651 tp = SearchSysCache(TYPEOID,
652 ObjectIdGetDatum(typid),
654 if (HeapTupleIsValid(tp))
656 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
659 result = typtup->typalign;
670 get_typstorage(Oid typid)
674 tp = SearchSysCache(TYPEOID,
675 ObjectIdGetDatum(typid),
677 if (HeapTupleIsValid(tp))
679 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
682 result = typtup->typstorage;
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.
700 get_typdefault(Oid typid)
704 struct varlena *typDefault;
711 typeTuple = SearchSysCache(TYPEOID,
712 ObjectIdGetDatum(typid),
715 if (!HeapTupleIsValid(typeTuple))
716 elog(ERROR, "get_typdefault: failed to lookup type %u", typid);
718 type = (Form_pg_type) GETSTRUCT(typeTuple);
721 * First, see if there is a non-null typdefault field (usually there
724 typDefault = (struct varlena *)
725 DatumGetPointer(SysCacheGetAttr(TYPEOID,
727 Anum_pg_type_typdefault,
732 ReleaseSysCache(typeTuple);
733 return PointerGetDatum(NULL);
737 * Otherwise, extract/copy the value.
739 dataSize = VARSIZE(typDefault) - VARHDRSZ;
740 typLen = type->typlen;
741 typByVal = type->typbyval;
745 if (dataSize == typLen)
746 returnValue = fetch_att(VARDATA(typDefault), typByVal, typLen);
748 returnValue = PointerGetDatum(NULL);
752 /* variable-size type */
754 returnValue = PointerGetDatum(NULL);
757 returnValue = PointerGetDatum(palloc(VARSIZE(typDefault)));
758 memcpy((char *) DatumGetPointer(returnValue),
760 (int) VARSIZE(typDefault));
765 /* fixed-size pass-by-ref type */
766 if (dataSize != typLen)
767 returnValue = PointerGetDatum(NULL);
770 returnValue = PointerGetDatum(palloc(dataSize));
771 memcpy((char *) DatumGetPointer(returnValue),
777 ReleaseSysCache(typeTuple);
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.
791 get_typavgwidth(Oid typid, int32 typmod)
793 int typlen = get_typlen(typid);
797 * Easy if it's a fixed-width type
802 * type_maximum_size knows the encoding of typmod for some datatypes;
803 * don't duplicate that knowledge here.
805 maxwidth = type_maximum_size(typid, typmod);
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.
813 if (typid == BPCHAROID)
816 return maxwidth; /* assume full width */
818 return 32 + (maxwidth - 32) / 2; /* assume 50% */
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.
824 return 32 + (1000 - 32) / 2;
827 * Ooops, we have no idea ... wild guess time.
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...
841 get_typtype(Oid typid)
845 tp = SearchSysCache(TYPEOID,
846 ObjectIdGetDatum(typid),
848 if (HeapTupleIsValid(tp))
850 Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
853 result = typtup->typtype;
863 /* ---------- STATISTICS CACHE ---------- */
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.
872 get_attavgwidth(Oid relid, AttrNumber attnum)
876 tp = SearchSysCache(STATRELATT,
877 ObjectIdGetDatum(relid),
878 Int16GetDatum(attnum),
880 if (HeapTupleIsValid(tp))
882 int32 stawidth = ((Form_pg_statistic) GETSTRUCT(tp))->stawidth;
894 * Extract the contents of a "slot" of a pg_statistic tuple.
895 * Returns TRUE if requested slot type was found, else FALSE.
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.
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.
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.
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)
922 Form_pg_statistic stats = (Form_pg_statistic) GETSTRUCT(statstuple);
927 ArrayType *statarray;
933 for (i = 0; i < STATISTIC_NUM_SLOTS; i++)
935 if ((&stats->stakind1)[i] == reqkind &&
936 (reqop == InvalidOid || (&stats->staop1)[i] == reqop))
939 if (i >= STATISTIC_NUM_SLOTS)
940 return false; /* not there */
944 val = SysCacheGetAttr(STATRELATT, statstuple,
945 Anum_pg_statistic_stavalues1 + i,
948 elog(ERROR, "get_attstatsslot: stavalues is null");
949 statarray = DatumGetArrayTypeP(val);
951 * Do initial examination of the array. This produces a list
952 * of text Datums --- ie, pointers into the text array value.
954 deconstruct_array(statarray, false, -1, 'i', values, nvalues);
955 narrayelem = *nvalues;
957 * We now need to replace each text Datum by its internal equivalent.
959 * Get the type input proc and typelem for the column datatype.
961 typeTuple = SearchSysCache(TYPEOID,
962 ObjectIdGetDatum(atttype),
964 if (!HeapTupleIsValid(typeTuple))
965 elog(ERROR, "get_attstatsslot: Cache lookup failed for type %u",
967 fmgr_info(((Form_pg_type) GETSTRUCT(typeTuple))->typinput, &inputproc);
968 typelem = ((Form_pg_type) GETSTRUCT(typeTuple))->typelem;
969 ReleaseSysCache(typeTuple);
971 * Do the conversions. The palloc'd array of Datums is reused
974 for (j = 0; j < narrayelem; j++)
978 strval = DatumGetCString(DirectFunctionCall1(textout,
980 (*values)[j] = FunctionCall3(&inputproc,
981 CStringGetDatum(strval),
982 ObjectIdGetDatum(typelem),
983 Int32GetDatum(atttypmod));
987 * Free statarray if it's a detoasted copy.
989 if ((Pointer) statarray != DatumGetPointer(val))
995 val = SysCacheGetAttr(STATRELATT, statstuple,
996 Anum_pg_statistic_stanumbers1 + i,
999 elog(ERROR, "get_attstatsslot: stanumbers is null");
1000 statarray = DatumGetArrayTypeP(val);
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.
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;
1014 * Free statarray if it's a detoasted copy.
1016 if ((Pointer) statarray != DatumGetPointer(val))
1024 free_attstatsslot(Oid atttype,
1025 Datum *values, int nvalues,
1026 float4 *numbers, int nnumbers)
1030 if (! get_typbyval(atttype))
1034 for (i = 0; i < nvalues; i++)
1035 pfree(DatumGetPointer(values[i]));