Commit a51f004d authored by Tom Lane's avatar Tom Lane

Repair breakage of rules containing INSERT ... SELECT actions, per bug

report from Joel Burton.  Turns out that my simple idea of turning the
SELECT into a subquery does not interact well *at all* with the way the
rule rewriter works.  Really what we need to make INSERT ... SELECT work
cleanly is to decouple targetlists from rangetables: an INSERT ... SELECT
wants to have two levels of targetlist but only one rangetable.  No time
for that for 7.1, however, so I've inserted some ugly hacks to make the
rewriter know explicitly about the structure of INSERT ... SELECT queries.
Ugh :-(
parent d9466046
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: analyze.c,v 1.168 2000/11/24 20:16:39 petere Exp $ * $Id: analyze.c,v 1.169 2000/12/05 19:15:10 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -312,7 +312,7 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt) ...@@ -312,7 +312,7 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
*/ */
if (stmt->selectStmt) if (stmt->selectStmt)
{ {
List *selectList; ParseState *sub_pstate = make_parsestate(pstate->parentParseState);
Query *selectQuery; Query *selectQuery;
RangeTblEntry *rte; RangeTblEntry *rte;
RangeTblRef *rtr; RangeTblRef *rtr;
...@@ -324,11 +324,18 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt) ...@@ -324,11 +324,18 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
* otherwise the behavior of SELECT within INSERT might be different * otherwise the behavior of SELECT within INSERT might be different
* from a stand-alone SELECT. (Indeed, Postgres up through 6.5 had * from a stand-alone SELECT. (Indeed, Postgres up through 6.5 had
* bugs of just that nature...) * bugs of just that nature...)
*
* If a non-nil rangetable was passed in, pass it down to the SELECT.
* This can only happen if we are inside a CREATE RULE, and in that
* case we want the rule's OLD and NEW rtable entries to appear as
* part of the SELECT's rtable, not as outer references for it.
*/ */
selectList = parse_analyze(stmt->selectStmt, pstate); sub_pstate->p_rtable = pstate->p_rtable;
Assert(length(selectList) == 1); pstate->p_rtable = NIL;
selectQuery = transformStmt(sub_pstate, stmt->selectStmt);
release_pstate_resources(sub_pstate);
pfree(sub_pstate);
selectQuery = (Query *) lfirst(selectList);
Assert(IsA(selectQuery, Query)); Assert(IsA(selectQuery, Query));
Assert(selectQuery->commandType == CMD_SELECT); Assert(selectQuery->commandType == CMD_SELECT);
if (selectQuery->into || selectQuery->isPortal) if (selectQuery->into || selectQuery->isPortal)
...@@ -1587,7 +1594,8 @@ transformRuleStmt(ParseState *pstate, RuleStmt *stmt) ...@@ -1587,7 +1594,8 @@ transformRuleStmt(ParseState *pstate, RuleStmt *stmt)
foreach(actions, stmt->actions) foreach(actions, stmt->actions)
{ {
ParseState *sub_pstate = make_parsestate(pstate->parentParseState); ParseState *sub_pstate = make_parsestate(pstate->parentParseState);
Query *sub_qry; Query *sub_qry,
*top_subqry;
bool has_old, bool has_old,
has_new; has_new;
...@@ -1608,7 +1616,14 @@ transformRuleStmt(ParseState *pstate, RuleStmt *stmt) ...@@ -1608,7 +1616,14 @@ transformRuleStmt(ParseState *pstate, RuleStmt *stmt)
newrte->checkForRead = false; newrte->checkForRead = false;
/* Transform the rule action statement */ /* Transform the rule action statement */
sub_qry = transformStmt(sub_pstate, lfirst(actions)); top_subqry = transformStmt(sub_pstate, lfirst(actions));
/*
* If the action is INSERT...SELECT, OLD/NEW have been pushed
* down into the SELECT, and that's what we need to look at.
* (Ugly kluge ... try to fix this when we redesign querytrees.)
*/
sub_qry = getInsertSelectQuery(top_subqry, NULL);
/* /*
* Validate action's use of OLD/NEW, qual too * Validate action's use of OLD/NEW, qual too
...@@ -1648,15 +1663,28 @@ transformRuleStmt(ParseState *pstate, RuleStmt *stmt) ...@@ -1648,15 +1663,28 @@ transformRuleStmt(ParseState *pstate, RuleStmt *stmt)
/* /*
* For efficiency's sake, add OLD to the rule action's jointree * For efficiency's sake, add OLD to the rule action's jointree
* only if it was actually referenced in the statement or qual. * only if it was actually referenced in the statement or qual.
* NEW is not really a relation and should never be added. *
*/ * For INSERT, NEW is not really a relation (only a reference to
if (has_old) * the to-be-inserted tuple) and should never be added to the
{ * jointree.
*
* For UPDATE, we treat NEW as being another kind of reference to
* OLD, because it represents references to *transformed* tuples
* of the existing relation. It would be wrong to enter NEW
* separately in the jointree, since that would cause a double
* join of the updated relation. It's also wrong to fail to make
* a jointree entry if only NEW and not OLD is mentioned.
*/
if (has_old || (has_new && stmt->event == CMD_UPDATE))
{
/* hack so we can use addRTEtoJoinList() */
sub_pstate->p_rtable = sub_qry->rtable;
sub_pstate->p_joinlist = sub_qry->jointree->fromlist;
addRTEtoJoinList(sub_pstate, oldrte); addRTEtoJoinList(sub_pstate, oldrte);
sub_qry->jointree->fromlist = sub_pstate->p_joinlist; sub_qry->jointree->fromlist = sub_pstate->p_joinlist;
} }
lfirst(actions) = sub_qry; lfirst(actions) = top_subqry;
release_pstate_resources(sub_pstate); release_pstate_resources(sub_pstate);
pfree(sub_pstate); pfree(sub_pstate);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteDefine.c,v 1.55 2000/10/26 21:36:50 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteDefine.c,v 1.56 2000/12/05 19:15:09 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include "optimizer/clauses.h" #include "optimizer/clauses.h"
#include "parser/parse_relation.h" #include "parser/parse_relation.h"
#include "rewrite/rewriteDefine.h" #include "rewrite/rewriteDefine.h"
#include "rewrite/rewriteManip.h"
#include "rewrite/rewriteSupport.h" #include "rewrite/rewriteSupport.h"
#include "storage/smgr.h" #include "storage/smgr.h"
#include "utils/builtins.h" #include "utils/builtins.h"
...@@ -205,17 +206,18 @@ DefineQueryRewrite(RuleStmt *stmt) ...@@ -205,17 +206,18 @@ DefineQueryRewrite(RuleStmt *stmt)
foreach(l, action) foreach(l, action)
{ {
query = (Query *) lfirst(l); query = (Query *) lfirst(l);
if (query->resultRelation == 0)
continue;
/* Don't be fooled by INSERT/SELECT */
if (query != getInsertSelectQuery(query, NULL))
continue;
if (query->resultRelation == PRS2_OLD_VARNO) if (query->resultRelation == PRS2_OLD_VARNO)
{
elog(ERROR, "rule actions on OLD currently not supported" elog(ERROR, "rule actions on OLD currently not supported"
"\n\tuse views or triggers instead"); "\n\tuse views or triggers instead");
}
if (query->resultRelation == PRS2_NEW_VARNO) if (query->resultRelation == PRS2_NEW_VARNO)
{
elog(ERROR, "rule actions on NEW currently not supported" elog(ERROR, "rule actions on NEW currently not supported"
"\n\tuse triggers instead"); "\n\tuse triggers instead");
} }
}
/* /*
* Rules ON SELECT are restricted to view definitions * Rules ON SELECT are restricted to view definitions
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.83 2000/11/08 22:09:59 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.84 2000/12/05 19:15:09 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -61,6 +61,8 @@ gatherRewriteMeta(Query *parsetree, ...@@ -61,6 +61,8 @@ gatherRewriteMeta(Query *parsetree,
bool instead_flag) bool instead_flag)
{ {
RewriteInfo *info; RewriteInfo *info;
Query *sub_action;
Query **sub_action_ptr;
int rt_length; int rt_length;
info = (RewriteInfo *) palloc(sizeof(RewriteInfo)); info = (RewriteInfo *) palloc(sizeof(RewriteInfo));
...@@ -70,24 +72,57 @@ gatherRewriteMeta(Query *parsetree, ...@@ -70,24 +72,57 @@ gatherRewriteMeta(Query *parsetree,
info->rule_action = (Query *) copyObject(rule_action); info->rule_action = (Query *) copyObject(rule_action);
info->rule_qual = (Node *) copyObject(rule_qual); info->rule_qual = (Node *) copyObject(rule_qual);
if (info->rule_action == NULL) if (info->rule_action == NULL)
info->nothing = TRUE;
else
{ {
info->nothing = TRUE;
return info;
}
info->nothing = FALSE; info->nothing = FALSE;
info->action = info->rule_action->commandType; info->action = info->rule_action->commandType;
info->current_varno = rt_index; info->current_varno = rt_index;
rt_length = length(parsetree->rtable); rt_length = length(parsetree->rtable);
/* Adjust rule action and qual to offset its varnos */
info->new_varno = PRS2_NEW_VARNO + rt_length; info->new_varno = PRS2_NEW_VARNO + rt_length;
OffsetVarNodes((Node *) info->rule_action, rt_length, 0);
/*
* Adjust rule action and qual to offset its varnos, so that we can
* merge its rtable into the main parsetree's rtable.
*
* If the rule action is an INSERT...SELECT, the OLD/NEW rtable
* entries will be in the SELECT part, and we have to modify that
* rather than the top-level INSERT (kluge!).
*/
sub_action = getInsertSelectQuery(info->rule_action, &sub_action_ptr);
OffsetVarNodes((Node *) sub_action, rt_length, 0);
OffsetVarNodes(info->rule_qual, rt_length, 0); OffsetVarNodes(info->rule_qual, rt_length, 0);
/* but its references to *OLD* should point at original rt_index */ /* but references to *OLD* should point at original rt_index */
ChangeVarNodes((Node *) info->rule_action, ChangeVarNodes((Node *) sub_action,
PRS2_OLD_VARNO + rt_length, rt_index, 0); PRS2_OLD_VARNO + rt_length, rt_index, 0);
ChangeVarNodes(info->rule_qual, ChangeVarNodes(info->rule_qual,
PRS2_OLD_VARNO + rt_length, rt_index, 0); PRS2_OLD_VARNO + rt_length, rt_index, 0);
/*
* Update resultRelation too ... perhaps this should be done by
* Offset/ChangeVarNodes?
*/
if (sub_action->resultRelation)
{
int result_reln;
int new_result_reln;
result_reln = sub_action->resultRelation;
switch (result_reln)
{
case PRS2_OLD_VARNO:
new_result_reln = rt_index;
break;
case PRS2_NEW_VARNO:
default:
new_result_reln = result_reln + rt_length;
break;
}
sub_action->resultRelation = new_result_reln;
}
/* /*
* We want the main parsetree's rtable to end up as the concatenation * We want the main parsetree's rtable to end up as the concatenation
* of its original contents plus those of all the relevant rule * of its original contents plus those of all the relevant rule
...@@ -104,8 +139,8 @@ gatherRewriteMeta(Query *parsetree, ...@@ -104,8 +139,8 @@ gatherRewriteMeta(Query *parsetree,
* they all have the same list head pointer. * they all have the same list head pointer.
*/ */
parsetree->rtable = nconc(parsetree->rtable, parsetree->rtable = nconc(parsetree->rtable,
info->rule_action->rtable); sub_action->rtable);
info->rule_action->rtable = parsetree->rtable; sub_action->rtable = parsetree->rtable;
/* /*
* Each rule action's jointree should be the main parsetree's jointree * Each rule action's jointree should be the main parsetree's jointree
...@@ -120,35 +155,52 @@ gatherRewriteMeta(Query *parsetree, ...@@ -120,35 +155,52 @@ gatherRewriteMeta(Query *parsetree,
rt_index, rt_index,
&found); &found);
info->rule_action->jointree->fromlist = sub_action->jointree->fromlist =
nconc(newjointree, nconc(newjointree, sub_action->jointree->fromlist);
info->rule_action->jointree->fromlist);
} }
/* /*
* bug here about replace CURRENT -- sort of replace current is * We copy the qualifications of the parsetree to the action and vice
* deprecated now so this code shouldn't really need to be so * versa. So force hasSubLinks if one of them has it. If this is not
* clutzy but..... * right, the flag will get cleared later, but we mustn't risk having
* it not set when it needs to be.
*/ */
if (info->action != CMD_SELECT) if (parsetree->hasSubLinks)
{ /* i.e update XXXXX */ sub_action->hasSubLinks = TRUE;
int result_reln; else if (sub_action->hasSubLinks)
int new_result_reln; parsetree->hasSubLinks = TRUE;
result_reln = info->rule_action->resultRelation; /*
switch (result_reln) * Event Qualification forces copying of parsetree and
{ * splitting into two queries one w/rule_qual, one w/NOT
case PRS2_OLD_VARNO: * rule_qual. Also add user query qual onto rule action
new_result_reln = rt_index; */
break; AddQual(sub_action, info->rule_qual);
case PRS2_NEW_VARNO: /* XXX */
default: AddQual(sub_action, parsetree->jointree->quals);
new_result_reln = result_reln + rt_length;
break; /*
} * Rewrite new.attribute w/ right hand side of target-list
info->rule_action->resultRelation = new_result_reln; * entry for appropriate field name in insert/update.
} *
* KLUGE ALERT: since ResolveNew returns a mutated copy, we can't just
* apply it to sub_action; we have to remember to update the sublink
* inside info->rule_action, too.
*/
if (info->event == CMD_INSERT || info->event == CMD_UPDATE)
{
sub_action = (Query *) ResolveNew((Node *) sub_action,
info->new_varno,
0,
parsetree->targetList,
info->event,
info->current_varno);
if (sub_action_ptr)
*sub_action_ptr = sub_action;
else
info->rule_action = sub_action;
} }
return info; return info;
} }
...@@ -536,42 +588,37 @@ orderRules(List *locks) ...@@ -536,42 +588,37 @@ orderRules(List *locks)
} }
/*
* Modify the given query by adding 'AND NOT rule_qual' to its qualification.
* This is used to generate suitable "else clauses" for conditional INSTEAD
* rules.
*
* The rule_qual may contain references to OLD or NEW. OLD references are
* replaced by references to the specified rt_index (the relation that the
* rule applies to). NEW references are only possible for INSERT and UPDATE
* queries on the relation itself, and so they should be replaced by copies
* of the related entries in the query's own targetlist.
*/
static Query * static Query *
CopyAndAddQual(Query *parsetree, CopyAndAddQual(Query *parsetree,
List *actions,
Node *rule_qual, Node *rule_qual,
int rt_index, int rt_index,
CmdType event) CmdType event)
{ {
Query *new_tree = (Query *) copyObject(parsetree); Query *new_tree = (Query *) copyObject(parsetree);
Node *new_qual = NULL; Node *new_qual = (Node *) copyObject(rule_qual);
Query *rule_action = NULL;
if (actions) /* Fix references to OLD */
rule_action = lfirst(actions); ChangeVarNodes(new_qual, PRS2_OLD_VARNO, rt_index, 0);
if (rule_qual != NULL) /* Fix references to NEW */
new_qual = (Node *) copyObject(rule_qual); if (event == CMD_INSERT || event == CMD_UPDATE)
if (rule_action != NULL) new_qual = ResolveNew(new_qual,
{ PRS2_NEW_VARNO,
List *rtable; 0,
int rt_length; parsetree->targetList,
List *jointreelist; event,
rt_index);
rtable = new_tree->rtable; /* And attach the fixed qual */
rt_length = length(rtable);
rtable = nconc(rtable, copyObject(rule_action->rtable));
new_tree->rtable = rtable;
OffsetVarNodes(new_qual, rt_length, 0);
ChangeVarNodes(new_qual, PRS2_OLD_VARNO + rt_length, rt_index, 0);
jointreelist = copyObject(rule_action->jointree->fromlist);
OffsetVarNodes((Node *) jointreelist, rt_length, 0);
ChangeVarNodes((Node *) jointreelist, PRS2_OLD_VARNO + rt_length,
rt_index, 0);
new_tree->jointree->fromlist = nconc(new_tree->jointree->fromlist,
jointreelist);
}
/* XXX -- where current doesn't work for instead nothing.... yet */
AddNotQual(new_tree, new_qual); AddNotQual(new_tree, new_qual);
return new_tree; return new_tree;
...@@ -598,7 +645,6 @@ fireRules(Query *parsetree, ...@@ -598,7 +645,6 @@ fireRules(Query *parsetree,
List *locks, List *locks,
List **qual_products) List **qual_products)
{ {
RewriteInfo *info;
List *results = NIL; List *results = NIL;
List *i; List *i;
...@@ -623,7 +669,6 @@ fireRules(Query *parsetree, ...@@ -623,7 +669,6 @@ fireRules(Query *parsetree,
if (event_qual != NULL && *instead_flag) if (event_qual != NULL && *instead_flag)
{ {
Query *qual_product; Query *qual_product;
RewriteInfo qual_info;
/* ---------- /* ----------
* If there are instead rules with qualifications, * If there are instead rules with qualifications,
...@@ -642,60 +687,23 @@ fireRules(Query *parsetree, ...@@ -642,60 +687,23 @@ fireRules(Query *parsetree,
else else
qual_product = (Query *) lfirst(*qual_products); qual_product = (Query *) lfirst(*qual_products);
MemSet(&qual_info, 0, sizeof(qual_info));
qual_info.event = qual_product->commandType;
qual_info.current_varno = rt_index;
qual_info.new_varno = length(qual_product->rtable) + 2;
qual_product = CopyAndAddQual(qual_product, qual_product = CopyAndAddQual(qual_product,
actions,
event_qual, event_qual,
rt_index, rt_index,
event); event);
qual_info.rule_action = qual_product;
if (event == CMD_INSERT || event == CMD_UPDATE)
FixNew(&qual_info, qual_product);
*qual_products = makeList1(qual_product); *qual_products = makeList1(qual_product);
} }
foreach(r, actions) foreach(r, actions)
{ {
Query *rule_action = lfirst(r); Query *rule_action = lfirst(r);
Node *rule_qual = copyObject(event_qual); RewriteInfo *info;
if (rule_action->commandType == CMD_NOTHING) if (rule_action->commandType == CMD_NOTHING)
continue; continue;
/*-------------------------------------------------- info = gatherRewriteMeta(parsetree, rule_action, event_qual,
* We copy the qualifications of the parsetree
* to the action and vice versa. So force
* hasSubLinks if one of them has it.
*
* As of 6.4 only parsetree qualifications can
* have sublinks. If this changes, we must make
* this a node lookup at the end of rewriting.
*
* Jan
*--------------------------------------------------
*/
if (parsetree->hasSubLinks && !rule_action->hasSubLinks)
{
rule_action = copyObject(rule_action);
rule_action->hasSubLinks = TRUE;
}
if (!parsetree->hasSubLinks && rule_action->hasSubLinks)
parsetree->hasSubLinks = TRUE;
/*--------------------------------------------------
* Step 1:
* Rewrite current.attribute or current to tuple variable
* this appears to be done in parser?
*--------------------------------------------------
*/
info = gatherRewriteMeta(parsetree, rule_action, rule_qual,
rt_index, event, *instead_flag); rt_index, event, *instead_flag);
/* handle escapable cases, or those handled by other code */ /* handle escapable cases, or those handled by other code */
...@@ -707,34 +715,6 @@ fireRules(Query *parsetree, ...@@ -707,34 +715,6 @@ fireRules(Query *parsetree,
continue; continue;
} }
if (info->action == info->event &&
info->event == CMD_SELECT)
continue;
/*
* Event Qualification forces copying of parsetree and
* splitting into two queries one w/rule_qual, one w/NOT
* rule_qual. Also add user query qual onto rule action
*/
AddQual(info->rule_action, info->rule_qual);
AddQual(info->rule_action, parsetree->jointree->quals);
/*--------------------------------------------------
* Step 2:
* Rewrite new.attribute w/ right hand side of target-list
* entry for appropriate field name in insert/update
*--------------------------------------------------
*/
if ((info->event == CMD_INSERT) || (info->event == CMD_UPDATE))
FixNew(info, parsetree);
/*--------------------------------------------------
* Step 3:
* Simplify? hey, no algorithm for simplification... let
* the planner do it.
*--------------------------------------------------
*/
results = lappend(results, info->rule_action); results = lappend(results, info->rule_action);
pfree(info); pfree(info);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteManip.c,v 1.51 2000/11/16 22:30:29 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteManip.c,v 1.52 2000/12/05 19:15:09 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -471,6 +471,70 @@ attribute_used(Node *node, int rt_index, int attno, int sublevels_up) ...@@ -471,6 +471,70 @@ attribute_used(Node *node, int rt_index, int attno, int sublevels_up)
} }
/*
* If the given Query is an INSERT ... SELECT construct, extract and
* return the sub-Query node that represents the SELECT part. Otherwise
* return the given Query.
*
* If subquery_ptr is not NULL, then *subquery_ptr is set to the location
* of the link to the SELECT subquery inside parsetree, or NULL if not an
* INSERT ... SELECT.
*
* This is a hack needed because transformations on INSERT ... SELECTs that
* appear in rule actions should be applied to the source SELECT, not to the
* INSERT part. Perhaps this can be cleaned up with redesigned querytrees.
*/
Query *
getInsertSelectQuery(Query *parsetree, Query ***subquery_ptr)
{
Query *selectquery;
RangeTblEntry *selectrte;
RangeTblRef *rtr;
if (subquery_ptr)
*subquery_ptr = NULL;
if (parsetree == NULL)
return parsetree;
if (parsetree->commandType != CMD_INSERT)
return parsetree;
/*
* Currently, this is ONLY applied to rule-action queries, and so
* we expect to find the *OLD* and *NEW* placeholder entries in the
* given query. If they're not there, it must be an INSERT/SELECT
* in which they've been pushed down to the SELECT.
*/
if (length(parsetree->rtable) >= 2 &&
strcmp(rt_fetch(PRS2_OLD_VARNO, parsetree->rtable)->eref->relname,
"*OLD*") == 0 &&
strcmp(rt_fetch(PRS2_NEW_VARNO, parsetree->rtable)->eref->relname,
"*NEW*") == 0)
return parsetree;
Assert(parsetree->jointree && IsA(parsetree->jointree, FromExpr));
if (length(parsetree->jointree->fromlist) != 1)
elog(ERROR, "getInsertSelectQuery: expected to find SELECT subquery");
rtr = (RangeTblRef *) lfirst(parsetree->jointree->fromlist);
Assert(IsA(rtr, RangeTblRef));
selectrte = rt_fetch(rtr->rtindex, parsetree->rtable);
selectquery = selectrte->subquery;
if (! (selectquery && IsA(selectquery, Query) &&
selectquery->commandType == CMD_SELECT))
elog(ERROR, "getInsertSelectQuery: expected to find SELECT subquery");
if (length(selectquery->rtable) >= 2 &&
strcmp(rt_fetch(PRS2_OLD_VARNO, selectquery->rtable)->eref->relname,
"*OLD*") == 0 &&
strcmp(rt_fetch(PRS2_NEW_VARNO, selectquery->rtable)->eref->relname,
"*NEW*") == 0)
{
if (subquery_ptr)
*subquery_ptr = & (selectrte->subquery);
return selectquery;
}
elog(ERROR, "getInsertSelectQuery: can't find rule placeholders");
return NULL; /* not reached */
}
/* /*
* Add the given qualifier condition to the query's WHERE clause * Add the given qualifier condition to the query's WHERE clause
*/ */
...@@ -721,25 +785,6 @@ ResolveNew(Node *node, int target_varno, int sublevels_up, ...@@ -721,25 +785,6 @@ ResolveNew(Node *node, int target_varno, int sublevels_up,
return ResolveNew_mutator(node, &context); return ResolveNew_mutator(node, &context);
} }
/*
* Alternate interface to ResolveNew: substitute Vars in info->rule_action
* with targetlist items from the parsetree's targetlist.
*/
void
FixNew(RewriteInfo *info, Query *parsetree)
{
ResolveNew_context context;
context.target_varno = info->new_varno;
context.sublevels_up = 0;
context.targetlist = parsetree->targetList;
context.event = info->event;
context.update_varno = info->current_varno;
query_tree_mutator(info->rule_action, ResolveNew_mutator,
(void *) &context, true);
}
#ifdef NOT_USED #ifdef NOT_USED
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: rewriteManip.h,v 1.23 2000/09/29 18:21:24 tgl Exp $ * $Id: rewriteManip.h,v 1.24 2000/12/05 19:15:10 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -28,6 +28,8 @@ extern bool rangeTableEntry_used(Node *node, int rt_index, ...@@ -28,6 +28,8 @@ extern bool rangeTableEntry_used(Node *node, int rt_index,
extern bool attribute_used(Node *node, int rt_index, int attno, extern bool attribute_used(Node *node, int rt_index, int attno,
int sublevels_up); int sublevels_up);
extern Query *getInsertSelectQuery(Query *parsetree, Query ***subquery_ptr);
extern void AddQual(Query *parsetree, Node *qual); extern void AddQual(Query *parsetree, Node *qual);
extern void AddHavingQual(Query *parsetree, Node *havingQual); extern void AddHavingQual(Query *parsetree, Node *havingQual);
extern void AddNotQual(Query *parsetree, Node *qual); extern void AddNotQual(Query *parsetree, Node *qual);
...@@ -37,6 +39,5 @@ extern bool checkExprHasSubLink(Node *node); ...@@ -37,6 +39,5 @@ extern bool checkExprHasSubLink(Node *node);
extern Node *ResolveNew(Node *node, int target_varno, int sublevels_up, extern Node *ResolveNew(Node *node, int target_varno, int sublevels_up,
List *targetlist, int event, int update_varno); List *targetlist, int event, int update_varno);
extern void FixNew(RewriteInfo *info, Query *parsetree);
#endif /* REWRITEMANIP_H */ #endif /* REWRITEMANIP_H */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment