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: