The contents of command.c, creatinh.c, define.c, remove.c and rename.c
authorTom Lane
Mon, 15 Apr 2002 05:22:04 +0000 (05:22 +0000)
committerTom Lane
Mon, 15 Apr 2002 05:22:04 +0000 (05:22 +0000)
have been divided according to the type of object manipulated - so ALTER
TABLE code is in tablecmds.c, aggregate commands in aggregatecmds.c and
so on.

A few common support routines remain in define.c (prototypes in
src/include/commands/defrem.h).

No code has been changed except for includes to reflect the new files.
The prototypes for aggregatecmds.c, functioncmds.c, operatorcmds.c,
and typecmds.c remain in src/include/commands/defrem.h.

From John Gray 

29 files changed:
src/backend/commands/Makefile
src/backend/commands/aggregatecmds.c [new file with mode: 0644]
src/backend/commands/cluster.c
src/backend/commands/creatinh.c [deleted file]
src/backend/commands/define.c
src/backend/commands/functioncmds.c [new file with mode: 0644]
src/backend/commands/lockcmds.c [new file with mode: 0644]
src/backend/commands/operatorcmds.c [new file with mode: 0644]
src/backend/commands/portalcmds.c [new file with mode: 0644]
src/backend/commands/proclang.c
src/backend/commands/remove.c [deleted file]
src/backend/commands/rename.c [deleted file]
src/backend/commands/schemacmds.c [new file with mode: 0644]
src/backend/commands/sequence.c
src/backend/commands/tablecmds.c [moved from src/backend/commands/command.c with 52% similarity]
src/backend/commands/typecmds.c [new file with mode: 0644]
src/backend/commands/view.c
src/backend/executor/execMain.c
src/backend/executor/spi.c
src/backend/tcop/pquery.c
src/backend/tcop/utility.c
src/include/commands/command.h [deleted file]
src/include/commands/creatinh.h [deleted file]
src/include/commands/defrem.h
src/include/commands/lockcmds.h [new file with mode: 0644]
src/include/commands/portalcmds.h [new file with mode: 0644]
src/include/commands/rename.h [deleted file]
src/include/commands/schemacmds.h [new file with mode: 0644]
src/include/commands/tablecmds.h [new file with mode: 0644]

index b27e6d77b2abeddfbc7d16faa3fbabe3dc6b115e..190b0fd64f64d75290ce2767864f39c1e606f26f 100644 (file)
@@ -1,10 +1,10 @@
 #-------------------------------------------------------------------------
 #
 # Makefile--
-#    Makefile for commands
+#    Makefile for backend/commands
 #
 # IDENTIFICATION
-#    $Header: /cvsroot/pgsql/src/backend/commands/Makefile,v 1.27 2001/07/13 22:55:59 tgl Exp $
+#    $Header: /cvsroot/pgsql/src/backend/commands/Makefile,v 1.28 2002/04/15 05:22:03 tgl Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -12,10 +12,11 @@ subdir = src/backend/commands
 top_builddir = ../../..
 include $(top_builddir)/src/Makefile.global
 
-OBJS = async.o creatinh.o command.o comment.o copy.o indexcmds.o define.o \
-       remove.o rename.o vacuum.o vacuumlazy.o analyze.o view.o cluster.o \
-       explain.o sequence.o trigger.o user.o proclang.o \
-       dbcommands.o variable.o
+OBJS = aggregatecmds.o analyze.o async.o cluster.o comment.o copy.o \
+   dbcommands.o define.o explain.o functioncmds.o \
+   indexcmds.o lockcmds.o operatorcmds.o portalcmds.o proclang.o \
+   schemacmds.o sequence.o tablecmds.o trigger.o typecmds.o user.o \
+   vacuum.o vacuumlazy.o variable.o view.o
 
 all: SUBSYS.o
 
diff --git a/src/backend/commands/aggregatecmds.c b/src/backend/commands/aggregatecmds.c
new file mode 100644 (file)
index 0000000..7ee0c8f
--- /dev/null
@@ -0,0 +1,208 @@
+/*-------------------------------------------------------------------------
+ *
+ * aggregatecmds.c
+ *
+ *   Routines for aggregate-manipulation commands
+ *
+ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *   $Header: /cvsroot/pgsql/src/backend/commands/aggregatecmds.c,v 1.1 2002/04/15 05:22:03 tgl Exp $
+ *
+ * DESCRIPTION
+ *   The "DefineFoo" routines take the parse tree and pick out the
+ *   appropriate arguments/flags, passing the results to the
+ *   corresponding "FooDefine" routines (in src/catalog) that do
+ *   the actual catalog-munging.  These routines also verify permission
+ *   of the user to execute the command.
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "access/heapam.h"
+#include "catalog/catname.h"
+#include "catalog/namespace.h"
+#include "catalog/pg_aggregate.h"
+#include "commands/comment.h"
+#include "commands/defrem.h"
+#include "miscadmin.h"
+#include "parser/parse_func.h"
+#include "parser/parse_type.h"
+#include "utils/acl.h"
+#include "utils/builtins.h"
+#include "utils/lsyscache.h"
+#include "utils/syscache.h"
+
+
+/*
+ * DefineAggregate
+ */
+void
+DefineAggregate(List *names, List *parameters)
+{
+   char       *aggName;
+   Oid         aggNamespace;
+   List       *transfuncName = NIL;
+   List       *finalfuncName = NIL;
+   TypeName   *baseType = NULL;
+   TypeName   *transType = NULL;
+   char       *initval = NULL;
+   Oid         baseTypeId;
+   Oid         transTypeId;
+   List       *pl;
+
+   /* Convert list of names to a name and namespace */
+   aggNamespace = QualifiedNameGetCreationNamespace(names, &aggName);
+
+   foreach(pl, parameters)
+   {
+       DefElem    *defel = (DefElem *) lfirst(pl);
+
+       /*
+        * sfunc1, stype1, and initcond1 are accepted as obsolete
+        * spellings for sfunc, stype, initcond.
+        */
+       if (strcasecmp(defel->defname, "sfunc") == 0)
+           transfuncName = defGetQualifiedName(defel);
+       else if (strcasecmp(defel->defname, "sfunc1") == 0)
+           transfuncName = defGetQualifiedName(defel);
+       else if (strcasecmp(defel->defname, "finalfunc") == 0)
+           finalfuncName = defGetQualifiedName(defel);
+       else if (strcasecmp(defel->defname, "basetype") == 0)
+           baseType = defGetTypeName(defel);
+       else if (strcasecmp(defel->defname, "stype") == 0)
+           transType = defGetTypeName(defel);
+       else if (strcasecmp(defel->defname, "stype1") == 0)
+           transType = defGetTypeName(defel);
+       else if (strcasecmp(defel->defname, "initcond") == 0)
+           initval = defGetString(defel);
+       else if (strcasecmp(defel->defname, "initcond1") == 0)
+           initval = defGetString(defel);
+       else
+           elog(WARNING, "DefineAggregate: attribute \"%s\" not recognized",
+                defel->defname);
+   }
+
+   /*
+    * make sure we have our required definitions
+    */
+   if (baseType == NULL)
+       elog(ERROR, "Define: \"basetype\" unspecified");
+   if (transType == NULL)
+       elog(ERROR, "Define: \"stype\" unspecified");
+   if (transfuncName == NIL)
+       elog(ERROR, "Define: \"sfunc\" unspecified");
+
+   /*
+    * Handle the aggregate's base type (input data type).  This can be
+    * specified as 'ANY' for a data-independent transition function, such
+    * as COUNT(*).
+    */
+   baseTypeId = LookupTypeName(baseType);
+   if (OidIsValid(baseTypeId))
+   {
+       /* no need to allow aggregates on as-yet-undefined types */
+       if (!get_typisdefined(baseTypeId))
+           elog(ERROR, "Type \"%s\" is only a shell",
+                TypeNameToString(baseType));
+   }
+   else
+   {
+       char      *typnam = TypeNameToString(baseType);
+
+       if (strcasecmp(typnam, "ANY") != 0)
+           elog(ERROR, "Type \"%s\" does not exist", typnam);
+       baseTypeId = InvalidOid;
+   }
+
+   /* handle transtype --- no special cases here */
+   transTypeId = typenameTypeId(transType);
+
+   /*
+    * Most of the argument-checking is done inside of AggregateCreate
+    */
+   AggregateCreate(aggName,    /* aggregate name */
+                   aggNamespace,   /* namespace */
+                   transfuncName,      /* step function name */
+                   finalfuncName,      /* final function name */
+                   baseTypeId, /* type of data being aggregated */
+                   transTypeId,    /* transition data type */
+                   initval);   /* initial condition */
+}
+
+
+void
+RemoveAggregate(List *aggName, TypeName *aggType)
+{
+   Relation    relation;
+   HeapTuple   tup;
+   Oid         basetypeID;
+   Oid         procOid;
+
+   /*
+    * if a basetype is passed in, then attempt to find an aggregate for
+    * that specific type.
+    *
+    * else if the basetype is blank, then attempt to find an aggregate with
+    * a basetype of zero.  This is valid. It means that the aggregate is
+    * to apply to all basetypes (eg, COUNT).
+    */
+   if (aggType)
+       basetypeID = typenameTypeId(aggType);
+   else
+       basetypeID = InvalidOid;
+
+   procOid = find_aggregate_func("RemoveAggregate", aggName, basetypeID);
+
+   /* Permission check */
+
+   if (!pg_proc_ownercheck(procOid, GetUserId()))
+   {
+       if (basetypeID == InvalidOid)
+           elog(ERROR, "RemoveAggregate: aggregate %s for all types: permission denied",
+                NameListToString(aggName));
+       else
+           elog(ERROR, "RemoveAggregate: aggregate %s for type %s: permission denied",
+                NameListToString(aggName), format_type_be(basetypeID));
+   }
+
+   /* Remove the pg_proc tuple */
+
+   relation = heap_openr(ProcedureRelationName, RowExclusiveLock);
+
+   tup = SearchSysCache(PROCOID,
+                        ObjectIdGetDatum(procOid),
+                        0, 0, 0);
+   if (!HeapTupleIsValid(tup)) /* should not happen */
+       elog(ERROR, "RemoveAggregate: couldn't find pg_proc tuple for %s",
+            NameListToString(aggName));
+
+   /* Delete any comments associated with this function */
+   DeleteComments(procOid, RelationGetRelid(relation));
+
+   simple_heap_delete(relation, &tup->t_self);
+
+   ReleaseSysCache(tup);
+
+   heap_close(relation, RowExclusiveLock);
+
+   /* Remove the pg_aggregate tuple */
+
+   relation = heap_openr(AggregateRelationName, RowExclusiveLock);
+
+   tup = SearchSysCache(AGGFNOID,
+                        ObjectIdGetDatum(procOid),
+                        0, 0, 0);
+   if (!HeapTupleIsValid(tup)) /* should not happen */
+       elog(ERROR, "RemoveAggregate: couldn't find pg_aggregate tuple for %s",
+            NameListToString(aggName));
+
+   simple_heap_delete(relation, &tup->t_self);
+
+   ReleaseSysCache(tup);
+
+   heap_close(relation, RowExclusiveLock);
+}
index aad5361b6b837d085c4ed7b8df261ece8b8b21ee..8883eddc49f7d0c9342507e2d063f14031dfdae4 100644 (file)
@@ -15,7 +15,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/commands/cluster.c,v 1.77 2002/03/31 07:49:30 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/commands/cluster.c,v 1.78 2002/04/15 05:22:03 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -29,8 +29,7 @@
 #include "catalog/pg_index.h"
 #include "catalog/pg_proc.h"
 #include "commands/cluster.h"
-#include "commands/command.h"
-#include "commands/rename.h"
+#include "commands/tablecmds.h"
 #include "miscadmin.h"
 #include "utils/builtins.h"
 #include "utils/lsyscache.h"
diff --git a/src/backend/commands/creatinh.c b/src/backend/commands/creatinh.c
deleted file mode 100644 (file)
index 6a0cf81..0000000
+++ /dev/null
@@ -1,932 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * creatinh.c
- *   POSTGRES create/destroy relation with inheritance utility code.
- *
- * 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/commands/Attic/creatinh.c,v 1.96 2002/04/12 20:38:22 tgl Exp $
- *
- *-------------------------------------------------------------------------
- */
-
-#include "postgres.h"
-
-#include "access/heapam.h"
-#include "catalog/catalog.h"
-#include "catalog/catname.h"
-#include "catalog/heap.h"
-#include "catalog/indexing.h"
-#include "catalog/namespace.h"
-#include "catalog/pg_inherits.h"
-#include "catalog/pg_type.h"
-#include "commands/creatinh.h"
-#include "miscadmin.h"
-#include "optimizer/clauses.h"
-#include "parser/parse_type.h"
-#include "utils/acl.h"
-#include "utils/syscache.h"
-
-
-/* ----------------
- *     local stuff
- * ----------------
- */
-
-static List *MergeAttributes(List *schema, List *supers, bool istemp,
-               List **supOids, List **supconstr, bool *supHasOids);
-static bool change_varattnos_of_a_node(Node *node, const AttrNumber *newattno);
-static void StoreCatalogInheritance(Oid relationId, List *supers);
-static int findAttrByName(const char *attributeName, List *schema);
-static void setRelhassubclassInRelation(Oid relationId, bool relhassubclass);
-static List *MergeDomainAttributes(List *schema);
-
-
-/* ----------------------------------------------------------------
- *     DefineRelation
- *             Creates a new relation.
- *
- * If successful, returns the OID of the new relation.
- * ----------------------------------------------------------------
- */
-Oid
-DefineRelation(CreateStmt *stmt, char relkind)
-{
-   char       *relname = palloc(NAMEDATALEN);
-   Oid         namespaceId;
-   List       *schema = stmt->tableElts;
-   int         numberOfAttributes;
-   Oid         relationId;
-   Relation    rel;
-   TupleDesc   descriptor;
-   List       *inheritOids;
-   List       *old_constraints;
-   bool        parentHasOids;
-   List       *rawDefaults;
-   List       *listptr;
-   int         i;
-   AttrNumber  attnum;
-
-   /*
-    * Truncate relname to appropriate length (probably a waste of time,
-    * as parser should have done this already).
-    */
-   StrNCpy(relname, (stmt->relation)->relname, NAMEDATALEN);
-
-   /*
-    * Look up the namespace in which we are supposed to create the
-    * relation.
-    */
-   namespaceId = RangeVarGetCreationNamespace(stmt->relation);
-
-   /*
-    * Merge domain attributes into the known columns before processing table
-    * inheritance.  Otherwise we risk adding double constraints to a
-    * domain-type column that's inherited.
-    */
-   schema = MergeDomainAttributes(schema);
-
-   /*
-    * Look up inheritance ancestors and generate relation schema,
-    * including inherited attributes.
-    */
-   schema = MergeAttributes(schema, stmt->inhRelations,
-                            stmt->relation->istemp,
-                            &inheritOids, &old_constraints, &parentHasOids);
-
-   numberOfAttributes = length(schema);
-   if (numberOfAttributes <= 0)
-       elog(ERROR, "DefineRelation: please inherit from a relation or define an attribute");
-
-   /*
-    * Create a relation descriptor from the relation schema and create
-    * the relation.  Note that in this stage only inherited (pre-cooked)
-    * defaults and constraints will be included into the new relation.
-    * (BuildDescForRelation takes care of the inherited defaults, but we
-    * have to copy inherited constraints here.)
-    */
-   descriptor = BuildDescForRelation(schema);
-
-   if (old_constraints != NIL)
-   {
-       ConstrCheck *check = (ConstrCheck *) palloc(length(old_constraints) *
-                                                   sizeof(ConstrCheck));
-       int         ncheck = 0;
-
-       foreach(listptr, old_constraints)
-       {
-           Constraint *cdef = (Constraint *) lfirst(listptr);
-
-           if (cdef->contype != CONSTR_CHECK)
-               continue;
-
-           if (cdef->name != NULL)
-           {
-               for (i = 0; i < ncheck; i++)
-               {
-                   if (strcmp(check[i].ccname, cdef->name) == 0)
-                       elog(ERROR, "Duplicate CHECK constraint name: '%s'",
-                            cdef->name);
-               }
-               check[ncheck].ccname = cdef->name;
-           }
-           else
-           {
-               check[ncheck].ccname = (char *) palloc(NAMEDATALEN);
-               snprintf(check[ncheck].ccname, NAMEDATALEN, "$%d", ncheck + 1);
-           }
-           Assert(cdef->raw_expr == NULL && cdef->cooked_expr != NULL);
-           check[ncheck].ccbin = pstrdup(cdef->cooked_expr);
-           ncheck++;
-       }
-       if (ncheck > 0)
-       {
-           if (descriptor->constr == NULL)
-           {
-               descriptor->constr = (TupleConstr *) palloc(sizeof(TupleConstr));
-               descriptor->constr->defval = NULL;
-               descriptor->constr->num_defval = 0;
-               descriptor->constr->has_not_null = false;
-           }
-           descriptor->constr->num_check = ncheck;
-           descriptor->constr->check = check;
-       }
-   }
-
-   relationId = heap_create_with_catalog(relname,
-                                         namespaceId,
-                                         descriptor,
-                                         relkind,
-                                         stmt->hasoids || parentHasOids,
-                                         allowSystemTableMods);
-
-   StoreCatalogInheritance(relationId, inheritOids);
-
-   /*
-    * We must bump the command counter to make the newly-created relation
-    * tuple visible for opening.
-    */
-   CommandCounterIncrement();
-
-   /*
-    * Open the new relation and acquire exclusive lock on it.  This isn't
-    * really necessary for locking out other backends (since they can't
-    * see the new rel anyway until we commit), but it keeps the lock
-    * manager from complaining about deadlock risks.
-    */
-   rel = heap_open(relationId, AccessExclusiveLock);
-
-   /*
-    * Now add any newly specified column default values and CHECK
-    * constraints to the new relation.  These are passed to us in the
-    * form of raw parsetrees; we need to transform them to executable
-    * expression trees before they can be added. The most convenient way
-    * to do that is to apply the parser's transformExpr routine, but
-    * transformExpr doesn't work unless we have a pre-existing relation.
-    * So, the transformation has to be postponed to this final step of
-    * CREATE TABLE.
-    *
-    * First, scan schema to find new column defaults.
-    */
-   rawDefaults = NIL;
-   attnum = 0;
-
-   foreach(listptr, schema)
-   {
-       ColumnDef  *colDef = lfirst(listptr);
-       RawColumnDefault *rawEnt;
-
-       attnum++;
-
-       if (colDef->raw_default == NULL)
-           continue;
-       Assert(colDef->cooked_default == NULL);
-
-       rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
-       rawEnt->attnum = attnum;
-       rawEnt->raw_default = colDef->raw_default;
-       rawDefaults = lappend(rawDefaults, rawEnt);
-   }
-
-   /*
-    * Parse and add the defaults/constraints, if any.
-    */
-   if (rawDefaults || stmt->constraints)
-       AddRelationRawConstraints(rel, rawDefaults, stmt->constraints);
-
-   /*
-    * Clean up.  We keep lock on new relation (although it shouldn't be
-    * visible to anyone else anyway, until commit).
-    */
-   heap_close(rel, NoLock);
-
-   return relationId;
-}
-
-/*
- * RemoveRelation
- *     Deletes a relation.
- *
- * Exceptions:
- *     BadArg if name is invalid.
- *
- * Note:
- *     If the relation has indices defined on it, then the index relations
- * themselves will be destroyed, too.
- */
-void
-RemoveRelation(const RangeVar *relation)
-{
-   Oid         relOid;
-
-   relOid = RangeVarGetRelid(relation, false);
-   heap_drop_with_catalog(relOid, allowSystemTableMods);
-}
-
-/*
- * TruncateRelation
- *               Removes all the rows from a relation
- *
- * Exceptions:
- *               BadArg if name is invalid
- *
- * Note:
- *               Rows are removed, indices are truncated and reconstructed.
- */
-void
-TruncateRelation(const RangeVar *relation)
-{
-   Relation    rel;
-   Oid         relid;
-
-   /* Grab exclusive lock in preparation for truncate */
-   rel = heap_openrv(relation, AccessExclusiveLock);
-   relid = RelationGetRelid(rel);
-
-   if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
-       elog(ERROR, "TRUNCATE cannot be used on sequences. '%s' is a sequence",
-            RelationGetRelationName(rel));
-
-   if (rel->rd_rel->relkind == RELKIND_VIEW)
-       elog(ERROR, "TRUNCATE cannot be used on views. '%s' is a view",
-            RelationGetRelationName(rel));
-
-   if (!allowSystemTableMods && IsSystemRelation(rel))
-       elog(ERROR, "TRUNCATE cannot be used on system tables. '%s' is a system table",
-            RelationGetRelationName(rel));
-
-   if (!pg_class_ownercheck(relid, GetUserId()))
-       elog(ERROR, "you do not own relation \"%s\"",
-            RelationGetRelationName(rel));
-
-   /* Keep the lock until transaction commit */
-   heap_close(rel, NoLock);
-
-   heap_truncate(relid);
-}
-
-
-/*
- * MergeDomainAttributes
- *      Returns a new table schema with the constraints, types, and other
- *      attributes of domains resolved for fields using a domain as
- *      their type.
- */
-static List *
-MergeDomainAttributes(List *schema)
-{
-   List       *entry;
-
-   /*
-    * Loop through the table elements supplied. These should
-    * never include inherited domains else they'll be
-    * double (or more) processed.
-    */
-   foreach(entry, schema)
-   {
-       ColumnDef  *coldef = lfirst(entry);
-       HeapTuple  tuple;
-       Form_pg_type typeTup;
-
-       tuple = typenameType(coldef->typename);
-       typeTup = (Form_pg_type) GETSTRUCT(tuple);
-
-       if (typeTup->typtype == 'd')
-       {
-           /* Force the column to have the correct typmod. */
-           coldef->typename->typmod = typeTup->typtypmod;
-           /* XXX more to do here? */
-       }
-
-       /* Enforce type NOT NULL || column definition NOT NULL -> NOT NULL */
-       /* Currently only used for domains, but could be valid for all */
-       coldef->is_not_null |= typeTup->typnotnull;
-
-       ReleaseSysCache(tuple);
-   }
-
-   return schema;
-}
-
-/*----------
- * MergeAttributes
- *     Returns new schema given initial schema and superclasses.
- *
- * Input arguments:
- * 'schema' is the column/attribute definition for the table. (It's a list
- *     of ColumnDef's.) It is destructively changed.
- * 'supers' is a list of names (as RangeVar nodes) of parent relations.
- * 'istemp' is TRUE if we are creating a temp relation.
- *
- * Output arguments:
- * 'supOids' receives an integer list of the OIDs of the parent relations.
- * 'supconstr' receives a list of constraints belonging to the parents,
- *     updated as necessary to be valid for the child.
- * 'supHasOids' is set TRUE if any parent has OIDs, else it is set FALSE.
- *
- * Return value:
- * Completed schema list.
- *
- * Notes:
- *   The order in which the attributes are inherited is very important.
- *   Intuitively, the inherited attributes should come first. If a table
- *   inherits from multiple parents, the order of those attributes are
- *   according to the order of the parents specified in CREATE TABLE.
- *
- *   Here's an example:
- *
- *     create table person (name text, age int4, location point);
- *     create table emp (salary int4, manager text) inherits(person);
- *     create table student (gpa float8) inherits (person);
- *     create table stud_emp (percent int4) inherits (emp, student);
- *
- *   The order of the attributes of stud_emp is:
- *
- *                         person {1:name, 2:age, 3:location}
- *                         /    \
- *            {6:gpa}  student   emp {4:salary, 5:manager}
- *                         \    /
- *                        stud_emp {7:percent}
- *
- *    If the same attribute name appears multiple times, then it appears
- *    in the result table in the proper location for its first appearance.
- *
- *    Constraints (including NOT NULL constraints) for the child table
- *    are the union of all relevant constraints, from both the child schema
- *    and parent tables.
- *
- *    The default value for a child column is defined as:
- *     (1) If the child schema specifies a default, that value is used.
- *     (2) If neither the child nor any parent specifies a default, then
- *         the column will not have a default.
- *     (3) If conflicting defaults are inherited from different parents
- *         (and not overridden by the child), an error is raised.
- *     (4) Otherwise the inherited default is used.
- *     Rule (3) is new in Postgres 7.1; in earlier releases you got a
- *     rather arbitrary choice of which parent default to use.
- *----------
- */
-static List *
-MergeAttributes(List *schema, List *supers, bool istemp,
-               List **supOids, List **supconstr, bool *supHasOids)
-{
-   List       *entry;
-   List       *inhSchema = NIL;
-   List       *parentOids = NIL;
-   List       *constraints = NIL;
-   bool        parentHasOids = false;
-   bool        have_bogus_defaults = false;
-   char       *bogus_marker = "Bogus!";        /* marks conflicting
-                                                * defaults */
-   int         child_attno;
-
-   /*
-    * Check for duplicate names in the explicit list of attributes.
-    *
-    * Although we might consider merging such entries in the same way that
-    * we handle name conflicts for inherited attributes, it seems to make
-    * more sense to assume such conflicts are errors.
-    */
-   foreach(entry, schema)
-   {
-       ColumnDef  *coldef = lfirst(entry);
-       List       *rest;
-
-       foreach(rest, lnext(entry))
-       {
-           ColumnDef  *restdef = lfirst(rest);
-
-           if (strcmp(coldef->colname, restdef->colname) == 0)
-               elog(ERROR, "CREATE TABLE: attribute \"%s\" duplicated",
-                    coldef->colname);
-       }
-   }
-
-   /*
-    * Scan the parents left-to-right, and merge their attributes to form
-    * a list of inherited attributes (inhSchema).  Also check to see if
-    * we need to inherit an OID column.
-    */
-   child_attno = 0;
-   foreach(entry, supers)
-   {
-       RangeVar   *parent = (RangeVar *) lfirst(entry);
-       Relation    relation;
-       TupleDesc   tupleDesc;
-       TupleConstr *constr;
-       AttrNumber *newattno;
-       AttrNumber  parent_attno;
-
-       relation = heap_openrv(parent, AccessShareLock);
-
-       if (relation->rd_rel->relkind != RELKIND_RELATION)
-           elog(ERROR, "CREATE TABLE: inherited relation \"%s\" is not a table",
-                parent->relname);
-       /* Permanent rels cannot inherit from temporary ones */
-       if (!istemp && isTempNamespace(RelationGetNamespace(relation)))
-           elog(ERROR, "CREATE TABLE: cannot inherit from temp relation \"%s\"",
-                parent->relname);
-
-       /*
-        * We should have an UNDER permission flag for this, but for now,
-        * demand that creator of a child table own the parent.
-        */
-       if (!pg_class_ownercheck(RelationGetRelid(relation), GetUserId()))
-           elog(ERROR, "you do not own table \"%s\"",
-                parent->relname);
-
-       /*
-        * Reject duplications in the list of parents.
-        */
-       if (intMember(RelationGetRelid(relation), parentOids))
-           elog(ERROR, "CREATE TABLE: inherited relation \"%s\" duplicated",
-                parent->relname);
-
-       parentOids = lappendi(parentOids, RelationGetRelid(relation));
-       setRelhassubclassInRelation(RelationGetRelid(relation), true);
-
-       parentHasOids |= relation->rd_rel->relhasoids;
-
-       tupleDesc = RelationGetDescr(relation);
-       constr = tupleDesc->constr;
-
-       /*
-        * newattno[] will contain the child-table attribute numbers for
-        * the attributes of this parent table.  (They are not the same
-        * for parents after the first one.)
-        */
-       newattno = (AttrNumber *) palloc(tupleDesc->natts * sizeof(AttrNumber));
-
-       for (parent_attno = 1; parent_attno <= tupleDesc->natts;
-            parent_attno++)
-       {
-           Form_pg_attribute attribute = tupleDesc->attrs[parent_attno - 1];
-           char       *attributeName = NameStr(attribute->attname);
-           int         exist_attno;
-           ColumnDef  *def;
-           TypeName   *typename;
-
-           /*
-            * Does it conflict with some previously inherited column?
-            */
-           exist_attno = findAttrByName(attributeName, inhSchema);
-           if (exist_attno > 0)
-           {
-               /*
-                * Yes, try to merge the two column definitions. They must
-                * have the same type and typmod.
-                */
-               elog(NOTICE, "CREATE TABLE: merging multiple inherited definitions of attribute \"%s\"",
-                    attributeName);
-               def = (ColumnDef *) nth(exist_attno - 1, inhSchema);
-               if (typenameTypeId(def->typename) != attribute->atttypid ||
-                   def->typename->typmod != attribute->atttypmod)
-                   elog(ERROR, "CREATE TABLE: inherited attribute \"%s\" type conflict (%s and %s)",
-                        attributeName,
-                        TypeNameToString(def->typename),
-                        typeidTypeName(attribute->atttypid));
-               /* Merge of NOT NULL constraints = OR 'em together */
-               def->is_not_null |= attribute->attnotnull;
-               /* Default and other constraints are handled below */
-               newattno[parent_attno - 1] = exist_attno;
-           }
-           else
-           {
-               /*
-                * No, create a new inherited column
-                */
-               def = makeNode(ColumnDef);
-               def->colname = pstrdup(attributeName);
-               typename = makeNode(TypeName);
-               typename->typeid = attribute->atttypid;
-               typename->typmod = attribute->atttypmod;
-               def->typename = typename;
-               def->is_not_null = attribute->attnotnull;
-               def->raw_default = NULL;
-               def->cooked_default = NULL;
-               def->constraints = NIL;
-               inhSchema = lappend(inhSchema, def);
-               newattno[parent_attno - 1] = ++child_attno;
-           }
-
-           /*
-            * Copy default if any
-            */
-           if (attribute->atthasdef)
-           {
-               char       *this_default = NULL;
-               AttrDefault *attrdef;
-               int         i;
-
-               /* Find default in constraint structure */
-               Assert(constr != NULL);
-               attrdef = constr->defval;
-               for (i = 0; i < constr->num_defval; i++)
-               {
-                   if (attrdef[i].adnum == parent_attno)
-                   {
-                       this_default = attrdef[i].adbin;
-                       break;
-                   }
-               }
-               Assert(this_default != NULL);
-
-               /*
-                * If default expr could contain any vars, we'd need to
-                * fix 'em, but it can't; so default is ready to apply to
-                * child.
-                *
-                * If we already had a default from some prior parent, check
-                * to see if they are the same.  If so, no problem; if
-                * not, mark the column as having a bogus default. Below,
-                * we will complain if the bogus default isn't overridden
-                * by the child schema.
-                */
-               Assert(def->raw_default == NULL);
-               if (def->cooked_default == NULL)
-                   def->cooked_default = pstrdup(this_default);
-               else if (strcmp(def->cooked_default, this_default) != 0)
-               {
-                   def->cooked_default = bogus_marker;
-                   have_bogus_defaults = true;
-               }
-           }
-       }
-
-       /*
-        * Now copy the constraints of this parent, adjusting attnos using
-        * the completed newattno[] map
-        */
-       if (constr && constr->num_check > 0)
-       {
-           ConstrCheck *check = constr->check;
-           int         i;
-
-           for (i = 0; i < constr->num_check; i++)
-           {
-               Constraint *cdef = makeNode(Constraint);
-               Node       *expr;
-
-               cdef->contype = CONSTR_CHECK;
-               if (check[i].ccname[0] == '$')
-                   cdef->name = NULL;
-               else
-                   cdef->name = pstrdup(check[i].ccname);
-               cdef->raw_expr = NULL;
-               /* adjust varattnos of ccbin here */
-               expr = stringToNode(check[i].ccbin);
-               change_varattnos_of_a_node(expr, newattno);
-               cdef->cooked_expr = nodeToString(expr);
-               constraints = lappend(constraints, cdef);
-           }
-       }
-
-       pfree(newattno);
-
-       /*
-        * Close the parent rel, but keep our AccessShareLock on it until
-        * xact commit.  That will prevent someone else from deleting or
-        * ALTERing the parent before the child is committed.
-        */
-       heap_close(relation, NoLock);
-   }
-
-   /*
-    * If we had no inherited attributes, the result schema is just the
-    * explicitly declared columns.  Otherwise, we need to merge the
-    * declared columns into the inherited schema list.
-    */
-   if (inhSchema != NIL)
-   {
-       foreach(entry, schema)
-       {
-           ColumnDef  *newdef = lfirst(entry);
-           char       *attributeName = newdef->colname;
-           int         exist_attno;
-
-           /*
-            * Does it conflict with some previously inherited column?
-            */
-           exist_attno = findAttrByName(attributeName, inhSchema);
-           if (exist_attno > 0)
-           {
-               ColumnDef  *def;
-
-               /*
-                * Yes, try to merge the two column definitions. They must
-                * have the same type and typmod.
-                */
-               elog(NOTICE, "CREATE TABLE: merging attribute \"%s\" with inherited definition",
-                    attributeName);
-               def = (ColumnDef *) nth(exist_attno - 1, inhSchema);
-               if (typenameTypeId(def->typename) != typenameTypeId(newdef->typename) ||
-                   def->typename->typmod != newdef->typename->typmod)
-                   elog(ERROR, "CREATE TABLE: attribute \"%s\" type conflict (%s and %s)",
-                        attributeName,
-                        TypeNameToString(def->typename),
-                        TypeNameToString(newdef->typename));
-               /* Merge of NOT NULL constraints = OR 'em together */
-               def->is_not_null |= newdef->is_not_null;
-               /* If new def has a default, override previous default */
-               if (newdef->raw_default != NULL)
-               {
-                   def->raw_default = newdef->raw_default;
-                   def->cooked_default = newdef->cooked_default;
-               }
-           }
-           else
-           {
-               /*
-                * No, attach new column to result schema
-                */
-               inhSchema = lappend(inhSchema, newdef);
-           }
-       }
-
-       schema = inhSchema;
-   }
-
-   /*
-    * If we found any conflicting parent default values, check to make
-    * sure they were overridden by the child.
-    */
-   if (have_bogus_defaults)
-   {
-       foreach(entry, schema)
-       {
-           ColumnDef  *def = lfirst(entry);
-
-           if (def->cooked_default == bogus_marker)
-               elog(ERROR, "CREATE TABLE: attribute \"%s\" inherits conflicting default values"
-                    "\n\tTo resolve the conflict, specify a default explicitly",
-                    def->colname);
-       }
-   }
-
-   *supOids = parentOids;
-   *supconstr = constraints;
-   *supHasOids = parentHasOids;
-   return schema;
-}
-
-/*
- * complementary static functions for MergeAttributes().
- *
- * Varattnos of pg_relcheck.rcbin must be rewritten when subclasses inherit
- * constraints from parent classes, since the inherited attributes could
- * be given different column numbers in multiple-inheritance cases.
- *
- * Note that the passed node tree is modified in place!
- */
-static bool
-change_varattnos_walker(Node *node, const AttrNumber *newattno)
-{
-   if (node == NULL)
-       return false;
-   if (IsA(node, Var))
-   {
-       Var        *var = (Var *) node;
-
-       if (var->varlevelsup == 0 && var->varno == 1 &&
-           var->varattno > 0)
-       {
-           /*
-            * ??? the following may be a problem when the node is
-            * multiply referenced though stringToNode() doesn't create
-            * such a node currently.
-            */
-           Assert(newattno[var->varattno - 1] > 0);
-           var->varattno = newattno[var->varattno - 1];
-       }
-       return false;
-   }
-   return expression_tree_walker(node, change_varattnos_walker,
-                                 (void *) newattno);
-}
-
-static bool
-change_varattnos_of_a_node(Node *node, const AttrNumber *newattno)
-{
-   return change_varattnos_walker(node, newattno);
-}
-
-/*
- * StoreCatalogInheritance
- *     Updates the system catalogs with proper inheritance information.
- *
- * supers is an integer list of the OIDs of the new relation's direct
- * ancestors.  NB: it is destructively changed to include indirect ancestors.
- */
-static void
-StoreCatalogInheritance(Oid relationId, List *supers)
-{
-   Relation    relation;
-   TupleDesc   desc;
-   int16       seqNumber;
-   List       *entry;
-   HeapTuple   tuple;
-
-   /*
-    * sanity checks
-    */
-   AssertArg(OidIsValid(relationId));
-
-   if (supers == NIL)
-       return;
-
-   /*
-    * Catalog INHERITS information using direct ancestors only.
-    */
-   relation = heap_openr(InheritsRelationName, RowExclusiveLock);
-   desc = RelationGetDescr(relation);
-
-   seqNumber = 1;
-   foreach(entry, supers)
-   {
-       Oid         entryOid = lfirsti(entry);
-       Datum       datum[Natts_pg_inherits];
-       char        nullarr[Natts_pg_inherits];
-
-       datum[0] = ObjectIdGetDatum(relationId);        /* inhrel */
-       datum[1] = ObjectIdGetDatum(entryOid);  /* inhparent */
-       datum[2] = Int16GetDatum(seqNumber);    /* inhseqno */
-
-       nullarr[0] = ' ';
-       nullarr[1] = ' ';
-       nullarr[2] = ' ';
-
-       tuple = heap_formtuple(desc, datum, nullarr);
-
-       heap_insert(relation, tuple);
-
-       if (RelationGetForm(relation)->relhasindex)
-       {
-           Relation    idescs[Num_pg_inherits_indices];
-
-           CatalogOpenIndices(Num_pg_inherits_indices, Name_pg_inherits_indices, idescs);
-           CatalogIndexInsert(idescs, Num_pg_inherits_indices, relation, tuple);
-           CatalogCloseIndices(Num_pg_inherits_indices, idescs);
-       }
-
-       heap_freetuple(tuple);
-
-       seqNumber += 1;
-   }
-
-   heap_close(relation, RowExclusiveLock);
-
-   /* ----------------
-    * Expand supers list to include indirect ancestors as well.
-    *
-    * Algorithm:
-    *  0. begin with list of direct superclasses.
-    *  1. append after each relationId, its superclasses, recursively.
-    *  2. remove all but last of duplicates.
-    * ----------------
-    */
-
-   /*
-    * 1. append after each relationId, its superclasses, recursively.
-    */
-   foreach(entry, supers)
-   {
-       HeapTuple   tuple;
-       Oid         id;
-       int16       number;
-       List       *next;
-       List       *current;
-
-       id = (Oid) lfirsti(entry);
-       current = entry;
-       next = lnext(entry);
-
-       for (number = 1;; number += 1)
-       {
-           tuple = SearchSysCache(INHRELID,
-                                  ObjectIdGetDatum(id),
-                                  Int16GetDatum(number),
-                                  0, 0);
-           if (!HeapTupleIsValid(tuple))
-               break;
-
-           lnext(current) = lconsi(((Form_pg_inherits)
-                                    GETSTRUCT(tuple))->inhparent,
-                                   NIL);
-
-           ReleaseSysCache(tuple);
-
-           current = lnext(current);
-       }
-       lnext(current) = next;
-   }
-
-   /*
-    * 2. remove all but last of duplicates.
-    */
-   foreach(entry, supers)
-   {
-       Oid         thisone;
-       bool        found;
-       List       *rest;
-
-again:
-       thisone = lfirsti(entry);
-       found = false;
-       foreach(rest, lnext(entry))
-       {
-           if (thisone == lfirsti(rest))
-           {
-               found = true;
-               break;
-           }
-       }
-       if (found)
-       {
-           /*
-            * found a later duplicate, so remove this entry.
-            */
-           lfirsti(entry) = lfirsti(lnext(entry));
-           lnext(entry) = lnext(lnext(entry));
-
-           goto again;
-       }
-   }
-}
-
-/*
- * Look for an existing schema entry with the given name.
- *
- * Returns the index (starting with 1) if attribute already exists in schema,
- * 0 if it doesn't.
- */
-static int
-findAttrByName(const char *attributeName, List *schema)
-{
-   List       *s;
-   int         i = 0;
-
-   foreach(s, schema)
-   {
-       ColumnDef  *def = lfirst(s);
-
-       ++i;
-       if (strcmp(attributeName, def->colname) == 0)
-           return i;
-   }
-   return 0;
-}
-
-/*
- * Update a relation's pg_class.relhassubclass entry to the given value
- */
-static void
-setRelhassubclassInRelation(Oid relationId, bool relhassubclass)
-{
-   Relation    relationRelation;
-   HeapTuple   tuple;
-   Relation    idescs[Num_pg_class_indices];
-
-   /*
-    * Fetch a modifiable copy of the tuple, modify it, update pg_class.
-    */
-   relationRelation = heap_openr(RelationRelationName, RowExclusiveLock);
-   tuple = SearchSysCacheCopy(RELOID,
-                              ObjectIdGetDatum(relationId),
-                              0, 0, 0);
-   if (!HeapTupleIsValid(tuple))
-       elog(ERROR, "setRelhassubclassInRelation: cache lookup failed for relation %u", relationId);
-
-   ((Form_pg_class) GETSTRUCT(tuple))->relhassubclass = relhassubclass;
-   simple_heap_update(relationRelation, &tuple->t_self, tuple);
-
-   /* keep the catalog indices up to date */
-   CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs);
-   CatalogIndexInsert(idescs, Num_pg_class_indices, relationRelation, tuple);
-   CatalogCloseIndices(Num_pg_class_indices, idescs);
-
-   heap_freetuple(tuple);
-   heap_close(relationRelation, RowExclusiveLock);
-}
index 692fc9f957c4a389dd1536d1d2deb1c6c1c9f10c..889ddd0f44026a578d78c8cfb1d67d890cd0ec54 100644 (file)
@@ -1,16 +1,15 @@
 /*-------------------------------------------------------------------------
  *
  * define.c
+ *   Support routines for various kinds of object creation.
  *
- *   These routines execute some of the CREATE statements.  In an earlier
- *   version of Postgres, these were "define" statements.
  *
  * 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/commands/define.c,v 1.75 2002/04/11 19:59:57 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.76 2002/04/15 05:22:03 tgl Exp $
  *
  * DESCRIPTION
  *   The "DefineFoo" routines take the parse tree and pick out the
@@ -28,8 +27,6 @@
  *     "create operator":
  *             operators
  *
- *     Most of the parse-tree manipulation routines are defined in
- *     commands/manip.c.
  *
  *-------------------------------------------------------------------------
  */
 #include 
 #include 
 
