aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser/analyze.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2012-08-07 19:02:54 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2012-08-07 19:02:54 -0400
commit5ebaaa49445eb1ba7b299bbea3a477d4e4c0430b (patch)
tree1a72c939a655e9acbba1c71a1831dd38ee41db95 /src/backend/parser/analyze.c
parent5078be480412790e4f1b2aeda04f8c65fc7a3b93 (diff)
downloadpostgresql-5ebaaa49445eb1ba7b299bbea3a477d4e4c0430b.tar.gz
postgresql-5ebaaa49445eb1ba7b299bbea3a477d4e4c0430b.zip
Implement SQL-standard LATERAL subqueries.
This patch implements the standard syntax of LATERAL attached to a sub-SELECT in FROM, and also allows LATERAL attached to a function in FROM, since set-returning function calls are expected to be one of the principal use-cases. The main change here is a rewrite of the mechanism for keeping track of which relations are visible for column references while the FROM clause is being scanned. The parser "namespace" lists are no longer lists of bare RTEs, but are lists of ParseNamespaceItem structs, which carry an RTE pointer as well as some visibility-controlling flags. Aside from supporting LATERAL correctly, this lets us get rid of the ancient hacks that required rechecking subqueries and JOIN/ON and function-in-FROM expressions for invalid references after they were initially parsed. Invalid column references are now always correctly detected on sight. In passing, remove assorted parser error checks that are now dead code by virtue of our having gotten rid of add_missing_from, as well as some comments that are obsolete for the same reason. (It was mainly add_missing_from that caused so much fudging here in the first place.) The planner support for this feature is very minimal, and will be improved in future patches. It works well enough for testing purposes, though. catversion bump forced due to new field in RangeTblEntry.
Diffstat (limited to 'src/backend/parser/analyze.c')
-rw-r--r--src/backend/parser/analyze.c72
1 files changed, 14 insertions, 58 deletions
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index 263edb5a7a6..1a112cd9a4e 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -533,6 +533,7 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
rte = addRangeTableEntryForSubquery(pstate,
selectQuery,
makeAlias("*SELECT*", NIL),
+ false,
false);
rtr = makeNode(RangeTblRef);
/* assume new rte is at end */
@@ -652,18 +653,6 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
collations = lappend_oid(collations, InvalidOid);
/*
- * There mustn't have been any table references in the expressions,
- * else strange things would happen, like Cartesian products of those
- * tables with the VALUES list ...
- */
- if (pstate->p_joinlist != NIL)
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("VALUES must not contain table references"),
- parser_errposition(pstate,
- locate_var_of_level((Node *) exprsLists, 0))));
-
- /*
* 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
@@ -1067,7 +1056,7 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
List **colexprs = NULL;
int sublist_length = -1;
RangeTblEntry *rte;
- RangeTblRef *rtr;
+ int rtindex;
ListCell *lc;
ListCell *lc2;
int i;
@@ -1215,19 +1204,17 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
*/
rte = addRangeTableEntryForValues(pstate, exprsLists, collations,
NULL, true);
- rtr = makeNode(RangeTblRef);
+ addRTEtoQuery(pstate, rte, true, true, true);
+
/* assume new rte is at end */
- rtr->rtindex = list_length(pstate->p_rtable);
- Assert(rte == rt_fetch(rtr->rtindex, pstate->p_rtable));
- pstate->p_joinlist = lappend(pstate->p_joinlist, rtr);
- pstate->p_relnamespace = lappend(pstate->p_relnamespace, rte);
- pstate->p_varnamespace = lappend(pstate->p_varnamespace, rte);
+ rtindex = list_length(pstate->p_rtable);
+ Assert(rte == rt_fetch(rtindex, pstate->p_rtable));
/*
* Generate a targetlist as though expanding "*"
*/
Assert(pstate->p_next_resno == 1);
- qry->targetList = expandRelAttrs(pstate, rte, rtr->rtindex, 0, -1);
+ qry->targetList = expandRelAttrs(pstate, rte, rtindex, 0, -1);
/*
* The grammar allows attaching ORDER BY, LIMIT, and FOR UPDATE to a
@@ -1250,19 +1237,6 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
errmsg("SELECT FOR UPDATE/SHARE cannot be applied to VALUES")));
/*
- * There mustn't have been any table references in the expressions, else
- * strange things would happen, like Cartesian products of those tables
- * with the VALUES list. We have to check this after parsing ORDER BY et
- * al since those could insert more junk.
- */
- if (list_length(pstate->p_joinlist) != 1)
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("VALUES must not contain table references"),
- parser_errposition(pstate,
- locate_var_of_level((Node *) exprsLists, 0))));
-
- /*
* 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.
@@ -1477,10 +1451,12 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
false);
sv_relnamespace = pstate->p_relnamespace;
- pstate->p_relnamespace = NIL; /* no qualified names allowed */
-
sv_varnamespace = pstate->p_varnamespace;
- pstate->p_varnamespace = list_make1(jrte);
+ pstate->p_relnamespace = NIL;
+ pstate->p_varnamespace = NIL;
+
+ /* add jrte to varnamespace only */
+ addRTEtoQuery(pstate, jrte, false, false, true);
/*
* For now, we don't support resjunk sort clauses on the output of a
@@ -1577,7 +1553,7 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt,
/*
* If an internal node of a set-op tree has ORDER BY, LIMIT, FOR UPDATE,
* or WITH clauses attached, we need to treat it like a leaf node to
- * generate an independent sub-Query tree. Otherwise, it can be
+ * generate an independent sub-Query tree. Otherwise, it can be
* represented by a SetOperationStmt node underneath the parent Query.
*/
if (stmt->op == SETOP_NONE)
@@ -1652,6 +1628,7 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt,
rte = addRangeTableEntryForSubquery(pstate,
selectQuery,
makeAlias(selectName, NIL),
+ false,
false);
/*
@@ -2074,7 +2051,6 @@ transformReturningList(ParseState *pstate, List *returningList)
int save_next_resno;
bool save_hasAggs;
bool save_hasWindowFuncs;
- int length_rtable;
if (returningList == NIL)
return NIL; /* nothing to do */
@@ -2092,7 +2068,6 @@ transformReturningList(ParseState *pstate, List *returningList)
pstate->p_hasAggs = false;
save_hasWindowFuncs = pstate->p_hasWindowFuncs;
pstate->p_hasWindowFuncs = false;
- length_rtable = list_length(pstate->p_rtable);
/* transform RETURNING identically to a SELECT targetlist */
rlist = transformTargetList(pstate, returningList);
@@ -2113,25 +2088,6 @@ transformReturningList(ParseState *pstate, List *returningList)
parser_errposition(pstate,
locate_windowfunc((Node *) rlist))));
- /* no new relation references please */
- if (list_length(pstate->p_rtable) != length_rtable)
- {
- int vlocation = -1;
- int relid;
-
- /* try to locate such a reference to point to */
- for (relid = length_rtable + 1; relid <= list_length(pstate->p_rtable); relid++)
- {
- vlocation = locate_var_of_relation((Node *) rlist, relid, 0);
- if (vlocation >= 0)
- break;
- }
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("RETURNING cannot contain references to other relations"),
- parser_errposition(pstate, vlocation)));
- }
-
/* mark column origins */
markTargetListOrigins(pstate, rlist);