From 5d3f393ea345e33001f0fea79e51ff146fc9fdca Mon Sep 17 00:00:00 2001 From: TsinghuaLucky912 <2903807914@qq.com> Date: Wed, 27 Nov 2024 01:00:42 -0800 Subject: [PATCH] Added prosupport functions for estimating numeric generate_series rows --- src/backend/utils/adt/numeric.c | 103 ++++++++++++++++++++++++++++++++ src/include/catalog/pg_proc.dat | 9 ++- 2 files changed, 110 insertions(+), 2 deletions(-) diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c index 344d7137f9..5c67e1f443 100644 --- a/src/backend/utils/adt/numeric.c +++ b/src/backend/utils/adt/numeric.c @@ -32,6 +32,7 @@ #include "lib/hyperloglog.h" #include "libpq/pqformat.h" #include "miscadmin.h" +#include "optimizer/optimizer.h" #include "nodes/nodeFuncs.h" #include "nodes/supportnodes.h" #include "utils/array.h" @@ -1828,6 +1829,108 @@ generate_series_step_numeric(PG_FUNCTION_ARGS) } +/* + * Planner support function for generate_series(numeric, numeric [, numeric]) + */ +Datum +generate_series_numeric_support(PG_FUNCTION_ARGS) +{ + Node *rawreq = (Node *) PG_GETARG_POINTER(0); + Node *ret = NULL; + + if (IsA(rawreq, SupportRequestRows)) + { + /* Try to estimate the number of rows returned */ + SupportRequestRows *req = (SupportRequestRows *) rawreq; + + if (is_funcclause(req->node)) /* be paranoid */ + { + List *args = ((FuncExpr *) req->node)->args; + Node *arg1, + *arg2, + *arg3; + + /* We can use estimated argument values here */ + arg1 = estimate_expression_value(req->root, linitial(args)); + arg2 = estimate_expression_value(req->root, lsecond(args)); + if (list_length(args) >= 3) + arg3 = estimate_expression_value(req->root, lthird(args)); + else + arg3 = NULL; + + /* + * If any argument is constant NULL, we can safely assume that + * zero rows are returned. Otherwise, if they're all non-NULL + * constants, we can calculate the number of rows that will be + * returned. Use double arithmetic to avoid overflow hazards. + */ + if ((IsA(arg1, Const) && + ((Const *) arg1)->constisnull) || + (IsA(arg2, Const) && + ((Const *) arg2)->constisnull) || + (arg3 != NULL && IsA(arg3, Const) && + ((Const *) arg3)->constisnull)) + { + req->rows = 0; + ret = (Node *) req; + } + else if (IsA(arg1, Const) && + IsA(arg2, Const) && + (arg3 == NULL || IsA(arg3, Const))) + { + Numeric start, + finish, + step; + NumericVar var_start, + var_finish, + var_diff; + NumericVar nstep = const_one; + + init_var(&var_start); + init_var(&var_finish); + init_var(&var_diff); + + start = DatumGetNumeric(((Const *) arg1)->constvalue); + finish = DatumGetNumeric(((Const *) arg2)->constvalue); + + set_var_from_num(start, &var_start); + set_var_from_num(finish, &var_finish); + + if(arg3) + { + step = DatumGetNumeric(((Const *) arg3)->constvalue); + init_var_from_num(step, &nstep); + } + + sub_var(&var_finish, &var_start, &var_diff); + + /* This equation works for either sign of step */ + if (cmp_var(&nstep, &const_zero) != 0) + { + if(nstep.sign != var_diff.sign) + { + req->rows = 0; + ret = (Node *) req; + } + else + { + double ddiff; + NumericVar q; + init_var(&q); + div_var(&var_diff, &nstep, &q, 0, false, false); + ddiff = numericvar_to_double_no_overflow(&q); + + req->rows = floor(ddiff + 1); + ret = (Node *) req; + } + } + } + } + } + + PG_RETURN_POINTER(ret); +} + /* * Implements the numeric version of the width_bucket() function * defined by SQL2003. See also width_bucket_float8(). diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index cbbe8acd38..9575524007 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -8464,13 +8464,18 @@ proname => 'generate_series_int8_support', prorettype => 'internal', proargtypes => 'internal', prosrc => 'generate_series_int8_support' }, { oid => '3259', descr => 'non-persistent series generator', - proname => 'generate_series', prorows => '1000', proretset => 't', + proname => 'generate_series', prorows => '1000', + prosupport => 'generate_series_numeric_support', proretset => 't', prorettype => 'numeric', proargtypes => 'numeric numeric numeric', prosrc => 'generate_series_step_numeric' }, { oid => '3260', descr => 'non-persistent series generator', - proname => 'generate_series', prorows => '1000', proretset => 't', + proname => 'generate_series', prorows => '1000', + prosupport => 'generate_series_numeric_support', proretset => 't', prorettype => 'numeric', proargtypes => 'numeric numeric', prosrc => 'generate_series_numeric' }, +{ oid => '8405', descr => 'planner support for generate_series', + proname => 'generate_series_numeric_support', prorettype => 'internal', + proargtypes => 'internal', prosrc => 'generate_series_numeric_support' }, { oid => '938', descr => 'non-persistent series generator', proname => 'generate_series', prorows => '1000', prosupport => 'generate_series_timestamp_support', proretset => 't', -- 2.31.1