diff options
author | Tom Lane | 2012-08-07 23:02:54 +0000 |
---|---|---|
committer | Tom Lane | 2012-08-07 23:02:54 +0000 |
commit | 5ebaaa49445eb1ba7b299bbea3a477d4e4c0430b (patch) | |
tree | 1a72c939a655e9acbba1c71a1831dd38ee41db95 /src/include | |
parent | 5078be480412790e4f1b2aeda04f8c65fc7a3b93 (diff) |
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/include')
-rw-r--r-- | src/include/catalog/catversion.h | 2 | ||||
-rw-r--r-- | src/include/nodes/parsenodes.h | 9 | ||||
-rw-r--r-- | src/include/nodes/relation.h | 8 | ||||
-rw-r--r-- | src/include/optimizer/cost.h | 2 | ||||
-rw-r--r-- | src/include/optimizer/pathnode.h | 3 | ||||
-rw-r--r-- | src/include/optimizer/var.h | 3 | ||||
-rw-r--r-- | src/include/parser/kwlist.h | 1 | ||||
-rw-r--r-- | src/include/parser/parse_node.h | 40 | ||||
-rw-r--r-- | src/include/parser/parse_relation.h | 4 |
9 files changed, 48 insertions, 24 deletions
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 4806b313341..82b6c0cfc71 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 201207201 +#define CATALOG_VERSION_NO 201208071 #endif diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 119e1ed2f6e..f433166cc68 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -451,6 +451,7 @@ typedef struct WindowDef typedef struct RangeSubselect { NodeTag type; + bool lateral; /* does it have LATERAL prefix? */ Node *subquery; /* the untransformed sub-select clause */ Alias *alias; /* table alias & optional column aliases */ } RangeSubselect; @@ -461,6 +462,7 @@ typedef struct RangeSubselect typedef struct RangeFunction { NodeTag type; + bool lateral; /* does it have LATERAL prefix? */ Node *funccallnode; /* untransformed function call tree */ Alias *alias; /* table alias & optional column aliases */ List *coldeflist; /* list of ColumnDef nodes to describe result @@ -706,7 +708,7 @@ typedef struct RangeTblEntry * Fields valid for a subquery RTE (else NULL): */ Query *subquery; /* the sub-query */ - bool security_barrier; /* subquery from security_barrier view */ + bool security_barrier; /* is from security_barrier view? */ /* * Fields valid for a join RTE (else NULL/zero): @@ -756,6 +758,7 @@ typedef struct RangeTblEntry */ Alias *alias; /* user-written alias clause, if any */ Alias *eref; /* expanded reference names */ + bool lateral; /* subquery or function is marked LATERAL? */ bool inh; /* inheritance requested? */ bool inFromCl; /* present in FROM clause? */ AclMode requiredPerms; /* bitmask of required access permissions */ @@ -1752,7 +1755,7 @@ typedef struct AlterEventTrigStmt { NodeTag type; char *trigname; /* TRIGGER's name */ - char tgenabled; /* trigger's firing configuration WRT + char tgenabled; /* trigger's firing configuration WRT * session_replication_role */ } AlterEventTrigStmt; @@ -2046,7 +2049,7 @@ typedef struct FetchStmt * * This represents creation of an index and/or an associated constraint. * If isconstraint is true, we should create a pg_constraint entry along - * with the index. But if indexOid isn't InvalidOid, we are not creating an + * with the index. But if indexOid isn't InvalidOid, we are not creating an * index, just a UNIQUE/PKEY constraint using an existing index. isconstraint * must always be true in this case, and the fields describing the index * properties are empty. diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h index cf0bbd9f159..8238981c289 100644 --- a/src/include/nodes/relation.h +++ b/src/include/nodes/relation.h @@ -307,15 +307,17 @@ typedef struct PlannerInfo * ppilist - ParamPathInfo nodes for parameterized Paths, if any * cheapest_startup_path - the pathlist member with lowest startup cost * (regardless of its ordering; but must be - * unparameterized) + * unparameterized; hence will be NULL for + * a LATERAL subquery) * cheapest_total_path - the pathlist member with lowest total cost * (regardless of its ordering; but must be - * unparameterized) + * unparameterized; hence will be NULL for + * a LATERAL subquery) * cheapest_unique_path - for caching cheapest path to produce unique * (no duplicates) output from relation * cheapest_parameterized_paths - paths with cheapest total costs for * their parameterizations; always includes - * cheapest_total_path + * cheapest_total_path, if that exists * * If the relation is a base relation it will have these fields set: * diff --git a/src/include/optimizer/cost.h b/src/include/optimizer/cost.h index b2cdb3d62e9..e3d33d69ba3 100644 --- a/src/include/optimizer/cost.h +++ b/src/include/optimizer/cost.h @@ -81,7 +81,7 @@ extern void cost_tidscan(Path *path, PlannerInfo *root, extern void cost_subqueryscan(Path *path, PlannerInfo *root, RelOptInfo *baserel, ParamPathInfo *param_info); extern void cost_functionscan(Path *path, PlannerInfo *root, - RelOptInfo *baserel); + RelOptInfo *baserel, ParamPathInfo *param_info); extern void cost_valuesscan(Path *path, PlannerInfo *root, RelOptInfo *baserel); extern void cost_ctescan(Path *path, PlannerInfo *root, RelOptInfo *baserel); diff --git a/src/include/optimizer/pathnode.h b/src/include/optimizer/pathnode.h index 385bae6eb80..3af1172cbe5 100644 --- a/src/include/optimizer/pathnode.h +++ b/src/include/optimizer/pathnode.h @@ -69,7 +69,8 @@ extern UniquePath *create_unique_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, SpecialJoinInfo *sjinfo); extern Path *create_subqueryscan_path(PlannerInfo *root, RelOptInfo *rel, List *pathkeys, Relids required_outer); -extern Path *create_functionscan_path(PlannerInfo *root, RelOptInfo *rel); +extern Path *create_functionscan_path(PlannerInfo *root, RelOptInfo *rel, + Relids required_outer); extern Path *create_valuesscan_path(PlannerInfo *root, RelOptInfo *rel); extern Path *create_ctescan_path(PlannerInfo *root, RelOptInfo *rel); extern Path *create_worktablescan_path(PlannerInfo *root, RelOptInfo *rel); diff --git a/src/include/optimizer/var.h b/src/include/optimizer/var.h index f546362b680..ec21df3a7e0 100644 --- a/src/include/optimizer/var.h +++ b/src/include/optimizer/var.h @@ -31,11 +31,12 @@ typedef enum } PVCPlaceHolderBehavior; extern Relids pull_varnos(Node *node); +extern Relids pull_varnos_of_level(Node *node, int levelsup); extern void pull_varattnos(Node *node, Index varno, Bitmapset **varattnos); +extern List *pull_vars_of_level(Node *node, int levelsup); extern bool contain_var_clause(Node *node); extern bool contain_vars_of_level(Node *node, int levelsup); extern int locate_var_of_level(Node *node, int levelsup); -extern int locate_var_of_relation(Node *node, int relid, int levelsup); extern int find_minimum_var_level(Node *node); extern List *pull_var_clause(Node *node, PVCAggregateBehavior aggbehavior, PVCPlaceHolderBehavior phbehavior); diff --git a/src/include/parser/kwlist.h b/src/include/parser/kwlist.h index 7e55a92185b..af60dac08e5 100644 --- a/src/include/parser/kwlist.h +++ b/src/include/parser/kwlist.h @@ -213,6 +213,7 @@ PG_KEYWORD("label", LABEL, UNRESERVED_KEYWORD) PG_KEYWORD("language", LANGUAGE, UNRESERVED_KEYWORD) PG_KEYWORD("large", LARGE_P, UNRESERVED_KEYWORD) PG_KEYWORD("last", LAST_P, UNRESERVED_KEYWORD) +PG_KEYWORD("lateral", LATERAL_P, RESERVED_KEYWORD) PG_KEYWORD("lc_collate", LC_COLLATE_P, UNRESERVED_KEYWORD) PG_KEYWORD("lc_ctype", LC_CTYPE_P, UNRESERVED_KEYWORD) PG_KEYWORD("leading", LEADING, RESERVED_KEYWORD) diff --git a/src/include/parser/parse_node.h b/src/include/parser/parse_node.h index 670e0849936..13f745f6fa6 100644 --- a/src/include/parser/parse_node.h +++ b/src/include/parser/parse_node.h @@ -54,22 +54,25 @@ typedef Node *(*CoerceParamHook) (ParseState *pstate, Param *param, * p_joinlist: list of join items (RangeTblRef and JoinExpr nodes) that * will become the fromlist of the query's top-level FromExpr node. * - * p_relnamespace: list of RTEs that represents the current namespace for - * table lookup, ie, those RTEs that are accessible by qualified names. - * This may be just a subset of the rtable + joinlist, and/or may contain - * entries that are not yet added to the main joinlist. - * - * p_varnamespace: list of RTEs that represents the current namespace for - * column lookup, ie, those RTEs that are accessible by unqualified names. - * This is different from p_relnamespace because a JOIN without an alias does - * not hide the contained tables (so they must still be in p_relnamespace) - * but it does hide their columns (unqualified references to the columns must - * refer to the JOIN, not the member tables). Other special RTEs such as - * NEW/OLD for rules may also appear in just one of these lists. + * p_relnamespace: list of ParseNamespaceItems that represents the current + * namespace for table lookup, ie, those RTEs that are accessible by + * qualified names. (This may be just a subset of the whole rtable.) + * + * p_varnamespace: list of ParseNamespaceItems that represents the current + * namespace for column lookup, ie, those RTEs that are accessible by + * unqualified names. This is different from p_relnamespace because a JOIN + * without an alias does not hide the contained tables (so they must be in + * p_relnamespace) but it does hide their columns (unqualified references to + * the columns must refer to the JOIN, not the member tables). Other special + * RTEs such as NEW/OLD for rules may also appear in just one of these lists. + * + * p_lateral_active: TRUE if we are currently parsing a LATERAL subexpression + * of this parse level. This makes p_lateral_only namespace items visible, + * whereas they are not visible when p_lateral_active is FALSE. * * p_ctenamespace: list of CommonTableExprs (WITH items) that are visible - * at the moment. This is different from p_relnamespace because you have - * to make an RTE before you can access a CTE. + * at the moment. This is entirely different from p_relnamespace because + * a CTE is not an RTE, rather "visibility" means you could make an RTE. * * p_future_ctes: list of CommonTableExprs (WITH items) that are not yet * visible due to scope rules. This is used to help improve error messages. @@ -93,6 +96,7 @@ struct ParseState * node's fromlist) */ List *p_relnamespace; /* current namespace for relations */ List *p_varnamespace; /* current namespace for columns */ + bool p_lateral_active; /* p_lateral_only items visible? */ List *p_ctenamespace; /* current namespace for common table exprs */ List *p_future_ctes; /* common table exprs not yet in namespace */ CommonTableExpr *p_parent_cte; /* this query's containing CTE */ @@ -121,6 +125,14 @@ struct ParseState void *p_ref_hook_state; /* common passthrough link for above */ }; +/* An element of p_relnamespace or p_varnamespace */ +typedef struct ParseNamespaceItem +{ + RangeTblEntry *p_rte; /* The relation's rangetable entry */ + bool p_lateral_only; /* Is only visible to LATERAL expressions? */ + bool p_lateral_ok; /* If so, does join type allow use? */ +} ParseNamespaceItem; + /* Support for parser_errposition_callback function */ typedef struct ParseCallbackState { diff --git a/src/include/parser/parse_relation.h b/src/include/parser/parse_relation.h index ababd74f82f..ba99fc2d8a3 100644 --- a/src/include/parser/parse_relation.h +++ b/src/include/parser/parse_relation.h @@ -55,11 +55,13 @@ extern RangeTblEntry *addRangeTableEntryForRelation(ParseState *pstate, extern RangeTblEntry *addRangeTableEntryForSubquery(ParseState *pstate, Query *subquery, Alias *alias, + bool lateral, bool inFromCl); extern RangeTblEntry *addRangeTableEntryForFunction(ParseState *pstate, char *funcname, Node *funcexpr, RangeFunction *rangefunc, + bool lateral, bool inFromCl); extern RangeTblEntry *addRangeTableEntryForValues(ParseState *pstate, List *exprs, @@ -82,6 +84,8 @@ extern void addRTEtoQuery(ParseState *pstate, RangeTblEntry *rte, bool addToJoinList, bool addToRelNameSpace, bool addToVarNameSpace); extern void errorMissingRTE(ParseState *pstate, RangeVar *relation); +extern void errorMissingColumn(ParseState *pstate, + char *relname, char *colname, int location); extern void expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up, int location, bool include_dropped, List **colnames, List **colvars); |