-#include "access/heapam.h"
-#include "catalog/catname.h"
-#include "catalog/heap.h"
-#include "catalog/namespace.h"
-#include "catalog/pg_aggregate.h"
-#include "catalog/pg_language.h"
-#include "catalog/pg_operator.h"
-#include "catalog/pg_proc.h"
-#include "catalog/pg_type.h"
 #include "commands/defrem.h"
-#include "fmgr.h"
-#include "miscadmin.h"
-#include "optimizer/cost.h"
-#include "parser/parse_func.h"
 #include "parser/parse_type.h"
-#include "utils/acl.h"
-#include "utils/builtins.h"
-#include "utils/fmgroids.h"
-#include "utils/lsyscache.h"
-#include "utils/syscache.h"
-
-
-static Oid findTypeIOFunction(List *procname, bool isOutput);
-static char *defGetString(DefElem *def);
-static double defGetNumeric(DefElem *def);
-static List *defGetQualifiedName(DefElem *def);
-static TypeName *defGetTypeName(DefElem *def);
-static int defGetTypeLength(DefElem *def);
-
-#define DEFAULT_TYPDELIM       ','
 
 
 /*
  * Translate the input language name to lower case.
+ *
+ * Output buffer should be NAMEDATALEN long.
  */
-static void
+void
 case_translate_language_name(const char *input, char *output)
 {
    int         i;
@@ -86,1021 +57,9 @@ case_translate_language_name(const char *input, char *output)
 
 
 /*
- *  Examine the "returns" clause returnType of the CREATE FUNCTION statement
- *  and return information about it as *prorettype_p and *returnsSet.
- *
- * This is more complex than the average typename lookup because we want to
- * allow a shell type to be used, or even created if the specified return type
- * doesn't exist yet.  (Without this, there's no way to define the I/O procs
- * for a new type.)  But SQL function creation won't cope, so error out if
- * the target language is SQL.
- */
-static void
-compute_return_type(TypeName *returnType, Oid languageOid,
-                   Oid *prorettype_p, bool *returnsSet_p)
-{
-   Oid     rettype;
-
-   rettype = LookupTypeName(returnType);
-
-   if (OidIsValid(rettype))
-   {
-       if (!get_typisdefined(rettype))
-       {
-           if (languageOid == SQLlanguageId)
-               elog(ERROR, "SQL functions cannot return shell types");
-           else
-               elog(WARNING, "Return type \"%s\" is only a shell",
-                    TypeNameToString(returnType));
-       }
-   }
-   else
-   {
-       char      *typnam = TypeNameToString(returnType);
-
-       if (strcmp(typnam, "opaque") == 0)
-           rettype = InvalidOid;
-       else
-       {
-           Oid         namespaceId;
-           char       *typname;
-
-           if (languageOid == SQLlanguageId)
-               elog(ERROR, "Type \"%s\" does not exist", typnam);
-           elog(WARNING, "ProcedureCreate: type %s is not yet defined",
-                typnam);
-           namespaceId = QualifiedNameGetCreationNamespace(returnType->names,
-                                                           &typname);
-           rettype = TypeShellMake(typname, namespaceId);
-           if (!OidIsValid(rettype))
-               elog(ERROR, "could not create type %s", typnam);
-       }
-   }
-
-   *prorettype_p = rettype;
-   *returnsSet_p = returnType->setof;
-}
-
-/*
- * Interpret the argument-types list of the CREATE FUNCTION statement.
- */
-static int
-compute_parameter_types(List *argTypes, Oid languageOid,
-                       Oid *parameterTypes)
-{
-   int         parameterCount = 0;
-   List       *x;
-
-   MemSet(parameterTypes, 0, FUNC_MAX_ARGS * sizeof(Oid));
-   foreach(x, argTypes)
-   {
-       TypeName   *t = (TypeName *) lfirst(x);
-       Oid         toid;
-
-       if (parameterCount >= FUNC_MAX_ARGS)
-           elog(ERROR, "functions cannot have more than %d arguments",
-                FUNC_MAX_ARGS);
-
-       toid = LookupTypeName(t);
-       if (OidIsValid(toid))
-       {
-           if (!get_typisdefined(toid))
-               elog(WARNING, "Argument type \"%s\" is only a shell",
-                    TypeNameToString(t));
-       }
-       else
-       {
-           char      *typnam = TypeNameToString(t);
-
-           if (strcmp(typnam, "opaque") == 0)
-           {
-               if (languageOid == SQLlanguageId)
-                   elog(ERROR, "SQL functions cannot have arguments of type \"opaque\"");
-               toid = InvalidOid;
-           }
-           else
-               elog(ERROR, "Type \"%s\" does not exist", typnam);
-       }
-
-       if (t->setof)
-           elog(ERROR, "functions cannot accept set arguments");
-
-       parameterTypes[parameterCount++] = toid;
-   }
-
-   return parameterCount;
-}
-
-/*-------------
- *  Interpret the parameters *parameters and return their contents as
- *  *byte_pct_p, etc.
- *
- * These parameters supply optional information about a function.
- * All have defaults if not specified.
- *
- * Note: currently, only three of these parameters actually do anything:
- *
- *  * isImplicit means the function may be used as an implicit type
- *    coercion.
- *
- *  * isStrict means the function should not be called when any NULL
- *    inputs are present; instead a NULL result value should be assumed.
- *
- *  * volatility tells the optimizer whether the function's result can
- *    be assumed to be repeatable over multiple evaluations.
- *
- * The other four parameters are not used anywhere.    They used to be
- * used in the "expensive functions" optimizer, but that's been dead code
- * for a long time.
- *------------
- */
-static void
-compute_full_attributes(List *parameters,
-                       int32 *byte_pct_p, int32 *perbyte_cpu_p,
-                       int32 *percall_cpu_p, int32 *outin_ratio_p,
-                       bool *isImplicit_p, bool *isStrict_p,
-                       char *volatility_p)
-{
-   List       *pl;
-
-   /* the defaults */
-   *byte_pct_p = BYTE_PCT;
-   *perbyte_cpu_p = PERBYTE_CPU;
-   *percall_cpu_p = PERCALL_CPU;
-   *outin_ratio_p = OUTIN_RATIO;
-   *isImplicit_p = false;
-   *isStrict_p = false;
-   *volatility_p = PROVOLATILE_VOLATILE;
-
-   foreach(pl, parameters)
-   {
-       DefElem    *param = (DefElem *) lfirst(pl);
-
-       if (strcasecmp(param->defname, "implicitcoercion") == 0)
-           *isImplicit_p = true;
-       else if (strcasecmp(param->defname, "isstrict") == 0)
-           *isStrict_p = true;
-       else if (strcasecmp(param->defname, "isimmutable") == 0)
-           *volatility_p = PROVOLATILE_IMMUTABLE;
-       else if (strcasecmp(param->defname, "isstable") == 0)
-           *volatility_p = PROVOLATILE_STABLE;
-       else if (strcasecmp(param->defname, "isvolatile") == 0)
-           *volatility_p = PROVOLATILE_VOLATILE;
-       else if (strcasecmp(param->defname, "iscachable") == 0)
-       {
-           /* obsolete spelling of isImmutable */
-           *volatility_p = PROVOLATILE_IMMUTABLE;
-       }
-       else if (strcasecmp(param->defname, "trusted") == 0)
-       {
-           /*
-            * we don't have untrusted functions any more. The 4.2
-            * implementation is lousy anyway so I took it out. -ay 10/94
-            */
-           elog(ERROR, "untrusted function has been decommissioned.");
-       }
-       else if (strcasecmp(param->defname, "byte_pct") == 0)
-           *byte_pct_p = (int) defGetNumeric(param);
-       else if (strcasecmp(param->defname, "perbyte_cpu") == 0)
-           *perbyte_cpu_p = (int) defGetNumeric(param);
-       else if (strcasecmp(param->defname, "percall_cpu") == 0)
-           *percall_cpu_p = (int) defGetNumeric(param);
-       else if (strcasecmp(param->defname, "outin_ratio") == 0)
-           *outin_ratio_p = (int) defGetNumeric(param);
-       else
-           elog(WARNING, "Unrecognized function attribute '%s' ignored",
-                param->defname);
-   }
-}
-
-
-/*
- * For a dynamically linked C language object, the form of the clause is
- *
- *    AS  [,  ]
- *
- * In all other cases
- *
- *    AS 
- *
- */
-
-static void
-interpret_AS_clause(Oid languageOid, const char *languageName, const List *as,
-                   char **prosrc_str_p, char **probin_str_p)
-{
-   Assert(as != NIL);
-
-   if (languageOid == ClanguageId)
-   {
-       /*
-        * For "C" language, store the file name in probin and, when
-        * given, the link symbol name in prosrc.
-        */
-       *probin_str_p = strVal(lfirst(as));
-       if (lnext(as) == NULL)
-           *prosrc_str_p = "-";
-       else
-           *prosrc_str_p = strVal(lsecond(as));
-   }
-   else
-   {
-       /* Everything else wants the given string in prosrc. */
-       *prosrc_str_p = strVal(lfirst(as));
-       *probin_str_p = "-";
-
-       if (lnext(as) != NIL)
-           elog(ERROR, "CREATE FUNCTION: only one AS item needed for %s language",
-                languageName);
-   }
-}
-
-
-
-/*
- * CreateFunction
- *  Execute a CREATE FUNCTION utility statement.
- */
-void
-CreateFunction(ProcedureStmt *stmt)
-{
-   char       *probin_str;
-   char       *prosrc_str;
-   Oid         prorettype;
-   bool        returnsSet;
-   char        languageName[NAMEDATALEN];
-   Oid         languageOid;
-   char       *funcname;
-   Oid         namespaceId;
-   int         parameterCount;
-   Oid         parameterTypes[FUNC_MAX_ARGS];
-   int32       byte_pct,
-               perbyte_cpu,
-               percall_cpu,
-               outin_ratio;
-   bool        isImplicit,
-               isStrict;
-   char        volatility;
-   HeapTuple   languageTuple;
-   Form_pg_language languageStruct;
-
-   /* Convert list of names to a name and namespace */
-   namespaceId = QualifiedNameGetCreationNamespace(stmt->funcname,
-                                                   &funcname);
-
-   /* Convert language name to canonical case */
-   case_translate_language_name(stmt->language, languageName);
-
-   /* Look up the language and validate permissions */
-   languageTuple = SearchSysCache(LANGNAME,
-                                  PointerGetDatum(languageName),
-                                  0, 0, 0);
-   if (!HeapTupleIsValid(languageTuple))
-       elog(ERROR, "language \"%s\" does not exist", languageName);
-
-   languageOid = languageTuple->t_data->t_oid;
-   languageStruct = (Form_pg_language) GETSTRUCT(languageTuple);
-
-   if (!((languageStruct->lanpltrusted
-          && pg_language_aclcheck(languageOid, GetUserId()) == ACLCHECK_OK)
-         || superuser()))
-       elog(ERROR, "permission denied");
-
-   ReleaseSysCache(languageTuple);
-
-   /*
-    * Convert remaining parameters of CREATE to form wanted by
-    * ProcedureCreate.
-    */
-   compute_return_type(stmt->returnType, languageOid,
-                       &prorettype, &returnsSet);
-
-   parameterCount = compute_parameter_types(stmt->argTypes, languageOid,
-                                            parameterTypes);
-
-   compute_full_attributes(stmt->withClause,
-                           &byte_pct, &perbyte_cpu, &percall_cpu,
-                           &outin_ratio, &isImplicit, &isStrict,
-                           &volatility);
-
-   interpret_AS_clause(languageOid, languageName, stmt->as,
-                       &prosrc_str, &probin_str);
-
-   /*
-    * And now that we have all the parameters, and know we're permitted
-    * to do so, go ahead and create the function.
-    */
-   ProcedureCreate(funcname,
-                   namespaceId,
-                   stmt->replace,
-                   returnsSet,
-                   prorettype,
-                   languageOid,
-                   prosrc_str, /* converted to text later */
-                   probin_str, /* converted to text later */
-                   false,      /* not an aggregate */
-                   true,       /* (obsolete "trusted") */
-                   isImplicit,
-                   isStrict,
-                   volatility,
-                   byte_pct,
-                   perbyte_cpu,
-                   percall_cpu,
-                   outin_ratio,
-                   parameterCount,
-                   parameterTypes);
-}
-
-
-/*
- * DefineOperator
- *     this function extracts all the information from the
- *     parameter list generated by the parser and then has
- *     OperatorCreate() do all the actual work.
- *
- * 'parameters' is a list of DefElem
- */
-void
-DefineOperator(List *names, List *parameters)
-{
-   char       *oprName;
-   Oid         oprNamespace;
-   uint16      precedence = 0; /* operator precedence */
-   bool        canHash = false;    /* operator hashes */
-   bool        isLeftAssociative = true;       /* operator is left
-                                                * associative */
-   char       *functionName = NULL;    /* function for operator */
-   TypeName   *typeName1 = NULL;       /* first type name */
-   TypeName   *typeName2 = NULL;       /* second type name */
-   Oid         typeId1 = InvalidOid;   /* types converted to OID */
-   Oid         typeId2 = InvalidOid;
-   char       *commutatorName = NULL;  /* optional commutator operator
-                                        * name */
-   char       *negatorName = NULL;     /* optional negator operator name */
-   char       *restrictionName = NULL; /* optional restrict. sel.
-                                        * procedure */
-   char       *joinName = NULL;    /* optional join sel. procedure name */
-   char       *sortName1 = NULL;       /* optional first sort operator */
-   char       *sortName2 = NULL;       /* optional second sort operator */
-   List       *pl;
-
-   /* Convert list of names to a name and namespace */
-   oprNamespace = QualifiedNameGetCreationNamespace(names, &oprName);
-
-   /*
-    * loop over the definition list and extract the information we need.
-    */
-   foreach(pl, parameters)
-   {
-       DefElem    *defel = (DefElem *) lfirst(pl);
-
-       if (strcasecmp(defel->defname, "leftarg") == 0)
-       {
-           typeName1 = defGetTypeName(defel);
-           if (typeName1->setof)
-               elog(ERROR, "setof type not implemented for leftarg");
-       }
-       else if (strcasecmp(defel->defname, "rightarg") == 0)
-       {
-           typeName2 = defGetTypeName(defel);
-           if (typeName2->setof)
-               elog(ERROR, "setof type not implemented for rightarg");
-       }
-       else if (strcasecmp(defel->defname, "procedure") == 0)
-           functionName = defGetString(defel);
-       else if (strcasecmp(defel->defname, "precedence") == 0)
-       {
-           /* NOT IMPLEMENTED (never worked in v4.2) */
-           elog(NOTICE, "CREATE OPERATOR: precedence not implemented");
-       }
-       else if (strcasecmp(defel->defname, "associativity") == 0)
-       {
-           /* NOT IMPLEMENTED (never worked in v4.2) */
-           elog(NOTICE, "CREATE OPERATOR: associativity not implemented");
-       }
-       else if (strcasecmp(defel->defname, "commutator") == 0)
-           commutatorName = defGetString(defel);
-       else if (strcasecmp(defel->defname, "negator") == 0)
-           negatorName = defGetString(defel);
-       else if (strcasecmp(defel->defname, "restrict") == 0)
-           restrictionName = defGetString(defel);
-       else if (strcasecmp(defel->defname, "join") == 0)
-           joinName = defGetString(defel);
-       else if (strcasecmp(defel->defname, "hashes") == 0)
-           canHash = TRUE;
-       else if (strcasecmp(defel->defname, "sort1") == 0)
-           sortName1 = defGetString(defel);
-       else if (strcasecmp(defel->defname, "sort2") == 0)
-           sortName2 = defGetString(defel);
-       else
-       {
-           elog(WARNING, "DefineOperator: attribute \"%s\" not recognized",
-                defel->defname);
-       }
-   }
-
-   /*
-    * make sure we have our required definitions
-    */
-   if (functionName == NULL)
-       elog(ERROR, "Define: \"procedure\" unspecified");
-
-   /* Transform type names to type OIDs */
-   if (typeName1)
-       typeId1 = typenameTypeId(typeName1);
-   if (typeName2)
-       typeId2 = typenameTypeId(typeName2);
-
-   /*
-    * now have OperatorCreate do all the work..
-    */
-   OperatorCreate(oprName,     /* operator name */
-                  typeId1,     /* left type id */
-                  typeId2,     /* right type id */
-                  functionName,    /* function for operator */
-                  precedence,  /* operator precedence */
-                  isLeftAssociative,   /* operator is left associative */
-                  commutatorName,      /* optional commutator operator
-                                        * name */
-                  negatorName, /* optional negator operator name */
-                  restrictionName,     /* optional restrict. sel.
-                                        * procedure */
-                  joinName,    /* optional join sel. procedure name */
-                  canHash,     /* operator hashes */
-                  sortName1,   /* optional first sort operator */
-                  sortName2);  /* optional second sort operator */
-
-}
-
-/*
- * DefineAggregate
- */
-void
-DefineAggregate(List *names, List *parameters)
-{
-   char       *aggName;
-   Oid         aggNamespace;
-   List       *transfuncName = NIL;
-   List       *finalfuncName = NIL;
-   TypeName   *baseType = NULL;
-   TypeName   *transType = NULL;
-   char       *initval = NULL;
-   Oid         baseTypeId;
-   Oid         transTypeId;
-   List       *pl;
-
-   /* Convert list of names to a name and namespace */
-   aggNamespace = QualifiedNameGetCreationNamespace(names, &aggName);
-
-   foreach(pl, parameters)
-   {
-       DefElem    *defel = (DefElem *) lfirst(pl);
-
-       /*
-        * sfunc1, stype1, and initcond1 are accepted as obsolete
-        * spellings for sfunc, stype, initcond.
-        */
-       if (strcasecmp(defel->defname, "sfunc") == 0)
-           transfuncName = defGetQualifiedName(defel);
-       else if (strcasecmp(defel->defname, "sfunc1") == 0)
-           transfuncName = defGetQualifiedName(defel);
-       else if (strcasecmp(defel->defname, "finalfunc") == 0)
-           finalfuncName = defGetQualifiedName(defel);
-       else if (strcasecmp(defel->defname, "basetype") == 0)
-           baseType = defGetTypeName(defel);
-       else if (strcasecmp(defel->defname, "stype") == 0)
-           transType = defGetTypeName(defel);
-       else if (strcasecmp(defel->defname, "stype1") == 0)
-           transType = defGetTypeName(defel);
-       else if (strcasecmp(defel->defname, "initcond") == 0)
-           initval = defGetString(defel);
-       else if (strcasecmp(defel->defname, "initcond1") == 0)
-           initval = defGetString(defel);
-       else
-           elog(WARNING, "DefineAggregate: attribute \"%s\" not recognized",
-                defel->defname);
-   }
-
-   /*
-    * make sure we have our required definitions
-    */
-   if (baseType == NULL)
-       elog(ERROR, "Define: \"basetype\" unspecified");
-   if (transType == NULL)
-       elog(ERROR, "Define: \"stype\" unspecified");
-   if (transfuncName == NIL)
-       elog(ERROR, "Define: \"sfunc\" unspecified");
-
-   /*
-    * Handle the aggregate's base type (input data type).  This can be
-    * specified as 'ANY' for a data-independent transition function, such
-    * as COUNT(*).
-    */
-   baseTypeId = LookupTypeName(baseType);
-   if (OidIsValid(baseTypeId))
-   {
-       /* no need to allow aggregates on as-yet-undefined types */
-       if (!get_typisdefined(baseTypeId))
-           elog(ERROR, "Type \"%s\" is only a shell",
-                TypeNameToString(baseType));
-   }
-   else
-   {
-       char      *typnam = TypeNameToString(baseType);
-
-       if (strcasecmp(typnam, "ANY") != 0)
-           elog(ERROR, "Type \"%s\" does not exist", typnam);
-       baseTypeId = InvalidOid;
-   }
-
-   /* handle transtype --- no special cases here */
-   transTypeId = typenameTypeId(transType);
-
-   /*
-    * Most of the argument-checking is done inside of AggregateCreate
-    */
-   AggregateCreate(aggName,    /* aggregate name */
-                   aggNamespace,   /* namespace */
-                   transfuncName,      /* step function name */
-                   finalfuncName,      /* final function name */
-                   baseTypeId, /* type of data being aggregated */
-                   transTypeId,    /* transition data type */
-                   initval);   /* initial condition */
-}
-
-/*
- * DefineDomain
- *     Registers a new domain.
- */
-void
-DefineDomain(CreateDomainStmt *stmt)
-{
-   char       *domainName;
-   Oid         domainNamespace;
-   int16       internalLength;
-   int16       externalLength;
-   Oid         inputProcedure;
-   Oid         outputProcedure;
-   Oid         receiveProcedure;
-   Oid         sendProcedure;
-   bool        byValue;
-   char        delimiter;
-   char        alignment;
-   char        storage;
-   char        typtype;
-   Datum       datum;
-   bool        isnull;
-   char       *defaultValue = NULL;
-   char       *defaultValueBin = NULL;
-   bool        typNotNull = false;
-   Oid         basetypelem;
-   int32       typNDims = length(stmt->typename->arrayBounds);
-   HeapTuple   typeTup;
-   List       *schema = stmt->constraints;
-   List       *listptr;
-
-   /* Convert list of names to a name and namespace */
-   domainNamespace = QualifiedNameGetCreationNamespace(stmt->domainname,
-                                                       &domainName);
-
-   /*
-    * Domainnames, unlike typenames don't need to account for the '_'
-    * prefix.  So they can be one character longer.
-    */
-   if (strlen(domainName) > (NAMEDATALEN - 1))
-       elog(ERROR, "CREATE DOMAIN: domain names must be %d characters or less",
-            NAMEDATALEN - 1);
-
-   /*
-    * Look up the base type.
-    */
-   typeTup = typenameType(stmt->typename);
-
-   /*
-    * What we really don't want is domains of domains.  This could cause all sorts
-    * of neat issues if we allow that.
-    *
-    * With testing, we may determine complex types should be allowed
-    */
-   typtype = ((Form_pg_type) GETSTRUCT(typeTup))->typtype;
-   if (typtype != 'b')
-       elog(ERROR, "DefineDomain: %s is not a basetype",
-            TypeNameToString(stmt->typename));
-
-   /* passed by value */
-   byValue = ((Form_pg_type) GETSTRUCT(typeTup))->typbyval;
-
-   /* Required Alignment */
-   alignment = ((Form_pg_type) GETSTRUCT(typeTup))->typalign;
-
-   /* TOAST Strategy */
-   storage = ((Form_pg_type) GETSTRUCT(typeTup))->typstorage;
-
-   /* Storage Length */
-   internalLength = ((Form_pg_type) GETSTRUCT(typeTup))->typlen;
-
-   /* External Length (unused) */
-   externalLength = ((Form_pg_type) GETSTRUCT(typeTup))->typprtlen;
-
-   /* Array element Delimiter */
-   delimiter = ((Form_pg_type) GETSTRUCT(typeTup))->typdelim;
-
-   /* I/O Functions */
-   inputProcedure = ((Form_pg_type) GETSTRUCT(typeTup))->typinput;
-   outputProcedure = ((Form_pg_type) GETSTRUCT(typeTup))->typoutput;
-   receiveProcedure = ((Form_pg_type) GETSTRUCT(typeTup))->typreceive;
-   sendProcedure = ((Form_pg_type) GETSTRUCT(typeTup))->typsend;
-
-   /* Inherited default value */
-   datum = SysCacheGetAttr(TYPEOID, typeTup,
-                           Anum_pg_type_typdefault, &isnull);
-   if (!isnull)
-       defaultValue = DatumGetCString(DirectFunctionCall1(textout, datum));
-
-   /* Inherited default binary value */
-   datum = SysCacheGetAttr(TYPEOID, typeTup,
-                           Anum_pg_type_typdefaultbin, &isnull);
-   if (!isnull)
-       defaultValueBin = DatumGetCString(DirectFunctionCall1(textout, datum));
-
-   /*
-    * Pull out the typelem name of the parent OID.
-    *
-    * This is what enables us to make a domain of an array
-    */
-   basetypelem = ((Form_pg_type) GETSTRUCT(typeTup))->typelem;
-
-   /*
-    * Run through constraints manually to avoid the additional
-    * processing conducted by DefineRelation() and friends.
-    *
-    * Besides, we don't want any constraints to be cooked.  We'll
-    * do that when the table is created via MergeDomainAttributes().
-    */
-   foreach(listptr, schema)
-   {
-       Constraint *colDef = lfirst(listptr);
-       bool nullDefined = false;
-       Node       *expr;
-       ParseState *pstate;
-
-       switch (colDef->contype)
-       {
-           /*
-            * The inherited default value may be overridden by the user
-            * with the DEFAULT  statement.
-            *
-            * We have to search the entire constraint tree returned as we
-            * don't want to cook or fiddle too much.
-            */
-           case CONSTR_DEFAULT:
-               /* Create a dummy ParseState for transformExpr */
-               pstate = make_parsestate(NULL);
-               /*
-                * Cook the colDef->raw_expr into an expression.
-                * Note: Name is strictly for error message
-                */
-               expr = cookDefault(pstate, colDef->raw_expr,
-                                  typeTup->t_data->t_oid,
-                                  stmt->typename->typmod,
-                                  domainName);
-               /*
-                * Expression must be stored as a nodeToString result,
-                * but we also require a valid textual representation
-                * (mainly to make life easier for pg_dump).
-                */
-               defaultValue = deparse_expression(expr,
-                               deparse_context_for(domainName,
-                                                   InvalidOid),
-                                                  false);
-               defaultValueBin = nodeToString(expr);
-               break;
-
-           /*
-            * Find the NULL constraint.
-            */
-           case CONSTR_NOTNULL:
-               if (nullDefined) {
-                   elog(ERROR, "CREATE DOMAIN has conflicting NULL / NOT NULL constraint");
-               } else {
-                   typNotNull = true;
-                   nullDefined = true;
-               }
-               break;
-
-           case CONSTR_NULL:
-               if (nullDefined) {
-                   elog(ERROR, "CREATE DOMAIN has conflicting NULL / NOT NULL constraint");
-               } else {
-                   typNotNull = false;
-                   nullDefined = true;
-               }
-               break;
-
-           case CONSTR_UNIQUE:
-               elog(ERROR, "CREATE DOMAIN / UNIQUE indexes not supported");
-               break;
-
-           case CONSTR_PRIMARY:
-               elog(ERROR, "CREATE DOMAIN / PRIMARY KEY indexes not supported");
-               break;
-
-           case CONSTR_CHECK:
-               elog(ERROR, "DefineDomain: CHECK Constraints not supported");
-               break;
-
-           case CONSTR_ATTR_DEFERRABLE:
-           case CONSTR_ATTR_NOT_DEFERRABLE:
-           case CONSTR_ATTR_DEFERRED:
-           case CONSTR_ATTR_IMMEDIATE:
-               elog(ERROR, "DefineDomain: DEFERRABLE, NON DEFERRABLE, DEFERRED and IMMEDIATE not supported");
-               break;
-
-           default:
-               elog(ERROR, "DefineDomain: unrecognized constraint node type");
-               break;
-       }
-   }
-
-   /*
-    * Have TypeCreate do all the real work.
-    */
-   TypeCreate(domainName,          /* type name */
-              domainNamespace,     /* namespace */
-              InvalidOid,          /* preassigned type oid (not done here) */
-              InvalidOid,          /* relation oid (n/a here) */
-              internalLength,      /* internal size */
-              externalLength,      /* external size */
-              'd',                 /* type-type (domain type) */
-              delimiter,           /* array element delimiter */
-              inputProcedure,      /* input procedure */
-              outputProcedure,     /* output procedure */
-              receiveProcedure,    /* receive procedure */
-              sendProcedure,       /* send procedure */
-              basetypelem,         /* element type ID */
-              typeTup->t_data->t_oid,  /* base type ID */
-              defaultValue,        /* default type value (text) */
-              defaultValueBin,     /* default type value (binary) */
-              byValue,             /* passed by value */
-              alignment,           /* required alignment */
-              storage,             /* TOAST strategy */
-              stmt->typename->typmod, /* typeMod value */
-              typNDims,            /* Array dimensions for base type */
-              typNotNull);         /* Type NOT NULL */
-
-   /*
-    * Now we can clean up.
-    */
-   ReleaseSysCache(typeTup);
-}
-
-/*
- * DefineType
- *     Registers a new type.
+ * Extract a string value (otherwise uninterpreted) from a DefElem.
  */
-void
-DefineType(List *names, List *parameters)
-{
-   char       *typeName;
-   Oid         typeNamespace;
-   int16       internalLength = -1;    /* int2 */
-   int16       externalLength = -1;    /* int2 */
-   Oid         elemType = InvalidOid;
-   List       *inputName = NIL;
-   List       *outputName = NIL;
-   List       *sendName = NIL;
-   List       *receiveName = NIL;
-   char       *defaultValue = NULL;
-   bool        byValue = false;
-   char        delimiter = DEFAULT_TYPDELIM;
-   char        alignment = 'i';    /* default alignment */
-   char        storage = 'p';  /* default TOAST storage method */
-   Oid         inputOid;
-   Oid         outputOid;
-   Oid         sendOid;
-   Oid         receiveOid;
-   char       *shadow_type;
-   List       *pl;
-   Oid         typoid;
-
-   /* Convert list of names to a name and namespace */
-   typeNamespace = QualifiedNameGetCreationNamespace(names, &typeName);
-
-   /*
-    * Type names must be one character shorter than other names, allowing
-    * room to create the corresponding array type name with prepended
-    * "_".
-    */
-   if (strlen(typeName) > (NAMEDATALEN - 2))
-       elog(ERROR, "DefineType: type names must be %d characters or less",
-            NAMEDATALEN - 2);
-
-   foreach(pl, parameters)
-   {
-       DefElem    *defel = (DefElem *) lfirst(pl);
-
-       if (strcasecmp(defel->defname, "internallength") == 0)
-           internalLength = defGetTypeLength(defel);
-       else if (strcasecmp(defel->defname, "externallength") == 0)
-           externalLength = defGetTypeLength(defel);
-       else if (strcasecmp(defel->defname, "input") == 0)
-           inputName = defGetQualifiedName(defel);
-       else if (strcasecmp(defel->defname, "output") == 0)
-           outputName = defGetQualifiedName(defel);
-       else if (strcasecmp(defel->defname, "send") == 0)
-           sendName = defGetQualifiedName(defel);
-       else if (strcasecmp(defel->defname, "receive") == 0)
-           receiveName = defGetQualifiedName(defel);
-       else if (strcasecmp(defel->defname, "delimiter") == 0)
-       {
-           char       *p = defGetString(defel);
-
-           delimiter = p[0];
-       }
-       else if (strcasecmp(defel->defname, "element") == 0)
-           elemType = typenameTypeId(defGetTypeName(defel));
-       else if (strcasecmp(defel->defname, "default") == 0)
-           defaultValue = defGetString(defel);
-       else if (strcasecmp(defel->defname, "passedbyvalue") == 0)
-           byValue = true;
-       else if (strcasecmp(defel->defname, "alignment") == 0)
-       {
-           char       *a = defGetString(defel);
-
-           /*
-            * Note: if argument was an unquoted identifier, parser will
-            * have applied xlateSqlType() to it, so be prepared to
-            * recognize translated type names as well as the nominal
-            * form.
-            */
-           if (strcasecmp(a, "double") == 0)
-               alignment = 'd';
-           else if (strcasecmp(a, "float8") == 0)
-               alignment = 'd';
-           else if (strcasecmp(a, "int4") == 0)
-               alignment = 'i';
-           else if (strcasecmp(a, "int2") == 0)
-               alignment = 's';
-           else if (strcasecmp(a, "char") == 0)
-               alignment = 'c';
-           else if (strcasecmp(a, "bpchar") == 0)
-               alignment = 'c';
-           else
-               elog(ERROR, "DefineType: \"%s\" alignment not recognized",
-                    a);
-       }
-       else if (strcasecmp(defel->defname, "storage") == 0)
-       {
-           char       *a = defGetString(defel);
-
-           if (strcasecmp(a, "plain") == 0)
-               storage = 'p';
-           else if (strcasecmp(a, "external") == 0)
-               storage = 'e';
-           else if (strcasecmp(a, "extended") == 0)
-               storage = 'x';
-           else if (strcasecmp(a, "main") == 0)
-               storage = 'm';
-           else
-               elog(ERROR, "DefineType: \"%s\" storage not recognized",
-                    a);
-       }
-       else
-       {
-           elog(WARNING, "DefineType: attribute \"%s\" not recognized",
-                defel->defname);
-       }
-   }
-
-   /*
-    * make sure we have our required definitions
-    */
-   if (inputName == NIL)
-       elog(ERROR, "Define: \"input\" unspecified");
-   if (outputName == NIL)
-       elog(ERROR, "Define: \"output\" unspecified");
-
-   /* Convert I/O proc names to OIDs */
-   inputOid = findTypeIOFunction(inputName, false);
-   outputOid = findTypeIOFunction(outputName, true);
-   if (sendName)
-       sendOid = findTypeIOFunction(sendName, true);
-   else
-       sendOid = outputOid;
-   if (receiveName)
-       receiveOid = findTypeIOFunction(receiveName, false);
-   else
-       receiveOid = inputOid;
-
-   /*
-    * now have TypeCreate do all the real work.
-    */
-   typoid =
-       TypeCreate(typeName,        /* type name */
-                  typeNamespace,   /* namespace */
-                  InvalidOid,      /* preassigned type oid (not done here) */
-                  InvalidOid,      /* relation oid (n/a here) */
-                  internalLength,  /* internal size */
-                  externalLength,  /* external size */
-                  'b',             /* type-type (base type) */
-                  delimiter,       /* array element delimiter */
-                  inputOid,        /* input procedure */
-                  outputOid,       /* output procedure */
-                  receiveOid,      /* receive procedure */
-                  sendOid,         /* send procedure */
-                  elemType,        /* element type ID */
-                  InvalidOid,      /* base type ID (only for domains) */
-                  defaultValue,    /* default type value */
-                  NULL,            /* no binary form available */
-                  byValue,         /* passed by value */
-                  alignment,       /* required alignment */
-                  storage,         /* TOAST strategy */
-                  -1,              /* typMod (Domains only) */
-                  0,               /* Array Dimensions of typbasetype */
-                  false);          /* Type NOT NULL */
-
-   /*
-    * When we create a base type (as opposed to a complex type) we need
-    * to have an array entry for it in pg_type as well.
-    */
-   shadow_type = makeArrayTypeName(typeName);
-
-   /* alignment must be 'i' or 'd' for arrays */
-   alignment = (alignment == 'd') ? 'd' : 'i';
-
-   TypeCreate(shadow_type,     /* type name */
-              typeNamespace,   /* namespace */
-              InvalidOid,      /* preassigned type oid (not done here) */
-              InvalidOid,      /* relation oid (n/a here) */
-              -1,              /* internal size */
-              -1,              /* external size */
-              'b',             /* type-type (base type) */
-              DEFAULT_TYPDELIM,    /* array element delimiter */
-              F_ARRAY_IN,      /* input procedure */
-              F_ARRAY_OUT,     /* output procedure */
-              F_ARRAY_IN,      /* receive procedure */
-              F_ARRAY_OUT,     /* send procedure */
-              typoid,          /* element type ID */
-              InvalidOid,      /* base type ID */
-              NULL,            /* never a default type value */
-              NULL,            /* binary default isn't sent either */
-              false,           /* never passed by value */
-              alignment,       /* see above */
-              'x',             /* ARRAY is always toastable */
-              -1,              /* typMod (Domains only) */
-              0,               /* Array dimensions of typbasetype */
-              false);          /* Type NOT NULL */
-
-   pfree(shadow_type);
-}
-
-static Oid
-findTypeIOFunction(List *procname, bool isOutput)
-{
-   Oid         argList[FUNC_MAX_ARGS];
-   int         nargs;
-   Oid         procOid;
-
-   /*
-    * First look for a 1-argument func with all argtypes 0. This is
-    * valid for all kinds of procedure.
-    */
-   MemSet(argList, 0, FUNC_MAX_ARGS * sizeof(Oid));
-
-   procOid = LookupFuncName(procname, 1, argList);
-
-   if (!OidIsValid(procOid))
-   {
-       /*
-        * Alternatively, input procedures may take 3 args (data
-        * value, element OID, atttypmod); the pg_proc argtype
-        * signature is 0,OIDOID,INT4OID.  Output procedures may
-        * take 2 args (data value, element OID).
-        */
-       if (isOutput)
-       {
-           /* output proc */
-           nargs = 2;
-           argList[1] = OIDOID;
-       }
-       else
-       {
-           /* input proc */
-           nargs = 3;
-           argList[1] = OIDOID;
-           argList[2] = INT4OID;
-       }
-       procOid = LookupFuncName(procname, nargs, argList);
-
-       if (!OidIsValid(procOid))
-           func_error("TypeCreate", procname, 1, argList, NULL);
-   }
-
-   return procOid;
-}
-
-
-static char *
+char *
 defGetString(DefElem *def)
 {
    if (def->arg == NULL)
@@ -1133,7 +92,10 @@ defGetString(DefElem *def)
    return NULL;                /* keep compiler quiet */
 }
 
-static double
+/*
+ * Extract a numeric value (actually double) from a DefElem.
+ */
+double
 defGetNumeric(DefElem *def)
 {
    if (def->arg == NULL)
@@ -1152,7 +114,10 @@ defGetNumeric(DefElem *def)
    return 0;                   /* keep compiler quiet */
 }
 
-static List *
+/*
+ * Extract a possibly-qualified name (as a List of Strings) from a DefElem.
+ */
+List *
 defGetQualifiedName(DefElem *def)
 {
    if (def->arg == NULL)
@@ -1172,7 +137,10 @@ defGetQualifiedName(DefElem *def)
    return NIL;                 /* keep compiler quiet */
 }
 
-static TypeName *
+/*
+ * Extract a TypeName from a DefElem.
+ */
+TypeName *
 defGetTypeName(DefElem *def)
 {
    if (def->arg == NULL)
@@ -1198,7 +166,11 @@ defGetTypeName(DefElem *def)
    return NULL;                /* keep compiler quiet */
 }
 
-static int
+/*
+ * Extract a type length indicator (either absolute bytes, or
+ * -1 for "variable") from a DefElem.
+ */
+int
 defGetTypeLength(DefElem *def)
 {
    if (def->arg == NULL)
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
new file mode 100644 (file)
index 0000000..0bee7cd
--- /dev/null
@@ -0,0 +1,431 @@
+/*-------------------------------------------------------------------------
+ *
+ * functioncmds.c
+ *
+ *   Routines for CREATE and DROP FUNCTION commands
+ *
+ * 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/commands/functioncmds.c,v 1.1 2002/04/15 05:22:03 tgl Exp $
+ *
+ * DESCRIPTION
+ *   These routines take the parse tree and pick out the
+ *   appropriate arguments/flags, and pass the results to the
+ *   corresponding "FooDefine" routines (in src/catalog) that do
+ *   the actual catalog-munging.  These routines also verify permission
+ *   of the user to execute the command.
+ *
+ * NOTES
+ *   These things must be defined and committed in the following order:
+ *     "create function":
+ *             input/output, recv/send procedures
+ *     "create type":
+ *             type
+ *     "create operator":
+ *             operators
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "access/heapam.h"
+#include "catalog/catname.h"
+#include "catalog/namespace.h"
+#include "catalog/pg_language.h"
+#include "catalog/pg_proc.h"
+#include "catalog/pg_type.h"
+#include "commands/comment.h"
+#include "commands/defrem.h"
+#include "miscadmin.h"
+#include "optimizer/cost.h"
+#include "parser/parse_func.h"
+#include "parser/parse_type.h"
+#include "utils/acl.h"
+#include "utils/lsyscache.h"
+#include "utils/syscache.h"
+
+
+/*
+ *  Examine the "returns" clause returnType of the CREATE FUNCTION statement
+ *  and return information about it as *prorettype_p and *returnsSet.
+ *
+ * This is more complex than the average typename lookup because we want to
+ * allow a shell type to be used, or even created if the specified return type
+ * doesn't exist yet.  (Without this, there's no way to define the I/O procs
+ * for a new type.)  But SQL function creation won't cope, so error out if
+ * the target language is SQL.
+ */
+static void
+compute_return_type(TypeName *returnType, Oid languageOid,
+                   Oid *prorettype_p, bool *returnsSet_p)
+{
+   Oid     rettype;
+
+   rettype = LookupTypeName(returnType);
+
+   if (OidIsValid(rettype))
+   {
+       if (!get_typisdefined(rettype))
+       {
+           if (languageOid == SQLlanguageId)
+               elog(ERROR, "SQL functions cannot return shell types");
+           else
+               elog(WARNING, "Return type \"%s\" is only a shell",
+                    TypeNameToString(returnType));
+       }
+   }
+   else
+   {
+       char      *typnam = TypeNameToString(returnType);
+
+       if (strcmp(typnam, "opaque") == 0)
+           rettype = InvalidOid;
+       else
+       {
+           Oid         namespaceId;
+           char       *typname;
+
+           if (languageOid == SQLlanguageId)
+               elog(ERROR, "Type \"%s\" does not exist", typnam);
+           elog(WARNING, "ProcedureCreate: type %s is not yet defined",
+                typnam);
+           namespaceId = QualifiedNameGetCreationNamespace(returnType->names,
+                                                           &typname);
+           rettype = TypeShellMake(typname, namespaceId);
+           if (!OidIsValid(rettype))
+               elog(ERROR, "could not create type %s", typnam);
+       }
+   }
+
+   *prorettype_p = rettype;
+   *returnsSet_p = returnType->setof;
+}
+
+/*
+ * Interpret the argument-types list of the CREATE FUNCTION statement.
+ */
+static int
+compute_parameter_types(List *argTypes, Oid languageOid,
+                       Oid *parameterTypes)
+{
+   int         parameterCount = 0;
+   List       *x;
+
+   MemSet(parameterTypes, 0, FUNC_MAX_ARGS * sizeof(Oid));
+   foreach(x, argTypes)
+   {
+       TypeName   *t = (TypeName *) lfirst(x);
+       Oid         toid;
+
+       if (parameterCount >= FUNC_MAX_ARGS)
+           elog(ERROR, "functions cannot have more than %d arguments",
+                FUNC_MAX_ARGS);
+
+       toid = LookupTypeName(t);
+       if (OidIsValid(toid))
+       {
+           if (!get_typisdefined(toid))
+               elog(WARNING, "Argument type \"%s\" is only a shell",
+                    TypeNameToString(t));
+       }
+       else
+       {
+           char      *typnam = TypeNameToString(t);
+
+           if (strcmp(typnam, "opaque") == 0)
+           {
+               if (languageOid == SQLlanguageId)
+                   elog(ERROR, "SQL functions cannot have arguments of type \"opaque\"");
+               toid = InvalidOid;
+           }
+           else
+               elog(ERROR, "Type \"%s\" does not exist", typnam);
+       }
+
+       if (t->setof)
+           elog(ERROR, "functions cannot accept set arguments");
+
+       parameterTypes[parameterCount++] = toid;
+   }
+
+   return parameterCount;
+}
+
+/*-------------
+ *  Interpret the parameters *parameters and return their contents as
+ *  *byte_pct_p, etc.
+ *
+ * These parameters supply optional information about a function.
+ * All have defaults if not specified.
+ *
+ * Note: currently, only three of these parameters actually do anything:
+ *
+ *  * isImplicit means the function may be used as an implicit type
+ *    coercion.
+ *
+ *  * isStrict means the function should not be called when any NULL
+ *    inputs are present; instead a NULL result value should be assumed.
+ *
+ *  * volatility tells the optimizer whether the function's result can
+ *    be assumed to be repeatable over multiple evaluations.
+ *
+ * The other four parameters are not used anywhere.    They used to be
+ * used in the "expensive functions" optimizer, but that's been dead code
+ * for a long time.
+ *------------
+ */
+static void
+compute_full_attributes(List *parameters,
+                       int32 *byte_pct_p, int32 *perbyte_cpu_p,
+                       int32 *percall_cpu_p, int32 *outin_ratio_p,
+                       bool *isImplicit_p, bool *isStrict_p,
+                       char *volatility_p)
+{
+   List       *pl;
+
+   /* the defaults */
+   *byte_pct_p = BYTE_PCT;
+   *perbyte_cpu_p = PERBYTE_CPU;
+   *percall_cpu_p = PERCALL_CPU;
+   *outin_ratio_p = OUTIN_RATIO;
+   *isImplicit_p = false;
+   *isStrict_p = false;
+   *volatility_p = PROVOLATILE_VOLATILE;
+
+   foreach(pl, parameters)
+   {
+       DefElem    *param = (DefElem *) lfirst(pl);
+
+       if (strcasecmp(param->defname, "implicitcoercion") == 0)
+           *isImplicit_p = true;
+       else if (strcasecmp(param->defname, "isstrict") == 0)
+           *isStrict_p = true;
+       else if (strcasecmp(param->defname, "isimmutable") == 0)
+           *volatility_p = PROVOLATILE_IMMUTABLE;
+       else if (strcasecmp(param->defname, "isstable") == 0)
+           *volatility_p = PROVOLATILE_STABLE;
+       else if (strcasecmp(param->defname, "isvolatile") == 0)
+           *volatility_p = PROVOLATILE_VOLATILE;
+       else if (strcasecmp(param->defname, "iscachable") == 0)
+       {
+           /* obsolete spelling of isImmutable */
+           *volatility_p = PROVOLATILE_IMMUTABLE;
+       }
+       else if (strcasecmp(param->defname, "trusted") == 0)
+       {
+           /*
+            * we don't have untrusted functions any more. The 4.2
+            * implementation is lousy anyway so I took it out. -ay 10/94
+            */
+           elog(ERROR, "untrusted function has been decommissioned.");
+       }
+       else if (strcasecmp(param->defname, "byte_pct") == 0)
+           *byte_pct_p = (int) defGetNumeric(param);
+       else if (strcasecmp(param->defname, "perbyte_cpu") == 0)
+           *perbyte_cpu_p = (int) defGetNumeric(param);
+       else if (strcasecmp(param->defname, "percall_cpu") == 0)
+           *percall_cpu_p = (int) defGetNumeric(param);
+       else if (strcasecmp(param->defname, "outin_ratio") == 0)
+           *outin_ratio_p = (int) defGetNumeric(param);
+       else
+           elog(WARNING, "Unrecognized function attribute '%s' ignored",
+                param->defname);
+   }
+}
+
+
+/*
+ * For a dynamically linked C language object, the form of the clause is
+ *
+ *    AS  [,  ]
+ *
+ * In all other cases
+ *
+ *    AS 
+ *
+ */
+
+static void
+interpret_AS_clause(Oid languageOid, const char *languageName, const List *as,
+                   char **prosrc_str_p, char **probin_str_p)
+{
+   Assert(as != NIL);
+
+   if (languageOid == ClanguageId)
+   {
+       /*
+        * For "C" language, store the file name in probin and, when
+        * given, the link symbol name in prosrc.
+        */
+       *probin_str_p = strVal(lfirst(as));
+       if (lnext(as) == NULL)
+           *prosrc_str_p = "-";
+       else
+           *prosrc_str_p = strVal(lsecond(as));
+   }
+   else
+   {
+       /* Everything else wants the given string in prosrc. */
+       *prosrc_str_p = strVal(lfirst(as));
+       *probin_str_p = "-";
+
+       if (lnext(as) != NIL)
+           elog(ERROR, "CREATE FUNCTION: only one AS item needed for %s language",
+                languageName);
+   }
+}
+
+
+
+/*
+ * CreateFunction
+ *  Execute a CREATE FUNCTION utility statement.
+ */
+void
+CreateFunction(ProcedureStmt *stmt)
+{
+   char       *probin_str;
+   char       *prosrc_str;
+   Oid         prorettype;
+   bool        returnsSet;
+   char        languageName[NAMEDATALEN];
+   Oid         languageOid;
+   char       *funcname;
+   Oid         namespaceId;
+   int         parameterCount;
+   Oid         parameterTypes[FUNC_MAX_ARGS];
+   int32       byte_pct,
+               perbyte_cpu,
+               percall_cpu,
+               outin_ratio;
+   bool        isImplicit,
+               isStrict;
+   char        volatility;
+   HeapTuple   languageTuple;
+   Form_pg_language languageStruct;
+
+   /* Convert list of names to a name and namespace */
+   namespaceId = QualifiedNameGetCreationNamespace(stmt->funcname,
+                                                   &funcname);
+
+   /* Convert language name to canonical case */
+   case_translate_language_name(stmt->language, languageName);
+
+   /* Look up the language and validate permissions */
+   languageTuple = SearchSysCache(LANGNAME,
+                                  PointerGetDatum(languageName),
+                                  0, 0, 0);
+   if (!HeapTupleIsValid(languageTuple))
+       elog(ERROR, "language \"%s\" does not exist", languageName);
+
+   languageOid = languageTuple->t_data->t_oid;
+   languageStruct = (Form_pg_language) GETSTRUCT(languageTuple);
+
+   if (!((languageStruct->lanpltrusted
+          && pg_language_aclcheck(languageOid, GetUserId()) == ACLCHECK_OK)
+         || superuser()))
+       elog(ERROR, "permission denied");
+
+   ReleaseSysCache(languageTuple);
+
+   /*
+    * Convert remaining parameters of CREATE to form wanted by
+    * ProcedureCreate.
+    */
+   compute_return_type(stmt->returnType, languageOid,
+                       &prorettype, &returnsSet);
+
+   parameterCount = compute_parameter_types(stmt->argTypes, languageOid,
+                                            parameterTypes);
+
+   compute_full_attributes(stmt->withClause,
+                           &byte_pct, &perbyte_cpu, &percall_cpu,
+                           &outin_ratio, &isImplicit, &isStrict,
+                           &volatility);
+
+   interpret_AS_clause(languageOid, languageName, stmt->as,
+                       &prosrc_str, &probin_str);
+
+   /*
+    * And now that we have all the parameters, and know we're permitted
+    * to do so, go ahead and create the function.
+    */
+   ProcedureCreate(funcname,
+                   namespaceId,
+                   stmt->replace,
+                   returnsSet,
+                   prorettype,
+                   languageOid,
+                   prosrc_str, /* converted to text later */
+                   probin_str, /* converted to text later */
+                   false,      /* not an aggregate */
+                   true,       /* (obsolete "trusted") */
+                   isImplicit,
+                   isStrict,
+                   volatility,
+                   byte_pct,
+                   perbyte_cpu,
+                   percall_cpu,
+                   outin_ratio,
+                   parameterCount,
+                   parameterTypes);
+}
+
+
+/*
+ * RemoveFunction
+ *     Deletes a function.
+ *
+ * Exceptions:
+ *     BadArg if name is invalid.
+ *     "ERROR" if function nonexistent.
+ *     ...
+ */
+void
+RemoveFunction(List *functionName,     /* function name to be removed */
+              List *argTypes)  /* list of TypeName nodes */
+{
+   Oid         funcOid;
+   Relation    relation;
+   HeapTuple   tup;
+
+   funcOid = LookupFuncNameTypeNames(functionName, argTypes, 
+                                     true, "RemoveFunction");
+
+   relation = heap_openr(ProcedureRelationName, RowExclusiveLock);
+
+   tup = SearchSysCache(PROCOID,
+                        ObjectIdGetDatum(funcOid),
+                        0, 0, 0);
+   if (!HeapTupleIsValid(tup)) /* should not happen */
+       elog(ERROR, "RemoveFunction: couldn't find tuple for function %s",
+            NameListToString(functionName));
+
+   if (!pg_proc_ownercheck(funcOid, GetUserId()))
+       elog(ERROR, "RemoveFunction: function '%s': permission denied",
+            NameListToString(functionName));
+
+   if (((Form_pg_proc) GETSTRUCT(tup))->proisagg)
+       elog(ERROR, "RemoveFunction: function '%s' is an aggregate"
+            "\n\tUse DROP AGGREGATE to remove it",
+            NameListToString(functionName));
+
+   if (((Form_pg_proc) GETSTRUCT(tup))->prolang == INTERNALlanguageId)
+   {
+       /* "Helpful" WARNING when removing a builtin function ... */
+       elog(WARNING, "Removing built-in function \"%s\"",
+            NameListToString(functionName));
+   }
+
+   /* Delete any comments associated with this function */
+   DeleteComments(funcOid, RelationGetRelid(relation));
+
+   simple_heap_delete(relation, &tup->t_self);
+
+   ReleaseSysCache(tup);
+
+   heap_close(relation, RowExclusiveLock);
+}
diff --git a/src/backend/commands/lockcmds.c b/src/backend/commands/lockcmds.c
new file mode 100644 (file)
index 0000000..c916695
--- /dev/null
@@ -0,0 +1,69 @@
+/*-------------------------------------------------------------------------
+ *
+ * lockcmds.c
+ *   Lock command support code
+ *
+ * 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/commands/lockcmds.c,v 1.1 2002/04/15 05:22:03 tgl Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "access/heapam.h"
+#include "catalog/namespace.h"
+#include "commands/lockcmds.h"
+#include "miscadmin.h"
+#include "utils/acl.h"
+
+
+/*
+ * LOCK TABLE
+ */
+void
+LockTableCommand(LockStmt *lockstmt)
+{
+   List       *p;
+
+   /*
+    * Iterate over the list and open, lock, and close the relations one
+    * at a time
+    */
+
+   foreach(p, lockstmt->relations)
+   {
+       RangeVar   *relation = lfirst(p);
+       Oid         reloid;
+       int32       aclresult;
+       Relation    rel;
+
+       /*
+        * We don't want to open the relation until we've checked privilege.
+        * So, manually get the relation OID.
+        */
+       reloid = RangeVarGetRelid(relation, false);
+
+       if (lockstmt->mode == AccessShareLock)
+           aclresult = pg_class_aclcheck(reloid, GetUserId(),
+                                         ACL_SELECT);
+       else
+           aclresult = pg_class_aclcheck(reloid, GetUserId(),
+                                         ACL_UPDATE | ACL_DELETE);
+
+       if (aclresult != ACLCHECK_OK)
+           elog(ERROR, "LOCK TABLE: permission denied");
+
+       rel = relation_open(reloid, lockstmt->mode);
+
+       /* Currently, we only allow plain tables to be locked */
+       if (rel->rd_rel->relkind != RELKIND_RELATION)
+           elog(ERROR, "LOCK TABLE: %s is not a table",
+                relation->relname);
+
+       relation_close(rel, NoLock);    /* close rel, keep lock */
+   }
+}
diff --git a/src/backend/commands/operatorcmds.c b/src/backend/commands/operatorcmds.c
new file mode 100644 (file)
index 0000000..54f4892
--- /dev/null
@@ -0,0 +1,247 @@
+/*-------------------------------------------------------------------------
+ *
+ * operatorcmds.c
+ *
+ *   Routines for operator manipulation commands
+ *
+ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *   $Header: /cvsroot/pgsql/src/backend/commands/operatorcmds.c,v 1.1 2002/04/15 05:22:03 tgl Exp $
+ *
+ * DESCRIPTION
+ *   The "DefineFoo" routines take the parse tree and pick out the
+ *   appropriate arguments/flags, passing the results to the
+ *   corresponding "FooDefine" routines (in src/catalog) that do
+ *   the actual catalog-munging.  These routines also verify permission
+ *   of the user to execute the command.
+ *
+ * NOTES
+ *   These things must be defined and committed in the following order:
+ *     "create function":
+ *             input/output, recv/send procedures
+ *     "create type":
+ *             type
+ *     "create operator":
+ *             operators
+ *
+ *     Most of the parse-tree manipulation routines are defined in
+ *     commands/manip.c.
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "access/heapam.h"
+#include "catalog/catname.h"
+#include "catalog/namespace.h"
+#include "catalog/pg_operator.h"
+#include "commands/comment.h"
+#include "commands/defrem.h"
+#include "miscadmin.h"
+#include "parser/parse_type.h"
+#include "utils/acl.h"
+#include "utils/syscache.h"
+
+
+/*
+ * DefineOperator
+ *     this function extracts all the information from the
+ *     parameter list generated by the parser and then has
+ *     OperatorCreate() do all the actual work.
+ *
+ * 'parameters' is a list of DefElem
+ */
+void
+DefineOperator(List *names, List *parameters)
+{
+   char       *oprName;
+   Oid         oprNamespace;
+   uint16      precedence = 0; /* operator precedence */
+   bool        canHash = false;    /* operator hashes */
+   bool        isLeftAssociative = true;       /* operator is left
+                                                * associative */
+   char       *functionName = NULL;    /* function for operator */
+   TypeName   *typeName1 = NULL;       /* first type name */
+   TypeName   *typeName2 = NULL;       /* second type name */
+   Oid         typeId1 = InvalidOid;   /* types converted to OID */
+   Oid         typeId2 = InvalidOid;
+   char       *commutatorName = NULL;  /* optional commutator operator
+                                        * name */
+   char       *negatorName = NULL;     /* optional negator operator name */
+   char       *restrictionName = NULL; /* optional restrict. sel.
+                                        * procedure */
+   char       *joinName = NULL;    /* optional join sel. procedure name */
+   char       *sortName1 = NULL;       /* optional first sort operator */
+   char       *sortName2 = NULL;       /* optional second sort operator */
+   List       *pl;
+
+   /* Convert list of names to a name and namespace */
+   oprNamespace = QualifiedNameGetCreationNamespace(names, &oprName);
+
+   /*
+    * loop over the definition list and extract the information we need.
+    */
+   foreach(pl, parameters)
+   {
+       DefElem    *defel = (DefElem *) lfirst(pl);
+
+       if (strcasecmp(defel->defname, "leftarg") == 0)
+       {
+           typeName1 = defGetTypeName(defel);
+           if (typeName1->setof)
+               elog(ERROR, "setof type not implemented for leftarg");
+       }
+       else if (strcasecmp(defel->defname, "rightarg") == 0)
+       {
+           typeName2 = defGetTypeName(defel);
+           if (typeName2->setof)
+               elog(ERROR, "setof type not implemented for rightarg");
+       }
+       else if (strcasecmp(defel->defname, "procedure") == 0)
+           functionName = defGetString(defel);
+       else if (strcasecmp(defel->defname, "precedence") == 0)
+       {
+           /* NOT IMPLEMENTED (never worked in v4.2) */
+           elog(NOTICE, "CREATE OPERATOR: precedence not implemented");
+       }
+       else if (strcasecmp(defel->defname, "associativity") == 0)
+       {
+           /* NOT IMPLEMENTED (never worked in v4.2) */
+           elog(NOTICE, "CREATE OPERATOR: associativity not implemented");
+       }
+       else if (strcasecmp(defel->defname, "commutator") == 0)
+           commutatorName = defGetString(defel);
+       else if (strcasecmp(defel->defname, "negator") == 0)
+           negatorName = defGetString(defel);
+       else if (strcasecmp(defel->defname, "restrict") == 0)
+           restrictionName = defGetString(defel);
+       else if (strcasecmp(defel->defname, "join") == 0)
+           joinName = defGetString(defel);
+       else if (strcasecmp(defel->defname, "hashes") == 0)
+           canHash = TRUE;
+       else if (strcasecmp(defel->defname, "sort1") == 0)
+           sortName1 = defGetString(defel);
+       else if (strcasecmp(defel->defname, "sort2") == 0)
+           sortName2 = defGetString(defel);
+       else
+       {
+           elog(WARNING, "DefineOperator: attribute \"%s\" not recognized",
+                defel->defname);
+       }
+   }
+
+   /*
+    * make sure we have our required definitions
+    */
+   if (functionName == NULL)
+       elog(ERROR, "Define: \"procedure\" unspecified");
+
+   /* Transform type names to type OIDs */
+   if (typeName1)
+       typeId1 = typenameTypeId(typeName1);
+   if (typeName2)
+       typeId2 = typenameTypeId(typeName2);
+
+   /*
+    * now have OperatorCreate do all the work..
+    */
+   OperatorCreate(oprName,     /* operator name */
+                  typeId1,     /* left type id */
+                  typeId2,     /* right type id */
+                  functionName,    /* function for operator */
+                  precedence,  /* operator precedence */
+                  isLeftAssociative,   /* operator is left associative */
+                  commutatorName,      /* optional commutator operator
+                                        * name */
+                  negatorName, /* optional negator operator name */
+                  restrictionName,     /* optional restrict. sel.
+                                        * procedure */
+                  joinName,    /* optional join sel. procedure name */
+                  canHash,     /* operator hashes */
+                  sortName1,   /* optional first sort operator */
+                  sortName2);  /* optional second sort operator */
+
+}
+
+
+/*
+ * RemoveOperator
+ *     Deletes an operator.
+ *
+ * Exceptions:
+ *     BadArg if name is invalid.
+ *     BadArg if type1 is invalid.
+ *     "ERROR" if operator nonexistent.
+ *     ...
+ */
+void
+RemoveOperator(char *operatorName,     /* operator name */
+              TypeName *typeName1, /* left argument type name */
+              TypeName *typeName2) /* right argument type name */
+{
+   Relation    relation;
+   HeapTuple   tup;
+   Oid         typeId1 = InvalidOid;
+   Oid         typeId2 = InvalidOid;
+   char        oprtype;
+
+   if (typeName1)
+       typeId1 = typenameTypeId(typeName1);
+
+   if (typeName2)
+       typeId2 = typenameTypeId(typeName2);
+
+   if (OidIsValid(typeId1) && OidIsValid(typeId2))
+       oprtype = 'b';
+   else if (OidIsValid(typeId1))
+       oprtype = 'r';
+   else
+       oprtype = 'l';
+
+   relation = heap_openr(OperatorRelationName, RowExclusiveLock);
+
+   tup = SearchSysCacheCopy(OPERNAME,
+                            PointerGetDatum(operatorName),
+                            ObjectIdGetDatum(typeId1),
+                            ObjectIdGetDatum(typeId2),
+                            CharGetDatum(oprtype));
+
+   if (HeapTupleIsValid(tup))
+   {
+       if (!pg_oper_ownercheck(tup->t_data->t_oid, GetUserId()))
+           elog(ERROR, "RemoveOperator: operator '%s': permission denied",
+                operatorName);
+
+       /* Delete any comments associated with this operator */
+       DeleteComments(tup->t_data->t_oid, RelationGetRelid(relation));
+
+       simple_heap_delete(relation, &tup->t_self);
+   }
+   else
+   {
+       if (OidIsValid(typeId1) && OidIsValid(typeId2))
+       {
+           elog(ERROR, "RemoveOperator: binary operator '%s' taking '%s' and '%s' does not exist",
+                operatorName,
+                TypeNameToString(typeName1),
+                TypeNameToString(typeName2));
+       }
+       else if (OidIsValid(typeId1))
+       {
+           elog(ERROR, "RemoveOperator: right unary operator '%s' taking '%s' does not exist",
+                operatorName,
+                TypeNameToString(typeName1));
+       }
+       else
+       {
+           elog(ERROR, "RemoveOperator: left unary operator '%s' taking '%s' does not exist",
+                operatorName,
+                TypeNameToString(typeName2));
+       }
+   }
+   heap_freetuple(tup);
+   heap_close(relation, RowExclusiveLock);
+}
diff --git a/src/backend/commands/portalcmds.c b/src/backend/commands/portalcmds.c
new file mode 100644 (file)
index 0000000..6f690c0
--- /dev/null
@@ -0,0 +1,234 @@
+/*-------------------------------------------------------------------------
+ *
+ * portalcmds.c
+ *   portal support code
+ *
+ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *   $Header: /cvsroot/pgsql/src/backend/commands/portalcmds.c,v 1.1 2002/04/15 05:22:03 tgl Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+
+#include "commands/portalcmds.h"
+#include "executor/executor.h"
+
+
+/*
+ * PortalCleanup
+ */
+void
+PortalCleanup(Portal portal)
+{
+   MemoryContext oldcontext;
+
+   /*
+    * sanity checks
+    */
+   AssertArg(PortalIsValid(portal));
+   AssertArg(portal->cleanup == PortalCleanup);
+
+   /*
+    * set proper portal-executor context before calling ExecMain.
+    */
+   oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
+
+   /*
+    * tell the executor to shutdown the query
+    */
+   ExecutorEnd(PortalGetQueryDesc(portal), PortalGetState(portal));
+
+   /*
+    * switch back to previous context
+    */
+   MemoryContextSwitchTo(oldcontext);
+}
+
+
+/*
+ * PerformPortalFetch
+ *
+ * name: name of portal
+ * forward: forward or backward fetch?
+ * count: # of tuples to fetch (0 implies all)
+ * dest: where to send results
+ * completionTag: points to a buffer of size COMPLETION_TAG_BUFSIZE
+ *     in which to store a command completion status string.
+ *
+ * completionTag may be NULL if caller doesn't want a status string.
+ */
+void
+PerformPortalFetch(char *name,
+                  bool forward,
+                  int count,
+                  CommandDest dest,
+                  char *completionTag)
+{
+   Portal      portal;
+   QueryDesc  *queryDesc;
+   EState     *estate;
+   MemoryContext oldcontext;
+   ScanDirection direction;
+   CommandId   savedId;
+   bool        temp_desc = false;
+
+   /* initialize completion status in case of early exit */
+   if (completionTag)
+       strcpy(completionTag, (dest == None) ? "MOVE 0" : "FETCH 0");
+
+   /*
+    * sanity checks
+    */
+   if (name == NULL)
+   {
+       elog(WARNING, "PerformPortalFetch: missing portal name");
+       return;
+   }
+
+   /*
+    * get the portal from the portal name
+    */
+   portal = GetPortalByName(name);
+   if (!PortalIsValid(portal))
+   {
+       elog(WARNING, "PerformPortalFetch: portal \"%s\" not found",
+            name);
+       return;
+   }
+
+   /*
+    * switch into the portal context
+    */
+   oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
+
+   queryDesc = PortalGetQueryDesc(portal);
+   estate = PortalGetState(portal);
+
+   /*
+    * If the requested destination is not the same as the query's
+    * original destination, make a temporary QueryDesc with the proper
+    * destination.  This supports MOVE, for example, which will pass in
+    * dest = None.
+    *
+    * EXCEPTION: if the query's original dest is RemoteInternal (ie, it's a
+    * binary cursor) and the request is Remote, we do NOT override the
+    * original dest.  This is necessary since a FETCH command will pass
+    * dest = Remote, not knowing whether the cursor is binary or not.
+    */
+   if (dest != queryDesc->dest &&
+       !(queryDesc->dest == RemoteInternal && dest == Remote))
+   {
+       QueryDesc  *qdesc = (QueryDesc *) palloc(sizeof(QueryDesc));
+
+       memcpy(qdesc, queryDesc, sizeof(QueryDesc));
+       qdesc->dest = dest;
+       queryDesc = qdesc;
+       temp_desc = true;
+   }
+
+   /*
+    * Restore the scanCommandId that was current when the cursor was
+    * opened.  This ensures that we see the same tuples throughout the
+    * execution of the cursor.
+    */
+   savedId = GetScanCommandId();
+   SetScanCommandId(PortalGetCommandId(portal));
+
+   /*
+    * Determine which direction to go in, and check to see if we're
+    * already at the end of the available tuples in that direction.  If
+    * so, set the direction to NoMovement to avoid trying to fetch any
+    * tuples.  (This check exists because not all plan node types
+    * are robust about being called again if they've already returned
+    * NULL once.)  Then call the executor (we must not skip this, because
+    * the destination needs to see a setup and shutdown even if no tuples
+    * are available).  Finally, update the atStart/atEnd state depending
+    * on the number of tuples that were retrieved.
+    */
+   if (forward)
+   {
+       if (portal->atEnd)
+           direction = NoMovementScanDirection;
+       else
+           direction = ForwardScanDirection;
+
+       ExecutorRun(queryDesc, estate, direction, (long) count);
+
+       if (estate->es_processed > 0)
+           portal->atStart = false; /* OK to back up now */
+       if (count <= 0 || (int) estate->es_processed < count)
+           portal->atEnd = true;   /* we retrieved 'em all */
+   }
+   else
+   {
+       if (portal->atStart)
+           direction = NoMovementScanDirection;
+       else
+           direction = BackwardScanDirection;
+
+       ExecutorRun(queryDesc, estate, direction, (long) count);
+
+       if (estate->es_processed > 0)
+           portal->atEnd = false;  /* OK to go forward now */
+       if (count <= 0 || (int) estate->es_processed < count)
+           portal->atStart = true; /* we retrieved 'em all */
+   }
+
+   /* Return command status if wanted */
+   if (completionTag)
+       snprintf(completionTag, COMPLETION_TAG_BUFSIZE, "%s %u",
+                (dest == None) ? "MOVE" : "FETCH",
+                estate->es_processed);
+
+   /*
+    * Restore outer command ID.
+    */
+   SetScanCommandId(savedId);
+
+   /*
+    * Clean up and switch back to old context.
+    */
+   if (temp_desc)
+       pfree(queryDesc);
+
+   MemoryContextSwitchTo(oldcontext);
+}
+
+/*
+ * PerformPortalClose
+ */
+void
+PerformPortalClose(char *name, CommandDest dest)
+{
+   Portal      portal;
+
+   /*
+    * sanity checks
+    */
+   if (name == NULL)
+   {
+       elog(WARNING, "PerformPortalClose: missing portal name");
+       return;
+   }
+
+   /*
+    * get the portal from the portal name
+    */
+   portal = GetPortalByName(name);
+   if (!PortalIsValid(portal))
+   {
+       elog(WARNING, "PerformPortalClose: portal \"%s\" not found",
+            name);
+       return;
+   }
+
+   /*
+    * Note: PortalCleanup is called as a side-effect
+    */
+   PortalDrop(portal);
+}
index 4ef8d8f72a0bee3b3a69cab019cd467181aa6bd2..2ad25fdbd4f2cf977f9cd78175e99cd70b7a40b9 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/commands/proclang.c,v 1.30 2002/04/09 20:35:48 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/commands/proclang.c,v 1.31 2002/04/15 05:22:03 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -22,6 +22,7 @@
 #include "catalog/pg_language.h"
 #include "catalog/pg_proc.h"
 #include "commands/proclang.h"
+#include "commands/defrem.h"
 #include "fmgr.h"
 #include "miscadmin.h"
 #include "parser/parse_func.h"
 #include "utils/syscache.h"
 
 
-/*
- * Translate the input language name to lower case.
- */
-static void
-case_translate_language_name(const char *input, char *output)
-{
-   int         i;
-
-   for (i = 0; i < NAMEDATALEN && input[i]; ++i)
-       output[i] = tolower((unsigned char) input[i]);
-
-   output[i] = '\0';
-}
-
-
 /* ---------------------------------------------------------------------
  * CREATE PROCEDURAL LANGUAGE
  * ---------------------------------------------------------------------
diff --git a/src/backend/commands/remove.c b/src/backend/commands/remove.c
deleted file mode 100644 (file)
index c32d2b2..0000000
+++ /dev/null
@@ -1,476 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * remove.c
- *   POSTGRES remove (domain | function | type | operator ) utilty code.
- *
- * 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/commands/Attic/remove.c,v 1.74 2002/04/11 19:59:58 tgl Exp $
- *
- *-------------------------------------------------------------------------
- */
-#include "postgres.h"
-
-#include "access/heapam.h"
-#include "catalog/catname.h"
-#include "catalog/namespace.h"
-#include "catalog/pg_language.h"
-#include "catalog/pg_proc.h"
-#include "catalog/pg_type.h"
-#include "commands/comment.h"
-#include "commands/defrem.h"
-#include "miscadmin.h"
-#include "parser/parse.h"
-#include "parser/parse_func.h"
-#include "parser/parse_type.h"
-#include "utils/acl.h"
-#include "utils/builtins.h"
-#include "utils/syscache.h"
-
-
-/*
- * RemoveOperator
- *     Deletes an operator.
- *
- * Exceptions:
- *     BadArg if name is invalid.
- *     BadArg if type1 is invalid.
- *     "ERROR" if operator nonexistent.
- *     ...
- */
-void
-RemoveOperator(char *operatorName,     /* operator name */
-              TypeName *typeName1, /* left argument type name */
-              TypeName *typeName2) /* right argument type name */
-{
-   Relation    relation;
-   HeapTuple   tup;
-   Oid         typeId1 = InvalidOid;
-   Oid         typeId2 = InvalidOid;
-   char        oprtype;
-
-   if (typeName1)
-       typeId1 = typenameTypeId(typeName1);
-
-   if (typeName2)
-       typeId2 = typenameTypeId(typeName2);
-
-   if (OidIsValid(typeId1) && OidIsValid(typeId2))
-       oprtype = 'b';
-   else if (OidIsValid(typeId1))
-       oprtype = 'r';
-   else
-       oprtype = 'l';
-
-   relation = heap_openr(OperatorRelationName, RowExclusiveLock);
-
-   tup = SearchSysCacheCopy(OPERNAME,
-                            PointerGetDatum(operatorName),
-                            ObjectIdGetDatum(typeId1),
-                            ObjectIdGetDatum(typeId2),
-                            CharGetDatum(oprtype));
-
-   if (HeapTupleIsValid(tup))
-   {
-       if (!pg_oper_ownercheck(tup->t_data->t_oid, GetUserId()))
-           elog(ERROR, "RemoveOperator: operator '%s': permission denied",
-                operatorName);
-
-       /* Delete any comments associated with this operator */
-       DeleteComments(tup->t_data->t_oid, RelationGetRelid(relation));
-
-       simple_heap_delete(relation, &tup->t_self);
-   }
-   else
-   {
-       if (OidIsValid(typeId1) && OidIsValid(typeId2))
-       {
-           elog(ERROR, "RemoveOperator: binary operator '%s' taking '%s' and '%s' does not exist",
-                operatorName,
-                TypeNameToString(typeName1),
-                TypeNameToString(typeName2));
-       }
-       else if (OidIsValid(typeId1))
-       {
-           elog(ERROR, "RemoveOperator: right unary operator '%s' taking '%s' does not exist",
-                operatorName,
-                TypeNameToString(typeName1));
-       }
-       else
-       {
-           elog(ERROR, "RemoveOperator: left unary operator '%s' taking '%s' does not exist",
-                operatorName,
-                TypeNameToString(typeName2));
-       }
-   }
-   heap_freetuple(tup);
-   heap_close(relation, RowExclusiveLock);
-}
-
-#ifdef NOTYET
-/*
- * this stuff is to support removing all reference to a type
- * don't use it  - pma 2/1/94
- */
-/*
- * SingleOpOperatorRemove
- *     Removes all operators that have operands or a result of type 'typeOid'.
- */
-static void
-SingleOpOperatorRemove(Oid typeOid)
-{
-   Relation    rel;
-   ScanKeyData key[3];
-   HeapScanDesc scan;
-   HeapTuple   tup;
-   static      attnums[3] = {7, 8, 9}; /* left, right, return */
-   int         i;
-
-   ScanKeyEntryInitialize(&key[0],
-                          0, 0, F_OIDEQ, (Datum) typeOid);
-   rel = heap_openr(OperatorRelationName, RowExclusiveLock);
-   for (i = 0; i < 3; ++i)
-   {
-       key[0].sk_attno = attnums[i];
-       scan = heap_beginscan(rel, 0, SnapshotNow, 1, key);
-       while (HeapTupleIsValid(tup = heap_getnext(scan, 0)))
-       {
-           /* Delete any comments associated with this operator */
-           DeleteComments(tup->t_data->t_oid, RelationGetRelid(rel));
-
-           simple_heap_delete(rel, &tup->t_self);
-       }
-
-       heap_endscan(scan);
-   }
-   heap_close(rel, RowExclusiveLock);
-}
-
-/*
- * AttributeAndRelationRemove
- *     Removes all entries in the attribute and relation relations
- *     that contain entries of type 'typeOid'.
- *     Currently nothing calls this code, it is untested.
- */
-static void
-AttributeAndRelationRemove(Oid typeOid)
-{
-   struct oidlist
-   {
-       Oid         reloid;
-       struct oidlist *next;
-   };
-   struct oidlist *oidptr,
-              *optr;
-   Relation    rel;
-   ScanKeyData key[1];
-   HeapScanDesc scan;
-   HeapTuple   tup;
-
-   /*
-    * Get the oid's of the relations to be removed by scanning the entire
-    * attribute relation. We don't need to remove the attributes here,
-    * because amdestroy will remove all attributes of the relation. XXX
-    * should check for duplicate relations
-    */
-
-   ScanKeyEntryInitialize(&key[0],
-                          0, 3, F_OIDEQ, (Datum) typeOid);
-
-   oidptr = (struct oidlist *) palloc(sizeof(*oidptr));
-   oidptr->next = NULL;
-   optr = oidptr;
-   rel = heap_openr(AttributeRelationName, AccessShareLock);
-   scan = heap_beginscan(rel, 0, SnapshotNow, 1, key);
-   while (HeapTupleIsValid(tup = heap_getnext(scan, 0)))
-   {
-       optr->reloid = ((Form_pg_attribute) GETSTRUCT(tup))->attrelid;
-       optr->next = (struct oidlist *) palloc(sizeof(*oidptr));
-       optr = optr->next;
-   }
-   optr->next = NULL;
-   heap_endscan(scan);
-   heap_close(rel, AccessShareLock);
-
-   optr = oidptr;
-
-   ScanKeyEntryInitialize(&key[0], 0,
-                          ObjectIdAttributeNumber,
-                          F_OIDEQ, (Datum) 0);
-   /* get RowExclusiveLock because heap_destroy will need it */
-   rel = heap_openr(RelationRelationName, RowExclusiveLock);
-   while (PointerIsValid((char *) optr->next))
-   {
-       Oid     relOid = (optr++)->reloid;
-
-       key[0].sk_argument = ObjectIdGetDatum(relOid);
-       scan = heap_beginscan(rel, 0, SnapshotNow, 1, key);
-       tup = heap_getnext(scan, 0);
-       if (HeapTupleIsValid(tup))
-           heap_drop_with_catalog(relOid, allowSystemTableMods);
-       heap_endscan(scan);
-   }
-   heap_close(rel, RowExclusiveLock);
-}
-#endif   /* NOTYET */
-
-/*
- * TypeRemove
- *     Removes a datatype.
- *
- * NOTE: since this tries to remove the associated array type too, it'll
- * only work on scalar types.
- */
-void
-RemoveType(List *names)
-{
-   TypeName   *typename;
-   Relation    relation;
-   Oid         typeoid;
-   HeapTuple   tup;
-
-   /* Make a TypeName so we can use standard type lookup machinery */
-   typename = makeNode(TypeName);
-   typename->names = names;
-   typename->typmod = -1;
-   typename->arrayBounds = NIL;
-
-   relation = heap_openr(TypeRelationName, RowExclusiveLock);
-
-   /* Use LookupTypeName here so that shell types can be removed. */
-   typeoid = LookupTypeName(typename);
-   if (!OidIsValid(typeoid))
-       elog(ERROR, "Type \"%s\" does not exist",
-            TypeNameToString(typename));
-
-   tup = SearchSysCache(TYPEOID,
-                        ObjectIdGetDatum(typeoid),
-                        0, 0, 0);
-   if (!HeapTupleIsValid(tup))
-       elog(ERROR, "Type \"%s\" does not exist",
-            TypeNameToString(typename));
-
-   if (!pg_type_ownercheck(typeoid, GetUserId()))
-       elog(ERROR, "RemoveType: type '%s': permission denied",
-            TypeNameToString(typename));
-
-   /* Delete any comments associated with this type */
-   DeleteComments(typeoid, RelationGetRelid(relation));
-
-   /* Remove the type tuple from pg_type */
-   simple_heap_delete(relation, &tup->t_self);
-
-   ReleaseSysCache(tup);
-
-   /* Now, delete the "array of" that type */
-   typename->arrayBounds = makeList1(makeInteger(1));
-
-   typeoid = LookupTypeName(typename);
-   if (!OidIsValid(typeoid))
-       elog(ERROR, "Type \"%s\" does not exist",
-            TypeNameToString(typename));
-
-   tup = SearchSysCache(TYPEOID,
-                        ObjectIdGetDatum(typeoid),
-                        0, 0, 0);
-   if (!HeapTupleIsValid(tup))
-       elog(ERROR, "Type \"%s\" does not exist",
-            TypeNameToString(typename));
-
-   DeleteComments(typeoid, RelationGetRelid(relation));
-
-   simple_heap_delete(relation, &tup->t_self);
-
-   ReleaseSysCache(tup);
-
-   heap_close(relation, RowExclusiveLock);
-}
-
-/*
- * RemoveDomain
- *     Removes a domain.
- */
-void
-RemoveDomain(List *names, int behavior)
-{
-   TypeName   *typename;
-   Relation    relation;
-   Oid         typeoid;
-   HeapTuple   tup;
-   char        typtype;
-
-   /* CASCADE unsupported */
-   if (behavior == CASCADE)
-       elog(ERROR, "DROP DOMAIN does not support the CASCADE keyword");
-
-   /* Make a TypeName so we can use standard type lookup machinery */
-   typename = makeNode(TypeName);
-   typename->names = names;
-   typename->typmod = -1;
-   typename->arrayBounds = NIL;
-
-   relation = heap_openr(TypeRelationName, RowExclusiveLock);
-
-   typeoid = typenameTypeId(typename);
-
-   tup = SearchSysCache(TYPEOID,
-                        ObjectIdGetDatum(typeoid),
-                        0, 0, 0);
-   if (!HeapTupleIsValid(tup))
-       elog(ERROR, "RemoveDomain: type '%s' does not exist",
-            TypeNameToString(typename));
-
-   if (!pg_type_ownercheck(typeoid, GetUserId()))
-       elog(ERROR, "RemoveDomain: type '%s': permission denied",
-            TypeNameToString(typename));
-
-   /* Check that this is actually a domain */
-   typtype = ((Form_pg_type) GETSTRUCT(tup))->typtype;
-
-   if (typtype != 'd')
-       elog(ERROR, "%s is not a domain",
-            TypeNameToString(typename));
-
-   /* Delete any comments associated with this type */
-   DeleteComments(typeoid, RelationGetRelid(relation));
-
-   /* Remove the type tuple from pg_type */
-   simple_heap_delete(relation, &tup->t_self);
-
-   ReleaseSysCache(tup);
-
-   /* At present, domains don't have associated array types */
-
-   heap_close(relation, RowExclusiveLock);
-}
-
-/*
- * RemoveFunction
- *     Deletes a function.
- *
- * Exceptions:
- *     BadArg if name is invalid.
- *     "ERROR" if function nonexistent.
- *     ...
- */
-void
-RemoveFunction(List *functionName,     /* function name to be removed */
-              List *argTypes)  /* list of TypeName nodes */
-{
-   Oid         funcOid;
-   Relation    relation;
-   HeapTuple   tup;
-
-   funcOid = LookupFuncNameTypeNames(functionName, argTypes, 
-                                     true, "RemoveFunction");
-
-   relation = heap_openr(ProcedureRelationName, RowExclusiveLock);
-
-   tup = SearchSysCache(PROCOID,
-                        ObjectIdGetDatum(funcOid),
-                        0, 0, 0);
-   if (!HeapTupleIsValid(tup)) /* should not happen */
-       elog(ERROR, "RemoveFunction: couldn't find tuple for function %s",
-            NameListToString(functionName));
-
-   if (!pg_proc_ownercheck(funcOid, GetUserId()))
-       elog(ERROR, "RemoveFunction: function '%s': permission denied",
-            NameListToString(functionName));
-
-   if (((Form_pg_proc) GETSTRUCT(tup))->proisagg)
-       elog(ERROR, "RemoveFunction: function '%s' is an aggregate"
-            "\n\tUse DROP AGGREGATE to remove it",
-            NameListToString(functionName));
-
-   if (((Form_pg_proc) GETSTRUCT(tup))->prolang == INTERNALlanguageId)
-   {
-       /* "Helpful" WARNING when removing a builtin function ... */
-       elog(WARNING, "Removing built-in function \"%s\"",
-            NameListToString(functionName));
-   }
-
-   /* Delete any comments associated with this function */
-   DeleteComments(funcOid, RelationGetRelid(relation));
-
-   simple_heap_delete(relation, &tup->t_self);
-
-   ReleaseSysCache(tup);
-
-   heap_close(relation, RowExclusiveLock);
-}
-
-void
-RemoveAggregate(List *aggName, TypeName *aggType)
-{
-   Relation    relation;
-   HeapTuple   tup;
-   Oid         basetypeID;
-   Oid         procOid;
-
-   /*
-    * if a basetype is passed in, then attempt to find an aggregate for
-    * that specific type.
-    *
-    * else if the basetype is blank, then attempt to find an aggregate with
-    * a basetype of zero.  This is valid. It means that the aggregate is
-    * to apply to all basetypes (eg, COUNT).
-    */
-   if (aggType)
-       basetypeID = typenameTypeId(aggType);
-   else
-       basetypeID = InvalidOid;
-
-   procOid = find_aggregate_func("RemoveAggregate", aggName, basetypeID);
-
-   /* Permission check */
-
-   if (!pg_proc_ownercheck(procOid, GetUserId()))
-   {
-       if (basetypeID == InvalidOid)
-           elog(ERROR, "RemoveAggregate: aggregate %s for all types: permission denied",
-                NameListToString(aggName));
-       else
-           elog(ERROR, "RemoveAggregate: aggregate %s for type %s: permission denied",
-                NameListToString(aggName), format_type_be(basetypeID));
-   }
-
-   /* Remove the pg_proc tuple */
-
-   relation = heap_openr(ProcedureRelationName, RowExclusiveLock);
-
-   tup = SearchSysCache(PROCOID,
-                        ObjectIdGetDatum(procOid),
-                        0, 0, 0);
-   if (!HeapTupleIsValid(tup)) /* should not happen */
-       elog(ERROR, "RemoveAggregate: couldn't find pg_proc tuple for %s",
-            NameListToString(aggName));
-
-   /* Delete any comments associated with this function */
-   DeleteComments(procOid, RelationGetRelid(relation));
-
-   simple_heap_delete(relation, &tup->t_self);
-
-   ReleaseSysCache(tup);
-
-   heap_close(relation, RowExclusiveLock);
-
-   /* Remove the pg_aggregate tuple */
-
-   relation = heap_openr(AggregateRelationName, RowExclusiveLock);
-
-   tup = SearchSysCache(AGGFNOID,
-                        ObjectIdGetDatum(procOid),
-                        0, 0, 0);
-   if (!HeapTupleIsValid(tup)) /* should not happen */
-       elog(ERROR, "RemoveAggregate: couldn't find pg_aggregate tuple for %s",
-            NameListToString(aggName));
-
-   simple_heap_delete(relation, &tup->t_self);
-
-   ReleaseSysCache(tup);
-
-   heap_close(relation, RowExclusiveLock);
-}
diff --git a/src/backend/commands/rename.c b/src/backend/commands/rename.c
deleted file mode 100644 (file)
index 21db59b..0000000
+++ /dev/null
@@ -1,591 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * rename.c
- *   renameatt() and renamerel() reside here.
- *
- * 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/commands/Attic/rename.c,v 1.70 2002/04/12 20:38:24 tgl Exp $
- *
- *-------------------------------------------------------------------------
- */
-#include "postgres.h"
-
-#include 
-
-#include "access/genam.h"
-#include "access/heapam.h"
-#include "access/itup.h"
-#include "catalog/catname.h"
-#include "catalog/pg_index.h"
-#include "catalog/pg_trigger.h"
-#include "catalog/pg_type.h"
-#include "catalog/heap.h"
-#include "catalog/indexing.h"
-#include "catalog/catalog.h"
-#include "commands/rename.h"
-#include "commands/trigger.h"
-#include "miscadmin.h"
-#include "storage/smgr.h"
-#include "optimizer/prep.h"
-#include "rewrite/rewriteDefine.h"
-#include "rewrite/rewriteSupport.h"
-#include "utils/acl.h"
-#include "utils/builtins.h"
-#include "utils/fmgroids.h"
-#include "utils/lsyscache.h"
-#include "utils/relcache.h"
-#include "utils/syscache.h"
-
-
-#define RI_TRIGGER_PK  1       /* is a trigger on the PK relation */
-#define RI_TRIGGER_FK  2       /* is a trigger on the FK relation */
-#define RI_TRIGGER_NONE 0      /* is not an RI trigger function */
-
-static int ri_trigger_type(Oid tgfoid);
-static void update_ri_trigger_args(Oid relid,
-                      const char *oldname,
-                      const char *newname,
-                      bool fk_scan,
-                      bool update_relname);
-
-
-/*
- *     renameatt       - changes the name of a attribute in a relation
- *
- *     Attname attribute is changed in attribute catalog.
- *     No record of the previous attname is kept (correct?).
- *
- *     get proper relrelation from relation catalog (if not arg)
- *     scan attribute catalog
- *             for name conflict (within rel)
- *             for original attribute (if not arg)
- *     modify attname in attribute tuple
- *     insert modified attribute in attribute catalog
- *     delete original attribute from attribute catalog
- */
-void
-renameatt(Oid relid,
-         const char *oldattname,
-         const char *newattname,
-         bool recurse)
-{
-   Relation    targetrelation;
-   Relation    attrelation;
-   HeapTuple   atttup;
-   List       *indexoidlist;
-   List       *indexoidscan;
-
-   /*
-    * Grab an exclusive lock on the target table, which we will NOT
-    * release until end of transaction.
-    */
-   targetrelation = heap_open(relid, AccessExclusiveLock);
-
-   /*
-    * permissions checking.  this would normally be done in utility.c,
-    * but this particular routine is recursive.
-    *
-    * normally, only the owner of a class can change its schema.
-    */
-   if (!allowSystemTableMods 
-       && IsSystemRelation(targetrelation))
-       elog(ERROR, "renameatt: class \"%s\" is a system catalog",
-            RelationGetRelationName(targetrelation));
-   if (!pg_class_ownercheck(relid, GetUserId()))
-       elog(ERROR, "renameatt: you do not own class \"%s\"",
-            RelationGetRelationName(targetrelation));
-
-   /*
-    * if the 'recurse' flag is set then we are supposed to rename this
-    * attribute in all classes that inherit from 'relname' (as well as in
-    * 'relname').
-    *
-    * any permissions or problems with duplicate attributes will cause the
-    * whole transaction to abort, which is what we want -- all or
-    * nothing.
-    */
-   if (recurse)
-   {
-       List       *child,
-                  *children;
-
-       /* this routine is actually in the planner */
-       children = find_all_inheritors(relid);
-
-       /*
-        * find_all_inheritors does the recursive search of the
-        * inheritance hierarchy, so all we have to do is process all of
-        * the relids in the list that it returns.
-        */
-       foreach(child, children)
-       {
-           Oid         childrelid = lfirsti(child);
-
-           if (childrelid == relid)
-               continue;
-           /* note we need not recurse again! */
-           renameatt(childrelid, oldattname, newattname, false);
-       }
-   }
-
-   attrelation = heap_openr(AttributeRelationName, RowExclusiveLock);
-
-   atttup = SearchSysCacheCopy(ATTNAME,
-                               ObjectIdGetDatum(relid),
-                               PointerGetDatum(oldattname),
-                               0, 0);
-   if (!HeapTupleIsValid(atttup))
-       elog(ERROR, "renameatt: attribute \"%s\" does not exist", oldattname);
-
-   if (((Form_pg_attribute) GETSTRUCT(atttup))->attnum < 0)
-       elog(ERROR, "renameatt: system attribute \"%s\" not renamed", oldattname);
-
-   /* should not already exist */
-   if (SearchSysCacheExists(ATTNAME,
-                            ObjectIdGetDatum(relid),
-                            PointerGetDatum(newattname),
-                            0, 0))
-       elog(ERROR, "renameatt: attribute \"%s\" exists", newattname);
-
-   StrNCpy(NameStr(((Form_pg_attribute) GETSTRUCT(atttup))->attname),
-           newattname, NAMEDATALEN);
-
-   simple_heap_update(attrelation, &atttup->t_self, atttup);
-
-   /* keep system catalog indices current */
-   {
-       Relation    irelations[Num_pg_attr_indices];
-
-       CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, irelations);
-       CatalogIndexInsert(irelations, Num_pg_attr_indices, attrelation, atttup);
-       CatalogCloseIndices(Num_pg_attr_indices, irelations);
-   }
-
-   heap_freetuple(atttup);
-
-   /*
-    * Update column names of indexes that refer to the column being
-    * renamed.
-    */
-   indexoidlist = RelationGetIndexList(targetrelation);
-
-   foreach(indexoidscan, indexoidlist)
-   {
-       Oid         indexoid = lfirsti(indexoidscan);
-       HeapTuple   indextup;
-
-       /*
-        * First check to see if index is a functional index. If so, its
-        * column name is a function name and shouldn't be renamed here.
-        */
-       indextup = SearchSysCache(INDEXRELID,
-                                 ObjectIdGetDatum(indexoid),
-                                 0, 0, 0);
-       if (!HeapTupleIsValid(indextup))
-           elog(ERROR, "renameatt: can't find index id %u", indexoid);
-       if (OidIsValid(((Form_pg_index) GETSTRUCT(indextup))->indproc))
-       {
-           ReleaseSysCache(indextup);
-           continue;
-       }
-       ReleaseSysCache(indextup);
-
-       /*
-        * Okay, look to see if any column name of the index matches the
-        * old attribute name.
-        */
-       atttup = SearchSysCacheCopy(ATTNAME,
-                                   ObjectIdGetDatum(indexoid),
-                                   PointerGetDatum(oldattname),
-                                   0, 0);
-       if (!HeapTupleIsValid(atttup))
-           continue;           /* Nope, so ignore it */
-
-       /*
-        * Update the (copied) attribute tuple.
-        */
-       StrNCpy(NameStr(((Form_pg_attribute) GETSTRUCT(atttup))->attname),
-               newattname, NAMEDATALEN);
-
-       simple_heap_update(attrelation, &atttup->t_self, atttup);
-
-       /* keep system catalog indices current */
-       {
-           Relation    irelations[Num_pg_attr_indices];
-
-           CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, irelations);
-           CatalogIndexInsert(irelations, Num_pg_attr_indices, attrelation, atttup);
-           CatalogCloseIndices(Num_pg_attr_indices, irelations);
-       }
-       heap_freetuple(atttup);
-   }
-
-   freeList(indexoidlist);
-
-   heap_close(attrelation, RowExclusiveLock);
-
-   /*
-    * Update att name in any RI triggers associated with the relation.
-    */
-   if (targetrelation->rd_rel->reltriggers > 0)
-   {
-       /* update tgargs column reference where att is primary key */
-       update_ri_trigger_args(RelationGetRelid(targetrelation),
-                              oldattname, newattname,
-                              false, false);
-       /* update tgargs column reference where att is foreign key */
-       update_ri_trigger_args(RelationGetRelid(targetrelation),
-                              oldattname, newattname,
-                              true, false);
-   }
-
-   heap_close(targetrelation, NoLock); /* close rel but keep lock! */
-}
-
-/*
- *     renamerel       - change the name of a relation
- *
- *     XXX - When renaming sequences, we don't bother to modify the
- *           sequence name that is stored within the sequence itself
- *           (this would cause problems with MVCC). In the future,
- *           the sequence name should probably be removed from the
- *           sequence, AFAIK there's no need for it to be there.
- */
-void
-renamerel(Oid relid, const char *newrelname)
-{
-   Relation    targetrelation;
-   Relation    relrelation;    /* for RELATION relation */
-   HeapTuple   reltup;
-   Oid         namespaceId;
-   char        relkind;
-   bool        relhastriggers;
-   Relation    irelations[Num_pg_class_indices];
-
-   /*
-    * Grab an exclusive lock on the target table or index, which we will
-    * NOT release until end of transaction.
-    */
-   targetrelation = relation_open(relid, AccessExclusiveLock);
-
-   namespaceId = RelationGetNamespace(targetrelation);
-
-   /* Validity checks */
-   if (!allowSystemTableMods &&
-       IsSystemRelation(targetrelation))
-       elog(ERROR, "renamerel: system relation \"%s\" may not be renamed",
-            RelationGetRelationName(targetrelation));
-
-   relkind = targetrelation->rd_rel->relkind;
-   relhastriggers = (targetrelation->rd_rel->reltriggers > 0);
-
-   /*
-    * Find relation's pg_class tuple, and make sure newrelname isn't in
-    * use.
-    */
-   relrelation = heap_openr(RelationRelationName, RowExclusiveLock);
-
-   reltup = SearchSysCacheCopy(RELOID,
-                               PointerGetDatum(relid),
-                               0, 0, 0);
-   if (!HeapTupleIsValid(reltup))
-       elog(ERROR, "renamerel: relation \"%s\" does not exist",
-            RelationGetRelationName(targetrelation));
-
-   if (get_relname_relid(newrelname, namespaceId) != InvalidOid)
-       elog(ERROR, "renamerel: relation \"%s\" exists", newrelname);
-
-   /*
-    * Update pg_class tuple with new relname.  (Scribbling on reltup is
-    * OK because it's a copy...)
-    */
-   StrNCpy(NameStr(((Form_pg_class) GETSTRUCT(reltup))->relname),
-           newrelname, NAMEDATALEN);
-
-   simple_heap_update(relrelation, &reltup->t_self, reltup);
-
-   /* keep the system catalog indices current */
-   CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, irelations);
-   CatalogIndexInsert(irelations, Num_pg_class_indices, relrelation, reltup);
-   CatalogCloseIndices(Num_pg_class_indices, irelations);
-
-   heap_close(relrelation, NoLock);
-   heap_freetuple(reltup);
-
-   /*
-    * Also rename the associated type, if any.
-    */
-   if (relkind != RELKIND_INDEX)
-       TypeRename(RelationGetRelationName(targetrelation), namespaceId,
-                  newrelname);
-
-   /*
-    * If it's a view, must also rename the associated ON SELECT rule.
-    */
-   if (relkind == RELKIND_VIEW)
-   {
-       char       *oldrulename,
-                  *newrulename;
-
-       oldrulename = MakeRetrieveViewRuleName(RelationGetRelationName(targetrelation));
-       newrulename = MakeRetrieveViewRuleName(newrelname);
-       RenameRewriteRule(oldrulename, newrulename);
-   }
-
-   /*
-    * Update rel name in any RI triggers associated with the relation.
-    */
-   if (relhastriggers)
-   {
-       /* update tgargs where relname is primary key */
-       update_ri_trigger_args(relid,
-                              RelationGetRelationName(targetrelation),
-                              newrelname,
-                              false, true);
-       /* update tgargs where relname is foreign key */
-       update_ri_trigger_args(relid,
-                              RelationGetRelationName(targetrelation),
-                              newrelname,
-                              true, true);
-   }
-
-   /*
-    * Close rel, but keep exclusive lock!
-    */
-   relation_close(targetrelation, NoLock);
-}
-
-/*
- * Given a trigger function OID, determine whether it is an RI trigger,
- * and if so whether it is attached to PK or FK relation.
- *
- * XXX this probably doesn't belong here; should be exported by
- * ri_triggers.c
- */
-static int
-ri_trigger_type(Oid tgfoid)
-{
-   switch (tgfoid)
-   {
-       case F_RI_FKEY_CASCADE_DEL:
-       case F_RI_FKEY_CASCADE_UPD:
-       case F_RI_FKEY_RESTRICT_DEL:
-       case F_RI_FKEY_RESTRICT_UPD:
-       case F_RI_FKEY_SETNULL_DEL:
-       case F_RI_FKEY_SETNULL_UPD:
-       case F_RI_FKEY_SETDEFAULT_DEL:
-       case F_RI_FKEY_SETDEFAULT_UPD:
-       case F_RI_FKEY_NOACTION_DEL:
-       case F_RI_FKEY_NOACTION_UPD:
-           return RI_TRIGGER_PK;
-
-       case F_RI_FKEY_CHECK_INS:
-       case F_RI_FKEY_CHECK_UPD:
-           return RI_TRIGGER_FK;
-   }
-
-   return RI_TRIGGER_NONE;
-}
-
-/*
- * Scan pg_trigger for RI triggers that are on the specified relation
- * (if fk_scan is false) or have it as the tgconstrrel (if fk_scan
- * is true).  Update RI trigger args fields matching oldname to contain
- * newname instead.  If update_relname is true, examine the relname
- * fields; otherwise examine the attname fields.
- */
-static void
-update_ri_trigger_args(Oid relid,
-                      const char *oldname,
-                      const char *newname,
-                      bool fk_scan,
-                      bool update_relname)
-{
-   Relation    tgrel;
-   Relation    irel;
-   ScanKeyData skey[1];
-   IndexScanDesc idxtgscan;
-   RetrieveIndexResult idxres;
-   Datum       values[Natts_pg_trigger];
-   char        nulls[Natts_pg_trigger];
-   char        replaces[Natts_pg_trigger];
-
-   tgrel = heap_openr(TriggerRelationName, RowExclusiveLock);
-   if (fk_scan)
-       irel = index_openr(TriggerConstrRelidIndex);
-   else
-       irel = index_openr(TriggerRelidIndex);
-
-   ScanKeyEntryInitialize(&skey[0], 0x0,
-                          1,   /* always column 1 of index */
-                          F_OIDEQ,
-                          ObjectIdGetDatum(relid));
-   idxtgscan = index_beginscan(irel, false, 1, skey);
-
-   while ((idxres = index_getnext(idxtgscan, ForwardScanDirection)) != NULL)
-   {
-       HeapTupleData tupledata;
-       Buffer      buffer;
-       HeapTuple   tuple;
-       Form_pg_trigger pg_trigger;
-       bytea      *val;
-       bytea      *newtgargs;
-       bool        isnull;
-       int         tg_type;
-       bool        examine_pk;
-       bool        changed;
-       int         tgnargs;
-       int         i;
-       int         newlen;
-       const char *arga[RI_MAX_ARGUMENTS];
-       const char *argp;
-
-       tupledata.t_self = idxres->heap_iptr;
-       heap_fetch(tgrel, SnapshotNow, &tupledata, &buffer, idxtgscan);
-       pfree(idxres);
-       if (!tupledata.t_data)
-           continue;
-       tuple = &tupledata;
-       pg_trigger = (Form_pg_trigger) GETSTRUCT(tuple);
-       tg_type = ri_trigger_type(pg_trigger->tgfoid);
-       if (tg_type == RI_TRIGGER_NONE)
-       {
-           /* Not an RI trigger, forget it */
-           ReleaseBuffer(buffer);
-           continue;
-       }
-
-       /*
-        * It is an RI trigger, so parse the tgargs bytea.
-        *
-        * NB: we assume the field will never be compressed or moved out of
-        * line; so does trigger.c ...
-        */
-       tgnargs = pg_trigger->tgnargs;
-       val = (bytea *) fastgetattr(tuple,
-                                   Anum_pg_trigger_tgargs,
-                                   tgrel->rd_att, &isnull);
-       if (isnull || tgnargs < RI_FIRST_ATTNAME_ARGNO ||
-           tgnargs > RI_MAX_ARGUMENTS)
-       {
-           /* This probably shouldn't happen, but ignore busted triggers */
-           ReleaseBuffer(buffer);
-           continue;
-       }
-       argp = (const char *) VARDATA(val);
-       for (i = 0; i < tgnargs; i++)
-       {
-           arga[i] = argp;
-           argp += strlen(argp) + 1;
-       }
-
-       /*
-        * Figure out which item(s) to look at.  If the trigger is
-        * primary-key type and attached to my rel, I should look at the
-        * PK fields; if it is foreign-key type and attached to my rel, I
-        * should look at the FK fields.  But the opposite rule holds when
-        * examining triggers found by tgconstrrel search.
-        */
-       examine_pk = (tg_type == RI_TRIGGER_PK) == (!fk_scan);
-
-       changed = false;
-       if (update_relname)
-       {
-           /* Change the relname if needed */
-           i = examine_pk ? RI_PK_RELNAME_ARGNO : RI_FK_RELNAME_ARGNO;
-           if (strcmp(arga[i], oldname) == 0)
-           {
-               arga[i] = newname;
-               changed = true;
-           }
-       }
-       else
-       {
-           /* Change attname(s) if needed */
-           i = examine_pk ? RI_FIRST_ATTNAME_ARGNO + RI_KEYPAIR_PK_IDX :
-               RI_FIRST_ATTNAME_ARGNO + RI_KEYPAIR_FK_IDX;
-           for (; i < tgnargs; i += 2)
-           {
-               if (strcmp(arga[i], oldname) == 0)
-               {
-                   arga[i] = newname;
-                   changed = true;
-               }
-           }
-       }
-
-       if (!changed)
-       {
-           /* Don't need to update this tuple */
-           ReleaseBuffer(buffer);
-           continue;
-       }
-
-       /*
-        * Construct modified tgargs bytea.
-        */
-       newlen = VARHDRSZ;
-       for (i = 0; i < tgnargs; i++)
-           newlen += strlen(arga[i]) + 1;
-       newtgargs = (bytea *) palloc(newlen);
-       VARATT_SIZEP(newtgargs) = newlen;
-       newlen = VARHDRSZ;
-       for (i = 0; i < tgnargs; i++)
-       {
-           strcpy(((char *) newtgargs) + newlen, arga[i]);
-           newlen += strlen(arga[i]) + 1;
-       }
-
-       /*
-        * Build modified tuple.
-        */
-       for (i = 0; i < Natts_pg_trigger; i++)
-       {
-           values[i] = (Datum) 0;
-           replaces[i] = ' ';
-           nulls[i] = ' ';
-       }
-       values[Anum_pg_trigger_tgargs - 1] = PointerGetDatum(newtgargs);
-       replaces[Anum_pg_trigger_tgargs - 1] = 'r';
-
-       tuple = heap_modifytuple(tuple, tgrel, values, nulls, replaces);
-
-       /*
-        * Now we can release hold on original tuple.
-        */
-       ReleaseBuffer(buffer);
-
-       /*
-        * Update pg_trigger and its indexes
-        */
-       simple_heap_update(tgrel, &tuple->t_self, tuple);
-
-       {
-           Relation    irelations[Num_pg_attr_indices];
-
-           CatalogOpenIndices(Num_pg_trigger_indices, Name_pg_trigger_indices, irelations);
-           CatalogIndexInsert(irelations, Num_pg_trigger_indices, tgrel, tuple);
-           CatalogCloseIndices(Num_pg_trigger_indices, irelations);
-       }
-
-       /* free up our scratch memory */
-       pfree(newtgargs);
-       heap_freetuple(tuple);
-   }
-
-   index_endscan(idxtgscan);
-   index_close(irel);
-
-   heap_close(tgrel, RowExclusiveLock);
-
-   /*
-    * Increment cmd counter to make updates visible; this is needed in
-    * case the same tuple has to be updated again by next pass (can
-    * happen in case of a self-referential FK relationship).
-    */
-   CommandCounterIncrement();
-}
diff --git a/src/backend/commands/schemacmds.c b/src/backend/commands/schemacmds.c
new file mode 100644 (file)
index 0000000..191d5e3
--- /dev/null
@@ -0,0 +1,116 @@
+/*-------------------------------------------------------------------------
+ *
+ * schemacmds.c
+ *   schema creation command support code
+ *
+ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *   $Header: /cvsroot/pgsql/src/backend/commands/schemacmds.c,v 1.1 2002/04/15 05:22:03 tgl Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "catalog/catalog.h"
+#include "catalog/pg_namespace.h"
+#include "commands/schemacmds.h"
+#include "miscadmin.h"
+#include "parser/analyze.h"
+#include "tcop/utility.h"
+#include "utils/lsyscache.h"
+
+
+/*
+ * CREATE SCHEMA
+ */
+void
+CreateSchemaCommand(CreateSchemaStmt *stmt)
+{
+   const char *schemaName = stmt->schemaname;
+   const char *authId = stmt->authid;
+   List       *parsetree_list;
+   List       *parsetree_item;
+   const char *owner_name;
+   Oid         owner_userid;
+   Oid         saved_userid;
+
+   saved_userid = GetUserId();
+
+   if (!authId)
+   {
+       owner_userid = saved_userid;
+       owner_name = GetUserName(owner_userid);
+   }
+   else if (superuser())
+   {
+       owner_name = authId;
+       /* The following will error out if user does not exist */
+       owner_userid = get_usesysid(owner_name);
+       /*
+        * Set the current user to the requested authorization so
+        * that objects created in the statement have the requested
+        * owner.  (This will revert to session user on error or at
+        * the end of this routine.)
+        */
+       SetUserId(owner_userid);
+   }
+   else /* not superuser */
+   {
+       owner_userid = saved_userid;
+       owner_name = GetUserName(owner_userid);
+       if (strcmp(authId, owner_name) != 0)
+           elog(ERROR, "CREATE SCHEMA: permission denied"
+                "\n\t\"%s\" is not a superuser, so cannot create a schema for \"%s\"",
+                owner_name, authId);
+   }
+
+   if (!allowSystemTableMods && IsReservedName(schemaName))
+       elog(ERROR, "CREATE SCHEMA: Illegal schema name: \"%s\" -- pg_ is reserved for system schemas",
+            schemaName);
+
+   /* Create the schema's namespace */
+   NamespaceCreate(schemaName, owner_userid);
+
+   /* Let commands in the schema-element-list know about the schema */
+   CommandCounterIncrement();
+
+   /*
+    * Examine the list of commands embedded in the CREATE SCHEMA command,
+    * and reorganize them into a sequentially executable order with no
+    * forward references.  Note that the result is still a list of raw
+    * parsetrees in need of parse analysis --- we cannot, in general,
+    * run analyze.c on one statement until we have actually executed the
+    * prior ones.
+    */
+   parsetree_list = analyzeCreateSchemaStmt(stmt);
+
+   /*
+    * Analyze and execute each command contained in the CREATE SCHEMA
+    */
+   foreach(parsetree_item, parsetree_list)
+   {
+       Node       *parsetree = (Node *) lfirst(parsetree_item);
+       List       *querytree_list,
+                  *querytree_item;
+
+       querytree_list = parse_analyze(parsetree, NULL);
+
+       foreach(querytree_item, querytree_list)
+       {
+           Query      *querytree = (Query *) lfirst(querytree_item);
+
+           /* schemas should contain only utility stmts */
+           Assert(querytree->commandType == CMD_UTILITY);
+           /* do this step */
+           ProcessUtility(querytree->utilityStmt, None, NULL);
+           /* make sure later steps can see the object created here */
+           CommandCounterIncrement();
+       }
+   }
+
+   /* Reset current user */
+   SetUserId(saved_userid);
+}
index a7678c5ce38484567e7ff38c25a27bf3f463947c..0fa56fcfb7db7fdba605fade2ae2ecc978069076 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/commands/sequence.c,v 1.76 2002/03/30 01:02:41 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/commands/sequence.c,v 1.77 2002/04/15 05:22:03 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -17,7 +17,7 @@
 #include "access/heapam.h"
 #include "catalog/namespace.h"
 #include "catalog/pg_type.h"
