diff options
-rw-r--r-- | src/test/regress/expected/aggregates.out | 255 | ||||
-rw-r--r-- | src/test/regress/expected/aggregates_1.out | 1018 | ||||
-rw-r--r-- | src/test/regress/sql/aggregates.sql | 30 |
3 files changed, 1138 insertions, 165 deletions
diff --git a/src/test/regress/expected/aggregates.out b/src/test/regress/expected/aggregates.out index e2d3bc9c8a..dd20688519 100644 --- a/src/test/regress/expected/aggregates.out +++ b/src/test/regress/expected/aggregates.out @@ -445,19 +445,19 @@ FROM bool_test; -- -- Test cases that should be optimized into indexscans instead of -- the generic aggregate implementation. +-- In Postgres-XC, plans printed by explain are the ones created on the +-- coordinator. Coordinator does not generate index scan plans. -- analyze tenk1; -- ensure we get consistent plans here -- Basic cases -explain (costs off) +explain (costs off, nodes off) select min(unique1) from tenk1; - QUERY PLAN -------------------------------------------------------- - Result - InitPlan 1 (returns $0) - -> Limit - -> Index Scan using tenk1_unique1 on tenk1 - Index Cond: (unique1 IS NOT NULL) -(5 rows) + QUERY PLAN +-------------------------------------------------------- + Aggregate + -> Materialize + -> Data Node Scan on "__REMOTE_GROUP_QUERY__" +(3 rows) select min(unique1) from tenk1; min @@ -465,16 +465,14 @@ select min(unique1) from tenk1; 0 (1 row) -explain (costs off) +explain (costs off, nodes off) select max(unique1) from tenk1; - QUERY PLAN ----------------------------------------------------------------- - Result - InitPlan 1 (returns $0) - -> Limit - -> Index Scan Backward using tenk1_unique1 on tenk1 - Index Cond: (unique1 IS NOT NULL) -(5 rows) + QUERY PLAN +-------------------------------------------------------- + Aggregate + -> Materialize + -> Data Node Scan on "__REMOTE_GROUP_QUERY__" +(3 rows) select max(unique1) from tenk1; max @@ -482,16 +480,14 @@ select max(unique1) from tenk1; 9999 (1 row) -explain (costs off) +explain (costs off, nodes off) select max(unique1) from tenk1 where unique1 < 42; - QUERY PLAN ------------------------------------------------------------------------- - Result - InitPlan 1 (returns $0) - -> Limit - -> Index Scan Backward using tenk1_unique1 on tenk1 - Index Cond: ((unique1 IS NOT NULL) AND (unique1 < 42)) -(5 rows) + QUERY PLAN +-------------------------------------------------------- + Aggregate + -> Materialize + -> Data Node Scan on "__REMOTE_GROUP_QUERY__" +(3 rows) select max(unique1) from tenk1 where unique1 < 42; max @@ -499,16 +495,14 @@ select max(unique1) from tenk1 where unique1 < 42; 41 (1 row) -explain (costs off) +explain (costs off, nodes off) select max(unique1) from tenk1 where unique1 > 42; - QUERY PLAN ------------------------------------------------------------------------- - Result - InitPlan 1 (returns $0) - -> Limit - -> Index Scan Backward using tenk1_unique1 on tenk1 - Index Cond: ((unique1 IS NOT NULL) AND (unique1 > 42)) -(5 rows) + QUERY PLAN +-------------------------------------------------------- + Aggregate + -> Materialize + -> Data Node Scan on "__REMOTE_GROUP_QUERY__" +(3 rows) select max(unique1) from tenk1 where unique1 > 42; max @@ -516,16 +510,14 @@ select max(unique1) from tenk1 where unique1 > 42; 9999 (1 row) -explain (costs off) +explain (costs off, nodes off) select max(unique1) from tenk1 where unique1 > 42000; - QUERY PLAN ---------------------------------------------------------------------------- - Result - InitPlan 1 (returns $0) - -> Limit - -> Index Scan Backward using tenk1_unique1 on tenk1 - Index Cond: ((unique1 IS NOT NULL) AND (unique1 > 42000)) -(5 rows) + QUERY PLAN +-------------------------------------------------------- + Aggregate + -> Materialize + -> Data Node Scan on "__REMOTE_GROUP_QUERY__" +(3 rows) select max(unique1) from tenk1 where unique1 > 42000; max @@ -534,16 +526,14 @@ select max(unique1) from tenk1 where unique1 > 42000; (1 row) -- multi-column index (uses tenk1_thous_tenthous) -explain (costs off) +explain (costs off, nodes off) select max(tenthous) from tenk1 where thousand = 33; - QUERY PLAN --------------------------------------------------------------------------- - Result - InitPlan 1 (returns $0) - -> Limit - -> Index Scan Backward using tenk1_thous_tenthous on tenk1 - Index Cond: ((thousand = 33) AND (tenthous IS NOT NULL)) -(5 rows) + QUERY PLAN +-------------------------------------------------------- + Aggregate + -> Materialize + -> Data Node Scan on "__REMOTE_GROUP_QUERY__" +(3 rows) select max(tenthous) from tenk1 where thousand = 33; max @@ -551,16 +541,14 @@ select max(tenthous) from tenk1 where thousand = 33; 9033 (1 row) -explain (costs off) +explain (costs off, nodes off) select min(tenthous) from tenk1 where thousand = 33; - QUERY PLAN --------------------------------------------------------------------------- - Result - InitPlan 1 (returns $0) - -> Limit - -> Index Scan using tenk1_thous_tenthous on tenk1 - Index Cond: ((thousand = 33) AND (tenthous IS NOT NULL)) -(5 rows) + QUERY PLAN +-------------------------------------------------------- + Aggregate + -> Materialize + -> Data Node Scan on "__REMOTE_GROUP_QUERY__" +(3 rows) select min(tenthous) from tenk1 where thousand = 33; min @@ -569,19 +557,18 @@ select min(tenthous) from tenk1 where thousand = 33; (1 row) -- check parameter propagation into an indexscan subquery -explain (costs off) +explain (costs off, nodes off) select f1, (select min(unique1) from tenk1 where unique1 > f1) AS gt from int4_tbl; - QUERY PLAN ------------------------------------------------------------------------------------------ - Seq Scan on int4_tbl - SubPlan 2 - -> Result - InitPlan 1 (returns $1) - -> Limit - -> Index Scan using tenk1_unique1 on tenk1 - Index Cond: ((unique1 IS NOT NULL) AND (unique1 > int4_tbl.f1)) -(7 rows) + QUERY PLAN +------------------------------------------------------------ + Result + -> Data Node Scan on int4_tbl + SubPlan 1 + -> Aggregate + -> Data Node Scan on tenk1 + Coordinator quals: (unique1 > int4_tbl.f1) +(6 rows) select f1, (select min(unique1) from tenk1 where unique1 > f1) AS gt from int4_tbl @@ -596,17 +583,14 @@ order by f1; (5 rows) -- check some cases that were handled incorrectly in 8.3.0 -explain (costs off) +explain (costs off, nodes off) select distinct max(unique2) from tenk1; - QUERY PLAN ----------------------------------------------------------------- + QUERY PLAN +------------------------------------- HashAggregate - InitPlan 1 (returns $0) - -> Limit - -> Index Scan Backward using tenk1_unique2 on tenk1 - Index Cond: (unique2 IS NOT NULL) - -> Result -(6 rows) + -> Aggregate + -> Data Node Scan on tenk1 +(3 rows) select distinct max(unique2) from tenk1; max @@ -614,18 +598,15 @@ select distinct max(unique2) from tenk1; 9999 (1 row) -explain (costs off) +explain (costs off, nodes off) select max(unique2) from tenk1 order by 1; - QUERY PLAN ----------------------------------------------------------------- + QUERY PLAN +------------------------------------- Sort - Sort Key: ($0) - InitPlan 1 (returns $0) - -> Limit - -> Index Scan Backward using tenk1_unique2 on tenk1 - Index Cond: (unique2 IS NOT NULL) - -> Result -(7 rows) + Sort Key: (max(unique2)) + -> Aggregate + -> Data Node Scan on tenk1 +(4 rows) select max(unique2) from tenk1 order by 1; max @@ -633,18 +614,15 @@ select max(unique2) from tenk1 order by 1; 9999 (1 row) -explain (costs off) +explain (costs off, nodes off) select max(unique2) from tenk1 order by max(unique2); - QUERY PLAN ----------------------------------------------------------------- + QUERY PLAN +------------------------------------- Sort - Sort Key: ($0) - InitPlan 1 (returns $0) - -> Limit - -> Index Scan Backward using tenk1_unique2 on tenk1 - Index Cond: (unique2 IS NOT NULL) - -> Result -(7 rows) + Sort Key: (max(unique2)) + -> Aggregate + -> Data Node Scan on tenk1 +(4 rows) select max(unique2) from tenk1 order by max(unique2); max @@ -652,18 +630,15 @@ select max(unique2) from tenk1 order by max(unique2); 9999 (1 row) -explain (costs off) +explain (costs off, nodes off) select max(unique2) from tenk1 order by max(unique2)+1; - QUERY PLAN ----------------------------------------------------------------- + QUERY PLAN +------------------------------------- Sort - Sort Key: (($0 + 1)) - InitPlan 1 (returns $0) - -> Limit - -> Index Scan Backward using tenk1_unique2 on tenk1 - Index Cond: (unique2 IS NOT NULL) - -> Result -(7 rows) + Sort Key: ((max(unique2) + 1)) + -> Aggregate + -> Data Node Scan on tenk1 +(4 rows) select max(unique2) from tenk1 order by max(unique2)+1; max @@ -671,18 +646,15 @@ select max(unique2) from tenk1 order by max(unique2)+1; 9999 (1 row) -explain (costs off) +explain (costs off, nodes off) select max(unique2), generate_series(1,3) as g from tenk1 order by g desc; - QUERY PLAN ----------------------------------------------------------------- + QUERY PLAN +------------------------------------- Sort Sort Key: (generate_series(1, 3)) - InitPlan 1 (returns $0) - -> Limit - -> Index Scan Backward using tenk1_unique2 on tenk1 - Index Cond: (unique2 IS NOT NULL) - -> Result -(7 rows) + -> Aggregate + -> Data Node Scan on tenk1 +(4 rows) select max(unique2), generate_series(1,3) as g from tenk1 order by g desc; max | g @@ -705,36 +677,17 @@ insert into minmaxtest values(11), (12); insert into minmaxtest1 values(13), (14); insert into minmaxtest2 values(15), (16); insert into minmaxtest3 values(17), (18); -explain (costs off) +explain (costs off, nodes off) select min(f1), max(f1) from minmaxtest; - QUERY PLAN --------------------------------------------------------------------------------------- - Result - InitPlan 1 (returns $0) - -> Limit - -> Merge Append - Sort Key: public.minmaxtest.f1 - -> Index Scan using minmaxtesti on minmaxtest - Index Cond: (f1 IS NOT NULL) - -> Index Scan using minmaxtest1i on minmaxtest1 minmaxtest - Index Cond: (f1 IS NOT NULL) - -> Index Scan Backward using minmaxtest2i on minmaxtest2 minmaxtest - Index Cond: (f1 IS NOT NULL) - -> Index Scan using minmaxtest3i on minmaxtest3 minmaxtest - Index Cond: (f1 IS NOT NULL) - InitPlan 2 (returns $1) - -> Limit - -> Merge Append - Sort Key: public.minmaxtest.f1 - -> Index Scan Backward using minmaxtesti on minmaxtest - Index Cond: (f1 IS NOT NULL) - -> Index Scan Backward using minmaxtest1i on minmaxtest1 minmaxtest - Index Cond: (f1 IS NOT NULL) - -> Index Scan using minmaxtest2i on minmaxtest2 minmaxtest - Index Cond: (f1 IS NOT NULL) - -> Index Scan Backward using minmaxtest3i on minmaxtest3 minmaxtest - Index Cond: (f1 IS NOT NULL) -(25 rows) + QUERY PLAN +------------------------------------------ + Aggregate + -> Append + -> Data Node Scan on minmaxtest + -> Data Node Scan on minmaxtest + -> Data Node Scan on minmaxtest + -> Data Node Scan on minmaxtest +(6 rows) select min(f1), max(f1) from minmaxtest; min | max diff --git a/src/test/regress/expected/aggregates_1.out b/src/test/regress/expected/aggregates_1.out new file mode 100644 index 0000000000..12be7c64c2 --- /dev/null +++ b/src/test/regress/expected/aggregates_1.out @@ -0,0 +1,1018 @@ +-- +-- AGGREGATES +-- +SELECT avg(four) AS avg_1 FROM onek; + avg_1 +-------------------- + 1.5000000000000000 +(1 row) + +SELECT avg(a) AS avg_32 FROM aggtest WHERE a < 100; + avg_32 +--------------------- + 32.6666666666666667 +(1 row) + +-- In 7.1, avg(float4) is computed using float8 arithmetic. +-- Round the result to 3 digits to avoid platform-specific results. +SELECT avg(b)::numeric(10,3) AS avg_107_943 FROM aggtest; + avg_107_943 +------------- + 107.943 +(1 row) + +SELECT avg(gpa) AS avg_3_4 FROM ONLY student; + avg_3_4 +--------- + 3.4 +(1 row) + +SELECT sum(four) AS sum_1500 FROM onek; + sum_1500 +---------- + 1500 +(1 row) + +SELECT sum(a) AS sum_198 FROM aggtest; + sum_198 +--------- + 198 +(1 row) + +SELECT sum(b) AS avg_431_773 FROM aggtest; + avg_431_773 +------------- + 431.773 +(1 row) + +SELECT sum(gpa) AS avg_6_8 FROM ONLY student; + avg_6_8 +--------- + 6.8 +(1 row) + +SELECT max(four) AS max_3 FROM onek; + max_3 +------- + 3 +(1 row) + +SELECT max(a) AS max_100 FROM aggtest; + max_100 +--------- + 100 +(1 row) + +SELECT max(aggtest.b) AS max_324_78 FROM aggtest; + max_324_78 +------------ + 324.78 +(1 row) + +SELECT max(student.gpa) AS max_3_7 FROM student; + max_3_7 +--------- + 3.7 +(1 row) + +SELECT stddev_pop(b) FROM aggtest; + stddev_pop +------------------ + 131.107032318951 +(1 row) + +SELECT stddev_samp(b) FROM aggtest; + stddev_samp +------------------ + 151.389360803998 +(1 row) + +SELECT var_pop(b) FROM aggtest; + var_pop +------------------ + 17189.0539234824 +(1 row) + +SELECT var_samp(b) FROM aggtest; + var_samp +------------------ + 22918.7385646432 +(1 row) + +SELECT stddev_pop(b::numeric) FROM aggtest; + stddev_pop +------------------ + 131.107032862199 +(1 row) + +SELECT stddev_samp(b::numeric) FROM aggtest; + stddev_samp +------------------ + 151.389361431288 +(1 row) + +SELECT var_pop(b::numeric) FROM aggtest; + var_pop +-------------------- + 17189.054065929769 +(1 row) + +SELECT var_samp(b::numeric) FROM aggtest; + var_samp +-------------------- + 22918.738754573025 +(1 row) + +-- population variance is defined for a single tuple, sample variance +-- is not +SELECT var_pop(1.0), var_samp(2.0); + var_pop | var_samp +---------+---------- + 0 | +(1 row) + +SELECT stddev_pop(3.0::numeric), stddev_samp(4.0::numeric); + stddev_pop | stddev_samp +------------+------------- + 0 | +(1 row) + +-- SQL2003 binary aggregates +SELECT regr_count(b, a) FROM aggtest; + regr_count +------------ + 4 +(1 row) + +SELECT regr_sxx(b, a) FROM aggtest; + regr_sxx +---------- + 5099 +(1 row) + +SELECT regr_syy(b, a) FROM aggtest; + regr_syy +------------------ + 68756.2156939297 +(1 row) + +SELECT regr_sxy(b, a) FROM aggtest; + regr_sxy +------------------ + 2614.51582155001 +(1 row) + +SELECT regr_avgx(b, a), regr_avgy(b, a) FROM aggtest; + regr_avgx | regr_avgy +-----------+------------------ + 49.5 | 107.943152273074 +(1 row) + +SELECT regr_r2(b, a) FROM aggtest; + regr_r2 +-------------------- + 0.0194977982031797 +(1 row) + +SELECT regr_slope(b, a), regr_intercept(b, a) FROM aggtest; + regr_slope | regr_intercept +-------------------+------------------ + 0.512750700441265 | 82.5619926012313 +(1 row) + +SELECT covar_pop(b, a), covar_samp(b, a) FROM aggtest; + covar_pop | covar_samp +------------------+------------------ + 653.628955387502 | 871.505273850003 +(1 row) + +SELECT corr(b, a) FROM aggtest; + corr +------------------- + 0.139634516517871 +(1 row) + +SELECT count(four) AS cnt_1000 FROM onek; + cnt_1000 +---------- + 1000 +(1 row) + +SELECT count(DISTINCT four) AS cnt_4 FROM onek; + cnt_4 +------- + 4 +(1 row) + +select ten, count(*), sum(four) from onek +group by ten order by ten; + ten | count | sum +-----+-------+----- + 0 | 100 | 100 + 1 | 100 | 200 + 2 | 100 | 100 + 3 | 100 | 200 + 4 | 100 | 100 + 5 | 100 | 200 + 6 | 100 | 100 + 7 | 100 | 200 + 8 | 100 | 100 + 9 | 100 | 200 +(10 rows) + +select ten, count(four), sum(DISTINCT four) from onek +group by ten order by ten; + ten | count | sum +-----+-------+----- + 0 | 100 | 2 + 1 | 100 | 4 + 2 | 100 | 2 + 3 | 100 | 4 + 4 | 100 | 2 + 5 | 100 | 4 + 6 | 100 | 2 + 7 | 100 | 4 + 8 | 100 | 2 + 9 | 100 | 4 +(10 rows) + +-- user-defined aggregates +SELECT newavg(four) AS avg_1 FROM onek; + avg_1 +-------------------- + 1.5000000000000000 +(1 row) + +SELECT newsum(four) AS sum_1500 FROM onek; + sum_1500 +---------- + 1500 +(1 row) + +SELECT newcnt(four) AS cnt_1000 FROM onek; + cnt_1000 +---------- + 1000 +(1 row) + +SELECT newcnt(*) AS cnt_1000 FROM onek; + cnt_1000 +---------- + 1000 +(1 row) + +SELECT oldcnt(*) AS cnt_1000 FROM onek; + cnt_1000 +---------- + 1000 +(1 row) + +SELECT sum2(q1,q2) FROM int8_tbl; + sum2 +------------------- + 18271560493827981 +(1 row) + +-- test for outer-level aggregates +-- this should work +select ten, sum(distinct four) from onek a +group by ten +having exists (select 1 from onek b where sum(distinct a.four) = b.four) +order by ten; + ten | sum +-----+----- + 0 | 2 + 2 | 2 + 4 | 2 + 6 | 2 + 8 | 2 +(5 rows) + +-- this should fail because subquery has an agg of its own in WHERE +select ten, sum(distinct four) from onek a +group by ten +having exists (select 1 from onek b + where sum(distinct a.four + b.four) = b.four); +ERROR: aggregates not allowed in WHERE clause +LINE 4: where sum(distinct a.four + b.four) = b.four)... + ^ +-- Test handling of sublinks within outer-level aggregates. +-- Per bug report from Daniel Grace. +select + (select max((select i.unique2 from tenk1 i where i.unique1 = o.unique1))) +from tenk1 o; + ?column? +---------- + 9999 +(1 row) + +-- +-- test for bitwise integer aggregates +-- +CREATE TEMPORARY TABLE bitwise_test( + i2 INT2, + i4 INT4, + i8 INT8, + i INTEGER, + x INT2, + y BIT(4) +); +-- empty case +SELECT + BIT_AND(i2) AS "?", + BIT_OR(i4) AS "?" +FROM bitwise_test; + ? | ? +---+--- + | +(1 row) + +COPY bitwise_test FROM STDIN NULL 'null'; +SELECT + BIT_AND(i2) AS "1", + BIT_AND(i4) AS "1", + BIT_AND(i8) AS "1", + BIT_AND(i) AS "?", + BIT_AND(x) AS "0", + BIT_AND(y) AS "0100", + BIT_OR(i2) AS "7", + BIT_OR(i4) AS "7", + BIT_OR(i8) AS "7", + BIT_OR(i) AS "?", + BIT_OR(x) AS "7", + BIT_OR(y) AS "1101" +FROM bitwise_test; + 1 | 1 | 1 | ? | 0 | 0100 | 7 | 7 | 7 | ? | 7 | 1101 +---+---+---+---+---+------+---+---+---+---+---+------ + 1 | 1 | 1 | 1 | 0 | 0100 | 7 | 7 | 7 | 3 | 7 | 1101 +(1 row) + +-- +-- test boolean aggregates +-- +-- first test all possible transition and final states +SELECT + -- boolean and transitions + -- null because strict + booland_statefunc(NULL, NULL) IS NULL AS "t", + booland_statefunc(TRUE, NULL) IS NULL AS "t", + booland_statefunc(FALSE, NULL) IS NULL AS "t", + booland_statefunc(NULL, TRUE) IS NULL AS "t", + booland_statefunc(NULL, FALSE) IS NULL AS "t", + -- and actual computations + booland_statefunc(TRUE, TRUE) AS "t", + NOT booland_statefunc(TRUE, FALSE) AS "t", + NOT booland_statefunc(FALSE, TRUE) AS "t", + NOT booland_statefunc(FALSE, FALSE) AS "t"; + t | t | t | t | t | t | t | t | t +---+---+---+---+---+---+---+---+--- + t | t | t | t | t | t | t | t | t +(1 row) + +SELECT + -- boolean or transitions + -- null because strict + boolor_statefunc(NULL, NULL) IS NULL AS "t", + boolor_statefunc(TRUE, NULL) IS NULL AS "t", + boolor_statefunc(FALSE, NULL) IS NULL AS "t", + boolor_statefunc(NULL, TRUE) IS NULL AS "t", + boolor_statefunc(NULL, FALSE) IS NULL AS "t", + -- actual computations + boolor_statefunc(TRUE, TRUE) AS "t", + boolor_statefunc(TRUE, FALSE) AS "t", + boolor_statefunc(FALSE, TRUE) AS "t", + NOT boolor_statefunc(FALSE, FALSE) AS "t"; + t | t | t | t | t | t | t | t | t +---+---+---+---+---+---+---+---+--- + t | t | t | t | t | t | t | t | t +(1 row) + +CREATE TEMPORARY TABLE bool_test( + b1 BOOL, + b2 BOOL, + b3 BOOL, + b4 BOOL); +-- empty case +SELECT + BOOL_AND(b1) AS "n", + BOOL_OR(b3) AS "n" +FROM bool_test; + n | n +---+--- + | +(1 row) + +COPY bool_test FROM STDIN NULL 'null'; +SELECT + BOOL_AND(b1) AS "f", + BOOL_AND(b2) AS "t", + BOOL_AND(b3) AS "f", + BOOL_AND(b4) AS "n", + BOOL_AND(NOT b2) AS "f", + BOOL_AND(NOT b3) AS "t" +FROM bool_test; + f | t | f | n | f | t +---+---+---+---+---+--- + f | t | f | | f | t +(1 row) + +SELECT + EVERY(b1) AS "f", + EVERY(b2) AS "t", + EVERY(b3) AS "f", + EVERY(b4) AS "n", + EVERY(NOT b2) AS "f", + EVERY(NOT b3) AS "t" +FROM bool_test; + f | t | f | n | f | t +---+---+---+---+---+--- + f | t | f | | f | t +(1 row) + +SELECT + BOOL_OR(b1) AS "t", + BOOL_OR(b2) AS "t", + BOOL_OR(b3) AS "f", + BOOL_OR(b4) AS "n", + BOOL_OR(NOT b2) AS "f", + BOOL_OR(NOT b3) AS "t" +FROM bool_test; + t | t | f | n | f | t +---+---+---+---+---+--- + t | t | f | | f | t +(1 row) + +-- +-- Test cases that should be optimized into indexscans instead of +-- the generic aggregate implementation. +-- In Postgres-XC, plans printed by explain are the ones created on the +-- coordinator. Coordinator does not generate index scan plans. +-- +analyze tenk1; -- ensure we get consistent plans here +-- Basic cases +explain (costs off, nodes off) + select min(unique1) from tenk1; + QUERY PLAN +-------------------------------------------------------- + Aggregate + -> Materialize + -> Data Node Scan on "__REMOTE_GROUP_QUERY__" +(3 rows) + +select min(unique1) from tenk1; + min +----- + 0 +(1 row) + +explain (costs off, nodes off) + select max(unique1) from tenk1; + QUERY PLAN +-------------------------------------------------------- + Aggregate + -> Materialize + -> Data Node Scan on "__REMOTE_GROUP_QUERY__" +(3 rows) + +select max(unique1) from tenk1; + max +------ + 9999 +(1 row) + +explain (costs off, nodes off) + select max(unique1) from tenk1 where unique1 < 42; + QUERY PLAN +-------------------------------------------------------- + Aggregate + -> Materialize + -> Data Node Scan on "__REMOTE_GROUP_QUERY__" +(3 rows) + +select max(unique1) from tenk1 where unique1 < 42; + max +----- + 41 +(1 row) + +explain (costs off, nodes off) + select max(unique1) from tenk1 where unique1 > 42; + QUERY PLAN +-------------------------------------------------------- + Aggregate + -> Materialize + -> Data Node Scan on "__REMOTE_GROUP_QUERY__" +(3 rows) + +select max(unique1) from tenk1 where unique1 > 42; + max +------ + 9999 +(1 row) + +explain (costs off, nodes off) + select max(unique1) from tenk1 where unique1 > 42000; + QUERY PLAN +-------------------------------------------------------- + Aggregate + -> Materialize + -> Data Node Scan on "__REMOTE_GROUP_QUERY__" +(3 rows) + +select max(unique1) from tenk1 where unique1 > 42000; + max +----- + +(1 row) + +-- multi-column index (uses tenk1_thous_tenthous) +explain (costs off, nodes off) + select max(tenthous) from tenk1 where thousand = 33; + QUERY PLAN +-------------------------------------------------------- + Aggregate + -> Materialize + -> Data Node Scan on "__REMOTE_GROUP_QUERY__" +(3 rows) + +select max(tenthous) from tenk1 where thousand = 33; + max +------ + 9033 +(1 row) + +explain (costs off, nodes off) + select min(tenthous) from tenk1 where thousand = 33; + QUERY PLAN +-------------------------------------------------------- + Aggregate + -> Materialize + -> Data Node Scan on "__REMOTE_GROUP_QUERY__" +(3 rows) + +select min(tenthous) from tenk1 where thousand = 33; + min +----- + 33 +(1 row) + +-- check parameter propagation into an indexscan subquery +explain (costs off, nodes off) + select f1, (select min(unique1) from tenk1 where unique1 > f1) AS gt + from int4_tbl; + QUERY PLAN +------------------------------------------------------------ + Result + -> Data Node Scan on int4_tbl + SubPlan 1 + -> Aggregate + -> Data Node Scan on tenk1 + Coordinator quals: (unique1 > int4_tbl.f1) +(6 rows) + +select f1, (select min(unique1) from tenk1 where unique1 > f1) AS gt +from int4_tbl +order by f1; + f1 | gt +-------------+---- + -2147483647 | 0 + -123456 | 0 + 0 | 1 + 123456 | + 2147483647 | +(5 rows) + +-- check some cases that were handled incorrectly in 8.3.0 +explain (costs off, nodes off) + select distinct max(unique2) from tenk1; + QUERY PLAN +------------------------------------- + HashAggregate + -> Aggregate + -> Data Node Scan on tenk1 +(3 rows) + +select distinct max(unique2) from tenk1; + max +------ + 9999 +(1 row) + +explain (costs off, nodes off) + select max(unique2) from tenk1 order by 1; + QUERY PLAN +------------------------------------- + Sort + Sort Key: (max(unique2)) + -> Aggregate + -> Data Node Scan on tenk1 +(4 rows) + +select max(unique2) from tenk1 order by 1; + max +------ + 9999 +(1 row) + +explain (costs off, nodes off) + select max(unique2) from tenk1 order by max(unique2); + QUERY PLAN +------------------------------------- + Sort + Sort Key: (max(unique2)) + -> Aggregate + -> Data Node Scan on tenk1 +(4 rows) + +select max(unique2) from tenk1 order by max(unique2); + max +------ + 9999 +(1 row) + +explain (costs off, nodes off) + select max(unique2) from tenk1 order by max(unique2)+1; + QUERY PLAN +------------------------------------- + Sort + Sort Key: ((max(unique2) + 1)) + -> Aggregate + -> Data Node Scan on tenk1 +(4 rows) + +select max(unique2) from tenk1 order by max(unique2)+1; + max +------ + 9999 +(1 row) + +explain (costs off, nodes off) + select max(unique2), generate_series(1,3) as g from tenk1 order by g desc; + QUERY PLAN +------------------------------------- + Sort + Sort Key: (generate_series(1, 3)) + -> Aggregate + -> Data Node Scan on tenk1 +(4 rows) + +select max(unique2), generate_series(1,3) as g from tenk1 order by g desc; + max | g +------+--- + 9999 | 3 + 9999 | 2 + 9999 | 1 +(3 rows) + +-- try it on an inheritance tree +create table minmaxtest(f1 int); +create table minmaxtest1() inherits (minmaxtest); +create table minmaxtest2() inherits (minmaxtest); +create table minmaxtest3() inherits (minmaxtest); +create index minmaxtesti on minmaxtest(f1); +create index minmaxtest1i on minmaxtest1(f1); +create index minmaxtest2i on minmaxtest2(f1 desc); +create index minmaxtest3i on minmaxtest3(f1) where f1 is not null; +insert into minmaxtest values(11), (12); +insert into minmaxtest1 values(13), (14); +insert into minmaxtest2 values(15), (16); +insert into minmaxtest3 values(17), (18); +explain (costs off, nodes off) + select min(f1), max(f1) from minmaxtest; + QUERY PLAN +------------------------------------------ + Aggregate + -> Append + -> Data Node Scan on minmaxtest + -> Data Node Scan on minmaxtest + -> Data Node Scan on minmaxtest + -> Data Node Scan on minmaxtest +(6 rows) + +select min(f1), max(f1) from minmaxtest; + min | max +-----+----- + 11 | 18 +(1 row) + +drop table minmaxtest cascade; +NOTICE: drop cascades to 3 other objects +DETAIL: drop cascades to table minmaxtest1 +drop cascades to table minmaxtest2 +drop cascades to table minmaxtest3 +-- +-- Test combinations of DISTINCT and/or ORDER BY +-- +select array_agg(a order by b) + from (values (1,4),(2,3),(3,1),(4,2)) v(a,b); + array_agg +----------- + {3,4,2,1} +(1 row) + +select array_agg(a order by a) + from (values (1,4),(2,3),(3,1),(4,2)) v(a,b); + array_agg +----------- + {1,2,3,4} +(1 row) + +select array_agg(a order by a desc) + from (values (1,4),(2,3),(3,1),(4,2)) v(a,b); + array_agg +----------- + {4,3,2,1} +(1 row) + +select array_agg(b order by a desc) + from (values (1,4),(2,3),(3,1),(4,2)) v(a,b); + array_agg +----------- + {2,1,3,4} +(1 row) + +select array_agg(distinct a) + from (values (1),(2),(1),(3),(null),(2)) v(a); + array_agg +-------------- + {1,2,3,NULL} +(1 row) + +select array_agg(distinct a order by a) + from (values (1),(2),(1),(3),(null),(2)) v(a); + array_agg +-------------- + {1,2,3,NULL} +(1 row) + +select array_agg(distinct a order by a desc) + from (values (1),(2),(1),(3),(null),(2)) v(a); + array_agg +-------------- + {NULL,3,2,1} +(1 row) + +select array_agg(distinct a order by a desc nulls last) + from (values (1),(2),(1),(3),(null),(2)) v(a); + array_agg +-------------- + {3,2,1,NULL} +(1 row) + +-- multi-arg aggs, strict/nonstrict, distinct/order by +select aggfstr(a,b,c) + from (values (1,3,'foo'),(0,null,null),(2,2,'bar'),(3,1,'baz')) v(a,b,c); + aggfstr +--------------------------------------- + {"(1,3,foo)","(2,2,bar)","(3,1,baz)"} +(1 row) + +select aggfns(a,b,c) + from (values (1,3,'foo'),(0,null,null),(2,2,'bar'),(3,1,'baz')) v(a,b,c); + aggfns +----------------------------------------------- + {"(1,3,foo)","(0,,)","(2,2,bar)","(3,1,baz)"} +(1 row) + +select aggfstr(distinct a,b,c) + from (values (1,3,'foo'),(0,null,null),(2,2,'bar'),(3,1,'baz')) v(a,b,c), + generate_series(1,3) i; + aggfstr +--------------------------------------- + {"(1,3,foo)","(2,2,bar)","(3,1,baz)"} +(1 row) + +select aggfns(distinct a,b,c) + from (values (1,3,'foo'),(0,null,null),(2,2,'bar'),(3,1,'baz')) v(a,b,c), + generate_series(1,3) i; + aggfns +----------------------------------------------- + {"(0,,)","(1,3,foo)","(2,2,bar)","(3,1,baz)"} +(1 row) + +select aggfstr(distinct a,b,c order by b) + from (values (1,3,'foo'),(0,null,null),(2,2,'bar'),(3,1,'baz')) v(a,b,c), + generate_series(1,3) i; + aggfstr +--------------------------------------- + {"(3,1,baz)","(2,2,bar)","(1,3,foo)"} +(1 row) + +select aggfns(distinct a,b,c order by b) + from (values (1,3,'foo'),(0,null,null),(2,2,'bar'),(3,1,'baz')) v(a,b,c), + generate_series(1,3) i; + aggfns +----------------------------------------------- + {"(3,1,baz)","(2,2,bar)","(1,3,foo)","(0,,)"} +(1 row) + +-- test specific code paths +select aggfns(distinct a,a,c order by c using ~<~,a) + from (values (1,3,'foo'),(0,null,null),(2,2,'bar'),(3,1,'baz')) v(a,b,c), + generate_series(1,2) i; + aggfns +------------------------------------------------ + {"(2,2,bar)","(3,3,baz)","(1,1,foo)","(0,0,)"} +(1 row) + +select aggfns(distinct a,a,c order by c using ~<~) + from (values (1,3,'foo'),(0,null,null),(2,2,'bar'),(3,1,'baz')) v(a,b,c), + generate_series(1,2) i; + aggfns +------------------------------------------------ + {"(2,2,bar)","(3,3,baz)","(1,1,foo)","(0,0,)"} +(1 row) + +select aggfns(distinct a,a,c order by a) + from (values (1,3,'foo'),(0,null,null),(2,2,'bar'),(3,1,'baz')) v(a,b,c), + generate_series(1,2) i; + aggfns +------------------------------------------------ + {"(0,0,)","(1,1,foo)","(2,2,bar)","(3,3,baz)"} +(1 row) + +select aggfns(distinct a,b,c order by a,c using ~<~,b) + from (values (1,3,'foo'),(0,null,null),(2,2,'bar'),(3,1,'baz')) v(a,b,c), + generate_series(1,2) i; + aggfns +----------------------------------------------- + {"(0,,)","(1,3,foo)","(2,2,bar)","(3,1,baz)"} +(1 row) + +-- check node I/O via view creation and usage, also deparsing logic +create view agg_view1 as + select aggfns(a,b,c) + from (values (1,3,'foo'),(0,null,null),(2,2,'bar'),(3,1,'baz')) v(a,b,c); +select * from agg_view1; + aggfns +----------------------------------------------- + {"(1,3,foo)","(0,,)","(2,2,bar)","(3,1,baz)"} +(1 row) + +select pg_get_viewdef('agg_view1'::regclass); + pg_get_viewdef +-------------------------------------------------------------------------------------------------------------------------------------------------------- + SELECT aggfns(v.a, v.b, v.c) AS aggfns FROM (VALUES (1,3,'foo'::text), (0,NULL::integer,NULL::text), (2,2,'bar'::text), (3,1,'baz'::text)) v(a, b, c); +(1 row) + +create or replace view agg_view1 as + select aggfns(distinct a,b,c) + from (values (1,3,'foo'),(0,null,null),(2,2,'bar'),(3,1,'baz')) v(a,b,c), + generate_series(1,3) i; +select * from agg_view1; + aggfns +----------------------------------------------- + {"(0,,)","(1,3,foo)","(2,2,bar)","(3,1,baz)"} +(1 row) + +select pg_get_viewdef('agg_view1'::regclass); + pg_get_viewdef +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + SELECT aggfns(DISTINCT v.a, v.b, v.c) AS aggfns FROM (VALUES (1,3,'foo'::text), (0,NULL::integer,NULL::text), (2,2,'bar'::text), (3,1,'baz'::text)) v(a, b, c), generate_series(1, 3) i(i); +(1 row) + +create or replace view agg_view1 as + select aggfns(distinct a,b,c order by b) + from (values (1,3,'foo'),(0,null,null),(2,2,'bar'),(3,1,'baz')) v(a,b,c), + generate_series(1,3) i; +select * from agg_view1; + aggfns +----------------------------------------------- + {"(3,1,baz)","(2,2,bar)","(1,3,foo)","(0,,)"} +(1 row) + +select pg_get_viewdef('agg_view1'::regclass); + pg_get_viewdef +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + SELECT aggfns(DISTINCT v.a, v.b, v.c ORDER BY v.b) AS aggfns FROM (VALUES (1,3,'foo'::text), (0,NULL::integer,NULL::text), (2,2,'bar'::text), (3,1,'baz'::text)) v(a, b, c), generate_series(1, 3) i(i); +(1 row) + +create or replace view agg_view1 as + select aggfns(a,b,c order by b+1) + from (values (1,3,'foo'),(0,null,null),(2,2,'bar'),(3,1,'baz')) v(a,b,c); +select * from agg_view1; + aggfns +----------------------------------------------- + {"(3,1,baz)","(2,2,bar)","(1,3,foo)","(0,,)"} +(1 row) + +select pg_get_viewdef('agg_view1'::regclass); + pg_get_viewdef +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + SELECT aggfns(v.a, v.b, v.c ORDER BY (v.b + 1)) AS aggfns FROM (VALUES (1,3,'foo'::text), (0,NULL::integer,NULL::text), (2,2,'bar'::text), (3,1,'baz'::text)) v(a, b, c); +(1 row) + +create or replace view agg_view1 as + select aggfns(a,a,c order by b) + from (values (1,3,'foo'),(0,null,null),(2,2,'bar'),(3,1,'baz')) v(a,b,c); +select * from agg_view1; + aggfns +------------------------------------------------ + {"(3,3,baz)","(2,2,bar)","(1,1,foo)","(0,0,)"} +(1 row) + +select pg_get_viewdef('agg_view1'::regclass); + pg_get_viewdef +--------------------------------------------------------------------------------------------------------------------------------------------------------------------- + SELECT aggfns(v.a, v.a, v.c ORDER BY v.b) AS aggfns FROM (VALUES (1,3,'foo'::text), (0,NULL::integer,NULL::text), (2,2,'bar'::text), (3,1,'baz'::text)) v(a, b, c); +(1 row) + +create or replace view agg_view1 as + select aggfns(a,b,c order by c using ~<~) + from (values (1,3,'foo'),(0,null,null),(2,2,'bar'),(3,1,'baz')) v(a,b,c); +select * from agg_view1; + aggfns +----------------------------------------------- + {"(2,2,bar)","(3,1,baz)","(1,3,foo)","(0,,)"} +(1 row) + +select pg_get_viewdef('agg_view1'::regclass); + pg_get_viewdef +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ + SELECT aggfns(v.a, v.b, v.c ORDER BY v.c USING ~<~ NULLS LAST) AS aggfns FROM (VALUES (1,3,'foo'::text), (0,NULL::integer,NULL::text), (2,2,'bar'::text), (3,1,'baz'::text)) v(a, b, c); +(1 row) + +create or replace view agg_view1 as + select aggfns(distinct a,b,c order by a,c using ~<~,b) + from (values (1,3,'foo'),(0,null,null),(2,2,'bar'),(3,1,'baz')) v(a,b,c), + generate_series(1,2) i; +select * from agg_view1; + aggfns +----------------------------------------------- + {"(0,,)","(1,3,foo)","(2,2,bar)","(3,1,baz)"} +(1 row) + +select pg_get_viewdef('agg_view1'::regclass); + pg_get_viewdef +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + SELECT aggfns(DISTINCT v.a, v.b, v.c ORDER BY v.a, v.c USING ~<~ NULLS LAST, v.b) AS aggfns FROM (VALUES (1,3,'foo'::text), (0,NULL::integer,NULL::text), (2,2,'bar'::text), (3,1,'baz'::text)) v(a, b, c), generate_series(1, 2) i(i); +(1 row) + +drop view agg_view1; +-- incorrect DISTINCT usage errors +select aggfns(distinct a,b,c order by i) + from (values (1,1,'foo')) v(a,b,c), generate_series(1,2) i; +ERROR: in an aggregate with DISTINCT, ORDER BY expressions must appear in argument list +LINE 1: select aggfns(distinct a,b,c order by i) + ^ +select aggfns(distinct a,b,c order by a,b+1) + from (values (1,1,'foo')) v(a,b,c), generate_series(1,2) i; +ERROR: in an aggregate with DISTINCT, ORDER BY expressions must appear in argument list +LINE 1: select aggfns(distinct a,b,c order by a,b+1) + ^ +select aggfns(distinct a,b,c order by a,b,i,c) + from (values (1,1,'foo')) v(a,b,c), generate_series(1,2) i; +ERROR: in an aggregate with DISTINCT, ORDER BY expressions must appear in argument list +LINE 1: select aggfns(distinct a,b,c order by a,b,i,c) + ^ +select aggfns(distinct a,a,c order by a,b) + from (values (1,1,'foo')) v(a,b,c), generate_series(1,2) i; +ERROR: in an aggregate with DISTINCT, ORDER BY expressions must appear in argument list +LINE 1: select aggfns(distinct a,a,c order by a,b) + ^ +-- string_agg tests +select string_agg(a,',') from (values('aaaa'),('bbbb'),('cccc')) g(a); + string_agg +---------------- + aaaa,bbbb,cccc +(1 row) + +select string_agg(a,',') from (values('aaaa'),(null),('bbbb'),('cccc')) g(a); + string_agg +---------------- + aaaa,bbbb,cccc +(1 row) + +select string_agg(a,'AB') from (values(null),(null),('bbbb'),('cccc')) g(a); + string_agg +------------ + bbbbABcccc +(1 row) + +select string_agg(a,',') from (values(null),(null)) g(a); + string_agg +------------ + +(1 row) + +-- check some implicit casting cases, as per bug #5564 +select string_agg(distinct f1, ',' order by f1) from varchar_tbl; -- ok + string_agg +------------ + a,ab,abcd +(1 row) + +select string_agg(distinct f1::text, ',' order by f1) from varchar_tbl; -- not ok +ERROR: in an aggregate with DISTINCT, ORDER BY expressions must appear in argument list +LINE 1: select string_agg(distinct f1::text, ',' order by f1) from v... + ^ +select string_agg(distinct f1, ',' order by f1::text) from varchar_tbl; -- not ok +ERROR: in an aggregate with DISTINCT, ORDER BY expressions must appear in argument list +LINE 1: select string_agg(distinct f1, ',' order by f1::text) from v... + ^ +select string_agg(distinct f1::text, ',' order by f1::text) from varchar_tbl; -- ok + string_agg +------------ + a,ab,abcd +(1 row) + diff --git a/src/test/regress/sql/aggregates.sql b/src/test/regress/sql/aggregates.sql index 7e148f5471..bd8df68d0e 100644 --- a/src/test/regress/sql/aggregates.sql +++ b/src/test/regress/sql/aggregates.sql @@ -208,36 +208,38 @@ FROM bool_test; -- -- Test cases that should be optimized into indexscans instead of -- the generic aggregate implementation. +-- In Postgres-XC, plans printed by explain are the ones created on the +-- coordinator. Coordinator does not generate index scan plans. -- analyze tenk1; -- ensure we get consistent plans here -- Basic cases -explain (costs off) +explain (costs off, nodes off) select min(unique1) from tenk1; select min(unique1) from tenk1; -explain (costs off) +explain (costs off, nodes off) select max(unique1) from tenk1; select max(unique1) from tenk1; -explain (costs off) +explain (costs off, nodes off) select max(unique1) from tenk1 where unique1 < 42; select max(unique1) from tenk1 where unique1 < 42; -explain (costs off) +explain (costs off, nodes off) select max(unique1) from tenk1 where unique1 > 42; select max(unique1) from tenk1 where unique1 > 42; -explain (costs off) +explain (costs off, nodes off) select max(unique1) from tenk1 where unique1 > 42000; select max(unique1) from tenk1 where unique1 > 42000; -- multi-column index (uses tenk1_thous_tenthous) -explain (costs off) +explain (costs off, nodes off) select max(tenthous) from tenk1 where thousand = 33; select max(tenthous) from tenk1 where thousand = 33; -explain (costs off) +explain (costs off, nodes off) select min(tenthous) from tenk1 where thousand = 33; select min(tenthous) from tenk1 where thousand = 33; -- check parameter propagation into an indexscan subquery -explain (costs off) +explain (costs off, nodes off) select f1, (select min(unique1) from tenk1 where unique1 > f1) AS gt from int4_tbl; select f1, (select min(unique1) from tenk1 where unique1 > f1) AS gt @@ -245,19 +247,19 @@ from int4_tbl order by f1; -- check some cases that were handled incorrectly in 8.3.0 -explain (costs off) +explain (costs off, nodes off) select distinct max(unique2) from tenk1; select distinct max(unique2) from tenk1; -explain (costs off) +explain (costs off, nodes off) select max(unique2) from tenk1 order by 1; select max(unique2) from tenk1 order by 1; -explain (costs off) +explain (costs off, nodes off) select max(unique2) from tenk1 order by max(unique2); select max(unique2) from tenk1 order by max(unique2); -explain (costs off) +explain (costs off, nodes off) select max(unique2) from tenk1 order by max(unique2)+1; select max(unique2) from tenk1 order by max(unique2)+1; -explain (costs off) +explain (costs off, nodes off) select max(unique2), generate_series(1,3) as g from tenk1 order by g desc; select max(unique2), generate_series(1,3) as g from tenk1 order by g desc; @@ -276,7 +278,7 @@ insert into minmaxtest1 values(13), (14); insert into minmaxtest2 values(15), (16); insert into minmaxtest3 values(17), (18); -explain (costs off) +explain (costs off, nodes off) select min(f1), max(f1) from minmaxtest; select min(f1), max(f1) from minmaxtest; |