OSDN Git Service

pg_type has a typnamespace column; system now supports creating types
[pg-rex/syncrep.git] / src / backend / utils / cache / lsyscache.c
index 573c21a..6ec682f 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.55 2001/05/09 23:13:35 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.67 2002/03/29 19:06:15 tgl Exp $
  *
  * NOTES
  *       Eventually, the index information should go through here, too.
 #include "postgres.h"
 
 #include "access/tupmacs.h"
+#include "catalog/pg_amop.h"
+#include "catalog/pg_opclass.h"
 #include "catalog/pg_operator.h"
 #include "catalog/pg_proc.h"
+#include "catalog/pg_shadow.h"
 #include "catalog/pg_statistic.h"
 #include "catalog/pg_type.h"
+#include "nodes/makefuncs.h"
 #include "utils/array.h"
 #include "utils/builtins.h"
 #include "utils/lsyscache.h"
 #include "utils/syscache.h"
 
+
 /*                             ---------- AMOP CACHES ----------                                                */
 
 /*
- * op_class
+ * op_in_opclass
  *
- *             Return t iff operator 'opno' is in operator class 'opclass' for
- *             access method 'amopid'.
+ *             Return t iff operator 'opno' is in operator class 'opclass'.
  */
 bool
-op_class(Oid opno, Oid opclass, Oid amopid)
+op_in_opclass(Oid opno, Oid opclass)
 {
        return SearchSysCacheExists(AMOPOPID,
                                                                ObjectIdGetDatum(opclass),
                                                                ObjectIdGetDatum(opno),
-                                                               ObjectIdGetDatum(amopid),
-                                                               0);
+                                                               0, 0);
+}
+
+/*
+ * op_requires_recheck
+ *
+ *             Return t if operator 'opno' requires a recheck when used as a
+ *             member of opclass 'opclass' (ie, this opclass is lossy for this
+ *             operator).
+ *
+ * Caller should already have verified that opno is a member of opclass,
+ * therefore we raise an error if the tuple is not found.
+ */
+bool
+op_requires_recheck(Oid opno, Oid opclass)
+{
+       HeapTuple       tp;
+       Form_pg_amop amop_tup;
+       bool            result;
+
+       tp = SearchSysCache(AMOPOPID,
+                                               ObjectIdGetDatum(opclass),
+                                               ObjectIdGetDatum(opno),
+                                               0, 0);
+       if (!HeapTupleIsValid(tp))
+               elog(ERROR, "op_requires_recheck: op %u is not a member of opclass %u",
+                        opno, opclass);
+       amop_tup = (Form_pg_amop) GETSTRUCT(tp);
+
+       result = amop_tup->amopreqcheck;
+       ReleaseSysCache(tp);
+       return result;
 }
 
 /*                             ---------- ATTRIBUTE CACHES ----------                                   */
@@ -220,6 +254,33 @@ get_atttypetypmod(Oid relid, AttrNumber attnum,
 /*             watch this space...
  */
 
+/*                             ---------- OPCLASS CACHE ----------                                              */
+
+/*
+ * opclass_is_btree
+ *
+ *             Returns TRUE iff the specified opclass is associated with the
+ *             btree index access method.
+ */
+bool
+opclass_is_btree(Oid opclass)
+{
+       HeapTuple       tp;
+       Form_pg_opclass cla_tup;
+       bool            result;
+
+       tp = SearchSysCache(CLAOID,
+                                               ObjectIdGetDatum(opclass),
+                                               0, 0, 0);
+       if (!HeapTupleIsValid(tp))
+               elog(ERROR, "cache lookup failed for opclass %u", opclass);
+       cla_tup = (Form_pg_opclass) GETSTRUCT(tp);
+
+       result = (cla_tup->opcamid == BTREE_AM_OID);
+       ReleaseSysCache(tp);
+       return result;
+}
+
 /*                             ---------- OPERATOR CACHE ----------                                     */
 
 /*
@@ -310,6 +371,76 @@ op_mergejoinable(Oid opno, Oid ltype, Oid rtype, Oid *leftOp, Oid *rightOp)
 }
 
 /*
+ * op_mergejoin_crossops
+ *
+ *             Returns the cross-type comparison operators (ltype "<" rtype and
+ *             ltype ">" rtype) for an operator previously determined to be
+ *             mergejoinable.  Optionally, fetches the regproc ids of these
+ *             operators, as well as their operator OIDs.
+ *
+ * Raises error if operators cannot be found.  Assuming that the operator
+ * had indeed been marked mergejoinable, this indicates that whoever marked
+ * it so was mistaken.
+ */
+void
+op_mergejoin_crossops(Oid opno, Oid *ltop, Oid *gtop,
+                                         RegProcedure *ltproc, RegProcedure *gtproc)
+{
+       HeapTuple       tp;
+       Form_pg_operator optup;
+       Oid                     oprleft,
+                               oprright;
+
+       /*
+        * Get the declared left and right operand types of the operator.
+        */
+       tp = SearchSysCache(OPEROID,
+                                               ObjectIdGetDatum(opno),
+                                               0, 0, 0);
+       if (!HeapTupleIsValid(tp))      /* shouldn't happen */
+               elog(ERROR, "op_mergejoin_crossops: operator %u not found", opno);
+       optup = (Form_pg_operator) GETSTRUCT(tp);
+       oprleft = optup->oprleft;
+       oprright = optup->oprright;
+       ReleaseSysCache(tp);
+
+       /*
+        * Look up the "<" operator with the same input types.  If there isn't
+        * one, whoever marked the "=" operator mergejoinable was a loser.
+        */
+       tp = SearchSysCache(OPERNAME,
+                                               PointerGetDatum("<"),
+                                               ObjectIdGetDatum(oprleft),
+                                               ObjectIdGetDatum(oprright),
+                                               CharGetDatum('b'));
+       if (!HeapTupleIsValid(tp))
+               elog(ERROR, "op_mergejoin_crossops: mergejoin operator %u has no matching < operator",
+                        opno);
+       optup = (Form_pg_operator) GETSTRUCT(tp);
+       *ltop = tp->t_data->t_oid;
+       if (ltproc)
+               *ltproc = optup->oprcode;
+       ReleaseSysCache(tp);
+
+       /*
+        * And the same for the ">" operator.
+        */
+       tp = SearchSysCache(OPERNAME,
+                                               PointerGetDatum(">"),
+                                               ObjectIdGetDatum(oprleft),
+                                               ObjectIdGetDatum(oprright),
+                                               CharGetDatum('b'));
+       if (!HeapTupleIsValid(tp))
+               elog(ERROR, "op_mergejoin_crossops: mergejoin operator %u has no matching > operator",
+                        opno);
+       optup = (Form_pg_operator) GETSTRUCT(tp);
+       *gtop = tp->t_data->t_oid;
+       if (gtproc)
+               *gtproc = optup->oprcode;
+       ReleaseSysCache(tp);
+}
+
+/*
  * op_hashjoinable
  *
  * Returns the hash operator corresponding to a hashjoinable operator,
@@ -503,6 +634,21 @@ func_iscachable(Oid funcid)
 
 /*                             ---------- RELATION CACHE ----------                                     */
 
+/*
+ * get_relname_relid
+ *             Given name and namespace of a relation, look up the OID.
+ *
+ * Returns InvalidOid if there is no such relation.
+ */
+Oid
+get_relname_relid(const char *relname, Oid relnamespace)
+{
+       return GetSysCacheOid(RELNAMENSP,
+                                                 PointerGetDatum(relname),
+                                                 ObjectIdGetDatum(relnamespace),
+                                                 0, 0);
+}
+
 #ifdef NOT_USED
 /*
  * get_relnatts
@@ -529,15 +675,16 @@ get_relnatts(Oid relid)
        else
                return InvalidAttrNumber;
 }
-
 #endif
 
 /*
  * get_rel_name
- *
  *             Returns the name of a given relation.
  *
- * Note: returns a palloc'd copy of the string, or NULL if no such operator.
+ * Returns a palloc'd copy of the string, or NULL if no such relation.
+ *
+ * NOTE: since relation name is not unique, be wary of code that uses this
+ * for anything except preparing error messages.
  */
 char *
 get_rel_name(Oid relid)
@@ -560,9 +707,65 @@ get_rel_name(Oid relid)
                return NULL;
 }
 
