提交 b877cd43 编写于 作者: H Heikki Linnakangas

Implement MEDIAN, as syntactic sugar over percentile_cont(0.5).

There's a rule in the grammar to accept MEDIAN(x), and turn it into
"median(0.5) WITHING GROUP (ORDER BY x)". The median function is
identical to percent_cont(), the pg_proc entry borrows percent_cont's
implementation. But it's a separate function so that we can distinguish
which syntax the user used, for deparsing.

In ruleutils.c, check if the special median functions were used, and
deparse back the "median(0.5) WITHIN GROUP (ORDER BY x)" into "MEDIAN(x)"
上级 33ef6134
......@@ -622,7 +622,7 @@ static Node *makeIsNotDistinctFromNode(Node *expr, int position);
LIST LOG_P
MASTER MISSING MODIFIES
MASTER MEDIAN MISSING MODIFIES
NEWLINE NOCREATEEXTTABLE NOOVERCOMMIT
......@@ -970,6 +970,7 @@ static Node *makeIsNotDistinctFromNode(Node *expr, int position);
%nonassoc INTEGER
%nonassoc INTERVAL
%nonassoc LEAST
%nonassoc MEDIAN
%nonassoc NATIONAL
%nonassoc NCHAR
%nonassoc NONE
......@@ -12229,6 +12230,34 @@ func_expr_common_subexpr:
GroupId *gid = makeNode(GroupId);
$$ = (Node *)gid;
}
| MEDIAN '(' a_expr ')'
{
/*
* MEDIAN is parsed as an alias to percentile_cont(0.5).
* We keep track of original expression to deparse
* it later in views, etc.
*/
FuncCall *n;
SortBy *sortby;
n = makeNode(FuncCall);
n->funcname = SystemFuncName("median");
n->args = list_make1(makeAConst(makeFloat(pstrdup("0.5")), @1));
sortby = makeNode(SortBy);
sortby->node = $3;
sortby->sortby_dir = SORTBY_DEFAULT;
sortby->sortby_nulls = SORTBY_NULLS_DEFAULT;
sortby->useOp = NIL;
sortby->location = -1; /* no operator */
n->agg_order = list_make1(sortby);
n->agg_within_group = TRUE;
n->agg_filter = NULL;
n->over = NULL;
n->location = @1;
$$ = (Node *) n;
}
| DECODE '(' a_expr ',' a_expr ')'
{
FuncCall *n = makeNode(FuncCall);
......@@ -14012,6 +14041,7 @@ col_name_keyword:
| INTEGER
| INTERVAL
| LEAST
| MEDIAN
| NATIONAL
| NCHAR
| NONE
......
......@@ -5617,6 +5617,48 @@ get_rule_orderby(List *orderList, List *targetList,
context, "");
}
/*
* Deparse an Aggref as a special MEDIAN() construct, if it looks like
* one.
*
* Returns true if the reference was handled as MEDIAN, false otherwise.
*/
static bool
get_median_expr(Aggref *aggref, deparse_context *context)
{
StringInfo buf = context->buf;
TargetEntry *tle;
if (!IS_MEDIAN_OID(aggref->aggfnoid))
return false;
if (list_length(aggref->aggdirectargs) != 1)
return false;
if (list_length(aggref->args) != 1)
return false;
tle = (TargetEntry *) linitial(aggref->args);
if (tle->resjunk)
return false;
/* Ok, it looks like a MEDIAN */
appendStringInfoString(buf, "MEDIAN(");
get_rule_expr((Node *) tle->expr, context, false);
/*
* MEDIAN (...) FILTER (...) isn't currently allowed by the grammar,
* but it's easy enough to handle here, so let's be prepared.
*/
if (aggref->aggfilter != NULL)
{
appendStringInfoString(buf, ") FILTER (WHERE ");
get_rule_expr((Node *) aggref->aggfilter, context, false);
}
appendStringInfoChar(buf, ')');
return true;
}
/*
* get_agg_expr - Parse back an Aggref node
*/
......@@ -5629,6 +5671,10 @@ get_agg_expr(Aggref *aggref, deparse_context *context)
bool use_variadic;
Oid fnoid;
/* Special handling of MEDIAN */
if (get_median_expr(aggref, context))
return;
/*
* Depending on the stage of aggregation, this Aggref
* may represent functions that are different from the
......
......@@ -310,6 +310,12 @@ DATA(insert ( 6121 o 1 ordered_set_transition - - - percentile_cont_timestamp_m
DATA(insert ( 6123 o 1 ordered_set_transition - - - percentile_cont_timestamptz_final f 0 2281 _null_ ));
DATA(insert ( 6125 o 1 ordered_set_transition - - - percentile_cont_timestamptz_multi_final f 0 2281 _null_ ));
/* median */
DATA(insert ( 6127 o 1 ordered_set_transition - - - percentile_cont_float8_final f 0 2281 _null_ ));
DATA(insert ( 6128 o 1 ordered_set_transition - - - percentile_cont_interval_final f 0 2281 _null_ ));
DATA(insert ( 6129 o 1 ordered_set_transition - - - percentile_cont_timestamp_final f 0 2281 _null_ ));
DATA(insert ( 6130 o 1 ordered_set_transition - - - percentile_cont_timestamptz_final f 0 2281 _null_ ));
/*
* prototypes for functions in pg_aggregate.c
*/
......
......@@ -4877,6 +4877,16 @@ DESCR("multiple continuous percentiles");
DATA(insert OID = 6126 ( percentile_cont_timestamptz_multi_final PGNSP PGUID 12 1 0 0 f f f f f i 2 0 1185 "2281 1022" _null_ _null_ _null_ _null_ percentile_cont_timestamptz_multi_final _null_ _null_ _null_ n a ));
DESCR("aggregate final function");
DATA(insert OID = 6127 ( median PGNSP PGUID 12 1 0 0 t f f f f i 2 0 701 "701 701" _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ n a ));
DESCR("median");
DATA(insert OID = 6128 ( median PGNSP PGUID 12 1 0 0 t f f f f i 2 0 1186 "701 1186" _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ n a ));
DESCR("median");
DATA(insert OID = 6129 ( median PGNSP PGUID 12 1 0 0 t f f f f i 2 0 1114 "701 1114" _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ n a ));
DESCR("median");
DATA(insert OID = 6130 ( median PGNSP PGUID 12 1 0 0 t f f f f i 2 0 1184 "701 1184" _null_ _null_ _null_ _null_ aggregate_dummy _null_ _null_ _null_ n a ));
DESCR("median");
#define IS_MEDIAN_OID(x) ((x) == 6127 || (x) == 6128 || (x) == 6129 || (x) == 6130)
/* hypothetical-set aggregates (and their support functions) */
DATA(insert OID = 3986 ( rank PGNSP PGUID 12 1 0 2276 t f f f f i 1 0 20 "2276" "{2276}" "{v}" _null_ _null_ aggregate_dummy _null_ _null_ _null_ n a ));
DESCR("rank of hypothetical row");
......
......@@ -257,6 +257,7 @@ PG_KEYWORD("mapping", MAPPING, UNRESERVED_KEYWORD)
PG_KEYWORD("master", MASTER, UNRESERVED_KEYWORD) /* GPDB */
PG_KEYWORD("match", MATCH, UNRESERVED_KEYWORD)
PG_KEYWORD("maxvalue", MAXVALUE, UNRESERVED_KEYWORD)
PG_KEYWORD("median", MEDIAN, COL_NAME_KEYWORD)
PG_KEYWORD("memory_limit", MEMORY_LIMIT, UNRESERVED_KEYWORD)
PG_KEYWORD("memory_shared_quota", MEMORY_SHARED_QUOTA, UNRESERVED_KEYWORD)
PG_KEYWORD("memory_spill_ratio", MEMORY_SPILL_RATIO, UNRESERVED_KEYWORD)
......
......@@ -980,14 +980,14 @@ select * from percv;
reset gp_idf_deduplicate;
select pg_get_viewdef('percv');
pg_get_viewdef
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SELECT percentile_cont(float8(0.4)) WITHIN GROUP (ORDER BY float8((perct.a / 10))) AS "percentile_cont", median(float8(perct.a)) AS "median", percentile_disc(float8(0.51)) WITHIN GROUP (ORDER BY float8(perct.a) DESC) AS "percentile_disc" FROM perct GROUP BY perct.b ORDER BY perct.b;
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SELECT percentile_cont((0.4)::double precision) WITHIN GROUP (ORDER BY ((perct.a / 10))::double precision) AS percentile_cont, MEDIAN(perct.a) AS "median", percentile_disc((0.51)::double precision) WITHIN GROUP (ORDER BY perct.a DESC) AS percentile_disc FROM perct GROUP BY perct.b ORDER BY perct.b;
(1 row)
select pg_get_viewdef('percv2');
pg_get_viewdef
---------------------------------------------------------------------------------------------
SELECT median(float8(perct.a)) AS m1, median((perct.a)::double precision) AS m2 FROM perct;
-------------------------------------------------------------------------------------
SELECT MEDIAN(perct.a) AS m1, MEDIAN((perct.a)::double precision) AS m2 FROM perct;
(1 row)
-- errors
......@@ -1020,7 +1020,9 @@ LINE 1: select sum(percentile_cont(0.22) within group (order by a)) ...
select percentile_cont(0.3333) within group (order by a) over (partition by a%2) from perct;
ERROR: window OVER clause can only be used with an aggregate
select median(a) over (partition by b) from perct group by b;
ERROR: window OVER clause can only be used with an aggregate
ERROR: syntax error at or near "over"
LINE 1: select median(a) over (partition by b) from perct group by b...
^
-- function scan
select * from median(10);
ERROR: cannot use aggregate function in function expression in FROM
......@@ -1067,11 +1069,14 @@ select percentile_cont(-0.1) within group (order by a) from perct;
ERROR: input is out of range
HINT: Argument to percentile function must be between 0.0 and 1.0.
select percentile_cont(1.00000001) within group (order by a) from perct;
ERROR: input is out of range
HINT: Argument to percentile function must be between 0.0 and 1.0.
-- CSQ is not supported currently. Shame.
ERROR: percentile value 1 is not between 0 and 1
-- correlated subquery
select sum((select median(a) from perct where b = t.b)) from perct t;
ERROR: correlated subquery cannot contain percentile functions
sum
------
5050
(1 row)
-- used in LIMIT
select * from perct limit median(a);
ERROR: argument of LIMIT must not contain variables
......@@ -1088,10 +1093,25 @@ select generate_series(1, 2), median(a) from perct;
ERROR: set-valued function called in context that cannot accept a set
-- GROUPING SETS
select median(a) from perct group by grouping sets((), (b));
ERROR: WITHIN GROUP aggregate cannot be used in GROUPING SETS query
median
--------
5
100
14.5
24.5
34.5
44.5
50.5
54.5
64.5
74.5
84.5
94.5
(12 rows)
-- wrong type in ORDER BY
select median('text') from perct;
ERROR: function "median(unknown)" is not unique
ERROR: function pg_catalog.median(double precision, unknown) is not unique
LINE 1: select median('text') from perct;
^
HINT: Could not choose a best candidate function. You might need to add explicit type casts.
......@@ -1105,11 +1125,13 @@ ERROR: function "percentile_cont(double precision) ORDER BY (point)" does not e
LINE 1: select percentile_cont(0.5) within group (order by point(0,0...
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
-- outer reference is not allowed for now
-- outer reference
select (select a from perct where median(t.a) = 5) from perct t;
ERROR: percentile functions cannot reference columns from outer queries
LINE 1: select (select a from perct where median(t.a) = 5) from perc...
^
?column?
----------
(1 row)
-- MPP-22219
select count(*) from
(SELECT b.dkey_a, MEDIAN(B.VALUE)
......
......@@ -869,8 +869,8 @@ create view idf_v1 as select median (( select median((select median(a) from perc
-- end_ignore
select pg_get_viewdef('idf_v1');
pg_get_viewdef
-----------------------------------------------------------------------------------------------------------------------------
SELECT median((SELECT median((SELECT median(float8(perct.a)) AS "median" FROM perct)) AS "median" FROM perct)) AS "median";
---------------------------------------------------------------------------------------------------------------------
SELECT MEDIAN((SELECT MEDIAN((SELECT MEDIAN(perct.a) AS "median" FROM perct)) AS "median" FROM perct)) AS "median";
(1 row)
......
......@@ -207,7 +207,7 @@ select percentile_cont(floor(random()*0.1)+0.5) within group (order by a) from p
-- out of range
select percentile_cont(-0.1) within group (order by a) from perct;
select percentile_cont(1.00000001) within group (order by a) from perct;
-- CSQ is not supported currently. Shame.
-- correlated subquery
select sum((select median(a) from perct where b = t.b)) from perct t;
-- used in LIMIT
select * from perct limit median(a);
......@@ -221,7 +221,7 @@ select median(a) from perct group by grouping sets((), (b));
select median('text') from perct;
select percentile_cont(now()) within group (order by a) from percts;
select percentile_cont(0.5) within group (order by point(0,0)) from perct;
-- outer reference is not allowed for now
-- outer reference
select (select a from perct where median(t.a) = 5) from perct t;
-- MPP-22219
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册