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.
This commit is contained in:
Tom Lane 2002-02-26 22:47:12 +00:00
parent f71dc6d0e2
commit 56ee2ecba9
17 changed files with 504 additions and 272 deletions

View File

@ -8,7 +8,7 @@
*
*
* 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
@ -89,16 +89,25 @@ PortalCleanup(Portal portal)
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;
@ -107,6 +116,10 @@ PerformPortalFetch(char *name,
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
*/
@ -167,7 +180,7 @@ PerformPortalFetch(char *name,
* relations */
false, /* this is a portal fetch, not a "retrieve
* portal" */
tag,
NULL, /* not used */
queryDesc->dest);
/*
@ -193,16 +206,15 @@ PerformPortalFetch(char *name,
{
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
@ -211,16 +223,15 @@ PerformPortalFetch(char *name,
{
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);
}
}
@ -236,11 +247,6 @@ PerformPortalFetch(char *name,
pfree(queryDesc);
MemoryContextSwitchTo(oldcontext);
/*
* Note: the "end-of-command" tag is returned by higher-level utility
* code
*/
}
/* --------------------------------

View File

@ -5,7 +5,7 @@
* 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 $
*
*/
@ -120,7 +120,7 @@ ExplainOneQuery(Query *query, bool verbose, bool analyze, CommandDest dest)
plan->instrument = InstrAlloc();
gettimeofday(&starttime, NULL);
ProcessQuery(query, plan, None);
ProcessQuery(query, plan, None, NULL);
CommandCounterIncrement();
gettimeofday(&endtime, NULL);

View File

@ -8,7 +8,7 @@
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
@ -275,7 +275,7 @@ postquel_getnext(execution_state *es)
/*
* 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;

View File

@ -8,7 +8,7 @@
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
@ -1011,7 +1011,7 @@ _SPI_execute(char *src, int tcount, _SPI_plan *plan)
res = SPI_OK_UTILITY;
if (plan == NULL)
{
ProcessUtility(queryTree->utilityStmt, None);
ProcessUtility(queryTree->utilityStmt, None, NULL);
if (!islastquery)
CommandCounterIncrement();
else
@ -1085,7 +1085,7 @@ _SPI_execute_plan(_SPI_plan *plan, Datum *Values, char *Nulls, int tcount)
if (queryTree->commandType == CMD_UTILITY)
{
ProcessUtility(queryTree->utilityStmt, None);
ProcessUtility(queryTree->utilityStmt, None, NULL);
if (!islastquery)
CommandCounterIncrement();
else

View File

@ -15,7 +15,7 @@
* 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 $
*
*-------------------------------------------------------------------------
*/
@ -1755,6 +1755,7 @@ _copyQuery(Query *from)
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);

View File

@ -20,7 +20,7 @@
* 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 $
*
*-------------------------------------------------------------------------
*/
@ -593,6 +593,7 @@ _equalQuery(Query *a, Query *b)
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))

View File

@ -8,7 +8,7 @@
*
*
* 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
@ -168,6 +168,9 @@ _readQuery(void)
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);

View File

@ -6,7 +6,7 @@
* 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 $
*
*-------------------------------------------------------------------------
*/
@ -122,10 +122,11 @@ parse_analyze(Node *parseTree, ParseState *parentParseState)
{
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);
@ -144,6 +145,18 @@ parse_analyze(Node *parseTree, ParseState *parentParseState)
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;

View File

