diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2012-08-07 19:02:54 -0400 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2012-08-07 19:02:54 -0400 |
commit | 5ebaaa49445eb1ba7b299bbea3a477d4e4c0430b (patch) | |
tree | 1a72c939a655e9acbba1c71a1831dd38ee41db95 /src/backend/optimizer/util/pathnode.c | |
parent | 5078be480412790e4f1b2aeda04f8c65fc7a3b93 (diff) | |
download | postgresql-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/optimizer/util/pathnode.c')
-rw-r--r-- | src/backend/optimizer/util/pathnode.c | 26 |
1 files changed, 19 insertions, 7 deletions
diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c index 00052f5c846..11de5c70d80 100644 --- a/src/backend/optimizer/util/pathnode.c +++ b/src/backend/optimizer/util/pathnode.c @@ -193,7 +193,7 @@ compare_path_costs_fuzzily(Path *path1, Path *path2, double fuzz_factor) * and cheapest_total. The cheapest_parameterized_paths list collects paths * that are cheapest-total for their parameterization (i.e., there is no * cheaper path with the same or weaker parameterization). This list always - * includes the unparameterized cheapest-total path, too. + * includes the unparameterized cheapest-total path, too, if there is one. * * This is normally called only after we've finished constructing the path * list for the rel node. @@ -250,15 +250,18 @@ set_cheapest(RelOptInfo *parent_rel) cheapest_total_path = path; } - if (cheapest_total_path == NULL) + if (cheapest_total_path == NULL && !have_parameterized_paths) elog(ERROR, "could not devise a query plan for the given query"); parent_rel->cheapest_startup_path = cheapest_startup_path; parent_rel->cheapest_total_path = cheapest_total_path; parent_rel->cheapest_unique_path = NULL; /* computed only if needed */ - /* Seed the parameterized-paths list with the cheapest total */ - parent_rel->cheapest_parameterized_paths = list_make1(cheapest_total_path); + /* Seed the parameterized-paths list with the cheapest total, if any */ + if (cheapest_total_path) + parent_rel->cheapest_parameterized_paths = list_make1(cheapest_total_path); + else + parent_rel->cheapest_parameterized_paths = NIL; /* And, if there are any parameterized paths, add them in one at a time */ if (have_parameterized_paths) @@ -1131,6 +1134,13 @@ create_unique_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, int numCols; ListCell *lc; + /* XXX temporary band-aid to not crash on LATERAL queries */ + if (subpath == NULL) + { + Assert(subpath == rel->cheapest_total_path); + return NULL; + } + /* Caller made a mistake if subpath isn't cheapest_total ... */ Assert(subpath == rel->cheapest_total_path); Assert(subpath->parent == rel); @@ -1657,16 +1667,18 @@ create_subqueryscan_path(PlannerInfo *root, RelOptInfo *rel, * returning the pathnode. */ Path * -create_functionscan_path(PlannerInfo *root, RelOptInfo *rel) +create_functionscan_path(PlannerInfo *root, RelOptInfo *rel, + Relids required_outer) { Path *pathnode = makeNode(Path); pathnode->pathtype = T_FunctionScan; pathnode->parent = rel; - pathnode->param_info = NULL; /* never parameterized at present */ + pathnode->param_info = get_baserel_parampathinfo(root, rel, + required_outer); pathnode->pathkeys = NIL; /* for now, assume unordered result */ - cost_functionscan(pathnode, root, rel); + cost_functionscan(pathnode, root, rel, pathnode->param_info); return pathnode; } |