mirror of
https://github.com/postgres/postgres.git
synced 2025-08-22 21:53:06 +03:00
Adjust handling of command status strings in the presence of rules,
as per recent pghackers discussions. initdb forced due to change in fields of stored Query nodes.
This commit is contained in:
@@ -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.213 2002/09/22 19:42:51 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.214 2002/10/14 22:14:34 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -1778,6 +1778,7 @@ _copyQuery(Query *from)
|
||||
Query *newnode = makeNode(Query);
|
||||
|
||||
newnode->commandType = from->commandType;
|
||||
newnode->querySource = from->querySource;
|
||||
Node_Copy(from, newnode, utilityStmt);
|
||||
newnode->resultRelation = from->resultRelation;
|
||||
Node_Copy(from, newnode, into);
|
||||
@@ -1785,7 +1786,6 @@ _copyQuery(Query *from)
|
||||
newnode->isBinary = from->isBinary;
|
||||
newnode->hasAggs = from->hasAggs;
|
||||
newnode->hasSubLinks = from->hasSubLinks;
|
||||
newnode->originalQuery = from->originalQuery;
|
||||
|
||||
Node_Copy(from, newnode, rtable);
|
||||
Node_Copy(from, newnode, jointree);
|
||||
|
@@ -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.160 2002/09/22 19:42:51 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.161 2002/10/14 22:14:34 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -573,6 +573,8 @@ _equalQuery(Query *a, Query *b)
|
||||
{
|
||||
if (a->commandType != b->commandType)
|
||||
return false;
|
||||
if (a->querySource != b->querySource)
|
||||
return false;
|
||||
if (!equal(a->utilityStmt, b->utilityStmt))
|
||||
return false;
|
||||
if (a->resultRelation != b->resultRelation)
|
||||
@@ -587,7 +589,6 @@ _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))
|
||||
|
@@ -5,7 +5,7 @@
|
||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.175 2002/09/22 19:42:51 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.176 2002/10/14 22:14:34 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* Every (plan) node in POSTGRES has an associated "out" routine which
|
||||
@@ -229,7 +229,8 @@ _outIndexElem(StringInfo str, IndexElem *node)
|
||||
static void
|
||||
_outQuery(StringInfo str, Query *node)
|
||||
{
|
||||
appendStringInfo(str, " QUERY :command %d :utility ", node->commandType);
|
||||
appendStringInfo(str, " QUERY :command %d :source %d :utility ",
|
||||
(int) node->commandType, (int) node->querySource);
|
||||
|
||||
/*
|
||||
* Hack to work around missing outfuncs routines for a lot of the
|
||||
@@ -299,6 +300,8 @@ _outQuery(StringInfo str, Query *node)
|
||||
|
||||
appendStringInfo(str, " :resultRelations ");
|
||||
_outIntList(str, node->resultRelations);
|
||||
|
||||
/* planner-internal fields are not written out */
|
||||
}
|
||||
|
||||
static void
|
||||
|
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.134 2002/09/22 19:42:51 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.135 2002/10/14 22:14:34 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* Most of the read functions for plan nodes are tested. (In fact, they
|
||||
@@ -123,6 +123,10 @@ _readQuery(void)
|
||||
token = pg_strtok(&length); /* get commandType */
|
||||
local_node->commandType = atoi(token);
|
||||
|
||||
token = pg_strtok(&length); /* skip :source */
|
||||
token = pg_strtok(&length); /* get querySource */
|
||||
local_node->querySource = atoi(token);
|
||||
|
||||
token = pg_strtok(&length); /* skip :utility */
|
||||
local_node->utilityStmt = nodeRead(true);
|
||||
|
||||
@@ -149,9 +153,6 @@ _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);
|
||||
|
||||
@@ -188,6 +189,8 @@ _readQuery(void)
|
||||
token = pg_strtok(&length); /* skip :resultRelations */
|
||||
local_node->resultRelations = toIntList(nodeRead(true));
|
||||
|
||||
/* planner-internal fields are left zero */
|
||||
|
||||
return local_node;
|
||||
}
|
||||
|
||||
|
@@ -6,7 +6,7 @@
|
||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.250 2002/09/22 00:37:09 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.251 2002/10/14 22:14:35 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -164,13 +164,13 @@ parse_analyze(Node *parseTree, ParseState *parentParseState)
|
||||
/*
|
||||
* 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.
|
||||
* have marked some of the added-on queries as "original".
|
||||
*/
|
||||
foreach(listscan, result)
|
||||
{
|
||||
Query *q = lfirst(listscan);
|
||||
|
||||
q->originalQuery = (q == query);
|
||||
q->querySource = (q == query ? QSRC_ORIGINAL : QSRC_PARSER);
|
||||
}
|
||||
|
||||
pfree(pstate);
|
||||
|
@@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.110 2002/09/18 21:35:22 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.111 2002/10/14 22:14:35 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -942,6 +942,7 @@ fireRules(Query *parsetree,
|
||||
RewriteRule *rule_lock = (RewriteRule *) lfirst(i);
|
||||
Node *event_qual;
|
||||
List *actions;
|
||||
QuerySource qsrc;
|
||||
List *r;
|
||||
|
||||
/* multiple rule action time */
|
||||
@@ -949,7 +950,18 @@ fireRules(Query *parsetree,
|
||||
event_qual = rule_lock->qual;
|
||||
actions = rule_lock->actions;
|
||||
|
||||
if (event_qual != NULL && *instead_flag)
|
||||
/* Determine correct QuerySource value for actions */
|
||||
if (rule_lock->isInstead)
|
||||
{
|
||||
if (event_qual != NULL)
|
||||
qsrc = QSRC_QUAL_INSTEAD_RULE;
|
||||
else
|
||||
qsrc = QSRC_INSTEAD_RULE;
|
||||
}
|
||||
else
|
||||
qsrc = QSRC_NON_INSTEAD_RULE;
|
||||
|
||||
if (qsrc == QSRC_QUAL_INSTEAD_RULE)
|
||||
{
|
||||
Query *qual_product;
|
||||
|
||||
@@ -976,6 +988,7 @@ fireRules(Query *parsetree,
|
||||
*qual_products = makeList1(qual_product);
|
||||
}
|
||||
|
||||
/* Now process the rule's actions and add them to the result list */
|
||||
foreach(r, actions)
|
||||
{
|
||||
Query *rule_action = lfirst(r);
|
||||
@@ -986,6 +999,8 @@ fireRules(Query *parsetree,
|
||||
rule_action = rewriteRuleAction(parsetree, rule_action,
|
||||
event_qual, rt_index, event);
|
||||
|
||||
rule_action->querySource = qsrc;
|
||||
|
||||
results = lappend(results, rule_action);
|
||||
}
|
||||
|
||||
@@ -993,9 +1008,10 @@ fireRules(Query *parsetree,
|
||||
* If this was an unqualified instead rule, throw away an
|
||||
* eventually saved 'default' parsetree
|
||||
*/
|
||||
if (event_qual == NULL && *instead_flag)
|
||||
if (qsrc == QSRC_INSTEAD_RULE)
|
||||
*qual_products = NIL;
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
|
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.301 2002/10/13 16:55:05 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.302 2002/10/14 22:14:35 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* this is the "main" module of the postgres backend and
|
||||
@@ -621,6 +621,8 @@ pg_exec_query_string(StringInfo query_string, /* string to execute */
|
||||
Node *parsetree = (Node *) lfirst(parsetree_item);
|
||||
const char *commandTag;
|
||||
char completionTag[COMPLETION_TAG_BUFSIZE];
|
||||
CmdType origCmdType;
|
||||
bool foundOriginalQuery = false;
|
||||
List *querytree_list,
|
||||
*querytree_item;
|
||||
|
||||
@@ -632,6 +634,26 @@ pg_exec_query_string(StringInfo query_string, /* string to execute */
|
||||
*/
|
||||
commandTag = CreateCommandTag(parsetree);
|
||||
|
||||
switch (nodeTag(parsetree))
|
||||
{
|
||||
case T_InsertStmt:
|
||||
origCmdType = CMD_INSERT;
|
||||
break;
|
||||
case T_DeleteStmt:
|
||||
origCmdType = CMD_DELETE;
|
||||
break;
|
||||
case T_UpdateStmt:
|
||||
origCmdType = CMD_UPDATE;
|
||||
break;
|
||||
case T_SelectStmt:
|
||||
origCmdType = CMD_SELECT;
|
||||
break;
|
||||
default:
|
||||
/* Otherwise, never match commandType */
|
||||
origCmdType = CMD_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
|
||||
set_ps_display(commandTag);
|
||||
|
||||
BeginCommand(commandTag, dest);
|
||||
@@ -694,6 +716,7 @@ pg_exec_query_string(StringInfo query_string, /* string to execute */
|
||||
{
|
||||
Query *querytree = (Query *) lfirst(querytree_item);
|
||||
bool endTransactionBlock = false;
|
||||
bool canSetTag;
|
||||
|
||||
/* Make sure we are in a transaction command */
|
||||
if (!xact_started)
|
||||
@@ -708,6 +731,24 @@ pg_exec_query_string(StringInfo query_string, /* string to execute */
|
||||
*/
|
||||
CHECK_FOR_INTERRUPTS();
|
||||
|
||||
/*
|
||||
* This query can set the completion tag if it is the original
|
||||
* query, or if it is an INSTEAD query of the same kind as the
|
||||
* original and we haven't yet seen the original query.
|
||||
*/
|
||||
if (querytree->querySource == QSRC_ORIGINAL)
|
||||
{
|
||||
canSetTag = true;
|
||||
foundOriginalQuery = true;
|
||||
}
|
||||
else if (!foundOriginalQuery &&
|
||||
querytree->commandType == origCmdType &&
|
||||
(querytree->querySource == QSRC_INSTEAD_RULE ||
|
||||
querytree->querySource == QSRC_QUAL_INSTEAD_RULE))
|
||||
canSetTag = true;
|
||||
else
|
||||
canSetTag = false;
|
||||
|
||||
if (querytree->commandType == CMD_UTILITY)
|
||||
{
|
||||
/*
|
||||
@@ -736,7 +777,7 @@ pg_exec_query_string(StringInfo query_string, /* string to execute */
|
||||
IsA(utilityStmt, VariableResetStmt))
|
||||
endTransactionBlock = true;
|
||||
|
||||
if (querytree->originalQuery)
|
||||
if (canSetTag)
|
||||
{
|
||||
/* utility statement can override default tag string */
|
||||
ProcessUtility(utilityStmt, dest, completionTag);
|
||||
@@ -785,9 +826,9 @@ pg_exec_query_string(StringInfo query_string, /* string to execute */
|
||||
{
|
||||
elog(DEBUG2, "ProcessQuery");
|
||||
|
||||
if (querytree->originalQuery || length(querytree_list) == 1)
|
||||
if (canSetTag)
|
||||
{
|
||||
/* original stmt can override default tag string */
|
||||
/* statement can override default tag string */
|
||||
ProcessQuery(querytree, plan, dest, completionTag);
|
||||
commandTag = completionTag;
|
||||
}
|
||||
@@ -853,17 +894,21 @@ pg_exec_query_string(StringInfo query_string, /* string to execute */
|
||||
|
||||
/*
|
||||
* 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
|
||||
* INSTEAD rewrite rule. If so, and if we found no INSTEAD query
|
||||
* matching the command type, we will still have the default
|
||||
* completion tag. This 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";
|
||||
if (!foundOriginalQuery)
|
||||
{
|
||||
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
|
||||
@@ -1724,7 +1769,7 @@ PostgresMain(int argc, char *argv[], const char *username)
|
||||
if (!IsUnderPostmaster)
|
||||
{
|
||||
puts("\nPOSTGRES backend interactive interface ");
|
||||
puts("$Revision: 1.301 $ $Date: 2002/10/13 16:55:05 $\n");
|
||||
puts("$Revision: 1.302 $ $Date: 2002/10/14 22:14:35 $\n");
|
||||
}
|
||||
|
||||
/*
|
||||
|
Reference in New Issue
Block a user