summaryrefslogtreecommitdiffstats
path: root/src/backend/optimizer
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/backend/optimizer/path/equivclass.c15
-rw-r--r--src/backend/optimizer/prep/prepjointree.c4
-rw-r--r--src/backend/optimizer/util/clauses.c43
-rw-r--r--src/backend/optimizer/util/pathnode.c9
-rw-r--r--src/backend/optimizer/util/relnode.c25
5 files changed, 70 insertions, 26 deletions
diff --git a/src/backend/optimizer/path/equivclass.c b/src/backend/optimizer/path/equivclass.c
index 9f39f46..06f89a6 100644
--- a/src/backend/optimizer/path/equivclass.c
+++ b/src/backend/optimizer/path/equivclass.c
@@ -1851,6 +1851,21 @@ create_join_clause(PlannerInfo *root,
rightem->em_nullable_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);
+
/* Mark the clause as redundant, or not */
rinfo->parent_ec = parent_ec;
diff --git a/src/backend/optimizer/prep/prepjointree.c b/src/backend/optimizer/prep/prepjointree.c
index ea05763..0efcc3b 100644
--- a/src/backend/optimizer/prep/prepjointree.c
+++ b/src/backend/optimizer/prep/prepjointree.c
@@ -1822,6 +1822,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 e1cedd9..9fcfd55 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -2347,6 +2347,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))
@@ -4319,12 +4323,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;
@@ -4618,9 +4621,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 */
/*
@@ -5134,16 +5138,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.
@@ -5165,9 +5173,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 46fd29b..e5c82bf 100644
--- a/src/backend/optimizer/util/pathnode.c
+++ b/src/backend/optimizer/util/pathnode.c
@@ -1696,8 +1696,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 3c75fd5..6e1c87a 100644
--- a/src/backend/optimizer/util/relnode.c
+++ b/src/backend/optimizer/util/relnode.c
@@ -1300,6 +1300,7 @@ get_baserel_parampathinfo(PlannerInfo *root, RelOptInfo *baserel,
ParamPathInfo *ppi;
Relids joinrelids;
List *pclauses;
+ List *eqclauses;
double rows;
ListCell *lc;
@@ -1333,14 +1334,24 @@ get_baserel_parampathinfo(PlannerInfo *root, RelOptInfo *baserel,
}
/*
- * Add in joinclauses generated by EquivalenceClasses, too. (These
- * necessarily satisfy join_clause_is_movable_into.)
+ * Add in joinclauses generated by EquivalenceClasses, too. In principle
+ * these should always satisfy join_clause_is_movable_into; but if we are
+ * below an outer join the clauses might contain Vars that should only be
+ * evaluated above the join, so we have to check.
*/
- pclauses = list_concat(pclauses,
- generate_join_implied_equalities(root,
- joinrelids,
- required_outer,
- baserel));
+ eqclauses = generate_join_implied_equalities(root,
+ joinrelids,
+ required_outer,
+ baserel);
+ foreach(lc, eqclauses)
+ {
+ RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
+
+ if (join_clause_is_movable_into(rinfo,
+ baserel->relids,
+ joinrelids))
+ pclauses = lappend(pclauses, rinfo);
+ }
/* Estimate the number of rows returned by the parameterized scan */
rows = get_parameterized_baserel_size(root, baserel, pclauses);