-#include "commands/creatinh.h"
+#include "commands/tablecmds.h"
 #include "commands/sequence.h"
 #include "miscadmin.h"
 #include "utils/acl.h"
similarity index 52%
rename from src/backend/commands/command.c
rename to src/backend/commands/tablecmds.c
index 9a20d8329ad9a60e7680c32ac936f10320f745a7..18cea28df12f79028abd87bb87f8631b3483a40e 100644 (file)
@@ -1,19 +1,14 @@
 /*-------------------------------------------------------------------------
  *
- * command.c
- *   random postgres portal and utility support code
+ * tablecmds.c
+ *   Commands for altering table structures and settings
  *
- * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.175 2002/04/14 16:47:16 momjian Exp $
- *
- * NOTES
- *   The PerformAddAttribute() code, like most of the relation
- *   manipulating code in the commands/ directory, should go
- *   someplace closer to the lib/catalog code.
+ *   $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.1 2002/04/15 05:22:03 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "catalog/indexing.h"
 #include "catalog/namespace.h"
 #include "catalog/pg_attrdef.h"
-#include "catalog/pg_index.h"
+#include "catalog/pg_inherits.h"
 #include "catalog/pg_namespace.h"
 #include "catalog/pg_opclass.h"
-#include "catalog/pg_relcheck.h"
+#include "catalog/pg_trigger.h"
 #include "catalog/pg_type.h"
-#include "commands/command.h"
+#include "commands/tablecmds.h"
 #include "commands/trigger.h"
-#include "executor/execdefs.h"
 #include "executor/executor.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
 #include "optimizer/clauses.h"
 #include "optimizer/planmain.h"
 #include "optimizer/prep.h"
-#include "parser/analyze.h"
 #include "parser/parse.h"
 #include "parser/parse_expr.h"
-#include "parser/parse_oper.h"
 #include "parser/parse_relation.h"
 #include "parser/parse_type.h"
-#include "tcop/utility.h"
+#include "rewrite/rewriteDefine.h"
+#include "rewrite/rewriteSupport.h"
 #include "utils/acl.h"
 #include "utils/builtins.h"
 #include "utils/fmgroids.h"
@@ -61,220 +54,27 @@ static void drop_default(Oid relid, int16 attnum);
 static bool needs_toast_table(Relation rel);
 static void CheckTupleType(Form_pg_class tuple_class);
 
+static List *MergeAttributes(List *schema, List *supers, bool istemp,
+               List **supOids, List **supconstr, bool *supHasOids);
+static bool change_varattnos_of_a_node(Node *node, const AttrNumber *newattno);
+static void StoreCatalogInheritance(Oid relationId, List *supers);
+static int findAttrByName(const char *attributeName, List *schema);
+static void setRelhassubclassInRelation(Oid relationId, bool relhassubclass);
+static List *MergeDomainAttributes(List *schema);
 
-/*
- *     PortalCleanup
- */
-void
-PortalCleanup(Portal portal)
-{
-   MemoryContext oldcontext;
-
-   /*
-    * sanity checks
-    */
-   AssertArg(PortalIsValid(portal));
-   AssertArg(portal->cleanup == PortalCleanup);
-
-   /*
-    * set proper portal-executor context before calling ExecMain.
-    */
-   oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
-
-   /*
-    * tell the executor to shutdown the query
-    */
-   ExecutorEnd(PortalGetQueryDesc(portal), PortalGetState(portal));
-
-   /*
-    * switch back to previous context
-    */
-   MemoryContextSwitchTo(oldcontext);
-}
-
-
-/*
- * PerformPortalFetch
- *
- * name: name of portal
- * forward: forward or backward fetch?
- * count: # of tuples to fetch (0 implies all)
- * dest: where to send results
- * completionTag: points to a buffer of size COMPLETION_TAG_BUFSIZE
- *     in which to store a command completion status string.
- *
- * completionTag may be NULL if caller doesn't want a status string.
- */
-void
-PerformPortalFetch(char *name,
-                  bool forward,
-                  int count,
-                  CommandDest dest,
-                  char *completionTag)
-{
-   Portal      portal;
-   QueryDesc  *queryDesc;
-   EState     *estate;
-   MemoryContext oldcontext;
-   ScanDirection direction;
-   CommandId   savedId;
-   bool        temp_desc = false;
-
-   /* initialize completion status in case of early exit */
-   if (completionTag)
-       strcpy(completionTag, (dest == None) ? "MOVE 0" : "FETCH 0");
-
-   /*
-    * sanity checks
-    */
-   if (name == NULL)
-   {
-       elog(WARNING, "PerformPortalFetch: missing portal name");
-       return;
-   }
-
-   /*
-    * get the portal from the portal name
-    */
-   portal = GetPortalByName(name);
-   if (!PortalIsValid(portal))
-   {
-       elog(WARNING, "PerformPortalFetch: portal \"%s\" not found",
-            name);
-       return;
-   }
-
-   /*
-    * switch into the portal context
-    */
-   oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
-
-   queryDesc = PortalGetQueryDesc(portal);
-   estate = PortalGetState(portal);
-
-   /*
-    * If the requested destination is not the same as the query's
-    * original destination, make a temporary QueryDesc with the proper
-    * destination.  This supports MOVE, for example, which will pass in
-    * dest = None.
-    *
-    * EXCEPTION: if the query's original dest is RemoteInternal (ie, it's a
-    * binary cursor) and the request is Remote, we do NOT override the
-    * original dest.  This is necessary since a FETCH command will pass
-    * dest = Remote, not knowing whether the cursor is binary or not.
-    */
-   if (dest != queryDesc->dest &&
-       !(queryDesc->dest == RemoteInternal && dest == Remote))
-   {
-       QueryDesc  *qdesc = (QueryDesc *) palloc(sizeof(QueryDesc));
-
-       memcpy(qdesc, queryDesc, sizeof(QueryDesc));
-       qdesc->dest = dest;
-       queryDesc = qdesc;
-       temp_desc = true;
-   }
-
-   /*
-    * Restore the scanCommandId that was current when the cursor was
-    * opened.  This ensures that we see the same tuples throughout the
-    * execution of the cursor.
-    */
-   savedId = GetScanCommandId();
-   SetScanCommandId(PortalGetCommandId(portal));
-
-   /*
-    * Determine which direction to go in, and check to see if we're
-    * already at the end of the available tuples in that direction.  If
-    * so, set the direction to NoMovement to avoid trying to fetch any
-    * tuples.  (This check exists because not all plan node types
-    * are robust about being called again if they've already returned
-    * NULL once.)  Then call the executor (we must not skip this, because
-    * the destination needs to see a setup and shutdown even if no tuples
-    * are available).  Finally, update the atStart/atEnd state depending
-    * on the number of tuples that were retrieved.
-    */
-   if (forward)
-   {
-       if (portal->atEnd)
-           direction = NoMovementScanDirection;
-       else
-           direction = ForwardScanDirection;
-
-       ExecutorRun(queryDesc, estate, direction, (long) count);
-
-       if (estate->es_processed > 0)
-           portal->atStart = false; /* OK to back up now */
-       if (count <= 0 || (int) estate->es_processed < count)
-           portal->atEnd = true;   /* we retrieved 'em all */
-   }
-   else
-   {
-       if (portal->atStart)
-           direction = NoMovementScanDirection;
-       else
-           direction = BackwardScanDirection;
-
-       ExecutorRun(queryDesc, estate, direction, (long) count);
-
-       if (estate->es_processed > 0)
-           portal->atEnd = false;  /* OK to go forward now */
-       if (count <= 0 || (int) estate->es_processed < count)
-           portal->atStart = true; /* we retrieved 'em all */
-   }
-
-   /* Return command status if wanted */
-   if (completionTag)
-       snprintf(completionTag, COMPLETION_TAG_BUFSIZE, "%s %u",
-                (dest == None) ? "MOVE" : "FETCH",
-                estate->es_processed);
-
-   /*
-    * Restore outer command ID.
-    */
-   SetScanCommandId(savedId);
-
-   /*
-    * Clean up and switch back to old context.
-    */
-   if (temp_desc)
-       pfree(queryDesc);
-
-   MemoryContextSwitchTo(oldcontext);
-}
-
-/*
- *     PerformPortalClose
- */
-void
-PerformPortalClose(char *name, CommandDest dest)
-{
-   Portal      portal;
+/* Used by attribute and relation renaming routines: */
 
-   /*
-    * sanity checks
-    */
-   if (name == NULL)
-   {
-       elog(WARNING, "PerformPortalClose: missing portal name");
-       return;
-   }
+#define RI_TRIGGER_PK  1       /* is a trigger on the PK relation */
+#define RI_TRIGGER_FK  2       /* is a trigger on the FK relation */
+#define RI_TRIGGER_NONE 0      /* is not an RI trigger function */
 
-   /*
-    * get the portal from the portal name
-    */
-   portal = GetPortalByName(name);
-   if (!PortalIsValid(portal))
-   {
-       elog(WARNING, "PerformPortalClose: portal \"%s\" not found",
-            name);
-       return;
-   }
+static int ri_trigger_type(Oid tgfoid);
+static void update_ri_trigger_args(Oid relid,
+                      const char *oldname,
+                      const char *newname,
+                      bool fk_scan,
+                      bool update_relname);
 
-   /*
-    * Note: PortalCleanup is called as a side-effect
-    */
-   PortalDrop(portal);
-}
 
 /* ----------------
  *     AlterTableAddColumn
@@ -1856,142 +1656,1427 @@ needs_toast_table(Relation rel)
    return (tuple_length > TOAST_TUPLE_THRESHOLD);
 }
 
-/*
- * LOCK TABLE
+
+/* ----------------------------------------------------------------
+ *     DefineRelation
+ *             Creates a new relation.
+ *
+ * If successful, returns the OID of the new relation.
+ * ----------------------------------------------------------------
  */
