Thread: Allows for commands to be processed iteractively

Allows for commands to be processed iteractively

From
Fernando Nasser
Date:
ChangeLog:

        Allows for some commands to be processed iteractively.
        This is necessary for CREATE SCHEMA
        statements because one has to create the base tables before
being able
        to create the views, and those before being able to grant, etc.


--
Fernando Nasser
Red Hat Canada Ltd.                     E-Mail:  fnasser@redhat.com
2323 Yonge Street, Suite #300
Toronto, Ontario   M4P 2C9Index: src/include/nodes/nodes.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/nodes/nodes.h,v
retrieving revision 1.97
diff -c -p -r1.97 nodes.h
*** src/include/nodes/nodes.h    2002/02/18 23:11:41    1.97
--- src/include/nodes/nodes.h    2002/02/28 20:46:38
*************** typedef enum NodeTag
*** 194,199 ****
--- 194,200 ----
      T_DropGroupStmt,
      T_ReindexStmt,
      T_CheckPointStmt,
+     T_CreateSchemaStmt,

      T_A_Expr = 700,
      T_Attr,
Index: src/backend/tcop/postgres.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/tcop/postgres.c,v
retrieving revision 1.250
diff -c -p -r1.250 postgres.c
*** src/backend/tcop/postgres.c    2002/02/27 23:16:07    1.250
--- src/backend/tcop/postgres.c    2002/02/28 20:46:36
*************** static int    SocketBackend(StringInfo inBu
*** 122,127 ****
--- 122,132 ----
  static int    ReadCommand(StringInfo inBuf);
  static List *pg_parse_query(char *query_string, Oid *typev, int nargs);
  static List *pg_analyze_and_rewrite(Node *parsetree);
+ static bool pg_process_one_parsetree(Node *parsetree,
+                     char *query_string,
+                     const char **commandTag,
+                     CommandDest dest,
+                     MemoryContext parse_context);
  static void start_xact_command(void);
  static void finish_xact_command(void);
  static void SigHupHandler(SIGNAL_ARGS);
*************** pg_parse_and_rewrite(char *query_string,
*** 344,351 ****
      {
          Node       *parsetree = (Node *) lfirst(list_item);

!         querytree_list = nconc(querytree_list,
!                                pg_analyze_and_rewrite(parsetree));
      }

      return querytree_list;
--- 349,358 ----
      {
          Node       *parsetree = (Node *) lfirst(list_item);

!         /* Should we handle CREATE SCHEMA in functions? */
!         if (nodeTag(parsetree) == T_CreateSchemaStmt)
!             elog(ERROR, "SQL functions cannot have CREATE SCHEMA statements");
!         querytree_list = nconc(querytree_list, pg_analyze_and_rewrite(parsetree));
      }

      return querytree_list;
*************** pg_analyze_and_rewrite(Node *parsetree)
*** 407,412 ****
--- 414,423 ----
          ResetUsage();

      querytree_list = parse_analyze(parsetree, NULL);
+
+     /* Check if we are done processing this parsetree */
+     if (querytree_list == NIL)
+         return NIL;

      if (Show_parser_stats)
      {
*************** pg_exec_query_string(char *query_string,
*** 638,646 ****
          Node       *parsetree = (Node *) lfirst(parsetree_item);
          bool        isTransactionStmt;
          const char *commandTag;
-         char        completionTag[COMPLETION_TAG_BUFSIZE];
-         List       *querytree_list,
-                    *querytree_item;

          /* Transaction control statements need some special handling */
          isTransactionStmt = IsA(parsetree, TransactionStmt);
--- 649,654 ----
*************** pg_exec_query_string(char *query_string,
*** 718,725 ****
          CHECK_FOR_INTERRUPTS();

          /*
!          * OK to analyze and rewrite this query.
           *
           * Switch to appropriate context for constructing querytrees (again,
           * these must outlive the execution context).
           */
--- 726,817 ----
          CHECK_FOR_INTERRUPTS();

          /*
!          * OK to process this query.
           *
+          */
+         xact_started = pg_process_one_parsetree(parsetree, query_string,
+                                         &commandTag, dest, parse_context);
+
+         /*
+          * If this is the last parsetree of the query string, close down
+          * transaction statement before reporting command-complete.  This is
+          * so that any end-of-transaction errors are reported before the
+          * command-complete message is issued, to avoid confusing clients
+          * who will expect either a command-complete message or an error,
+          * not one and then the other.  But for compatibility with
+          * historical Postgres behavior, we do not force a transaction
+          * boundary between queries appearing in a single query string.
+          */
+         if (lnext(parsetree_item) == NIL && xact_started)
+         {
+             finish_xact_command();
+             xact_started = false;
+         }
+
+         /*
+          * It is possible that the original query was removed due to
+          * a DO INSTEAD rewrite rule.  In that case we will still have
+          * the default completion tag, which is fine for most purposes,
+          * but it may confuse clients if it's INSERT/UPDATE/DELETE.
+          * Clients expect those tags to have counts after them (cf.
+          * ProcessQuery).
+          */
+         if (strcmp(commandTag, "INSERT") == 0)
+             commandTag = "INSERT 0 0";
+         else if (strcmp(commandTag, "UPDATE") == 0)
+             commandTag = "UPDATE 0";
+         else if (strcmp(commandTag, "DELETE") == 0)
+             commandTag = "DELETE 0";
+
+         /*
+          * Tell client that we're done with this query.  Note we emit
+          * exactly one EndCommand report for each raw parsetree, thus
+          * one for each SQL command the client sent, regardless of
+          * rewriting.  (But a command aborted by error will not send
+          * an EndCommand report at all.)
+          */
+         EndCommand(commandTag, dest);
+     }                            /* end loop over parsetrees */
+
+     /*
+      * Close down transaction statement, if one is open.
+      * (Note that this will only happen if the querystring was empty.)
+      */
+     if (xact_started)
+         finish_xact_command();
+
+     debug_query_string = NULL;    /* used by pgmonitor */
+ }
+
+ /*
+  * Helper for pg_process_query_string
+  *
+  * Process a single parsetree.  Assumes that it is called
+  * with a transaction started
+  *
+  * Returns true if we still have a transaction.
+  */
+ static bool
+ pg_process_one_parsetree(Node *parsetree,
+                     char *query_string,
+                     const char **commandTag,
+                     CommandDest dest,    /* where results should go */
+                     MemoryContext parse_context)        /* context for
+                                                          * parsetrees */
+ {
+     static char        completionTag[COMPLETION_TAG_BUFSIZE];
+     bool        xact_closed = false;
+     MemoryContext oldcontext;
+     List       *querytree_list,
+                *querytree_item;
+     bool        isTransactionStmt;
+
+     /* Transaction control statements need some special handling */
+     isTransactionStmt = IsA(parsetree, TransactionStmt);
+
+     do
+     {
+         /*
           * Switch to appropriate context for constructing querytrees (again,
           * these must outlive the execution context).
           */
*************** pg_exec_query_string(char *query_string,
*** 731,736 ****
--- 823,832 ----
           * Switch back to execution context for planning and execution.
           */
          MemoryContextSwitchTo(oldcontext);
+
+         /* Check if we are done processing this parseTree */
+         if (querytree_list == NIL)
+             return (!xact_closed);

          /*
           * Inner loop handles the individual queries generated from a
*************** pg_exec_query_string(char *query_string,
*** 741,750 ****
              Query       *querytree = (Query *) lfirst(querytree_item);

              /* Make sure we are in a transaction command */
!             if (!xact_started)
              {
                  start_xact_command();
!                 xact_started = true;
              }

              /*
--- 837,846 ----
              Query       *querytree = (Query *) lfirst(querytree_item);

              /* Make sure we are in a transaction command */
!             if (xact_closed)
              {
                  start_xact_command();
!                 xact_closed = false;
              }

              /*
*************** pg_exec_query_string(char *query_string,
*** 769,775 ****
                      ProcessUtility(querytree->utilityStmt, dest,
                                     completionTag);
                      if (completionTag[0])
!                         commandTag = completionTag;
                  }
                  else
                  {
--- 865,871 ----
                      ProcessUtility(querytree->utilityStmt, dest,
                                     completionTag);
                      if (completionTag[0])
!                         *commandTag = completionTag;
                  }
                  else
                  {
*************** pg_exec_query_string(char *query_string,
*** 812,818 ****
                      {
                          /* original stmt can override default tag string */
                          ProcessQuery(querytree, plan, dest, completionTag);
!                         commandTag = completionTag;
                      }
                      else
                      {
--- 908,914 ----
                      {
                          /* original stmt can override default tag string */
                          ProcessQuery(querytree, plan, dest, completionTag);
!                         *commandTag = completionTag;
                      }
                      else
                      {
*************** pg_exec_query_string(char *query_string,
*** 853,913 ****
              if (isTransactionStmt)
              {
                  finish_xact_command();
!                 xact_started = false;
              }

          }                        /* end loop over queries generated from a
                                   * parsetree */

!         /*
!          * If this is the last parsetree of the query string, close down
!          * transaction statement before reporting command-complete.  This is
!          * so that any end-of-transaction errors are reported before the
!          * command-complete message is issued, to avoid confusing clients
!          * who will expect either a command-complete message or an error,
!          * not one and then the other.  But for compatibility with
!          * historical Postgres behavior, we do not force a transaction
!          * boundary between queries appearing in a single query string.
!          */
!         if (lnext(parsetree_item) == NIL && xact_started)
!         {
!             finish_xact_command();
!             xact_started = false;
!         }
!
!         /*
!          * It is possible that the original query was removed due to
!          * a DO INSTEAD rewrite rule.  In that case we will still have
!          * the default completion tag, which is fine for most purposes,
!          * but it may confuse clients if it's INSERT/UPDATE/DELETE.
!          * Clients expect those tags to have counts after them (cf.
!          * ProcessQuery).
!          */
!         if (strcmp(commandTag, "INSERT") == 0)
!             commandTag = "INSERT 0 0";
!         else if (strcmp(commandTag, "UPDATE") == 0)
!             commandTag = "UPDATE 0";
!         else if (strcmp(commandTag, "DELETE") == 0)
!             commandTag = "DELETE 0";
!
!         /*
!          * Tell client that we're done with this query.  Note we emit
!          * exactly one EndCommand report for each raw parsetree, thus
!          * one for each SQL command the client sent, regardless of
!          * rewriting.  (But a command aborted by error will not send
!          * an EndCommand report at all.)
!          */
!         EndCommand(commandTag, dest);
!     }                            /* end loop over parsetrees */
!
!     /*
!      * Close down transaction statement, if one is open.
!      * (Note that this will only happen if the querystring was empty.)
!      */
!     if (xact_started)
!         finish_xact_command();
!
!     debug_query_string = NULL;    /* used by pgmonitor */
  }

  /*
--- 949,962 ----
              if (isTransactionStmt)
              {
                  finish_xact_command();
!                 xact_closed = true;
              }

          }                        /* end loop over queries generated from a
                                   * parsetree */
+     } while (nodeTag(parsetree) == T_CreateSchemaStmt);

!     return (!xact_closed);
  }

  /*
*************** CreateCommandTag(Node *parsetree)
*** 2184,2189 ****
--- 2233,2242 ----
                  FetchStmt  *stmt = (FetchStmt *) parsetree;
                  tag = (stmt->ismove) ? "MOVE" : "FETCH";
              }
+             break;
+
+         case T_CreateSchemaStmt:
+             tag = "CREATE";
              break;

          case T_CreateStmt:

Re: Allows for commands to be processed iteractively

From
Fernando Nasser
Date:
Tom Lane wrote:
>
> Fernando Nasser <fnasser@redhat.com> writes:
> >         Allows for some commands to be processed iteractively.
>
> This patch seems to be missing quite a lot, like the node struct
> definition and backend/nodes/*.c support for CreateSchemaStmt.
> Perhaps your intention was not to introduce that yet, but in that
> case I'd suggest not adding any sign of it in this patch.
>
> More to the point, though, what is the reason for restructuring
> pg_exec_query_string this way?  The patch doesn't make any sense
> to me as presented.  I should think that any effort needed for
> CREATE SCHEMA would be over in parser/analyze.c; restructuring
> pg_exec_query_string isn't going to help.
>

Please see the follow-up patch and things get more clear.

I broke the patch in two to make it easier to access the impact
of each part (I can glue both together again, if desired).

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

Re: Allows for commands to be processed iteractively

From
Tom Lane
Date:
Fernando Nasser <fnasser@redhat.com> writes:
>         Allows for some commands to be processed iteractively.

This patch seems to be missing quite a lot, like the node struct
definition and backend/nodes/*.c support for CreateSchemaStmt.
Perhaps your intention was not to introduce that yet, but in that
case I'd suggest not adding any sign of it in this patch.

More to the point, though, what is the reason for restructuring
pg_exec_query_string this way?  The patch doesn't make any sense
to me as presented.  I should think that any effort needed for
CREATE SCHEMA would be over in parser/analyze.c; restructuring
pg_exec_query_string isn't going to help.

            regards, tom lane