mirror of
https://git.postgresql.org/git/postgresql.git
synced 2026-02-05 09:37:41 +08:00
Evaluation of set returning functions (SRFs_ in the targetlist (like SELECT generate_series(1,5)) so far was done in the expression evaluation (i.e. ExecEvalExpr()) and projection (i.e. ExecProject/ExecTargetList) code. This meant that most executor nodes performing projection, and most expression evaluation functions, had to deal with the possibility that an evaluated expression could return a set of return values. That's bad because it leads to repeated code in a lot of places. It also, and that's my (Andres's) motivation, made it a lot harder to implement a more efficient way of doing expression evaluation. To fix this, introduce a new executor node (ProjectSet) that can evaluate targetlists containing one or more SRFs. To avoid the complexity of the old way of handling nested expressions returning sets (e.g. having to pass up ExprDoneCond, and dealing with arguments to functions returning sets etc.), those SRFs can only be at the top level of the node's targetlist. The planner makes sure (via split_pathtarget_at_srfs()) that SRF evaluation is only necessary in ProjectSet nodes and that SRFs are only present at the top level of the node's targetlist. If there are nested SRFs the planner creates multiple stacked ProjectSet nodes. The ProjectSet nodes always get input from an underlying node. We also discussed and prototyped evaluating targetlist SRFs using ROWS FROM(), but that turned out to be more complicated than we'd hoped. While moving SRF evaluation to ProjectSet would allow to retain the old "least common multiple" behavior when multiple SRFs are present in one targetlist (i.e. continue returning rows until all SRFs are at the end of their input at the same time), we decided to instead only return rows till all SRFs are exhausted, returning NULL for already exhausted ones. We deemed the previous behavior to be too confusing, unexpected and actually not particularly useful. As a side effect, the previously prohibited case of multiple set returning arguments to a function, is now allowed. Not because it's particularly desirable, but because it ends up working and there seems to be no argument for adding code to prohibit it. Currently the behavior for COALESCE and CASE containing SRFs has changed, returning multiple rows from the expression, even when the SRF containing "arm" of the expression is not evaluated. That's because the SRFs are evaluated in a separate ProjectSet node. As that's quite confusing, we're likely to instead prohibit SRFs in those places. But that's still being discussed, and the code would reside in places not touched here, so that's a task for later. There's a lot of, now superfluous, code dealing with set return expressions around. But as the changes to get rid of those are verbose largely boring, it seems better for readability to keep the cleanup as a separate commit. Author: Tom Lane and Andres Freund Discussion: https://postgr.es/m/20160822214023.aaxz5l4igypowyri@alap3.anarazel.de
276 lines
9.6 KiB
C
276 lines
9.6 KiB
C
/*-------------------------------------------------------------------------
|
|
*
|
|
* pathnode.h
|
|
* prototypes for pathnode.c, relnode.c.
|
|
*
|
|
*
|
|
* Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
*
|
|
* src/include/optimizer/pathnode.h
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
#ifndef PATHNODE_H
|
|
#define PATHNODE_H
|
|
|
|
#include "nodes/relation.h"
|
|
|
|
|
|
/*
|
|
* prototypes for pathnode.c
|
|
*/
|
|
extern int compare_path_costs(Path *path1, Path *path2,
|
|
CostSelector criterion);
|
|
extern int compare_fractional_path_costs(Path *path1, Path *path2,
|
|
double fraction);
|
|
extern void set_cheapest(RelOptInfo *parent_rel);
|
|
extern void add_path(RelOptInfo *parent_rel, Path *new_path);
|
|
extern bool add_path_precheck(RelOptInfo *parent_rel,
|
|
Cost startup_cost, Cost total_cost,
|
|
List *pathkeys, Relids required_outer);
|
|
extern void add_partial_path(RelOptInfo *parent_rel, Path *new_path);
|
|
extern bool add_partial_path_precheck(RelOptInfo *parent_rel,
|
|
Cost total_cost, List *pathkeys);
|
|
|
|
extern Path *create_seqscan_path(PlannerInfo *root, RelOptInfo *rel,
|
|
Relids required_outer, int parallel_workers);
|
|
extern Path *create_samplescan_path(PlannerInfo *root, RelOptInfo *rel,
|
|
Relids required_outer);
|
|
extern IndexPath *create_index_path(PlannerInfo *root,
|
|
IndexOptInfo *index,
|
|
List *indexclauses,
|
|
List *indexclausecols,
|
|
List *indexorderbys,
|
|
List *indexorderbycols,
|
|
List *pathkeys,
|
|
ScanDirection indexscandir,
|
|
bool indexonly,
|
|
Relids required_outer,
|
|
double loop_count);
|
|
extern BitmapHeapPath *create_bitmap_heap_path(PlannerInfo *root,
|
|
RelOptInfo *rel,
|
|
Path *bitmapqual,
|
|
Relids required_outer,
|
|
double loop_count);
|
|
extern BitmapAndPath *create_bitmap_and_path(PlannerInfo *root,
|
|
RelOptInfo *rel,
|
|
List *bitmapquals);
|
|
extern BitmapOrPath *create_bitmap_or_path(PlannerInfo *root,
|
|
RelOptInfo *rel,
|
|
List *bitmapquals);
|
|
extern TidPath *create_tidscan_path(PlannerInfo *root, RelOptInfo *rel,
|
|
List *tidquals, Relids required_outer);
|
|
extern AppendPath *create_append_path(RelOptInfo *rel, List *subpaths,
|
|
Relids required_outer, int parallel_workers);
|
|
extern MergeAppendPath *create_merge_append_path(PlannerInfo *root,
|
|
RelOptInfo *rel,
|
|
List *subpaths,
|
|
List *pathkeys,
|
|
Relids required_outer);
|
|
extern ResultPath *create_result_path(PlannerInfo *root, RelOptInfo *rel,
|
|
PathTarget *target, List *resconstantqual);
|
|
extern MaterialPath *create_material_path(RelOptInfo *rel, Path *subpath);
|
|
extern UniquePath *create_unique_path(PlannerInfo *root, RelOptInfo *rel,
|
|
Path *subpath, SpecialJoinInfo *sjinfo);
|
|
extern GatherPath *create_gather_path(PlannerInfo *root,
|
|
RelOptInfo *rel, Path *subpath, PathTarget *target,
|
|
Relids required_outer, double *rows);
|
|
extern SubqueryScanPath *create_subqueryscan_path(PlannerInfo *root,
|
|
RelOptInfo *rel, Path *subpath,
|
|
List *pathkeys, Relids required_outer);
|
|
extern Path *create_functionscan_path(PlannerInfo *root, RelOptInfo *rel,
|
|
List *pathkeys, Relids required_outer);
|
|
extern Path *create_valuesscan_path(PlannerInfo *root, RelOptInfo *rel,
|
|
Relids required_outer);
|
|
extern Path *create_ctescan_path(PlannerInfo *root, RelOptInfo *rel,
|
|
Relids required_outer);
|
|
extern Path *create_worktablescan_path(PlannerInfo *root, RelOptInfo *rel,
|
|
Relids required_outer);
|
|
extern ForeignPath *create_foreignscan_path(PlannerInfo *root, RelOptInfo *rel,
|
|
PathTarget *target,
|
|
double rows, Cost startup_cost, Cost total_cost,
|
|
List *pathkeys,
|
|
Relids required_outer,
|
|
Path *fdw_outerpath,
|
|
List *fdw_private);
|
|
|
|
extern Relids calc_nestloop_required_outer(Path *outer_path, Path *inner_path);
|
|
extern Relids calc_non_nestloop_required_outer(Path *outer_path, Path *inner_path);
|
|
|
|
extern NestPath *create_nestloop_path(PlannerInfo *root,
|
|
RelOptInfo *joinrel,
|
|
JoinType jointype,
|
|
JoinCostWorkspace *workspace,
|
|
SpecialJoinInfo *sjinfo,
|
|
SemiAntiJoinFactors *semifactors,
|
|
Path *outer_path,
|
|
Path *inner_path,
|
|
List *restrict_clauses,
|
|
List *pathkeys,
|
|
Relids required_outer);
|
|
|
|
extern MergePath *create_mergejoin_path(PlannerInfo *root,
|
|
RelOptInfo *joinrel,
|
|
JoinType jointype,
|
|
JoinCostWorkspace *workspace,
|
|
SpecialJoinInfo *sjinfo,
|
|
Path *outer_path,
|
|
Path *inner_path,
|
|
List *restrict_clauses,
|
|
List *pathkeys,
|
|
Relids required_outer,
|
|
List *mergeclauses,
|
|
List *outersortkeys,
|
|
List *innersortkeys);
|
|
|
|
extern HashPath *create_hashjoin_path(PlannerInfo *root,
|
|
RelOptInfo *joinrel,
|
|
JoinType jointype,
|
|
JoinCostWorkspace *workspace,
|
|
SpecialJoinInfo *sjinfo,
|
|
SemiAntiJoinFactors *semifactors,
|
|
Path *outer_path,
|
|
Path *inner_path,
|
|
List *restrict_clauses,
|
|
Relids required_outer,
|
|
List *hashclauses);
|
|
|
|
extern ProjectionPath *create_projection_path(PlannerInfo *root,
|
|
RelOptInfo *rel,
|
|
Path *subpath,
|
|
PathTarget *target);
|
|
extern Path *apply_projection_to_path(PlannerInfo *root,
|
|
RelOptInfo *rel,
|
|
Path *path,
|
|
PathTarget *target);
|
|
extern ProjectSetPath *create_set_projection_path(PlannerInfo *root,
|
|
RelOptInfo *rel,
|
|
Path *subpath,
|
|
PathTarget *target);
|
|
extern SortPath *create_sort_path(PlannerInfo *root,
|
|
RelOptInfo *rel,
|
|
Path *subpath,
|
|
List *pathkeys,
|
|
double limit_tuples);
|
|
extern GroupPath *create_group_path(PlannerInfo *root,
|
|
RelOptInfo *rel,
|
|
Path *subpath,
|
|
PathTarget *target,
|
|
List *groupClause,
|
|
List *qual,
|
|
double numGroups);
|
|
extern UpperUniquePath *create_upper_unique_path(PlannerInfo *root,
|
|
RelOptInfo *rel,
|
|
Path *subpath,
|
|
int numCols,
|
|
double numGroups);
|
|
extern AggPath *create_agg_path(PlannerInfo *root,
|
|
RelOptInfo *rel,
|
|
Path *subpath,
|
|
PathTarget *target,
|
|
AggStrategy aggstrategy,
|
|
AggSplit aggsplit,
|
|
List *groupClause,
|
|
List *qual,
|
|
const AggClauseCosts *aggcosts,
|
|
double numGroups);
|
|
extern GroupingSetsPath *create_groupingsets_path(PlannerInfo *root,
|
|
RelOptInfo *rel,
|
|
Path *subpath,
|
|
PathTarget *target,
|
|
List *having_qual,
|
|
List *rollup_lists,
|
|
List *rollup_groupclauses,
|
|
const AggClauseCosts *agg_costs,
|
|
double numGroups);
|
|
extern MinMaxAggPath *create_minmaxagg_path(PlannerInfo *root,
|
|
RelOptInfo *rel,
|
|
PathTarget *target,
|
|
List *mmaggregates,
|
|
List *quals);
|
|
extern WindowAggPath *create_windowagg_path(PlannerInfo *root,
|
|
RelOptInfo *rel,
|
|
Path *subpath,
|
|
PathTarget *target,
|
|
List *windowFuncs,
|
|
WindowClause *winclause,
|
|
List *winpathkeys);
|
|
extern SetOpPath *create_setop_path(PlannerInfo *root,
|
|
RelOptInfo *rel,
|
|
Path *subpath,
|
|
SetOpCmd cmd,
|
|
SetOpStrategy strategy,
|
|
List *distinctList,
|
|
AttrNumber flagColIdx,
|
|
int firstFlag,
|
|
double numGroups,
|
|
double outputRows);
|
|
extern RecursiveUnionPath *create_recursiveunion_path(PlannerInfo *root,
|
|
RelOptInfo *rel,
|
|
Path *leftpath,
|
|
Path *rightpath,
|
|
PathTarget *target,
|
|
List *distinctList,
|
|
int wtParam,
|
|
double numGroups);
|
|
extern LockRowsPath *create_lockrows_path(PlannerInfo *root, RelOptInfo *rel,
|
|
Path *subpath, List *rowMarks, int epqParam);
|
|
extern ModifyTablePath *create_modifytable_path(PlannerInfo *root,
|
|
RelOptInfo *rel,
|
|
CmdType operation, bool canSetTag,
|
|
Index nominalRelation,
|
|
List *resultRelations, List *subpaths,
|
|
List *subroots,
|
|
List *withCheckOptionLists, List *returningLists,
|
|
List *rowMarks, OnConflictExpr *onconflict,
|
|
int epqParam);
|
|
extern LimitPath *create_limit_path(PlannerInfo *root, RelOptInfo *rel,
|
|
Path *subpath,
|
|
Node *limitOffset, Node *limitCount,
|
|
int64 offset_est, int64 count_est);
|
|
|
|
extern Path *reparameterize_path(PlannerInfo *root, Path *path,
|
|
Relids required_outer,
|
|
double loop_count);
|
|
|
|
/*
|
|
* prototypes for relnode.c
|
|
*/
|
|
extern void setup_simple_rel_arrays(PlannerInfo *root);
|
|
extern RelOptInfo *build_simple_rel(PlannerInfo *root, int relid,
|
|
RelOptKind reloptkind);
|
|
extern RelOptInfo *find_base_rel(PlannerInfo *root, int relid);
|
|
extern RelOptInfo *find_join_rel(PlannerInfo *root, Relids relids);
|
|
extern RelOptInfo *build_join_rel(PlannerInfo *root,
|
|
Relids joinrelids,
|
|
RelOptInfo *outer_rel,
|
|
RelOptInfo *inner_rel,
|
|
SpecialJoinInfo *sjinfo,
|
|
List **restrictlist_ptr);
|
|
extern Relids min_join_parameterization(PlannerInfo *root,
|
|
Relids joinrelids,
|
|
RelOptInfo *outer_rel,
|
|
RelOptInfo *inner_rel);
|
|
extern RelOptInfo *build_empty_join_rel(PlannerInfo *root);
|
|
extern RelOptInfo *fetch_upper_rel(PlannerInfo *root, UpperRelationKind kind,
|
|
Relids relids);
|
|
extern AppendRelInfo *find_childrel_appendrelinfo(PlannerInfo *root,
|
|
RelOptInfo *rel);
|
|
extern RelOptInfo *find_childrel_top_parent(PlannerInfo *root, RelOptInfo *rel);
|
|
extern Relids find_childrel_parents(PlannerInfo *root, RelOptInfo *rel);
|
|
extern ParamPathInfo *get_baserel_parampathinfo(PlannerInfo *root,
|
|
RelOptInfo *baserel,
|
|
Relids required_outer);
|
|
extern ParamPathInfo *get_joinrel_parampathinfo(PlannerInfo *root,
|
|
RelOptInfo *joinrel,
|
|
Path *outer_path,
|
|
Path *inner_path,
|
|
SpecialJoinInfo *sjinfo,
|
|
Relids required_outer,
|
|
List **restrict_clauses);
|
|
extern ParamPathInfo *get_appendrel_parampathinfo(RelOptInfo *appendrel,
|
|
Relids required_outer);
|
|
|
|
#endif /* PATHNODE_H */
|