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.c98
1 files changed, 59 insertions, 39 deletions
diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c
index a628584f86b..858baf87ade 100644
--- a/src/backend/rewrite/rewriteHandler.c
+++ b/src/backend/rewrite/rewriteHandler.c
@@ -65,14 +65,13 @@ static List *rewriteTargetListIU(List *targetList,
CmdType commandType,
OverridingKind override,
Relation target_relation,
- int result_rti,
- List **attrno_list);
+ int result_rti);
static TargetEntry *process_matched_tle(TargetEntry *src_tle,
TargetEntry *prior_tle,
const char *attrName);
static Node *get_assignment_input(Node *node);
-static bool rewriteValuesRTE(Query *parsetree, RangeTblEntry *rte,
- Relation target_relation, List *attrnos, bool force_nulls);
+static bool rewriteValuesRTE(Query *parsetree, RangeTblEntry *rte, int rti,
+ Relation target_relation, bool force_nulls);
static void markQueryForLocking(Query *qry, Node *jtnode,
LockClauseStrength strength, LockWaitPolicy waitPolicy,
bool pushedDown);
@@ -701,11 +700,6 @@ adjustJoinTreeList(Query *parsetree, bool removert, int rt_index)
* is not needed for rewriting, but will be needed by the planner, and we
* can do it essentially for free while handling the other items.
*
- * If attrno_list isn't NULL, we return an additional output besides the
- * rewritten targetlist: an integer list of the assigned-to attnums, in
- * order of the original tlist's non-junk entries. This is needed for
- * processing VALUES RTEs.
- *
* Note that for an inheritable UPDATE, this processing is only done once,
* using the parent relation as reference. It must not do anything that
* will not be correct when transposed to the child relation(s). (Step 4
@@ -718,8 +712,7 @@ rewriteTargetListIU(List *targetList,
CmdType commandType,
OverridingKind override,
Relation target_relation,
- int result_rti,
- List **attrno_list)
+ int result_rti)
{
TargetEntry **new_tles;
List *new_tlist = NIL;
@@ -730,9 +723,6 @@ rewriteTargetListIU(List *targetList,
numattrs;
ListCell *temp;
- if (attrno_list) /* initialize optional result list */
- *attrno_list = NIL;
-
/*
* We process the normal (non-junk) attributes by scanning the input tlist
* once and transferring TLEs into an array, then scanning the array to
@@ -758,10 +748,6 @@ rewriteTargetListIU(List *targetList,
elog(ERROR, "bogus resno %d in targetlist", attrno);
att_tup = TupleDescAttr(target_relation->rd_att, attrno - 1);
- /* put attrno into attrno_list even if it's dropped */
- if (attrno_list)
- *attrno_list = lappend_int(*attrno_list, attrno);
-
/* We can (and must) ignore deleted attributes */
if (att_tup->attisdropped)
continue;
@@ -1234,22 +1220,26 @@ searchForDefault(RangeTblEntry *rte)
* an insert into an auto-updatable view, and the product queries are inserts
* into a rule-updatable view.
*
- * Note that we currently can't support subscripted or field assignment
- * in the multi-VALUES case. The targetlist will contain simple Vars
- * referencing the VALUES RTE, and therefore process_matched_tle() will
- * reject any such attempt with "multiple assignments to same column".
+ * Note that we may have subscripted or field assignment targetlist entries,
+ * as well as more complex expressions from already-replaced DEFAULT items if
+ * we have recursed to here for an auto-updatable view. However, it ought to
+ * be impossible for such entries to have DEFAULTs assigned to them --- we
+ * should only have to replace DEFAULT items for targetlist entries that
+ * contain simple Vars referencing the VALUES RTE.
*
* Returns true if all DEFAULT items were replaced, and false if some were
* left untouched.
*/
static bool
-rewriteValuesRTE(Query *parsetree, RangeTblEntry *rte,
- Relation target_relation, List *attrnos, bool force_nulls)
+rewriteValuesRTE(Query *parsetree, RangeTblEntry *rte, int rti,
+ Relation target_relation, bool force_nulls)
{
List *newValues;
ListCell *lc;
bool isAutoUpdatableView;
bool allReplaced;
+ int numattrs;
+ int *attrnos;
/*
* Rebuilding all the lists is a pretty expensive proposition in a big
@@ -1262,8 +1252,33 @@ rewriteValuesRTE(Query *parsetree, RangeTblEntry *rte,
if (!force_nulls && !searchForDefault(rte))
return true; /* nothing to do */
- /* Check list lengths (we can assume all the VALUES sublists are alike) */
- Assert(list_length(attrnos) == list_length(linitial(rte->values_lists)));
+ /*
+ * Scan the targetlist for entries referring to the VALUES RTE, and note
+ * the target attributes. As noted above, we should only need to do this
+ * for targetlist entries containing simple Vars --- nothing else in the
+ * VALUES RTE should contain DEFAULT items, and we complain if such a
+ * thing does occur.
+ */
+ numattrs = list_length(linitial(rte->values_lists));
+ attrnos = (int *) palloc0(numattrs * sizeof(int));
+
+ foreach(lc, parsetree->targetList)
+ {
+ TargetEntry *tle = (TargetEntry *) lfirst(lc);
+
+ if (IsA(tle->expr, Var))
+ {
+ Var *var = (Var *) tle->expr;
+
+ if (var->varno == rti)
+ {
+ int attrno = var->varattno;
+
+ Assert(attrno >= 1 && attrno <= numattrs);
+ attrnos[attrno - 1] = tle->resno;
+ }
+ }
+ }
/*
* Check if the target relation is an auto-updatable view, in which case
@@ -1314,18 +1329,23 @@ rewriteValuesRTE(Query *parsetree, RangeTblEntry *rte,
List *sublist = (List *) lfirst(lc);
List *newList = NIL;
ListCell *lc2;
- ListCell *lc3;
+ int i;
+
+ Assert(list_length(sublist) == numattrs);
- forboth(lc2, sublist, lc3, attrnos)
+ i = 0;
+ foreach(lc2, sublist)
{
Node *col = (Node *) lfirst(lc2);
- int attrno = lfirst_int(lc3);
+ int attrno = attrnos[i++];
if (IsA(col, SetToDefault))
{
Form_pg_attribute att_tup;
Node *new_expr;
+ if (attrno == 0)
+ elog(ERROR, "cannot set value in column %d to DEFAULT", i);
att_tup = TupleDescAttr(target_relation->rd_att, attrno - 1);
if (!force_nulls && !att_tup->attisdropped)
@@ -1373,6 +1393,8 @@ rewriteValuesRTE(Query *parsetree, RangeTblEntry *rte,
}
rte->values_lists = newValues;
+ pfree(attrnos);
+
return allReplaced;
}
@@ -3451,7 +3473,6 @@ RewriteQuery(Query *parsetree, List *rewrite_events)
List *locks;
List *product_queries;
bool hasUpdate = false;
- List *attrnos = NIL;
int values_rte_index = 0;
bool defaults_remaining = false;
@@ -3501,11 +3522,10 @@ RewriteQuery(Query *parsetree, List *rewrite_events)
parsetree->commandType,
parsetree->override,
rt_entry_relation,
- parsetree->resultRelation,
- &attrnos);
+ parsetree->resultRelation);
/* ... and the VALUES expression lists */
- if (!rewriteValuesRTE(parsetree, values_rte,
- rt_entry_relation, attrnos, false))
+ if (!rewriteValuesRTE(parsetree, values_rte, values_rte_index,
+ rt_entry_relation, false))
defaults_remaining = true;
}
else
@@ -3516,7 +3536,7 @@ RewriteQuery(Query *parsetree, List *rewrite_events)
parsetree->commandType,
parsetree->override,
rt_entry_relation,
- parsetree->resultRelation, NULL);
+ parsetree->resultRelation);
}
if (parsetree->onConflict &&
@@ -3527,8 +3547,7 @@ RewriteQuery(Query *parsetree, List *rewrite_events)
CMD_UPDATE,
parsetree->override,
rt_entry_relation,
- parsetree->resultRelation,
- NULL);
+ parsetree->resultRelation);
}
}
else if (event == CMD_UPDATE)
@@ -3538,7 +3557,7 @@ RewriteQuery(Query *parsetree, List *rewrite_events)
parsetree->commandType,
parsetree->override,
rt_entry_relation,
- parsetree->resultRelation, NULL);
+ parsetree->resultRelation);
}
else if (event == CMD_DELETE)
{
@@ -3583,7 +3602,8 @@ RewriteQuery(Query *parsetree, List *rewrite_events)
RangeTblEntry *values_rte = rt_fetch(values_rte_index,
pt->rtable);
- rewriteValuesRTE(pt, values_rte, rt_entry_relation, attrnos,
+ rewriteValuesRTE(pt, values_rte, values_rte_index,
+ rt_entry_relation,
true); /* Force remaining defaults to NULL */
}
}