diff options
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; +} |