Fix issuing of multiple command completions per command - Mailing list pgsql-patches

(Please note that "[PATCHES] Allow arbitrary levels of
analyze/rewriting"
must be applied before this patch)

This patch prevents the issue of multiple command completions
when queries are rewritten into a sequence queries by analyze/rewrite.
Currently the front ends are receiving many;  libpq just uses the last
one received so that is why we see only one response in psql, for
instance.

It fixes a bug where the user receives a bogus completion message
for queries that have been turned into a sequence of queries where
the last one has a different completion tag.

It also prevents command-completions to be generated by utility commands
that are inside SQL-functions.

It also fixes some misplaced calls to set ps_status.

Furthermore, these changes made possible to reduce the number of
times ps_status is set (a request from Tom Lane). This is done by
default but it is still possible to set a compiler flag and have
it generate more calls as it does today (one for each query produced
by the rewriting of the original query).


Here is basically what is done:

The completion is sent by EndCommand().  This call is used OK by
plannable queries and is necessary there for telling that the data
sent to a backend has come to an end.  Utilities, however, don't
send any data (except FETCH) and may be rewritten into a series of
other utility queries.  The changes consolidate the calls to
EndCommand() for utility queries and let the plannable ones
handle it pairwise with BeginCommand() (which is not used by
utility queries).


ChangeLog:

        * src/backend/commands/command.c (PerformPortalFetch): Send
        command completion so that fe knows we are done with sending
data.
        * src/backend/commands/explain.c (ExplainOneQuery): Set
ps_status
        to EXPLAIN or SELECT (for the EXPLAIN ANALYZE case).
        * src/backend/executor/functions.c (postquel_getnext): Do not
send
        command completion messages for utilities inside SQL-functions
        (one will be sent for the command that invoked the function).
        * src/backend/executor/spi.c (_SPI_execute, _SPI_execute_plan):
Add
        comments.
        * src/backend/tcop/postgres.c (pg_exec_query_string):
        Do not send a command completion message or set the ps_status
for
        each utility query that results for the rewriting of a command;
        just send one for the original command.  Let plannable queries
take
        care of their own completion.
        (CreateCommandTag): New function.  Create a command completion
tag
        based on the parse tree node (rather than on an already/analyzed
        query node).
        * src/backend/tcop/utility.c (ProcessUtility): Do
        not meddle with ps_status or command completion in this
function.
        * src/backend/tcop/pquery.c (ProcessQuery): Let the caller set
        ps_status.





--
Fernando Nasser
Red Hat Canada Ltd.                     E-Mail:  fnasser@redhat.com
2323 Yonge Street, Suite #300
Toronto, Ontario   M4P 2C9Index: src/backend/commands/command.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/commands/command.c,v
retrieving revision 1.152
diff -c -p -r1.152 command.c
*** src/backend/commands/command.c    2002/01/03 23:19:30    1.152
--- src/backend/commands/command.c    2002/02/14 10:49:18
*************** PerformPortalFetch(char *name,
*** 215,231 ****
      }

      /*
       * Clean up and switch back to old context.
       */
      if (temp_desc)
          pfree(queryDesc);

      MemoryContextSwitchTo(oldcontext);
-
-     /*
-      * Note: the "end-of-command" tag is returned by higher-level utility
-      * code
-      */
  }

  /* --------------------------------
--- 215,231 ----
      }

      /*
+      * tell fe/be or whatever that we're done sending the data
+      */
+     EndCommand(tag, queryDesc->dest);
+
+     /*
       * Clean up and switch back to old context.
       */
      if (temp_desc)
          pfree(queryDesc);

      MemoryContextSwitchTo(oldcontext);
  }

  /* --------------------------------
Index: src/backend/commands/explain.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/commands/explain.c,v
retrieving revision 1.67
diff -c -p -r1.67 explain.c
*** src/backend/commands/explain.c    2001/10/25 05:49:25    1.67
--- src/backend/commands/explain.c    2002/02/14 10:49:18
***************
*** 19,24 ****
--- 19,25 ----
  #include "parser/parsetree.h"
  #include "rewrite/rewriteHandler.h"
  #include "tcop/pquery.h"
+ #include "utils/ps_status.h"
  #include "utils/relcache.h"

  typedef struct ExplainState
*************** ExplainOneQuery(Query *query, bool verbo
*** 113,118 ****
--- 114,121 ----
          struct timeval starttime;
          struct timeval endtime;

+         set_ps_display("SELECT");
+
          /*
           * Set up the instrumentation for the top node. This will cascade
           * during plan initialisation
*************** ExplainOneQuery(Query *query, bool verbo
*** 133,138 ****
--- 136,143 ----
          }
          totaltime = (double) endtime.tv_sec +
              (double) endtime.tv_usec / 1000000.0;
+
+         set_ps_display("EXPLAIN");
      }

      es = (ExplainState *) palloc(sizeof(ExplainState));
Index: src/backend/executor/functions.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/executor/functions.c,v
retrieving revision 1.47
diff -c -p -r1.47 functions.c
*** src/backend/executor/functions.c    2001/10/28 06:25:43    1.47
--- src/backend/executor/functions.c    2002/02/14 10:49:18
*************** postquel_getnext(execution_state *es)
*** 276,281 ****
--- 276,283 ----
           * Process a utility command. (create, destroy...)    DZ - 30-8-1996
           */
          ProcessUtility(es->qd->parsetree->utilityStmt, es->qd->dest);
+         /* We should not call EndCommand() here as we are inside a function
+          * call and command-complete reports should not be issued. */
          if (!LAST_POSTQUEL_COMMAND(es))
              CommandCounterIncrement();
          return (TupleTableSlot *) NULL;
