findoidjoins
-This program scans a database, and prints oid fields (also regproc fields)
-and the tables they join to. CAUTION: it is ver-r-r-y slow on a large
-database, or even a not-so-large one. We don't really recommend running
-it on anything but an empty database, such as template1.
+This program scans a database, and prints oid fields (also regproc, regclass
+and regtype fields) and the tables they join to. CAUTION: it is ver-r-r-y
+slow on a large database, or even a not-so-large one. We don't really
+recommend running it on anything but an empty database, such as template1.
Uses pgeasy library.
WHERE a.attnum > 0 AND \
relkind = 'r' AND \
(typname = 'oid' OR \
- typname = 'regproc') AND \
+ typname = 'regproc' OR \
+ typname = 'regclass' OR \
+ typname = 'regtype') AND \
a.attrelid = c.oid AND \
a.atttypid = t.oid \
ORDER BY 2, a.attnum ; \
DECLARE c_matches BINARY CURSOR FOR \
SELECT count(*)::int4 \
FROM \"%s\" t1, \"%s\" t2 \
- WHERE RegprocToOid(t1.\"%s\") = t2.oid ",
+ WHERE t1.\"%s\"::oid = t2.oid ",
relname, relname2, attname);
doquery(query);
<!--
-$Header: /cvsroot/pgsql/doc/src/sgml/bki.sgml,v 1.10 2002/03/22 19:20:02 petere Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/bki.sgml,v 1.11 2002/04/25 02:56:55 tgl Exp $
-->
<chapter id="bki">
storage. The following types are allowed: <type>bool</type>,
<type>bytea</type>, <type>char</type> (1 byte),
<type>name</type>, <type>int2</type>, <type>int2vector</type>,
- <type>int4</type>, <type>regproc</type>, <type>text</type>,
+ <type>int4</type>, <type>regproc</type>, <type>regclass</type>,
+ <type>regtype</type>, <type>text</type>,
<type>oid</type>, <type>tid</type>, <type>xid</type>,
<type>cid</type>, <type>oidvector</type>, <type>smgr</type>,
<type>_int4</type> (array), <type>_aclitem</type> (array).
<!--
-$Header: /cvsroot/pgsql/doc/src/sgml/datatype.sgml,v 1.89 2002/04/21 18:58:00 thomas Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/datatype.sgml,v 1.90 2002/04/25 02:56:55 tgl Exp $
-->
<chapter id="datatype">
</row>
<row>
- <entry><type>oid</type></entry>
- <entry></entry>
- <entry>object identifier</entry>
- </row>
-
- <row>
<entry><type>path</type></entry>
<entry></entry>
<entry>open and closed geometric path in 2D plane</entry>
</sect1>
+ <sect1 id="datatype-oid">
+ <title>Object Identifier Types</title>
+
+ <indexterm zone="datatype-oid">
+ <primary>object identifier</primary>
+ <secondary>data type</secondary>
+ </indexterm>
+
+ <indexterm zone="datatype-oid">
+ <primary>oid</primary>
+ </indexterm>
+
+ <indexterm zone="datatype-oid">
+ <primary>regproc</primary>
+ </indexterm>
+
+ <indexterm zone="datatype-oid">
+ <primary>regprocedure</primary>
+ </indexterm>
+
+ <indexterm zone="datatype-oid">
+ <primary>regoper</primary>
+ </indexterm>
+
+ <indexterm zone="datatype-oid">
+ <primary>regoperator</primary>
+ </indexterm>
+
+ <indexterm zone="datatype-oid">
+ <primary>regclass</primary>
+ </indexterm>
+
+ <indexterm zone="datatype-oid">
+ <primary>regtype</primary>
+ </indexterm>
+
+ <para>
+ Object identifiers (OIDs) are used internally by
+ <productname>PostgreSQL</productname> as primary keys for various system
+ tables. Also, an OID system column is added to user-created tables
+ (unless <literal>WITHOUT OIDS</> is specified at table creation time).
+ Type <type>oid</> represents an object identifier. There are also
+ several aliases for <type>oid</>: <type>regproc</>, <type>regprocedure</>,
+ <type>regoper</>, <type>regoperator</>, <type>regclass</>,
+ and <type>regtype</>.
+ </para>
+
+ <para>
+ The <type>oid</> type is currently implemented as an unsigned four-byte
+ integer.
+ Therefore, it is not large enough to provide database-wide uniqueness
+ in large databases, or even in large individual tables. So, using a
+ user-created table's OID column as a primary key is discouraged.
+ OIDs are best used only for references to system tables.
+ </para>
+
+ <para>
+ The <type>oid</> type itself has few operations beyond comparison
+ (which is implemented as unsigned comparison). It can be cast to
+ integer, however, and then manipulated using the standard integer
+ operators. (Beware of possible signed-versus-unsigned confusion
+ if you do this.)
+ </para>
+
+ <para>
+ The <type>oid</> alias types have no operations of their own except
+ for specialized input and output routines. These routines are able
+ to accept and display symbolic names for system objects, rather than
+ the raw numeric value that type <type>oid</> would use. The alias
+ types allow simplified lookup of OID values for objects: for example,
+ one may write <literal>'mytable'::regclass</> to get the OID of table
+ <literal>mytable</>, rather than <literal>SELECT oid FROM pg_class WHERE
+ relname = 'mytable'</>. (In reality, a much more complicated SELECT would
+ be needed to deal with selecting the right OID when there are multiple
+ tables named <literal>mytable</> in different schemas.)
+ </para>
+
+ <para>
+ <table tocentry="1">
+ <title>Object Identifier Types</title>
+ <tgroup cols="4">
+ <thead>
+ <row>
+ <entry>Type name</entry>
+ <entry>References</entry>
+ <entry>Description</entry>
+ <entry>Examples</entry>
+ </row>
+ </thead>
+
+ <tbody>
+
+ <row>
+ <entry><type>oid</></entry>
+ <entry>any</entry>
+ <entry>Numeric object identifier</entry>
+ <entry>564182</entry>
+ </row>
+
+ <row>
+ <entry><type>regproc</></entry>
+ <entry>pg_proc</entry>
+ <entry>Function name</entry>
+ <entry>sum</entry>
+ </row>
+
+ <row>
+ <entry><type>regprocedure</></entry>
+ <entry>pg_proc</entry>
+ <entry>Function with argument types</entry>
+ <entry>sum(int4)</entry>
+ </row>
+
+ <row>
+ <entry><type>regoper</></entry>
+ <entry>pg_operator</entry>
+ <entry>Operator name</entry>
+ <entry>+</entry>
+ </row>
+
+ <row>
+ <entry><type>regoperator</></entry>
+ <entry>pg_operator</entry>
+ <entry>Operator with argument types</entry>
+ <entry>*(integer,integer) -(NONE,integer)</entry>
+ </row>
+
+ <row>
+ <entry><type>regclass</></entry>
+ <entry>pg_class</entry>
+ <entry>Relation name</entry>
+ <entry>pg_type</entry>
+ </row>
+
+ <row>
+ <entry><type>regtype</></entry>
+ <entry>pg_type</entry>
+ <entry>Type name</entry>
+ <entry>integer</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </para>
+
+ <para>
+ All of the alias types accept schema-qualified names, and will
+ display schema-qualified names on output if the object would not
+ be found in the current search path without being qualified.
+ The <type>regproc</> and <type>regoper</> alias types will only
+ accept input names that are unique (not overloaded), so they are
+ of limited use; for most uses <type>regprocedure</> or
+ <type>regoperator</> is more appropriate. For <type>regoperator</>,
+ unary operators are identified by writing NONE for the unused
+ operand.
+ </para>
+
+ </sect1>
+
</chapter>
<!-- Keep this comment at the end of the file
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.125 2002/03/26 19:15:16 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.126 2002/04/25 02:56:55 tgl Exp $
*
*-------------------------------------------------------------------------
*/
{"int2vector", INT2VECTOROID, 0, INDEX_MAX_KEYS * 2, F_INT2VECTORIN, F_INT2VECTOROUT},
{"int4", INT4OID, 0, 4, F_INT4IN, F_INT4OUT},
{"regproc", REGPROCOID, 0, 4, F_REGPROCIN, F_REGPROCOUT},
+ {"regclass", REGCLASSOID, 0, 4, F_REGCLASSIN, F_REGCLASSOUT},
+ {"regtype", REGTYPEOID, 0, 4, F_REGTYPEIN, F_REGTYPEOUT},
{"text", TEXTOID, 0, -1, F_TEXTIN, F_TEXTOUT},
{"oid", OIDOID, 0, 4, F_OIDIN, F_OIDOUT},
{"tid", TIDOID, 0, 6, F_TIDIN, F_TIDOUT},
{"xid", XIDOID, 0, 4, F_XIDIN, F_XIDOUT},
{"cid", CIDOID, 0, 4, F_CIDIN, F_CIDOUT},
- {"oidvector", 30, 0, INDEX_MAX_KEYS * 4, F_OIDVECTORIN, F_OIDVECTOROUT},
+ {"oidvector", OIDVECTOROID, 0, INDEX_MAX_KEYS * 4, F_OIDVECTORIN, F_OIDVECTOROUT},
{"smgr", 210, 0, 2, F_SMGRIN, F_SMGROUT},
{"_int4", 1007, INT4OID, -1, F_ARRAY_IN, F_ARRAY_OUT},
{"_aclitem", 1034, 1033, -1, F_ARRAY_IN, F_ARRAY_OUT}
attrtypes[attnum]->attnum = 1 + attnum; /* fillatt */
attlen = attrtypes[attnum]->attlen = Ap->am_typ.typlen;
attrtypes[attnum]->attbyval = Ap->am_typ.typbyval;
- attrtypes[attnum]->attstorage = Ap->am_typ.typstorage;;
+ attrtypes[attnum]->attstorage = Ap->am_typ.typstorage;
attrtypes[attnum]->attalign = Ap->am_typ.typalign;
}
else
elog(DEBUG3, "column %s %s", NameStr(attrtypes[attnum]->attname), type);
attrtypes[attnum]->attnum = 1 + attnum; /* fillatt */
attlen = attrtypes[attnum]->attlen = Procid[typeoid].len;
- attrtypes[attnum]->attstorage = 'p';
/*
* Cheat like mad to fill in these items from the length only.
- * This only has to work for types used in the system catalogs...
+ * This only has to work for types that appear in Procid[].
*/
switch (attlen)
{
case 1:
attrtypes[attnum]->attbyval = true;
+ attrtypes[attnum]->attstorage = 'p';
attrtypes[attnum]->attalign = 'c';
break;
case 2:
attrtypes[attnum]->attbyval = true;
+ attrtypes[attnum]->attstorage = 'p';
attrtypes[attnum]->attalign = 's';
break;
case 4:
attrtypes[attnum]->attbyval = true;
+ attrtypes[attnum]->attstorage = 'p';
+ attrtypes[attnum]->attalign = 'i';
+ break;
+ case -1:
+ attrtypes[attnum]->attbyval = false;
+ attrtypes[attnum]->attstorage = 'x';
attrtypes[attnum]->attalign = 'i';
break;
default:
+ /* TID and fixed-length arrays, such as oidvector */
attrtypes[attnum]->attbyval = false;
+ attrtypes[attnum]->attstorage = 'p';
attrtypes[attnum]->attalign = 'i';
break;
}
/* ----------------
* gettype
+ *
+ * NB: this is really ugly; it will return an integer index into Procid[],
+ * and not an OID at all, until the first reference to a type not known in
+ * Procid[]. At that point it will read and cache pg_type in the Typ array,
+ * and subsequently return a real OID (and set the global pointer Ap to
+ * point at the found row in Typ). So caller must check whether Typ is
+ * still NULL to determine what the return value is!
* ----------------
*/
static Oid
}
else
{
- for (i = 0; i <= n_types; i++)
+ for (i = 0; i < n_types; i++)
{
if (strncmp(type, Procid[i].name, NAMEDATALEN) == 0)
return i;
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/catalog/namespace.c,v 1.11 2002/04/17 20:57:56 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/catalog/namespace.c,v 1.12 2002/04/25 02:56:55 tgl Exp $
*
*-------------------------------------------------------------------------
*/
* Given a possibly-qualified function name and argument count,
* retrieve a list of the possible matches.
*
+ * If nargs is -1, we return all functions matching the given name,
+ * regardless of argument count.
+ *
* We search a single namespace if the function name is qualified, else
* all namespaces in the search path. The return list will never contain
- * multiple entries with identical argument types --- in the multiple-
+ * multiple entries with identical argument lists --- in the multiple-
* namespace case, we arrange for entries in earlier namespaces to mask
* identical entries in later namespaces.
*/
namespaceId = InvalidOid;
}
- /* Search syscache by name and nargs only */
- catlist = SearchSysCacheList(PROCNAMENSP, 2,
- CStringGetDatum(funcname),
- Int16GetDatum(nargs),
- 0, 0);
+ /* Search syscache by name and (optionally) nargs only */
+ if (nargs >= 0)
+ catlist = SearchSysCacheList(PROCNAMENSP, 2,
+ CStringGetDatum(funcname),
+ Int16GetDatum(nargs),
+ 0, 0);
+ else
+ catlist = SearchSysCacheList(PROCNAMENSP, 1,
+ CStringGetDatum(funcname),
+ 0, 0, 0);
for (i = 0; i < catlist->n_members; i++)
{
int pathpos = 0;
FuncCandidateList newResult;
+ nargs = procform->pronargs;
+
if (OidIsValid(namespaceId))
{
/* Consider only procs in specified namespace */
if (catlist->ordered)
{
- if (memcmp(procform->proargtypes, resultList->args,
+ if (nargs == resultList->nargs &&
+ memcmp(procform->proargtypes, resultList->args,
nargs * sizeof(Oid)) == 0)
prevResult = resultList;
else
prevResult;
prevResult = prevResult->next)
{
- if (memcmp(procform->proargtypes, prevResult->args,
+ if (nargs == prevResult->nargs &&
+ memcmp(procform->proargtypes, prevResult->args,
nargs * sizeof(Oid)) == 0)
break;
}
+ nargs * sizeof(Oid));
newResult->pathpos = pathpos;
newResult->oid = proctup->t_data->t_oid;
+ newResult->nargs = nargs;
memcpy(newResult->args, procform->proargtypes, nargs * sizeof(Oid));
newResult->next = resultList;
* Given a possibly-qualified operator name and operator kind,
* retrieve a list of the possible matches.
*
+ * If oprkind is '\0', we return all operators matching the given name,
+ * regardless of arguments.
+ *
* We search a single namespace if the operator name is qualified, else
* all namespaces in the search path. The return list will never contain
- * multiple entries with identical argument types --- in the multiple-
+ * multiple entries with identical argument lists --- in the multiple-
* namespace case, we arrange for entries in earlier namespaces to mask
* identical entries in later namespaces.
*
* The returned items always have two args[] entries --- one or the other
- * will be InvalidOid for a prefix or postfix oprkind.
+ * will be InvalidOid for a prefix or postfix oprkind. nargs is 2, too.
*/
FuncCandidateList
OpernameGetCandidates(List *names, char oprkind)
int pathpos = 0;
FuncCandidateList newResult;
- /* Ignore operators of wrong kind */
- if (operform->oprkind != oprkind)
+ /* Ignore operators of wrong kind, if specific kind requested */
+ if (oprkind && operform->oprkind != oprkind)
continue;
if (OidIsValid(namespaceId))
palloc(sizeof(struct _FuncCandidateList) + sizeof(Oid));
newResult->pathpos = pathpos;
newResult->oid = opertup->t_data->t_oid;
+ newResult->nargs = 2;
newResult->args[0] = operform->oprleft;
newResult->args[1] = operform->oprright;
newResult->next = resultList;
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.66 2002/04/16 23:08:10 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.67 2002/04/25 02:56:55 tgl Exp $
*
* NOTES
* these routines moved here from commands/define.c and somewhat cleaned up.
ObjectIdGetDatum(operatorNamespace));
if (HeapTupleIsValid(tup))
{
- regproc oprcode = ((Form_pg_operator) GETSTRUCT(tup))->oprcode;
+ RegProcedure oprcode = ((Form_pg_operator) GETSTRUCT(tup))->oprcode;
operatorObjectId = tup->t_data->t_oid;
*defined = RegProcedureIsValid(oprcode);
bool *defined)
{
Oid operatorObjectId;
- regproc oprcode;
+ RegProcedure oprcode;
operatorObjectId = LookupOperName(operatorName, leftObjectId,
rightObjectId);
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.70 2002/04/11 20:00:00 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.71 2002/04/25 02:56:55 tgl Exp $
*
*-------------------------------------------------------------------------
*/
if (!con->constisnull)
{
- /* We know the source constant is really of type 'text' */
- char *val = DatumGetCString(DirectFunctionCall1(textout,
+ char *val = DatumGetCString(DirectFunctionCall1(unknownout,
con->constvalue));
newcon->constvalue = stringTypeDatum(targetType, val, atttypmod);
case (OIDOID):
case (REGPROCOID):
+ case (REGPROCEDUREOID):
+ case (REGOPEROID):
+ case (REGOPERATOROID):
+ case (REGCLASSOID):
+ case (REGTYPEOID):
case (INT2OID):
case (INT4OID):
case (INT8OID):
* to allow for better type extensibility.
*/
+#define TypeIsTextGroup(t) \
+ ((t) == TEXTOID || \
+ (t) == BPCHAROID || \
+ (t) == VARCHAROID)
+
+/* Notice OidGroup is a subset of Int4GroupA */
+#define TypeIsOidGroup(t) \
+ ((t) == OIDOID || \
+ (t) == REGPROCOID || \
+ (t) == REGPROCEDUREOID || \
+ (t) == REGOPEROID || \
+ (t) == REGOPERATOROID || \
+ (t) == REGCLASSOID || \
+ (t) == REGTYPEOID)
+
/*
- * This macro describes hard-coded knowledge of binary compatibility
- * for built-in types.
+ * INT4 is binary-compatible with many types, but we don't want to allow
+ * implicit coercion directly between, say, OID and AbsTime. So we subdivide
+ * the categories.
*/
-#define IS_BINARY_COMPATIBLE(a,b) \
- (((a) == BPCHAROID && (b) == TEXTOID) \
- || ((a) == BPCHAROID && (b) == VARCHAROID) \
- || ((a) == VARCHAROID && (b) == TEXTOID) \
- || ((a) == VARCHAROID && (b) == BPCHAROID) \
- || ((a) == TEXTOID && (b) == BPCHAROID) \
- || ((a) == TEXTOID && (b) == VARCHAROID) \
- || ((a) == OIDOID && (b) == INT4OID) \
- || ((a) == OIDOID && (b) == REGPROCOID) \
- || ((a) == INT4OID && (b) == OIDOID) \
- || ((a) == INT4OID && (b) == REGPROCOID) \
- || ((a) == REGPROCOID && (b) == OIDOID) \
- || ((a) == REGPROCOID && (b) == INT4OID) \
- || ((a) == ABSTIMEOID && (b) == INT4OID) \
- || ((a) == INT4OID && (b) == ABSTIMEOID) \
- || ((a) == RELTIMEOID && (b) == INT4OID) \
- || ((a) == INT4OID && (b) == RELTIMEOID) \
- || ((a) == INETOID && (b) == CIDROID) \
- || ((a) == CIDROID && (b) == INETOID) \
- || ((a) == BITOID && (b) == VARBITOID) \
- || ((a) == VARBITOID && (b) == BITOID))
+#define TypeIsInt4GroupA(t) \
+ ((t) == INT4OID || \
+ TypeIsOidGroup(t))
-bool
-IsBinaryCompatible(Oid type1, Oid type2)
+#define TypeIsInt4GroupB(t) \
+ ((t) == INT4OID || \
+ (t) == ABSTIMEOID)
+
+#define TypeIsInt4GroupC(t) \
+ ((t) == INT4OID || \
+ (t) == RELTIMEOID)
+
+#define TypeIsInetGroup(t) \
+ ((t) == INETOID || \
+ (t) == CIDROID)
+
+#define TypeIsBitGroup(t) \
+ ((t) == BITOID || \
+ (t) == VARBITOID)
+
+
+static bool
+DirectlyBinaryCompatible(Oid type1, Oid type2)
{
if (type1 == type2)
return true;
- if (IS_BINARY_COMPATIBLE(type1, type2))
+ if (TypeIsTextGroup(type1) && TypeIsTextGroup(type2))
+ return true;
+ if (TypeIsInt4GroupA(type1) && TypeIsInt4GroupA(type2))
+ return true;
+ if (TypeIsInt4GroupB(type1) && TypeIsInt4GroupB(type2))
+ return true;
+ if (TypeIsInt4GroupC(type1) && TypeIsInt4GroupC(type2))
+ return true;
+ if (TypeIsInetGroup(type1) && TypeIsInetGroup(type2))
+ return true;
+ if (TypeIsBitGroup(type1) && TypeIsBitGroup(type2))
+ return true;
+ return false;
+}
+
+
+bool
+IsBinaryCompatible(Oid type1, Oid type2)
+{
+ if (DirectlyBinaryCompatible(type1, type2))
return true;
/*
* Perhaps the types are domains; if so, look at their base types
type1 = getBaseType(type1);
if (OidIsValid(type2))
type2 = getBaseType(type2);
- if (type1 == type2)
- return true;
- if (IS_BINARY_COMPATIBLE(type1, type2))
+ if (DirectlyBinaryCompatible(type1, type2))
return true;
return false;
}
break;
case (NUMERIC_TYPE):
- if (type == OIDOID)
+ if (TypeIsOidGroup(type))
result = OIDOID;
else if (type == NUMERICOID)
result = NUMERICOID;
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.62 2002/04/16 23:08:11 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.63 2002/04/25 02:56:55 tgl Exp $
*
*-------------------------------------------------------------------------
*/
break;
case T_String:
- val = DirectFunctionCall1(textin, CStringGetDatum(strVal(value)));
+ val = DirectFunctionCall1(unknownin,
+ CStringGetDatum(strVal(value)));
typeid = UNKNOWNOID; /* will be coerced later */
typelen = -1; /* variable len */
- /*-------------------------------------------------------------------------
+/*-------------------------------------------------------------------------
*
* regproc.c
- * Functions for the built-in type "RegProcedure".
+ * Functions for the built-in types regproc, regclass, regtype, etc.
+ *
+ * These types are all binary-compatible with type Oid, and rely on Oid
+ * for comparison and so forth. Their only interesting behavior is in
+ * special I/O conversion routines.
+ *
*
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/regproc.c,v 1.65 2002/04/05 00:31:29 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/regproc.c,v 1.66 2002/04/25 02:56:55 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
+#include <ctype.h>
+
#include "access/genam.h"
#include "access/heapam.h"
#include "catalog/catname.h"
#include "catalog/indexing.h"
+#include "catalog/namespace.h"
+#include "catalog/pg_operator.h"
#include "catalog/pg_proc.h"
+#include "catalog/pg_type.h"
+#include "lib/stringinfo.h"
#include "miscadmin.h"
+#include "parser/parse_type.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
+#include "utils/lsyscache.h"
#include "utils/syscache.h"
+static List *stringToQualifiedNameList(const char *string, const char *caller);
+static void parseNameAndArgTypes(const char *string, const char *caller,
+ bool allow_none,
+ List **names, int *nargs, Oid *argtypes);
+
+
/*****************************************************************************
* USER I/O ROUTINES *
*****************************************************************************/
/*
- * regprocin - converts "proname" or "proid" to proid
+ * regprocin - converts "proname" to proc OID
*
- * We need to accept an OID for cases where the name is ambiguous.
+ * We also accept a numeric OID, mostly for historical reasons.
*
- * proid of '-' signifies unknown, for consistency with regprocout
+ * '-' signifies unknown (OID 0). In all other cases, the input must
+ * match an existing pg_proc entry.
*/
Datum
regprocin(PG_FUNCTION_ARGS)
{
char *pro_name_or_oid = PG_GETARG_CSTRING(0);
RegProcedure result = InvalidOid;
- int matches = 0;
+ List *names;
+ FuncCandidateList clist;
- if (pro_name_or_oid[0] == '-' && pro_name_or_oid[1] == '\0')
+ /* '-' ? */
+ if (strcmp(pro_name_or_oid, "-") == 0)
PG_RETURN_OID(InvalidOid);
+ /* Numeric OID? */
if (pro_name_or_oid[0] >= '0' &&
pro_name_or_oid[0] <= '9' &&
strspn(pro_name_or_oid, "0123456789") == strlen(pro_name_or_oid))
0, 0, 0);
if (!RegProcedureIsValid(result))
elog(ERROR, "No procedure with oid %s", pro_name_or_oid);
- matches = 1;
+ PG_RETURN_OID(result);
}
- else
+
+ /* Else it's a name, possibly schema-qualified */
+
+ /*
+ * In bootstrap mode we assume the given name is not schema-qualified,
+ * and just search pg_proc for a unique match. This is needed for
+ * initializing other system catalogs (pg_namespace may not exist yet,
+ * and certainly there are no schemas other than pg_catalog).
+ */
+ if (IsBootstrapProcessingMode())
{
+ int matches = 0;
Relation hdesc;
ScanKeyData skey[1];
- SysScanDesc funcscan;
+ SysScanDesc sysscan;
HeapTuple tuple;
ScanKeyEntryInitialize(&skey[0], 0x0,
CStringGetDatum(pro_name_or_oid));
hdesc = heap_openr(ProcedureRelationName, AccessShareLock);
+ sysscan = systable_beginscan(hdesc, ProcedureNameNspIndex, true,
+ SnapshotNow, 1, skey);
- funcscan = systable_beginscan(hdesc, ProcedureNameNspIndex, true,
- SnapshotNow, 1, skey);
-
- while (HeapTupleIsValid(tuple = systable_getnext(funcscan)))
+ while (HeapTupleIsValid(tuple = systable_getnext(sysscan)))
{
result = (RegProcedure) tuple->t_data->t_oid;
if (++matches > 1)
break;
}
- systable_endscan(funcscan);
-
+ systable_endscan(sysscan);
heap_close(hdesc, AccessShareLock);
+
+ if (matches == 0)
+ elog(ERROR, "No procedure with name %s", pro_name_or_oid);
+ else if (matches > 1)
+ elog(ERROR, "There is more than one procedure named %s",
+ pro_name_or_oid);
+ PG_RETURN_OID(result);
}
- if (matches > 1)
- elog(ERROR, "There is more than one procedure named %s.\n\tSupply the pg_proc oid inside single quotes.", pro_name_or_oid);
- else if (matches == 0)
+ /*
+ * Normal case: parse the name into components and see if it
+ * matches any pg_proc entries in the current search path.
+ */
+ names = stringToQualifiedNameList(pro_name_or_oid, "regprocin");
+ clist = FuncnameGetCandidates(names, -1);
+
+ if (clist == NULL)
elog(ERROR, "No procedure with name %s", pro_name_or_oid);
+ else if (clist->next != NULL)
+ elog(ERROR, "There is more than one procedure named %s",
+ pro_name_or_oid);
+
+ result = clist->oid;
PG_RETURN_OID(result);
}
/*
- * regprocout - converts proid to "pro_name"
+ * regprocout - converts proc OID to "pro_name"
*/
Datum
regprocout(PG_FUNCTION_ARGS)
{
RegProcedure proid = PG_GETARG_OID(0);
- HeapTuple proctup;
char *result;
+ HeapTuple proctup;
+
+ if (proid == InvalidOid)
+ {
+ result = pstrdup("-");
+ PG_RETURN_CSTRING(result);
+ }
+
+ proctup = SearchSysCache(PROCOID,
+ ObjectIdGetDatum(proid),
+ 0, 0, 0);
+
+ if (HeapTupleIsValid(proctup))
+ {
+ Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(proctup);
+ char *proname = NameStr(procform->proname);
+
+ /*
+ * In bootstrap mode, skip the fancy namespace stuff and just
+ * return the proc name. (This path is only needed for debugging
+ * output anyway.)
+ */
+ if (IsBootstrapProcessingMode())
+ {
+ result = pstrdup(proname);
+ }
+ else
+ {
+ char *nspname;
+ FuncCandidateList clist;
+
+ /*
+ * Would this proc be found (uniquely!) by regprocin?
+ * If not, qualify it.
+ */
+ clist = FuncnameGetCandidates(makeList1(makeString(proname)), -1);
+ if (clist != NULL && clist->next == NULL &&
+ clist->oid == proid)
+ nspname = NULL;
+ else
+ nspname = get_namespace_name(procform->pronamespace);
+
+ result = quote_qualified_identifier(nspname, proname);
+ }
+
+ ReleaseSysCache(proctup);
+ }
+ else
+ {
+ /* If OID doesn't match any pg_proc entry, return it numerically */
+ result = (char *) palloc(NAMEDATALEN);
+ snprintf(result, NAMEDATALEN, "%u", proid);
+ }
+
+ PG_RETURN_CSTRING(result);
+}
- result = (char *) palloc(NAMEDATALEN);
+
+/*
+ * regprocedurein - converts "proname(args)" to proc OID
+ *
+ * We also accept a numeric OID, mostly for historical reasons.
+ *
+ * '-' signifies unknown (OID 0). In all other cases, the input must
+ * match an existing pg_proc entry.
+ */
+Datum
+regprocedurein(PG_FUNCTION_ARGS)
+{
+ char *pro_name_or_oid = PG_GETARG_CSTRING(0);
+ RegProcedure result = InvalidOid;
+ List *names;
+ int nargs;
+ Oid argtypes[FUNC_MAX_ARGS];
+ FuncCandidateList clist;
+
+ /* '-' ? */
+ if (strcmp(pro_name_or_oid, "-") == 0)
+ PG_RETURN_OID(InvalidOid);
+
+ /* Numeric OID? */
+ if (pro_name_or_oid[0] >= '0' &&
+ pro_name_or_oid[0] <= '9' &&
+ strspn(pro_name_or_oid, "0123456789") == strlen(pro_name_or_oid))
+ {
+ Oid searchOid;
+
+ searchOid = DatumGetObjectId(DirectFunctionCall1(oidin,
+ CStringGetDatum(pro_name_or_oid)));
+ result = (RegProcedure) GetSysCacheOid(PROCOID,
+ ObjectIdGetDatum(searchOid),
+ 0, 0, 0);
+ if (!RegProcedureIsValid(result))
+ elog(ERROR, "No procedure with oid %s", pro_name_or_oid);
+ PG_RETURN_OID(result);
+ }
+
+ /*
+ * Else it's a name and arguments. Parse the name and arguments,
+ * look up potential matches in the current namespace search list,
+ * and scan to see which one exactly matches the given argument
+ * types. (There will not be more than one match.)
+ *
+ * XXX at present, this code will not work in bootstrap mode, hence this
+ * datatype cannot be used for any system column that needs to receive
+ * data during bootstrap.
+ */
+ parseNameAndArgTypes(pro_name_or_oid, "regprocedurein", false,
+ &names, &nargs, argtypes);
+
+ clist = FuncnameGetCandidates(names, nargs);
+
+ for (; clist; clist = clist->next)
+ {
+ if (memcmp(clist->args, argtypes, nargs * sizeof(Oid)) == 0)
+ break;
+ }
+
+ if (clist == NULL)
+ elog(ERROR, "No procedure with name %s", pro_name_or_oid);
+
+ result = clist->oid;
+
+ PG_RETURN_OID(result);
+}
+
+/*
+ * regprocedureout - converts proc OID to "pro_name(args)"
+ */
+Datum
+regprocedureout(PG_FUNCTION_ARGS)
+{
+ RegProcedure proid = PG_GETARG_OID(0);
+ char *result;
+ HeapTuple proctup;
if (proid == InvalidOid)
{
- result[0] = '-';
- result[1] = '\0';
+ result = pstrdup("-");
PG_RETURN_CSTRING(result);
}
if (HeapTupleIsValid(proctup))
{
- char *s;
+ Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(proctup);
+ char *proname = NameStr(procform->proname);
+ int nargs = procform->pronargs;
+ int i;
+ char *nspname;
+ FuncCandidateList clist;
+ StringInfoData buf;
+
+ /* XXX no support here for bootstrap mode */
+
+ /*
+ * Would this proc be found (given the right args) by regprocedurein?
+ * If not, we need to qualify it.
+ */
+ clist = FuncnameGetCandidates(makeList1(makeString(proname)), nargs);
+
+ for (; clist; clist = clist->next)
+ {
+ if (memcmp(clist->args, procform->proargtypes,
+ nargs * sizeof(Oid)) == 0)
+ break;
+ }
+
+ if (clist != NULL && clist->oid == proid)
+ nspname = NULL;
+ else
+ nspname = get_namespace_name(procform->pronamespace);
+
+ initStringInfo(&buf);
+
+ appendStringInfo(&buf, "%s(",
+ quote_qualified_identifier(nspname, proname));
+ for (i = 0; i < nargs; i++)
+ {
+ appendStringInfo(&buf, "%s%s",
+ (i > 0) ? "," : "",
+ format_type_be(procform->proargtypes[i]));
+ }
+
+ appendStringInfo(&buf, ")");
+
+ result = buf.data;
- s = NameStr(((Form_pg_proc) GETSTRUCT(proctup))->proname);
- StrNCpy(result, s, NAMEDATALEN);
ReleaseSysCache(proctup);
}
else
{
- result[0] = '-';
- result[1] = '\0';
+ /* If OID doesn't match any pg_proc entry, return it numerically */
+ result = (char *) palloc(NAMEDATALEN);
+ snprintf(result, NAMEDATALEN, "%u", proid);
+ }
+
+ PG_RETURN_CSTRING(result);
+}
+
+
+/*
+ * regoperin - converts "oprname" to operator OID
+ *
+ * We also accept a numeric OID, mostly for historical reasons.
+ *
+ * '0' signifies unknown (OID 0). In all other cases, the input must
+ * match an existing pg_operator entry.
+ */
+Datum
+regoperin(PG_FUNCTION_ARGS)
+{
+ char *opr_name_or_oid = PG_GETARG_CSTRING(0);
+ Oid result = InvalidOid;
+ List *names;
+ FuncCandidateList clist;
+
+ /* '0' ? */
+ if (strcmp(opr_name_or_oid, "0") == 0)
+ PG_RETURN_OID(InvalidOid);
+
+ /* Numeric OID? */
+ if (opr_name_or_oid[0] >= '0' &&
+ opr_name_or_oid[0] <= '9' &&
+ strspn(opr_name_or_oid, "0123456789") == strlen(opr_name_or_oid))
+ {
+ Oid searchOid;
+
+ searchOid = DatumGetObjectId(DirectFunctionCall1(oidin,
+ CStringGetDatum(opr_name_or_oid)));
+ result = GetSysCacheOid(OPEROID,
+ ObjectIdGetDatum(searchOid),
+ 0, 0, 0);
+ if (!OidIsValid(result))
+ elog(ERROR, "No operator with oid %s", opr_name_or_oid);
+ PG_RETURN_OID(result);
+ }
+
+ /* Else it's a name, possibly schema-qualified */
+
+ /*
+ * In bootstrap mode we assume the given name is not schema-qualified,
+ * and just search pg_operator for a unique match. This is needed for
+ * initializing other system catalogs (pg_namespace may not exist yet,
+ * and certainly there are no schemas other than pg_catalog).
+ */
+ if (IsBootstrapProcessingMode())
+ {
+ int matches = 0;
+ Relation hdesc;
+ ScanKeyData skey[1];
+ SysScanDesc sysscan;
+ HeapTuple tuple;
+
+ ScanKeyEntryInitialize(&skey[0], 0x0,
+ (AttrNumber) Anum_pg_operator_oprname,
+ (RegProcedure) F_NAMEEQ,
+ CStringGetDatum(opr_name_or_oid));
+
+ hdesc = heap_openr(OperatorRelationName, AccessShareLock);
+ sysscan = systable_beginscan(hdesc, OperatorNameNspIndex, true,
+ SnapshotNow, 1, skey);
+
+ while (HeapTupleIsValid(tuple = systable_getnext(sysscan)))
+ {
+ result = tuple->t_data->t_oid;
+ if (++matches > 1)
+ break;
+ }
+
+ systable_endscan(sysscan);
+ heap_close(hdesc, AccessShareLock);
+
+ if (matches == 0)
+ elog(ERROR, "No operator with name %s", opr_name_or_oid);
+ else if (matches > 1)
+ elog(ERROR, "There is more than one operator named %s",
+ opr_name_or_oid);
+ PG_RETURN_OID(result);
+ }
+
+ /*
+ * Normal case: parse the name into components and see if it
+ * matches any pg_operator entries in the current search path.
+ */
+ names = stringToQualifiedNameList(opr_name_or_oid, "regoperin");
+ clist = OpernameGetCandidates(names, '\0');
+
+ if (clist == NULL)
+ elog(ERROR, "No operator with name %s", opr_name_or_oid);
+ else if (clist->next != NULL)
+ elog(ERROR, "There is more than one operator named %s",
+ opr_name_or_oid);
+
+ result = clist->oid;
+
+ PG_RETURN_OID(result);
+}
+
+/*
+ * regoperout - converts operator OID to "opr_name"
+ */
+Datum
+regoperout(PG_FUNCTION_ARGS)
+{
+ Oid oprid = PG_GETARG_OID(0);
+ char *result;
+ HeapTuple opertup;
+
+ if (oprid == InvalidOid)
+ {
+ result = pstrdup("0");
+ PG_RETURN_CSTRING(result);
+ }
+
+ opertup = SearchSysCache(OPEROID,
+ ObjectIdGetDatum(oprid),
+ 0, 0, 0);
+
+ if (HeapTupleIsValid(opertup))
+ {
+ Form_pg_operator operform = (Form_pg_operator) GETSTRUCT(opertup);
+ char *oprname = NameStr(operform->oprname);
+
+ /*
+ * In bootstrap mode, skip the fancy namespace stuff and just
+ * return the oper name. (This path is only needed for debugging
+ * output anyway.)
+ */
+ if (IsBootstrapProcessingMode())
+ {
+ result = pstrdup(oprname);
+ }
+ else
+ {
+ FuncCandidateList clist;
+
+ /*
+ * Would this oper be found (uniquely!) by regoperin?
+ * If not, qualify it.
+ */
+ clist = OpernameGetCandidates(makeList1(makeString(oprname)),
+ '\0');
+ if (clist != NULL && clist->next == NULL &&
+ clist->oid == oprid)
+ result = pstrdup(oprname);
+ else
+ {
+ const char *nspname;
+
+ nspname = get_namespace_name(operform->oprnamespace);
+ nspname = quote_identifier(nspname);
+ result = (char *) palloc(strlen(nspname)+strlen(oprname)+2);
+ sprintf(result, "%s.%s", nspname, oprname);
+ }
+ }
+
+ ReleaseSysCache(opertup);
+ }
+ else
+ {
+ /* If OID doesn't match any pg_operator entry, return it numerically */
+ result = (char *) palloc(NAMEDATALEN);
+ snprintf(result, NAMEDATALEN, "%u", oprid);
+ }
+
+ PG_RETURN_CSTRING(result);
+}
+
+
+/*
+ * regoperatorin - converts "oprname(args)" to operator OID
+ *
+ * We also accept a numeric OID, mostly for historical reasons.
+ *
+ * '0' signifies unknown (OID 0). In all other cases, the input must
+ * match an existing pg_operator entry.
+ */
+Datum
+regoperatorin(PG_FUNCTION_ARGS)
+{
+ char *opr_name_or_oid = PG_GETARG_CSTRING(0);
+ Oid result = InvalidOid;
+ List *names;
+ int nargs;
+ Oid argtypes[FUNC_MAX_ARGS];
+ char oprkind;
+ FuncCandidateList clist;
+
+ /* '0' ? */
+ if (strcmp(opr_name_or_oid, "0") == 0)
+ PG_RETURN_OID(InvalidOid);
+
+ /* Numeric OID? */
+ if (opr_name_or_oid[0] >= '0' &&
+ opr_name_or_oid[0] <= '9' &&
+ strspn(opr_name_or_oid, "0123456789") == strlen(opr_name_or_oid))
+ {
+ Oid searchOid;
+
+ searchOid = DatumGetObjectId(DirectFunctionCall1(oidin,
+ CStringGetDatum(opr_name_or_oid)));
+ result = GetSysCacheOid(OPEROID,
+ ObjectIdGetDatum(searchOid),
+ 0, 0, 0);
+ if (!OidIsValid(result))
+ elog(ERROR, "No operator with oid %s", opr_name_or_oid);
+ PG_RETURN_OID(result);
+ }
+
+ /*
+ * Else it's a name and arguments. Parse the name and arguments,
+ * look up potential matches in the current namespace search list,
+ * and scan to see which one exactly matches the given argument
+ * types. (There will not be more than one match.)
+ *
+ * XXX at present, this code will not work in bootstrap mode, hence this
+ * datatype cannot be used for any system column that needs to receive
+ * data during bootstrap.
+ */
+ parseNameAndArgTypes(opr_name_or_oid, "regoperatorin", true,
+ &names, &nargs, argtypes);
+ if (nargs == 1)
+ elog(ERROR, "regoperatorin: use NONE to denote the missing argument of a unary operator");
+ if (nargs != 2)
+ elog(ERROR, "regoperatorin: provide two argument types for operator");
+
+ if (argtypes[0] == InvalidOid)
+ oprkind = 'l';
+ else if (argtypes[1] == InvalidOid)
+ oprkind = 'r';
+ else
+ oprkind = 'b';
+
+ clist = OpernameGetCandidates(names, oprkind);
+
+ for (; clist; clist = clist->next)
+ {
+ if (memcmp(clist->args, argtypes, 2 * sizeof(Oid)) == 0)
+ break;
+ }
+
+ if (clist == NULL)
+ elog(ERROR, "No operator with name %s", opr_name_or_oid);
+
+ result = clist->oid;
+
+ PG_RETURN_OID(result);
+}
+
+/*
+ * regoperatorout - converts operator OID to "opr_name(args)"
+ */
+Datum
+regoperatorout(PG_FUNCTION_ARGS)
+{
+ Oid oprid = PG_GETARG_OID(0);
+ char *result;
+ HeapTuple opertup;
+
+ if (oprid == InvalidOid)
+ {
+ result = pstrdup("0");
+ PG_RETURN_CSTRING(result);
+ }
+
+ opertup = SearchSysCache(OPEROID,
+ ObjectIdGetDatum(oprid),
+ 0, 0, 0);
+
+ if (HeapTupleIsValid(opertup))
+ {
+ Form_pg_operator operform = (Form_pg_operator) GETSTRUCT(opertup);
+ char *oprname = NameStr(operform->oprname);
+ char *nspname;
+ FuncCandidateList clist;
+ StringInfoData buf;
+
+ /* XXX no support here for bootstrap mode */
+
+ /*
+ * Would this oper be found (given the right args) by regoperatorin?
+ * If not, we need to qualify it.
+ */
+ clist = OpernameGetCandidates(makeList1(makeString(oprname)),
+ operform->oprkind);
+
+ for (; clist; clist = clist->next)
+ {
+ if (clist->args[0] == operform->oprleft &&
+ clist->args[1] == operform->oprright)
+ break;
+ }
+
+ initStringInfo(&buf);
+
+ if (clist == NULL || clist->oid != oprid)
+ {
+ nspname = get_namespace_name(operform->oprnamespace);
+ appendStringInfo(&buf, "%s.",
+ quote_identifier(nspname));
+ }
+
+ appendStringInfo(&buf, "%s(", oprname);
+
+ if (operform->oprleft)
+ appendStringInfo(&buf, "%s,",
+ format_type_be(operform->oprleft));
+ else
+ appendStringInfo(&buf, "NONE,");
+
+ if (operform->oprright)
+ appendStringInfo(&buf, "%s)",
+ format_type_be(operform->oprright));
+ else
+ appendStringInfo(&buf, "NONE)");
+
+ result = buf.data;
+
+ ReleaseSysCache(opertup);
+ }
+ else
+ {
+ /* If OID doesn't match any pg_operator entry, return it numerically */
+ result = (char *) palloc(NAMEDATALEN);
+ snprintf(result, NAMEDATALEN, "%u", oprid);
}
PG_RETURN_CSTRING(result);
}
+/*
+ * regclassin - converts "classname" to class OID
+ *
+ * We also accept a numeric OID, mostly for historical reasons.
+ *
+ * '-' signifies unknown (OID 0). In all other cases, the input must
+ * match an existing pg_class entry.
+ */
+Datum
+regclassin(PG_FUNCTION_ARGS)
+{
+ char *class_name_or_oid = PG_GETARG_CSTRING(0);
+ Oid result = InvalidOid;
+ List *names;
+
+ /* '-' ? */
+ if (strcmp(class_name_or_oid, "-") == 0)
+ PG_RETURN_OID(InvalidOid);
+
+ /* Numeric OID? */
+ if (class_name_or_oid[0] >= '0' &&
+ class_name_or_oid[0] <= '9' &&
+ strspn(class_name_or_oid, "0123456789") == strlen(class_name_or_oid))
+ {
+ Oid searchOid;
+
+ searchOid = DatumGetObjectId(DirectFunctionCall1(oidin,
+ CStringGetDatum(class_name_or_oid)));
+ result = GetSysCacheOid(RELOID,
+ ObjectIdGetDatum(searchOid),
+ 0, 0, 0);
+ if (!OidIsValid(result))
+ elog(ERROR, "No class with oid %s", class_name_or_oid);
+ PG_RETURN_OID(result);
+ }
+
+ /* Else it's a name, possibly schema-qualified */
+
+ /*
+ * In bootstrap mode we assume the given name is not schema-qualified,
+ * and just search pg_class for a match. This is needed for
+ * initializing other system catalogs (pg_namespace may not exist yet,
+ * and certainly there are no schemas other than pg_catalog).
+ */
+ if (IsBootstrapProcessingMode())
+ {
+ Relation hdesc;
+ ScanKeyData skey[1];
+ SysScanDesc sysscan;
+ HeapTuple tuple;
+
+ ScanKeyEntryInitialize(&skey[0], 0x0,
+ (AttrNumber) Anum_pg_class_relname,
+ (RegProcedure) F_NAMEEQ,
+ CStringGetDatum(class_name_or_oid));
+
+ hdesc = heap_openr(RelationRelationName, AccessShareLock);
+ sysscan = systable_beginscan(hdesc, ClassNameNspIndex, true,
+ SnapshotNow, 1, skey);
+
+ if (HeapTupleIsValid(tuple = systable_getnext(sysscan)))
+ result = tuple->t_data->t_oid;
+ else
+ elog(ERROR, "No class with name %s", class_name_or_oid);
+
+ /* We assume there can be only one match */
+
+ systable_endscan(sysscan);
+ heap_close(hdesc, AccessShareLock);
+
+ PG_RETURN_OID(result);
+ }
+
+ /*
+ * Normal case: parse the name into components and see if it
+ * matches any pg_class entries in the current search path.
+ */
+ names = stringToQualifiedNameList(class_name_or_oid, "regclassin");
+
+ result = RangeVarGetRelid(makeRangeVarFromNameList(names), false);
+
+ PG_RETURN_OID(result);
+}
+
+/*
+ * regclassout - converts class OID to "class_name"
+ */
+Datum
+regclassout(PG_FUNCTION_ARGS)
+{
+ Oid classid = PG_GETARG_OID(0);
+ char *result;
+ HeapTuple classtup;
+
+ if (classid == InvalidOid)
+ {
+ result = pstrdup("-");
+ PG_RETURN_CSTRING(result);
+ }
+
+ classtup = SearchSysCache(RELOID,
+ ObjectIdGetDatum(classid),
+ 0, 0, 0);
+
+ if (HeapTupleIsValid(classtup))
+ {
+ Form_pg_class classform = (Form_pg_class) GETSTRUCT(classtup);
+ char *classname = NameStr(classform->relname);
+
+ /*
+ * In bootstrap mode, skip the fancy namespace stuff and just
+ * return the class name. (This path is only needed for debugging
+ * output anyway.)
+ */
+ if (IsBootstrapProcessingMode())
+ {
+ result = pstrdup(classname);
+ }
+ else
+ {
+ char *nspname;
+
+ /*
+ * Would this class be found by regclassin?
+ * If not, qualify it.
+ */
+ if (RelnameGetRelid(classname) == classid)
+ nspname = NULL;
+ else
+ nspname = get_namespace_name(classform->relnamespace);
+
+ result = quote_qualified_identifier(nspname, classname);
+ }
+
+ ReleaseSysCache(classtup);
+ }
+ else
+ {
+ /* If OID doesn't match any pg_class entry, return it numerically */
+ result = (char *) palloc(NAMEDATALEN);
+ snprintf(result, NAMEDATALEN, "%u", classid);
+ }
+
+ PG_RETURN_CSTRING(result);
+}
+
+
+/*
+ * regtypein - converts "typename" to type OID
+ *
+ * We also accept a numeric OID, mostly for historical reasons.
+ *
+ * '-' signifies unknown (OID 0). In all other cases, the input must
+ * match an existing pg_type entry.
+ *
+ * In bootstrap mode the name must just equal some existing name in pg_type.
+ * In normal mode the type name can be specified using the full type syntax
+ * recognized by the parser; for example, DOUBLE PRECISION and INTEGER[] will
+ * work and be translated to the correct type names. (We ignore any typmod
+ * info generated by the parser, however.)
+ */
+Datum
+regtypein(PG_FUNCTION_ARGS)
+{
+ char *typ_name_or_oid = PG_GETARG_CSTRING(0);
+ Oid result = InvalidOid;
+ int32 typmod;
+
+ /* '-' ? */
+ if (strcmp(typ_name_or_oid, "-") == 0)
+ PG_RETURN_OID(InvalidOid);
+
+ /* Numeric OID? */
+ if (typ_name_or_oid[0] >= '0' &&
+ typ_name_or_oid[0] <= '9' &&
+ strspn(typ_name_or_oid, "0123456789") == strlen(typ_name_or_oid))
+ {
+ Oid searchOid;
+
+ searchOid = DatumGetObjectId(DirectFunctionCall1(oidin,
+ CStringGetDatum(typ_name_or_oid)));
+ result = GetSysCacheOid(TYPEOID,
+ ObjectIdGetDatum(searchOid),
+ 0, 0, 0);
+ if (!OidIsValid(result))
+ elog(ERROR, "No type with oid %s", typ_name_or_oid);
+ PG_RETURN_OID(result);
+ }
+
+ /* Else it's a type name, possibly schema-qualified or decorated */
+
+ /*
+ * In bootstrap mode we assume the given name is not schema-qualified,
+ * and just search pg_type for a match. This is needed for
+ * initializing other system catalogs (pg_namespace may not exist yet,
+ * and certainly there are no schemas other than pg_catalog).
+ */
+ if (IsBootstrapProcessingMode())
+ {
+ Relation hdesc;
+ ScanKeyData skey[1];
+ SysScanDesc sysscan;
+ HeapTuple tuple;
+
+ ScanKeyEntryInitialize(&skey[0], 0x0,
+ (AttrNumber) Anum_pg_type_typname,
+ (RegProcedure) F_NAMEEQ,
+ CStringGetDatum(typ_name_or_oid));
+
+ hdesc = heap_openr(TypeRelationName, AccessShareLock);
+ sysscan = systable_beginscan(hdesc, TypeNameNspIndex, true,
+ SnapshotNow, 1, skey);
+
+ if (HeapTupleIsValid(tuple = systable_getnext(sysscan)))
+ result = tuple->t_data->t_oid;
+ else
+ elog(ERROR, "No type with name %s", typ_name_or_oid);
+
+ /* We assume there can be only one match */
+
+ systable_endscan(sysscan);
+ heap_close(hdesc, AccessShareLock);
+
+ PG_RETURN_OID(result);
+ }
+
+ /*
+ * Normal case: invoke the full parser to deal with special cases
+ * such as array syntax.
+ */
+ parseTypeString(typ_name_or_oid, &result, &typmod);
+
+ PG_RETURN_OID(result);
+}
+
+/*
+ * regtypeout - converts type OID to "typ_name"
+ */
+Datum
+regtypeout(PG_FUNCTION_ARGS)
+{
+ Oid typid = PG_GETARG_OID(0);
+ char *result;
+ HeapTuple typetup;
+
+ if (typid == InvalidOid)
+ {
+ result = pstrdup("-");
+ PG_RETURN_CSTRING(result);
+ }
+
+ typetup = SearchSysCache(TYPEOID,
+ ObjectIdGetDatum(typid),
+ 0, 0, 0);
+
+ if (HeapTupleIsValid(typetup))
+ {
+ Form_pg_type typeform = (Form_pg_type) GETSTRUCT(typetup);
+ char *typname = NameStr(typeform->typname);
+
+ /*
+ * In bootstrap mode, skip the fancy namespace stuff and just
+ * return the type name. (This path is only needed for debugging
+ * output anyway.)
+ */
+ if (IsBootstrapProcessingMode())
+ {
+ result = pstrdup(typname);
+ }
+ else
+ {
+ char *nspname;
+
+ /*
+ * Would this type be found by regtypein?
+ * If not, qualify it.
+ *
+ * XXX shouldn't we use format_type instead?
+ */
+ if (TypenameGetTypid(typname) == typid)
+ nspname = NULL;
+ else
+ nspname = get_namespace_name(typeform->typnamespace);
+
+ result = quote_qualified_identifier(nspname, typname);
+ }
+
+ ReleaseSysCache(typetup);
+ }
+ else
+ {
+ /* If OID doesn't match any pg_type entry, return it numerically */
+ result = (char *) palloc(NAMEDATALEN);
+ snprintf(result, NAMEDATALEN, "%u", typid);
+ }
+
+ PG_RETURN_CSTRING(result);
+}
+
/*****************************************************************************
- * PUBLIC ROUTINES *
+ * SUPPORT ROUTINES *
*****************************************************************************/
-/* regproctooid()
- * Lowercase version of RegprocToOid() to allow case-insensitive SQL.
- * Define RegprocToOid() as a macro in builtins.h.
- * Referenced in pg_proc.h. - tgl 97/04/26
+/*
+ * Given a C string, parse it into a qualified-name list.
*/
-Datum
-regproctooid(PG_FUNCTION_ARGS)
+static List *
+stringToQualifiedNameList(const char *string, const char *caller)
{
- RegProcedure rp = PG_GETARG_OID(0);
+ char *rawname;
+ List *result = NIL;
+ List *namelist;
+ List *l;
+
+ /* We need a modifiable copy of the input string. */
+ rawname = pstrdup(string);
+
+ if (!SplitIdentifierString(rawname, '.', &namelist))
+ elog(ERROR, "%s: invalid name syntax", caller);
+
+ if (namelist == NIL)
+ elog(ERROR, "%s: invalid name syntax", caller);
+
+ foreach(l, namelist)
+ {
+ char *curname = (char *) lfirst(l);
- PG_RETURN_OID((Oid) rp);
+ result = lappend(result, makeString(pstrdup(curname)));
+ }
+
+ pfree(rawname);
+ freeList(namelist);
+
+ return result;
}
-/* (see int.c for comparison/operation routines) */
+/*
+ * Given a C string, parse it into a qualified function or operator name
+ * followed by a parenthesized list of type names. Reduce the
+ * type names to an array of OIDs (returned into *nargs and *argtypes;
+ * the argtypes array should be of size FUNC_MAX_ARGS). The function or
+ * operator name is returned to *names as a List of Strings.
+ *
+ * NONE is accepted as a placeholder for OID 0 if allow_none is true.
+ */
+static void
+parseNameAndArgTypes(const char *string, const char *caller, bool allow_none,
+ List **names, int *nargs, Oid *argtypes)
+{
+ char *rawname;
+ char *ptr;
+ char *ptr2;
+ char *typename;
+ bool in_quote;
+ bool had_comma;
+ int paren_count;
+ Oid typeid;
+ int32 typmod;
+
+ /* We need a modifiable copy of the input string. */
+ rawname = pstrdup(string);
+
+ /* Scan to find the expected left paren; mustn't be quoted */
+ in_quote = false;
+ for (ptr = rawname; *ptr; ptr++)
+ {
+ if (*ptr == '"')
+ in_quote = !in_quote;
+ else if (*ptr == '(' && !in_quote)
+ break;
+ }
+ if (*ptr == '\0')
+ elog(ERROR, "%s: expected a left parenthesis", caller);
+
+ /* Separate the name and parse it into a list */
+ *ptr++ = '\0';
+ *names = stringToQualifiedNameList(rawname, caller);
+
+ /* Check for the trailing right parenthesis and remove it */
+ ptr2 = ptr + strlen(ptr);
+ while (--ptr2 > ptr)
+ {
+ if (!isspace((unsigned char) *ptr2))
+ break;
+ }
+ if (*ptr2 != ')')
+ elog(ERROR, "%s: expected a right parenthesis", caller);
+ *ptr2 = '\0';
+
+ /* Separate the remaining string into comma-separated type names */
+ *nargs = 0;
+ had_comma = false;
+
+ for (;;)
+ {
+ /* allow leading whitespace */
+ while (isspace((unsigned char) *ptr))
+ ptr++;
+ if (*ptr == '\0')
+ {
+ /* End of string. Okay unless we had a comma before. */
+ if (had_comma)
+ elog(ERROR, "%s: expected a type name", caller);
+ break;
+ }
+ typename = ptr;
+ /* Find end of type name --- end of string or comma */
+ /* ... but not a quoted or parenthesized comma */
+ in_quote = false;
+ paren_count = 0;
+ for (; *ptr; ptr++)
+ {
+ if (*ptr == '"')
+ in_quote = !in_quote;
+ else if (*ptr == ',' && !in_quote && paren_count == 0)
+ break;
+ else if (!in_quote)
+ {
+ switch (*ptr)
+ {
+ case '(':
+ case '[':
+ paren_count++;
+ break;
+ case ')':
+ case ']':
+ paren_count--;
+ break;
+ }
+ }
+ }
+ if (in_quote || paren_count != 0)
+ elog(ERROR, "%s: improper type name", caller);
+ ptr2 = ptr;
+ if (*ptr == ',')
+ {
+ had_comma = true;
+ *ptr++ = '\0';
+ }
+ else
+ {
+ had_comma = false;
+ Assert(*ptr == '\0');
+ }
+ /* Lop off trailing whitespace */
+ while (--ptr2 >= typename)
+ {
+ if (!isspace((unsigned char) *ptr2))
+ break;
+ *ptr2 = '\0';
+ }
+
+ if (allow_none && strcasecmp(typename, "none") == 0)
+ {
+ /* Report NONE as OID 0 */
+ typeid = InvalidOid;
+ typmod = -1;
+ }
+ else
+ {
+ /* Use full parser to resolve the type name */
+ parseTypeString(typename, &typeid, &typmod);
+ }
+ if (*nargs >= FUNC_MAX_ARGS)
+ elog(ERROR, "%s: too many argument datatypes", caller);
+ argtypes[*nargs] = typeid;
+ (*nargs)++;
+ }
+
+ pfree(rawname);
+}
* back to source text
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.98 2002/04/19 23:13:54 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.99 2002/04/25 02:56:55 tgl Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
static void get_utility_query_def(Query *query, deparse_context *context);
static void get_basic_select_query(Query *query, deparse_context *context);
static void get_setop_query(Node *setOp, Query *query,
- deparse_context *context, bool toplevel);
+ deparse_context *context);
static void get_rule_sortgroupclause(SortClause *srt, List *tlist,
bool force_colno,
deparse_context *context);
static void get_opclass_name(Oid opclass, Oid actual_datatype,
StringInfo buf);
static bool tleIsArrayAssign(TargetEntry *tle);
-static char *quote_identifier(char *ident);
static char *get_relid_attribute_name(Oid relid, AttrNumber attnum);
#define only_marker(rte) ((rte)->inh ? "" : "ONLY ")
*/
if (query->setOperations)
{
- get_setop_query(query->setOperations, query, context, true);
+ get_setop_query(query->setOperations, query, context);
/* ORDER BY clauses must be simple in this case */
force_colno = true;
}
}
static void
-get_setop_query(Node *setOp, Query *query, deparse_context *context,
- bool toplevel)
+get_setop_query(Node *setOp, Query *query, deparse_context *context)
{
StringInfo buf = context->buf;
{
SetOperationStmt *op = (SetOperationStmt *) setOp;
- /*
- * Must suppress parens at top level of a setop tree because of
- * grammar limitations...
- */
- if (!toplevel)
- appendStringInfo(buf, "(");
- get_setop_query(op->larg, query, context, false);
+ appendStringInfo(buf, "((");
+ get_setop_query(op->larg, query, context);
switch (op->op)
{
case SETOP_UNION:
- appendStringInfo(buf, " UNION ");
+ appendStringInfo(buf, ") UNION ");
break;
case SETOP_INTERSECT:
- appendStringInfo(buf, " INTERSECT ");
+ appendStringInfo(buf, ") INTERSECT ");
break;
case SETOP_EXCEPT:
- appendStringInfo(buf, " EXCEPT ");
+ appendStringInfo(buf, ") EXCEPT ");
break;
default:
elog(ERROR, "get_setop_query: unexpected set op %d",
(int) op->op);
}
if (op->all)
- appendStringInfo(buf, "ALL ");
- get_setop_query(op->rarg, query, context, false);
- if (!toplevel)
- appendStringInfo(buf, ")");
+ appendStringInfo(buf, "ALL (");
+ else
+ appendStringInfo(buf, "(");
+ get_setop_query(op->rarg, query, context);
+ appendStringInfo(buf, "))");
}
else
{
* space-wasteful but well worth it for notational simplicity.
* ----------
*/
-static char *
-quote_identifier(char *ident)
+const char *
+quote_identifier(const char *ident)
{
/*
* Can avoid quoting if ident starts with a lowercase letter and
safe = (ident[0] >= 'a' && ident[0] <= 'z');
if (safe)
{
- char *ptr;
+ const char *ptr;
for (ptr = ident + 1; *ptr; ptr++)
{
* Note: ScanKeywordLookup() does case-insensitive comparison, but
* that's fine, since we already know we have all-lower-case.
*/
- if (ScanKeywordLookup(ident) != NULL)
+ if (ScanKeywordLookup((char *) ident) != NULL)
safe = false;
}
}
/* ----------
+ * quote_qualified_identifier - Quote a possibly-qualified identifier
+ *
+ * Return a name of the form namespace.ident, or just ident if namespace
+ * is NULL, quoting each component if necessary. The result is palloc'd.
+ * ----------
+ */
+char *
+quote_qualified_identifier(const char *namespace,
+ const char *ident)
+{
+ StringInfoData buf;
+
+ initStringInfo(&buf);
+ if (namespace)
+ appendStringInfo(&buf, "%s.", quote_identifier(namespace));
+ appendStringInfo(&buf, "%s", quote_identifier(ident));
+ return buf.data;
+}
+
+/* ----------
* get_relid_attribute_name
* Get an attribute name by its relations Oid and its attnum
*
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.109 2002/04/21 19:48:13 thomas Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.110 2002/04/25 02:56:55 tgl Exp $
*
*-------------------------------------------------------------------------
*/
case NUMERICOID:
case OIDOID:
case REGPROCOID:
+ case REGPROCEDUREOID:
+ case REGOPEROID:
+ case REGOPERATOROID:
+ case REGCLASSOID:
+ case REGTYPEOID:
*scaledvalue = convert_numeric_to_scalar(value, valuetypid);
*scaledlobound = convert_numeric_to_scalar(lobound, boundstypid);
*scaledhibound = convert_numeric_to_scalar(hibound, boundstypid);
value));
case OIDOID:
case REGPROCOID:
+ case REGPROCEDUREOID:
+ case REGOPEROID:
+ case REGOPERATOROID:
+ case REGCLASSOID:
+ case REGTYPEOID:
/* we can treat OIDs as integers... */
return (double) DatumGetObjectId(value);
}
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/varlena.c,v 1.84 2002/04/24 02:12:53 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/varlena.c,v 1.85 2002/04/25 02:56:56 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "utils/builtins.h"
#include "utils/pg_locale.h"
+
+typedef struct varlena unknown;
+
+#define DatumGetUnknownP(X) ((unknown *) PG_DETOAST_DATUM(X))
+#define PG_GETARG_UNKNOWN_P(n) DatumGetUnknownP(PG_GETARG_DATUM(n))
+#define PG_RETURN_UNKNOWN_P(x) PG_RETURN_POINTER(x)
+
static int text_cmp(text *arg1, text *arg2);
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/cache/catcache.c,v 1.94 2002/04/06 06:59:22 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/cache/catcache.c,v 1.95 2002/04/25 02:56:56 tgl Exp $
*
*-------------------------------------------------------------------------
*/
return hashint4;
case TEXTOID:
return hashvarlena;
- case REGPROCOID:
case OIDOID:
+ case REGPROCOID:
+ case REGPROCEDUREOID:
+ case REGOPEROID:
+ case REGOPERATOROID:
+ case REGCLASSOID:
+ case REGTYPEOID:
return hashoid;
case OIDVECTOROID:
return hashoidvector;
*
* Copyright 2000 by PostgreSQL Global Development Group
*
- * $Header: /cvsroot/pgsql/src/bin/psql/describe.c,v 1.52 2002/04/24 06:17:04 petere Exp $
+ * $Header: /cvsroot/pgsql/src/bin/psql/describe.c,v 1.53 2002/04/25 02:56:56 tgl Exp $
*/
#include "postgres_fe.h"
#include "describe.h"
/* Operator descriptions (must get comment via associated function) */
"UNION ALL\n"
- " SELECT RegprocToOid(o.oprcode) as oid,\n"
+ " SELECT CAST(o.oprcode AS oid) as oid,\n"
" (SELECT oid FROM pg_class WHERE relname = 'pg_proc') as tableoid,\n"
" CAST(o.oprname AS text) as name, CAST('%s' AS text) as object\n"
" FROM pg_operator o\n"
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: c.h,v 1.118 2002/04/24 02:12:53 momjian Exp $
+ * $Id: c.h,v 1.119 2002/04/25 02:56:56 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/* typedef Oid is in postgres_ext.h */
-/* unfortunately, both regproc and RegProcedure are used */
+/*
+ * regproc is the type name used in the include/catalog headers, but
+ * RegProcedure is the preferred name in C code.
+ */
typedef Oid regproc;
-typedef Oid RegProcedure;
+typedef regproc RegProcedure;
typedef uint32 TransactionId;
*/
typedef struct varlena bytea;
typedef struct varlena text;
-typedef struct varlena unknown;
typedef struct varlena BpChar; /* blank-padded char, ie SQL char(n) */
typedef struct varlena VarChar; /* var-length char, ie SQL varchar(n) */
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: catversion.h,v 1.125 2002/04/24 05:23:14 momjian Exp $
+ * $Id: catversion.h,v 1.126 2002/04/25 02:56:56 tgl Exp $
*
*-------------------------------------------------------------------------
*/
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 200204241
+#define CATALOG_VERSION_NO 200204242
#endif
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: namespace.h,v 1.9 2002/04/17 20:57:56 tgl Exp $
+ * $Id: namespace.h,v 1.10 2002/04/25 02:56:56 tgl Exp $
*
*-------------------------------------------------------------------------
*/
* found by namespace lookup. Each function/operator is identified
* by OID and by argument types; the list must be pruned by type
* resolution rules that are embodied in the parser, not here.
- * The number of arguments is assumed to be known a priori.
*/
typedef struct _FuncCandidateList
{
struct _FuncCandidateList *next;
int pathpos; /* for internal use of namespace lookup */
Oid oid; /* the function or operator's OID */
+ int nargs; /* number of arg types returned */
Oid args[1]; /* arg types --- VARIABLE LENGTH ARRAY */
} *FuncCandidateList; /* VARIABLE LENGTH STRUCT */
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: pg_namespace.h,v 1.5 2002/04/21 00:26:43 tgl Exp $
+ * $Id: pg_namespace.h,v 1.6 2002/04/25 02:56:56 tgl Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
DATA(insert OID = 99 ( "pg_toast" PGUID "{=}" ));
DESCR("Reserved namespace for TOAST tables");
#define PG_TOAST_NAMESPACE 99
-DATA(insert OID = 2071 ( "public" PGUID "{=UC}" ));
+DATA(insert OID = 2200 ( "public" PGUID "{=UC}" ));
DESCR("Standard public namespace");
-#define PG_PUBLIC_NAMESPACE 2071
+#define PG_PUBLIC_NAMESPACE 2200
/*
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: pg_operator.h,v 1.103 2002/04/21 19:48:23 thomas Exp $
+ * $Id: pg_operator.h,v 1.104 2002/04/25 02:56:56 tgl Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
DATA(insert OID = 2067 ( "-" PGNSP PGUID 0 b t f 1114 1114 1186 0 0 0 0 0 0 timestamp_mi - - ));
DATA(insert OID = 2068 ( "-" PGNSP PGUID 0 b t f 1114 1186 1114 0 0 0 0 0 0 timestamp_mi_span - - ));
+/* array equality operators */
+DATA(insert OID = 2222 ( "=" PGNSP PGUID 0 b t f 2207 2207 16 2222 0 0 0 0 0 array_eq eqsel eqjoinsel ));
+DATA(insert OID = 2223 ( "=" PGNSP PGUID 0 b t f 2208 2208 16 2223 0 0 0 0 0 array_eq eqsel eqjoinsel ));
+DATA(insert OID = 2224 ( "=" PGNSP PGUID 0 b t f 2209 2209 16 2224 0 0 0 0 0 array_eq eqsel eqjoinsel ));
+DATA(insert OID = 2225 ( "=" PGNSP PGUID 0 b t f 2210 2210 16 2225 0 0 0 0 0 array_eq eqsel eqjoinsel ));
+DATA(insert OID = 2226 ( "=" PGNSP PGUID 0 b t f 2211 2211 16 2226 0 0 0 0 0 array_eq eqsel eqjoinsel ));
+
+DATA(insert OID = 2227 ( "=" PGNSP PGUID 0 b t f 629 629 16 2227 0 0 0 0 0 array_eq eqsel eqjoinsel ));
+DATA(insert OID = 2228 ( "=" PGNSP PGUID 0 b t f 651 651 16 2228 0 0 0 0 0 array_eq eqsel eqjoinsel ));
+DATA(insert OID = 2229 ( "=" PGNSP PGUID 0 b t f 719 719 16 2229 0 0 0 0 0 array_eq eqsel eqjoinsel ));
+DATA(insert OID = 2230 ( "=" PGNSP PGUID 0 b t f 791 791 16 2230 0 0 0 0 0 array_eq eqsel eqjoinsel ));
+DATA(insert OID = 2231 ( "=" PGNSP PGUID 0 b t f 1014 1014 16 2231 0 0 0 0 0 array_eq eqsel eqjoinsel ));
+DATA(insert OID = 2232 ( "=" PGNSP PGUID 0 b t f 1015 1015 16 2232 0 0 0 0 0 array_eq eqsel eqjoinsel ));
+DATA(insert OID = 2233 ( "=" PGNSP PGUID 0 b t f 1016 1016 16 2233 0 0 0 0 0 array_eq eqsel eqjoinsel ));
+DATA(insert OID = 2234 ( "=" PGNSP PGUID 0 b t f 1040 1040 16 2234 0 0 0 0 0 array_eq eqsel eqjoinsel ));
+DATA(insert OID = 2235 ( "=" PGNSP PGUID 0 b t f 1041 1041 16 2235 0 0 0 0 0 array_eq eqsel eqjoinsel ));
+DATA(insert OID = 2236 ( "=" PGNSP PGUID 0 b t f 1115 1115 16 2236 0 0 0 0 0 array_eq eqsel eqjoinsel ));
+DATA(insert OID = 2237 ( "=" PGNSP PGUID 0 b t f 1182 1182 16 2237 0 0 0 0 0 array_eq eqsel eqjoinsel ));
+DATA(insert OID = 2238 ( "=" PGNSP PGUID 0 b t f 1183 1183 16 2238 0 0 0 0 0 array_eq eqsel eqjoinsel ));
+DATA(insert OID = 2239 ( "=" PGNSP PGUID 0 b t f 1185 1185 16 2239 0 0 0 0 0 array_eq eqsel eqjoinsel ));
+DATA(insert OID = 2240 ( "=" PGNSP PGUID 0 b t f 1187 1187 16 2240 0 0 0 0 0 array_eq eqsel eqjoinsel ));
+DATA(insert OID = 2241 ( "=" PGNSP PGUID 0 b t f 1231 1231 16 2241 0 0 0 0 0 array_eq eqsel eqjoinsel ));
+DATA(insert OID = 2242 ( "=" PGNSP PGUID 0 b t f 1270 1270 16 2242 0 0 0 0 0 array_eq eqsel eqjoinsel ));
+DATA(insert OID = 2243 ( "=" PGNSP PGUID 0 b t f 1561 1561 16 2243 0 0 0 0 0 array_eq eqsel eqjoinsel ));
+DATA(insert OID = 2244 ( "=" PGNSP PGUID 0 b t f 1563 1563 16 2244 0 0 0 0 0 array_eq eqsel eqjoinsel ));
+DATA(insert OID = 2245 ( "=" PGNSP PGUID 0 b t f 2201 2201 16 2245 0 0 0 0 0 array_eq eqsel eqjoinsel ));
+
/*
* function prototypes
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: pg_proc.h,v 1.232 2002/04/24 05:22:20 momjian Exp $
+ * $Id: pg_proc.h,v 1.233 2002/04/25 02:56:56 tgl Exp $
*
* NOTES
* The script catalog/genbki.sh reads this file and generates .bki
DATA(insert OID = 964 ( lo_unlink PGNSP PGUID 12 f t f t f v 1 23 "26" 100 0 0 100 lo_unlink - _null_ ));
DESCR("large object unlink(delete)");
-DATA(insert OID = 972 ( regproctooid PGNSP PGUID 12 f t f t f i 1 26 "24" 100 0 0 100 regproctooid - _null_ ));
-DESCR("get oid for regproc");
DATA(insert OID = 973 ( path_inter PGNSP PGUID 12 f t f t f i 2 16 "602 602" 100 0 0 100 path_inter - _null_ ));
DESCR("paths intersect?");
DATA(insert OID = 2159 ( stddev PGNSP PGUID 12 t t f f f i 1 1700 "1700" 100 0 0 100 aggregate_dummy - _null_ ));
+DATA(insert OID = 2212 ( regprocedurein PGNSP PGUID 12 f t f t f s 1 2202 "0" 100 0 0 100 regprocedurein - _null_ ));
+DESCR("(internal)");
+DATA(insert OID = 2213 ( regprocedureout PGNSP PGUID 12 f t f t f s 1 23 "0" 100 0 0 100 regprocedureout - _null_ ));
+DESCR("(internal)");
+DATA(insert OID = 2214 ( regoperin PGNSP PGUID 12 f t f t f s 1 2203 "0" 100 0 0 100 regoperin - _null_ ));
+DESCR("(internal)");
+DATA(insert OID = 2215 ( regoperout PGNSP PGUID 12 f t f t f s 1 23 "0" 100 0 0 100 regoperout - _null_ ));
+DESCR("(internal)");
+DATA(insert OID = 2216 ( regoperatorin PGNSP PGUID 12 f t f t f s 1 2204 "0" 100 0 0 100 regoperatorin - _null_ ));
+DESCR("(internal)");
+DATA(insert OID = 2217 ( regoperatorout PGNSP PGUID 12 f t f t f s 1 23 "0" 100 0 0 100 regoperatorout - _null_ ));
+DESCR("(internal)");
+DATA(insert OID = 2218 ( regclassin PGNSP PGUID 12 f t f t f s 1 2205 "0" 100 0 0 100 regclassin - _null_ ));
+DESCR("(internal)");
+DATA(insert OID = 2219 ( regclassout PGNSP PGUID 12 f t f t f s 1 23 "0" 100 0 0 100 regclassout - _null_ ));
+DESCR("(internal)");
+DATA(insert OID = 2220 ( regtypein PGNSP PGUID 12 f t f t f s 1 2206 "0" 100 0 0 100 regtypein - _null_ ));
+DESCR("(internal)");
+DATA(insert OID = 2221 ( regtypeout PGNSP PGUID 12 f t f t f s 1 23 "0" 100 0 0 100 regtypeout - _null_ ));
+DESCR("(internal)");
+
+
/*
* Symbolic values for provolatile column: these indicate whether the result
* of a function is dependent *only* on the values of its explicit arguments,
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: pg_type.h,v 1.121 2002/04/24 02:12:53 momjian Exp $
+ * $Id: pg_type.h,v 1.122 2002/04/25 02:56:56 tgl Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
DESCR("-2 billion to 2 billion integer, 4-byte storage");
#define INT4OID 23
-DATA(insert OID = 24 ( regproc PGNSP PGUID 4 16 t b t \054 0 0 regprocin regprocout regprocin regprocout i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 24 ( regproc PGNSP PGUID 4 -1 t b t \054 0 0 regprocin regprocout regprocin regprocout i p f 0 -1 0 _null_ _null_ ));
DESCR("registered procedure");
#define REGPROCOID 24
DATA(insert OID = 1114 ( timestamp PGNSP PGUID 8 47 f b t \054 0 0 timestamp_in timestamp_out timestamp_in timestamp_out d p f 0 -1 0 _null_ _null_ ));
DESCR("date and time");
#define TIMESTAMPOID 1114
-DATA(insert OID = 1115 ( _timestamp PGNSP PGUID -1 -1 f b t \054 0 1184 array_in array_out array_in array_out d x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1115 ( _timestamp PGNSP PGUID -1 -1 f b t \054 0 1114 array_in array_out array_in array_out d x f 0 -1 0 _null_ _null_ ));
DATA(insert OID = 1182 ( _date PGNSP PGUID -1 -1 f b t \054 0 1082 array_in array_out array_in array_out i x f 0 -1 0 _null_ _null_ ));
DATA(insert OID = 1183 ( _time PGNSP PGUID -1 -1 f b t \054 0 1083 array_in array_out array_in array_out d x f 0 -1 0 _null_ _null_ ));
DATA(insert OID = 1184 ( timestamptz PGNSP PGUID 8 47 f b t \054 0 0 timestamptz_in timestamptz_out timestamptz_in timestamptz_out d p f 0 -1 0 _null_ _null_ ));
DESCR("reference cursor (portal name)");
#define REFCURSOROID 1790
-/* OIDS 2000 - 2099 */
-DATA(insert OID = 2019 ( _refcursor PGNSP PGUID -1 -1 f b t \054 0 1790 array_in array_out array_in array_out i x f 0 -1 0 _null_ _null_ ));
+/* OIDS 2200 - 2299 */
+DATA(insert OID = 2201 ( _refcursor PGNSP PGUID -1 -1 f b t \054 0 1790 array_in array_out array_in array_out i x f 0 -1 0 _null_ _null_ ));
+
+DATA(insert OID = 2202 ( regprocedure PGNSP PGUID 4 -1 t b t \054 0 0 regprocedurein regprocedureout regprocedurein regprocedureout i p f 0 -1 0 _null_ _null_ ));
+DESCR("registered procedure (with args)");
+#define REGPROCEDUREOID 2202
+
+DATA(insert OID = 2203 ( regoper PGNSP PGUID 4 -1 t b t \054 0 0 regoperin regoperout regoperin regoperout i p f 0 -1 0 _null_ _null_ ));
+DESCR("registered operator");
+#define REGOPEROID 2203
+
+DATA(insert OID = 2204 ( regoperator PGNSP PGUID 4 -1 t b t \054 0 0 regoperatorin regoperatorout regoperatorin regoperatorout i p f 0 -1 0 _null_ _null_ ));
+DESCR("registered operator (with args)");
+#define REGOPERATOROID 2204
+
+DATA(insert OID = 2205 ( regclass PGNSP PGUID 4 -1 t b t \054 0 0 regclassin regclassout regclassin regclassout i p f 0 -1 0 _null_ _null_ ));
+DESCR("registered class");
+#define REGCLASSOID 2205
+
+DATA(insert OID = 2206 ( regtype PGNSP PGUID 4 -1 t b t \054 0 0 regtypein regtypeout regtypein regtypeout i p f 0 -1 0 _null_ _null_ ));
+DESCR("registered type");
+#define REGTYPEOID 2206
+
+DATA(insert OID = 2207 ( _regprocedure PGNSP PGUID -1 -1 f b t \054 0 2202 array_in array_out array_in array_out i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 2208 ( _regoper PGNSP PGUID -1 -1 f b t \054 0 2203 array_in array_out array_in array_out i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 2209 ( _regoperator PGNSP PGUID -1 -1 f b t \054 0 2204 array_in array_out array_in array_out i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 2210 ( _regclass PGNSP PGUID -1 -1 f b t \054 0 2205 array_in array_out array_in array_out i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 2211 ( _regtype PGNSP PGUID -1 -1 f b t \054 0 2206 array_in array_out array_in array_out i x f 0 -1 0 _null_ _null_ ));
/*
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: fmgr.h,v 1.20 2002/04/24 02:12:53 momjian Exp $
+ * $Id: fmgr.h,v 1.21 2002/04/25 02:56:56 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/* DatumGetFoo macros for varlena types will typically look like this: */
#define DatumGetByteaP(X) ((bytea *) PG_DETOAST_DATUM(X))
#define DatumGetTextP(X) ((text *) PG_DETOAST_DATUM(X))
-#define DatumGetUnknownP(X) ((unknown *) PG_DETOAST_DATUM(X))
#define DatumGetBpCharP(X) ((BpChar *) PG_DETOAST_DATUM(X))
#define DatumGetVarCharP(X) ((VarChar *) PG_DETOAST_DATUM(X))
/* And we also offer variants that return an OK-to-write copy */
/* GETARG macros for varlena types will typically look like this: */
#define PG_GETARG_BYTEA_P(n) DatumGetByteaP(PG_GETARG_DATUM(n))
#define PG_GETARG_TEXT_P(n) DatumGetTextP(PG_GETARG_DATUM(n))
-#define PG_GETARG_UNKNOWN_P(n) DatumGetUnknownP(PG_GETARG_DATUM(n))
#define PG_GETARG_BPCHAR_P(n) DatumGetBpCharP(PG_GETARG_DATUM(n))
#define PG_GETARG_VARCHAR_P(n) DatumGetVarCharP(PG_GETARG_DATUM(n))
/* And we also offer variants that return an OK-to-write copy */
/* RETURN macros for other pass-by-ref types will typically look like this: */
#define PG_RETURN_BYTEA_P(x) PG_RETURN_POINTER(x)
#define PG_RETURN_TEXT_P(x) PG_RETURN_POINTER(x)
-#define PG_RETURN_UNKNOWN_P(x) PG_RETURN_POINTER(x)
#define PG_RETURN_BPCHAR_P(x) PG_RETURN_POINTER(x)
#define PG_RETURN_VARCHAR_P(x) PG_RETURN_POINTER(x)
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: builtins.h,v 1.178 2002/04/24 02:12:53 momjian Exp $
+ * $Id: builtins.h,v 1.179 2002/04/25 02:56:56 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/* regproc.c */
extern Datum regprocin(PG_FUNCTION_ARGS);
extern Datum regprocout(PG_FUNCTION_ARGS);
-extern Datum regproctooid(PG_FUNCTION_ARGS);
-
-/* define macro to replace mixed-case function call - tgl 97/04/27 */
-#define RegprocToOid(rp) ((Oid) (rp))
+extern Datum regprocedurein(PG_FUNCTION_ARGS);
+extern Datum regprocedureout(PG_FUNCTION_ARGS);
+extern Datum regoperin(PG_FUNCTION_ARGS);
+extern Datum regoperout(PG_FUNCTION_ARGS);
+extern Datum regoperatorin(PG_FUNCTION_ARGS);
+extern Datum regoperatorout(PG_FUNCTION_ARGS);
+extern Datum regclassin(PG_FUNCTION_ARGS);
+extern Datum regclassout(PG_FUNCTION_ARGS);
+extern Datum regtypein(PG_FUNCTION_ARGS);
+extern Datum regtypeout(PG_FUNCTION_ARGS);
/* ruleutils.c */
extern Datum pg_get_ruledef(PG_FUNCTION_ARGS);
extern Node *deparse_context_for_relation(const char *aliasname, Oid relid);
extern Node *deparse_context_for_subplan(const char *name, List *tlist,
List *rtable);
+extern const char *quote_identifier(const char *ident);
+extern char *quote_qualified_identifier(const char *namespace,
+ const char *ident);
/* tid.c */
extern void setLastTid(const ItemPointer tid);
--
-- NB: run this test earlier than the create_operator test, because
-- that test creates some bogus operators...
---
--- NOTE hardwired assumptions about standard types:
--- type bool has OID 16
--- type float8 has OID 701
---
-- **************** pg_proc ****************
-- Look for illegal values in pg_proc fields.
-- NOTE: currently there are a few pg_proc entries that have prorettype = 0.
SELECT p1.oid, p1.proname
FROM pg_proc as p1
WHERE (p1.prolang = 0 OR p1.prorettype = 0 OR
- p1.pronargs < 0 OR p1.pronargs > 9)
+ p1.pronargs < 0 OR p1.pronargs > 16)
AND p1.proname !~ '^pl[^_]+_call_handler$'
AND p1.proname !~ '^RI_FKey_'
AND p1.proname !~ 'costestimate$'
t.typname = p1.proname) OR
NOT ((p1.pronargs = 1 AND p1.proargtypes[0] != prorettype) OR
(p1.pronargs = 2 AND p1.proargtypes[0] = prorettype AND
- p1.proargtypes[1] = 23)));
+ p1.proargtypes[1] = 'int4'::regtype)));
oid | proname
-----+---------
(0 rows)
(p1.oprkind != p2.oprkind OR
p1.oprleft != p2.oprleft OR
p1.oprright != p2.oprright OR
- p1.oprresult != 16 OR
- p2.oprresult != 16 OR
+ p1.oprresult != 'bool'::regtype OR
+ p2.oprresult != 'bool'::regtype OR
p1.oid != p2.oprnegate OR
p1.oid = p2.oid);
oid | oprcode | oid | oprcode
p1.oprkind != 'b' OR p2.oprkind != 'b' OR
p1.oprleft != p2.oprleft OR
p1.oprleft != p2.oprright OR
- p1.oprresult != 16 OR
- p2.oprresult != 16 OR
+ p1.oprresult != 'bool'::regtype OR
+ p2.oprresult != 'bool'::regtype OR
p1.oprrsortop = 0);
oid | oprcode | oid | oprcode
-----+---------+-----+---------
p1.oprkind != 'b' OR p2.oprkind != 'b' OR
p1.oprright != p2.oprleft OR
p1.oprright != p2.oprright OR
- p1.oprresult != 16 OR
- p2.oprresult != 16 OR
+ p1.oprresult != 'bool'::regtype OR
+ p2.oprresult != 'bool'::regtype OR
p1.oprlsortop = 0);
oid | oprcode | oid | oprcode
-----+---------+-----+---------
SELECT p1.oid, p1.oprname
FROM pg_operator AS p1
WHERE p1.oprcanhash AND NOT
- (p1.oprkind = 'b' AND p1.oprresult = 16 AND p1.oprleft = p1.oprright AND
- p1.oprname = '=' AND p1.oprcom = p1.oid);
+ (p1.oprkind = 'b' AND p1.oprresult = 'bool'::regtype AND
+ p1.oprleft = p1.oprright AND p1.oprname = '=' AND p1.oprcom = p1.oid);
oid | oprname
------+---------
353 | =
SELECT p1.oid, p1.oprname, p2.oid, p2.proname
FROM pg_operator AS p1, pg_proc AS p2
WHERE p1.oprrest = p2.oid AND
- (p1.oprresult != 16 OR
- p2.prorettype != 701 OR p2.proretset OR
+ (p1.oprresult != 'bool'::regtype OR
+ p2.prorettype != 'float8'::regtype OR p2.proretset OR
p2.pronargs != 4 OR
- p2.proargtypes[0] != 0 OR p2.proargtypes[1] != 26 OR
- p2.proargtypes[2] != 0 OR p2.proargtypes[3] != 23);
+ p2.proargtypes[0] != 0 OR p2.proargtypes[1] != 'oid'::regtype OR
+ p2.proargtypes[2] != 0 OR p2.proargtypes[3] != 'int4'::regtype);
oid | oprname | oid | proname
-----+---------+-----+---------
(0 rows)
SELECT p1.oid, p1.oprname, p2.oid, p2.proname
FROM pg_operator AS p1, pg_proc AS p2
WHERE p1.oprjoin = p2.oid AND
- (p1.oprkind != 'b' OR p1.oprresult != 16 OR
- p2.prorettype != 701 OR p2.proretset OR
+ (p1.oprkind != 'b' OR p1.oprresult != 'bool'::regtype OR
+ p2.prorettype != 'float8'::regtype OR p2.proretset OR
p2.pronargs != 3 OR
- p2.proargtypes[0] != 0 OR p2.proargtypes[1] != 26 OR
+ p2.proargtypes[0] != 0 OR p2.proargtypes[1] != 'oid'::regtype OR
p2.proargtypes[2] != 0);
oid | oprname | oid | proname
-----+---------+-----+---------
SELECT p1.amopclaid, p1.amopopr, p2.oid, p2.oprname
FROM pg_amop AS p1, pg_operator AS p2
WHERE p1.amopopr = p2.oid AND
- (p2.oprkind != 'b' OR p2.oprresult != 16 OR p2.oprleft != p2.oprright);
+ (p2.oprkind != 'b' OR p2.oprresult != 'bool'::regtype OR
+ p2.oprleft != p2.oprright);
amopclaid | amopopr | oid | oprname
-----------+---------+-----+---------
(0 rows)
(p1.typtype != 'b' AND p1.typtype != 'c') OR
NOT p1.typisdefined OR
(p1.typalign != 'c' AND p1.typalign != 's' AND
- p1.typalign != 'i' AND p1.typalign != 'd');
+ p1.typalign != 'i' AND p1.typalign != 'd') OR
+ (p1.typstorage != 'p' AND p1.typstorage != 'x' AND
+ p1.typstorage != 'e' AND p1.typstorage != 'm');
oid | typname
-----+---------
(0 rows)
-----+---------
(0 rows)
+-- Look for "toastable" types that aren't varlena.
+SELECT p1.oid, p1.typname
+FROM pg_type as p1
+WHERE p1.typstorage != 'p' AND
+ (p1.typbyval OR p1.typlen != -1);
+ oid | typname
+-----+---------
+(0 rows)
+
-- Look for complex types that do not have a typrelid entry,
-- or basic types that do.
SELECT p1.oid, p1.typname
-----+---------
(0 rows)
+-- Look for basic types that don't have an array type.
+-- NOTE: as of 7.3, this check finds SET, smgr, and unknown.
+SELECT p1.oid, p1.typname
+FROM pg_type as p1
+WHERE p1.typtype != 'c' AND p1.typname NOT LIKE '\\_%' AND NOT EXISTS
+ (SELECT 1 FROM pg_type as p2
+ WHERE p2.typname = ('_' || p1.typname)::name AND
+ p2.typelem = p1.oid);
+ oid | typname
+-----+---------
+ 32 | SET
+ 210 | smgr
+ 705 | unknown
+(3 rows)
+
+-- Look for array types that don't have an equality operator.
+SELECT p1.oid, p1.typname
+FROM pg_type as p1
+WHERE p1.typtype != 'c' AND p1.typname LIKE '\\_%' AND NOT EXISTS
+ (SELECT 1 FROM pg_operator
+ WHERE oprname = '=' AND oprleft = p1.oid AND oprright = p1.oid);
+ oid | typname
+-----+---------
+(0 rows)
+
-- Conversion routines must be provided except in 'c' entries.
SELECT p1.oid, p1.typname
FROM pg_type as p1
FROM pg_type AS p1, pg_proc AS p2
WHERE p1.typinput = p2.oid AND p1.typtype = 'b' AND
(p2.pronargs != 1 OR p2.proretset) AND
- (p2.pronargs != 3 OR p2.proretset OR p2.proargtypes[2] != 23);
+ (p2.pronargs != 3 OR p2.proretset OR p2.proargtypes[2] != 'int4'::regtype);
oid | typname | oid | proname
-----+---------+-----+---------
(0 rows)
FROM pg_type AS p1, pg_proc AS p2
WHERE p1.typreceive = p2.oid AND p1.typtype = 'b' AND
(p2.pronargs != 1 OR p2.proretset) AND
- (p2.pronargs != 3 OR p2.proretset OR p2.proargtypes[2] != 23);
+ (p2.pronargs != 3 OR p2.proretset OR p2.proargtypes[2] != 'int4'::regtype);
oid | typname | oid | proname
-----+---------+-----+---------
(0 rows)
(0 rows)
-- Cross-check against pg_type entry
+-- NOTE: we allow attstorage to be 'plain' even when typstorage is not;
+-- this is mainly for toast tables.
SELECT p1.attrelid, p1.attname, p2.oid, p2.typname
FROM pg_attribute AS p1, pg_type AS p2
WHERE p1.atttypid = p2.oid AND
(p1.attlen != p2.typlen OR
p1.attalign != p2.typalign OR
- p1.attbyval != p2.typbyval);
+ p1.attbyval != p2.typbyval OR
+ (p1.attstorage != p2.typstorage AND p1.attstorage != 'p'));
attrelid | attname | oid | typname
----------+---------+-----+---------
(0 rows)
--
-- NB: run this test earlier than the create_operator test, because
-- that test creates some bogus operators...
---
--- NOTE hardwired assumptions about standard types:
--- type bool has OID 16
--- type float8 has OID 701
---
-- **************** pg_proc ****************
SELECT p1.oid, p1.proname
FROM pg_proc as p1
WHERE (p1.prolang = 0 OR p1.prorettype = 0 OR
- p1.pronargs < 0 OR p1.pronargs > 9)
+ p1.pronargs < 0 OR p1.pronargs > 16)
AND p1.proname !~ '^pl[^_]+_call_handler$'
AND p1.proname !~ '^RI_FKey_'
AND p1.proname !~ 'costestimate$'
t.typname = p1.proname) OR
NOT ((p1.pronargs = 1 AND p1.proargtypes[0] != prorettype) OR
(p1.pronargs = 2 AND p1.proargtypes[0] = prorettype AND
- p1.proargtypes[1] = 23)));
+ p1.proargtypes[1] = 'int4'::regtype)));
-- **************** pg_operator ****************
(p1.oprkind != p2.oprkind OR
p1.oprleft != p2.oprleft OR
p1.oprright != p2.oprright OR
- p1.oprresult != 16 OR
- p2.oprresult != 16 OR
+ p1.oprresult != 'bool'::regtype OR
+ p2.oprresult != 'bool'::regtype OR
p1.oid != p2.oprnegate OR
p1.oid = p2.oid);
p1.oprkind != 'b' OR p2.oprkind != 'b' OR
p1.oprleft != p2.oprleft OR
p1.oprleft != p2.oprright OR
- p1.oprresult != 16 OR
- p2.oprresult != 16 OR
+ p1.oprresult != 'bool'::regtype OR
+ p2.oprresult != 'bool'::regtype OR
p1.oprrsortop = 0);
SELECT p1.oid, p1.oprcode, p2.oid, p2.oprcode
p1.oprkind != 'b' OR p2.oprkind != 'b' OR
p1.oprright != p2.oprleft OR
p1.oprright != p2.oprright OR
- p1.oprresult != 16 OR
- p2.oprresult != 16 OR
+ p1.oprresult != 'bool'::regtype OR
+ p2.oprresult != 'bool'::regtype OR
p1.oprlsortop = 0);
-- A mergejoinable = operator must have a commutator (usually itself)
SELECT p1.oid, p1.oprname
FROM pg_operator AS p1
WHERE p1.oprcanhash AND NOT
- (p1.oprkind = 'b' AND p1.oprresult = 16 AND p1.oprleft = p1.oprright AND
- p1.oprname = '=' AND p1.oprcom = p1.oid);
+ (p1.oprkind = 'b' AND p1.oprresult = 'bool'::regtype AND
+ p1.oprleft = p1.oprright AND p1.oprname = '=' AND p1.oprcom = p1.oid);
-- In 6.5 we accepted hashable array equality operators when the array element
-- type is hashable. However, what we actually need to make hashjoin work on
SELECT p1.oid, p1.oprname, p2.oid, p2.proname
FROM pg_operator AS p1, pg_proc AS p2
WHERE p1.oprrest = p2.oid AND
- (p1.oprresult != 16 OR
- p2.prorettype != 701 OR p2.proretset OR
+ (p1.oprresult != 'bool'::regtype OR
+ p2.prorettype != 'float8'::regtype OR p2.proretset OR
p2.pronargs != 4 OR
- p2.proargtypes[0] != 0 OR p2.proargtypes[1] != 26 OR
- p2.proargtypes[2] != 0 OR p2.proargtypes[3] != 23);
+ p2.proargtypes[0] != 0 OR p2.proargtypes[1] != 'oid'::regtype OR
+ p2.proargtypes[2] != 0 OR p2.proargtypes[3] != 'int4'::regtype);
-- If oprjoin is set, the operator must be a binary boolean op,
-- and it must link to a proc with the right signature
SELECT p1.oid, p1.oprname, p2.oid, p2.proname
FROM pg_operator AS p1, pg_proc AS p2
WHERE p1.oprjoin = p2.oid AND
- (p1.oprkind != 'b' OR p1.oprresult != 16 OR
- p2.prorettype != 701 OR p2.proretset OR
+ (p1.oprkind != 'b' OR p1.oprresult != 'bool'::regtype OR
+ p2.prorettype != 'float8'::regtype OR p2.proretset OR
p2.pronargs != 3 OR
- p2.proargtypes[0] != 0 OR p2.proargtypes[1] != 26 OR
+ p2.proargtypes[0] != 0 OR p2.proargtypes[1] != 'oid'::regtype OR
p2.proargtypes[2] != 0);
-- **************** pg_aggregate ****************
SELECT p1.amopclaid, p1.amopopr, p2.oid, p2.oprname
FROM pg_amop AS p1, pg_operator AS p2
WHERE p1.amopopr = p2.oid AND
- (p2.oprkind != 'b' OR p2.oprresult != 16 OR p2.oprleft != p2.oprright);
+ (p2.oprkind != 'b' OR p2.oprresult != 'bool'::regtype OR
+ p2.oprleft != p2.oprright);
-- Check that all operators linked to by opclass entries have selectivity
-- estimators. This is not absolutely required, but it seems a reasonable
(p1.typtype != 'b' AND p1.typtype != 'c') OR
NOT p1.typisdefined OR
(p1.typalign != 'c' AND p1.typalign != 's' AND
- p1.typalign != 'i' AND p1.typalign != 'd');
+ p1.typalign != 'i' AND p1.typalign != 'd') OR
+ (p1.typstorage != 'p' AND p1.typstorage != 'x' AND
+ p1.typstorage != 'e' AND p1.typstorage != 'm');
-- Look for "pass by value" types that can't be passed by value.
(p1.typlen != 2 OR p1.typalign != 's') AND
(p1.typlen != 4 OR p1.typalign != 'i');
+-- Look for "toastable" types that aren't varlena.
+
+SELECT p1.oid, p1.typname
+FROM pg_type as p1
+WHERE p1.typstorage != 'p' AND
+ (p1.typbyval OR p1.typlen != -1);
+
-- Look for complex types that do not have a typrelid entry,
-- or basic types that do.
WHERE (p1.typtype = 'c' AND p1.typrelid = 0) OR
(p1.typtype != 'c' AND p1.typrelid != 0);
+-- Look for basic types that don't have an array type.
+-- NOTE: as of 7.3, this check finds SET, smgr, and unknown.
+
+SELECT p1.oid, p1.typname
+FROM pg_type as p1
+WHERE p1.typtype != 'c' AND p1.typname NOT LIKE '\\_%' AND NOT EXISTS
+ (SELECT 1 FROM pg_type as p2
+ WHERE p2.typname = ('_' || p1.typname)::name AND
+ p2.typelem = p1.oid);
+
+-- Look for array types that don't have an equality operator.
+
+SELECT p1.oid, p1.typname
+FROM pg_type as p1
+WHERE p1.typtype != 'c' AND p1.typname LIKE '\\_%' AND NOT EXISTS
+ (SELECT 1 FROM pg_operator
+ WHERE oprname = '=' AND oprleft = p1.oid AND oprright = p1.oid);
+
-- Conversion routines must be provided except in 'c' entries.
SELECT p1.oid, p1.typname
FROM pg_type AS p1, pg_proc AS p2
WHERE p1.typinput = p2.oid AND p1.typtype = 'b' AND
(p2.pronargs != 1 OR p2.proretset) AND
- (p2.pronargs != 3 OR p2.proretset OR p2.proargtypes[2] != 23);
+ (p2.pronargs != 3 OR p2.proretset OR p2.proargtypes[2] != 'int4'::regtype);
-- Check for bogus typoutput routines
-- The first OR subclause detects bogus non-array cases,
FROM pg_type AS p1, pg_proc AS p2
WHERE p1.typreceive = p2.oid AND p1.typtype = 'b' AND
(p2.pronargs != 1 OR p2.proretset) AND
- (p2.pronargs != 3 OR p2.proretset OR p2.proargtypes[2] != 23);
+ (p2.pronargs != 3 OR p2.proretset OR p2.proargtypes[2] != 'int4'::regtype);
-- Check for bogus typsend routines
-- The first OR subclause detects bogus non-array cases,
WHERE p2.attrelid = p1.oid AND p2.attnum > 0);
-- Cross-check against pg_type entry
+-- NOTE: we allow attstorage to be 'plain' even when typstorage is not;
+-- this is mainly for toast tables.
SELECT p1.attrelid, p1.attname, p2.oid, p2.typname
FROM pg_attribute AS p1, pg_type AS p2
WHERE p1.atttypid = p2.oid AND
(p1.attlen != p2.typlen OR
p1.attalign != p2.typalign OR
- p1.attbyval != p2.typbyval);
+ p1.attbyval != p2.typbyval OR
+ (p1.attstorage != p2.typstorage AND p1.attstorage != 'p'));