-void
-LockTableCommand(LockStmt *lockstmt)
+Oid
+DefineRelation(CreateStmt *stmt, char relkind)
 {
-   List       *p;
+   char       *relname = palloc(NAMEDATALEN);
+   Oid         namespaceId;
+   List       *schema = stmt->tableElts;
+   int         numberOfAttributes;
+   Oid         relationId;
+   Relation    rel;
+   TupleDesc   descriptor;
+   List       *inheritOids;
+   List       *old_constraints;
+   bool        parentHasOids;
+   List       *rawDefaults;
+   List       *listptr;
+   int         i;
+   AttrNumber  attnum;
+
+   /*
+    * Truncate relname to appropriate length (probably a waste of time,
+    * as parser should have done this already).
+    */
+   StrNCpy(relname, (stmt->relation)->relname, NAMEDATALEN);
+
+   /*
+    * Look up the namespace in which we are supposed to create the
+    * relation.
+    */
+   namespaceId = RangeVarGetCreationNamespace(stmt->relation);
+
+   /*
+    * Merge domain attributes into the known columns before processing table
+    * inheritance.  Otherwise we risk adding double constraints to a
+    * domain-type column that's inherited.
+    */
+   schema = MergeDomainAttributes(schema);
+
+   /*
+    * Look up inheritance ancestors and generate relation schema,
+    * including inherited attributes.
+    */
+   schema = MergeAttributes(schema, stmt->inhRelations,
+                            stmt->relation->istemp,
+                            &inheritOids, &old_constraints, &parentHasOids);
+
+   numberOfAttributes = length(schema);
+   if (numberOfAttributes <= 0)
+       elog(ERROR, "DefineRelation: please inherit from a relation or define an attribute");
 
    /*
-    * Iterate over the list and open, lock, and close the relations one
-    * at a time
+    * Create a relation descriptor from the relation schema and create
+    * the relation.  Note that in this stage only inherited (pre-cooked)
+    * defaults and constraints will be included into the new relation.
+    * (BuildDescForRelation takes care of the inherited defaults, but we
+    * have to copy inherited constraints here.)
     */
+   descriptor = BuildDescForRelation(schema);
 
-   foreach(p, lockstmt->relations)
+   if (old_constraints != NIL)
    {
-       RangeVar   *relation = lfirst(p);
-       Oid         reloid;
-       int32       aclresult;
-       Relation    rel;
+       ConstrCheck *check = (ConstrCheck *) palloc(length(old_constraints) *
+                                                   sizeof(ConstrCheck));
+       int         ncheck = 0;
 
-       /*
-        * We don't want to open the relation until we've checked privilege.
-        * So, manually get the relation OID.
-        */
-       reloid = RangeVarGetRelid(relation, false);
+       foreach(listptr, old_constraints)
+       {
+           Constraint *cdef = (Constraint *) lfirst(listptr);
 
-       if (lockstmt->mode == AccessShareLock)
-           aclresult = pg_class_aclcheck(reloid, GetUserId(),
-                                         ACL_SELECT);
-       else
-           aclresult = pg_class_aclcheck(reloid, GetUserId(),
-                                         ACL_UPDATE | ACL_DELETE);
+           if (cdef->contype != CONSTR_CHECK)
+               continue;
+
+           if (cdef->name != NULL)
+           {
+               for (i = 0; i < ncheck; i++)
+               {
+                   if (strcmp(check[i].ccname, cdef->name) == 0)
+                       elog(ERROR, "Duplicate CHECK constraint name: '%s'",
+                            cdef->name);
+               }
+               check[ncheck].ccname = cdef->name;
+           }
+           else
+           {
+               check[ncheck].ccname = (char *) palloc(NAMEDATALEN);
+               snprintf(check[ncheck].ccname, NAMEDATALEN, "$%d", ncheck + 1);
+           }
+           Assert(cdef->raw_expr == NULL && cdef->cooked_expr != NULL);
+           check[ncheck].ccbin = pstrdup(cdef->cooked_expr);
+           ncheck++;
+       }
+       if (ncheck > 0)
+       {
+           if (descriptor->constr == NULL)
+           {
+               descriptor->constr = (TupleConstr *) palloc(sizeof(TupleConstr));
+               descriptor->constr->defval = NULL;
+               descriptor->constr->num_defval = 0;
+               descriptor->constr->has_not_null = false;
+           }
+           descriptor->constr->num_check = ncheck;
+           descriptor->constr->check = check;
+       }
+   }
+
+   relationId = heap_create_with_catalog(relname,
+                                         namespaceId,
+                                         descriptor,
+                                         relkind,
+                                         stmt->hasoids || parentHasOids,
+                                         allowSystemTableMods);
+
+   StoreCatalogInheritance(relationId, inheritOids);
+
+   /*
+    * We must bump the command counter to make the newly-created relation
+    * tuple visible for opening.
+    */
+   CommandCounterIncrement();
+
+   /*
+    * Open the new relation and acquire exclusive lock on it.  This isn't
+    * really necessary for locking out other backends (since they can't
+    * see the new rel anyway until we commit), but it keeps the lock
+    * manager from complaining about deadlock risks.
+    */
+   rel = heap_open(relationId, AccessExclusiveLock);
+
+   /*
+    * Now add any newly specified column default values and CHECK
+    * constraints to the new relation.  These are passed to us in the
+    * form of raw parsetrees; we need to transform them to executable
+    * expression trees before they can be added. The most convenient way
+    * to do that is to apply the parser's transformExpr routine, but
+    * transformExpr doesn't work unless we have a pre-existing relation.
+    * So, the transformation has to be postponed to this final step of
+    * CREATE TABLE.
+    *
+    * First, scan schema to find new column defaults.
+    */
+   rawDefaults = NIL;
+   attnum = 0;
 
-       if (aclresult != ACLCHECK_OK)
-           elog(ERROR, "LOCK TABLE: permission denied");
+   foreach(listptr, schema)
+   {
+       ColumnDef  *colDef = lfirst(listptr);
+       RawColumnDefault *rawEnt;
 
-       rel = relation_open(reloid, lockstmt->mode);
+       attnum++;
 
-       /* Currently, we only allow plain tables to be locked */
-       if (rel->rd_rel->relkind != RELKIND_RELATION)
-           elog(ERROR, "LOCK TABLE: %s is not a table",
-                relation->relname);
+       if (colDef->raw_default == NULL)
+           continue;
+       Assert(colDef->cooked_default == NULL);
 
-       relation_close(rel, NoLock);    /* close rel, keep lock */
+       rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
+       rawEnt->attnum = attnum;
+       rawEnt->raw_default = colDef->raw_default;
+       rawDefaults = lappend(rawDefaults, rawEnt);
    }
+
+   /*
+    * Parse and add the defaults/constraints, if any.
+    */
+   if (rawDefaults || stmt->constraints)
+       AddRelationRawConstraints(rel, rawDefaults, stmt->constraints);
+
+   /*
+    * Clean up.  We keep lock on new relation (although it shouldn't be
+    * visible to anyone else anyway, until commit).
+    */
+   heap_close(rel, NoLock);
+
+   return relationId;
 }
 