Index: src/backend/executor/spi.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/executor/spi.c,v
retrieving revision 1.64
diff -c -p -r1.64 spi.c
*** src/backend/executor/spi.c    2002/01/03 20:30:47    1.64
--- src/backend/executor/spi.c    2002/02/14 10:49:18
*************** _SPI_execute(char *src, int tcount, _SPI
*** 1010,1015 ****
--- 1010,1017 ----
              if (plan == NULL)
              {
                  ProcessUtility(queryTree->utilityStmt, None);
+                 /* We don't need to call EndCommand() as we don't want to
+                  * send anything (dest = None) */
                  if (!islastquery)
                      CommandCounterIncrement();
                  else
*************** _SPI_execute_plan(_SPI_plan *plan, Datum
*** 1084,1089 ****
--- 1086,1093 ----
          if (queryTree->commandType == CMD_UTILITY)
          {
              ProcessUtility(queryTree->utilityStmt, None);
+             /* We don't need to call EndCommand() as we don't want to
+              * send anything (dest = None) */
              if (!islastquery)
                  CommandCounterIncrement();
              else
Index: src/backend/parser/analyze.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/parser/analyze.c,v
retrieving revision 1.213
diff -c -p -r1.213 analyze.c
*** src/backend/parser/analyze.c    2002/01/03 23:21:31    1.213
--- src/backend/parser/analyze.c    2002/02/14 10:49:18
*************** typedef struct
*** 64,80 ****
  } CreateStmtContext;


! static Query *transformStmt(ParseState *pstate, Node *stmt);
  static Query *transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt);
! static Query *transformInsertStmt(ParseState *pstate, InsertStmt *stmt);
  static Query *transformIndexStmt(ParseState *pstate, IndexStmt *stmt);
! static Query *transformRuleStmt(ParseState *query, RuleStmt *stmt);
  static Query *transformSelectStmt(ParseState *pstate, SelectStmt *stmt);
  static Query *transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt);
  static Node *transformSetOperationTree(ParseState *pstate, SelectStmt *stmt);
  static Query *transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt);
! static Query *transformCreateStmt(ParseState *pstate, CreateStmt *stmt);
! static Query *transformAlterTableStmt(ParseState *pstate, AlterTableStmt *stmt);
  static void transformColumnDefinition(ParseState *pstate,
                            CreateStmtContext *cxt,
                            ColumnDef *column);
--- 64,85 ----
  } CreateStmtContext;


! static Query *transformStmt(ParseState *pstate, Node *stmt,
!                         List **extras_before, List **extras_after);
  static Query *transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt);
! static Query *transformInsertStmt(ParseState *pstate, InsertStmt *stmt,
!                         List **extras_before, List **extras_after);
  static Query *transformIndexStmt(ParseState *pstate, IndexStmt *stmt);
! static Query *transformRuleStmt(ParseState *query, RuleStmt *stmt,
!                         List **extras_before, List **extras_after);
  static Query *transformSelectStmt(ParseState *pstate, SelectStmt *stmt);
  static Query *transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt);
  static Node *transformSetOperationTree(ParseState *pstate, SelectStmt *stmt);
  static Query *transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt);
! static Query *transformCreateStmt(ParseState *pstate, CreateStmt *stmt,
!                         List **extras_before, List **extras_after);
! static Query *transformAlterTableStmt(ParseState *pstate, AlterTableStmt *stmt,
!                         List **extras_before, List **extras_after);
  static void transformColumnDefinition(ParseState *pstate,
                            CreateStmtContext *cxt,
                            ColumnDef *column);
