diff options
Diffstat (limited to 'src/backend')
| -rw-r--r-- | src/backend/optimizer/plan/initsplan.c | 20 | ||||
| -rw-r--r-- | src/backend/optimizer/util/clauses.c | 73 | ||||
| -rw-r--r-- | src/backend/utils/adt/int8.c | 49 |
3 files changed, 123 insertions, 19 deletions
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c index 65d473d95b6..671c5cde8fc 100644 --- a/src/backend/optimizer/plan/initsplan.c +++ b/src/backend/optimizer/plan/initsplan.c @@ -3414,22 +3414,6 @@ add_base_clause_to_rel(PlannerInfo *root, Index relid, } /* - * expr_is_nonnullable - * Check to see if the Expr cannot be NULL - * - * Currently we only support simple Vars. - */ -static bool -expr_is_nonnullable(PlannerInfo *root, Expr *expr) -{ - /* For now only check simple Vars */ - if (!IsA(expr, Var)) - return false; - - return var_is_nonnullable(root, (Var *) expr, true); -} - -/* * restriction_is_always_true * Check to see if the RestrictInfo is always true. * @@ -3465,7 +3449,7 @@ restriction_is_always_true(PlannerInfo *root, if (nulltest->argisrow) return false; - return expr_is_nonnullable(root, nulltest->arg); + return expr_is_nonnullable(root, nulltest->arg, true); } /* If it's an OR, check its sub-clauses */ @@ -3530,7 +3514,7 @@ restriction_is_always_false(PlannerInfo *root, if (nulltest->argisrow) return false; - return expr_is_nonnullable(root, nulltest->arg); + return expr_is_nonnullable(root, nulltest->arg, true); } /* If it's an OR, check its sub-clauses */ diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index 202ba8ed4bb..9975185934b 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -131,6 +131,8 @@ static Expr *simplify_function(Oid funcid, Oid result_collid, Oid input_collid, List **args_p, bool funcvariadic, bool process_args, bool allow_non_const, eval_const_expressions_context *context); +static Node *simplify_aggref(Aggref *aggref, + eval_const_expressions_context *context); static List *reorder_function_arguments(List *args, int pronargs, HeapTuple func_tuple); static List *add_function_defaults(List *args, int pronargs, @@ -2634,6 +2636,9 @@ eval_const_expressions_mutator(Node *node, newexpr->location = expr->location; return (Node *) newexpr; } + case T_Aggref: + node = ece_generic_processing(node); + return simplify_aggref((Aggref *) node, context); case T_OpExpr: { OpExpr *expr = (OpExpr *) node; @@ -4201,6 +4206,50 @@ simplify_function(Oid funcid, Oid result_type, int32 result_typmod, } /* + * simplify_aggref + * Call the Aggref.aggfnoid's prosupport function to allow it to + * determine if simplification of the Aggref is possible. Returns the + * newly simplified node if conversion took place; otherwise, returns the + * original Aggref. + * + * See SupportRequestSimplifyAggref comments in supportnodes.h for further + * details. + */ +static Node * +simplify_aggref(Aggref *aggref, eval_const_expressions_context *context) +{ + Oid prosupport = get_func_support(aggref->aggfnoid); + + if (OidIsValid(prosupport)) + { + SupportRequestSimplifyAggref req; + Node *newnode; + + /* + * Build a SupportRequestSimplifyAggref node to pass to the support + * function. + */ + req.type = T_SupportRequestSimplifyAggref; + req.root = context->root; + req.aggref = aggref; + + newnode = (Node *) DatumGetPointer(OidFunctionCall1(prosupport, + PointerGetDatum(&req))); + + /* + * We expect the support function to return either a new Node or NULL + * (when simplification isn't possible). + */ + Assert(newnode != (Node *) aggref || newnode == NULL); + + if (newnode != NULL) + return newnode; + } + + return (Node *) aggref; +} + +/* * var_is_nonnullable: check to see if the Var cannot be NULL * * If the Var is defined NOT NULL and meanwhile is not nulled by any outer @@ -4262,6 +4311,30 @@ var_is_nonnullable(PlannerInfo *root, Var *var, bool use_rel_info) } /* + * expr_is_nonnullable: check to see if the Expr cannot be NULL + * + * Returns true iff the given 'expr' cannot produce SQL NULLs. + * + * If 'use_rel_info' is true, nullability of Vars is checked via the + * corresponding RelOptInfo for the given Var. Some callers require + * nullability information before RelOptInfos are generated. These should + * pass 'use_rel_info' as false. + * + * For now, we only support Var and Const. Support for other node types may + * be possible. + */ +bool +expr_is_nonnullable(PlannerInfo *root, Expr *expr, bool use_rel_info) +{ + if (IsA(expr, Var)) + return var_is_nonnullable(root, (Var *) expr, use_rel_info); + if (IsA(expr, Const)) + return !castNode(Const, expr)->constisnull; + + return false; +} + +/* * expand_function_arguments: convert named-notation args to positional args * and/or insert default args, as needed * diff --git a/src/backend/utils/adt/int8.c b/src/backend/utils/adt/int8.c index bdea490202a..9cd420b4b9d 100644 --- a/src/backend/utils/adt/int8.c +++ b/src/backend/utils/adt/int8.c @@ -24,7 +24,7 @@ #include "nodes/supportnodes.h" #include "optimizer/optimizer.h" #include "utils/builtins.h" - +#include "utils/fmgroids.h" typedef struct { @@ -811,6 +811,53 @@ int8inc_support(PG_FUNCTION_ARGS) PG_RETURN_POINTER(req); } + if (IsA(rawreq, SupportRequestSimplifyAggref)) + { + SupportRequestSimplifyAggref *req = (SupportRequestSimplifyAggref *) rawreq; + Aggref *agg = req->aggref; + + /* + * Check for COUNT(ANY) and try to convert to COUNT(*). The input + * argument cannot be NULL, we can't have an ORDER BY / DISTINCT in + * the aggregate, and agglevelsup must be 0. + * + * Technically COUNT(ANY) must have 1 arg, but be paranoid and check. + */ + if (agg->aggfnoid == F_COUNT_ANY && list_length(agg->args) == 1) + { + TargetEntry *tle = (TargetEntry *) linitial(agg->args); + Expr *arg = tle->expr; + + /* Check for unsupported cases */ + if (agg->aggdistinct != NIL || agg->aggorder != NIL || + agg->agglevelsup != 0) + PG_RETURN_POINTER(NULL); + + /* If the arg isn't NULLable, do the conversion */ + if (expr_is_nonnullable(req->root, arg, false)) + { + Aggref *newagg; + + /* We don't expect these to have been set yet */ + Assert(agg->aggtransno == -1); + Assert(agg->aggtranstype == InvalidOid); + + /* Convert COUNT(ANY) to COUNT(*) by making a new Aggref */ + newagg = makeNode(Aggref); + memcpy(newagg, agg, sizeof(Aggref)); + newagg->aggfnoid = F_COUNT_; + + /* count(*) has no args */ + newagg->aggargtypes = NULL; + newagg->args = NULL; + newagg->aggstar = true; + newagg->location = -1; + + PG_RETURN_POINTER(newagg); + } + } + } + PG_RETURN_POINTER(NULL); } |