+/*
+ * RemoveRelation
+ *     Deletes a relation.
+ *
+ * Exceptions:
+ *     BadArg if name is invalid.
+ *
+ * Note:
+ *     If the relation has indices defined on it, then the index relations
+ * themselves will be destroyed, too.
+ */
+void
+RemoveRelation(const RangeVar *relation)
+{
+   Oid         relOid;
+
+   relOid = RangeVarGetRelid(relation, false);
+   heap_drop_with_catalog(relOid, allowSystemTableMods);
+}
 
 /*
- * CREATE SCHEMA
+ * TruncateRelation
+ *               Removes all the rows from a relation
+ *
+ * Exceptions:
+ *               BadArg if name is invalid
+ *
+ * Note:
+ *               Rows are removed, indices are truncated and reconstructed.
  */
 void
-CreateSchemaCommand(CreateSchemaStmt *stmt)
+TruncateRelation(const RangeVar *relation)
 {
-   const char *schemaName = stmt->schemaname;
-   const char *authId = stmt->authid;
-   List       *parsetree_list;
-   List       *parsetree_item;
-   const char *owner_name;
-   Oid         owner_userid;
-   Oid         saved_userid;
+   Relation    rel;
+   Oid         relid;
 
-   saved_userid = GetUserId();
+   /* Grab exclusive lock in preparation for truncate */
+   rel = heap_openrv(relation, AccessExclusiveLock);
+   relid = RelationGetRelid(rel);
 
-   if (!authId)
-   {
-       owner_userid = saved_userid;
-       owner_name = GetUserName(owner_userid);
-   }
-   else if (superuser())
-   {
-       owner_name = authId;
-       /* The following will error out if user does not exist */
-       owner_userid = get_usesysid(owner_name);
-       /*
-        * Set the current user to the requested authorization so
-        * that objects created in the statement have the requested
-        * owner.  (This will revert to session user on error or at
-        * the end of this routine.)
-        */
-       SetUserId(owner_userid);
-   }
-   else /* not superuser */
-   {
-       owner_userid = saved_userid;
-       owner_name = GetUserName(owner_userid);
-       if (strcmp(authId, owner_name) != 0)
-           elog(ERROR, "CREATE SCHEMA: permission denied"
-                "\n\t\"%s\" is not a superuser, so cannot create a schema for \"%s\"",
-                owner_name, authId);
-   }
+   if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
+       elog(ERROR, "TRUNCATE cannot be used on sequences. '%s' is a sequence",
+            RelationGetRelationName(rel));
+
+   if (rel->rd_rel->relkind == RELKIND_VIEW)
+       elog(ERROR, "TRUNCATE cannot be used on views. '%s' is a view",
+            RelationGetRelationName(rel));
 
-   if (!allowSystemTableMods && IsReservedName(schemaName))
-       elog(ERROR, "CREATE SCHEMA: Illegal schema name: \"%s\" -- pg_ is reserved for system schemas",
-            schemaName);
+   if (!allowSystemTableMods && IsSystemRelation(rel))
+       elog(ERROR, "TRUNCATE cannot be used on system tables. '%s' is a system table",
+            RelationGetRelationName(rel));
 
-   /* Create the schema's namespace */
-   NamespaceCreate(schemaName, owner_userid);
+   if (!pg_class_ownercheck(relid, GetUserId()))
+       elog(ERROR, "you do not own relation \"%s\"",
+            RelationGetRelationName(rel));
 
-   /* Let commands in the schema-element-list know about the schema */
-   CommandCounterIncrement();
+   /* Keep the lock until transaction commit */
+   heap_close(rel, NoLock);
+
+   heap_truncate(relid);
+}
+
+
+/*
+ * MergeDomainAttributes
+ *      Returns a new table schema with the constraints, types, and other
+ *      attributes of domains resolved for fields using a domain as
+ *      their type.
+ */
+static List *
+MergeDomainAttributes(List *schema)
+{
+   List       *entry;
 
    /*
-    * Examine the list of commands embedded in the CREATE SCHEMA command,
-    * and reorganize them into a sequentially executable order with no
-    * forward references.  Note that the result is still a list of raw
-    * parsetrees in need of parse analysis --- we cannot, in general,
-    * run analyze.c on one statement until we have actually executed the
-    * prior ones.
+    * Loop through the table elements supplied. These should
+    * never include inherited domains else they'll be
+    * double (or more) processed.
     */
-   parsetree_list = analyzeCreateSchemaStmt(stmt);
+   foreach(entry, schema)
+   {
+       ColumnDef  *coldef = lfirst(entry);
+       HeapTuple  tuple;
+       Form_pg_type typeTup;
+
+       tuple = typenameType(coldef->typename);
+       typeTup = (Form_pg_type) GETSTRUCT(tuple);
+
+       if (typeTup->typtype == 'd')
+       {
+           /* Force the column to have the correct typmod. */
+           coldef->typename->typmod = typeTup->typtypmod;
+           /* XXX more to do here? */
+       }
+
+       /* Enforce type NOT NULL || column definition NOT NULL -> NOT NULL */
+       /* Currently only used for domains, but could be valid for all */
+       coldef->is_not_null |= typeTup->typnotnull;
+
+       ReleaseSysCache(tuple);
+   }
+
+   return schema;
+}
+
+/*----------
+ * MergeAttributes
+ *     Returns new schema given initial schema and superclasses.
+ *
+ * Input arguments:
+ * 'schema' is the column/attribute definition for the table. (It's a list
+ *     of ColumnDef's.) It is destructively changed.
+ * 'supers' is a list of names (as RangeVar nodes) of parent relations.
+ * 'istemp' is TRUE if we are creating a temp relation.
+ *
+ * Output arguments:
+ * 'supOids' receives an integer list of the OIDs of the parent relations.
+ * 'supconstr' receives a list of constraints belonging to the parents,
+ *     updated as necessary to be valid for the child.
+ * 'supHasOids' is set TRUE if any parent has OIDs, else it is set FALSE.
+ *
+ * Return value:
+ * Completed schema list.
+ *
+ * Notes:
+ *   The order in which the attributes are inherited is very important.
+ *   Intuitively, the inherited attributes should come first. If a table
+ *   inherits from multiple parents, the order of those attributes are
+ *   according to the order of the parents specified in CREATE TABLE.
+ *
+ *   Here's an example:
+ *
+ *     create table person (name text, age int4, location point);
+ *     create table emp (salary int4, manager text) inherits(person);
+ *     create table student (gpa float8) inherits (person);
+ *     create table stud_emp (percent int4) inherits (emp, student);
+ *
+ *   The order of the attributes of stud_emp is:
+ *
+ *                         person {1:name, 2:age, 3:location}
+ *                         /    \
+ *            {6:gpa}  student   emp {4:salary, 5:manager}
+ *                         \    /
+ *                        stud_emp {7:percent}
+ *
+ *    If the same attribute name appears multiple times, then it appears
+ *    in the result table in the proper location for its first appearance.
+ *
+ *    Constraints (including NOT NULL constraints) for the child table
+ *    are the union of all relevant constraints, from both the child schema
+ *    and parent tables.
+ *
+ *    The default value for a child column is defined as:
+ *     (1) If the child schema specifies a default, that value is used.
+ *     (2) If neither the child nor any parent specifies a default, then
+ *         the column will not have a default.
+ *     (3) If conflicting defaults are inherited from different parents
+ *         (and not overridden by the child), an error is raised.
+ *     (4) Otherwise the inherited default is used.
+ *     Rule (3) is new in Postgres 7.1; in earlier releases you got a
+ *     rather arbitrary choice of which parent default to use.
+ *----------
+ */
+static List *
+MergeAttributes(List *schema, List *supers, bool istemp,
+               List **supOids, List **supconstr, bool *supHasOids)
+{
+   List       *entry;
+   List       *inhSchema = NIL;
+   List       *parentOids = NIL;
+   List       *constraints = NIL;
+   bool        parentHasOids = false;
+   bool        have_bogus_defaults = false;
+   char       *bogus_marker = "Bogus!";        /* marks conflicting
+                                                * defaults */
+   int         child_attno;
 
    /*
-    * Analyze and execute each command contained in the CREATE SCHEMA
+    * Check for duplicate names in the explicit list of attributes.
+    *
+    * Although we might consider merging such entries in the same way that
+    * we handle name conflicts for inherited attributes, it seems to make
+    * more sense to assume such conflicts are errors.
     */
-   foreach(parsetree_item, parsetree_list)
+   foreach(entry, schema)
    {
-       Node       *parsetree = (Node *) lfirst(parsetree_item);
-       List       *querytree_list,
-                  *querytree_item;
+       ColumnDef  *coldef = lfirst(entry);
+       List       *rest;
 
-       querytree_list = parse_analyze(parsetree, NULL);
-
-       foreach(querytree_item, querytree_list)
+       foreach(rest, lnext(entry))
        {
-           Query      *querytree = (Query *) lfirst(querytree_item);
-
-           /* schemas should contain only utility stmts */
-           Assert(querytree->commandType == CMD_UTILITY);
-           /* do this step */
-           ProcessUtility(querytree->utilityStmt, None, NULL);
-           /* make sure later steps can see the object created here */
-           CommandCounterIncrement();
+           ColumnDef  *restdef = lfirst(rest);
+
+           if (strcmp(coldef->colname, restdef->colname) == 0)
+               elog(ERROR, "CREATE TABLE: attribute \"%s\" duplicated",
+                    coldef->colname);
        }
    }
 
-   /* Reset current user */
-   SetUserId(saved_userid);
+   /*
+    * Scan the parents left-to-right, and merge their attributes to form
+    * a list of inherited attributes (inhSchema).  Also check to see if
+    * we need to inherit an OID column.
+    */
+   child_attno = 0;
+   foreach(entry, supers)
+   {
+       RangeVar   *parent = (RangeVar *) lfirst(entry);
+       Relation    relation;
+       TupleDesc   tupleDesc;
+       TupleConstr *constr;
+       AttrNumber *newattno;
+       AttrNumber  parent_attno;
+
+       relation = heap_openrv(parent, AccessShareLock);
+
+       if (relation->rd_rel->relkind != RELKIND_RELATION)
+           elog(ERROR, "CREATE TABLE: inherited relation \"%s\" is not a table",
+                parent->relname);
+       /* Permanent rels cannot inherit from temporary ones */
+       if (!istemp && isTempNamespace(RelationGetNamespace(relation)))
+           elog(ERROR, "CREATE TABLE: cannot inherit from temp relation \"%s\"",
+                parent->relname);
+
+       /*
+        * We should have an UNDER permission flag for this, but for now,
+        * demand that creator of a child table own the parent.
+        */
+       if (!pg_class_ownercheck(RelationGetRelid(relation), GetUserId()))
+           elog(ERROR, "you do not own table \"%s\"",
+                parent->relname);
+
+       /*
+        * Reject duplications in the list of parents.
+        */
+       if (intMember(RelationGetRelid(relation), parentOids))
+           elog(ERROR, "CREATE TABLE: inherited relation \"%s\" duplicated",
+                parent->relname);
+
+       parentOids = lappendi(parentOids, RelationGetRelid(relation));
+       setRelhassubclassInRelation(RelationGetRelid(relation), true);
+
+       parentHasOids |= relation->rd_rel->relhasoids;
+
+       tupleDesc = RelationGetDescr(relation);
+       constr = tupleDesc->constr;
+
+       /*
+        * newattno[] will contain the child-table attribute numbers for
+        * the attributes of this parent table.  (They are not the same
+        * for parents after the first one.)
+        */
+       newattno = (AttrNumber *) palloc(tupleDesc->natts * sizeof(AttrNumber));
+
+       for (parent_attno = 1; parent_attno <= tupleDesc->natts;
+            parent_attno++)
+       {
+           Form_pg_attribute attribute = tupleDesc->attrs[parent_attno - 1];
+           char       *attributeName = NameStr(attribute->attname);
+           int         exist_attno;
+           ColumnDef  *def;
+           TypeName   *typename;
+
+           /*
+            * Does it conflict with some previously inherited column?
+            */
+           exist_attno = findAttrByName(attributeName, inhSchema);
+           if (exist_attno > 0)
+           {
+               /*
+                * Yes, try to merge the two column definitions. They must
+                * have the same type and typmod.
+                */
+               elog(NOTICE, "CREATE TABLE: merging multiple inherited definitions of attribute \"%s\"",
+                    attributeName);
+               def = (ColumnDef *) nth(exist_attno - 1, inhSchema);
+               if (typenameTypeId(def->typename) != attribute->atttypid ||
+                   def->typename->typmod != attribute->atttypmod)
+                   elog(ERROR, "CREATE TABLE: inherited attribute \"%s\" type conflict (%s and %s)",
+                        attributeName,
+                        TypeNameToString(def->typename),
+                        typeidTypeName(attribute->atttypid));
+               /* Merge of NOT NULL constraints = OR 'em together */
+               def->is_not_null |= attribute->attnotnull;
+               /* Default and other constraints are handled below */
+               newattno[parent_attno - 1] = exist_attno;
+           }
+           else
+           {
+               /*
+                * No, create a new inherited column
+                */
+               def = makeNode(ColumnDef);
+               def->colname = pstrdup(attributeName);
+               typename = makeNode(TypeName);
+               typename->typeid = attribute->atttypid;
+               typename->typmod = attribute->atttypmod;
+               def->typename = typename;
+               def->is_not_null = attribute->attnotnull;
+               def->raw_default = NULL;
+               def->cooked_default = NULL;
+               def->constraints = NIL;
+               inhSchema = lappend(inhSchema, def);
+               newattno[parent_attno - 1] = ++child_attno;
+           }
+
+           /*
+            * Copy default if any
+            */
+           if (attribute->atthasdef)
+           {
+               char       *this_default = NULL;
+               AttrDefault *attrdef;
+               int         i;
+
+               /* Find default in constraint structure */
+               Assert(constr != NULL);
+               attrdef = constr->defval;
+               for (i = 0; i < constr->num_defval; i++)
+               {
+                   if (attrdef[i].adnum == parent_attno)
+                   {
+                       this_default = attrdef[i].adbin;
+                       break;
+                   }
+               }
+               Assert(this_default != NULL);
+
+               /*
+                * If default expr could contain any vars, we'd need to
+                * fix 'em, but it can't; so default is ready to apply to
+                * child.
+                *
+                * If we already had a default from some prior parent, check
+                * to see if they are the same.  If so, no problem; if
+                * not, mark the column as having a bogus default. Below,
+                * we will complain if the bogus default isn't overridden
+                * by the child schema.
+                */
+               Assert(def->raw_default == NULL);
+               if (def->cooked_default == NULL)
+                   def->cooked_default = pstrdup(this_default);
+               else if (strcmp(def->cooked_default, this_default) != 0)
+               {
+                   def->cooked_default = bogus_marker;
+                   have_bogus_defaults = true;
+               }
+           }
+       }
+
+       /*
+        * Now copy the constraints of this parent, adjusting attnos using
+        * the completed newattno[] map
+        */
+       if (constr && constr->num_check > 0)
+       {
+           ConstrCheck *check = constr->check;
+           int         i;
+
+           for (i = 0; i < constr->num_check; i++)
+           {
+               Constraint *cdef = makeNode(Constraint);
+               Node       *expr;
+
+               cdef->contype = CONSTR_CHECK;
+               if (check[i].ccname[0] == '$')
+                   cdef->name = NULL;
+               else
+                   cdef->name = pstrdup(check[i].ccname);
+               cdef->raw_expr = NULL;
+               /* adjust varattnos of ccbin here */
+               expr = stringToNode(check[i].ccbin);
+               change_varattnos_of_a_node(expr, newattno);
+               cdef->cooked_expr = nodeToString(expr);
+               constraints = lappend(constraints, cdef);
+           }
+       }
+
+       pfree(newattno);
+
+       /*
+        * Close the parent rel, but keep our AccessShareLock on it until
+        * xact commit.  That will prevent someone else from deleting or
+        * ALTERing the parent before the child is committed.
+        */
+       heap_close(relation, NoLock);
+   }
+
+   /*
+    * If we had no inherited attributes, the result schema is just the
+    * explicitly declared columns.  Otherwise, we need to merge the
+    * declared columns into the inherited schema list.
+    */
+   if (inhSchema != NIL)
+   {
+       foreach(entry, schema)
+       {
+           ColumnDef  *newdef = lfirst(entry);
+           char       *attributeName = newdef->colname;
+           int         exist_attno;
+
+           /*
+            * Does it conflict with some previously inherited column?
+            */
+           exist_attno = findAttrByName(attributeName, inhSchema);
+           if (exist_attno > 0)
+           {
+               ColumnDef  *def;
+
+               /*
+                * Yes, try to merge the two column definitions. They must
+                * have the same type and typmod.
+                */
+               elog(NOTICE, "CREATE TABLE: merging attribute \"%s\" with inherited definition",
+                    attributeName);
+               def = (ColumnDef *) nth(exist_attno - 1, inhSchema);
+               if (typenameTypeId(def->typename) != typenameTypeId(newdef->typename) ||
+                   def->typename->typmod != newdef->typename->typmod)
+                   elog(ERROR, "CREATE TABLE: attribute \"%s\" type conflict (%s and %s)",
+                        attributeName,
+                        TypeNameToString(def->typename),
+                        TypeNameToString(newdef->typename));
+               /* Merge of NOT NULL constraints = OR 'em together */
+               def->is_not_null |= newdef->is_not_null;
+               /* If new def has a default, override previous default */
+               if (newdef->raw_default != NULL)
+               {
+                   def->raw_default = newdef->raw_default;
+                   def->cooked_default = newdef->cooked_default;
+               }
+           }
+           else
+           {
+               /*
+                * No, attach new column to result schema
+                */
+               inhSchema = lappend(inhSchema, newdef);
+           }
+       }
+
+       schema = inhSchema;
+   }
+
+   /*
+    * If we found any conflicting parent default values, check to make
+    * sure they were overridden by the child.
+    */
+   if (have_bogus_defaults)
+   {
+       foreach(entry, schema)
+       {
+           ColumnDef  *def = lfirst(entry);
+
+           if (def->cooked_default == bogus_marker)
+               elog(ERROR, "CREATE TABLE: attribute \"%s\" inherits conflicting default values"
+                    "\n\tTo resolve the conflict, specify a default explicitly",
+                    def->colname);
+       }
+   }
+
+   *supOids = parentOids;
+   *supconstr = constraints;
+   *supHasOids = parentHasOids;
+   return schema;
+}
+
+/*
+ * complementary static functions for MergeAttributes().
+ *
+ * Varattnos of pg_relcheck.rcbin must be rewritten when subclasses inherit
+ * constraints from parent classes, since the inherited attributes could
+ * be given different column numbers in multiple-inheritance cases.
+ *
+ * Note that the passed node tree is modified in place!
+ */
+static bool
+change_varattnos_walker(Node *node, const AttrNumber *newattno)
+{
+   if (node == NULL)
+       return false;
+   if (IsA(node, Var))
+   {
+       Var        *var = (Var *) node;
+
+       if (var->varlevelsup == 0 && var->varno == 1 &&
+           var->varattno > 0)
+       {
+           /*
+            * ??? the following may be a problem when the node is
+            * multiply referenced though stringToNode() doesn't create
+            * such a node currently.
+            */
+           Assert(newattno[var->varattno - 1] > 0);
+           var->varattno = newattno[var->varattno - 1];
+       }
+       return false;
+   }
+   return expression_tree_walker(node, change_varattnos_walker,
+                                 (void *) newattno);
+}
+
+static bool
+change_varattnos_of_a_node(Node *node, const AttrNumber *newattno)
+{
+   return change_varattnos_walker(node, newattno);
+}
+
+/*
+ * StoreCatalogInheritance
+ *     Updates the system catalogs with proper inheritance information.
+ *
+ * supers is an integer list of the OIDs of the new relation's direct
+ * ancestors.  NB: it is destructively changed to include indirect ancestors.
+ */
+static void
+StoreCatalogInheritance(Oid relationId, List *supers)
+{
+   Relation    relation;
+   TupleDesc   desc;
+   int16       seqNumber;
+   List       *entry;
+   HeapTuple   tuple;
+
+   /*
+    * sanity checks
+    */
+   AssertArg(OidIsValid(relationId));
+
+   if (supers == NIL)
+       return;
+
+   /*
+    * Catalog INHERITS information using direct ancestors only.
+    */
+   relation = heap_openr(InheritsRelationName, RowExclusiveLock);
+   desc = RelationGetDescr(relation);
+
+   seqNumber = 1;
+   foreach(entry, supers)
+   {
+       Oid         entryOid = lfirsti(entry);
+       Datum       datum[Natts_pg_inherits];
+       char        nullarr[Natts_pg_inherits];
+
+       datum[0] = ObjectIdGetDatum(relationId);        /* inhrel */
+       datum[1] = ObjectIdGetDatum(entryOid);  /* inhparent */
+       datum[2] = Int16GetDatum(seqNumber);    /* inhseqno */
+
+       nullarr[0] = ' ';
+       nullarr[1] = ' ';
+       nullarr[2] = ' ';
+
+       tuple = heap_formtuple(desc, datum, nullarr);
+
+       heap_insert(relation, tuple);
+
+       if (RelationGetForm(relation)->relhasindex)
+       {
+           Relation    idescs[Num_pg_inherits_indices];
+
+           CatalogOpenIndices(Num_pg_inherits_indices, Name_pg_inherits_indices, idescs);
+           CatalogIndexInsert(idescs, Num_pg_inherits_indices, relation, tuple);
+           CatalogCloseIndices(Num_pg_inherits_indices, idescs);
+       }
+
+       heap_freetuple(tuple);
+
+       seqNumber += 1;
+   }
+
+   heap_close(relation, RowExclusiveLock);
+
+   /* ----------------
+    * Expand supers list to include indirect ancestors as well.
+    *
+    * Algorithm:
+    *  0. begin with list of direct superclasses.
+    *  1. append after each relationId, its superclasses, recursively.
+    *  2. remove all but last of duplicates.
+    * ----------------
+    */
+
+   /*
+    * 1. append after each relationId, its superclasses, recursively.
+    */
+   foreach(entry, supers)
+   {
+       HeapTuple   tuple;
+       Oid         id;
+       int16       number;
+       List       *next;
+       List       *current;
+
+       id = (Oid) lfirsti(entry);
+       current = entry;
+       next = lnext(entry);
+
+       for (number = 1;; number += 1)
+       {
+           tuple = SearchSysCache(INHRELID,
+                                  ObjectIdGetDatum(id),
+                                  Int16GetDatum(number),
+                                  0, 0);
+           if (!HeapTupleIsValid(tuple))
+               break;
+
+           lnext(current) = lconsi(((Form_pg_inherits)
+                                    GETSTRUCT(tuple))->inhparent,
+                                   NIL);
+
+           ReleaseSysCache(tuple);
+
+           current = lnext(current);
+       }
+       lnext(current) = next;
+   }
+
+   /*
+    * 2. remove all but last of duplicates.
+    */
+   foreach(entry, supers)
+   {
+       Oid         thisone;
+       bool        found;
+       List       *rest;
+
+again:
+       thisone = lfirsti(entry);
+       found = false;
+       foreach(rest, lnext(entry))
+       {
+           if (thisone == lfirsti(rest))
+           {
+               found = true;
+               break;
+           }
+       }
+       if (found)
+       {
+           /*
+            * found a later duplicate, so remove this entry.
+            */
+           lfirsti(entry) = lfirsti(lnext(entry));
+           lnext(entry) = lnext(lnext(entry));
+
+           goto again;
+       }
+   }
+}
+
+/*
+ * Look for an existing schema entry with the given name.
+ *
+ * Returns the index (starting with 1) if attribute already exists in schema,
+ * 0 if it doesn't.
+ */
+static int
+findAttrByName(const char *attributeName, List *schema)
+{
+   List       *s;
+   int         i = 0;
+
+   foreach(s, schema)
+   {
+       ColumnDef  *def = lfirst(s);
+
+       ++i;
+       if (strcmp(attributeName, def->colname) == 0)
+           return i;
+   }
+   return 0;
+}
+
+/*
+ * Update a relation's pg_class.relhassubclass entry to the given value
+ */
+static void
+setRelhassubclassInRelation(Oid relationId, bool relhassubclass)
+{
+   Relation    relationRelation;
+   HeapTuple   tuple;
+   Relation    idescs[Num_pg_class_indices];
+
+   /*
+    * Fetch a modifiable copy of the tuple, modify it, update pg_class.
+    */
+   relationRelation = heap_openr(RelationRelationName, RowExclusiveLock);
+   tuple = SearchSysCacheCopy(RELOID,
+                              ObjectIdGetDatum(relationId),
+                              0, 0, 0);
+   if (!HeapTupleIsValid(tuple))
+       elog(ERROR, "setRelhassubclassInRelation: cache lookup failed for relation %u", relationId);
+
+   ((Form_pg_class) GETSTRUCT(tuple))->relhassubclass = relhassubclass;
+   simple_heap_update(relationRelation, &tuple->t_self, tuple);
+
+   /* keep the catalog indices up to date */
+   CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs);
+   CatalogIndexInsert(idescs, Num_pg_class_indices, relationRelation, tuple);
+   CatalogCloseIndices(Num_pg_class_indices, idescs);
+
+   heap_freetuple(tuple);
+   heap_close(relationRelation, RowExclusiveLock);
+}
+
+
+/*
+ *     renameatt       - changes the name of a attribute in a relation
+ *
+ *     Attname attribute is changed in attribute catalog.
+ *     No record of the previous attname is kept (correct?).
+ *
+ *     get proper relrelation from relation catalog (if not arg)
+ *     scan attribute catalog
+ *             for name conflict (within rel)
+ *             for original attribute (if not arg)
+ *     modify attname in attribute tuple
+ *     insert modified attribute in attribute catalog
+ *     delete original attribute from attribute catalog
+ */
+void
+renameatt(Oid relid,
+         const char *oldattname,
+         const char *newattname,
+         bool recurse)
+{
+   Relation    targetrelation;
+   Relation    attrelation;
+   HeapTuple   atttup;
+   List       *indexoidlist;
+   List       *indexoidscan;
+
+   /*
+    * Grab an exclusive lock on the target table, which we will NOT
+    * release until end of transaction.
+    */
+   targetrelation = heap_open(relid, AccessExclusiveLock);
+
+   /*
+    * permissions checking.  this would normally be done in utility.c,
+    * but this particular routine is recursive.
+    *
+    * normally, only the owner of a class can change its schema.
+    */
+   if (!allowSystemTableMods 
+       && IsSystemRelation(targetrelation))
+       elog(ERROR, "renameatt: class \"%s\" is a system catalog",
+            RelationGetRelationName(targetrelation));
+   if (!pg_class_ownercheck(relid, GetUserId()))
+       elog(ERROR, "renameatt: you do not own class \"%s\"",
+            RelationGetRelationName(targetrelation));
+
+   /*
+    * if the 'recurse' flag is set then we are supposed to rename this
+    * attribute in all classes that inherit from 'relname' (as well as in
+    * 'relname').
+    *
+    * any permissions or problems with duplicate attributes will cause the
+    * whole transaction to abort, which is what we want -- all or
+    * nothing.
+    */
+   if (recurse)
+   {
+       List       *child,
+                  *children;
+
+       /* this routine is actually in the planner */
+       children = find_all_inheritors(relid);
+
+       /*
+        * find_all_inheritors does the recursive search of the
+        * inheritance hierarchy, so all we have to do is process all of
+        * the relids in the list that it returns.
+        */
+       foreach(child, children)
+       {
+           Oid         childrelid = lfirsti(child);
+
+           if (childrelid == relid)
+               continue;
+           /* note we need not recurse again! */
+           renameatt(childrelid, oldattname, newattname, false);
+       }
+   }
+
+   attrelation = heap_openr(AttributeRelationName, RowExclusiveLock);
+
+   atttup = SearchSysCacheCopy(ATTNAME,
+                               ObjectIdGetDatum(relid),
+                               PointerGetDatum(oldattname),
+                               0, 0);
+   if (!HeapTupleIsValid(atttup))
+       elog(ERROR, "renameatt: attribute \"%s\" does not exist", oldattname);
+
+   if (((Form_pg_attribute) GETSTRUCT(atttup))->attnum < 0)
+       elog(ERROR, "renameatt: system attribute \"%s\" not renamed", oldattname);
+
+   /* should not already exist */
+   if (SearchSysCacheExists(ATTNAME,
+                            ObjectIdGetDatum(relid),
+                            PointerGetDatum(newattname),
+                            0, 0))
+       elog(ERROR, "renameatt: attribute \"%s\" exists", newattname);
+
+   StrNCpy(NameStr(((Form_pg_attribute) GETSTRUCT(atttup))->attname),
+           newattname, NAMEDATALEN);
+
+   simple_heap_update(attrelation, &atttup->t_self, atttup);
+
+   /* keep system catalog indices current */
+   {
+       Relation    irelations[Num_pg_attr_indices];
+
+       CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, irelations);
+       CatalogIndexInsert(irelations, Num_pg_attr_indices, attrelation, atttup);
+       CatalogCloseIndices(Num_pg_attr_indices, irelations);
+   }
+
+   heap_freetuple(atttup);
+
+   /*
+    * Update column names of indexes that refer to the column being
+    * renamed.
+    */
+   indexoidlist = RelationGetIndexList(targetrelation);
+
+   foreach(indexoidscan, indexoidlist)
+   {
+       Oid         indexoid = lfirsti(indexoidscan);
+       HeapTuple   indextup;
+
+       /*
+        * First check to see if index is a functional index. If so, its
+        * column name is a function name and shouldn't be renamed here.
+        */
+       indextup = SearchSysCache(INDEXRELID,
+                                 ObjectIdGetDatum(indexoid),
+                                 0, 0, 0);
+       if (!HeapTupleIsValid(indextup))
+           elog(ERROR, "renameatt: can't find index id %u", indexoid);
+       if (OidIsValid(((Form_pg_index) GETSTRUCT(indextup))->indproc))
+       {
+           ReleaseSysCache(indextup);
+           continue;
+       }
+       ReleaseSysCache(indextup);
+
+       /*
+        * Okay, look to see if any column name of the index matches the
+        * old attribute name.
+        */
+       atttup = SearchSysCacheCopy(ATTNAME,
+                                   ObjectIdGetDatum(indexoid),
+                                   PointerGetDatum(oldattname),
+                                   0, 0);
+       if (!HeapTupleIsValid(atttup))
+           continue;           /* Nope, so ignore it */
+
+       /*
+        * Update the (copied) attribute tuple.
+        */
+       StrNCpy(NameStr(((Form_pg_attribute) GETSTRUCT(atttup))->attname),
+               newattname, NAMEDATALEN);
+
+       simple_heap_update(attrelation, &atttup->t_self, atttup);
+
+       /* keep system catalog indices current */
+       {
+           Relation    irelations[Num_pg_attr_indices];
+
+           CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, irelations);
+           CatalogIndexInsert(irelations, Num_pg_attr_indices, attrelation, atttup);
+           CatalogCloseIndices(Num_pg_attr_indices, irelations);
+       }
+       heap_freetuple(atttup);
+   }
+
+   freeList(indexoidlist);
+
+   heap_close(attrelation, RowExclusiveLock);
+
+   /*
+    * Update att name in any RI triggers associated with the relation.
+    */
+   if (targetrelation->rd_rel->reltriggers > 0)
+   {
+       /* update tgargs column reference where att is primary key */
+       update_ri_trigger_args(RelationGetRelid(targetrelation),
+                              oldattname, newattname,
+                              false, false);
+       /* update tgargs column reference where att is foreign key */
+       update_ri_trigger_args(RelationGetRelid(targetrelation),
+                              oldattname, newattname,
+                              true, false);
+   }
+
+   heap_close(targetrelation, NoLock); /* close rel but keep lock! */
+}
+
+/*
+ *     renamerel       - change the name of a relation
+ *
+ *     XXX - When renaming sequences, we don't bother to modify the
+ *           sequence name that is stored within the sequence itself
+ *           (this would cause problems with MVCC). In the future,
+ *           the sequence name should probably be removed from the
+ *           sequence, AFAIK there's no need for it to be there.
+ */
+void
+renamerel(Oid relid, const char *newrelname)
+{
+   Relation    targetrelation;
+   Relation    relrelation;    /* for RELATION relation */
+   HeapTuple   reltup;
+   Oid         namespaceId;
+   char        relkind;
+   bool        relhastriggers;
+   Relation    irelations[Num_pg_class_indices];
+
+   /*
+    * Grab an exclusive lock on the target table or index, which we will
+    * NOT release until end of transaction.
+    */
+   targetrelation = relation_open(relid, AccessExclusiveLock);
+
+   namespaceId = RelationGetNamespace(targetrelation);
+
+   /* Validity checks */
+   if (!allowSystemTableMods &&
+       IsSystemRelation(targetrelation))
+       elog(ERROR, "renamerel: system relation \"%s\" may not be renamed",
+            RelationGetRelationName(targetrelation));
+
+   relkind = targetrelation->rd_rel->relkind;
+   relhastriggers = (targetrelation->rd_rel->reltriggers > 0);
+
+   /*
+    * Find relation's pg_class tuple, and make sure newrelname isn't in
+    * use.
+    */
+   relrelation = heap_openr(RelationRelationName, RowExclusiveLock);
+
+   reltup = SearchSysCacheCopy(RELOID,
+                               PointerGetDatum(relid),
+                               0, 0, 0);
+   if (!HeapTupleIsValid(reltup))
+       elog(ERROR, "renamerel: relation \"%s\" does not exist",
+            RelationGetRelationName(targetrelation));
+
+   if (get_relname_relid(newrelname, namespaceId) != InvalidOid)
+       elog(ERROR, "renamerel: relation \"%s\" exists", newrelname);
+
+   /*
+    * Update pg_class tuple with new relname.  (Scribbling on reltup is
+    * OK because it's a copy...)
+    */
+   StrNCpy(NameStr(((Form_pg_class) GETSTRUCT(reltup))->relname),
+           newrelname, NAMEDATALEN);
+
+   simple_heap_update(relrelation, &reltup->t_self, reltup);
+
+   /* keep the system catalog indices current */
+   CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, irelations);
+   CatalogIndexInsert(irelations, Num_pg_class_indices, relrelation, reltup);
+   CatalogCloseIndices(Num_pg_class_indices, irelations);
+
+   heap_close(relrelation, NoLock);
+   heap_freetuple(reltup);
+
+   /*
+    * Also rename the associated type, if any.
+    */
+   if (relkind != RELKIND_INDEX)
+       TypeRename(RelationGetRelationName(targetrelation), namespaceId,
+                  newrelname);
+
+   /*
+    * If it's a view, must also rename the associated ON SELECT rule.
+    */
+   if (relkind == RELKIND_VIEW)
+   {
+       char       *oldrulename,
+                  *newrulename;
+
+       oldrulename = MakeRetrieveViewRuleName(RelationGetRelationName(targetrelation));
+       newrulename = MakeRetrieveViewRuleName(newrelname);
+       RenameRewriteRule(oldrulename, newrulename);
+   }
+
+   /*
+    * Update rel name in any RI triggers associated with the relation.
+    */
+   if (relhastriggers)
+   {
+       /* update tgargs where relname is primary key */
+       update_ri_trigger_args(relid,
+                              RelationGetRelationName(targetrelation),
+                              newrelname,
+                              false, true);
+       /* update tgargs where relname is foreign key */
+       update_ri_trigger_args(relid,
+                              RelationGetRelationName(targetrelation),
+                              newrelname,
+                              true, true);
+   }
+
+   /*
+    * Close rel, but keep exclusive lock!
+    */
+   relation_close(targetrelation, NoLock);
+}
+
+/*
+ * Given a trigger function OID, determine whether it is an RI trigger,
+ * and if so whether it is attached to PK or FK relation.
+ *
+ * XXX this probably doesn't belong here; should be exported by
+ * ri_triggers.c
+ */
+static int
+ri_trigger_type(Oid tgfoid)
+{
+   switch (tgfoid)
+   {
+       case F_RI_FKEY_CASCADE_DEL:
+       case F_RI_FKEY_CASCADE_UPD:
+       case F_RI_FKEY_RESTRICT_DEL:
+       case F_RI_FKEY_RESTRICT_UPD:
+       case F_RI_FKEY_SETNULL_DEL:
+       case F_RI_FKEY_SETNULL_UPD:
+       case F_RI_FKEY_SETDEFAULT_DEL:
+       case F_RI_FKEY_SETDEFAULT_UPD:
+       case F_RI_FKEY_NOACTION_DEL:
+       case F_RI_FKEY_NOACTION_UPD:
+           return RI_TRIGGER_PK;
+
+       case F_RI_FKEY_CHECK_INS:
+       case F_RI_FKEY_CHECK_UPD:
+           return RI_TRIGGER_FK;
+   }
+
+   return RI_TRIGGER_NONE;
+}
+
+/*
+ * Scan pg_trigger for RI triggers that are on the specified relation
+ * (if fk_scan is false) or have it as the tgconstrrel (if fk_scan
+ * is true).  Update RI trigger args fields matching oldname to contain
+ * newname instead.  If update_relname is true, examine the relname
+ * fields; otherwise examine the attname fields.
+ */
+static void
+update_ri_trigger_args(Oid relid,
+                      const char *oldname,
+                      const char *newname,
+                      bool fk_scan,
+                      bool update_relname)
+{
+   Relation    tgrel;
+   Relation    irel;
+   ScanKeyData skey[1];
+   IndexScanDesc idxtgscan;
+   RetrieveIndexResult idxres;
+   Datum       values[Natts_pg_trigger];
+   char        nulls[Natts_pg_trigger];
+   char        replaces[Natts_pg_trigger];
+
+   tgrel = heap_openr(TriggerRelationName, RowExclusiveLock);
+   if (fk_scan)
+       irel = index_openr(TriggerConstrRelidIndex);
+   else
+       irel = index_openr(TriggerRelidIndex);
+
+   ScanKeyEntryInitialize(&skey[0], 0x0,
+                          1,   /* always column 1 of index */
+                          F_OIDEQ,
+                          ObjectIdGetDatum(relid));
+   idxtgscan = index_beginscan(irel, false, 1, skey);
+
+   while ((idxres = index_getnext(idxtgscan, ForwardScanDirection)) != NULL)
+   {
+       HeapTupleData tupledata;
+       Buffer      buffer;
+       HeapTuple   tuple;
+       Form_pg_trigger pg_trigger;
+       bytea      *val;
+       bytea      *newtgargs;
+       bool        isnull;
+       int         tg_type;
+       bool        examine_pk;
+       bool        changed;
+       int         tgnargs;
+       int         i;
+       int         newlen;
+       const char *arga[RI_MAX_ARGUMENTS];
+       const char *argp;
+
+       tupledata.t_self = idxres->heap_iptr;
+       heap_fetch(tgrel, SnapshotNow, &tupledata, &buffer, idxtgscan);
+       pfree(idxres);
+       if (!tupledata.t_data)
+           continue;
+       tuple = &tupledata;
+       pg_trigger = (Form_pg_trigger) GETSTRUCT(tuple);
+       tg_type = ri_trigger_type(pg_trigger->tgfoid);
+       if (tg_type == RI_TRIGGER_NONE)
+       {
+           /* Not an RI trigger, forget it */
+           ReleaseBuffer(buffer);
+           continue;
+       }
+
+       /*
+        * It is an RI trigger, so parse the tgargs bytea.
+        *
+        * NB: we assume the field will never be compressed or moved out of
+        * line; so does trigger.c ...
+        */
+       tgnargs = pg_trigger->tgnargs;
+       val = (bytea *) fastgetattr(tuple,
+                                   Anum_pg_trigger_tgargs,
+                                   tgrel->rd_att, &isnull);
+       if (isnull || tgnargs < RI_FIRST_ATTNAME_ARGNO ||
+           tgnargs > RI_MAX_ARGUMENTS)
+       {
+           /* This probably shouldn't happen, but ignore busted triggers */
+           ReleaseBuffer(buffer);
+           continue;
+       }
+       argp = (const char *) VARDATA(val);
+       for (i = 0; i < tgnargs; i++)
+       {
+           arga[i] = argp;
+           argp += strlen(argp) + 1;
+       }
+
+       /*
+        * Figure out which item(s) to look at.  If the trigger is
+        * primary-key type and attached to my rel, I should look at the
+        * PK fields; if it is foreign-key type and attached to my rel, I
+        * should look at the FK fields.  But the opposite rule holds when
+        * examining triggers found by tgconstrrel search.
+        */
+       examine_pk = (tg_type == RI_TRIGGER_PK) == (!fk_scan);
+
+       changed = false;
+       if (update_relname)
+       {
+           /* Change the relname if needed */
+           i = examine_pk ? RI_PK_RELNAME_ARGNO : RI_FK_RELNAME_ARGNO;
+           if (strcmp(arga[i], oldname) == 0)
+           {
+               arga[i] = newname;
+               changed = true;
+           }
+       }
+       else
+       {
+           /* Change attname(s) if needed */
+           i = examine_pk ? RI_FIRST_ATTNAME_ARGNO + RI_KEYPAIR_PK_IDX :
+               RI_FIRST_ATTNAME_ARGNO + RI_KEYPAIR_FK_IDX;
+           for (; i < tgnargs; i += 2)
+           {
+               if (strcmp(arga[i], oldname) == 0)
+               {
+                   arga[i] = newname;
+                   changed = true;
+               }
+           }
+       }
+
+       if (!changed)
+       {
+           /* Don't need to update this tuple */
+           ReleaseBuffer(buffer);
+           continue;
+       }
+
+       /*
+        * Construct modified tgargs bytea.
+        */
+       newlen = VARHDRSZ;
+       for (i = 0; i < tgnargs; i++)
+           newlen += strlen(arga[i]) + 1;
+       newtgargs = (bytea *) palloc(newlen);
+       VARATT_SIZEP(newtgargs) = newlen;
+       newlen = VARHDRSZ;
+       for (i = 0; i < tgnargs; i++)
+       {
+           strcpy(((char *) newtgargs) + newlen, arga[i]);
+           newlen += strlen(arga[i]) + 1;
+       }
+
+       /*
+        * Build modified tuple.
+        */
+       for (i = 0; i < Natts_pg_trigger; i++)
+       {
+           values[i] = (Datum) 0;
+           replaces[i] = ' ';
+           nulls[i] = ' ';
+       }
+       values[Anum_pg_trigger_tgargs - 1] = PointerGetDatum(newtgargs);
+       replaces[Anum_pg_trigger_tgargs - 1] = 'r';
+
+       tuple = heap_modifytuple(tuple, tgrel, values, nulls, replaces);
+
+       /*
+        * Now we can release hold on original tuple.
+        */
+       ReleaseBuffer(buffer);
+
+       /*
+        * Update pg_trigger and its indexes
+        */
+       simple_heap_update(tgrel, &tuple->t_self, tuple);
+
+       {
+           Relation    irelations[Num_pg_attr_indices];
+
+           CatalogOpenIndices(Num_pg_trigger_indices, Name_pg_trigger_indices, irelations);
+           CatalogIndexInsert(irelations, Num_pg_trigger_indices, tgrel, tuple);
+           CatalogCloseIndices(Num_pg_trigger_indices, irelations);
+       }
+
+       /* free up our scratch memory */
+       pfree(newtgargs);
+       heap_freetuple(tuple);
+   }
+
+   index_endscan(idxtgscan);
+   index_close(irel);
+
+   heap_close(tgrel, RowExclusiveLock);
+
+   /*
+    * Increment cmd counter to make updates visible; this is needed in
+    * case the same tuple has to be updated again by next pass (can
+    * happen in case of a self-referential FK relationship).
+    */
+   CommandCounterIncrement();
 }
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
new file mode 100644 (file)
index 0000000..13dbf04
--- /dev/null
@@ -0,0 +1,660 @@
+/*-------------------------------------------------------------------------
+ *
+ * typecmds.c
+ *   Routines for SQL commands that manipulate types (and domains).
+ *
+ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *   $Header: /cvsroot/pgsql/src/backend/commands/typecmds.c,v 1.1 2002/04/15 05:22:03 tgl Exp $
+ *
+ * DESCRIPTION
+ *   The "DefineFoo" routines take the parse tree and pick out the
+ *   appropriate arguments/flags, passing the results to the
+ *   corresponding "FooDefine" routines (in src/catalog) that do
+ *   the actual catalog-munging.  These routines also verify permission
+ *   of the user to execute the command.
+ *
+ * NOTES
+ *   These things must be defined and committed in the following order:
+ *     "create function":
+ *             input/output, recv/send procedures
+ *     "create type":
+ *             type
+ *     "create operator":
+ *             operators
+ *
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "access/heapam.h"
+#include "catalog/catname.h"
+#include "catalog/heap.h"
+#include "catalog/namespace.h"
+#include "catalog/pg_type.h"
+#include "commands/comment.h"
+#include "commands/defrem.h"
+#include "miscadmin.h"
+#include "parser/parse.h"
+#include "parser/parse_func.h"
+#include "parser/parse_type.h"
+#include "utils/acl.h"
+#include "utils/builtins.h"
+#include "utils/fmgroids.h"
+#include "utils/syscache.h"
+
+
+static Oid findTypeIOFunction(List *procname, bool isOutput);
+
+
+/*
+ * DefineType
+ *     Registers a new type.
+ */
+void
+DefineType(List *names, List *parameters)
+{
+   char       *typeName;
+   Oid         typeNamespace;
+   int16       internalLength = -1;    /* int2 */
+   int16       externalLength = -1;    /* int2 */
+   Oid         elemType = InvalidOid;
+   List       *inputName = NIL;
+   List       *outputName = NIL;
+   List       *sendName = NIL;
+   List       *receiveName = NIL;
+   char       *defaultValue = NULL;
+   bool        byValue = false;
+   char        delimiter = DEFAULT_TYPDELIM;
+   char        alignment = 'i';    /* default alignment */
+   char        storage = 'p';  /* default TOAST storage method */
+   Oid         inputOid;
+   Oid         outputOid;
+   Oid         sendOid;
+   Oid         receiveOid;
+   char       *shadow_type;
+   List       *pl;
+   Oid         typoid;
+
+   /* Convert list of names to a name and namespace */
+   typeNamespace = QualifiedNameGetCreationNamespace(names, &typeName);
+
+   /*
+    * Type names must be one character shorter than other names, allowing
+    * room to create the corresponding array type name with prepended
+    * "_".
+    */
+   if (strlen(typeName) > (NAMEDATALEN - 2))
+       elog(ERROR, "DefineType: type names must be %d characters or less",
+            NAMEDATALEN - 2);
+
+   foreach(pl, parameters)
+   {
+       DefElem    *defel = (DefElem *) lfirst(pl);
+
+       if (strcasecmp(defel->defname, "internallength") == 0)
+           internalLength = defGetTypeLength(defel);
+       else if (strcasecmp(defel->defname, "externallength") == 0)
+           externalLength = defGetTypeLength(defel);
+       else if (strcasecmp(defel->defname, "input") == 0)
+           inputName = defGetQualifiedName(defel);
+       else if (strcasecmp(defel->defname, "output") == 0)
+           outputName = defGetQualifiedName(defel);
+       else if (strcasecmp(defel->defname, "send") == 0)
+           sendName = defGetQualifiedName(defel);
+       else if (strcasecmp(defel->defname, "receive") == 0)
+           receiveName = defGetQualifiedName(defel);
+       else if (strcasecmp(defel->defname, "delimiter") == 0)
+       {
+           char       *p = defGetString(defel);
+
+           delimiter = p[0];
+       }
+       else if (strcasecmp(defel->defname, "element") == 0)
+           elemType = typenameTypeId(defGetTypeName(defel));
+       else if (strcasecmp(defel->defname, "default") == 0)
+           defaultValue = defGetString(defel);
+       else if (strcasecmp(defel->defname, "passedbyvalue") == 0)
+           byValue = true;
+       else if (strcasecmp(defel->defname, "alignment") == 0)
+       {
+           char       *a = defGetString(defel);
+
+           /*
+            * Note: if argument was an unquoted identifier, parser will
+            * have applied xlateSqlType() to it, so be prepared to
+            * recognize translated type names as well as the nominal
+            * form.
+            */
+           if (strcasecmp(a, "double") == 0)
+               alignment = 'd';
+           else if (strcasecmp(a, "float8") == 0)
+               alignment = 'd';
+           else if (strcasecmp(a, "int4") == 0)
+               alignment = 'i';
+           else if (strcasecmp(a, "int2") == 0)
+               alignment = 's';
+           else if (strcasecmp(a, "char") == 0)
+               alignment = 'c';
+           else if (strcasecmp(a, "bpchar") == 0)
+               alignment = 'c';
+           else
+               elog(ERROR, "DefineType: \"%s\" alignment not recognized",
+                    a);
+       }
+       else if (strcasecmp(defel->defname, "storage") == 0)
+       {
+           char       *a = defGetString(defel);
+
+           if (strcasecmp(a, "plain") == 0)
+               storage = 'p';
+           else if (strcasecmp(a, "external") == 0)
+               storage = 'e';
+           else if (strcasecmp(a, "extended") == 0)
+               storage = 'x';
+           else if (strcasecmp(a, "main") == 0)
+               storage = 'm';
+           else
+               elog(ERROR, "DefineType: \"%s\" storage not recognized",
+                    a);
+       }
+       else
+       {
+           elog(WARNING, "DefineType: attribute \"%s\" not recognized",
+                defel->defname);
+       }
+   }
+
+   /*
+    * make sure we have our required definitions
+    */
+   if (inputName == NIL)
+       elog(ERROR, "Define: \"input\" unspecified");
+   if (outputName == NIL)
+       elog(ERROR, "Define: \"output\" unspecified");
+
+   /* Convert I/O proc names to OIDs */
+   inputOid = findTypeIOFunction(inputName, false);
+   outputOid = findTypeIOFunction(outputName, true);
+   if (sendName)
+       sendOid = findTypeIOFunction(sendName, true);
+   else
+       sendOid = outputOid;
+   if (receiveName)
+       receiveOid = findTypeIOFunction(receiveName, false);
+   else
+       receiveOid = inputOid;
+
+   /*
+    * now have TypeCreate do all the real work.
+    */
+   typoid =
+       TypeCreate(typeName,        /* type name */
+                  typeNamespace,   /* namespace */
+                  InvalidOid,      /* preassigned type oid (not done here) */
+                  InvalidOid,      /* relation oid (n/a here) */
+                  internalLength,  /* internal size */
+                  externalLength,  /* external size */
+                  'b',             /* type-type (base type) */
+                  delimiter,       /* array element delimiter */
+                  inputOid,        /* input procedure */
+                  outputOid,       /* output procedure */
+                  receiveOid,      /* receive procedure */
+                  sendOid,         /* send procedure */
+                  elemType,        /* element type ID */
+                  InvalidOid,      /* base type ID (only for domains) */
+                  defaultValue,    /* default type value */
+                  NULL,            /* no binary form available */
+                  byValue,         /* passed by value */
+                  alignment,       /* required alignment */
+                  storage,         /* TOAST strategy */
+                  -1,              /* typMod (Domains only) */
+                  0,               /* Array Dimensions of typbasetype */
+                  false);          /* Type NOT NULL */
+
+   /*
+    * When we create a base type (as opposed to a complex type) we need
+    * to have an array entry for it in pg_type as well.
+    */
+   shadow_type = makeArrayTypeName(typeName);
+
+   /* alignment must be 'i' or 'd' for arrays */
+   alignment = (alignment == 'd') ? 'd' : 'i';
+
+   TypeCreate(shadow_type,     /* type name */
+              typeNamespace,   /* namespace */
+              InvalidOid,      /* preassigned type oid (not done here) */
+              InvalidOid,      /* relation oid (n/a here) */
+              -1,              /* internal size */
+              -1,              /* external size */
+              'b',             /* type-type (base type) */
+              DEFAULT_TYPDELIM,    /* array element delimiter */
+              F_ARRAY_IN,      /* input procedure */
+              F_ARRAY_OUT,     /* output procedure */
+              F_ARRAY_IN,      /* receive procedure */
+              F_ARRAY_OUT,     /* send procedure */
+              typoid,          /* element type ID */
+              InvalidOid,      /* base type ID */
+              NULL,            /* never a default type value */
+              NULL,            /* binary default isn't sent either */
+              false,           /* never passed by value */
+              alignment,       /* see above */
+              'x',             /* ARRAY is always toastable */
+              -1,              /* typMod (Domains only) */
+              0,               /* Array dimensions of typbasetype */
+              false);          /* Type NOT NULL */
+
+   pfree(shadow_type);
+}
+
+
+/*
+ * RemoveType
+ *     Removes a datatype.
+ *
+ * NOTE: since this tries to remove the associated array type too, it'll
+ * only work on scalar types.
+ */
+void
+RemoveType(List *names)
+{
+   TypeName   *typename;
+   Relation    relation;
+   Oid         typeoid;
+   HeapTuple   tup;
+
+   /* Make a TypeName so we can use standard type lookup machinery */
+   typename = makeNode(TypeName);
+   typename->names = names;
+   typename->typmod = -1;
+   typename->arrayBounds = NIL;
+
+   relation = heap_openr(TypeRelationName, RowExclusiveLock);
+
+   /* Use LookupTypeName here so that shell types can be removed. */
+   typeoid = LookupTypeName(typename);
+   if (!OidIsValid(typeoid))
+       elog(ERROR, "Type \"%s\" does not exist",
+            TypeNameToString(typename));
+
+   tup = SearchSysCache(TYPEOID,
+                        ObjectIdGetDatum(typeoid),
+                        0, 0, 0);
+   if (!HeapTupleIsValid(tup))
+       elog(ERROR, "Type \"%s\" does not exist",
+            TypeNameToString(typename));
+
+   if (!pg_type_ownercheck(typeoid, GetUserId()))
+       elog(ERROR, "RemoveType: type '%s': permission denied",
+            TypeNameToString(typename));
+
+   /* Delete any comments associated with this type */
+   DeleteComments(typeoid, RelationGetRelid(relation));
+
+   /* Remove the type tuple from pg_type */
+   simple_heap_delete(relation, &tup->t_self);
+
+   ReleaseSysCache(tup);
+
+   /* Now, delete the "array of" that type */
+   typename->arrayBounds = makeList1(makeInteger(1));
+
+   typeoid = LookupTypeName(typename);
+   if (!OidIsValid(typeoid))
+       elog(ERROR, "Type \"%s\" does not exist",
+            TypeNameToString(typename));
+
+   tup = SearchSysCache(TYPEOID,
+                        ObjectIdGetDatum(typeoid),
+                        0, 0, 0);
+   if (!HeapTupleIsValid(tup))
+       elog(ERROR, "Type \"%s\" does not exist",
+            TypeNameToString(typename));
+
+   DeleteComments(typeoid, RelationGetRelid(relation));
+
+   simple_heap_delete(relation, &tup->t_self);
+
+   ReleaseSysCache(tup);
+
+   heap_close(relation, RowExclusiveLock);
+}
+
+
+/*
+ * DefineDomain
+ *     Registers a new domain.
+ */
+void
+DefineDomain(CreateDomainStmt *stmt)
+{
+   char       *domainName;
+   Oid         domainNamespace;
+   int16       internalLength;
+   int16       externalLength;
+   Oid         inputProcedure;
+   Oid         outputProcedure;
+   Oid         receiveProcedure;
+   Oid         sendProcedure;
+   bool        byValue;
+   char        delimiter;
+   char        alignment;
+   char        storage;
+   char        typtype;
+   Datum       datum;
+   bool        isnull;
+   char       *defaultValue = NULL;
+   char       *defaultValueBin = NULL;
+   bool        typNotNull = false;
+   Oid         basetypelem;
+   int32       typNDims = length(stmt->typename->arrayBounds);
+   HeapTuple   typeTup;
+   List       *schema = stmt->constraints;
+   List       *listptr;
+
+   /* Convert list of names to a name and namespace */
+   domainNamespace = QualifiedNameGetCreationNamespace(stmt->domainname,
+                                                       &domainName);
+
+   /*
+    * Domainnames, unlike typenames don't need to account for the '_'
+    * prefix.  So they can be one character longer.
+    */
+   if (strlen(domainName) > (NAMEDATALEN - 1))
+       elog(ERROR, "CREATE DOMAIN: domain names must be %d characters or less",
+            NAMEDATALEN - 1);
+
+   /*
+    * Look up the base type.
+    */
+   typeTup = typenameType(stmt->typename);
+
+   /*
+    * What we really don't want is domains of domains.  This could cause all sorts
+    * of neat issues if we allow that.
+    *
+    * With testing, we may determine complex types should be allowed
+    */
+   typtype = ((Form_pg_type) GETSTRUCT(typeTup))->typtype;
+   if (typtype != 'b')
+       elog(ERROR, "DefineDomain: %s is not a basetype",
+            TypeNameToString(stmt->typename));
+
+   /* passed by value */
+   byValue = ((Form_pg_type) GETSTRUCT(typeTup))->typbyval;
+
+   /* Required Alignment */
+   alignment = ((Form_pg_type) GETSTRUCT(typeTup))->typalign;
+
+   /* TOAST Strategy */
+   storage = ((Form_pg_type) GETSTRUCT(typeTup))->typstorage;
+
+   /* Storage Length */
+   internalLength = ((Form_pg_type) GETSTRUCT(typeTup))->typlen;
+
+   /* External Length (unused) */
+   externalLength = ((Form_pg_type) GETSTRUCT(typeTup))->typprtlen;
+
+   /* Array element Delimiter */
+   delimiter = ((Form_pg_type) GETSTRUCT(typeTup))->typdelim;
+
+   /* I/O Functions */
+   inputProcedure = ((Form_pg_type) GETSTRUCT(typeTup))->typinput;
+   outputProcedure = ((Form_pg_type) GETSTRUCT(typeTup))->typoutput;
+   receiveProcedure = ((Form_pg_type) GETSTRUCT(typeTup))->typreceive;
+   sendProcedure = ((Form_pg_type) GETSTRUCT(typeTup))->typsend;
+
+   /* Inherited default value */
+   datum = SysCacheGetAttr(TYPEOID, typeTup,
+                           Anum_pg_type_typdefault, &isnull);
+   if (!isnull)
+       defaultValue = DatumGetCString(DirectFunctionCall1(textout, datum));
+
+   /* Inherited default binary value */
+   datum = SysCacheGetAttr(TYPEOID, typeTup,
+                           Anum_pg_type_typdefaultbin, &isnull);
+   if (!isnull)
+       defaultValueBin = DatumGetCString(DirectFunctionCall1(textout, datum));
+
+   /*
+    * Pull out the typelem name of the parent OID.
+    *
+    * This is what enables us to make a domain of an array
+    */
+   basetypelem = ((Form_pg_type) GETSTRUCT(typeTup))->typelem;
+
+   /*
+    * Run through constraints manually to avoid the additional
+    * processing conducted by DefineRelation() and friends.
+    *
+    * Besides, we don't want any constraints to be cooked.  We'll
+    * do that when the table is created via MergeDomainAttributes().
+    */
+   foreach(listptr, schema)
+   {
+       Constraint *colDef = lfirst(listptr);
+       bool nullDefined = false;
+       Node       *expr;
+       ParseState *pstate;
+
+       switch (colDef->contype)
+       {
+           /*
+            * The inherited default value may be overridden by the user
+            * with the DEFAULT  statement.
+            *
+            * We have to search the entire constraint tree returned as we
+            * don't want to cook or fiddle too much.
+            */
+           case CONSTR_DEFAULT:
+               /* Create a dummy ParseState for transformExpr */
+               pstate = make_parsestate(NULL);
+               /*
+                * Cook the colDef->raw_expr into an expression.
+                * Note: Name is strictly for error message
+                */
+               expr = cookDefault(pstate, colDef->raw_expr,
+                                  typeTup->t_data->t_oid,
+                                  stmt->typename->typmod,
+                                  domainName);
+               /*
+                * Expression must be stored as a nodeToString result,
+                * but we also require a valid textual representation
+                * (mainly to make life easier for pg_dump).
+                */
+               defaultValue = deparse_expression(expr,
+                               deparse_context_for(domainName,
+                                                   InvalidOid),
+                                                  false);
+               defaultValueBin = nodeToString(expr);
+               break;
+
+           /*
+            * Find the NULL constraint.
+            */
+           case CONSTR_NOTNULL:
+               if (nullDefined) {
+                   elog(ERROR, "CREATE DOMAIN has conflicting NULL / NOT NULL constraint");
+               } else {
+                   typNotNull = true;
+                   nullDefined = true;
+               }
+               break;
+
+           case CONSTR_NULL:
+               if (nullDefined) {
+                   elog(ERROR, "CREATE DOMAIN has conflicting NULL / NOT NULL constraint");
+               } else {
+                   typNotNull = false;
+                   nullDefined = true;
+               }
+               break;
+
+           case CONSTR_UNIQUE:
+               elog(ERROR, "CREATE DOMAIN / UNIQUE indexes not supported");
+               break;
+
+           case CONSTR_PRIMARY:
+               elog(ERROR, "CREATE DOMAIN / PRIMARY KEY indexes not supported");
+               break;
+
+           case CONSTR_CHECK:
+               elog(ERROR, "DefineDomain: CHECK Constraints not supported");
+               break;
+
+           case CONSTR_ATTR_DEFERRABLE:
+           case CONSTR_ATTR_NOT_DEFERRABLE:
+           case CONSTR_ATTR_DEFERRED:
+           case CONSTR_ATTR_IMMEDIATE:
+               elog(ERROR, "DefineDomain: DEFERRABLE, NON DEFERRABLE, DEFERRED and IMMEDIATE not supported");
+               break;
+
+           default:
+               elog(ERROR, "DefineDomain: unrecognized constraint node type");
+               break;
+       }
+   }
+
+   /*
+    * Have TypeCreate do all the real work.
+    */
+   TypeCreate(domainName,          /* type name */
+              domainNamespace,     /* namespace */
+              InvalidOid,          /* preassigned type oid (not done here) */
+              InvalidOid,          /* relation oid (n/a here) */
+              internalLength,      /* internal size */
+              externalLength,      /* external size */
+              'd',                 /* type-type (domain type) */
+              delimiter,           /* array element delimiter */
+              inputProcedure,      /* input procedure */
+              outputProcedure,     /* output procedure */
+              receiveProcedure,    /* receive procedure */
+              sendProcedure,       /* send procedure */
+              basetypelem,         /* element type ID */
+              typeTup->t_data->t_oid,  /* base type ID */
+              defaultValue,        /* default type value (text) */
+              defaultValueBin,     /* default type value (binary) */
+              byValue,             /* passed by value */
+              alignment,           /* required alignment */
+              storage,             /* TOAST strategy */
+              stmt->typename->typmod, /* typeMod value */
+              typNDims,            /* Array dimensions for base type */
+              typNotNull);         /* Type NOT NULL */
+
+   /*
+    * Now we can clean up.
+    */
+   ReleaseSysCache(typeTup);
+}
+
+
+/*
+ * RemoveDomain
+ *     Removes a domain.
+ */
+void
+RemoveDomain(List *names, int behavior)
+{
+   TypeName   *typename;
+   Relation    relation;
+   Oid         typeoid;
+   HeapTuple   tup;
+   char        typtype;
+
+   /* CASCADE unsupported */
+   if (behavior == CASCADE)
+       elog(ERROR, "DROP DOMAIN does not support the CASCADE keyword");
+
+   /* Make a TypeName so we can use standard type lookup machinery */
+   typename = makeNode(TypeName);
+   typename->names = names;
+   typename->typmod = -1;
+   typename->arrayBounds = NIL;
+
+   relation = heap_openr(TypeRelationName, RowExclusiveLock);
+
+   typeoid = typenameTypeId(typename);
+
+   tup = SearchSysCache(TYPEOID,
+                        ObjectIdGetDatum(typeoid),
+                        0, 0, 0);
+   if (!HeapTupleIsValid(tup))
+       elog(ERROR, "RemoveDomain: type '%s' does not exist",
+            TypeNameToString(typename));
+
+   if (!pg_type_ownercheck(typeoid, GetUserId()))
+       elog(ERROR, "RemoveDomain: type '%s': permission denied",
+            TypeNameToString(typename));
+
+   /* Check that this is actually a domain */
+   typtype = ((Form_pg_type) GETSTRUCT(tup))->typtype;
+
+   if (typtype != 'd')
+       elog(ERROR, "%s is not a domain",
+            TypeNameToString(typename));
+
+   /* Delete any comments associated with this type */
+   DeleteComments(typeoid, RelationGetRelid(relation));
+
+   /* Remove the type tuple from pg_type */
+   simple_heap_delete(relation, &tup->t_self);
+
+   ReleaseSysCache(tup);
+
+   /* At present, domains don't have associated array types */
+
+   heap_close(relation, RowExclusiveLock);
+}
+
+
+/*
+ * Find a suitable I/O function for a type.
+ */
+static Oid
+findTypeIOFunction(List *procname, bool isOutput)
+{
+   Oid         argList[FUNC_MAX_ARGS];
+   int         nargs;
+   Oid         procOid;
+
+   /*
+    * First look for a 1-argument func with all argtypes 0. This is
+    * valid for all kinds of procedure.
+    */
+   MemSet(argList, 0, FUNC_MAX_ARGS * sizeof(Oid));
+
+   procOid = LookupFuncName(procname, 1, argList);
+
+   if (!OidIsValid(procOid))
+   {
+       /*
+        * Alternatively, input procedures may take 3 args (data
+        * value, element OID, atttypmod); the pg_proc argtype
+        * signature is 0,OIDOID,INT4OID.  Output procedures may
+        * take 2 args (data value, element OID).
+        */
+       if (isOutput)
+       {
+           /* output proc */
+           nargs = 2;
+           argList[1] = OIDOID;
+       }
+       else
+       {
+           /* input proc */
+           nargs = 3;
+           argList[1] = OIDOID;
+           argList[2] = INT4OID;
+       }
+       procOid = LookupFuncName(procname, nargs, argList);
+
+       if (!OidIsValid(procOid))
+           func_error("TypeCreate", procname, 1, argList, NULL);
+   }
+
+   return procOid;
+}
index 6b8652db5b72e5c4adba96046a00dad33917600c..bb4f2185b08baac403fedd2e693812864714a18c 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: view.c,v 1.61 2002/03/29 19:06:08 tgl Exp $
+ * $Id: view.c,v 1.62 2002/04/15 05:22:03 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -15,7 +15,7 @@
 #include "access/xact.h"
 #include "catalog/heap.h"
 #include "catalog/namespace.h"
