diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-14 19:16:19 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-14 19:16:19 +0000 |
commit | 31176cd686f31dcb71392f6583f7b8d9cef63770 (patch) | |
tree | 27fefbaada5177e179c6cf8806be49dfe613d5f4 /src/backend/optimizer | |
parent | Adding upstream version 16.2. (diff) | |
download | postgresql-16-upstream.tar.xz postgresql-16-upstream.zip |
Adding upstream version 16.3.upstream/16.3upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/backend/optimizer')
-rw-r--r-- | src/backend/optimizer/path/equivclass.c | 15 | ||||
-rw-r--r-- | src/backend/optimizer/plan/planner.c | 27 | ||||
-rw-r--r-- | src/backend/optimizer/prep/prepjointree.c | 4 | ||||
-rw-r--r-- | src/backend/optimizer/util/clauses.c | 43 | ||||
-rw-r--r-- | src/backend/optimizer/util/pathnode.c | 9 | ||||
-rw-r--r-- | src/backend/optimizer/util/relnode.c | 26 |
6 files changed, 90 insertions, 34 deletions
diff --git a/src/backend/optimizer/path/equivclass.c b/src/backend/optimizer/path/equivclass.c index 7fa502d..e79c7e4 100644 --- a/src/backend/optimizer/path/equivclass.c +++ b/src/backend/optimizer/path/equivclass.c @@ -1885,6 +1885,21 @@ create_join_clause(PlannerInfo *root, rightem->em_relids), ec->ec_min_security); + /* + * If either EM is a child, force the clause's clause_relids to include + * the relid(s) of the child rel. In normal cases it would already, but + * not if we are considering appendrel child relations with pseudoconstant + * translated variables (i.e., UNION ALL sub-selects with constant output + * items). We must do this so that join_clause_is_movable_into() will + * think that the clause should be evaluated at the correct place. + */ + if (leftem->em_is_child) + rinfo->clause_relids = bms_add_members(rinfo->clause_relids, + leftem->em_relids); + if (rightem->em_is_child) + rinfo->clause_relids = bms_add_members(rinfo->clause_relids, + rightem->em_relids); + /* If it's a child clause, copy the parent's rinfo_serial */ if (parent_rinfo) rinfo->rinfo_serial = parent_rinfo->rinfo_serial; diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 80ad6bf..2ffef1b 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -7349,13 +7349,24 @@ gather_grouping_paths(PlannerInfo *root, RelOptInfo *rel) { ListCell *lc; Path *cheapest_partial_path; + List *groupby_pathkeys; + + /* + * This occurs after any partial aggregation has taken place, so trim off + * any pathkeys added for ORDER BY / DISTINCT aggregates. + */ + if (list_length(root->group_pathkeys) > root->num_groupby_pathkeys) + groupby_pathkeys = list_copy_head(root->group_pathkeys, + root->num_groupby_pathkeys); + else + groupby_pathkeys = root->group_pathkeys; /* Try Gather for unordered paths and Gather Merge for ordered ones. */ generate_useful_gather_paths(root, rel, true); /* Try cheapest partial path + explicit Sort + Gather Merge. */ cheapest_partial_path = linitial(rel->partial_pathlist); - if (!pathkeys_contained_in(root->group_pathkeys, + if (!pathkeys_contained_in(groupby_pathkeys, cheapest_partial_path->pathkeys)) { Path *path; @@ -7364,14 +7375,14 @@ gather_grouping_paths(PlannerInfo *root, RelOptInfo *rel) total_groups = cheapest_partial_path->rows * cheapest_partial_path->parallel_workers; path = (Path *) create_sort_path(root, rel, cheapest_partial_path, - root->group_pathkeys, + groupby_pathkeys, -1.0); path = (Path *) create_gather_merge_path(root, rel, path, rel->reltarget, - root->group_pathkeys, + groupby_pathkeys, NULL, &total_groups); @@ -7382,10 +7393,10 @@ gather_grouping_paths(PlannerInfo *root, RelOptInfo *rel) * Consider incremental sort on all partial paths, if enabled. * * We can also skip the entire loop when we only have a single-item - * group_pathkeys because then we can't possibly have a presorted prefix + * groupby_pathkeys because then we can't possibly have a presorted prefix * of the list without having the list be fully sorted. */ - if (!enable_incremental_sort || list_length(root->group_pathkeys) == 1) + if (!enable_incremental_sort || list_length(groupby_pathkeys) == 1) return; /* also consider incremental sort on partial paths, if enabled */ @@ -7396,7 +7407,7 @@ gather_grouping_paths(PlannerInfo *root, RelOptInfo *rel) int presorted_keys; double total_groups; - is_sorted = pathkeys_count_contained_in(root->group_pathkeys, + is_sorted = pathkeys_count_contained_in(groupby_pathkeys, path->pathkeys, &presorted_keys); @@ -7409,7 +7420,7 @@ gather_grouping_paths(PlannerInfo *root, RelOptInfo *rel) path = (Path *) create_incremental_sort_path(root, rel, path, - root->group_pathkeys, + groupby_pathkeys, presorted_keys, -1.0); @@ -7418,7 +7429,7 @@ gather_grouping_paths(PlannerInfo *root, RelOptInfo *rel) rel, path, rel->reltarget, - root->group_pathkeys, + groupby_pathkeys, NULL, &total_groups); diff --git a/src/backend/optimizer/prep/prepjointree.c b/src/backend/optimizer/prep/prepjointree.c index 57262f9..1171097 100644 --- a/src/backend/optimizer/prep/prepjointree.c +++ b/src/backend/optimizer/prep/prepjointree.c @@ -1805,6 +1805,10 @@ pull_up_constant_function(PlannerInfo *root, Node *jtnode, if (rtf->funccolcount != 1) return jtnode; /* definitely composite */ + /* If it has a coldeflist, it certainly returns RECORD */ + if (rtf->funccolnames != NIL) + return jtnode; /* must be a one-column RECORD type */ + functypclass = get_expr_result_type(rtf->funcexpr, &funcrettype, &tupdesc); diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index 507c101..6265099 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -2423,6 +2423,10 @@ static Node * eval_const_expressions_mutator(Node *node, eval_const_expressions_context *context) { + + /* since this function recurses, it could be driven to stack overflow */ + check_stack_depth(); + if (node == NULL) return NULL; switch (nodeTag(node)) @@ -4410,12 +4414,11 @@ evaluate_function(Oid funcid, Oid result_type, int32 result_typmod, * Can't simplify if it returns RECORD. The immediate problem is that it * will be needing an expected tupdesc which we can't supply here. * - * In the case where it has OUT parameters, it could get by without an - * expected tupdesc, but we still have issues: get_expr_result_type() - * doesn't know how to extract type info from a RECORD constant, and in - * the case of a NULL function result there doesn't seem to be any clean - * way to fix that. In view of the likelihood of there being still other - * gotchas, seems best to leave the function call unreduced. + * In the case where it has OUT parameters, we could build an expected + * tupdesc from those, but there may be other gotchas lurking. In + * particular, if the function were to return NULL, we would produce a + * null constant with no remaining indication of which concrete record + * type it is. For now, seems best to leave the function call unreduced. */ if (funcform->prorettype == RECORDOID) return NULL; @@ -4704,9 +4707,10 @@ inline_function(Oid funcid, Oid result_type, Oid result_collid, * needed; that's probably not important, but let's be careful. */ querytree_list = list_make1(querytree); - if (check_sql_fn_retval(list_make1(querytree_list), - result_type, rettupdesc, - false, NULL)) + if (check_sql_fn_retval_ext(list_make1(querytree_list), + result_type, rettupdesc, + funcform->prokind, + false, NULL)) goto fail; /* reject whole-tuple-result cases */ /* @@ -5215,16 +5219,20 @@ inline_set_returning_function(PlannerInfo *root, RangeTblEntry *rte) } /* - * Also resolve the actual function result tupdesc, if composite. If the - * function is just declared to return RECORD, dig the info out of the AS - * clause. + * Also resolve the actual function result tupdesc, if composite. If we + * have a coldeflist, believe that; otherwise use get_expr_result_type. + * (This logic should match ExecInitFunctionScan.) */ - functypclass = get_expr_result_type((Node *) fexpr, NULL, &rettupdesc); - if (functypclass == TYPEFUNC_RECORD) + if (rtfunc->funccolnames != NIL) + { + functypclass = TYPEFUNC_RECORD; rettupdesc = BuildDescFromLists(rtfunc->funccolnames, rtfunc->funccoltypes, rtfunc->funccoltypmods, rtfunc->funccolcollations); + } + else + functypclass = get_expr_result_type((Node *) fexpr, NULL, &rettupdesc); /* * The single command must be a plain SELECT. @@ -5246,9 +5254,10 @@ inline_set_returning_function(PlannerInfo *root, RangeTblEntry *rte) * shows it's returning a whole tuple result; otherwise what it's * returning is a single composite column which is not what we need. */ - if (!check_sql_fn_retval(list_make1(querytree_list), - fexpr->funcresulttype, rettupdesc, - true, NULL) && + if (!check_sql_fn_retval_ext(list_make1(querytree_list), + fexpr->funcresulttype, rettupdesc, + funcform->prokind, + true, NULL) && (functypclass == TYPEFUNC_COMPOSITE || functypclass == TYPEFUNC_COMPOSITE_DOMAIN || functypclass == TYPEFUNC_RECORD)) diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c index 841be37..bd23226 100644 --- a/src/backend/optimizer/util/pathnode.c +++ b/src/backend/optimizer/util/pathnode.c @@ -1708,8 +1708,13 @@ create_unique_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, pathnode->path.pathkeys = NIL; pathnode->subpath = subpath; - pathnode->in_operators = sjinfo->semi_operators; - pathnode->uniq_exprs = sjinfo->semi_rhs_exprs; + + /* + * Under GEQO, the sjinfo might be short-lived, so we'd better make copies + * of data structures we extract from it. + */ + pathnode->in_operators = copyObject(sjinfo->semi_operators); + pathnode->uniq_exprs = copyObject(sjinfo->semi_rhs_exprs); /* * If the input is a relation and it has a unique index that proves the diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c index 76dad17..e6d5cd8 100644 --- a/src/backend/optimizer/util/relnode.c +++ b/src/backend/optimizer/util/relnode.c @@ -1535,6 +1535,7 @@ get_baserel_parampathinfo(PlannerInfo *root, RelOptInfo *baserel, ParamPathInfo *ppi; Relids joinrelids; List *pclauses; + List *eqclauses; Bitmapset *pserials; double rows; ListCell *lc; @@ -1570,14 +1571,25 @@ get_baserel_parampathinfo(PlannerInfo *root, RelOptInfo *baserel, /* * Add in joinclauses generated by EquivalenceClasses, too. (These - * necessarily satisfy join_clause_is_movable_into.) + * necessarily satisfy join_clause_is_movable_into; but in assert-enabled + * builds, let's verify that.) */ - pclauses = list_concat(pclauses, - generate_join_implied_equalities(root, - joinrelids, - required_outer, - baserel, - NULL)); + eqclauses = generate_join_implied_equalities(root, + joinrelids, + required_outer, + baserel, + NULL); +#ifdef USE_ASSERT_CHECKING + foreach(lc, eqclauses) + { + RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc); + + Assert(join_clause_is_movable_into(rinfo, + baserel->relids, + joinrelids)); + } +#endif + pclauses = list_concat(pclauses, eqclauses); /* Compute set of serial numbers of the enforced clauses */ pserials = NULL; |