Index: 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: