diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2002-02-26 22:47:12 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2002-02-26 22:47:12 +0000 |
commit | 56ee2ecba96a742bb6e18dfe8ee48054e90ebaa9 (patch) | |
tree | 905c72dc3db475d47d04472a1de7ab715b5725c7 /src/backend/tcop/postgres.c | |
parent | f71dc6d0e28a855f2d782ec48f950ffeaca1307d (diff) | |
download | postgresql-56ee2ecba96a742bb6e18dfe8ee48054e90ebaa9.tar.gz postgresql-56ee2ecba96a742bb6e18dfe8ee48054e90ebaa9.zip |
Restructure command-completion-report code so that there is just one
report for each received SQL command, regardless of rewriting activity.
Also ensure that this report comes from the 'original' command, not the
last command generated by rewrite; this fixes 7.2 breakage for INSERT
commands that have actions added by rules. Fernando Nasser and Tom Lane.
Diffstat (limited to 'src/backend/tcop/postgres.c')
-rw-r--r-- | src/backend/tcop/postgres.c | 365 |
1 files changed, 346 insertions, 19 deletions
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 976b434655f..61fdf9c5acf 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.247 2002/02/23 01:31:36 petere Exp $ + * $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.248 2002/02/26 22:47:08 tgl Exp $ * * NOTES * this is the "main" module of the postgres backend and @@ -64,6 +64,7 @@ #include "pgstat.h" + /* ---------------- * global variables * ---------------- @@ -87,6 +88,13 @@ bool InError = false; static bool EchoQuery = false; /* default don't echo */ +/* + * Flag to mark SIGHUP. Whenever the main loop comes around it + * will reread the configuration file. (Better than doing the + * reading in the signal handler, ey?) + */ +static volatile bool got_SIGHUP = false; + /* ---------------- * people who want to use EOF should #define DONTUSENEWLINE in * tcop/tcopdebug.h @@ -118,13 +126,7 @@ static void start_xact_command(void); static void finish_xact_command(void); static void SigHupHandler(SIGNAL_ARGS); static void FloatExceptionHandler(SIGNAL_ARGS); - -/* - * Flag to mark SIGHUP. Whenever the main loop comes around it - * will reread the configuration file. (Better than doing the - * reading in the signal handler, ey?) - */ -static volatile bool got_SIGHUP = false; +static const char *CreateCommandTag(Node *parsetree); /* ---------------------------------------------------------------- @@ -635,6 +637,8 @@ pg_exec_query_string(char *query_string, /* string to execute */ { Node *parsetree = (Node *) lfirst(parsetree_item); bool isTransactionStmt; + const char *commandTag; + char completionTag[COMPLETION_TAG_BUFSIZE]; List *querytree_list, *querytree_item; @@ -670,16 +674,17 @@ pg_exec_query_string(char *query_string, /* string to execute */ if (!allowit) { - /* - * the EndCommand() stuff is to tell the frontend that the - * command ended. -cim 6/1/90 - */ - char *tag = "*ABORT STATE*"; - elog(NOTICE, "current transaction is aborted, " "queries ignored until end of transaction block"); - EndCommand(tag, dest); + /* + * We need to emit a command-complete report to the client, + * even though we didn't process the query. + * - cim 6/1/90 + */ + commandTag = "*ABORT STATE*"; + + EndCommand(commandTag, dest); /* * We continue in the loop, on the off chance that there @@ -702,7 +707,18 @@ pg_exec_query_string(char *query_string, /* string to execute */ /* * 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 be generated by + * analyze and rewrite). Also set ps_status to the main query tag. + */ + commandTag = CreateCommandTag(parsetree); + + set_ps_display(commandTag); + + /* * Switch to appropriate context for constructing querytrees (again, * these must outlive the execution context). */ @@ -746,7 +762,19 @@ pg_exec_query_string(char *query_string, /* string to execute */ else if (DebugLvl > 1) elog(DEBUG, "ProcessUtility"); - ProcessUtility(querytree->utilityStmt, dest); + if (querytree->originalQuery) + { + /* utility statement can override default tag string */ + ProcessUtility(querytree->utilityStmt, dest, + completionTag); + if (completionTag[0]) + commandTag = completionTag; + } + else + { + /* utility added by rewrite cannot override tag */ + ProcessUtility(querytree->utilityStmt, dest, NULL); + } } else { @@ -778,7 +806,18 @@ pg_exec_query_string(char *query_string, /* string to execute */ { if (DebugLvl > 1) elog(DEBUG, "ProcessQuery"); - ProcessQuery(querytree, plan, dest); + + if (querytree->originalQuery) + { + /* original stmt can override default tag string */ + ProcessQuery(querytree, plan, dest, completionTag); + commandTag = completionTag; + } + else + { + /* stmt added by rewrite cannot override tag */ + ProcessQuery(querytree, plan, dest, NULL); + } } if (Show_executor_stats) @@ -818,6 +857,29 @@ pg_exec_query_string(char *query_string, /* string to execute */ } /* end loop over queries generated from a * parsetree */ + + /* + * 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. + */ + EndCommand(commandTag, dest); } /* end loop over parsetrees */ /* @@ -1626,7 +1688,7 @@ PostgresMain(int argc, char *argv[], const char *username) if (!IsUnderPostmaster) { puts("\nPOSTGRES backend interactive interface "); - puts("$Revision: 1.247 $ $Date: 2002/02/23 01:31:36 $\n"); + puts("$Revision: 1.248 $ $Date: 2002/02/26 22:47:08 $\n"); } /* @@ -2037,3 +2099,268 @@ assertTest(int val) #endif #endif + + +/* ---------------------------------------------------------------- + * CreateCommandTag + * + * utility to get a string representation of the + * command operation. + * ---------------------------------------------------------------- + */ +static const char * +CreateCommandTag(Node *parsetree) +{ + const char *tag; + + 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; + + default: + tag = "???"; + 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, "CreateCommandTag: unknown parse node type %d", + nodeTag(parsetree)); + tag = "???"; + break; + } + + return tag; +} |