+/*
+ * get_rel_type_id
+ *
+ *             Returns the pg_type OID associated with a given relation.
+ *
+ * Note: not all pg_class entries have associated pg_type OIDs; so be
+ * careful to check for InvalidOid result.
+ */
+Oid
+get_rel_type_id(Oid relid)
+{
+       HeapTuple       tp;
+
+       tp = SearchSysCache(RELOID,
+                                               ObjectIdGetDatum(relid),
+                                               0, 0, 0);
+       if (HeapTupleIsValid(tp))
+       {
+               Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
+               Oid             result;
+
+               result = reltup->reltype;
+               ReleaseSysCache(tp);
+               return result;
+       }
+       else
+               return InvalidOid;
+}
+
 /*                             ---------- TYPE CACHE ----------                                                 */
 
 /*
+ * get_typisdefined
+ *
+ *             Given the type OID, determine whether the type is defined
+ *             (if not, it's only a shell).
+ */
+bool
+get_typisdefined(Oid typid)
+{
+       HeapTuple       tp;
+
+       tp = SearchSysCache(TYPEOID,
+                                               ObjectIdGetDatum(typid),
+                                               0, 0, 0);
+       if (HeapTupleIsValid(tp))
+       {
+               Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
+               bool            result;
+
+               result = typtup->typisdefined;
+               ReleaseSysCache(tp);
+               return result;
+       }
+       else
+               return false;
+}
+
+/*
  * get_typlen
  *
  *             Given the type OID, return the length of the type.
@@ -663,7 +866,6 @@ get_typalign(Oid typid)
        else
                return 'i';
 }
-
 #endif
 
 char
@@ -689,94 +891,122 @@ get_typstorage(Oid typid)
 
 /*
  * get_typdefault
+ *       Given a type OID, return the type's default value, if any.
+ *
+ *       The result is a palloc'd expression node tree, or NULL if there
+ *       is no defined default for the datatype.
  *
- *       Given a type OID, return the typdefault field associated with that
- *       type, or Datum(NULL) if there is no typdefault.  (This implies
- *       that pass-by-value types can't have a default value that has
- *       a representation of zero.  Not worth fixing now.)
- *       The result points to palloc'd storage for non-pass-by-value types.
+ * NB: caller should be prepared to coerce result to correct datatype;
+ * the returned expression tree might produce something of the wrong type.
  */
-Datum
+Node *
 get_typdefault(Oid typid)
 {
        HeapTuple       typeTuple;
        Form_pg_type type;
-       struct varlena *typDefault;
+       Datum           datum;
        bool            isNull;
-       int32           dataSize;
-       int32           typLen;
-       bool            typByVal;
-       Datum           returnValue;
+       Node       *expr;
 
        typeTuple = SearchSysCache(TYPEOID,
                                                           ObjectIdGetDatum(typid),
                                                           0, 0, 0);
-
        if (!HeapTupleIsValid(typeTuple))
                elog(ERROR, "get_typdefault: failed to lookup type %u", typid);
-
        type = (Form_pg_type) GETSTRUCT(typeTuple);
 
        /*
-        * First, see if there is a non-null typdefault field (usually there
-        * isn't)
+        * typdefault and typdefaultbin are potentially null, so don't try to
+        * access 'em as struct fields. Must do it the hard way with
+        * SysCacheGetAttr.
         */
-       typDefault = (struct varlena *)
-               DatumGetPointer(SysCacheGetAttr(TYPEOID,
-                                                                               typeTuple,
-                                                                               Anum_pg_type_typdefault,
-                                                                               &isNull));
+       datum = SysCacheGetAttr(TYPEOID,
+                                                       typeTuple,
+                                                       Anum_pg_type_typdefaultbin,
+                                                       &isNull);
 
-       if (isNull)
+       if (!isNull)
        {
-               ReleaseSysCache(typeTuple);
-               return PointerGetDatum(NULL);
-       }
-
-       /*
-        * Otherwise, extract/copy the value.
-        */
-       dataSize = VARSIZE(typDefault) - VARHDRSZ;
-       typLen = type->typlen;
-       typByVal = type->typbyval;
-
-       if (typByVal)
-       {
-               if (dataSize == typLen)
-                       returnValue = fetch_att(VARDATA(typDefault), typByVal, typLen);
-               else
-                       returnValue = PointerGetDatum(NULL);
+               /* We have an expression default */
+               expr = stringToNode(DatumGetCString(DirectFunctionCall1(textout,
+                                                                                                                               datum)));
        }
-       else if (typLen < 0)
+       else
        {
-               /* variable-size type */
-               if (dataSize < 0)
-                       returnValue = PointerGetDatum(NULL);
-               else
+               /* Perhaps we have a plain literal default */
+               datum = SysCacheGetAttr(TYPEOID,
+                                                               typeTuple,
+                                                               Anum_pg_type_typdefault,
+                                                               &isNull);
+
+               if (!isNull)
                {
-                       returnValue = PointerGetDatum(palloc(VARSIZE(typDefault)));
-                       memcpy((char *) DatumGetPointer(returnValue),
-                                  (char *) typDefault,
-                                  (int) VARSIZE(typDefault));
+                       char       *strDefaultVal;
+
+                       /* Convert text datum to C string */
+                       strDefaultVal = DatumGetCString(DirectFunctionCall1(textout,
+                                                                                                                               datum));
+                       /* Convert C string to a value of the given type */
+                       datum = OidFunctionCall3(type->typinput,
+                                                                        CStringGetDatum(strDefaultVal),
+                                                                        ObjectIdGetDatum(type->typelem),
+                                                                        Int32GetDatum(-1));
+                       /* Build a Const node containing the value */
+                       expr = (Node *) makeConst(typid,
+                                                                         type->typlen,
+                                                                         datum,
+                                                                         false,
+                                                                         type->typbyval,
+                                                                         false,        /* not a set */
+                                                                         false);
+                       pfree(strDefaultVal);
                }
-       }
-       else
-       {
-               /* fixed-size pass-by-ref type */
-               if (dataSize != typLen)
-                       returnValue = PointerGetDatum(NULL);
                else
                {
-                       returnValue = PointerGetDatum(palloc(dataSize));
-                       memcpy((char *) DatumGetPointer(returnValue),
-                                  VARDATA(typDefault),
-                                  (int) dataSize);
+                       /* No default */
+                       expr = NULL;
                }
        }
 
        ReleaseSysCache(typeTuple);
 
-       return returnValue;
+       return expr;
+}
+
+/*
+ * getBaseType
+ *             If the given type is a domain, return its base type;
+ *             otherwise return the type's own OID.
+ */
+Oid
+getBaseType(Oid typid)
+{
+       /*
+        * We loop to find the bottom base type in a stack of domains.
+        */
+       for (;;)
+       {
+               HeapTuple       tup;
+               Form_pg_type typTup;
+
+               tup = SearchSysCache(TYPEOID,
+                                                        ObjectIdGetDatum(typid),
+                                                        0, 0, 0);
+               if (!HeapTupleIsValid(tup))
+                       elog(ERROR, "getBaseType: failed to lookup type %u", typid);
+               typTup = (Form_pg_type) GETSTRUCT(tup);
+               if (typTup->typtype != 'd')
+               {
+                       /* Not a domain, so done */
+                       ReleaseSysCache(tup);
+                       break;
+               }
+
+               typid = typTup->typbasetype;
+               ReleaseSysCache(tup);
+       }
+
+       return typid;
 }
 
 /*
@@ -798,6 +1028,7 @@ get_typavgwidth(Oid typid, int32 typmod)
         */
        if (typlen > 0)
                return typlen;