-#include "commands/creatinh.h"
+#include "commands/tablecmds.h"
 #include "commands/view.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
index 659ab63f5536dfd4ff2f65b6b95e50123ba6bfa4..a2045a9eb80e2dc808020df999865d9932defdd5 100644 (file)
@@ -27,7 +27,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.157 2002/04/08 22:42:18 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.158 2002/04/15 05:22:04 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -36,7 +36,7 @@
 #include "access/heapam.h"
 #include "catalog/heap.h"
 #include "catalog/namespace.h"
-#include "commands/command.h"
+#include "commands/tablecmds.h"
 #include "commands/trigger.h"
 #include "executor/execdebug.h"
 #include "executor/execdefs.h"
index f09f90744e8fcae68cf416368dccadc3295d56af..b9bcce30e29acab992940a0f59ff650b7d638349 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/executor/spi.c,v 1.68 2002/03/21 16:00:38 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/executor/spi.c,v 1.69 2002/04/15 05:22:04 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -16,7 +16,7 @@
 
 #include "access/printtup.h"
 #include "catalog/heap.h"
-#include "commands/command.h"
+#include "commands/portalcmds.h"
 #include "executor/spi_priv.h"
 #include "tcop/tcopprot.h"
 #include "utils/lsyscache.h"
index 4599a27a6428512fd8c4b634270373e8c621299b..e8df96a53defeb4bc6e26b6a6674f36f0745a2a3 100644 (file)
@@ -8,14 +8,14 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.51 2002/03/21 16:01:27 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.52 2002/04/15 05:22:04 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 
 #include "postgres.h"
 
