summaryrefslogtreecommitdiffstats
path: root/src/backend/optimizer/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/util')
-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
3 files changed, 51 insertions, 26 deletions
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);