+
        /*
         * type_maximum_size knows the encoding of typmod for some datatypes;
         * don't duplicate that knowledge here.
@@ -806,16 +1037,17 @@ get_typavgwidth(Oid typid, int32 typmod)
        if (maxwidth > 0)
        {
                /*
-                * For BPCHAR, the max width is also the only width.  Otherwise
-                * we need to guess about the typical data width given the max.
-                * sliding scale for percentage of max width seems reasonable.
+                * For BPCHAR, the max width is also the only width.  Otherwise we
+                * need to guess about the typical data width given the max. A
+                * sliding scale for percentage of max width seems reasonable.
                 */
                if (typid == BPCHAROID)
                        return maxwidth;
                if (maxwidth <= 32)
                        return maxwidth;        /* assume full width */
                if (maxwidth < 1000)
-                       return 32 + (maxwidth - 32) / 2; /* assume 50% */
+                       return 32 + (maxwidth - 32) / 2;        /* assume 50% */
+
                /*
                 * Beyond 1000, assume we're looking at something like
                 * "varchar(10000)" where the limit isn't actually reached often,
@@ -823,6 +1055,7 @@ get_typavgwidth(Oid typid, int32 typmod)
                 */
                return 32 + (1000 - 32) / 2;
        }
+
        /*
         * Ooops, we have no idea ... wild guess time.
         */
@@ -857,7 +1090,6 @@ get_typtype(Oid typid)
        else
                return '\0';
 }
-
 #endif
 
 /*                             ---------- STATISTICS CACHE ----------                                   */
