aboutsummaryrefslogtreecommitdiff
path: root/src/backend/tcop/postgres.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/tcop/postgres.c')
-rw-r--r--src/backend/tcop/postgres.c365
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;
+}