-#include "commands/command.h"
+#include "commands/portalcmds.h"
 #include "executor/execdefs.h"
 #include "executor/executor.h"
 #include "tcop/pquery.h"
index 77dfe4a23651b9124ea60ce1bfb3673ae81dc3af..63e6b5dd9b2184ccc8a453b0d2c6bade4644696b 100644 (file)
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.148 2002/04/12 20:38:27 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.149 2002/04/15 05:22:04 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "catalog/pg_shadow.h"
 #include "commands/async.h"
 #include "commands/cluster.h"
-#include "commands/command.h"
 #include "commands/comment.h"
 #include "commands/copy.h"
-#include "commands/creatinh.h"
 #include "commands/dbcommands.h"
 #include "commands/defrem.h"
 #include "commands/explain.h"
+#include "commands/lockcmds.h"
+#include "commands/portalcmds.h"
 #include "commands/proclang.h"
-#include "commands/rename.h"
+#include "commands/schemacmds.h"
 #include "commands/sequence.h"
+#include "commands/tablecmds.h"
 #include "commands/trigger.h"
 #include "commands/user.h"
 #include "commands/vacuum.h"
diff --git a/src/include/commands/command.h b/src/include/commands/command.h
deleted file mode 100644 (file)
index cfb8f20..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * command.h
- *   prototypes for command.c.
- *
- *
- * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- * $Id: command.h,v 1.37 2002/04/01 04:35:39 tgl Exp $
- *
- *-------------------------------------------------------------------------
- */
-#ifndef COMMAND_H
-#define COMMAND_H
-
-#include "utils/portal.h"
-
-
-/*
- * PerformPortalFetch
- *     Performs the POSTQUEL function FETCH.  Fetches count (or all if 0)
- * tuples in portal with name in the forward direction iff goForward.
- *
- * Exceptions:
- *     BadArg if forward invalid.
- *     "ERROR" if portal not found.
- */
-extern void PerformPortalFetch(char *name, bool forward, int count,
-                              CommandDest dest, char *completionTag);
-
-/*
- * PerformPortalClose
- *     Performs the POSTQUEL function CLOSE.
- */
-extern void PerformPortalClose(char *name, CommandDest dest);
-
-extern void PortalCleanup(Portal portal);
-
-/*
- * ALTER TABLE variants
- */
-extern void AlterTableAddColumn(Oid myrelid, bool inherits, ColumnDef *colDef);
-
-extern void AlterTableAlterColumnDefault(Oid myrelid, bool inh,
-                                        const char *colName, Node *newDefault);
-
-extern void AlterTableAlterColumnDropNotNull(Oid myrelid,
-                            bool inh, const char *colName);
-
-extern void AlterTableAlterColumnSetNotNull(Oid myrelid,
-                            bool inh, const char *colName);
-
-extern void AlterTableAlterColumnFlags(Oid myrelid,
-                                      bool inh, const char *colName,
-                                      Node *flagValue, const char *flagType);
-
-extern void AlterTableDropColumn(Oid myrelid, bool inh,
-                                const char *colName, int behavior);
-
-extern void AlterTableAddConstraint(Oid myrelid,
-                                   bool inh, List *newConstraints);
-
-extern void AlterTableDropConstraint(Oid myrelid,
-                                    bool inh, const char *constrName, int behavior);
-
-extern void AlterTableCreateToastTable(Oid relOid, bool silent);
-
-extern void AlterTableOwner(Oid relationOid, int32 newOwnerSysId);
-
-/*
- * LOCK
- */
-extern void LockTableCommand(LockStmt *lockstmt);
-
-/*
- * SCHEMA
- */
-extern void CreateSchemaCommand(CreateSchemaStmt *parsetree);
-
-#endif   /* COMMAND_H */
diff --git a/src/include/commands/creatinh.h b/src/include/commands/creatinh.h
deleted file mode 100644 (file)
index fe0f2bc..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * creatinh.h
- *   prototypes for creatinh.c.
- *
- *
- * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- * $Id: creatinh.h,v 1.20 2002/03/29 19:06:22 tgl Exp $
- *
- *-------------------------------------------------------------------------
- */
-#ifndef CREATINH_H
-#define CREATINH_H
-
-#include "nodes/parsenodes.h"
-
-extern Oid DefineRelation(CreateStmt *stmt, char relkind);
-extern void RemoveRelation(const RangeVar *relation);
-extern void TruncateRelation(const RangeVar *relation);
-
-#endif   /* CREATINH_H */
index 83b8fec6d77cb05cc6e06f9561186fcf7231181d..711bc91f57993f3a37e29795635e466e698bc35b 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: defrem.h,v 1.34 2002/04/09 20:35:54 tgl Exp $
+ * $Id: defrem.h,v 1.35 2002/04/15 05:22:03 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -16,6 +16,8 @@
 
 #include "nodes/parsenodes.h"
 