@@ -879,7 +1111,7 @@ get_attavgwidth(Oid relid, AttrNumber attnum)
                                                0, 0);
        if (HeapTupleIsValid(tp))
        {
-               int32   stawidth = ((Form_pg_statistic) GETSTRUCT(tp))->stawidth;
+               int32           stawidth = ((Form_pg_statistic) GETSTRUCT(tp))->stawidth;
 
                ReleaseSysCache(tp);
                if (stawidth > 0)
@@ -947,14 +1179,17 @@ get_attstatsslot(HeapTuple statstuple,
                if (isnull)
                        elog(ERROR, "get_attstatsslot: stavalues is null");
                statarray = DatumGetArrayTypeP(val);
+
                /*
-                * Do initial examination of the array.  This produces a list
-                * of text Datums --- ie, pointers into the text array value.
+                * Do initial examination of the array.  This produces a list of
+                * text Datums --- ie, pointers into the text array value.
                 */
                deconstruct_array(statarray, false, -1, 'i', values, nvalues);
                narrayelem = *nvalues;
+
                /*
-                * We now need to replace each text Datum by its internal equivalent.
+                * We now need to replace each text Datum by its internal
+                * equivalent.
                 *
                 * Get the type input proc and typelem for the column datatype.
                 */
@@ -967,9 +1202,10 @@ get_attstatsslot(HeapTuple statstuple,
                fmgr_info(((Form_pg_type) GETSTRUCT(typeTuple))->typinput, &inputproc);
                typelem = ((Form_pg_type) GETSTRUCT(typeTuple))->typelem;
                ReleaseSysCache(typeTuple);
+
                /*
-                * Do the conversions.  The palloc'd array of Datums is reused
-                * in place.
+                * Do the conversions.  The palloc'd array of Datums is reused in
+                * place.
                 */
                for (j = 0; j < narrayelem; j++)
                {
@@ -983,6 +1219,7 @@ get_attstatsslot(HeapTuple statstuple,
                                                                                 Int32GetDatum(atttypmod));
                        pfree(strval);
                }
+
                /*
                 * Free statarray if it's a detoasted copy.
                 */
@@ -998,10 +1235,11 @@ get_attstatsslot(HeapTuple statstuple,
                if (isnull)
                        elog(ERROR, "get_attstatsslot: stanumbers is null");
                statarray = DatumGetArrayTypeP(val);
+
                /*
-                * We expect the array to be a 1-D float4 array; verify that.
-                * We don't need to use deconstruct_array() since the array
-                * data is just going to look like a C array of float4 values.
+                * We expect the array to be a 1-D float4 array; verify that. We
+                * don't need to use deconstruct_array() since the array data is
+                * just going to look like a C array of float4 values.
                 */
                narrayelem = ARR_DIMS(statarray)[0];
                if (ARR_NDIM(statarray) != 1 || narrayelem <= 0 ||
@@ -1010,6 +1248,7 @@ get_attstatsslot(HeapTuple statstuple,
                *numbers = (float4 *) palloc(narrayelem * sizeof(float4));
                memcpy(*numbers, ARR_DATA_PTR(statarray), narrayelem * sizeof(float4));
                *nnumbers = narrayelem;
+
                /*
                 * Free statarray if it's a detoasted copy.
                 */
@@ -1027,9 +1266,9 @@ free_attstatsslot(Oid atttype,
 {
        if (values)
        {
-               if (! get_typbyval(atttype))
+               if (!get_typbyval(atttype))
                {
-                       int             i;
+                       int                     i;
 
                        for (i = 0; i < nvalues; i++)
                                pfree(DatumGetPointer(values[i]));
@@ -1039,3 +1278,35 @@ free_attstatsslot(Oid atttype,
        if (numbers)
                pfree(numbers);
 }
+
+/*                             ---------- PG_SHADOW CACHE ----------                                    */
+
+/*
+ * get_usesysid
+ *
+ *       Given a user name, look up the user's sysid.
+ *       Raises an error if no such user (rather than returning zero,
+ *       which might possibly be a valid usesysid).
+ *
+ * Note: the type of usesysid is currently int4, but may change to Oid
+ * someday.  It'd be reasonable to return zero on failure if we were
+ * using Oid ...
+ */
+int32
+get_usesysid(const char *username)
+{
+       int32           result;
+       HeapTuple       userTup;
+
+       userTup = SearchSysCache(SHADOWNAME,
+                                                        PointerGetDatum(username),
+                                                        0, 0, 0);
+       if (!HeapTupleIsValid(userTup))
+               elog(ERROR, "user \"%s\" does not exist", username);
+
+       result = ((Form_pg_shadow) GETSTRUCT(userTup))->usesysid;
+
+       ReleaseSysCache(userTup);
+
+       return result;
+}