@ -8,7 +8,7 @@
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
@ -41,8 +41,6 @@
#include "libpq/pqformat.h"
static char CommandInfo[32] = {0};
/* ----------------
* dummy DestReceiver functions
* ----------------
@ -102,7 +100,6 @@ BeginCommand(char *pname,
* if this is a "retrieve into portal" query, done because
* nothing needs to be sent to the fe.
*/
CommandInfo[0] = '\0';
if (isIntoPortal)
break;
@ -198,30 +195,22 @@ DestToFunction(CommandDest dest)
}
/* ----------------
* 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;
}
}
@ -317,23 +306,3 @@ ReadyForQuery(CommandDest dest)
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;
}
}

View File

@ -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;
}

View File

@ -8,7 +8,7 @@
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
@ -23,9 +23,6 @@
#include "utils/ps_status.h"
static char *CreateOperationTag(int operationType);
/* ----------------------------------------------------------------
* CreateQueryDesc
* ----------------------------------------------------------------
@ -89,42 +86,6 @@ CreateExecutorState(void)
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
* ----------------
@ -158,19 +119,25 @@ PreparePortal(char *portalName)
}
/* ----------------------------------------------------------------
* 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;
@ -180,8 +147,6 @@ ProcessQuery(Query *parsetree,
EState *state;
TupleDesc attinfo;
set_ps_display(tag = CreateOperationTag(operation));
/*
* initialize portal/into relation status
*/
@ -238,8 +203,7 @@ ProcessQuery(Query *parsetree,
* 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;
@ -263,7 +227,7 @@ ProcessQuery(Query *parsetree,
attinfo,
isRetrieveIntoRelation,
isRetrieveIntoPortal,
tag,
NULL, /* not used */
dest);
/*
@ -281,7 +245,9 @@ ProcessQuery(Query *parsetree,
/* 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;
}
@ -292,16 +258,42 @@ ProcessQuery(Query *parsetree,
*/
ExecutorRun(queryDesc, state, EXEC_RUN, 0L);
/* save infos for EndCommand */
UpdateCommandInfo(operation, state->es_lastoid, state->es_processed);
/*
* Build command completion status string, if caller wants one.
*/
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;
}
}
/*
* Now, we close down all the scans and free allocated resources.
*/
ExecutorEnd(queryDesc, state);
/*
* Notify the destination of end of processing.
*/
EndCommand(tag, dest);
}

View File

