+/*
+ * get_typ_typrelid
+ *
+ * Given the type OID, get the typrelid (InvalidOid if not a complex
+ * type).
+ */
+Oid
+get_typ_typrelid(Oid typid)
+{
+ HeapTuple tp;
+
+ tp = SearchSysCache(TYPEOID,
+ ObjectIdGetDatum(typid),
+ 0, 0, 0);
+ if (HeapTupleIsValid(tp))
+ {
+ Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
+ Oid result;
+
+ result = typtup->typrelid;
+ ReleaseSysCache(tp);
+ return result;
+ }
+ else
+ return InvalidOid;
+}
+
+/*
+ * get_element_type
+ *
+ * Given the type OID, get the typelem (InvalidOid if not an array type).
+ *
+ * NB: this only considers varlena arrays to be true arrays; InvalidOid is
+ * returned if the input is a fixed-length array type.
+ */
+Oid
+get_element_type(Oid typid)
+{
+ HeapTuple tp;
+
+ tp = SearchSysCache(TYPEOID,
+ ObjectIdGetDatum(typid),
+ 0, 0, 0);
+ if (HeapTupleIsValid(tp))
+ {
+ Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
+ Oid result;
+
+ if (typtup->typlen == -1)
+ result = typtup->typelem;
+ else
+ result = InvalidOid;
+ ReleaseSysCache(tp);
+ return result;
+ }
+ else
+ return InvalidOid;
+}
+
+/*
+ * get_array_type
+ *
+ * Given the type OID, get the corresponding array type.
+ * Returns InvalidOid if no array type can be found.
+ *
+ * NB: this only considers varlena arrays to be true arrays.
+ */
+Oid
+get_array_type(Oid typid)
+{
+ HeapTuple tp;
+
+ tp = SearchSysCache(TYPEOID,
+ ObjectIdGetDatum(typid),
+ 0, 0, 0);
+ if (HeapTupleIsValid(tp))
+ {
+ Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
+ char *array_typename;
+ Oid namespaceId;
+
+ array_typename = makeArrayTypeName(NameStr(typtup->typname));
+ namespaceId = typtup->typnamespace;
+ ReleaseSysCache(tp);
+
+ tp = SearchSysCache(TYPENAMENSP,
+ PointerGetDatum(array_typename),
+ ObjectIdGetDatum(namespaceId),
+ 0, 0);
+
+ pfree(array_typename);
+
+ if (HeapTupleIsValid(tp))
+ {
+ Oid result;
+
+ typtup = (Form_pg_type) GETSTRUCT(tp);
+ if (typtup->typlen == -1 && typtup->typelem == typid)
+ result = HeapTupleGetOid(tp);
+ else
+ result = InvalidOid;
+ ReleaseSysCache(tp);
+ return result;
+ }
+ }
+ return InvalidOid;
+}
+
+/*
+ * getTypeInputInfo
+ *
+ * Get info needed for converting values of a type to internal form
+ */
+void
+getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam)
+{
+ HeapTuple typeTuple;
+ Form_pg_type pt;
+
+ typeTuple = SearchSysCache(TYPEOID,
+ ObjectIdGetDatum(type),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(typeTuple))
+ elog(ERROR, "cache lookup failed for type %u", type);
+ pt = (Form_pg_type) GETSTRUCT(typeTuple);
+
+ if (!pt->typisdefined)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("type %s is only a shell",
+ format_type_be(type))));
+ if (!OidIsValid(pt->typinput))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_FUNCTION),
+ errmsg("no input function available for type %s",
+ format_type_be(type))));
+
+ *typInput = pt->typinput;
+ *typIOParam = getTypeIOParam(typeTuple);
+
+ ReleaseSysCache(typeTuple);
+}
+
+/*
+ * getTypeOutputInfo
+ *
+ * Get info needed for printing values of a type
+ */
+void
+getTypeOutputInfo(Oid type, Oid *typOutput, Oid *typIOParam,
+ bool *typIsVarlena)
+{
+ HeapTuple typeTuple;
+ Form_pg_type pt;
+
+ typeTuple = SearchSysCache(TYPEOID,
+ ObjectIdGetDatum(type),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(typeTuple))
+ elog(ERROR, "cache lookup failed for type %u", type);
+ pt = (Form_pg_type) GETSTRUCT(typeTuple);
+
+ if (!pt->typisdefined)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("type %s is only a shell",
+ format_type_be(type))));
+ if (!OidIsValid(pt->typoutput))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_FUNCTION),
+ errmsg("no output function available for type %s",
+ format_type_be(type))));
+
+ *typOutput = pt->typoutput;
+ *typIOParam = getTypeIOParam(typeTuple);
+ *typIsVarlena = (!pt->typbyval) && (pt->typlen == -1);
+
+ ReleaseSysCache(typeTuple);
+}
+
+/*
+ * getTypeBinaryInputInfo
+ *
+ * Get info needed for binary input of values of a type
+ */
+void
+getTypeBinaryInputInfo(Oid type, Oid *typReceive, Oid *typIOParam)
+{
+ HeapTuple typeTuple;
+ Form_pg_type pt;
+
+ typeTuple = SearchSysCache(TYPEOID,
+ ObjectIdGetDatum(type),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(typeTuple))
+ elog(ERROR, "cache lookup failed for type %u", type);
+ pt = (Form_pg_type) GETSTRUCT(typeTuple);
+
+ if (!pt->typisdefined)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("type %s is only a shell",
+ format_type_be(type))));
+ if (!OidIsValid(pt->typreceive))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_FUNCTION),
+ errmsg("no binary input function available for type %s",
+ format_type_be(type))));
+
+ *typReceive = pt->typreceive;
+ *typIOParam = getTypeIOParam(typeTuple);
+
+ ReleaseSysCache(typeTuple);
+}
+
+/*
+ * getTypeBinaryOutputInfo
+ *
+ * Get info needed for binary output of values of a type
+ */
+void
+getTypeBinaryOutputInfo(Oid type, Oid *typSend, Oid *typIOParam,
+ bool *typIsVarlena)
+{
+ HeapTuple typeTuple;
+ Form_pg_type pt;
+
+ typeTuple = SearchSysCache(TYPEOID,
+ ObjectIdGetDatum(type),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(typeTuple))
+ elog(ERROR, "cache lookup failed for type %u", type);
+ pt = (Form_pg_type) GETSTRUCT(typeTuple);
+
+ if (!pt->typisdefined)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("type %s is only a shell",
+ format_type_be(type))));
+ if (!OidIsValid(pt->typsend))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_FUNCTION),
+ errmsg("no binary output function available for type %s",
+ format_type_be(type))));
+
+ *typSend = pt->typsend;
+ *typIOParam = getTypeIOParam(typeTuple);
+ *typIsVarlena = (!pt->typbyval) && (pt->typlen == -1);
+
+ ReleaseSysCache(typeTuple);
+}
+
+
+/* ---------- STATISTICS CACHE ---------- */
+
+/*
+ * get_attavgwidth
+ *
+ * Given the table and attribute number of a column, get the average
+ * width of entries in the column. Return zero if no data available.
+ */
+int32
+get_attavgwidth(Oid relid, AttrNumber attnum)
+{
+ HeapTuple tp;
+
+ tp = SearchSysCache(STATRELATT,
+ ObjectIdGetDatum(relid),
+ Int16GetDatum(attnum),
+ 0, 0);
+ if (HeapTupleIsValid(tp))
+ {
+ int32 stawidth = ((Form_pg_statistic) GETSTRUCT(tp))->stawidth;
+
+ ReleaseSysCache(tp);
+ if (stawidth > 0)
+ return stawidth;
+ }
+ return 0;
+}
+
+/*
+ * get_attstatsslot
+ *
+ * Extract the contents of a "slot" of a pg_statistic tuple.
+ * Returns TRUE if requested slot type was found, else FALSE.
+ *
+ * Unlike other routines in this file, this takes a pointer to an
+ * already-looked-up tuple in the pg_statistic cache. We do this since
+ * most callers will want to extract more than one value from the cache
+ * entry, and we don't want to repeat the cache lookup unnecessarily.
+ *
+ * statstuple: pg_statistics tuple to be examined.
+ * atttype: type OID of attribute.
+ * atttypmod: typmod of attribute.
+ * reqkind: STAKIND code for desired statistics slot kind.
+ * reqop: STAOP value wanted, or InvalidOid if don't care.
+ * values, nvalues: if not NULL, the slot's stavalues are extracted.
+ * numbers, nnumbers: if not NULL, the slot's stanumbers are extracted.
+ *
+ * If assigned, values and numbers are set to point to palloc'd arrays.
+ * If the attribute type is pass-by-reference, the values referenced by
+ * the values array are themselves palloc'd. The palloc'd stuff can be
+ * freed by calling free_attstatsslot.
+ */
+bool
+get_attstatsslot(HeapTuple statstuple,
+ Oid atttype, int32 atttypmod,
+ int reqkind, Oid reqop,
+ Datum **values, int *nvalues,
+ float4 **numbers, int *nnumbers)
+{
+ Form_pg_statistic stats = (Form_pg_statistic) GETSTRUCT(statstuple);
+ int i,
+ j;
+ Datum val;
+ bool isnull;
+ ArrayType *statarray;
+ int narrayelem;
+ HeapTuple typeTuple;
+ Form_pg_type typeForm;
+
+ for (i = 0; i < STATISTIC_NUM_SLOTS; i++)
+ {
+ if ((&stats->stakind1)[i] == reqkind &&
+ (reqop == InvalidOid || (&stats->staop1)[i] == reqop))
+ break;
+ }
+ if (i >= STATISTIC_NUM_SLOTS)
+ return false; /* not there */
+
+ if (values)
+ {
+ val = SysCacheGetAttr(STATRELATT, statstuple,
+ Anum_pg_statistic_stavalues1 + i,
+ &isnull);
+ if (isnull)
+ elog(ERROR, "stavalues is null");
+ statarray = DatumGetArrayTypeP(val);
+
+ /* Need to get info about the array element type */
+ typeTuple = SearchSysCache(TYPEOID,
+ ObjectIdGetDatum(atttype),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(typeTuple))
+ elog(ERROR, "cache lookup failed for type %u", atttype);
+ typeForm = (Form_pg_type) GETSTRUCT(typeTuple);
+
+ /* Deconstruct array into Datum elements */
+ deconstruct_array(statarray,
+ atttype,
+ typeForm->typlen,
+ typeForm->typbyval,
+ typeForm->typalign,
+ values, nvalues);
+
+ /*
+ * If the element type is pass-by-reference, we now have a bunch
+ * of Datums that are pointers into the syscache value. Copy them
+ * to avoid problems if syscache decides to drop the entry.
+ */
+ if (!typeForm->typbyval)
+ {
+ for (j = 0; j < *nvalues; j++)
+ {
+ (*values)[j] = datumCopy((*values)[j],
+ typeForm->typbyval,
+ typeForm->typlen);
+ }
+ }
+
+ ReleaseSysCache(typeTuple);
+
+ /*
+ * Free statarray if it's a detoasted copy.
+ */
+ if ((Pointer) statarray != DatumGetPointer(val))
+ pfree(statarray);
+ }
+
+ if (numbers)
+ {
+ val = SysCacheGetAttr(STATRELATT, statstuple,
+ Anum_pg_statistic_stanumbers1 + i,
+ &isnull);
+ if (isnull)
+ elog(ERROR, "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.
+ */
+ narrayelem = ARR_DIMS(statarray)[0];
+ if (ARR_NDIM(statarray) != 1 || narrayelem <= 0 ||
+ ARR_ELEMTYPE(statarray) != FLOAT4OID)
+ elog(ERROR, "stanumbers is not a 1-D float4 array");
+ *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.
+ */
+ if ((Pointer) statarray != DatumGetPointer(val))
+ pfree(statarray);
+ }
+
+ return true;
+}
+
+void
+free_attstatsslot(Oid atttype,
+ Datum *values, int nvalues,
+ float4 *numbers, int nnumbers)
+{
+ if (values)
+ {
+ if (!get_typbyval(atttype))
+ {
+ int i;
+
+ for (i = 0; i < nvalues; i++)
+ pfree(DatumGetPointer(values[i]));
+ }
+ pfree(values);
+ }
+ if (numbers)
+ pfree(numbers);
+}
+
+/* ---------- PG_NAMESPACE CACHE ---------- */
+
+/*
+ * get_namespace_name
+ * Returns the name of a given namespace
+ *
+ * Returns a palloc'd copy of the string, or NULL if no such namespace.
+ */
+char *
+get_namespace_name(Oid nspid)
+{
+ HeapTuple tp;
+
+ tp = SearchSysCache(NAMESPACEOID,
+ ObjectIdGetDatum(nspid),
+ 0, 0, 0);
+ if (HeapTupleIsValid(tp))
+ {
+ Form_pg_namespace nsptup = (Form_pg_namespace) GETSTRUCT(tp);
+ char *result;
+
+ result = pstrdup(NameStr(nsptup->nspname));
+ ReleaseSysCache(tp);
+ return result;
+ }
+ else
+ return NULL;
+}
+
+/* ---------- 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 ...
+ */
+AclId
+get_usesysid(const char *username)
+{
+ AclId userId;
+ HeapTuple userTup;
+
+ userTup = SearchSysCache(SHADOWNAME,
+ PointerGetDatum(username),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(userTup))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("user \"%s\" does not exist", username)));
+
+ userId = ((Form_pg_shadow) GETSTRUCT(userTup))->usesysid;
+
+ ReleaseSysCache(userTup);
+
+ return userId;
+}
+
+/*
+ * get_grosysid
+ *
+ * Given a group name, look up the group's sysid.
+ * Raises an error if no such group (rather than returning zero,
+ * which might possibly be a valid grosysid).
+ *
+ */
+AclId
+get_grosysid(char *groname)
+{
+ AclId groupId;
+ HeapTuple groupTup;
+
+ groupTup = SearchSysCache(GRONAME,
+ PointerGetDatum(groname),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(groupTup))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("group \"%s\" does not exist", groname)));
+
+ groupId = ((Form_pg_group) GETSTRUCT(groupTup))->grosysid;
+
+ ReleaseSysCache(groupTup);
+
+ return groupId;
+}
+