Back-patch fix for command completion report handling. This is

primarily needed so that INSERTing a row still reports the row's OID
even when there are ON INSERT rules firing additional queries.
This commit is contained in:
Tom Lane 2002-02-26 23:48:47 +00:00
parent 5fb5066cb6
commit 75c07d5b4d
17 changed files with 501 additions and 269 deletions

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.153 2002/02/14 15:24:06 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.153.2.1 2002/02/26 23:48:37 tgl Exp $
*
* NOTES
* The PerformAddAttribute() code, like most of the relation
@ -88,16 +88,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;
@ -106,6 +115,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
*/
@ -166,7 +179,7 @@ PerformPortalFetch(char *name,
* relations */
false, /* this is a portal fetch, not a "retrieve
* portal" */
tag,
NULL, /* not used */
queryDesc->dest);
/*
@ -192,16 +205,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
@ -210,16 +222,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);
}
}
@ -235,11 +246,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.67.2.1 2002/02/26 23:48:38 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.47.2.1 2002/02/26 23:48:39 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.65.2.1 2002/02/26 23:48:40 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.160 2001/11/05 05:00:14 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.160.2.1 2002/02/26 23:48:41 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.108 2001/11/05 05:00:14 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.108.2.1 2002/02/26 23:48:42 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.113.2.1 2002/02/26 23:48:42 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.213 2002/01/03 23:21:31 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.213.2.1 2002/02/26 23:48:43 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -121,6 +121,7 @@ parse_analyze(Node *parseTree, ParseState *parentParseState)
List *result = NIL;
ParseState *pstate = make_parsestate(parentParseState);
Query *query;
List *listscan;
extras_before = extras_after = NIL;
@ -145,6 +146,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.46.2.1 2002/02/26 23:48:45 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.245 2002/01/10 01:11:45 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.245.2.1 2002/02/26 23:48:45 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.245 $ $Date: 2002/01/10 01:11:45 $\n");
puts("$Revision: 1.245.2.1 $ $Date: 2002/02/26 23:48:45 $\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.46.2.1 2002/02/26 23:48:45 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.125 2002/02/07 00:27:30 inoue Exp $
* $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.125.2.1 2002/02/26 23:48:46 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->dbpath,
stmt->dbtemplate, stmt->encoding);
}
@ -633,8 +603,6 @@ ProcessUtility(Node *parsetree,
{
DropdbStmt *stmt = (DropdbStmt *) parsetree;
set_ps_display(commandTag = "DROP DATABASE");
dropdb(stmt->dbname);
}
break;
@ -644,8 +612,6 @@ ProcessUtility(Node *parsetree,
{
NotifyStmt *stmt = (NotifyStmt *) parsetree;
set_ps_display(commandTag = "NOTIFY");
Async_Notify(stmt->relname);
}
break;
@ -654,8 +620,6 @@ ProcessUtility(Node *parsetree,
{
ListenStmt *stmt = (ListenStmt *) parsetree;
set_ps_display(commandTag = "LISTEN");
Async_Listen(stmt->relname, MyProcPid);
}
break;
@ -664,8 +628,6 @@ ProcessUtility(Node *parsetree,
{
UnlistenStmt *stmt = (UnlistenStmt *) parsetree;
set_ps_display(commandTag = "UNLISTEN");
Async_Unlisten(stmt->relname, MyProcPid);
}
break;
@ -678,8 +640,6 @@ ProcessUtility(Node *parsetree,
{
LoadStmt *stmt = (LoadStmt *) parsetree;
set_ps_display(commandTag = "LOAD");
closeAllVfds(); /* probably not necessary... */
load_file(stmt->filename);
}
@ -689,8 +649,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",
@ -703,12 +661,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;
@ -716,8 +668,6 @@ ProcessUtility(Node *parsetree,
{
ExplainStmt *stmt = (ExplainStmt *) parsetree;
set_ps_display(commandTag = "EXPLAIN");
ExplainQuery(stmt->query, stmt->verbose, stmt->analyze, dest);
}
break;
@ -731,8 +681,6 @@ ProcessUtility(Node *parsetree,
{
RecipeStmt *stmt = (RecipeStmt *) parsetree;
set_ps_display(commandTag = "EXECUTE RECIPE");
beginRecipe(stmt);
}
break;
@ -746,7 +694,6 @@ ProcessUtility(Node *parsetree,
VariableSetStmt *n = (VariableSetStmt *) parsetree;
SetPGVariable(n->name, n->args);
set_ps_display(commandTag = "SET VARIABLE");
}
break;
@ -755,7 +702,6 @@ ProcessUtility(Node *parsetree,
VariableShowStmt *n = (VariableShowStmt *) parsetree;
GetPGVariable(n->name);
set_ps_display(commandTag = "SHOW VARIABLE");
}
break;
@ -764,7 +710,6 @@ ProcessUtility(Node *parsetree,
VariableResetStmt *n = (VariableResetStmt *) parsetree;
ResetPGVariable(n->name);
set_ps_display(commandTag = "RESET VARIABLE");
}
break;
@ -772,14 +717,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;
@ -787,14 +728,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;
@ -803,57 +740,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);
@ -864,8 +783,6 @@ ProcessUtility(Node *parsetree,
{
ReindexStmt *stmt = (ReindexStmt *) parsetree;
set_ps_display(commandTag = "REINDEX");
switch (stmt->reindexType)
{
case INDEX:
@ -911,9 +828,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.31.2.1 2002/02/26 23:48:46 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.151 2001/11/05 17:46:34 momjian Exp $
* $Id: parsenodes.h,v 1.151.2.1 2002/02/26 23:48:46 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.28.2.1 2002/02/26 23:48:47 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.19.2.1 2002/02/26 23:48:47 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.13.2.1 2002/02/26 23:48:47 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 */