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.
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.154 2002/02/19 20:11:12 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.155 2002/02/26 22:47:04 tgl Exp $
*
* NOTES
* The PerformAddAttribute() code, like most of the relation
MemoryContextSwitchTo(oldcontext);
}
-/* --------------------------------
- * PerformPortalFetch
- * --------------------------------
+
+/*
+ * PerformPortalFetch
+ *
+ * name: name of portal
+ * forward: forward or backward fetch?
+ * count: # of tuples to fetch (0 implies all)
+ * dest: where to send results
+ * completionTag: points to a buffer of size COMPLETION_TAG_BUFSIZE
+ * in which to store a command completion status string.
+ *
+ * completionTag may be NULL if caller doesn't want a status string.
*/
void
PerformPortalFetch(char *name,
bool forward,
int count,
- char *tag,
- CommandDest dest)
+ CommandDest dest,
+ char *completionTag)
{
Portal portal;
QueryDesc *queryDesc;
CommandId savedId;
bool temp_desc = false;
+ /* initialize completion status in case of early exit */
+ if (completionTag)
+ strcpy(completionTag, (dest == None) ? "MOVE 0" : "FETCH 0");
+
/*
* sanity checks
*/
* relations */
false, /* this is a portal fetch, not a "retrieve
* portal" */
- tag,
+ NULL, /* not used */
queryDesc->dest);
/*
{
ExecutorRun(queryDesc, estate, EXEC_FOR, (long) count);
- /*
- * I use CMD_UPDATE, because no CMD_MOVE or the like exists,
- * and I would like to provide the same kind of info as
- * CMD_UPDATE
- */
- UpdateCommandInfo(CMD_UPDATE, 0, estate->es_processed);
if (estate->es_processed > 0)
portal->atStart = false; /* OK to back up now */
if (count <= 0 || (int) estate->es_processed < count)
portal->atEnd = true; /* we retrieved 'em all */
+
+ if (completionTag)
+ snprintf(completionTag, COMPLETION_TAG_BUFSIZE, "%s %u",
+ (dest == None) ? "MOVE" : "FETCH",
+ estate->es_processed);
}
}
else
{
ExecutorRun(queryDesc, estate, EXEC_BACK, (long) count);
- /*
- * I use CMD_UPDATE, because no CMD_MOVE or the like exists,
- * and I would like to provide the same kind of info as
- * CMD_UPDATE
- */
- UpdateCommandInfo(CMD_UPDATE, 0, estate->es_processed);
if (estate->es_processed > 0)
portal->atEnd = false; /* OK to go forward now */
if (count <= 0 || (int) estate->es_processed < count)
portal->atStart = true; /* we retrieved 'em all */
+
+ if (completionTag)
+ snprintf(completionTag, COMPLETION_TAG_BUFSIZE, "%s %u",
+ (dest == None) ? "MOVE" : "FETCH",
+ estate->es_processed);
}
}
pfree(queryDesc);
MemoryContextSwitchTo(oldcontext);
-
- /*
- * Note: the "end-of-command" tag is returned by higher-level utility
- * code
- */
}
/* --------------------------------
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994-5, Regents of the University of California
*
- * $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.67 2001/10/25 05:49:25 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.68 2002/02/26 22:47:04 tgl Exp $
*
*/
plan->instrument = InstrAlloc();
gettimeofday(&starttime, NULL);
- ProcessQuery(query, plan, None);
+ ProcessQuery(query, plan, None, NULL);
CommandCounterIncrement();
gettimeofday(&endtime, NULL);
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.47 2001/10/28 06:25:43 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.48 2002/02/26 22:47:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/*
* Process a utility command. (create, destroy...) DZ - 30-8-1996
*/
- ProcessUtility(es->qd->parsetree->utilityStmt, es->qd->dest);
+ ProcessUtility(es->qd->parsetree->utilityStmt, es->qd->dest, NULL);
if (!LAST_POSTQUEL_COMMAND(es))
CommandCounterIncrement();
return (TupleTableSlot *) NULL;
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/spi.c,v 1.65 2002/02/14 15:24:08 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/spi.c,v 1.66 2002/02/26 22:47:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
res = SPI_OK_UTILITY;
if (plan == NULL)
{
- ProcessUtility(queryTree->utilityStmt, None);
+ ProcessUtility(queryTree->utilityStmt, None, NULL);
if (!islastquery)
CommandCounterIncrement();
else
if (queryTree->commandType == CMD_UTILITY)
{
- ProcessUtility(queryTree->utilityStmt, None);
+ ProcessUtility(queryTree->utilityStmt, None, NULL);
if (!islastquery)
CommandCounterIncrement();
else
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.162 2002/02/24 20:20:20 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.163 2002/02/26 22:47:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
newnode->isTemp = from->isTemp;
newnode->hasAggs = from->hasAggs;
newnode->hasSubLinks = from->hasSubLinks;
+ newnode->originalQuery = from->originalQuery;
Node_Copy(from, newnode, rtable);
Node_Copy(from, newnode, jointree);
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.110 2002/02/24 20:20:20 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.111 2002/02/26 22:47:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
return false;
if (a->hasSubLinks != b->hasSubLinks)
return false;
+ /* we deliberately ignore originalQuery */
if (!equal(a->rtable, b->rtable))
return false;
if (!equal(a->jointree, b->jointree))
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.113 2001/10/25 05:49:31 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.114 2002/02/26 22:47:07 tgl Exp $
*
* NOTES
* Most of the read functions for plan nodes are tested. (In fact, they
token = pg_strtok(&length); /* get hasSubLinks */
local_node->hasSubLinks = strtobool(token);
+ /* we always want originalQuery to be false in a read-in query */
+ local_node->originalQuery = false;
+
token = pg_strtok(&length); /* skip :rtable */
local_node->rtable = nodeRead(true);
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.214 2002/02/25 04:21:55 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.215 2002/02/26 22:47:08 tgl Exp $
*
*-------------------------------------------------------------------------
*/
{
List *result = NIL;
ParseState *pstate = make_parsestate(parentParseState);
- Query *query;
/* Lists to return extra commands from transformation */
- List *extras_before = NIL;
- List *extras_after = NIL;
+ List *extras_before = NIL;
+ List *extras_after = NIL;
+ Query *query;
+ List *listscan;
query = transformStmt(pstate, parseTree, &extras_before, &extras_after);
release_pstate_resources(pstate);
extras_after = lnext(extras_after);
}
+ /*
+ * Make sure that only the original query is marked original.
+ * We have to do this explicitly since recursive calls of parse_analyze
+ * will have set originalQuery in some of the added-on queries.
+ */
+ foreach(listscan, result)
+ {
+ Query *q = lfirst(listscan);
+
+ q->originalQuery = (q == query);
+ }
+
pfree(pstate);
return result;
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/tcop/dest.c,v 1.46 2001/10/28 06:25:51 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/tcop/dest.c,v 1.47 2002/02/26 22:47:08 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "libpq/pqformat.h"
-static char CommandInfo[32] = {0};
-
/* ----------------
* dummy DestReceiver functions
* ----------------
* if this is a "retrieve into portal" query, done because
* nothing needs to be sent to the fe.
*/
- CommandInfo[0] = '\0';
if (isIntoPortal)
break;
}
/* ----------------
- * EndCommand - tell destination that no more tuples will arrive
+ * EndCommand - tell destination that query is complete
* ----------------
*/
void
-EndCommand(char *commandTag, CommandDest dest)
+EndCommand(const char *commandTag, CommandDest dest)
{
- char buf[64];
-
switch (dest)
{
case Remote:
case RemoteInternal:
-
- /*
- * tell the fe that the query is over
- */
- sprintf(buf, "%s%s", commandTag, CommandInfo);
- pq_puttextmessage('C', buf);
- CommandInfo[0] = '\0';
+ pq_puttextmessage('C', commandTag);
break;
- case Debug:
case None:
- default:
+ case Debug:
+ case SPI:
break;
}
}
break;
}
}
-
-void
-UpdateCommandInfo(int operation, Oid lastoid, uint32 tuples)
-{
- switch (operation)
- {
- case CMD_INSERT:
- if (tuples > 1)
- lastoid = InvalidOid;
- sprintf(CommandInfo, " %u %u", lastoid, tuples);
- break;
- case CMD_DELETE:
- case CMD_UPDATE:
- sprintf(CommandInfo, " %u", tuples);
- break;
- default:
- CommandInfo[0] = '\0';
- break;
- }
-}
*
*
* 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
#include "pgstat.h"
+
/* ----------------
* global variables
* ----------------
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
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);
/* ----------------------------------------------------------------
{
Node *parsetree = (Node *) lfirst(parsetree_item);
bool isTransactionStmt;
+ const char *commandTag;
+ char completionTag[COMPLETION_TAG_BUFSIZE];
List *querytree_list,
*querytree_item;
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
/*
* 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).
*/
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
{
{
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)
} /* 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 */
/*
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");
}
/*
#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;
+}
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.46 2001/10/25 05:49:43 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.47 2002/02/26 22:47:09 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "utils/ps_status.h"
-static char *CreateOperationTag(int operationType);
-
-
/* ----------------------------------------------------------------
* CreateQueryDesc
* ----------------------------------------------------------------
return state;
}
-/* ----------------------------------------------------------------
- * CreateOperationTag
- *
- * utility to get a string representation of the
- * query operation.
- * ----------------------------------------------------------------
- */
-static char *
-CreateOperationTag(int operationType)
-{
- char *tag;
-
- switch (operationType)
- {
- case CMD_SELECT:
- tag = "SELECT";
- break;
- case CMD_INSERT:
- tag = "INSERT";
- break;
- case CMD_DELETE:
- tag = "DELETE";
- break;
- case CMD_UPDATE:
- tag = "UPDATE";
- break;
- default:
- elog(DEBUG, "CreateOperationTag: unknown operation type %d",
- operationType);
- tag = "???";
- break;
- }
-
- return tag;
-}
-
/* ----------------
* PreparePortal
* ----------------
}
-/* ----------------------------------------------------------------
- * ProcessQuery
+/*
+ * ProcessQuery
+ * Execute a query
*
- * Execute a plan, the non-parallel version
- * ----------------------------------------------------------------
+ * parsetree: the query tree
+ * plan: the plan tree for the query
+ * dest: where to send results
+ * completionTag: points to a buffer of size COMPLETION_TAG_BUFSIZE
+ * in which to store a command completion status string.
+ *
+ * completionTag may be NULL if caller doesn't want a status string.
*/
void
ProcessQuery(Query *parsetree,
Plan *plan,
- CommandDest dest)
+ CommandDest dest,
+ char *completionTag)
{
int operation = parsetree->commandType;
- char *tag;
bool isRetrieveIntoPortal;
bool isRetrieveIntoRelation;
char *intoName = NULL;
EState *state;
TupleDesc attinfo;
- set_ps_display(tag = CreateOperationTag(operation));
-
/*
* initialize portal/into relation status
*/
* When performing a retrieve into, we override the normal
* communication destination during the processing of the the query.
* This only affects the tuple-output function - the correct
- * destination will still see BeginCommand() and EndCommand()
- * messages.
+ * destination will still see the BeginCommand() call.
*/
if (isRetrieveIntoRelation)
queryDesc->dest = None;
attinfo,
isRetrieveIntoRelation,
isRetrieveIntoPortal,
- tag,
+ NULL, /* not used */
dest);
/*
/* Now we can return to caller's memory context. */
MemoryContextSwitchTo(oldContext);
- EndCommand(tag, dest);
+ /* Set completion tag. SQL calls this operation DECLARE CURSOR */
+ if (completionTag)
+ strcpy(completionTag, "DECLARE");
return;
}
*/
ExecutorRun(queryDesc, state, EXEC_RUN, 0L);
- /* save infos for EndCommand */
- UpdateCommandInfo(operation, state->es_lastoid, state->es_processed);
-
/*
- * Now, we close down all the scans and free allocated resources.
+ * Build command completion status string, if caller wants one.
*/
- ExecutorEnd(queryDesc, state);
+ if (completionTag)
+ {
+ Oid lastOid;
+
+ switch (operation)
+ {
+ case CMD_SELECT:
+ strcpy(completionTag, "SELECT");
+ break;
+ case CMD_INSERT:
+ if (state->es_processed == 1)
+ lastOid = state->es_lastoid;
+ else
+ lastOid = InvalidOid;
+ snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
+ "INSERT %u %u", lastOid, state->es_processed);
+ break;
+ case CMD_UPDATE:
+ snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
+ "UPDATE %u", state->es_processed);
+ break;
+ case CMD_DELETE:
+ snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
+ "DELETE %u", state->es_processed);
+ break;
+ default:
+ strcpy(completionTag, "???");
+ break;
+ }
+ }
/*
- * Notify the destination of end of processing.
+ * Now, we close down all the scans and free allocated resources.
*/
- EndCommand(tag, dest);
+ ExecutorEnd(queryDesc, state);
}
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.126 2002/02/24 20:20:20 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.127 2002/02/26 22:47:09 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "rewrite/rewriteRemove.h"
#include "tcop/utility.h"
#include "utils/acl.h"
-#include "utils/ps_status.h"
#include "utils/syscache.h"
#include "utils/temprel.h"
#include "access/xlog.h"
}
-/* ----------------
+/*
+ * ProcessUtility
* general utility function invoker
- * ----------------
+ *
+ * parsetree: the parse tree for the utility statement
+ * dest: where to send results
+ * completionTag: points to a buffer of size COMPLETION_TAG_BUFSIZE
+ * in which to store a command completion status string.
+ *
+ * completionTag is only set nonempty if we want to return a nondefault
+ * status (currently, only used for MOVE/FETCH).
+ *
+ * completionTag may be NULL if caller doesn't want a status string.
*/
void
ProcessUtility(Node *parsetree,
- CommandDest dest)
+ CommandDest dest,
+ char *completionTag)
{
- char *commandTag = NULL;
char *relname;
char *relationName;
+ if (completionTag)
+ completionTag[0] = '\0';
+
switch (nodeTag(parsetree))
{
/*
switch (stmt->command)
{
case BEGIN_TRANS:
- set_ps_display(commandTag = "BEGIN");
BeginTransactionBlock();
break;
case COMMIT:
- set_ps_display(commandTag = "COMMIT");
EndTransactionBlock();
break;
case ROLLBACK:
- set_ps_display(commandTag = "ROLLBACK");
UserAbortTransactionBlock();
break;
}
{
ClosePortalStmt *stmt = (ClosePortalStmt *) parsetree;
- set_ps_display(commandTag = "CLOSE");
-
PerformPortalClose(stmt->portalname, dest);
}
break;
bool forward;
int count;
- set_ps_display(commandTag = (stmt->ismove) ? "MOVE" : "FETCH");
-
SetQuerySnapshot();
forward = (bool) (stmt->direction == FORWARD);
*/
count = stmt->howMany;
- PerformPortalFetch(portalName, forward, count, commandTag,
- (stmt->ismove) ? None : dest); /* /dev/null for MOVE */
+ PerformPortalFetch(portalName, forward, count,
+ (stmt->ismove) ? None : dest,
+ completionTag);
}
break;
*
*/
case T_CreateStmt:
- set_ps_display(commandTag = "CREATE");
-
DefineRelation((CreateStmt *) parsetree, RELKIND_RELATION);
/*
List *args = stmt->names;
List *arg;
- set_ps_display(commandTag = "DROP");
-
foreach(arg, args)
{
relname = strVal(lfirst(arg));
{
Relation rel;
- set_ps_display(commandTag = "TRUNCATE");
-
relname = ((TruncateStmt *) parsetree)->relName;
if (!allowSystemTableMods && IsSystemRelationName(relname))
elog(ERROR, "TRUNCATE cannot be used on system tables. '%s' is a system table",
statement = ((CommentStmt *) parsetree);
- set_ps_display(commandTag = "COMMENT");
-
CommentObject(statement->objtype, statement->objname,
statement->objproperty, statement->objlist,
statement->comment);
{
CopyStmt *stmt = (CopyStmt *) parsetree;
- set_ps_display(commandTag = "COPY");
-
if (stmt->direction != FROM)
SetQuerySnapshot();
{
RenameStmt *stmt = (RenameStmt *) parsetree;
- set_ps_display(commandTag = "ALTER");
-
relname = stmt->relname;
if (!allowSystemTableMods && IsSystemRelationName(relname))
elog(ERROR, "ALTER TABLE: relation \"%s\" is a system catalog",
{
AlterTableStmt *stmt = (AlterTableStmt *) parsetree;
- set_ps_display(commandTag = "ALTER");
-
/*
* Some or all of these functions are recursive to cover
* inherited things, so permission checks are done there.
{
GrantStmt *stmt = (GrantStmt *) parsetree;
- commandTag = stmt->is_grant ? "GRANT" : "REVOKE";
- set_ps_display(commandTag);
-
ExecuteGrantStmt(stmt);
}
break;
{
DefineStmt *stmt = (DefineStmt *) parsetree;
- set_ps_display(commandTag = "CREATE");
-
switch (stmt->defType)
{
case OPERATOR:
{
ViewStmt *stmt = (ViewStmt *) parsetree;
- set_ps_display(commandTag = "CREATE");
-
DefineView(stmt->viewname, stmt->query); /* retrieve parsetree */
}
break;
case T_ProcedureStmt: /* CREATE FUNCTION */
- set_ps_display(commandTag = "CREATE");
-
CreateFunction((ProcedureStmt *) parsetree);
break;
{
IndexStmt *stmt = (IndexStmt *) parsetree;
- set_ps_display(commandTag = "CREATE");
-
relname = stmt->relname;
if (!allowSystemTableMods && IsSystemRelationName(relname))
elog(ERROR, "CREATE INDEX: relation \"%s\" is a system catalog",
aclcheck_result = pg_aclcheck(relname, GetUserId(), ACL_RULE);
if (aclcheck_result != ACLCHECK_OK)
elog(ERROR, "%s: %s", relname, aclcheck_error_strings[aclcheck_result]);
- set_ps_display(commandTag = "CREATE");
DefineQueryRewrite(stmt);
}
break;
case T_CreateSeqStmt:
- set_ps_display(commandTag = "CREATE");
-
DefineSequence((CreateSeqStmt *) parsetree);
break;
RemoveAggrStmt *stmt = (RemoveAggrStmt *) parsetree;
char *typename = (char *) NULL;
- set_ps_display(commandTag = "DROP");
-
if (stmt->aggtype != NULL)
typename = TypeNameToInternalName((TypeName *) stmt->aggtype);
{
RemoveFuncStmt *stmt = (RemoveFuncStmt *) parsetree;
- set_ps_display(commandTag = "DROP");
-
RemoveFunction(stmt->funcname, stmt->args);
}
break;
char *typename1 = (char *) NULL;
char *typename2 = (char *) NULL;
- set_ps_display(commandTag = "DROP");
-
if (typenode1 != NULL)
typename1 = TypeNameToInternalName(typenode1);
if (typenode2 != NULL)
{
CreatedbStmt *stmt = (CreatedbStmt *) parsetree;
- set_ps_display(commandTag = "CREATE DATABASE");
-
createdb(stmt->dbname, stmt->dbowner,
stmt->dbpath, stmt->dbtemplate,
stmt->encoding);
{
DropdbStmt *stmt = (DropdbStmt *) parsetree;
- set_ps_display(commandTag = "DROP DATABASE");
-
dropdb(stmt->dbname);
}
break;
{
NotifyStmt *stmt = (NotifyStmt *) parsetree;
- set_ps_display(commandTag = "NOTIFY");
-
Async_Notify(stmt->relname);
}
break;
{
ListenStmt *stmt = (ListenStmt *) parsetree;
- set_ps_display(commandTag = "LISTEN");
-
Async_Listen(stmt->relname, MyProcPid);
}
break;
{
UnlistenStmt *stmt = (UnlistenStmt *) parsetree;
- set_ps_display(commandTag = "UNLISTEN");
-
Async_Unlisten(stmt->relname, MyProcPid);
}
break;
{
LoadStmt *stmt = (LoadStmt *) parsetree;
- set_ps_display(commandTag = "LOAD");
-
closeAllVfds(); /* probably not necessary... */
load_file(stmt->filename);
}
{
ClusterStmt *stmt = (ClusterStmt *) parsetree;
- set_ps_display(commandTag = "CLUSTER");
-
relname = stmt->relname;
if (IsSystemRelationName(relname))
elog(ERROR, "CLUSTER: relation \"%s\" is a system catalog",
break;
case T_VacuumStmt:
- if (((VacuumStmt *) parsetree)->vacuum)
- commandTag = "VACUUM";
- else
- commandTag = "ANALYZE";
- set_ps_display(commandTag);
-
vacuum((VacuumStmt *) parsetree);
break;
{
ExplainStmt *stmt = (ExplainStmt *) parsetree;
- set_ps_display(commandTag = "EXPLAIN");
-
ExplainQuery(stmt->query, stmt->verbose, stmt->analyze, dest);
}
break;
{
RecipeStmt *stmt = (RecipeStmt *) parsetree;
- set_ps_display(commandTag = "EXECUTE RECIPE");
-
beginRecipe(stmt);
}
break;
VariableSetStmt *n = (VariableSetStmt *) parsetree;
SetPGVariable(n->name, n->args);
- set_ps_display(commandTag = "SET VARIABLE");
}
break;
VariableShowStmt *n = (VariableShowStmt *) parsetree;
GetPGVariable(n->name);
- set_ps_display(commandTag = "SHOW VARIABLE");
}
break;
VariableResetStmt *n = (VariableResetStmt *) parsetree;
ResetPGVariable(n->name);
- set_ps_display(commandTag = "RESET VARIABLE");
}
break;
* ******************************** TRIGGER statements *******************************
*/
case T_CreateTrigStmt:
- set_ps_display(commandTag = "CREATE");
-
CreateTrigger((CreateTrigStmt *) parsetree);
break;
case T_DropTrigStmt:
- set_ps_display(commandTag = "DROP");
-
DropTrigger((DropTrigStmt *) parsetree);
break;
* ************* PROCEDURAL LANGUAGE statements *****************
*/
case T_CreatePLangStmt:
- set_ps_display(commandTag = "CREATE");
-
CreateProceduralLanguage((CreatePLangStmt *) parsetree);
break;
case T_DropPLangStmt:
- set_ps_display(commandTag = "DROP");
-
DropProceduralLanguage((DropPLangStmt *) parsetree);
break;
*
*/
case T_CreateUserStmt:
- set_ps_display(commandTag = "CREATE USER");
-
CreateUser((CreateUserStmt *) parsetree);
break;
case T_AlterUserStmt:
- set_ps_display(commandTag = "ALTER USER");
-
AlterUser((AlterUserStmt *) parsetree);
break;
case T_DropUserStmt:
- set_ps_display(commandTag = "DROP USER");
-
DropUser((DropUserStmt *) parsetree);
break;
case T_LockStmt:
- set_ps_display(commandTag = "LOCK TABLE");
-
LockTableCommand((LockStmt *) parsetree);
break;
case T_ConstraintsSetStmt:
- set_ps_display(commandTag = "SET CONSTRAINTS");
-
DeferredTriggerSetState((ConstraintsSetStmt *) parsetree);
break;
case T_CreateGroupStmt:
- set_ps_display(commandTag = "CREATE GROUP");
-
CreateGroup((CreateGroupStmt *) parsetree);
break;
case T_AlterGroupStmt:
- set_ps_display(commandTag = "ALTER GROUP");
-
AlterGroup((AlterGroupStmt *) parsetree, "ALTER GROUP");
break;
case T_DropGroupStmt:
- set_ps_display(commandTag = "DROP GROUP");
-
DropGroup((DropGroupStmt *) parsetree);
break;
case T_CheckPointStmt:
{
- set_ps_display(commandTag = "CHECKPOINT");
-
if (!superuser())
elog(ERROR, "permission denied");
CreateCheckPoint(false);
{
ReindexStmt *stmt = (ReindexStmt *) parsetree;
- set_ps_display(commandTag = "REINDEX");
-
switch (stmt->reindexType)
{
case INDEX:
nodeTag(parsetree));
break;
}
-
- /*
- * tell fe/be or whatever that we're done.
- */
- EndCommand(commandTag, dest);
}
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: command.h,v 1.31 2001/11/05 17:46:33 momjian Exp $
+ * $Id: command.h,v 1.32 2002/02/26 22:47:10 tgl Exp $
*
*-------------------------------------------------------------------------
*/
* "ERROR" if portal not found.
*/
extern void PerformPortalFetch(char *name, bool forward, int count,
- char *tag, CommandDest dest);
+ CommandDest dest, char *completionTag);
/*
* PerformPortalClose
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: parsenodes.h,v 1.153 2002/02/24 20:20:21 tgl Exp $
+ * $Id: parsenodes.h,v 1.154 2002/02/26 22:47:10 tgl Exp $
*
*-------------------------------------------------------------------------
*/
bool hasAggs; /* has aggregates in tlist or havingQual */
bool hasSubLinks; /* has subquery SubLink */
+ bool originalQuery; /* marks original query through rewriting */
+
List *rtable; /* list of range table entries */
FromExpr *jointree; /* table join tree (FROM and WHERE
* clauses) */
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: dest.h,v 1.28 2001/11/05 17:46:36 momjian Exp $
+ * $Id: dest.h,v 1.29 2002/02/26 22:47:11 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "access/htup.h"
+
+/* buffer size to use for command completion tags */
+#define COMPLETION_TAG_BUFSIZE 64
+
+
/* ----------------
* CommandDest is a simplistic means of identifying the desired
* destination. Someday this will probably need to be improved.
bool isIntoRel, bool isIntoPortal, char *tag,
CommandDest dest);
extern DestReceiver *DestToFunction(CommandDest dest);
-extern void EndCommand(char *commandTag, CommandDest dest);
+extern void EndCommand(const char *commandTag, CommandDest dest);
/* Additional functions that go with destination management, more or less. */
extern void ReceiveCopyBegin(void);
extern void NullCommand(CommandDest dest);
extern void ReadyForQuery(CommandDest dest);
-extern void UpdateCommandInfo(int operation, Oid lastoid, uint32 tuples);
#endif /* DEST_H */
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: pquery.h,v 1.19 2001/11/05 17:46:36 momjian Exp $
+ * $Id: pquery.h,v 1.20 2002/02/26 22:47:12 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "utils/portal.h"
-extern void ProcessQuery(Query *parsetree, Plan *plan, CommandDest dest);
+extern void ProcessQuery(Query *parsetree, Plan *plan, CommandDest dest,
+ char *completionTag);
extern EState *CreateExecutorState(void);
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: utility.h,v 1.13 2001/11/05 17:46:36 momjian Exp $
+ * $Id: utility.h,v 1.14 2002/02/26 22:47:12 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "executor/execdesc.h"
-extern void ProcessUtility(Node *parsetree, CommandDest dest);
+extern void ProcessUtility(Node *parsetree, CommandDest dest,
+ char *completionTag);
#endif /* UTILITY_H */