Thread: Adds the parsing of a CREATE SCHEMA statement

Adds the parsing of a CREATE SCHEMA statement

From
Fernando Nasser
Date:
ChnageLog:

        Adds the parsing of a CREATE SCHEMA statement.  It is
        still just syntactic sugar as we still have a single namespace.
        We also now accept qualified names for tables and views (where
the
        reference is for tables, not for columns) but we do nothing with
it.


--
Fernando Nasser
Red Hat Canada Ltd.                     E-Mail:  fnasser@redhat.com
2323 Yonge Street, Suite #300
Toronto, Ontario   M4P 2C9Index: src/backend/nodes/copyfuncs.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v
retrieving revision 1.163
diff -c -p -r1.163 copyfuncs.c
*** src/backend/nodes/copyfuncs.c    2002/02/26 22:47:05    1.163
--- src/backend/nodes/copyfuncs.c    2002/02/28 20:46:34
*************** _copyReindexStmt(ReindexStmt *from)
*** 2508,2514 ****
--- 2508,2528 ----
      return newnode;
  }

+ static CreateSchemaStmt *
+ _copyCreateSchemaStmt(CreateSchemaStmt *from)
+ {
+     CreateSchemaStmt *newnode = makeNode(CreateSchemaStmt);
+
+     newnode->schemaname = pstrdup(from->schemaname);
+     if (from->authid)
+         newnode->authid = pstrdup(from->authid);
+     Node_Copy(from, newnode, schemaElts);
+     newnode->in_progress = from->in_progress;

+     return newnode;
+ }
+
+
  /* ****************************************************************
   *                    pg_list.h copy functions
   * ****************************************************************
*************** copyObject(void *from)
*** 2905,2910 ****
--- 2919,2927 ----
              break;
          case T_CheckPointStmt:
              retval = (void *) makeNode(CheckPointStmt);
+             break;
+         case T_CreateSchemaStmt:
+             retval = _copyCreateSchemaStmt(from);
              break;

          case T_A_Expr:
Index: src/backend/nodes/equalfuncs.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v
retrieving revision 1.111
diff -c -p -r1.111 equalfuncs.c
*** src/backend/nodes/equalfuncs.c    2002/02/26 22:47:05    1.111
--- src/backend/nodes/equalfuncs.c    2002/02/28 20:46:34
*************** _equalReindexStmt(ReindexStmt *a, Reinde
*** 1369,1374 ****
--- 1369,1389 ----
  }

  static bool
+ _equalCreateSchemaStmt(CreateSchemaStmt *a, CreateSchemaStmt *b)
+ {
+     if (!equalstr(a->schemaname, b->schemaname))
+         return false;
+     if (!equalstr(a->authid, b->authid))
+         return false;
+     if (!equal(a->schemaElts, b->schemaElts))
+         return false;
+     if (a->in_progress != b->in_progress)
+         return false;
+
+     return true;
+ }
+
+ static bool
  _equalAExpr(A_Expr *a, A_Expr *b)
  {
      if (a->oper != b->oper)
*************** equal(void *a, void *b)
*** 2050,2055 ****
--- 2065,2073 ----
              break;
          case T_CheckPointStmt:
              retval = true;
+             break;
+         case T_CreateSchemaStmt:
+             retval = _equalCreateSchemaStmt(a, b);
              break;

          case T_A_Expr:
Index: src/backend/parser/analyze.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/parser/analyze.c,v
retrieving revision 1.215
diff -c -p -r1.215 analyze.c
*** src/backend/parser/analyze.c    2002/02/26 22:47:08    1.215
--- src/backend/parser/analyze.c    2002/02/28 20:46:34
***************
*** 43,48 ****
--- 43,66 ----
  #endif


+ /* State shared by transformCreateSchemaStmt and its subroutines */
+ typedef struct
+ {
+     const char *stmtType;        /* "CREATE TABLE" or "ALTER TABLE" */
+     char       *schemaname;        /* name of schema */
+     char       *authid;            /* owner of schema */
+     List       *tables;            /* CREATE TABLE items */
+     List       *views;            /* CREATE VIEW items */
+     List       *grants;            /* GRANT items */
+     List       *fwconstraints;    /* Forward referencing FOREIGN KEY constraints */
+     List       *alters;            /* Generated ALTER items (from the above) */
+     List       *ixconstraints;    /* index-creating constraints */
+     List       *blist;            /* "before list" of things to do before
+                                  * creating the schema */
+     List       *alist;            /* "after list" of things to do after
+                                  * creating the schema */
+ } CreateSchemaStmtContext;
+
  /* State shared by transformCreateStmt and its subroutines */
  typedef struct
  {
*************** static Query *transformSelectStmt(ParseS
*** 76,81 ****
--- 94,101 ----
  static Query *transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt);
  static Node *transformSetOperationTree(ParseState *pstate, SelectStmt *stmt);
  static Query *transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt);
