1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-13 07:41:39 +03:00

Allow OLD and NEW in multi-row VALUES within rules.

Now that we have LATERAL, it's fairly painless to allow this case, which
was left as a TODO in the original multi-row VALUES implementation.
This commit is contained in:
Tom Lane
2012-08-19 14:12:16 -04:00
parent c246eb5aaf
commit 092d7ded29
8 changed files with 164 additions and 47 deletions

View File

@ -587,6 +587,7 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
List *exprsLists = NIL;
List *collations = NIL;
int sublist_length = -1;
bool lateral = false;
int i;
Assert(selectStmt->intoClause == NULL);
@ -647,25 +648,20 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
collations = lappend_oid(collations, InvalidOid);
/*
* Another thing we can't currently support is NEW/OLD references in
* rules --- seems we'd need something like SQL99's LATERAL construct
* to ensure that the values would be available while evaluating the
* VALUES RTE. This is a shame. FIXME
* Ordinarily there can't be any current-level Vars in the expression
* lists, because the namespace was empty ... but if we're inside
* CREATE RULE, then NEW/OLD references might appear. In that case we
* have to mark the VALUES RTE as LATERAL.
*/
if (list_length(pstate->p_rtable) != 1 &&
contain_vars_of_level((Node *) exprsLists, 0))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("VALUES must not contain OLD or NEW references"),
errhint("Use SELECT ... UNION ALL ... instead."),
parser_errposition(pstate,
locate_var_of_level((Node *) exprsLists, 0))));
lateral = true;
/*
* Generate the VALUES RTE
*/
rte = addRangeTableEntryForValues(pstate, exprsLists, collations,
NULL, true);
NULL, lateral, true);
rtr = makeNode(RangeTblRef);
/* assume new rte is at end */
rtr->rtindex = list_length(pstate->p_rtable);
@ -1032,6 +1028,7 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
List *collations;
List **colexprs = NULL;
int sublist_length = -1;
bool lateral = false;
RangeTblEntry *rte;
int rtindex;
ListCell *lc;
@ -1176,11 +1173,21 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
list_free(colexprs[i]);
}
/*
* Ordinarily there can't be any current-level Vars in the expression
* lists, because the namespace was empty ... but if we're inside CREATE
* RULE, then NEW/OLD references might appear. In that case we have to
* mark the VALUES RTE as LATERAL.
*/
if (pstate->p_rtable != NIL &&
contain_vars_of_level((Node *) exprsLists, 0))
lateral = true;
/*
* Generate the VALUES RTE
*/
rte = addRangeTableEntryForValues(pstate, exprsLists, collations,
NULL, true);
NULL, lateral, true);
addRTEtoQuery(pstate, rte, true, true, true);
/* assume new rte is at end */
@ -1214,21 +1221,6 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("SELECT FOR UPDATE/SHARE cannot be applied to VALUES")));
/*
* Another thing we can't currently support is NEW/OLD references in rules
* --- seems we'd need something like SQL99's LATERAL construct to ensure
* that the values would be available while evaluating the VALUES RTE.
* This is a shame. FIXME
*/
if (list_length(pstate->p_rtable) != 1 &&
contain_vars_of_level((Node *) exprsLists, 0))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("VALUES must not contain OLD or NEW references"),
errhint("Use SELECT ... UNION ALL ... instead."),
parser_errposition(pstate,
locate_var_of_level((Node *) exprsLists, 0))));
qry->rtable = pstate->p_rtable;
qry->jointree = makeFromExpr(pstate->p_joinlist, NULL);

View File

@ -1313,6 +1313,7 @@ addRangeTableEntryForValues(ParseState *pstate,
List *exprs,
List *collations,
Alias *alias,
bool lateral,
bool inFromCl)
{
RangeTblEntry *rte = makeNode(RangeTblEntry);
@ -1355,7 +1356,7 @@ addRangeTableEntryForValues(ParseState *pstate,
*
* Subqueries are never checked for access rights.
*/
rte->lateral = false;
rte->lateral = lateral;
rte->inh = false; /* never true for values RTEs */
rte->inFromCl = inFromCl;