*************** static Oid    transformFkeyGetColType(Creat
*** 101,109 ****
  static void release_pstate_resources(ParseState *pstate);
  static FromExpr *makeFromExpr(List *fromlist, Node *quals);

- /* kluge to return extra info from transformCreateStmt() */
- static List *extras_before;
- static List *extras_after;


  /*
--- 106,111 ----
*************** parse_analyze(Node *parseTree, ParseStat
*** 121,137 ****
      List       *result = NIL;
      ParseState *pstate = make_parsestate(parentParseState);
      Query       *query;

!     extras_before = extras_after = NIL;
!
!     query = transformStmt(pstate, parseTree);
      release_pstate_resources(pstate);
!
      while (extras_before != NIL)
      {
!         result = lappend(result,
!                          transformStmt(pstate, lfirst(extras_before)));
!         release_pstate_resources(pstate);
          extras_before = lnext(extras_before);
      }

--- 123,138 ----
      List       *result = NIL;
      ParseState *pstate = make_parsestate(parentParseState);
      Query       *query;
+     /* Lists to return extra commands from transformation */
+     List *extras_before = NIL;
+     List *extras_after = NIL;

!     query = transformStmt(pstate, parseTree, &extras_before, &extras_after);
      release_pstate_resources(pstate);
!
      while (extras_before != NIL)
      {
!         result = nconc(result, parse_analyze(lfirst(extras_before), pstate));
          extras_before = lnext(extras_before);
      }

*************** parse_analyze(Node *parseTree, ParseStat
*** 139,147 ****

      while (extras_after != NIL)
      {
!         result = lappend(result,
!                          transformStmt(pstate, lfirst(extras_after)));
!         release_pstate_resources(pstate);
          extras_after = lnext(extras_after);
      }

--- 140,146 ----

      while (extras_after != NIL)
      {
!         result = nconc(result, parse_analyze(lfirst(extras_after), pstate));
          extras_after = lnext(extras_after);
      }

*************** release_pstate_resources(ParseState *pst
*** 164,170 ****
   *      transform a Parse tree into a Query tree.
   */
  static Query *
! transformStmt(ParseState *pstate, Node *parseTree)
  {
      Query       *result = NULL;

--- 163,170 ----
   *      transform a Parse tree into a Query tree.
   */
  static Query *
! transformStmt(ParseState *pstate, Node *parseTree,
!               List **extras_before,    List **extras_after)
  {
      Query       *result = NULL;

*************** transformStmt(ParseState *pstate, Node *
*** 174,180 ****
               * Non-optimizable statements
               */
          case T_CreateStmt:
!             result = transformCreateStmt(pstate, (CreateStmt *) parseTree);
              break;

          case T_IndexStmt:
--- 174,181 ----
               * Non-optimizable statements
               */
          case T_CreateStmt:
!             result = transformCreateStmt(pstate, (CreateStmt *) parseTree,
!                                     extras_before, extras_after);
              break;

          case T_IndexStmt:
*************** transformStmt(ParseState *pstate, Node *
*** 182,195 ****
              break;

          case T_RuleStmt:
!             result = transformRuleStmt(pstate, (RuleStmt *) parseTree);
              break;

          case T_ViewStmt:
              {
                  ViewStmt   *n = (ViewStmt *) parseTree;

!                 n->query = transformStmt(pstate, (Node *) n->query);

                  /*
                   * If a list of column names was given, run through and
--- 183,198 ----
              break;

          case T_RuleStmt:
!             result = transformRuleStmt(pstate, (RuleStmt *) parseTree,
!                                     extras_before, extras_after);
              break;

          case T_ViewStmt:
              {
                  ViewStmt   *n = (ViewStmt *) parseTree;

!                 n->query = transformStmt(pstate, (Node *) n->query,
!                                     extras_before, extras_after);

                  /*
                   * If a list of column names was given, run through and
*************** transformStmt(ParseState *pstate, Node *
*** 239,258 ****

                  result = makeNode(Query);
                  result->commandType = CMD_UTILITY;
!                 n->query = transformStmt(pstate, (Node *) n->query);
                  result->utilityStmt = (Node *) parseTree;
              }
              break;

          case T_AlterTableStmt:
!             result = transformAlterTableStmt(pstate, (AlterTableStmt *) parseTree);
              break;

              /*
               * Optimizable statements
               */
          case T_InsertStmt:
!             result = transformInsertStmt(pstate, (InsertStmt *) parseTree);
              break;

          case T_DeleteStmt:
--- 242,264 ----

                  result = makeNode(Query);
                  result->commandType = CMD_UTILITY;
!                 n->query = transformStmt(pstate, (Node *) n->query,
!                                 extras_before, extras_after);
                  result->utilityStmt = (Node *) parseTree;
              }
              break;

          case T_AlterTableStmt:
!             result = transformAlterTableStmt(pstate, (AlterTableStmt *) parseTree,
!                                         extras_before, extras_after);
              break;

              /*
               * Optimizable statements
               */
          case T_InsertStmt:
!             result = transformInsertStmt(pstate, (InsertStmt *) parseTree,
!                                         extras_before, extras_after);
              break;

          case T_DeleteStmt:
*************** transformDeleteStmt(ParseState *pstate,
*** 337,343 ****
   *      transform an Insert Statement
   */
  static Query *
! transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
  {
      Query       *qry = makeNode(Query);
      List       *sub_rtable;
--- 343,350 ----
   *      transform an Insert Statement
   */
  static Query *
! transformInsertStmt(ParseState *pstate, InsertStmt *stmt,
!                     List **extras_before, List **extras_after)
  {
      Query       *qry = makeNode(Query);
      List       *sub_rtable;
*************** transformInsertStmt(ParseState *pstate,
*** 402,408 ****
          sub_pstate->p_rtable = sub_rtable;
          sub_pstate->p_namespace = sub_namespace;

!         selectQuery = transformStmt(sub_pstate, stmt->selectStmt);

          release_pstate_resources(sub_pstate);
          pfree(sub_pstate);
--- 409,420 ----
          sub_pstate->p_rtable = sub_rtable;
          sub_pstate->p_namespace = sub_namespace;

!         /*
!          * Note: we are not expecting that extras_before and extras_after
!          * are going to be used by the transformation of the SELECT statement.
!           */
!         selectQuery = transformStmt(sub_pstate, stmt->selectStmt,
!                                 extras_before, extras_after);

          release_pstate_resources(sub_pstate);
          pfree(sub_pstate);
*************** CreateIndexName(char *table_name, char *
*** 658,664 ****
   *      - thomas 1997-12-02
   */
  static Query *
! transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
  {
      CreateStmtContext cxt;
      Query       *q;
--- 670,677 ----
   *      - thomas 1997-12-02
   */
  static Query *
! transformCreateStmt(ParseState *pstate, CreateStmt *stmt,
!                     List **extras_before, List **extras_after)
  {
      CreateStmtContext cxt;
      Query       *q;
*************** transformCreateStmt(ParseState *pstate,
*** 728,735 ****
      q->utilityStmt = (Node *) stmt;
      stmt->tableElts = cxt.columns;
      stmt->constraints = cxt.ckconstraints;
!     extras_before = cxt.blist;
!     extras_after = cxt.alist;

      return q;
  }
--- 741,748 ----
      q->utilityStmt = (Node *) stmt;
      stmt->tableElts = cxt.columns;
      stmt->constraints = cxt.ckconstraints;
!     *extras_before = nconc (*extras_before, cxt.blist);
!     *extras_after = nconc (cxt.alist, *extras_after);

      return q;
  }
*************** transformIndexStmt(ParseState *pstate, I
*** 1668,1674 ****
   *      trees which is transformed into a list of query trees.
   */
  static Query *
! transformRuleStmt(ParseState *pstate, RuleStmt *stmt)
  {
      Query       *qry;
      RangeTblEntry *oldrte;
--- 1681,1688 ----
   *      trees which is transformed into a list of query trees.
   */
  static Query *
! transformRuleStmt(ParseState *pstate, RuleStmt *stmt,
!                 List **extras_before, List **extras_after)
  {
      Query       *qry;
      RangeTblEntry *oldrte;
*************** transformRuleStmt(ParseState *pstate, Ru
*** 1797,1803 ****
              addRTEtoQuery(sub_pstate, newrte, false, true);

              /* Transform the rule action statement */
!             top_subqry = transformStmt(sub_pstate, action);

              /*
               * We cannot support utility-statement actions (eg NOTIFY)
--- 1811,1818 ----
              addRTEtoQuery(sub_pstate, newrte, false, true);

              /* Transform the rule action statement */
!             top_subqry = transformStmt(sub_pstate, action,
!                                 extras_before, extras_after);

              /*
               * We cannot support utility-statement actions (eg NOTIFY)
*************** transformUpdateStmt(ParseState *pstate,
*** 2494,2500 ****
   *    transform an Alter Table Statement
   */
  static Query *
! transformAlterTableStmt(ParseState *pstate, AlterTableStmt *stmt)
  {
      CreateStmtContext cxt;
      Query       *qry;
--- 2509,2516 ----
   *    transform an Alter Table Statement
   */
  static Query *
! transformAlterTableStmt(ParseState *pstate, AlterTableStmt *stmt,
!                         List **extras_before, List **extras_after)
  {
      CreateStmtContext cxt;
      Query       *qry;
*************** transformAlterTableStmt(ParseState *psta
*** 2534,2541 ****
              transformFKConstraints(pstate, &cxt);

              ((ColumnDef *) stmt->def)->constraints = cxt.ckconstraints;
!             extras_before = cxt.blist;
!             extras_after = cxt.alist;
              break;

          case 'C':
--- 2550,2557 ----
              transformFKConstraints(pstate, &cxt);

              ((ColumnDef *) stmt->def)->constraints = cxt.ckconstraints;
!             *extras_before = nconc(*extras_before, cxt.blist);
!             *extras_after = nconc(cxt.alist, *extras_after);
              break;

          case 'C':
*************** transformAlterTableStmt(ParseState *psta
*** 2571,2578 ****

              Assert(cxt.columns == NIL);
              stmt->def = (Node *) nconc(cxt.ckconstraints, cxt.fkconstraints);
!             extras_before = cxt.blist;
!             extras_after = cxt.alist;
              break;

          default:
--- 2587,2594 ----

              Assert(cxt.columns == NIL);
              stmt->def = (Node *) nconc(cxt.ckconstraints, cxt.fkconstraints);
!             *extras_before = nconc(*extras_before, cxt.blist);
!             *extras_after = nconc(cxt.alist, *extras_after);
              break;

          default:
Index: src/backend/tcop/postgres.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/tcop/postgres.c,v
retrieving revision 1.245
diff -c -p -r1.245 postgres.c
*** src/backend/tcop/postgres.c    2002/01/10 01:11:45    1.245
--- src/backend/tcop/postgres.c    2002/02/14 10:49:19
***************
*** 64,69 ****
--- 64,78 ----

  #include "pgstat.h"

+ static char *CreateCommandTag(Node *parsetree);
+
+ /* Uncomment the following line if you want ps_status
+  * to be set for each individual query that may result from
+  * a rewrite as oposed to just the main (original) one
+  */
+ /* #define FINE_GRAIN_PROFILE 1 */
+
+
  /* ----------------
   *        global variables
   * ----------------
*************** pg_exec_query_string(char *query_string,
*** 634,639 ****
--- 643,650 ----
      foreach(parsetree_item, parsetree_list)
      {
          Node       *parsetree = (Node *) lfirst(parsetree_item);
+         char       *commandTag = NULL;
+         bool        isQueryStmt = false;
          bool        isTransactionStmt;
          List       *querytree_list,
                     *querytree_item;
*************** pg_exec_query_string(char *query_string,
*** 675,680 ****
--- 686,693 ----
                   * command ended. -cim 6/1/90
                   */
                  char       *tag = "*ABORT STATE*";
+
+                 set_ps_display(tag);

                  elog(NOTICE, "current transaction is aborted, "
                       "queries ignored until end of transaction block");
*************** pg_exec_query_string(char *query_string,
*** 702,708 ****

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

          /*
           * OK to analyze and rewrite this query.
!          */
!
!         /*
!          * First we set the command-completion tag to the main query
!          * (as opposed to each of the others that may have
!          * been generated by analyze and rewrite)
!          */
!         commandTag = CreateCommandTag(parsetree);
!
! #ifndef FINE_GRAIN_PROFILE
!         /*
!          * Set ps_status to the main query tag
!          */
!         set_ps_display(commandTag);
! #endif
!
!         /*
           * Switch to appropriate context for constructing querytrees (again,
           * these must outlive the execution context).
           */
*************** pg_exec_query_string(char *query_string,
*** 746,752 ****
--- 775,796 ----
                  else if (DebugLvl > 1)
                      elog(DEBUG, "ProcessUtility");

+ #ifdef FINE_GRAIN_PROFILE
+                 set_ps_display(CreateUtilityTag(querytree->utilityStmt));
+ #endif
                  ProcessUtility(querytree->utilityStmt, dest);
+
+                 /*
+                  * FETCHes, as plannable queries, take care of completion
+                  * themselves but we still have to do it for MOVEs as they
+                  * do not send data (and thus, do not send a completion).
+                  */
+                 if (nodeTag(parsetree) == T_FetchStmt)
+                 {
+                     FetchStmt  *stmt = (FetchStmt *) parsetree;
+                     if (!(stmt->ismove))
+                         isQueryStmt = true;  /* Don't do it twice */
+                 }
              }
              else
              {
*************** pg_exec_query_string(char *query_string,
*** 754,759 ****
--- 798,805 ----
                   * process a plannable query.
                   */
                  Plan       *plan;
+
+                 isQueryStmt = true;

                  plan = pg_plan_query(querytree);

*************** pg_exec_query_string(char *query_string,
*** 818,823 ****
--- 864,876 ----

          }                        /* end loop over queries generated from a
                                   * parsetree */
+
+         /*
+          * tell fe/be or whatever that we're done if we only processed
+          * utilities (plannable queries take care of completion themselves)
+          */
+         if (!isQueryStmt)
+             EndCommand(commandTag, dest);
      }                            /* end loop over parsetrees */

      /*
*************** assertTest(int val)
*** 2037,2039 ****
--- 2090,2354 ----
  #endif

  #endif
+
+
+ /* ----------------------------------------------------------------
+  *        CreateCommandTag
+  *
+  *        utility to get a string representation of the
+  *        command operation.
+  * ----------------------------------------------------------------
+  */
+ static char *
+ CreateCommandTag(Node *parsetree)
+ {
+     char       *tag = NULL;
+
+     switch (nodeTag(parsetree))
+     {
+         case T_InsertStmt:
+             tag = "INSERT";
+             break;
+
+         case T_DeleteStmt:
+             tag = "DELETE";
+             break;
+
+         case T_UpdateStmt:
+             tag = "UPDATE";
+             break;
+
+         case T_SelectStmt:
+             tag = "SELECT";
+             break;
+
+         case T_TransactionStmt:
+             {
+                 TransactionStmt *stmt = (TransactionStmt *) parsetree;
+
+                 switch (stmt->command)
+                 {
+                     case BEGIN_TRANS:
+                         tag = "BEGIN";
+                         break;
+
+                     case COMMIT:
+                         tag = "COMMIT";
+                         break;
+
+                     case ROLLBACK:
+                         tag = "ROLLBACK";
+                         break;
+                 }
+             }
+             break;
+
+         case T_ClosePortalStmt:
+             tag = "CLOSE";
+             break;
+
+         case T_FetchStmt:
+             {
+                 FetchStmt  *stmt = (FetchStmt *) parsetree;
+                 tag = (stmt->ismove) ? "MOVE" : "FETCH";
+             }
+             break;
+
+         case T_CreateStmt:
+             tag = "CREATE";
+             break;
+
+         case T_DropStmt:
+             tag = "DROP";
+             break;
+
+         case T_TruncateStmt:
+             tag = "TRUNCATE";
+             break;
+
+         case T_CommentStmt:
+             tag = "COMMENT";
+             break;
+
+         case T_CopyStmt:
+             tag = "COPY";
+             break;
+
+         case T_RenameStmt:
+             tag = "ALTER";
+             break;
+
+         case T_AlterTableStmt:
+             tag = "ALTER";
+             break;
+
+         case T_GrantStmt:
+             {
+                 GrantStmt  *stmt = (GrantStmt *) parsetree;
+                 tag = (stmt->is_grant) ? "GRANT" : "REVOKE";
+             }
+             break;
+
+         case T_DefineStmt:
+             tag = "CREATE";
+             break;
+
+         case T_ViewStmt:        /* CREATE VIEW */
+             tag = "CREATE";
+             break;
+
+         case T_ProcedureStmt:    /* CREATE FUNCTION */
+             tag = "CREATE";
+             break;
+
+         case T_IndexStmt:        /* CREATE INDEX */
+             tag = "CREATE";
+             break;
+
+         case T_RuleStmt:        /* CREATE RULE */
+             tag = "CREATE";
+             break;
+
+         case T_CreateSeqStmt:
+             tag = "CREATE";
+             break;
+
+         case T_RemoveAggrStmt:
+             tag = "DROP";
+             break;
+
+         case T_RemoveFuncStmt:
+             tag = "DROP";
+             break;
+
+         case T_RemoveOperStmt:
+             tag = "DROP";
+             break;
+
+         case T_VersionStmt:
+             tag = "CREATE VERSION";
+             break;
+
+         case T_CreatedbStmt:
+             tag = "CREATE DATABASE";
+             break;
+
+         case T_DropdbStmt:
+             tag = "DROP DATABASE";
+             break;
+
+         case T_NotifyStmt:
+             tag = "NOTIFY";
+             break;
+
+         case T_ListenStmt:
+             tag = "LISTEN";
+             break;
+
+         case T_UnlistenStmt:
+             tag = "UNLISTEN";
+             break;
+
+         case T_LoadStmt:
+             tag = "LOAD";
+             break;
+
+         case T_ClusterStmt:
+             tag = "CLUSTER";
+             break;
+
+         case T_VacuumStmt:
+             if (((VacuumStmt *) parsetree)->vacuum)
+                 tag = "VACUUM";
+             else
+                 tag = "ANALYZE";
+             break;
+
+         case T_ExplainStmt:
+             tag = "EXPLAIN";
+             break;
+
+ #ifdef NOT_USED
+         case T_RecipeStmt:
+             tag = "EXECUTE RECIPE";
+             break;
+ #endif
+
+         case T_VariableSetStmt:
+             tag = "SET VARIABLE";
+             break;
+
+         case T_VariableShowStmt:
+             tag = "SHOW VARIABLE";
+             break;
+
+         case T_VariableResetStmt:
+             tag = "RESET VARIABLE";
+             break;
+
+         case T_CreateTrigStmt:
+             tag = "CREATE";
+             break;
+
+         case T_DropTrigStmt:
+             tag = "DROP";
+             break;
+
+         case T_CreatePLangStmt:
+             tag = "CREATE";
+             break;
+
+         case T_DropPLangStmt:
+             tag = "DROP";
+             break;
+
+         case T_CreateUserStmt:
+             tag = "CREATE USER";
+             break;
+
+         case T_AlterUserStmt:
+             tag = "ALTER USER";
+             break;
+
+         case T_DropUserStmt:
+             tag = "DROP USER";
+             break;
+
+         case T_LockStmt:
+             tag = "LOCK TABLE";
+             break;
+
+         case T_ConstraintsSetStmt:
+             tag = "SET CONSTRAINTS";
+             break;
+
+         case T_CreateGroupStmt:
+             tag = "CREATE GROUP";
+             break;
+
+         case T_AlterGroupStmt:
+             tag = "ALTER GROUP";
+             break;
+
+         case T_DropGroupStmt:
+             tag = "DROP GROUP";
+             break;
+
+         case T_CheckPointStmt:
+             tag = "CHECKPOINT";
+             break;
+
+         case T_ReindexStmt:
+             tag = "REINDEX";
+             break;
+
+         default:
+             elog(DEBUG, "CreateUtilityTag: unknown utility operation type %d",
+                  nodeTag(parsetree));
+             tag = "???";
+             break;
+     }
+
+     return tag;
+ }
+
Index: src/backend/tcop/pquery.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/tcop/pquery.c,v
retrieving revision 1.46
diff -c -p -r1.46 pquery.c
*** src/backend/tcop/pquery.c    2001/10/25 05:49:43    1.46
--- src/backend/tcop/pquery.c    2002/02/14 10:49:19
*************** ProcessQuery(Query *parsetree,
*** 180,186 ****
      EState       *state;
      TupleDesc    attinfo;

!     set_ps_display(tag = CreateOperationTag(operation));

      /*
       * initialize portal/into relation status
--- 180,186 ----
      EState       *state;
      TupleDesc    attinfo;

!     tag = CreateOperationTag(operation);

      /*
       * initialize portal/into relation status
Index: src/backend/tcop/utility.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/tcop/utility.c,v
retrieving revision 1.125
diff -c -p -r1.125 utility.c
*** src/backend/tcop/utility.c    2002/02/07 00:27:30    1.125
--- src/backend/tcop/utility.c    2002/02/14 10:49:19
***************
*** 44,54 ****
  #include "rewrite/rewriteRemove.h"
  #include "tcop/utility.h"
  #include "utils/acl.h"
- #include "utils/ps_status.h"
  #include "utils/syscache.h"
  #include "utils/temprel.h"
  #include "access/xlog.h"

  /*
   * Error-checking support for DROP commands
   */
--- 44,54 ----
  #include "rewrite/rewriteRemove.h"
  #include "tcop/utility.h"
  #include "utils/acl.h"
  #include "utils/syscache.h"
  #include "utils/temprel.h"
  #include "access/xlog.h"

+
  /*
   * Error-checking support for DROP commands
   */
*************** CheckDropPermissions(char *name, char ri
*** 132,144 ****

  /* ----------------
   *        general utility function invoker
   * ----------------
   */
  void
  ProcessUtility(Node *parsetree,
                 CommandDest dest)
  {
-     char       *commandTag = NULL;
      char       *relname;
      char       *relationName;

--- 132,145 ----

  /* ----------------
   *        general utility function invoker
+  *
+  *    Returns the command-complete tag appropriate for the function
   * ----------------
   */
  void
  ProcessUtility(Node *parsetree,
                 CommandDest dest)
  {
      char       *relname;
      char       *relationName;

*************** ProcessUtility(Node *parsetree,
*** 155,171 ****
                  switch (stmt->command)
                  {
                      case BEGIN_TRANS:
-                         set_ps_display(commandTag = "BEGIN");
                          BeginTransactionBlock();
                          break;

                      case COMMIT:
-                         set_ps_display(commandTag = "COMMIT");
                          EndTransactionBlock();
                          break;

                      case ROLLBACK:
-                         set_ps_display(commandTag = "ROLLBACK");
                          UserAbortTransactionBlock();
                          break;
                  }
--- 156,169 ----
*************** ProcessUtility(Node *parsetree,
*** 180,187 ****
              {
                  ClosePortalStmt *stmt = (ClosePortalStmt *) parsetree;

-                 set_ps_display(commandTag = "CLOSE");
-
                  PerformPortalClose(stmt->portalname, dest);
              }
              break;
--- 178,183 ----
*************** ProcessUtility(Node *parsetree,
*** 193,200 ****
                  bool        forward;
                  int            count;

-                 set_ps_display(commandTag = (stmt->ismove) ? "MOVE" : "FETCH");
-
                  SetQuerySnapshot();

                  forward = (bool) (stmt->direction == FORWARD);
--- 189,194 ----
*************** ProcessUtility(Node *parsetree,
*** 204,210 ****
                   */

                  count = stmt->howMany;
!                 PerformPortalFetch(portalName, forward, count, commandTag,
                                     (stmt->ismove) ? None : dest);        /* /dev/null for MOVE */
              }
              break;
--- 198,204 ----
                   */

                  count = stmt->howMany;
!                 PerformPortalFetch(portalName, forward, count,(stmt->ismove) ? "MOVE" : "FETCH",
                                     (stmt->ismove) ? None : dest);        /* /dev/null for MOVE */
              }
              break;
*************** ProcessUtility(Node *parsetree,
*** 215,222 ****
               *
               */
          case T_CreateStmt:
-             set_ps_display(commandTag = "CREATE");
-
              DefineRelation((CreateStmt *) parsetree, RELKIND_RELATION);

              /*
--- 209,214 ----
*************** ProcessUtility(Node *parsetree,
*** 234,241 ****
                  List       *args = stmt->names;
                  List       *arg;

-                 set_ps_display(commandTag = "DROP");
-
                  foreach(arg, args)
                  {
                      relname = strVal(lfirst(arg));
--- 226,231 ----
*************** ProcessUtility(Node *parsetree,
*** 296,303 ****
              {
                  Relation    rel;

-                 set_ps_display(commandTag = "TRUNCATE");
-
                  relname = ((TruncateStmt *) parsetree)->relName;
                  if (!allowSystemTableMods && IsSystemRelationName(relname))
                      elog(ERROR, "TRUNCATE cannot be used on system tables. '%s' is a system table",
--- 286,291 ----
*************** ProcessUtility(Node *parsetree,
*** 325,332 ****

                  statement = ((CommentStmt *) parsetree);

-                 set_ps_display(commandTag = "COMMENT");
-
                  CommentObject(statement->objtype, statement->objname,
                                statement->objproperty, statement->objlist,
                                statement->comment);
--- 313,318 ----
*************** ProcessUtility(Node *parsetree,
*** 337,344 ****
              {
                  CopyStmt   *stmt = (CopyStmt *) parsetree;

-                 set_ps_display(commandTag = "COPY");
-
                  if (stmt->direction != FROM)
                      SetQuerySnapshot();

--- 323,328 ----
*************** ProcessUtility(Node *parsetree,
*** 365,372 ****
              {
                  RenameStmt *stmt = (RenameStmt *) parsetree;

-                 set_ps_display(commandTag = "ALTER");
-
                  relname = stmt->relname;
                  if (!allowSystemTableMods && IsSystemRelationName(relname))
                      elog(ERROR, "ALTER TABLE: relation \"%s\" is a system catalog",
--- 349,354 ----
*************** ProcessUtility(Node *parsetree,
*** 413,420 ****
              {
                  AlterTableStmt *stmt = (AlterTableStmt *) parsetree;

-                 set_ps_display(commandTag = "ALTER");
-
                  /*
                   * Some or all of these functions are recursive to cover
                   * inherited things, so permission checks are done there.
--- 395,400 ----
*************** ProcessUtility(Node *parsetree,
*** 475,483 ****
              {
                  GrantStmt  *stmt = (GrantStmt *) parsetree;

-                 commandTag = stmt->is_grant ? "GRANT" : "REVOKE";
-                 set_ps_display(commandTag);
-
                  ExecuteGrantStmt(stmt);
              }
              break;
--- 455,460 ----
*************** ProcessUtility(Node *parsetree,
*** 491,498 ****
              {
                  DefineStmt *stmt = (DefineStmt *) parsetree;

-                 set_ps_display(commandTag = "CREATE");
-
                  switch (stmt->defType)
                  {
                      case OPERATOR:
--- 468,473 ----
*************** ProcessUtility(Node *parsetree,
*** 514,528 ****
              {
                  ViewStmt   *stmt = (ViewStmt *) parsetree;

-                 set_ps_display(commandTag = "CREATE");
-
                  DefineView(stmt->viewname, stmt->query);        /* retrieve parsetree */
              }
              break;

          case T_ProcedureStmt:    /* CREATE FUNCTION */
-             set_ps_display(commandTag = "CREATE");
-
              CreateFunction((ProcedureStmt *) parsetree);
              break;

--- 489,499 ----
*************** ProcessUtility(Node *parsetree,
*** 530,537 ****
              {
                  IndexStmt  *stmt = (IndexStmt *) parsetree;

-                 set_ps_display(commandTag = "CREATE");
-
                  relname = stmt->relname;
                  if (!allowSystemTableMods && IsSystemRelationName(relname))
                      elog(ERROR, "CREATE INDEX: relation \"%s\" is a system catalog",
--- 501,506 ----
*************** ProcessUtility(Node *parsetree,
*** 559,573 ****
                  aclcheck_result = pg_aclcheck(relname, GetUserId(), ACL_RULE);
                  if (aclcheck_result != ACLCHECK_OK)
                      elog(ERROR, "%s: %s", relname, aclcheck_error_strings[aclcheck_result]);
-                 set_ps_display(commandTag = "CREATE");

                  DefineQueryRewrite(stmt);
              }
              break;

          case T_CreateSeqStmt:
-             set_ps_display(commandTag = "CREATE");
-
              DefineSequence((CreateSeqStmt *) parsetree);
              break;

--- 528,539 ----
*************** ProcessUtility(Node *parsetree,
*** 576,583 ****
                  RemoveAggrStmt *stmt = (RemoveAggrStmt *) parsetree;
                  char       *typename = (char *) NULL;

-                 set_ps_display(commandTag = "DROP");
-
                  if (stmt->aggtype != NULL)
                      typename = TypeNameToInternalName((TypeName *) stmt->aggtype);

--- 542,547 ----
*************** ProcessUtility(Node *parsetree,
*** 589,596 ****
              {
                  RemoveFuncStmt *stmt = (RemoveFuncStmt *) parsetree;

-                 set_ps_display(commandTag = "DROP");
-
                  RemoveFunction(stmt->funcname, stmt->args);
              }
              break;
--- 553,558 ----
*************** ProcessUtility(Node *parsetree,
*** 603,610 ****
                  char       *typename1 = (char *) NULL;
                  char       *typename2 = (char *) NULL;

-                 set_ps_display(commandTag = "DROP");
-
                  if (typenode1 != NULL)
                      typename1 = TypeNameToInternalName(typenode1);
                  if (typenode2 != NULL)
--- 565,570 ----
*************** ProcessUtility(Node *parsetree,
*** 622,629 ****
              {
                  CreatedbStmt *stmt = (CreatedbStmt *) parsetree;

-                 set_ps_display(commandTag = "CREATE DATABASE");
-
                  createdb(stmt->dbname, stmt->dbpath,
                           stmt->dbtemplate, stmt->encoding);
              }
--- 582,587 ----
*************** ProcessUtility(Node *parsetree,
*** 633,640 ****
              {
                  DropdbStmt *stmt = (DropdbStmt *) parsetree;

-                 set_ps_display(commandTag = "DROP DATABASE");
-
                  dropdb(stmt->dbname);
              }
              break;
--- 591,596 ----
*************** ProcessUtility(Node *parsetree,
*** 644,651 ****
              {
                  NotifyStmt *stmt = (NotifyStmt *) parsetree;

-                 set_ps_display(commandTag = "NOTIFY");
-
                  Async_Notify(stmt->relname);
              }
              break;
--- 600,605 ----
*************** ProcessUtility(Node *parsetree,
*** 654,661 ****
              {
                  ListenStmt *stmt = (ListenStmt *) parsetree;

-                 set_ps_display(commandTag = "LISTEN");
-
                  Async_Listen(stmt->relname, MyProcPid);
              }
              break;
--- 608,613 ----
*************** ProcessUtility(Node *parsetree,
*** 664,671 ****
              {
                  UnlistenStmt *stmt = (UnlistenStmt *) parsetree;

-                 set_ps_display(commandTag = "UNLISTEN");
-
                  Async_Unlisten(stmt->relname, MyProcPid);
              }
              break;
--- 616,621 ----
*************** ProcessUtility(Node *parsetree,
*** 678,685 ****
              {
                  LoadStmt   *stmt = (LoadStmt *) parsetree;

-                 set_ps_display(commandTag = "LOAD");
-
                  closeAllVfds(); /* probably not necessary... */
                  load_file(stmt->filename);
              }
--- 628,633 ----
*************** ProcessUtility(Node *parsetree,
*** 689,696 ****
              {
                  ClusterStmt *stmt = (ClusterStmt *) parsetree;

-                 set_ps_display(commandTag = "CLUSTER");
-
                  relname = stmt->relname;
                  if (IsSystemRelationName(relname))
                      elog(ERROR, "CLUSTER: relation \"%s\" is a system catalog",
--- 637,642 ----
*************** ProcessUtility(Node *parsetree,
*** 703,714 ****
              break;

          case T_VacuumStmt:
-             if (((VacuumStmt *) parsetree)->vacuum)
-                 commandTag = "VACUUM";
-             else
-                 commandTag = "ANALYZE";
-             set_ps_display(commandTag);
-
              vacuum((VacuumStmt *) parsetree);
              break;

--- 649,654 ----
*************** ProcessUtility(Node *parsetree,
*** 716,723 ****
              {
                  ExplainStmt *stmt = (ExplainStmt *) parsetree;

-                 set_ps_display(commandTag = "EXPLAIN");
-
                  ExplainQuery(stmt->query, stmt->verbose, stmt->analyze, dest);
              }
              break;
--- 656,661 ----
*************** ProcessUtility(Node *parsetree,
*** 731,738 ****
              {
                  RecipeStmt *stmt = (RecipeStmt *) parsetree;

-                 set_ps_display(commandTag = "EXECUTE RECIPE");
-
                  beginRecipe(stmt);
              }
              break;
--- 669,674 ----
*************** ProcessUtility(Node *parsetree,
*** 746,752 ****
                  VariableSetStmt *n = (VariableSetStmt *) parsetree;

                  SetPGVariable(n->name, n->args);
-                 set_ps_display(commandTag = "SET VARIABLE");
              }
              break;

--- 682,687 ----
*************** ProcessUtility(Node *parsetree,
*** 755,761 ****
                  VariableShowStmt *n = (VariableShowStmt *) parsetree;

                  GetPGVariable(n->name);
-                 set_ps_display(commandTag = "SHOW VARIABLE");
              }
              break;

--- 690,695 ----
*************** ProcessUtility(Node *parsetree,
*** 764,770 ****
                  VariableResetStmt *n = (VariableResetStmt *) parsetree;

                  ResetPGVariable(n->name);
-                 set_ps_display(commandTag = "RESET VARIABLE");
              }
              break;

--- 698,703 ----
*************** ProcessUtility(Node *parsetree,
*** 772,785 ****
               * ******************************** TRIGGER statements *******************************
               */
          case T_CreateTrigStmt:
-             set_ps_display(commandTag = "CREATE");
-
              CreateTrigger((CreateTrigStmt *) parsetree);
              break;

          case T_DropTrigStmt:
-             set_ps_display(commandTag = "DROP");
-
              DropTrigger((DropTrigStmt *) parsetree);
              break;

--- 705,714 ----
*************** ProcessUtility(Node *parsetree,
*** 787,800 ****
               * ************* PROCEDURAL LANGUAGE statements *****************
               */
          case T_CreatePLangStmt:
-             set_ps_display(commandTag = "CREATE");
-
              CreateProceduralLanguage((CreatePLangStmt *) parsetree);
              break;

          case T_DropPLangStmt:
-             set_ps_display(commandTag = "DROP");
-
              DropProceduralLanguage((DropPLangStmt *) parsetree);
              break;

--- 716,725 ----
*************** ProcessUtility(Node *parsetree,
*** 803,859 ****
               *
               */
          case T_CreateUserStmt:
-             set_ps_display(commandTag = "CREATE USER");
-
              CreateUser((CreateUserStmt *) parsetree);
              break;

          case T_AlterUserStmt:
-             set_ps_display(commandTag = "ALTER USER");
-
              AlterUser((AlterUserStmt *) parsetree);
              break;

          case T_DropUserStmt:
-             set_ps_display(commandTag = "DROP USER");
-
              DropUser((DropUserStmt *) parsetree);
              break;

          case T_LockStmt:
-             set_ps_display(commandTag = "LOCK TABLE");
-
              LockTableCommand((LockStmt *) parsetree);
              break;

          case T_ConstraintsSetStmt:
-             set_ps_display(commandTag = "SET CONSTRAINTS");
-
              DeferredTriggerSetState((ConstraintsSetStmt *) parsetree);
              break;

          case T_CreateGroupStmt:
-             set_ps_display(commandTag = "CREATE GROUP");
-
              CreateGroup((CreateGroupStmt *) parsetree);
              break;

          case T_AlterGroupStmt:
-             set_ps_display(commandTag = "ALTER GROUP");
-
              AlterGroup((AlterGroupStmt *) parsetree, "ALTER GROUP");
              break;

          case T_DropGroupStmt:
-             set_ps_display(commandTag = "DROP GROUP");
-
              DropGroup((DropGroupStmt *) parsetree);
              break;

          case T_CheckPointStmt:
              {
-                 set_ps_display(commandTag = "CHECKPOINT");
-
                  if (!superuser())
                      elog(ERROR, "permission denied");
                  CreateCheckPoint(false);
--- 728,766 ----
*************** ProcessUtility(Node *parsetree,
*** 864,871 ****
              {
                  ReindexStmt *stmt = (ReindexStmt *) parsetree;

-                 set_ps_display(commandTag = "REINDEX");
-
                  switch (stmt->reindexType)
                  {
                      case INDEX:
--- 771,776 ----
*************** ProcessUtility(Node *parsetree,
*** 913,919 ****
      }

      /*
!      * tell fe/be or whatever that we're done.
       */
!     EndCommand(commandTag, dest);
  }
--- 818,826 ----
      }

      /*
!      * Note: the "end-of-command" tag is to be sent by the caller,
!      * if appropriate.
       */
!     return;
  }
+

pgsql-patches by date:

Previous
From: Bruce Momjian
Date:
Subject: Re: Re: nocreatetable for 7.1.2 [patch]
Next
From: Fernando Nasser
Date:
Subject: Fix command completion for CREATE TABEL ... AS