+#define DEFAULT_TYPDELIM       ','
+
 /*
  * prototypes in indexcmds.c
  */
@@ -33,22 +35,33 @@ extern void ReindexTable(RangeVar *relation, bool force);
 extern void ReindexDatabase(const char *databaseName, bool force, bool all);
 
 /*
- * prototypes in define.c
+ * DefineFoo and RemoveFoo are now both in foocmds.c
  */
+
 extern void CreateFunction(ProcedureStmt *stmt);
+extern void RemoveFunction(List *functionName, List *argTypes);
+
 extern void DefineOperator(List *names, List *parameters);
+extern void RemoveOperator(char *operatorName,
+                          TypeName *typeName1, TypeName *typeName2);
+
 extern void DefineAggregate(List *names, List *parameters);
+extern void RemoveAggregate(List *aggName, TypeName *aggType);
+
 extern void DefineType(List *names, List *parameters);
+extern void RemoveType(List *names);
 extern void DefineDomain(CreateDomainStmt *stmt);
-
-/*
- * prototypes in remove.c
- */
 extern void RemoveDomain(List *names, int behavior);
-extern void RemoveFunction(List *functionName, List *argTypes);
-extern void RemoveOperator(char *operatorName,
-              TypeName *typeName1, TypeName *typeName2);
-extern void RemoveType(List *names);
-extern void RemoveAggregate(List *aggName, TypeName *aggType);
+
+
+/* support routines in define.c */
+
+extern void case_translate_language_name(const char *input, char *output);
+
+extern char *defGetString(DefElem *def);
+extern double defGetNumeric(DefElem *def);
+extern List *defGetQualifiedName(DefElem *def);
+extern TypeName *defGetTypeName(DefElem *def);
+extern int defGetTypeLength(DefElem *def);
 
 #endif   /* DEFREM_H */
diff --git a/src/include/commands/lockcmds.h b/src/include/commands/lockcmds.h
new file mode 100644 (file)
index 0000000..04335c3
--- /dev/null
@@ -0,0 +1,24 @@
+/*-------------------------------------------------------------------------
+ *
+ * lockcmds.h
+ *   prototypes for lockcmds.c.
+ *
+ *
+ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * $Id: lockcmds.h,v 1.1 2002/04/15 05:22:03 tgl Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef LOCKCMDS_H
+#define LOCKCMDS_H
+
+#include "nodes/parsenodes.h"
+
+/*
+ * LOCK
+ */
+extern void LockTableCommand(LockStmt *lockstmt);
+
+#endif  /* LOCKCMDS_H */
diff --git a/src/include/commands/portalcmds.h b/src/include/commands/portalcmds.h
new file mode 100644 (file)
index 0000000..b62e363
--- /dev/null
@@ -0,0 +1,39 @@
+/*-------------------------------------------------------------------------
+ *
+ * portalcmds.h
+ *   prototypes for portalcmds.c.
+ *
+ *
+ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * $Id: portalcmds.h,v 1.1 2002/04/15 05:22:03 tgl Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef PORTALCMDS_H
+#define PORTALCMDS_H
+
+#include "utils/portal.h"
+
+/*
+ * PerformPortalFetch
+ *     Performs the POSTQUEL function FETCH.  Fetches count (or all if 0)
+ * tuples in portal with name in the forward direction iff goForward.
+ *
+ * Exceptions:
+ *     BadArg if forward invalid.
+ *     "ERROR" if portal not found.
+ */
+extern void PerformPortalFetch(char *name, bool forward, int count,
+                              CommandDest dest, char *completionTag);
+
+/*
+ * PerformPortalClose
+ *     Performs the POSTQUEL function CLOSE.
+ */
+extern void PerformPortalClose(char *name, CommandDest dest);
+
+extern void PortalCleanup(Portal portal);
+
+#endif  /* PORTALCMDS_H */
diff --git a/src/include/commands/rename.h b/src/include/commands/rename.h
deleted file mode 100644 (file)
index 48e1a1c..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * rename.h
- *
- *
- *
- * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- * $Id: rename.h,v 1.16 2002/03/31 07:49:30 tgl Exp $
- *
- *-------------------------------------------------------------------------
- */
-#ifndef RENAME_H
-#define RENAME_H
-
-extern void renameatt(Oid relid,
-         const char *oldattname,
-         const char *newattname,
-         bool recurse);
-
-extern void renamerel(Oid relid,
-         const char *newrelname);
-
-#endif   /* RENAME_H */
diff --git a/src/include/commands/schemacmds.h b/src/include/commands/schemacmds.h
new file mode 100644 (file)
index 0000000..6adf9a4
--- /dev/null
@@ -0,0 +1,22 @@
+/*-------------------------------------------------------------------------
+ *
+ * schemacmds.h
+ *   prototypes for schemacmds.c.
+ *
+ *
+ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * $Id: schemacmds.h,v 1.1 2002/04/15 05:22:04 tgl Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifndef SCHEMACMDS_H
+#define SCHEMACMDS_H
+
+#include "nodes/parsenodes.h"
+
+extern void CreateSchemaCommand(CreateSchemaStmt *parsetree);
+
+#endif  /* SCHEMACMDS_H */
diff --git a/src/include/commands/tablecmds.h b/src/include/commands/tablecmds.h
new file mode 100644 (file)
index 0000000..5d89597
--- /dev/null
@@ -0,0 +1,63 @@
+/*-------------------------------------------------------------------------
+ *
+ * tablecmds.h
+ *   prototypes for tablecmds.c.
+ *
+ *
+ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * $Id: tablecmds.h,v 1.1 2002/04/15 05:22:04 tgl Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef TABLECMDS_H
+#define TABLECMDS_H
+
+#include "nodes/parsenodes.h"
+
+extern void AlterTableAddColumn(Oid myrelid, bool inherits,
+                               ColumnDef *colDef);
+
+extern void AlterTableAlterColumnDefault(Oid myrelid, bool inh,
+                                        const char *colName,
+                                        Node *newDefault);
+
+extern void AlterTableAlterColumnDropNotNull(Oid myrelid, bool inh,
+                                            const char *colName);
+
+extern void AlterTableAlterColumnSetNotNull(Oid myrelid, bool inh,
+                                           const char *colName);
+
+extern void AlterTableAlterColumnFlags(Oid myrelid, bool inh,
+                                      const char *colName,
+                                      Node *flagValue, const char *flagType);
+
+extern void AlterTableDropColumn(Oid myrelid, bool inh,
+                                const char *colName, int behavior);
+
+extern void AlterTableAddConstraint(Oid myrelid, bool inh,
+                                   List *newConstraints);
+
+extern void AlterTableDropConstraint(Oid myrelid, bool inh,
+                                    const char *constrName, int behavior);
+
+extern void AlterTableCreateToastTable(Oid relOid, bool silent);
+
+extern void AlterTableOwner(Oid relationOid, int32 newOwnerSysId);
+
+extern Oid DefineRelation(CreateStmt *stmt, char relkind);
+
+extern void RemoveRelation(const RangeVar *relation);
+
+extern void TruncateRelation(const RangeVar *relation);
+
+extern void renameatt(Oid relid,
+         const char *oldattname,
+         const char *newattname,
+         bool recurse);
+
+extern void renamerel(Oid relid,
+         const char *newrelname);
+
+#endif   /* TABLECMDS_H */