+ static Query *transformCreateSchemaStmt(ParseState *pstate, CreateSchemaStmt *stmt,
+                         List **extras_before, List **extras_after);
  static Query *transformCreateStmt(ParseState *pstate, CreateStmt *stmt,
                          List **extras_before, List **extras_after);
  static Query *transformAlterTableStmt(ParseState *pstate, AlterTableStmt *stmt,
*************** parse_analyze(Node *parseTree, ParseStat
*** 130,135 ****
--- 150,159 ----

      query = transformStmt(pstate, parseTree, &extras_before, &extras_after);
      release_pstate_resources(pstate);
+
+     /* Check if we are done processing this parseTree */
+     if (query == NULL)
+         return NIL;

      while (extras_before != NIL)
      {
*************** transformStmt(ParseState *pstate, Node *
*** 186,191 ****
--- 210,225 ----
              /*
               * Non-optimizable statements
               */
+         case T_CreateSchemaStmt:
+             /*
+              * transformCreateSchemaStmt sets the parseTree nodeTag to
+              * T_Invalid when its done; otherwise the parseTree
+              * is modified to contain what still has to be done
+              */
+             result = transformCreateSchemaStmt(pstate, (CreateSchemaStmt *) parseTree,
+                                     extras_before, extras_after);
+             break;
+
          case T_CreateStmt:
              result = transformCreateStmt(pstate, (CreateStmt *) parseTree,
                                      extras_before, extras_after);
*************** CreateIndexName(char *table_name, char *
*** 671,676 ****
--- 705,797 ----
      }

      return iname;
+ }
+
+ /*
+  * transformCreateSchemaStmt -
+  *      transforms the "create schema" statement
+  *
+  *    Split the schema element list into individual commands and place
+  *     them in the extras_after list in an order such that there is no
+  *     forward references (e.g. GRANT to a table created after in the list).
+  *      SQL92also allows constraints to make forward references, so thumb through
+  *       the table columns and move forward references to a posterior alter table.
+  */
+ static Query *
+ transformCreateSchemaStmt(ParseState *pstate, CreateSchemaStmt *stmt,
+                     List **extras_before, List **extras_after)
+ {
+     CreateSchemaStmtContext cxt;
+     Query       *q;
+     List       *elements;
+
+     cxt.stmtType = "CREATE SCHEMA";
+     cxt.schemaname = stmt->schemaname;
+     cxt.authid = stmt->authid;
+     cxt.tables = NIL;
+     cxt.views = NIL;
+     cxt.grants = NIL;
+     cxt.fwconstraints = NIL;
+     cxt.alters = NIL;
+     cxt.blist = NIL;
+     cxt.alist = NIL;
+
+     /*
+      * Run through each schema element in the schema element list.
+      * Separate statements by type, and do preliminary analysis.
+      */
+     foreach(elements, stmt->schemaElts)
+     {
+         Node       *element = lfirst(elements);
+
+         switch (nodeTag(element))
+         {
+             case T_CreateStmt:
+                 cxt.tables = lappend(cxt.tables, element);
+                 break;
+
+             case T_ViewStmt:
+                 cxt.views = lappend(cxt.views, element);
+                 break;
+
+             case T_GrantStmt:
+                 cxt.grants = lappend(cxt.grants, element);
+                 break;
+
+             default:
+                 elog(ERROR, "parser: unrecognized schema node (internal error)");
+         }
+     }
+
+     if (cxt.tables != NIL)
+     {
+         cxt.alist = nconc(cxt.alist, cxt.tables);
+         stmt->schemaElts = cxt.views;
+         stmt->schemaElts = nconc(stmt->schemaElts, cxt.grants);
+     } else if (cxt.views != NIL)
+     {
+         /* Views have to be processed one at a time */
+         cxt.alist = makeList1(lfirst(cxt.views));
+         stmt->schemaElts = nconc(lnext(cxt.views), cxt.grants);
+     } else if (cxt.grants != NIL)
+     {
+         cxt.alist = nconc(cxt.alist, cxt.grants);
+         stmt->schemaElts = NIL;
+     } else if (stmt->in_progress)
+         /* ProcessUtility marks the T_CreateSchemaStmt as in progress so
+            we do not try to create the schema again */
+         return NULL;
+
+     /*
+      * Output results.
+      */
+     q = makeNode(Query);
+     q->commandType = CMD_UTILITY;
+     q->utilityStmt = (Node *) stmt;
+     *extras_before = nconc (*extras_before, cxt.blist);
+     *extras_after = nconc (cxt.alist, *extras_after);
+
+     return q;
  }

  /*
Index: src/backend/parser/gram.y
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/parser/gram.y,v
retrieving revision 2.281
diff -c -p -r2.281 gram.y
*** src/backend/parser/gram.y    2002/02/25 03:37:14    2.281
--- src/backend/parser/gram.y    2002/02/28 20:46:36
*************** static void doNegateFloat(Value *v);
*** 129,135 ****
      InsertStmt            *istmt;
  }

! %type <node>    stmt,
          AlterGroupStmt, AlterSchemaStmt, AlterTableStmt, AlterUserStmt,
          AnalyzeStmt,
          ClosePortalStmt, ClusterStmt, CommentStmt, ConstraintsSetStmt,
--- 129,135 ----
      InsertStmt            *istmt;
  }

! %type <node>    stmt, schema_stmt, nonschema_stmt,
          AlterGroupStmt, AlterSchemaStmt, AlterTableStmt, AlterUserStmt,
          AnalyzeStmt,
          ClosePortalStmt, ClusterStmt, CommentStmt, ConstraintsSetStmt,
*************** static void doNegateFloat(Value *v);
*** 166,171 ****
--- 166,174 ----
  %type <list>    OptUserList
  %type <defelt>    OptUserElem

+ %type <str>        OptSchemaName
+ %type <list>    OptSchemaEltList
+
  %type <boolean>    TriggerActionTime, TriggerForSpec, opt_trusted, opt_procedural
  %type <str>        opt_lancompiler

*************** static void doNegateFloat(Value *v);
*** 176,182 ****

  %type <str>        relation_name, copy_file_name, copy_delimiter, copy_null,
          database_name, access_method_clause, access_method, attr_name,
!         class, index_name, name, func_name, file_name

  %type <str>        opt_id,
          all_Op, MathOp, opt_name,
--- 179,185 ----

  %type <str>        relation_name, copy_file_name, copy_delimiter, copy_null,
          database_name, access_method_clause, access_method, attr_name,
!         class, index_name, name, func_name, file_name, qualified_name

  %type <str>        opt_id,
          all_Op, MathOp, opt_name,
*************** stmtmulti:  stmtmulti ';' stmt
*** 435,448 ****
                      $$ = NIL;
                  }
          ;

! stmt :    AlterSchemaStmt
          | AlterTableStmt
          | AlterGroupStmt
          | AlterUserStmt
          | ClosePortalStmt
          | CopyStmt
-         | CreateStmt
          | CreateAsStmt
          | CreateSchemaStmt
          | CreateGroupStmt
--- 438,462 ----
                      $$ = NIL;
                  }
          ;
+
+ /*
+  *    schema_stmt are the ones that can show up inside a CREATE SCHEMA
+  *  statement (in addition to by themselves).
+  */
+ stmt:    schema_stmt | nonschema_stmt
+         ;

! schema_stmt : CreateStmt
!         | GrantStmt
!         | ViewStmt
!         ;
!
! nonschema_stmt :    AlterSchemaStmt
          | AlterTableStmt
          | AlterGroupStmt
          | AlterUserStmt
          | ClosePortalStmt
          | CopyStmt
          | CreateAsStmt
          | CreateSchemaStmt
          | CreateGroupStmt
*************** stmt :    AlterSchemaStmt
*** 462,468 ****
          | DropUserStmt
          | ExplainStmt
          | FetchStmt
-         | GrantStmt
          | IndexStmt
          | ListenStmt
          | UnlistenStmt
--- 476,481 ----
*************** stmt :    AlterSchemaStmt
*** 478,484 ****
          | OptimizableStmt
          | RuleStmt
          | TransactionStmt
-         | ViewStmt
          | LoadStmt
          | CreatedbStmt
          | DropdbStmt
--- 491,496 ----
*************** DropGroupStmt: DROP GROUP UserId
*** 729,743 ****
   *
   *****************************************************************************/

! CreateSchemaStmt:  CREATE SCHEMA UserId
                  {
!                     /* for now, just make this the same as CREATE DATABASE */
!                     CreatedbStmt *n = makeNode(CreatedbStmt);
!                     n->dbname = $3;
!                     n->dbowner = NULL;
!                     n->dbpath = NULL;
!                     n->dbtemplate = NULL;
!                     n->encoding = -1;
                      $$ = (Node *)n;
                  }
          ;
--- 741,767 ----
   *
   *****************************************************************************/

! CreateSchemaStmt:  CREATE SCHEMA OptSchemaName AUTHORIZATION UserId OptSchemaEltList
                  {
!                     CreateSchemaStmt *n = makeNode(CreateSchemaStmt);
!                     /* One can omit the schema name or the authorization id... */
!                     if ($3 != NULL)
!                         n->schemaname = $3;
!                     else
!                         n->schemaname = $5;
!                     n->authid = $5;
!                     n->schemaElts = $6;
!                     n->in_progress = false;
!                     $$ = (Node *)n;
!                 }
!         | CREATE SCHEMA ColId OptSchemaEltList
!                 {
!                     CreateSchemaStmt *n = makeNode(CreateSchemaStmt);
!                     /* ...but not both */
!                     n->schemaname = $3;
!                     n->authid = NULL;
!                     n->schemaElts = $4;
!                     n->in_progress = false;
                      $$ = (Node *)n;
                  }
          ;
*************** AlterSchemaStmt:  ALTER SCHEMA UserId
*** 750,760 ****

  DropSchemaStmt:  DROP SCHEMA UserId
                  {
!                     DropdbStmt *n = makeNode(DropdbStmt);
!                     n->dbname = $3;
!                     $$ = (Node *)n;
                  }


  /*****************************************************************************
   *
--- 774,794 ----

  DropSchemaStmt:  DROP SCHEMA UserId
                  {
!                     elog(ERROR, "DROP SCHEMA not yet supported");
                  }

+ OptSchemaName: ColId                                { $$ = $1 }
+         | /* EMPTY */                                { $$ = NULL; }
+         ;
+
+ OptSchemaEltList: OptSchemaEltList schema_stmt
+         {    if ($1 == NIL)
+                 $$ = makeList1($2);
+             else
+                 $$ = lappend($1, $2);
+         }
+         | /* EMPTY */                                { $$ = NIL; }
+         ;

  /*****************************************************************************
   *
*************** copy_null:      WITH NULL_P AS Sconst
*** 1253,1259 ****
   *
   *****************************************************************************/

! CreateStmt:  CREATE OptTemp TABLE relation_name '(' OptTableElementList ')' OptInherit OptWithOids
                  {
                      CreateStmt *n = makeNode(CreateStmt);
                      n->relname = $4;
--- 1287,1293 ----
   *
   *****************************************************************************/

! CreateStmt:  CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')' OptInherit OptWithOids
                  {
                      CreateStmt *n = makeNode(CreateStmt);
                      n->relname = $4;
*************** OptWithOids:  WITH OIDS                        { $$ = TRUE
*** 1616,1622 ****
   * SELECT ... INTO.
   */

! CreateAsStmt:  CREATE OptTemp TABLE relation_name OptCreateAs AS SelectStmt
                  {
                      /*
                       * When the SelectStmt is a set-operation tree, we must
--- 1650,1656 ----
   * SELECT ... INTO.
   */

! CreateAsStmt:  CREATE OptTemp TABLE qualified_name OptCreateAs AS SelectStmt
                  {
                      /*
                       * When the SelectStmt is a set-operation tree, we must
*************** opt_chain: AND NO CHAIN
*** 3010,3016 ****
   *
   *****************************************************************************/

! ViewStmt:  CREATE VIEW name opt_column_list AS SelectStmt
                  {
                      ViewStmt *n = makeNode(ViewStmt);
                      n->viewname = $3;
--- 3044,3050 ----
   *
   *****************************************************************************/

! ViewStmt:  CREATE VIEW qualified_name opt_column_list AS SelectStmt
                  {
                      ViewStmt *n = makeNode(ViewStmt);
                      n->viewname = $3;
*************** join_qual:  USING '(' name_list ')'                {
*** 4049,4055 ****
          ;


! relation_expr:    relation_name
                  {
                      /* default inheritance */
                      $$ = makeNode(RangeVar);
--- 4083,4089 ----
          ;


! relation_expr:    qualified_name
                  {
                      /* default inheritance */
                      $$ = makeNode(RangeVar);
*************** relation_expr:    relation_name
*** 4057,4063 ****
                      $$->inhOpt = INH_DEFAULT;
                      $$->name = NULL;
                  }
!         | relation_name '*'
                  {
                      /* inheritance query */
                      $$ = makeNode(RangeVar);
--- 4091,4097 ----
                      $$->inhOpt = INH_DEFAULT;
                      $$->name = NULL;
                  }
!         | qualified_name '*'
                  {
                      /* inheritance query */
                      $$ = makeNode(RangeVar);
*************** relation_expr:    relation_name
*** 4065,4071 ****
                      $$->inhOpt = INH_YES;
                      $$->name = NULL;
                  }
!         | ONLY relation_name
                  {
                      /* no inheritance */
                      $$ = makeNode(RangeVar);
--- 4099,4105 ----
                      $$->inhOpt = INH_YES;
                      $$->name = NULL;
                  }
!         | ONLY qualified_name
                  {
                      /* no inheritance */
                      $$ = makeNode(RangeVar);
*************** relation_name:    SpecialRuleRelation
*** 5611,5616 ****
--- 5645,5660 ----
                  }
          ;

+ qualified_name: ColId
+                 {
+                     $$ = $1;
+                 }
+         | ColId '.' ColId
+                 {
+                     $$ = $3;
+                 }
+         ;
+
  name:                    ColId            { $$ = $1; };
  database_name:            ColId            { $$ = $1; };
  access_method:            ColId            { $$ = $1; };
*************** unreserved_keyword:
*** 5791,5797 ****
          | AGGREGATE                        { $$ = "aggregate"; }
          | ALTER                            { $$ = "alter"; }
          | AT                            { $$ = "at"; }
-         | AUTHORIZATION                    { $$ = "authorization"; }
          | BACKWARD                        { $$ = "backward"; }
          | BEFORE                        { $$ = "before"; }
          | BEGIN_TRANS                    { $$ = "begin"; }
--- 5835,5840 ----
*************** unreserved_keyword:
*** 5808,5814 ****
          | COMMITTED                        { $$ = "committed"; }
          | CONSTRAINTS                    { $$ = "constraints"; }
          | COPY                            { $$ = "copy"; }
-         | CREATE                        { $$ = "create"; }
          | CREATEDB                        { $$ = "createdb"; }
          | CREATEUSER                    { $$ = "createuser"; }
          | CURSOR                        { $$ = "cursor"; }
--- 5851,5856 ----
*************** unreserved_keyword:
*** 5833,5839 ****
          | FORWARD                        { $$ = "forward"; }
          | FUNCTION                        { $$ = "function"; }
          | GLOBAL                        { $$ = "global"; }
-         | GRANT                            { $$ = "grant"; }
          | HANDLER                        { $$ = "handler"; }
          | HOUR_P                        { $$ = "hour"; }
          | IMMEDIATE                        { $$ = "immediate"; }
--- 5875,5880 ----
*************** unreserved_keyword:
*** 5911,5917 ****
          | STDIN                            { $$ = "stdin"; }
          | STDOUT                        { $$ = "stdout"; }
          | SYSID                            { $$ = "sysid"; }
-         | TEMP                            { $$ = "temp"; }
          | TEMPLATE                        { $$ = "template"; }
          | TEMPORARY                        { $$ = "temporary"; }
          | TOAST                            { $$ = "toast"; }
--- 5952,5957 ----
*************** col_name_keyword:
*** 5967,5972 ****
--- 6007,6013 ----
          | POSITION                        { $$ = "position"; }
          | SETOF                            { $$ = "setof"; }
          | SUBSTRING                        { $$ = "substring"; }
+         | TEMP                            { $$ = "temp"; }
          | TIME                            { $$ = "time"; }
          | TIMESTAMP                        { $$ = "timestamp"; }
          | TRIM                            { $$ = "trim"; }
*************** col_name_keyword:
*** 5984,5990 ****
   *  - thomas 2000-11-28
   */
  func_name_keyword:
!           BETWEEN                        { $$ = "between"; }
          | BINARY                        { $$ = "binary"; }
          | CROSS                            { $$ = "cross"; }
          | FREEZE                        { $$ = "freeze"; }
--- 6025,6032 ----
   *  - thomas 2000-11-28
   */
  func_name_keyword:
!           AUTHORIZATION                    { $$ = "authorization"; }
!         | BETWEEN                        { $$ = "between"; }
          | BINARY                        { $$ = "binary"; }
          | CROSS                            { $$ = "cross"; }
          | FREEZE                        { $$ = "freeze"; }
*************** reserved_keyword:
*** 6027,6032 ****
--- 6069,6075 ----
          | COLLATE                        { $$ = "collate"; }
          | COLUMN                        { $$ = "column"; }
          | CONSTRAINT                    { $$ = "constraint"; }
+         | CREATE                        { $$ = "create"; }
          | CURRENT_DATE                    { $$ = "current_date"; }
          | CURRENT_TIME                    { $$ = "current_time"; }
          | CURRENT_TIMESTAMP                { $$ = "current_timestamp"; }
*************** reserved_keyword:
*** 6043,6048 ****
--- 6086,6092 ----
          | FOR                            { $$ = "for"; }
          | FOREIGN                        { $$ = "foreign"; }
          | FROM                            { $$ = "from"; }
+         | GRANT                            { $$ = "grant"; }
          | GROUP                            { $$ = "group"; }
          | HAVING                        { $$ = "having"; }
          | INITIALLY                        { $$ = "initially"; }
Index: src/backend/tcop/utility.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/tcop/utility.c,v
retrieving revision 1.127
diff -c -p -r1.127 utility.c
*** src/backend/tcop/utility.c    2002/02/26 22:47:09    1.127
--- src/backend/tcop/utility.c    2002/02/28 20:46:36
*************** ProcessUtility(Node *parsetree,
*** 220,225 ****
--- 220,240 ----
               * manipulation ********************************
               *
               */
+         case T_CreateSchemaStmt:
+             {
+                 CreateSchemaStmt  *stmt = (CreateSchemaStmt *) parsetree;
+                 if (stmt->in_progress)
+                     break;  /* Has created the schema already in a previous pass */
+                 stmt->in_progress = true;
+                 elog(NOTICE, "Schema %s owned by %s will be created",
+                     stmt->schemaname, stmt->authid);
+                 /*
+                  * Let commands in the schema-element-list know about the schema
+                  */
+                 CommandCounterIncrement();
+             }
+             break;
+
          case T_CreateStmt:
              DefineRelation((CreateStmt *) parsetree, RELKIND_RELATION);

Index: src/include/nodes/parsenodes.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/nodes/parsenodes.h,v
retrieving revision 1.154
diff -c -p -r1.154 parsenodes.h
*** src/include/nodes/parsenodes.h    2002/02/26 22:47:10    1.154
--- src/include/nodes/parsenodes.h    2002/02/28 20:46:38
*************** typedef enum InhOption
*** 110,115 ****
--- 110,132 ----
   *****************************************************************************/

  /* ----------------------
+  *        Create Schema Statement
+  *
+  * NOTE: The schemaElts list contain several of the other nodes before
+  * parse analysis.  These become independent nodes after that and the
+  * list is empty.
+  * ----------------------
+  */
+ typedef struct CreateSchemaStmt
+ {
+     NodeTag        type;
+     char       *schemaname;        /* the name of the schema to create */
+     char       *authid;            /* the owner of the created schema */
+     List       *schemaElts;        /* column definitions (list of ColumnDef) */
+     bool        in_progress;    /* used by analyze */
+ } CreateSchemaStmt;
+
+ /* ----------------------
   *    Alter Table
   *
   * The fields are used in different ways by the different variants of

Re: Adds the parsing of a CREATE SCHEMA statement

From
Tom Lane
Date:
This self-modification of the CreateSchema statement makes my head hurt
... isn't there a cleaner way?

I would really like to see us move towards a processing pipeline in
which parse analysis, rewrite, planning, and execution steps each take
their input data structures as *read only*.  I know it's not like that
today, but it needs to be so.  If I were to enumerate the bugs we've had
in the past because of violations of that rule, I'd still be composing
this message at dinnertime.  (And I still have a very long to-fix list
of kluges, workarounds, and memory leaks that are traceable to the lack
of read-only data structures.)  I really really don't want to see any
new work introducing new violations of the rule.

            regards, tom lane

Re: Adds the parsing of a CREATE SCHEMA statement

From
Fernando Nasser
Date:
Tom Lane wrote:
>
> This self-modification of the CreateSchema statement makes my head hurt
> ... isn't there a cleaner way?
>
> I would really like to see us move towards a processing pipeline in
> which parse analysis, rewrite, planning, and execution steps each take
> their input data structures as *read only*.  I know it's not like that
> today, but it needs to be so.  If I were to enumerate the bugs we've had
> in the past because of violations of that rule, I'd still be composing
> this message at dinnertime.  (And I still have a very long to-fix list
> of kluges, workarounds, and memory leaks that are traceable to the lack
> of read-only data structures.)  I really really don't want to see any
> new work introducing new violations of the rule.
>

OK, I will tell you what the problem is and maybe you can help finding
a solution.  Here it is:

The CREATE SCHEMA statement is actually a collection of object creation
and privilege statements.  What happens is that the creation of some
objects, or the assignment of privileges, may depend on the existence
of previous ones.  Following your suggestion, I grouped them in classes
and ordered them so most of the dependencies are solved.  So far so
good.

But then VIEWs came into play.  We can have:

  CREATE SCHEMA
  AUTHORIZATION HU

  CREATE TABLE STAFF
   (EMPNUM   CHAR(3) NOT NULL UNIQUE,
    EMPNAME  CHAR(20),
    GRADE    DECIMAL(4),
    CITY     CHAR(15))

  CREATE VIEW STAFFV1
           AS SELECT * FROM STAFF
              WHERE  GRADE >= 12

  CREATE VIEW STAFFV2
           AS SELECT * FROM STAFF
              WHERE  GRADE >= 12


The creation of the STAFFV1 view requires that the table STAFF has
been created already, i.e., that the CREATE TABLE has been executed
before it can be analyzed (I will explain why below, and that is where
you may be able to help).  Furthermore, the view STAFFV2 requires
that the CREATE VIEW STAFFV1 has been executed already.
That is why I had to iterate in the analyze-execute cycle.

Here is where you can help:  the reason I need the tables (or views)
which are used to create a view to be created before I can analyze
a new view is that it contains a SELECT statement and the analyze
of a SELECT statement _opens_ the relation to do some checking on
columns etc.   If we could avoid that, I could just analyze the
whole CREATE SCHEMA and then execute the (reordered) resulting
commands as a whole.

Here is where it happens:

transformStmt() when called with T_ViewStmt calls itself for the
SELECT statement that defines the view.

transformSelectStmt() is then called, which calls transformFromClause().

transformFromClause() loops calling transformFromClauseItem() and it
calls transformTableEntry().

transformTableEntry() calls addRangeTableEntry(), which is where
the problem is.

addRangeTableEntry() calls heap_open() on the relation we have not
created yet (if we don't iterate as I did) and... BOOM!!!
"relation xxxx does not exist", where xxxx is the relation
previously appearing in the CREATE SCHEMA statement.


addRangeTableEntry() has the following comment at the top:

/*
 * Add an entry for a relation to the pstate's range table (p_rtable).
 *
 * If pstate is NULL, we just build an RTE and return it without adding
it
 * to an rtable list.
 *
 * Note: formerly this checked for refname conflicts, but that's wrong.
 * Caller is responsible for checking for conflicts in the appropriate
scope.
 */

Is there any way we can parse views without doing this?  If we can, we
can
avoid the iteration between analyze-execute.


Another thing: can this happen again with other objects when we add them
to the list of things that can go into a create schema?  I.e., can the
analyze phase of an object depend on another from the same create schema
statement to be created (statement executed) already?


I felt sort of funny about keeping the state on the CreateSchemaStmt.
But this statement is a really weird one and the other possibilities
seemed
worse.  Everything considered, it was still the most logical place.
I guess the only way to avoid this is to get rid of all heap_open()
calls in the analyze phase, at least for statements that can appear in a
create schema statement.


Regards,
Fernando

--
Fernando Nasser
Red Hat Canada Ltd.                     E-Mail:  fnasser@redhat.com
2323 Yonge Street, Suite #300
Toronto, Ontario   M4P 2C9

Re: Adds the parsing of a CREATE SCHEMA statement

From
Bruce Momjian
Date:
I assume you do _not_ want this applied as is is part of Tom's schema
work, right?


---------------------------------------------------------------------------

Fernando Nasser wrote:
> ChnageLog:
>
>         Adds the parsing of a CREATE SCHEMA statement.  It is
>         still just syntactic sugar as we still have a single namespace.
>         We also now accept qualified names for tables and views (where
> the
>         reference is for tables, not for columns) but we do nothing with
> it.
>
>
> --
> Fernando Nasser
> Red Hat Canada Ltd.                     E-Mail:  fnasser@redhat.com
> 2323 Yonge Street, Suite #300
> Toronto, Ontario   M4P 2C9

> Index: src/backend/nodes/copyfuncs.c
> ===================================================================
> RCS file: /projects/cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v
> retrieving revision 1.163
> diff -c -p -r1.163 copyfuncs.c
> *** src/backend/nodes/copyfuncs.c    2002/02/26 22:47:05    1.163
> --- src/backend/nodes/copyfuncs.c    2002/02/28 20:46:34
> *************** _copyReindexStmt(ReindexStmt *from)
> *** 2508,2514 ****
> --- 2508,2528 ----
>       return newnode;
>   }
>
> + static CreateSchemaStmt *
> + _copyCreateSchemaStmt(CreateSchemaStmt *from)
> + {
> +     CreateSchemaStmt *newnode = makeNode(CreateSchemaStmt);
> +
> +     newnode->schemaname = pstrdup(from->schemaname);
> +     if (from->authid)
> +         newnode->authid = pstrdup(from->authid);
> +     Node_Copy(from, newnode, schemaElts);
> +     newnode->in_progress = from->in_progress;
>
> +     return newnode;
> + }
> +
> +
>   /* ****************************************************************
>    *                    pg_list.h copy functions
>    * ****************************************************************
> *************** copyObject(void *from)
> *** 2905,2910 ****
> --- 2919,2927 ----
>               break;
>           case T_CheckPointStmt:
>               retval = (void *) makeNode(CheckPointStmt);
> +             break;
> +         case T_CreateSchemaStmt:
> +             retval = _copyCreateSchemaStmt(from);
>               break;
>
>           case T_A_Expr:
> Index: src/backend/nodes/equalfuncs.c
> ===================================================================
> RCS file: /projects/cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v
> retrieving revision 1.111
> diff -c -p -r1.111 equalfuncs.c
> *** src/backend/nodes/equalfuncs.c    2002/02/26 22:47:05    1.111
> --- src/backend/nodes/equalfuncs.c    2002/02/28 20:46:34
> *************** _equalReindexStmt(ReindexStmt *a, Reinde
> *** 1369,1374 ****
> --- 1369,1389 ----
>   }
>
>   static bool
> + _equalCreateSchemaStmt(CreateSchemaStmt *a, CreateSchemaStmt *b)
> + {
> +     if (!equalstr(a->schemaname, b->schemaname))
> +         return false;
> +     if (!equalstr(a->authid, b->authid))
> +         return false;
> +     if (!equal(a->schemaElts, b->schemaElts))
> +         return false;
> +     if (a->in_progress != b->in_progress)
> +         return false;
> +
> +     return true;
> + }
> +
> + static bool
>   _equalAExpr(A_Expr *a, A_Expr *b)
>   {
>       if (a->oper != b->oper)
> *************** equal(void *a, void *b)
> *** 2050,2055 ****
> --- 2065,2073 ----
>               break;
>           case T_CheckPointStmt:
>               retval = true;
> +             break;
> +         case T_CreateSchemaStmt:
> +             retval = _equalCreateSchemaStmt(a, b);
>               break;
>
>           case T_A_Expr:
> Index: src/backend/parser/analyze.c
> ===================================================================
> RCS file: /projects/cvsroot/pgsql/src/backend/parser/analyze.c,v
> retrieving revision 1.215
> diff -c -p -r1.215 analyze.c
> *** src/backend/parser/analyze.c    2002/02/26 22:47:08    1.215
> --- src/backend/parser/analyze.c    2002/02/28 20:46:34
> ***************
> *** 43,48 ****
> --- 43,66 ----
>   #endif
>
>
> + /* State shared by transformCreateSchemaStmt and its subroutines */
> + typedef struct
> + {
> +     const char *stmtType;        /* "CREATE TABLE" or "ALTER TABLE" */
> +     char       *schemaname;        /* name of schema */
> +     char       *authid;            /* owner of schema */
> +     List       *tables;            /* CREATE TABLE items */
> +     List       *views;            /* CREATE VIEW items */
> +     List       *grants;            /* GRANT items */
> +     List       *fwconstraints;    /* Forward referencing FOREIGN KEY constraints */
> +     List       *alters;            /* Generated ALTER items (from the above) */
> +     List       *ixconstraints;    /* index-creating constraints */
> +     List       *blist;            /* "before list" of things to do before
> +                                  * creating the schema */
> +     List       *alist;            /* "after list" of things to do after
> +                                  * creating the schema */
> + } CreateSchemaStmtContext;
> +
>   /* State shared by transformCreateStmt and its subroutines */
>   typedef struct
>   {
> *************** static Query *transformSelectStmt(ParseS
> *** 76,81 ****
> --- 94,101 ----
>   static Query *transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt);
>   static Node *transformSetOperationTree(ParseState *pstate, SelectStmt *stmt);
>   static Query *transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt);
> + static Query *transformCreateSchemaStmt(ParseState *pstate, CreateSchemaStmt *stmt,
> +                         List **extras_before, List **extras_after);
>   static Query *transformCreateStmt(ParseState *pstate, CreateStmt *stmt,
>                           List **extras_before, List **extras_after);
>   static Query *transformAlterTableStmt(ParseState *pstate, AlterTableStmt *stmt,
> *************** parse_analyze(Node *parseTree, ParseStat
> *** 130,135 ****
> --- 150,159 ----
>
>       query = transformStmt(pstate, parseTree, &extras_before, &extras_after);
>       release_pstate_resources(pstate);
> +
> +     /* Check if we are done processing this parseTree */
> +     if (query == NULL)
> +         return NIL;
>
>       while (extras_before != NIL)
>       {
> *************** transformStmt(ParseState *pstate, Node *
> *** 186,191 ****
> --- 210,225 ----
>               /*
>                * Non-optimizable statements
>                */
> +         case T_CreateSchemaStmt:
> +             /*
> +              * transformCreateSchemaStmt sets the parseTree nodeTag to
> +              * T_Invalid when its done; otherwise the parseTree
> +              * is modified to contain what still has to be done
> +              */
> +             result = transformCreateSchemaStmt(pstate, (CreateSchemaStmt *) parseTree,
> +                                     extras_before, extras_after);
> +             break;
> +
>           case T_CreateStmt:
>               result = transformCreateStmt(pstate, (CreateStmt *) parseTree,
>                                       extras_before, extras_after);
> *************** CreateIndexName(char *table_name, char *
> *** 671,676 ****
> --- 705,797 ----
>       }
>
>       return iname;
> + }
> +
> + /*
> +  * transformCreateSchemaStmt -
> +  *      transforms the "create schema" statement
> +  *
> +  *    Split the schema element list into individual commands and place
> +  *     them in the extras_after list in an order such that there is no
> +  *     forward references (e.g. GRANT to a table created after in the list).
> +  *      SQL92also allows constraints to make forward references, so thumb through
> +  *       the table columns and move forward references to a posterior alter table.
> +  */
> + static Query *
> + transformCreateSchemaStmt(ParseState *pstate, CreateSchemaStmt *stmt,
> +                     List **extras_before, List **extras_after)
> + {
> +     CreateSchemaStmtContext cxt;
> +     Query       *q;
> +     List       *elements;
> +
> +     cxt.stmtType = "CREATE SCHEMA";
> +     cxt.schemaname = stmt->schemaname;
> +     cxt.authid = stmt->authid;
> +     cxt.tables = NIL;
> +     cxt.views = NIL;
> +     cxt.grants = NIL;
> +     cxt.fwconstraints = NIL;
> +     cxt.alters = NIL;
> +     cxt.blist = NIL;
> +     cxt.alist = NIL;
> +
> +     /*
> +      * Run through each schema element in the schema element list.
> +      * Separate statements by type, and do preliminary analysis.
> +      */
> +     foreach(elements, stmt->schemaElts)
> +     {
> +         Node       *element = lfirst(elements);
> +
> +         switch (nodeTag(element))
> +         {
> +             case T_CreateStmt:
> +                 cxt.tables = lappend(cxt.tables, element);
> +                 break;
> +
> +             case T_ViewStmt:
> +                 cxt.views = lappend(cxt.views, element);
> +                 break;
> +
> +             case T_GrantStmt:
> +                 cxt.grants = lappend(cxt.grants, element);
> +                 break;
> +
> +             default:
> +                 elog(ERROR, "parser: unrecognized schema node (internal error)");
> +         }
> +     }
> +
> +     if (cxt.tables != NIL)
> +     {
> +         cxt.alist = nconc(cxt.alist, cxt.tables);
> +         stmt->schemaElts = cxt.views;
> +         stmt->schemaElts = nconc(stmt->schemaElts, cxt.grants);
> +     } else if (cxt.views != NIL)
> +     {
> +         /* Views have to be processed one at a time */
> +         cxt.alist = makeList1(lfirst(cxt.views));
> +         stmt->schemaElts = nconc(lnext(cxt.views), cxt.grants);
> +     } else if (cxt.grants != NIL)
> +     {
> +         cxt.alist = nconc(cxt.alist, cxt.grants);
> +         stmt->schemaElts = NIL;
> +     } else if (stmt->in_progress)
> +         /* ProcessUtility marks the T_CreateSchemaStmt as in progress so
> +            we do not try to create the schema again */
> +         return NULL;
> +
> +     /*
> +      * Output results.
> +      */
> +     q = makeNode(Query);
> +     q->commandType = CMD_UTILITY;
> +     q->utilityStmt = (Node *) stmt;
> +     *extras_before = nconc (*extras_before, cxt.blist);
> +     *extras_after = nconc (cxt.alist, *extras_after);
> +
> +     return q;
>   }
>
>   /*
> Index: src/backend/parser/gram.y
> ===================================================================
> RCS file: /projects/cvsroot/pgsql/src/backend/parser/gram.y,v
> retrieving revision 2.281
> diff -c -p -r2.281 gram.y
> *** src/backend/parser/gram.y    2002/02/25 03:37:14    2.281
> --- src/backend/parser/gram.y    2002/02/28 20:46:36
> *************** static void doNegateFloat(Value *v);
> *** 129,135 ****
>       InsertStmt            *istmt;
>   }
>
> ! %type <node>    stmt,
>           AlterGroupStmt, AlterSchemaStmt, AlterTableStmt, AlterUserStmt,
>           AnalyzeStmt,
>           ClosePortalStmt, ClusterStmt, CommentStmt, ConstraintsSetStmt,
> --- 129,135 ----
>       InsertStmt            *istmt;
>   }
>
> ! %type <node>    stmt, schema_stmt, nonschema_stmt,
>           AlterGroupStmt, AlterSchemaStmt, AlterTableStmt, AlterUserStmt,
>           AnalyzeStmt,
>           ClosePortalStmt, ClusterStmt, CommentStmt, ConstraintsSetStmt,
> *************** static void doNegateFloat(Value *v);
> *** 166,171 ****
> --- 166,174 ----
>   %type <list>    OptUserList
>   %type <defelt>    OptUserElem
>
> + %type <str>        OptSchemaName
> + %type <list>    OptSchemaEltList
> +
>   %type <boolean>    TriggerActionTime, TriggerForSpec, opt_trusted, opt_procedural
>   %type <str>        opt_lancompiler
>
> *************** static void doNegateFloat(Value *v);
> *** 176,182 ****
>
>   %type <str>        relation_name, copy_file_name, copy_delimiter, copy_null,
>           database_name, access_method_clause, access_method, attr_name,
> !         class, index_name, name, func_name, file_name
>
>   %type <str>        opt_id,
>           all_Op, MathOp, opt_name,
> --- 179,185 ----
>
>   %type <str>        relation_name, copy_file_name, copy_delimiter, copy_null,
>           database_name, access_method_clause, access_method, attr_name,
> !         class, index_name, name, func_name, file_name, qualified_name
>
>   %type <str>        opt_id,
>           all_Op, MathOp, opt_name,
> *************** stmtmulti:  stmtmulti ';' stmt
> *** 435,448 ****
>                       $$ = NIL;
>                   }
>           ;
>
> ! stmt :    AlterSchemaStmt
>           | AlterTableStmt
>           | AlterGroupStmt
>           | AlterUserStmt
>           | ClosePortalStmt
>           | CopyStmt
> -         | CreateStmt
>           | CreateAsStmt
>           | CreateSchemaStmt
>           | CreateGroupStmt
> --- 438,462 ----
>                       $$ = NIL;
>                   }
>           ;
> +
> + /*
> +  *    schema_stmt are the ones that can show up inside a CREATE SCHEMA
> +  *  statement (in addition to by themselves).
> +  */
> + stmt:    schema_stmt | nonschema_stmt
> +         ;
>
> ! schema_stmt : CreateStmt
> !         | GrantStmt
> !         | ViewStmt
> !         ;
> !
> ! nonschema_stmt :    AlterSchemaStmt
>           | AlterTableStmt
>           | AlterGroupStmt
>           | AlterUserStmt
>           | ClosePortalStmt
>           | CopyStmt
>           | CreateAsStmt
>           | CreateSchemaStmt
>           | CreateGroupStmt
> *************** stmt :    AlterSchemaStmt
> *** 462,468 ****
>           | DropUserStmt
>           | ExplainStmt
>           | FetchStmt
> -         | GrantStmt
>           | IndexStmt
>           | ListenStmt
>           | UnlistenStmt
> --- 476,481 ----
> *************** stmt :    AlterSchemaStmt
> *** 478,484 ****
>           | OptimizableStmt
>           | RuleStmt
>           | TransactionStmt
> -         | ViewStmt
>           | LoadStmt
>           | CreatedbStmt
>           | DropdbStmt
> --- 491,496 ----
> *************** DropGroupStmt: DROP GROUP UserId
> *** 729,743 ****
>    *
>    *****************************************************************************/
>
> ! CreateSchemaStmt:  CREATE SCHEMA UserId
>                   {
> !                     /* for now, just make this the same as CREATE DATABASE */
> !                     CreatedbStmt *n = makeNode(CreatedbStmt);
> !                     n->dbname = $3;
> !                     n->dbowner = NULL;
> !                     n->dbpath = NULL;
> !                     n->dbtemplate = NULL;
> !                     n->encoding = -1;
>                       $$ = (Node *)n;
>                   }
>           ;
> --- 741,767 ----
>    *
>    *****************************************************************************/
>
> ! CreateSchemaStmt:  CREATE SCHEMA OptSchemaName AUTHORIZATION UserId OptSchemaEltList
>                   {
> !                     CreateSchemaStmt *n = makeNode(CreateSchemaStmt);
> !                     /* One can omit the schema name or the authorization id... */
> !                     if ($3 != NULL)
> !                         n->schemaname = $3;
> !                     else
> !                         n->schemaname = $5;
> !                     n->authid = $5;
> !                     n->schemaElts = $6;
> !                     n->in_progress = false;
> !                     $$ = (Node *)n;
> !                 }
> !         | CREATE SCHEMA ColId OptSchemaEltList
> !                 {
> !                     CreateSchemaStmt *n = makeNode(CreateSchemaStmt);
> !                     /* ...but not both */
> !                     n->schemaname = $3;
> !                     n->authid = NULL;
> !                     n->schemaElts = $4;
> !                     n->in_progress = false;
>                       $$ = (Node *)n;
>                   }
>           ;
> *************** AlterSchemaStmt:  ALTER SCHEMA UserId
> *** 750,760 ****
>
>   DropSchemaStmt:  DROP SCHEMA UserId
>                   {
> !                     DropdbStmt *n = makeNode(DropdbStmt);
> !                     n->dbname = $3;
> !                     $$ = (Node *)n;
>                   }
>
>
>   /*****************************************************************************
>    *
> --- 774,794 ----
>
>   DropSchemaStmt:  DROP SCHEMA UserId
>                   {
> !                     elog(ERROR, "DROP SCHEMA not yet supported");
>                   }
>
> + OptSchemaName: ColId                                { $$ = $1 }
> +         | /* EMPTY */                                { $$ = NULL; }
> +         ;
> +
> + OptSchemaEltList: OptSchemaEltList schema_stmt
> +         {    if ($1 == NIL)
> +                 $$ = makeList1($2);
> +             else
> +                 $$ = lappend($1, $2);
> +         }
> +         | /* EMPTY */                                { $$ = NIL; }
> +         ;
>
>   /*****************************************************************************
>    *
> *************** copy_null:      WITH NULL_P AS Sconst
> *** 1253,1259 ****
>    *
>    *****************************************************************************/
>
> ! CreateStmt:  CREATE OptTemp TABLE relation_name '(' OptTableElementList ')' OptInherit OptWithOids
>                   {
>                       CreateStmt *n = makeNode(CreateStmt);
>                       n->relname = $4;
> --- 1287,1293 ----
>    *
>    *****************************************************************************/
>
> ! CreateStmt:  CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')' OptInherit OptWithOids
>                   {
>                       CreateStmt *n = makeNode(CreateStmt);
>                       n->relname = $4;
> *************** OptWithOids:  WITH OIDS                        { $$ = TRUE
> *** 1616,1622 ****
>    * SELECT ... INTO.
>    */
>
> ! CreateAsStmt:  CREATE OptTemp TABLE relation_name OptCreateAs AS SelectStmt
>                   {
>                       /*
>                        * When the SelectStmt is a set-operation tree, we must
> --- 1650,1656 ----
>    * SELECT ... INTO.
>    */
>
> ! CreateAsStmt:  CREATE OptTemp TABLE qualified_name OptCreateAs AS SelectStmt
>                   {
>                       /*
>                        * When the SelectStmt is a set-operation tree, we must
> *************** opt_chain: AND NO CHAIN
> *** 3010,3016 ****
>    *
>    *****************************************************************************/
>
> ! ViewStmt:  CREATE VIEW name opt_column_list AS SelectStmt
>                   {
>                       ViewStmt *n = makeNode(ViewStmt);
>                       n->viewname = $3;
> --- 3044,3050 ----
>    *
>    *****************************************************************************/
>
> ! ViewStmt:  CREATE VIEW qualified_name opt_column_list AS SelectStmt
>                   {
>                       ViewStmt *n = makeNode(ViewStmt);
>                       n->viewname = $3;
> *************** join_qual:  USING '(' name_list ')'                {
> *** 4049,4055 ****
>           ;
>
>
> ! relation_expr:    relation_name
>                   {
>                       /* default inheritance */
>                       $$ = makeNode(RangeVar);
> --- 4083,4089 ----
>           ;
>
>
> ! relation_expr:    qualified_name
>                   {
>                       /* default inheritance */
>                       $$ = makeNode(RangeVar);
> *************** relation_expr:    relation_name
> *** 4057,4063 ****
>                       $$->inhOpt = INH_DEFAULT;
>                       $$->name = NULL;
>                   }
> !         | relation_name '*'
>                   {
>                       /* inheritance query */
>                       $$ = makeNode(RangeVar);
> --- 4091,4097 ----
>                       $$->inhOpt = INH_DEFAULT;
>                       $$->name = NULL;
>                   }
> !         | qualified_name '*'
>                   {
>                       /* inheritance query */
>                       $$ = makeNode(RangeVar);
> *************** relation_expr:    relation_name
> *** 4065,4071 ****
>                       $$->inhOpt = INH_YES;
>                       $$->name = NULL;
>                   }
> !         | ONLY relation_name
>                   {
>                       /* no inheritance */
>                       $$ = makeNode(RangeVar);
> --- 4099,4105 ----
>                       $$->inhOpt = INH_YES;
>                       $$->name = NULL;
>                   }
> !         | ONLY qualified_name
>                   {
>                       /* no inheritance */
>                       $$ = makeNode(RangeVar);
> *************** relation_name:    SpecialRuleRelation
> *** 5611,5616 ****
> --- 5645,5660 ----
>                   }
>           ;
>
> + qualified_name: ColId
> +                 {
> +                     $$ = $1;
> +                 }
> +         | ColId '.' ColId
> +                 {
> +                     $$ = $3;
> +                 }
> +         ;
> +
>   name:                    ColId            { $$ = $1; };
>   database_name:            ColId            { $$ = $1; };
>   access_method:            ColId            { $$ = $1; };
> *************** unreserved_keyword:
> *** 5791,5797 ****
>           | AGGREGATE                        { $$ = "aggregate"; }
>           | ALTER                            { $$ = "alter"; }
>           | AT                            { $$ = "at"; }
> -         | AUTHORIZATION                    { $$ = "authorization"; }
>           | BACKWARD                        { $$ = "backward"; }
>           | BEFORE                        { $$ = "before"; }
>           | BEGIN_TRANS                    { $$ = "begin"; }
> --- 5835,5840 ----
> *************** unreserved_keyword:
> *** 5808,5814 ****
>           | COMMITTED                        { $$ = "committed"; }
>           | CONSTRAINTS                    { $$ = "constraints"; }
>           | COPY                            { $$ = "copy"; }
> -         | CREATE                        { $$ = "create"; }
>           | CREATEDB                        { $$ = "createdb"; }
>           | CREATEUSER                    { $$ = "createuser"; }
>           | CURSOR                        { $$ = "cursor"; }
> --- 5851,5856 ----
> *************** unreserved_keyword:
> *** 5833,5839 ****
>           | FORWARD                        { $$ = "forward"; }
>           | FUNCTION                        { $$ = "function"; }
>           | GLOBAL                        { $$ = "global"; }
> -         | GRANT                            { $$ = "grant"; }
>           | HANDLER                        { $$ = "handler"; }
>           | HOUR_P                        { $$ = "hour"; }
>           | IMMEDIATE                        { $$ = "immediate"; }
> --- 5875,5880 ----
> *************** unreserved_keyword:
> *** 5911,5917 ****
>           | STDIN                            { $$ = "stdin"; }
>           | STDOUT                        { $$ = "stdout"; }
>           | SYSID                            { $$ = "sysid"; }
> -         | TEMP                            { $$ = "temp"; }
>           | TEMPLATE                        { $$ = "template"; }
>           | TEMPORARY                        { $$ = "temporary"; }
>           | TOAST                            { $$ = "toast"; }
> --- 5952,5957 ----
> *************** col_name_keyword:
> *** 5967,5972 ****
> --- 6007,6013 ----
>           | POSITION                        { $$ = "position"; }
>           | SETOF                            { $$ = "setof"; }
>           | SUBSTRING                        { $$ = "substring"; }
> +         | TEMP                            { $$ = "temp"; }
>           | TIME                            { $$ = "time"; }
>           | TIMESTAMP                        { $$ = "timestamp"; }
>           | TRIM                            { $$ = "trim"; }
> *************** col_name_keyword:
> *** 5984,5990 ****
>    *  - thomas 2000-11-28
>    */
>   func_name_keyword:
> !           BETWEEN                        { $$ = "between"; }
>           | BINARY                        { $$ = "binary"; }
>           | CROSS                            { $$ = "cross"; }
>           | FREEZE                        { $$ = "freeze"; }
> --- 6025,6032 ----
>    *  - thomas 2000-11-28
>    */
>   func_name_keyword:
> !           AUTHORIZATION                    { $$ = "authorization"; }
> !         | BETWEEN                        { $$ = "between"; }
>           | BINARY                        { $$ = "binary"; }
>           | CROSS                            { $$ = "cross"; }
>           | FREEZE                        { $$ = "freeze"; }
> *************** reserved_keyword:
> *** 6027,6032 ****
> --- 6069,6075 ----
>           | COLLATE                        { $$ = "collate"; }
>           | COLUMN                        { $$ = "column"; }
>           | CONSTRAINT                    { $$ = "constraint"; }
> +         | CREATE                        { $$ = "create"; }
>           | CURRENT_DATE                    { $$ = "current_date"; }
>           | CURRENT_TIME                    { $$ = "current_time"; }
>           | CURRENT_TIMESTAMP                { $$ = "current_timestamp"; }
> *************** reserved_keyword:
> *** 6043,6048 ****
> --- 6086,6092 ----
>           | FOR                            { $$ = "for"; }
>           | FOREIGN                        { $$ = "foreign"; }
>           | FROM                            { $$ = "from"; }
> +         | GRANT                            { $$ = "grant"; }
>           | GROUP                            { $$ = "group"; }
>           | HAVING                        { $$ = "having"; }
>           | INITIALLY                        { $$ = "initially"; }
> Index: src/backend/tcop/utility.c
> ===================================================================
> RCS file: /projects/cvsroot/pgsql/src/backend/tcop/utility.c,v
> retrieving revision 1.127
> diff -c -p -r1.127 utility.c
> *** src/backend/tcop/utility.c    2002/02/26 22:47:09    1.127
> --- src/backend/tcop/utility.c    2002/02/28 20:46:36
> *************** ProcessUtility(Node *parsetree,
> *** 220,225 ****
> --- 220,240 ----
>                * manipulation ********************************
>                *
>                */
> +         case T_CreateSchemaStmt:
> +             {
> +                 CreateSchemaStmt  *stmt = (CreateSchemaStmt *) parsetree;
> +                 if (stmt->in_progress)
> +                     break;  /* Has created the schema already in a previous pass */
> +                 stmt->in_progress = true;
> +                 elog(NOTICE, "Schema %s owned by %s will be created",
> +                     stmt->schemaname, stmt->authid);
> +                 /*
> +                  * Let commands in the schema-element-list know about the schema
> +                  */
> +                 CommandCounterIncrement();
> +             }
> +             break;
> +
>           case T_CreateStmt:
>               DefineRelation((CreateStmt *) parsetree, RELKIND_RELATION);
>
> Index: src/include/nodes/parsenodes.h
> ===================================================================
> RCS file: /projects/cvsroot/pgsql/src/include/nodes/parsenodes.h,v
> retrieving revision 1.154
> diff -c -p -r1.154 parsenodes.h
> *** src/include/nodes/parsenodes.h    2002/02/26 22:47:10    1.154
> --- src/include/nodes/parsenodes.h    2002/02/28 20:46:38
> *************** typedef enum InhOption
> *** 110,115 ****
> --- 110,132 ----
>    *****************************************************************************/
>
>   /* ----------------------
> +  *        Create Schema Statement
> +  *
> +  * NOTE: The schemaElts list contain several of the other nodes before
> +  * parse analysis.  These become independent nodes after that and the
> +  * list is empty.
> +  * ----------------------
> +  */
> + typedef struct CreateSchemaStmt
> + {
> +     NodeTag        type;
> +     char       *schemaname;        /* the name of the schema to create */
> +     char       *authid;            /* the owner of the created schema */
> +     List       *schemaElts;        /* column definitions (list of ColumnDef) */
> +     bool        in_progress;    /* used by analyze */
> + } CreateSchemaStmt;
> +
> + /* ----------------------
>    *    Alter Table
>    *
>    * The fields are used in different ways by the different variants of

>
> ---------------------------(end of broadcast)---------------------------
> TIP 1: subscribe and unsubscribe commands go to majordomo@postgresql.org

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026

Re: Adds the parsing of a CREATE SCHEMA statement

From
Tom Lane
Date:
Bruce Momjian <pgman@candle.pha.pa.us> writes:
> I assume you do _not_ want this applied as is is part of Tom's schema
> work, right?

Might as well hold off.  The schema stuff is currently happening in a
private CVS branch at Red Hat, and we're gonna have to figure out how to
merge with the project CVS when it's far enough along to justify it.

Fernando has been trying to send in bite-size pieces to keep the
branches from getting far apart, but I'm not sure if it's worth the
trouble ...

            regards, tom lane