@ -10,7 +10,7 @@
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
@ -44,7 +44,6 @@
#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"
@ -130,18 +129,31 @@ CheckDropPermissions(char *name, char rightkind)
}
/* ----------------
/*
* 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))
{
/*
@ -155,17 +167,14 @@ ProcessUtility(Node *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;
}
@ -180,8 +189,6 @@ ProcessUtility(Node *parsetree,
{
ClosePortalStmt *stmt = (ClosePortalStmt *) parsetree;
set_ps_display(commandTag = "CLOSE");
PerformPortalClose(stmt->portalname, dest);
}
break;
@ -193,8 +200,6 @@ ProcessUtility(Node *parsetree,
bool forward;
int count;
set_ps_display(commandTag = (stmt->ismove) ? "MOVE" : "FETCH");
SetQuerySnapshot();
forward = (bool) (stmt->direction == FORWARD);
@ -204,8 +209,9 @@ ProcessUtility(Node *parsetree,
*/
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;
@ -215,8 +221,6 @@ ProcessUtility(Node *parsetree,
*
*/
case T_CreateStmt:
set_ps_display(commandTag = "CREATE");
DefineRelation((CreateStmt *) parsetree, RELKIND_RELATION);
/*
@ -234,8 +238,6 @@ ProcessUtility(Node *parsetree,
List *args = stmt->names;
List *arg;
set_ps_display(commandTag = "DROP");
foreach(arg, args)
{
relname = strVal(lfirst(arg));
@ -296,8 +298,6 @@ ProcessUtility(Node *parsetree,
{
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",
@ -325,8 +325,6 @@ ProcessUtility(Node *parsetree,
statement = ((CommentStmt *) parsetree);
set_ps_display(commandTag = "COMMENT");
CommentObject(statement->objtype, statement->objname,
statement->objproperty, statement->objlist,
statement->comment);
@ -337,8 +335,6 @@ ProcessUtility(Node *parsetree,
{
CopyStmt *stmt = (CopyStmt *) parsetree;
set_ps_display(commandTag = "COPY");
if (stmt->direction != FROM)
SetQuerySnapshot();
@ -365,8 +361,6 @@ ProcessUtility(Node *parsetree,
{
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",
@ -413,8 +407,6 @@ ProcessUtility(Node *parsetree,
{
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.
@ -475,9 +467,6 @@ ProcessUtility(Node *parsetree,
{
GrantStmt *stmt = (GrantStmt *) parsetree;
commandTag = stmt->is_grant ? "GRANT" : "REVOKE";
set_ps_display(commandTag);
ExecuteGrantStmt(stmt);
}
break;
@ -491,8 +480,6 @@ ProcessUtility(Node *parsetree,
{
DefineStmt *stmt = (DefineStmt *) parsetree;
set_ps_display(commandTag = "CREATE");
switch (stmt->defType)
{
case OPERATOR:
@ -514,15 +501,11 @@ ProcessUtility(Node *parsetree,
{
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;
@ -530,8 +513,6 @@ ProcessUtility(Node *parsetree,
{
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",
@ -559,15 +540,12 @@ ProcessUtility(Node *parsetree,
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;
@ -576,8 +554,6 @@ ProcessUtility(Node *parsetree,
RemoveAggrStmt *stmt = (RemoveAggrStmt *) parsetree;
char *typename = (char *) NULL;
set_ps_display(commandTag = "DROP");
if (stmt->aggtype != NULL)
typename = TypeNameToInternalName((TypeName *) stmt->aggtype);
@ -589,8 +565,6 @@ ProcessUtility(Node *parsetree,
{
RemoveFuncStmt *stmt = (RemoveFuncStmt *) parsetree;
set_ps_display(commandTag = "DROP");
RemoveFunction(stmt->funcname, stmt->args);
}
break;
@ -603,8 +577,6 @@ ProcessUtility(Node *parsetree,
char *typename1 = (char *) NULL;
char *typename2 = (char *) NULL;
set_ps_display(commandTag = "DROP");
if (typenode1 != NULL)
typename1 = TypeNameToInternalName(typenode1);
if (typenode2 != NULL)
@ -622,8 +594,6 @@ ProcessUtility(Node *parsetree,
{
CreatedbStmt *stmt = (CreatedbStmt *) parsetree;
set_ps_display(commandTag = "CREATE DATABASE");
createdb(stmt->dbname, stmt->dbowner,
stmt->dbpath, stmt->dbtemplate,
stmt->encoding);
@ -634,8 +604,6 @@ ProcessUtility(Node *parsetree,
{
DropdbStmt *stmt = (DropdbStmt *) parsetree;
set_ps_display(commandTag = "DROP DATABASE");
dropdb(stmt->dbname);
}
break;
@ -645,8 +613,6 @@ ProcessUtility(Node *parsetree,
{
NotifyStmt *stmt = (NotifyStmt *) parsetree;
set_ps_display(commandTag = "NOTIFY");
Async_Notify(stmt->relname);
}
break;
@ -655,8 +621,6 @@ ProcessUtility(Node *parsetree,
{
ListenStmt *stmt = (ListenStmt *) parsetree;
set_ps_display(commandTag = "LISTEN");
Async_Listen(stmt->relname, MyProcPid);
}
break;
@ -665,8 +629,6 @@ ProcessUtility(Node *parsetree,
{
UnlistenStmt *stmt = (UnlistenStmt *) parsetree;
set_ps_display(commandTag = "UNLISTEN");
Async_Unlisten(stmt->relname, MyProcPid);
}
break;
@ -679,8 +641,6 @@ ProcessUtility(Node *parsetree,
{
LoadStmt *stmt = (LoadStmt *) parsetree;
set_ps_display(commandTag = "LOAD");
closeAllVfds(); /* probably not necessary... */
load_file(stmt->filename);
}
@ -690,8 +650,6 @@ ProcessUtility(Node *parsetree,
{
ClusterStmt *stmt = (ClusterStmt *) parsetree;
set_ps_display(commandTag = "CLUSTER");
relname = stmt->relname;
if (IsSystemRelationName(relname))
elog(ERROR, "CLUSTER: relation \"%s\" is a system catalog",
@ -704,12 +662,6 @@ ProcessUtility(Node *parsetree,
break;
case T_VacuumStmt:
if (((VacuumStmt *) parsetree)->vacuum)
commandTag = "VACUUM";
else
commandTag = "ANALYZE";
set_ps_display(commandTag);
vacuum((VacuumStmt *) parsetree);
break;
@ -717,8 +669,6 @@ ProcessUtility(Node *parsetree,
{
ExplainStmt *stmt = (ExplainStmt *) parsetree;
set_ps_display(commandTag = "EXPLAIN");
ExplainQuery(stmt->query, stmt->verbose, stmt->analyze, dest);
}
break;
@ -732,8 +682,6 @@ ProcessUtility(Node *parsetree,
{
RecipeStmt *stmt = (RecipeStmt *) parsetree;
set_ps_display(commandTag = "EXECUTE RECIPE");
beginRecipe(stmt);
}
break;
@ -747,7 +695,6 @@ ProcessUtility(Node *parsetree,
VariableSetStmt *n = (VariableSetStmt *) parsetree;
SetPGVariable(n->name, n->args);
set_ps_display(commandTag = "SET VARIABLE");
}
break;
@ -756,7 +703,6 @@ ProcessUtility(Node *parsetree,
VariableShowStmt *n = (VariableShowStmt *) parsetree;
GetPGVariable(n->name);
set_ps_display(commandTag = "SHOW VARIABLE");
}
break;
@ -765,7 +711,6 @@ ProcessUtility(Node *parsetree,
VariableResetStmt *n = (VariableResetStmt *) parsetree;
ResetPGVariable(n->name);
set_ps_display(commandTag = "RESET VARIABLE");
}
break;
@ -773,14 +718,10 @@ ProcessUtility(Node *parsetree,
* ******************************** 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;
@ -788,14 +729,10 @@ ProcessUtility(Node *parsetree,
* ************* 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;
@ -804,57 +741,39 @@ ProcessUtility(Node *parsetree,
*
*/
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);
@ -865,8 +784,6 @@ ProcessUtility(Node *parsetree,
{
ReindexStmt *stmt = (ReindexStmt *) parsetree;
set_ps_display(commandTag = "REINDEX");
switch (stmt->reindexType)
{
case INDEX:
@ -912,9 +829,4 @@ ProcessUtility(Node *parsetree,
nodeTag(parsetree));
break;
}
/*
* tell fe/be or whatever that we're done.
*/
EndCommand(commandTag, dest);
}

View File

@ -7,7 +7,7 @@
* 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 $
*
*-------------------------------------------------------------------------
*/
@ -27,7 +27,7 @@
* "ERROR" if portal not found.
*/
extern void PerformPortalFetch(char *name, bool forward, int count,
char *tag, CommandDest dest);
CommandDest dest, char *completionTag);
/*
* PerformPortalClose

View File

@ -7,7 +7,7 @@
* 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 $
*
*-------------------------------------------------------------------------
*/
@ -48,6 +48,8 @@ typedef struct Query
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) */

View File

@ -39,7 +39,7 @@
* 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 $
*
*-------------------------------------------------------------------------
*/
@ -48,6 +48,11 @@
#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.
@ -88,7 +93,7 @@ extern void BeginCommand(char *pname, int operation, TupleDesc attinfo,
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. */
@ -96,6 +101,5 @@ extern void SendCopyBegin(void);
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 */

View File

@ -7,7 +7,7 @@
* 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 $
*
*-------------------------------------------------------------------------
*/
@ -18,7 +18,8 @@
#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);

View File

@ -7,7 +7,7 @@
* 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 $
*
*-------------------------------------------------------------------------
*/
@ -16,6 +16,7 @@
#include "executor/execdesc.h"
extern void ProcessUtility(Node *parsetree, CommandDest dest);
extern void ProcessUtility(Node *parsetree, CommandDest dest,
char *completionTag);
#endif /* UTILITY_H */