aboutsummaryrefslogtreecommitdiff
path: root/src/backend/rewrite/rewriteHandler.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/rewrite/rewriteHandler.c')
-rw-r--r--src/backend/rewrite/rewriteHandler.c95
1 files changed, 91 insertions, 4 deletions
diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c
index 286fc5b498c..1af5bd7e7f5 100644
--- a/src/backend/rewrite/rewriteHandler.c
+++ b/src/backend/rewrite/rewriteHandler.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/rewrite/rewriteHandler.c,v 1.165 2006/08/02 01:59:47 joe Exp $
+ * $PostgreSQL: pgsql/src/backend/rewrite/rewriteHandler.c,v 1.166 2006/09/02 17:06:52 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -39,7 +39,8 @@ static Query *rewriteRuleAction(Query *parsetree,
Query *rule_action,
Node *rule_qual,
int rt_index,
- CmdType event);
+ CmdType event,
+ bool *returning_flag);
static List *adjustJoinTreeList(Query *parsetree, bool removert, int rt_index);
static void rewriteTargetList(Query *parsetree, Relation target_relation,
List **attrno_list);
@@ -251,13 +252,26 @@ acquireLocksOnSubLinks(Node *node, void *context)
* rewriteRuleAction -
* Rewrite the rule action with appropriate qualifiers (taken from
* the triggering query).
+ *
+ * Input arguments:
+ * parsetree - original query
+ * rule_action - one action (query) of a rule
+ * rule_qual - WHERE condition of rule, or NULL if unconditional
+ * rt_index - RT index of result relation in original query
+ * event - type of rule event
+ * Output arguments:
+ * *returning_flag - set TRUE if we rewrite RETURNING clause in rule_action
+ * (must be initialized to FALSE)
+ * Return value:
+ * rewritten form of rule_action
*/
static Query *
rewriteRuleAction(Query *parsetree,
Query *rule_action,
Node *rule_qual,
int rt_index,
- CmdType event)
+ CmdType event,
+ bool *returning_flag)
{
int current_varno,
new_varno;
@@ -416,6 +430,32 @@ rewriteRuleAction(Query *parsetree,
rule_action = sub_action;
}
+ /*
+ * If rule_action has a RETURNING clause, then either throw it away
+ * if the triggering query has no RETURNING clause, or rewrite it to
+ * emit what the triggering query's RETURNING clause asks for. Throw
+ * an error if more than one rule has a RETURNING clause.
+ */
+ if (!parsetree->returningList)
+ rule_action->returningList = NIL;
+ else if (rule_action->returningList)
+ {
+ if (*returning_flag)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("cannot have RETURNING lists in multiple rules")));
+ *returning_flag = true;
+ rule_action->returningList = (List *)
+ ResolveNew((Node *) parsetree->returningList,
+ parsetree->resultRelation,
+ 0,
+ rt_fetch(parsetree->resultRelation,
+ parsetree->rtable),
+ rule_action->returningList,
+ CMD_SELECT,
+ 0);
+ }
+
return rule_action;
}
@@ -1357,6 +1397,8 @@ CopyAndAddInvertedQual(Query *parsetree,
* Output arguments:
* *instead_flag - set TRUE if any unqualified INSTEAD rule is found
* (must be initialized to FALSE)
+ * *returning_flag - set TRUE if we rewrite RETURNING clause in any rule
+ * (must be initialized to FALSE)
* *qual_product - filled with modified original query if any qualified
* INSTEAD rule is found (must be initialized to NULL)
* Return value:
@@ -1377,6 +1419,7 @@ fireRules(Query *parsetree,
CmdType event,
List *locks,
bool *instead_flag,
+ bool *returning_flag,
Query **qual_product)
{
List *results = NIL;
@@ -1438,7 +1481,8 @@ fireRules(Query *parsetree,
continue;
rule_action = rewriteRuleAction(parsetree, rule_action,
- event_qual, rt_index, event);
+ event_qual, rt_index, event,
+ returning_flag);
rule_action->querySource = qsrc;
rule_action->canSetTag = false; /* might change later */
@@ -1463,6 +1507,7 @@ RewriteQuery(Query *parsetree, List *rewrite_events)
{
CmdType event = parsetree->commandType;
bool instead = false;
+ bool returning = false;
Query *qual_product = NULL;
List *rewritten = NIL;
@@ -1551,6 +1596,7 @@ RewriteQuery(Query *parsetree, List *rewrite_events)
event,
locks,
&instead,
+ &returning,
&qual_product);
/*
@@ -1591,6 +1637,47 @@ RewriteQuery(Query *parsetree, List *rewrite_events)
}
}
+ /*
+ * If there is an INSTEAD, and the original query has a RETURNING,
+ * we have to have found a RETURNING in the rule(s), else fail.
+ * (Because DefineQueryRewrite only allows RETURNING in unconditional
+ * INSTEAD rules, there's no need to worry whether the substituted
+ * RETURNING will actually be executed --- it must be.)
+ */
+ if ((instead || qual_product != NULL) &&
+ parsetree->returningList &&
+ !returning)
+ {
+ switch (event)
+ {
+ case CMD_INSERT:
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("cannot INSERT RETURNING on relation \"%s\"",
+ RelationGetRelationName(rt_entry_relation)),
+ errhint("You need an unconditional ON INSERT DO INSTEAD rule with a RETURNING clause.")));
+ break;
+ case CMD_UPDATE:
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("cannot UPDATE RETURNING on relation \"%s\"",
+ RelationGetRelationName(rt_entry_relation)),
+ errhint("You need an unconditional ON UPDATE DO INSTEAD rule with a RETURNING clause.")));
+ break;
+ case CMD_DELETE:
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("cannot DELETE RETURNING on relation \"%s\"",
+ RelationGetRelationName(rt_entry_relation)),
+ errhint("You need an unconditional ON DELETE DO INSTEAD rule with a RETURNING clause.")));
+ break;
+ default:
+ elog(ERROR, "unrecognized commandType: %d",
+ (int) event);
+ break;
+ }
+ }
+
heap_close(rt_entry_relation, NoLock);
}