From b2b423229777bfb40cbf3f72e546c46beb2eb8a5 Mon Sep 17 00:00:00 2001 From: zhanglong Date: Thu, 7 Nov 2024 18:51:13 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=81=9A=E9=9B=86=E5=87=BD?= =?UTF-8?q?=E6=95=B0CUME=5FDISTRANK,PERCENT=5FRANK,DENSE=5FRANK=E5=A4=9A?= =?UTF-8?q?=E5=8F=82=E6=95=B0=E5=A4=9A=E7=B1=BB=E5=9E=8B=E7=9A=84=E7=89=B9?= =?UTF-8?q?=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/bin/gs_guc/cluster_guc.conf | 1 + src/common/backend/catalog/builtin_funcs.ini | 40 +- src/common/backend/catalog/pg_aggregate.cpp | 18 +- src/common/backend/parser/parse_coerce.cpp | 11 +- src/common/backend/parser/parse_collate.cpp | 135 +++- src/common/backend/parser/parse_func.cpp | 116 +++- .../backend/utils/adt/orderedsetaggs.cpp | 584 +++++++++++++++--- src/common/backend/utils/init/globals.cpp | 2 +- src/common/backend/utils/misc/guc.cpp | 11 + .../optimizer/commands/aggregatecmds.cpp | 2 + src/gausskernel/runtime/executor/nodeAgg.cpp | 59 ++ .../storage/access/common/heaptuple.cpp | 1 - .../storage/access/common/tupdesc.cpp | 43 ++ src/include/access/tupdesc.h | 3 + src/include/catalog/pg_aggregate.h | 8 +- src/include/catalog/pg_proc.h | 2 + src/include/catalog/pg_proc.h_for_llt | 19 + .../rollback-post_catalog_maindb_93_022.sql | 9 + .../rollback-post_catalog_otherdb_93_022.sql | 9 + .../upgrade-post_catalog_maindb_93_022.sql | 49 ++ .../upgrade-post_catalog_otherdb_93_022.sql | 49 ++ src/include/executor/tuptable.h | 1 + src/include/fmgr.h | 5 + .../knl/knl_guc/knl_session_attr_common.h | 1 + src/include/nodes/execnodes.h | 1 + src/include/utils/builtins.h | 6 +- .../expected/aggregates_hypothetical.out | 154 +++++ src/test/regress/output/pg_proc_test.source | 11 +- src/test/regress/parallel_schedule0 | 1 + src/test/regress/parallel_schedule0B | 1 + .../regress/sql/aggregates_hypothetical.sql | 87 +++ 31 files changed, 1341 insertions(+), 98 deletions(-) create mode 100644 src/include/catalog/upgrade_sql/rollback_catalog_maindb/rollback-post_catalog_maindb_93_022.sql create mode 100644 src/include/catalog/upgrade_sql/rollback_catalog_otherdb/rollback-post_catalog_otherdb_93_022.sql create mode 100644 src/include/catalog/upgrade_sql/upgrade_catalog_maindb/upgrade-post_catalog_maindb_93_022.sql create mode 100644 src/include/catalog/upgrade_sql/upgrade_catalog_otherdb/upgrade-post_catalog_otherdb_93_022.sql create mode 100644 src/test/regress/expected/aggregates_hypothetical.out create mode 100644 src/test/regress/sql/aggregates_hypothetical.sql diff --git a/src/bin/gs_guc/cluster_guc.conf b/src/bin/gs_guc/cluster_guc.conf index 803227ec2..c09af69fe 100755 --- a/src/bin/gs_guc/cluster_guc.conf +++ b/src/bin/gs_guc/cluster_guc.conf @@ -838,6 +838,7 @@ uwal_rpc_flowcontrol_value|int|8,2048|NULL|NULL| uwal_truncate_interval|int|0,7200|NULL|NULL| uwal_async_append_switch|bool|0,0|NULL|NULL| enable_gazelle_performance_mode|bool|0,0|NULL|NULL| +enable_aggr_coerce_type|bool|0,0|NULL|NULL| [cmserver] log_dir|string|0,0|NULL|NULL| log_file_size|int|0,2047|MB|NULL| diff --git a/src/common/backend/catalog/builtin_funcs.ini b/src/common/backend/catalog/builtin_funcs.ini index 19f9591f0..2b973a9ec 100644 --- a/src/common/backend/catalog/builtin_funcs.ini +++ b/src/common/backend/catalog/builtin_funcs.ini @@ -2082,8 +2082,13 @@ AddBuiltinFunc(_0(2501), _1("cstring_send"), _2(1), _3(true), _4(false), _5(cstring_send), _6(17), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('s'), _19(0), _20(1, 2275), _21(NULL), _22(NULL), _23(NULL), _24(NULL), _25("cstring_send"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33("I/O"), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)) ), AddFuncGroup( - "cume_dist", 1, - AddBuiltinFunc(_0(3104), _1("cume_dist"), _2(0), _3(false), _4(false), _5(window_cume_dist), _6(701), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(true), _16(false), _17(false), _18('i'), _19(0), _20(0), _21(NULL), _22(NULL), _23(NULL), _24(NULL), _25("window_cume_dist"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33("fractional row number within partition"), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)) + "cume_dist", 2, + AddBuiltinFunc(_0(3104), _1("cume_dist"), _2(0), _3(false), _4(false), _5(window_cume_dist), _6(701), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(true), _16(false), _17(false), _18('i'), _19(0), _20(0), _21(NULL), _22(NULL), _23(NULL), _24(NULL), _25("window_cume_dist"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33("fractional row number within partition"), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)), + AddBuiltinFunc(_0(3148), _1("cume_dist"), _2(0), _3(false), _4(false), _5(aggregate_dummy), _6(701), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(2276), _13(0), _14(true), _15(true), _16(false), _17(false), _18('i'), _19(0), _20(1,2276), _21(1, 2276), _22(1, 'v'), _23(NULL), _24(NULL), _25("aggregate_dummy"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33("cumulative distribution of hypothetical row"), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)) + ), + AddFuncGroup( + "cume_dist_final", 1, + AddBuiltinFunc(_0(4465), _1("cume_dist_final"), _2(2), _3(false), _4(false), _5(hypothetical_cume_dist_final), _6(701), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(2276), _13(0), _14(false), _15(false), _16(false), _17(false), _18('i'), _19(0), _20(2, 2281, 2276), _21(2, 2281, 2276), _22(2, 'i', 'v'), _23(NULL), _24(NULL), _25("hypothetical_cume_dist_final"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33("aggregate final function"), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)) ), AddFuncGroup( "cupointer_bigint", 1, @@ -2398,8 +2403,13 @@ AddBuiltinFunc(_0(1508), _1("delete_breakpoint"), _2(1), _3(true), _4(false), _5(debug_client_delete_breakpoint), _6(16), _7(PG_PLDEBUG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('s'), _19(0), _20(1, 23), _21(NULL), _22(NULL), _23(NULL), _24(NULL), _25("debug_client_delete_breakpoint"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(false), _32(false), _33(NULL), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)) ), AddFuncGroup( - "dense_rank", 1, - AddBuiltinFunc(_0(DENSERANKFUNCOID), _1("dense_rank"), _2(0), _3(false), _4(false), _5(window_dense_rank), _6(20), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(true), _16(false), _17(false), _18('i'), _19(0), _20(0), _21(NULL), _22(NULL), _23(NULL), _24(NULL), _25("window_dense_rank"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33("integer rank without gaps"), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)) + "dense_rank", 2, + AddBuiltinFunc(_0(DENSERANKFUNCOID), _1("dense_rank"), _2(0), _3(false), _4(false), _5(window_dense_rank), _6(20), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(true), _16(false), _17(false), _18('i'), _19(0), _20(0), _21(NULL), _22(NULL), _23(NULL), _24(NULL), _25("window_dense_rank"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33("integer rank without gaps"), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)), + AddBuiltinFunc(_0(4082), _1("dense_rank"), _2(1), _3(false), _4(false), _5(aggregate_dummy), _6(20), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(2276), _13(0), _14(true), _15(false), _16(false), _17(false), _18('i'), _19(0), _20(1, 2276), _21(1, 2276), _22(1, 'v'), _23(NULL), _24(NULL), _25("aggregate_dummy"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(true), _32(false), _33("dense rank of hypothetical row"), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)) + ), + AddFuncGroup( + "dense_rank_final", 1, + AddBuiltinFunc(_0(4084), _1("dense_rank_final"), _2(2), _3(false), _4(false), _5(hypothetical_dense_rank_final), _6(20), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(2276), _13(0), _14(false), _15(false), _16(false), _17(false), _18('i'), _19(0), _20(2, 2281, 2276), _21(2, 2281, 2276), _22(2, 'i', 'v'), _23(NULL), _24(NULL), _25("hypothetical_dense_rank_final"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33("aggregate final function"), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)) ), AddFuncGroup( "dexp", 1, @@ -7986,8 +7996,13 @@ AddBuiltinFunc(_0(1433), _1("pclose"), _2(1), _3(true), _4(false), _5(path_close), _6(602), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('i'), _19(0), _20(1, 602), _21(NULL), _22(NULL), _23(NULL), _24(NULL), _25("path_close"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33("close path"), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)) ), AddFuncGroup( - "percent_rank", 1, - AddBuiltinFunc(_0(3103), _1("percent_rank"), _2(0), _3(false), _4(false), _5(window_percent_rank), _6(701), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(true), _16(false), _17(false), _18('i'), _19(0), _20(0), _21(NULL), _22(NULL), _23(NULL), _24(NULL), _25("window_percent_rank"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33("fractional rank within partition"), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)) + "percent_rank", 2, + AddBuiltinFunc(_0(3103), _1("percent_rank"), _2(0), _3(false), _4(false), _5(window_percent_rank), _6(701), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(true), _16(false), _17(false), _18('i'), _19(0), _20(0), _21(NULL), _22(NULL), _23(NULL), _24(NULL), _25("window_percent_rank"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33("fractional rank within partition"), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)), + AddBuiltinFunc(_0(4083), _1("percent_rank"), _2(1), _3(false), _4(false), _5(aggregate_dummy), _6(701), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(2276), _13(0), _14(true), _15(false), _16(false), _17(false), _18('i'), _19(0), _20(1, 2276), _21(1, 2276), _22(1, 'v'), _23(NULL), _24(NULL), _25("aggregate_dummy"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(true), _32(false), _33("percent rank of hypothetical row"), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)) + ), + AddFuncGroup( + "percent_rank_final", 1, + AddBuiltinFunc(_0(4085), _1("percent_rank_final"), _2(2), _3(false), _4(false), _5(hypothetical_percent_rank_final), _6(701), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(2276), _13(0), _14(false), _15(false), _16(false), _17(false), _18('i'), _19(0), _20(2, 2281, 2276), _21(2, 2281, 2276), _22(2, 'i', 'v'), _23(NULL), _24(NULL), _25("hypothetical_percent_rank_final"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33("aggregate final function"), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)) ), AddFuncGroup( "percentile_cont", 2, @@ -10135,8 +10150,13 @@ AddFuncGroup( AddBuiltinFunc(_0(3867), _1("range_union"), _2(2), _3(true), _4(false), _5(range_union), _6(3831), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('i'), _19(0), _20(2, 3831, 3831), _21(NULL), _22(NULL), _23(NULL), _24(NULL), _25("range_union"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33(NULL), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)) ), AddFuncGroup( - "rank", 1, - AddBuiltinFunc(_0(RANKFUNCOID), _1("rank"), _2(0), _3(false), _4(false), _5(window_rank), _6(20), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(true), _16(false), _17(false), _18('i'), _19(0), _20(0), _21(NULL), _22(NULL), _23(NULL), _24(NULL), _25("window_rank"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33("integer rank with gaps"), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)) + "rank", 2, + AddBuiltinFunc(_0(RANKFUNCOID), _1("rank"), _2(0), _3(false), _4(false), _5(window_rank), _6(20), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(true), _16(false), _17(false), _18('i'), _19(0), _20(0), _21(NULL), _22(NULL), _23(NULL), _24(NULL), _25("window_rank"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33("integer rank with gaps"), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)), + AddBuiltinFunc(_0(RANKFUNCHYPOOID), _1("rank"), _2(1), _3(false), _4(false), _5(aggregate_dummy), _6(20), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(2276), _13(0), _14(true), _15(false), _16(false), _17(false), _18('i'), _19(0), _20(1, 2276), _21(1, 2276), _22(1, 'v'), _23(NULL), _24(NULL), _25("aggregate_dummy"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(true), _32(false), _33("rank of hypothetical row"), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)) + ), + AddFuncGroup( + "rank_final", 1, + AddBuiltinFunc(_0(RANKFUNCHYPFINALOOID), _1("rank_final"), _2(2), _3(false), _4(false), _5(hypothetical_rank_final), _6(20), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(2276), _13(0), _14(false), _15(false), _16(false), _17(false), _18('i'), _19(0), _20(2,2281, 2276), _21(2,2281,2276), _22(2,'i','v'), _23(NULL), _24(NULL), _25("hypothetical_rank_final"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33("aggregate final function"), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)) ), AddFuncGroup( "rawcat", 1, @@ -13161,6 +13181,10 @@ AddFuncGroup( "gs_get_hba_conf", 1, AddBuiltinFunc(_0(2873), _1("gs_get_hba_conf"), _2(0), _3(true), _4(true), _5(gs_get_hba_conf), _6(2249), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(10), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('v'), _19(0), _20(0), _21(5, 25, 25, 25, 25, 25), _22(5, 'o', 'o', 'o', 'o','o'), _23(5, "type", "database", "user", "address", "method"), _24(NULL), _25("gs_get_hba_conf"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33("config: information about pg_hba conf file"), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)) ), + AddFuncGroup( + "ordered_set_transition_multi", 1, + AddBuiltinFunc(_0(4464), _1("ordered_set_transition_multi"), _2(2), _3(false), _4(false), _5(ordered_set_transition_multi), _6(2281), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('i'), _19(0), _20(2, 2281, 2276), _21(2, 2281, 2276), _22(2, 'i', 'v'), _23(NULL), _24(NULL), _25("ordered_set_transition_multi"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33("aggregate transition function"), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)) + ), AddFuncGroup( "query_imcstore_views", 1, AddBuiltinFunc(_0(6808), _1("query_imcstore_views"), _2(1), _3(true), _4(true), _5(query_imcstore_views), _6(2249), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(1000), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('s'), _19(0), _20(0), _21(11, 26, 19, 22, 21, 19, 16, 26, 20, 20, 20, 20), _22(11, 'o', 'o', 'o', 'o','o', 'o', 'o', 'o', 'o','o', 'o'), _23(11, "reloid", "relname", "imcs_attrs", "imcs_nattrs", "imcs_status", "is_partition", "parent_oid", "cu_size_in_mem", "cu_num_in_mem", "cu_size_in_disk", "cu_num_in_disk"), _24(NULL), _25("query_imcstore_views"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33("query_imcstore_views"), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)) diff --git a/src/common/backend/catalog/pg_aggregate.cpp b/src/common/backend/catalog/pg_aggregate.cpp index 2256805eb..52e4cac71 100644 --- a/src/common/backend/catalog/pg_aggregate.cpp +++ b/src/common/backend/catalog/pg_aggregate.cpp @@ -69,6 +69,10 @@ static void InternalAggIsSupported(const char *aggName) "age_collect", "age_percentilecont", "age_percentiledisc", + "cume_dist", + "dense_rank", + "rank", + "percent_rank", "corr_s", "corr_k" }; @@ -272,9 +276,15 @@ ObjectAddress AggregateCreate(const char* aggName, Oid aggNamespace, char aggKin #endif /* handle finalfn, if supplied */ + int nargsfinalfn = 1; if (aggfinalfnName != NULL) { fnArgs[0] = aggTransType; - finalfn = lookup_agg_function(aggfinalfnName, 1, fnArgs, &finaltype); + if (aggKind == AGGKIND_HYPOTHETICAL) + { + fnArgs[1] = 2276; + nargsfinalfn += 1; + } + finalfn = lookup_agg_function(aggfinalfnName, nargsfinalfn, fnArgs, &finaltype); } else { /* * If no finalfn, aggregate result type is type of the state value @@ -426,7 +436,10 @@ ObjectAddress AggregateCreate(const char* aggName, Oid aggNamespace, char aggKin #endif /* handle ordered set aggregate with no direct args. */ values[Anum_pg_aggregate_aggkind - 1] = CharGetDatum(aggKind); - values[Anum_pg_aggregate_aggnumdirectargs - 1] = Int8GetDatum(AGGNUMDIRECTARGS_DEFAULT); + if (aggKind == AGGKIND_HYPOTHETICAL) + values[Anum_pg_aggregate_aggnumdirectargs - 1] = Int8GetDatum(AGGNUMDIRECTARGS_DEFAULT + 1); + else + values[Anum_pg_aggregate_aggnumdirectargs - 1] = Int8GetDatum(AGGNUMDIRECTARGS_DEFAULT); aggdesc = heap_open(AggregateRelationId, RowExclusiveLock); tupDesc = aggdesc->rd_att; @@ -522,6 +535,7 @@ static Oid lookup_agg_function(List* fnName, int nargs, Oid* input_types, Oid* r ereport(ERROR, (errcode(ERRCODE_UNDEFINED_FUNCTION), errmsg("function %s does not exist", func_signature_string(fnName, nargs, NIL, input_types)))); + if (retset) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), diff --git a/src/common/backend/parser/parse_coerce.cpp b/src/common/backend/parser/parse_coerce.cpp index cb071ca0f..2c72a4a2c 100644 --- a/src/common/backend/parser/parse_coerce.cpp +++ b/src/common/backend/parser/parse_coerce.cpp @@ -1925,7 +1925,16 @@ static Oid choose_expr_type(ParseState* pstate, List* exprs, const char* context */ if (context == NULL) return InvalidOid; - else + /* + * Skip the check only when the parameter is true + * and the expression is WITIN GROUP + * This processing is to solve the aggregate function's + * (cume_dist,rank,dense_rank,percent_rank) + * direct args and hypothetical args type is not match. + */ + else if (u_sess->attr.attr_sql.sql_compatibility != A_FORMAT || + !(u_sess->attr.attr_common.enable_aggr_coerce_type && + CHECK_PARSE_PHRASE(context, "WITHIN GROUP"))) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), /* ------ diff --git a/src/common/backend/parser/parse_collate.cpp b/src/common/backend/parser/parse_collate.cpp index 8a9be8bab..482bc9410 100644 --- a/src/common/backend/parser/parse_collate.cpp +++ b/src/common/backend/parser/parse_collate.cpp @@ -108,7 +108,8 @@ static void merge_diff_charset_collation(Oid collation, CollateStrength strength CollateDerivation derivation, int charset, int context_charset, assign_collations_context* context); static void deal_expr_collation_b_compatibility( Node* node, Oid expr_type, assign_collations_context* context, int location); - +static void assign_hypothetical_collations(Aggref *aggref, + assign_collations_context *loccontext); #define TYPE_IS_COLLATABLE_B_FORMAT(type_oid) \ (IsSupportCharsetType(type_oid) || (type_oid) == UNKNOWNOID || IsBinaryType(type_oid)) /* @@ -661,16 +662,19 @@ static bool assign_collations_walker(Node* node, assign_collations_context* cont * For normal aggregates and orderd-set aggregates, we handled * them differently. */ + Aggref *aggref = (Aggref *) node; switch (((Aggref*)node)->aggkind) { case AGGKIND_NORMAL: - assign_aggregate_collations((Aggref*)node, &loccontext); + assign_aggregate_collations(aggref, &loccontext); break; case AGGKIND_ORDERED_SET: - assign_ordered_set_collations((Aggref*)node, &loccontext); + assign_ordered_set_collations(aggref, &loccontext); + break; + case AGGKIND_HYPOTHETICAL: + assign_hypothetical_collations(aggref, &loccontext); break; default: - /* support ordered set agg at 91269 kernel version */ - assign_aggregate_collations((Aggref*)node, &loccontext); + elog(ERROR, "unrecognized aggkind: %d", (int)aggref->aggkind); } assign_expr_collations(context->pstate, (Node *)((Aggref *)node)->aggfilter); } break; @@ -1052,14 +1056,14 @@ static void assign_aggregate_collations(Aggref* aggref, assign_collations_contex */ static void assign_ordered_set_collations(Aggref* aggref, assign_collations_context* loccontext) { - bool merge_sort_collations; + bool mergeSortCollations; ListCell* lc = NULL; /* * If it only have a single aggregated argument(the sort argument), we * can determine its collation directly */ - merge_sort_collations = (list_length(aggref->args) == 1 && get_func_variadictype(aggref->aggfnoid) == InvalidOid); + mergeSortCollations = (list_length(aggref->args) == 1 && get_func_variadictype(aggref->aggfnoid) == InvalidOid); /* Walk inside direct args of Aggref node to determine the collation */ (void)assign_collations_walker((Node*)aggref->aggdirectargs, loccontext); @@ -1069,7 +1073,7 @@ static void assign_ordered_set_collations(Aggref* aggref, assign_collations_cont tle = (TargetEntry*)lfirst(lc); Assert(IsA(tle, TargetEntry)); - if (merge_sort_collations) { + if (mergeSortCollations) { (void)assign_collations_walker((Node*)tle, loccontext); } else { assign_expr_collations(loccontext->pstate, (Node*)tle); @@ -1220,13 +1224,13 @@ static void merge_ordered_set_charsets(Aggref* aggref, Oid target_collation) merge_arg_charsets(target_collation, aggref->aggdirectargs); - bool merge_sort_collations = (list_length(aggref->args) == 1 && + bool mergeSortCollations = (list_length(aggref->args) == 1 && get_func_variadictype(aggref->aggfnoid) == InvalidOid); int target_charset = get_valid_charset_by_collation(target_collation); foreach_cell (lc, aggref->args) { TargetEntry* tle = (TargetEntry*)lfirst(lc); Assert(IsA(tle, TargetEntry)); - if (merge_sort_collations) { + if (mergeSortCollations) { tle->expr = (Expr*)convert_arg_charset((Node*)tle->expr, target_charset, target_collation); } } @@ -1381,3 +1385,114 @@ void check_duplicate_value_by_collation(List* vals, Oid collation, char type) } } } + + +/* + * Hypothetical-set aggregates are even more special: per spec, we need to + * unify the collations of each pair of hypothetical and aggregated args. + * And we need to force the choice of collation down into the sort column + * to ensure that the sort happens with the chosen collation. Other than + * that, the behavior is like regular ordered-set aggregates. Note that + * hypothetical direct arguments contribute to the aggregate collation + * only when their partner aggregated arguments do. + */ +static void assign_hypothetical_collations(Aggref *aggref, assign_collations_context *loccontext) +{ + ListCell *h_cell = list_head(aggref->aggdirectargs); + ListCell *s_cell = list_head(aggref->args); + bool mergeSortCollations = false; + int extraArgs = 0; + + /* Merge sort collations to parent only if there can be only one */ + mergeSortCollations = (list_length(aggref->args) == 1 && + get_func_variadictype(aggref->aggfnoid) == InvalidOid); + + /* Process any non-hypothetical direct args */ + extraArgs = list_length(aggref->aggdirectargs) - list_length(aggref->args); + Assert(extraArgs >= 0); + while (extraArgs-- > 0) { + (void) assign_collations_walker((Node *) lfirst(h_cell), loccontext); + h_cell = lnext(h_cell); + } + + /* Scan hypothetical args and aggregated args in parallel */ + while (h_cell && s_cell) { + Node *h_arg = (Node *) lfirst(h_cell); + TargetEntry *s_tle = (TargetEntry *) lfirst(s_cell); + assign_collations_context paircontext; + + /* + * Assign collations internally in this pair of expressions, then + * choose a common collation for them. This should match + * select_common_collation(), but we can't use that function as-is + * because we need access to the whole collation state so we can + * bubble it up to the aggregate function's level. + */ + paircontext.pstate = loccontext->pstate; + paircontext.collation = InvalidOid; + paircontext.strength = COLLATE_NONE; + paircontext.location = -1; + /* Set these fields just to suppress uninitialized-value warnings: */ + paircontext.collation2 = InvalidOid; + paircontext.location2 = -1; + + (void) assign_collations_walker(h_arg, &paircontext); + (void) assign_collations_walker((Node *) s_tle->expr, &paircontext); + + /* deal with collation conflict */ + if (paircontext.strength == COLLATE_CONFLICT) + ereport(ERROR, + (errcode(ERRCODE_COLLATION_MISMATCH), + errmsg("collation mismatch between implicit collations \"%s\" and \"%s\"", + get_collation_name(paircontext.collation), + get_collation_name(paircontext.collation2)), + errhint("You can choose the collation by applying the COLLATE clause to one or both expressions."), + parser_errposition(paircontext.pstate, + paircontext.location2))); + + /* + * At this point paircontext.collation can be InvalidOid only if the + * type is not collatable; no need to do anything in that case. If we + * do have to change the sort column's collation, do it by inserting a + * RelabelType node into the sort column TLE. + * + * XXX This is pretty grotty for a couple of reasons: + * assign_collations_walker isn't supposed to be changing the + * expression structure like this, and a parse-time change of + * collation ought to be signaled by a CollateExpr not a RelabelType + * (the use of RelabelType for collation marking is supposed to be a + * planner/executor thing only). But we have no better alternative. + * In particular, injecting a CollateExpr could result in the + * expression being interpreted differently after dump/reload, since + * we might be effectively promoting an implicit collation to + * explicit. This kluge is relying on ruleutils.c not printing a + * COLLATE clause for a RelabelType, and probably on some other + * fragile behaviors. + */ + if (OidIsValid(paircontext.collation) && + paircontext.collation != exprCollation((Node *) s_tle->expr)) { + s_tle->expr = (Expr *)makeRelabelType(s_tle->expr, + exprType((Node *)s_tle->expr), + exprTypmod((Node *)s_tle->expr), + paircontext.collation, + COERCE_IMPLICIT_CAST); + } + + /* + * If appropriate, merge this column's collation state up to the + * aggregate function. + */ + if (mergeSortCollations) { + merge_collation_state(paircontext.collation, + paircontext.strength, + paircontext.location, + DERIVATION_IGNORABLE, + paircontext.collation2, + paircontext.location2, + loccontext); + } + h_cell = lnext(h_cell); + s_cell = lnext(s_cell); + } + Assert(h_cell == NULL && s_cell == NULL); +} diff --git a/src/common/backend/parser/parse_func.cpp b/src/common/backend/parser/parse_func.cpp index 3e2aa1e25..90afc66eb 100644 --- a/src/common/backend/parser/parse_func.cpp +++ b/src/common/backend/parser/parse_func.cpp @@ -43,7 +43,8 @@ static List* GetDefaultVale(Oid funcoid, const int* argnumbers, int ndargs, bool static Oid cl_get_input_param_original_type(Oid func_oid, int argno); static bool CheckDefaultArgsPosition(int2vector* defaultargpos, int pronargdefaults, int ndargs, int pronallargs, int pronargs, HeapTuple procTup); - +static void unify_hypothetical_args(ParseState *pstate, + List *fargs, int numAggregatedArgs, Oid *actual_arg_types, Oid *declared_arg_types); /* * Parse a function call * @@ -305,6 +306,7 @@ Node* ParseFuncOrColumn(ParseState* pstate, List* funcname, List* fargs, Node* l /* Now do the saftey check. */ if (isOrderedSet) { int numDirectArgs = 0; + int numAggregatedArgs = 0; if (!agg_within_group) ereport(ERROR, @@ -337,7 +339,8 @@ Node* ParseFuncOrColumn(ParseState* pstate, List* funcname, List* fargs, Node* l * While agg_order is the number of aggregated args, we can conduct * the number of direct args. */ - numDirectArgs = nargs - list_length(agg_order); + numAggregatedArgs = list_length(agg_order); + numDirectArgs = nargs - numAggregatedArgs; Assert(numDirectArgs >= 0); if (nvargs > 1) pronargs -= nvargs - 1; @@ -354,8 +357,20 @@ Node* ParseFuncOrColumn(ParseState* pstate, List* funcname, List* fargs, Node* l numDirectArgs), parser_errposition(pstate, location))); } else { + if (aggkind == AGGKIND_HYPOTHETICAL) { + int argsfactor = 2; + if (nvargs != argsfactor * numAggregatedArgs) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_FUNCTION), + errmsg("function %s does not exist", + func_signature_string(funcname, nargs, argnames, actual_arg_types)), + errhint("To use the hypothetical-set aggregate %s, the number of hypothetical direct " + "arguments (here %d) must match the number of ordering columns (here %d).", + NameListToString(funcname), nvargs - numAggregatedArgs, numAggregatedArgs), + parser_errposition(pstate, location))); + } /* the agg was "..., VARIADIC ORDER BY VARIADIC" */ - if (nvargs <= list_length(agg_order)) + if (nvargs <= numAggregatedArgs) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_FUNCTION), errmsg("function %s does not exist", @@ -365,6 +380,11 @@ Node* ParseFuncOrColumn(ParseState* pstate, List* funcname, List* fargs, Node* l catDirectArgs), parser_errposition(pstate, location))); } + /* Check type matching of hypothetical arguments */ + if (aggkind == AGGKIND_HYPOTHETICAL) + unify_hypothetical_args(pstate, fargs, numAggregatedArgs, + actual_arg_types, declared_arg_types); + } else { /* Normal aggregate, so it can't have WITHIN GROUP */ if (agg_within_group) @@ -1886,6 +1906,96 @@ FuncDetailCode func_get_detail(List* funcname, List* fargs, List* fargnames, int return FUNCDETAIL_NOTFOUND; } + +/* + * unify_hypothetical_args() + * + * Ensure that each hypothetical direct argument of a hypothetical-set + * aggregate has the same type as the corresponding aggregated argument. + * Modify the expressions in the fargs list, if necessary, and update + * actual_arg_types[]. + * + * If the agg declared its args non-ANY (even ANYELEMENT), we need only a + * sanity check that the declared types match; make_fn_arguments will coerce + * the actual arguments to match the declared ones. But if the declaration + * is ANY, nothing will happen in make_fn_arguments, so we need to fix any + * mismatch here. We use the same type resolution logic as UNION etc. + */ +static void unify_hypothetical_args(ParseState *pstate, + List *fargs, + int numAggregatedArgs, + Oid *actual_arg_types, + Oid *declared_arg_types) +{ + Node *args[FUNC_MAX_ARGS]; + int numDirectArgs, numNonHypotheticalArgs; + int i; + ListCell *lc; + + numDirectArgs = list_length(fargs) - numAggregatedArgs; + numNonHypotheticalArgs = numDirectArgs - numAggregatedArgs; + /* safety check (should only trigger with a misdeclared agg) */ + if (numNonHypotheticalArgs < 0) + elog(ERROR, "incorrect number of arguments to hypothetical-set aggregate"); + + /* Deconstruct fargs into an array for ease of subscripting */ + i = 0; + foreach(lc, fargs) { + args[i++] = (Node *) lfirst(lc); + } + + /* Check each hypothetical arg and corresponding aggregated arg */ + for (i = numNonHypotheticalArgs; i < numDirectArgs; i++) { + int aargpos = numDirectArgs + (i - numNonHypotheticalArgs); + Oid commontype; + + /* A mismatch means AggregateCreate didn't check properly ... */ + if (declared_arg_types[i] != declared_arg_types[aargpos]) + elog(ERROR, "hypothetical-set aggregate has inconsistent declared argument types"); + + /* No need to unify if make_fn_arguments will coerce */ + if (declared_arg_types[i] != ANYOID) + continue; + + /* + * Select common type, giving preference to the aggregated argument's + * type (we'd rather coerce the direct argument once than coerce all + * the aggregated values). + */ + commontype = select_common_type(pstate, + list_make2(args[aargpos], args[i]), + "WITHIN GROUP", + NULL); + + /* + * Perform the coercions. We don't need to worry about NamedArgExprs + * here because they aren't supported with aggregates. + */ + args[i] = coerce_type(pstate, + args[i], + actual_arg_types[i], + commontype, -1, + COERCION_IMPLICIT, + COERCE_IMPLICIT_CAST, + -1); + actual_arg_types[i] = commontype; + args[aargpos] = coerce_type(pstate, + args[aargpos], + actual_arg_types[aargpos], + commontype, -1, + COERCION_IMPLICIT, + COERCE_IMPLICIT_CAST, + -1); + actual_arg_types[aargpos] = commontype; + } + + /* Reconstruct fargs from array */ + i = 0; + foreach(lc, fargs) { + lfirst(lc) = args[i++]; + } +} + /* * make_fn_arguments() * diff --git a/src/common/backend/utils/adt/orderedsetaggs.cpp b/src/common/backend/utils/adt/orderedsetaggs.cpp index db14c094a..f359cd9ee 100644 --- a/src/common/backend/utils/adt/orderedsetaggs.cpp +++ b/src/common/backend/utils/adt/orderedsetaggs.cpp @@ -14,17 +14,21 @@ */ #include "postgres.h" +#include "access/tableam.h" #include "knl/knl_variable.h" #include "catalog/pg_aggregate.h" +#include "catalog/pg_operator.h" #include "catalog/pg_type.h" #include "miscadmin.h" #include "nodes/nodeFuncs.h" #include "executor/node/nodeAgg.h" +#include "executor/tuptable.h" #include "utils/array.h" #include "utils/lsyscache.h" #include "utils/timestamp.h" #include "utils/tuplesort.h" +const int HYPOFUNC_ARGS_FACTOR = 2; const char* PERCENTILE_FLOAT8 = "percentile_float8"; const char* PERCENTILE_INTERVAL = "percentile_interval"; @@ -48,8 +52,10 @@ static void ordered_set_shutdown(Datum arg) /* * Initialize tuplesort state and save into OrderedSetAggState */ -static void tuplesort_state_init( - OrderedSetAggState* osastate, SortGroupClause* sort_clause, MemoryContext aggcontext, Plan* plan) +static void tuplesort_state_init(OrderedSetAggState* osastate, + SortGroupClause* sort_clause, + MemoryContext aggcontext, + Plan* plan) { Oid sort_col_type; Oid sort_operator; @@ -90,71 +96,190 @@ static void tuplesort_state_init( MemoryContextSwitchTo(oldcontext); } + /* - * Initialize ordered-set aggregate state and regarding tuplesort object + * Set up working state for an ordered-set aggregate */ -static OrderedSetAggState* ordered_set_startup(PG_FUNCTION_ARGS) +static OrderedSetAggState *ordered_set_startup(FunctionCallInfo fcinfo, bool use_tuples) { - Aggref* aggref = NULL; - Plan* plan = NULL; - List* sortlist = NIL; - MemoryContext aggcontext; - AggState* aggstate = NULL; - OrderedSetAggState* osastate = NULL; - SortGroupClause* sort_clause = NULL; + OrderedSetAggState *osastate; + Aggref *aggref; + ExprContext *peraggecontext; + MemoryContext aggcontext; + MemoryContext oldcontext; + List *sortlist; + int numSortCols; - /* Check be called in aggregate context; get the Agg node's query-lifespan context */ + /* Must be called as aggregate; get the Agg node's query-lifespan context */ if (AggCheckCallContext(fcinfo, &aggcontext) != AGG_CONTEXT_AGGREGATE) - ereport( - ERROR, (errcode(ERRCODE_INVALID_STATUS), errmsg("ordered-set aggregate called in non-aggregate context"))); - - if (fcinfo->context == NULL) - ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), errmsg("ordered_set_startup function context info is null"))); - - plan = ((AggState*)fcinfo->context)->ss.ps.plan; - /* Need the agg info to perform sort */ - if (IsA(fcinfo->context, AggState)) { - aggstate = (AggState*)fcinfo->context; - if (aggstate->ss.ps.state->es_is_flt_frame) { - AggStatePerTrans curpertrans = aggstate->curpertrans; - if (curpertrans != NULL) { - aggref = curpertrans->aggref; - } - } else { - AggStatePerAgg curperagg = aggstate->curperagg; - if (curperagg != NULL) { - aggref = curperagg->aggref; - } - } - } - - if (aggref == NULL || aggstate == NULL) - ereport( - ERROR, (errcode(ERRCODE_INVALID_STATUS), errmsg("ordered-set aggregate called in non-aggregate context"))); + ereport(ERROR, + (errcode(ERRCODE_INVALID_STATUS), + errmsg("ordered-set aggregate called in non-aggregate context"))); + /* Need the Aggref as well */ + aggref = AggGetAggref(fcinfo); + if (!aggref) + ereport(ERROR, + (errcode(ERRCODE_INVALID_STATUS), + errmsg("ordered-set aggregate called in non-aggregate context"))); if (!AGGKIND_IS_ORDERED_SET(aggref->aggkind)) ereport(ERROR, (errcode(ERRCODE_INVALID_STATUS), - errmsg("ordered-set aggregate support function called for non-ordered-set aggregate"))); - /* Initialize ordered-set agg state which be used in the whole aggregate lifespan */ - osastate = (OrderedSetAggState*)MemoryContextAllocZero(aggcontext, sizeof(OrderedSetAggState)); - osastate->aggstate = aggstate; - osastate->sign = AGGKIND_ORDERED_SET; + errmsg("ordered-set aggregate support function called for non-ordered-set aggregate"))); + /* Also get output exprcontext so we can register shutdown callback */ + peraggecontext = AggGetPerAggEContext(fcinfo); + if (!peraggecontext) + ereport(ERROR, + (errcode(ERRCODE_INVALID_STATUS), + errmsg("ordered-set aggregate called in non-aggregate context"))); + + /* Initialize working-state object in the aggregate-lifespan context */ + osastate = (OrderedSetAggState *) + MemoryContextAllocZero(aggcontext, sizeof(OrderedSetAggState)); osastate->aggref = aggref; - /* Ordered-set aggregate only support order by one column, aggref contains it info */ + /* Extract the sort information */ sortlist = aggref->aggorder; + numSortCols = list_length(sortlist); - if (list_length(sortlist) != 1) - ereport(ERROR, - (errcode(ERRCODE_INVALID_AGG), - errmsg("ordered-set aggregate support function does not support multiple aggregated columns"))); - sort_clause = (SortGroupClause*)linitial(sortlist); - tuplesort_state_init(osastate, sort_clause, aggcontext, plan); + if (use_tuples) { + bool ishypothetical = (aggref->aggkind == AGGKIND_HYPOTHETICAL); + AttrNumber *sortColIdx; + Oid *sortOperators; + Oid *sortCollations; + bool *sortNullsFirst; + ListCell *lc; + int i; - ExprContext* cxt = NULL; + if (ishypothetical) { + numSortCols++; /* make space for flag column */ + } + /* these arrays are made in short-lived context */ + sortColIdx = (AttrNumber *) palloc(numSortCols * sizeof(AttrNumber)); + sortOperators = (Oid *) palloc(numSortCols * sizeof(Oid)); + sortCollations = (Oid *) palloc(numSortCols * sizeof(Oid)); + sortNullsFirst = (bool *) palloc(numSortCols * sizeof(bool)); + + i = 0; + foreach(lc, sortlist) { + SortGroupClause *sortcl = (SortGroupClause *) lfirst(lc); + TargetEntry *tle = get_sortgroupclause_tle(sortcl, aggref->args); + + /* the parser should have made sure of this */ + Assert(OidIsValid(sortcl->sortop)); + + sortColIdx[i] = tle->resno; + sortOperators[i] = sortcl->sortop; + sortCollations[i] = exprCollation((Node *) tle->expr); + sortNullsFirst[i] = sortcl->nulls_first; + i++; + } + + if (ishypothetical) { + /* Add an integer flag column as the last sort column */ + sortColIdx[i] = list_length(aggref->args) + 1; + sortOperators[i] = INT4LTOID; + sortCollations[i] = InvalidOid; + sortNullsFirst[i] = false; + i++; + } + + Assert(i == numSortCols); + + /* Now build the stuff we need in aggregate-lifespan context */ + oldcontext = MemoryContextSwitchTo(aggcontext); + + /* + * Get a tupledesc corresponding to the aggregated inputs (including + * sort expressions) of the agg. + */ + osastate->tupdesc = ExecTypeFromTL(aggref->args, false); + + /* If we need a flag column, hack the tupledesc to include that */ + if (ishypothetical) { + TupleDesc newdesc; + int natts = osastate->tupdesc->natts; + + newdesc = CreateTemplateTupleDesc(natts + 1, false); + for (i = 1; i <= natts; i++) + TupleDescCopyEntry(newdesc, i, osastate->tupdesc, i); + + TupleDescInitEntry(newdesc, + (AttrNumber) ++natts, + "flag", + INT4OID, + -1, + 0); + + FreeTupleDesc(osastate->tupdesc); + osastate->tupdesc = newdesc; + } + + /* Initialize tuplesort object */ + osastate->sortstate = tuplesort_begin_heap(osastate->tupdesc, + numSortCols, + sortColIdx, + sortOperators, + sortCollations, + sortNullsFirst, + u_sess->attr.attr_memory.work_mem, + false); + + /* Create slot we'll use to store/retrieve rows */ + osastate->tupslot = MakeSingleTupleTableSlot(osastate->tupdesc); + } else { + /* Sort single datums */ + SortGroupClause *sortcl; + TargetEntry *tle; + Oid sortColType; + Oid sortOperator; + Oid eqOperator; + Oid sortCollation; + bool sortNullsFirst; + + if (numSortCols != 1 || aggref->aggkind == AGGKIND_HYPOTHETICAL) + ereport(ERROR, + (errcode(ERRCODE_INVALID_STATUS), + errmsg("ordered-set aggregate support function does not support multiple aggregated columns"))); + + sortcl = (SortGroupClause *) linitial(sortlist); + tle = get_sortgroupclause_tle(sortcl, aggref->args); + + /* the parser should have made sure of this */ + Assert(OidIsValid(sortcl->sortop)); + + sortColType = exprType((Node *) tle->expr); + sortOperator = sortcl->sortop; + eqOperator = sortcl->eqop; + sortCollation = exprCollation((Node *) tle->expr); + sortNullsFirst = sortcl->nulls_first; + + /* Save datatype info */ + osastate->datumtype = sortColType; + get_typlenbyvalalign(sortColType, + &osastate->typLen, + &osastate->typByVal, + &osastate->typAlign); + osastate->eq_operator = eqOperator; + + /* Now build the stuff we need in aggregate-lifespan context */ + oldcontext = MemoryContextSwitchTo(aggcontext); + + /* Initialize tuplesort object */ + osastate->sortstate = tuplesort_begin_datum(sortColType, + sortOperator, + sortCollation, + sortNullsFirst, + u_sess->attr.attr_memory.work_mem, + false); + } + + /* Now register a shutdown callback to clean it all up */ + RegisterExprContextCallback(peraggecontext, + ordered_set_shutdown, + PointerGetDatum(osastate)); + + MemoryContextSwitchTo(oldcontext); - cxt = aggstate->ss.ps.ps_ExprContext; - RegisterExprContextCallback(cxt, ordered_set_shutdown, PointerGetDatum(osastate)); return osastate; } @@ -168,9 +293,9 @@ Datum ordered_set_transition(PG_FUNCTION_ARGS) OrderedSetAggState* osastate = NULL; Datum datum; /* Create the transition state workspace */ - if (PG_ARGISNULL(0)) - osastate = ordered_set_startup(fcinfo); - else { + if (PG_ARGISNULL(0)) { + osastate = ordered_set_startup(fcinfo, false); + } else { if (AggCheckCallContext(fcinfo, NULL) != AGG_CONTEXT_AGGREGATE) ereport(ERROR, (errcode(ERRCODE_INVALID_STATUS), errmsg("ordered-set aggregate called in non-aggregate context"))); @@ -626,12 +751,12 @@ double TdValueAt(TdigestData *td, double q) /* * Inputs: param 0-3 - * param0: Store results. - * param1: scan data from dn and store param 1 in param 0 - * param2: value to calcute - * param3: comperssion + * param0: Store results. + * param1: scan data from dn and store param 1 in param 0 + * param2: value to calcute + * param3: comperssion * Outputs: param0 - * param0: Store results. + * param0: Store results. */ Datum tdigest_merge(PG_FUNCTION_ARGS) @@ -687,10 +812,10 @@ Datum tdigest_merge(PG_FUNCTION_ARGS) /* * Inputs: param 0-1 - * param0: Store results. - * param1: TdigestData from dn and merge param 1 in param 0 + * param0: Store results. + * param1: TdigestData from dn and merge param 1 in param 0 * Outputs: param 0 - * param0: Store results. + * param0: Store results. */ Datum tdigest_merge_to_one(PG_FUNCTION_ARGS) @@ -739,12 +864,12 @@ Datum calculate_quantile_of(PG_FUNCTION_ARGS) /* * Inputs: param 0-3 - * param0: Store results. - * param1: scan data from dn and store param 1 in param 0 - * param2: value to calcute - * param3: comperssion + * param0: Store results. + * param1: scan data from dn and store param 1 in param 0 + * param2: value to calcute + * param3: comperssion * Outputs: param 0 - * param0: Store results. + * param0: Store results. */ Datum tdigest_mergep(PG_FUNCTION_ARGS) @@ -815,3 +940,324 @@ Datum calculate_value_at(PG_FUNCTION_ARGS) double res = TdValueAt(newval, percentile); PG_RETURN_FLOAT8(res); } + +Datum ordered_set_transition_multi(PG_FUNCTION_ARGS) +{ + OrderedSetAggState *osastate; + TupleTableSlot *slot; + int nargs; + int i; + + /* If first call, create the transition state workspace */ + if (PG_ARGISNULL(0)) { + osastate = ordered_set_startup(fcinfo, true); + } else { + /* safety check */ + if (AggCheckCallContext(fcinfo, NULL) != AGG_CONTEXT_AGGREGATE) + ereport(ERROR, + (errcode(ERRCODE_INVALID_STATUS), errmsg("ordered-set aggregate called in non-aggregate context"))); + osastate = (OrderedSetAggState *) PG_GETARG_POINTER(0); + } + + /* Form a tuple from all the other inputs besides the transition value */ + slot = osastate->tupslot; + ExecClearTuple(slot); + nargs = PG_NARGS() - 1; + for (i = 0; i < nargs; i++) { + slot->tts_values[i] = PG_GETARG_DATUM(i + 1); + slot->tts_isnull[i] = PG_ARGISNULL(i + 1); + } + if (osastate->aggref->aggkind == AGGKIND_HYPOTHETICAL) { + /* Add a zero flag value to mark this row as a normal input row */ + slot->tts_values[i] = Int32GetDatum(0); + slot->tts_isnull[i] = false; + i++; + } + Assert(i == slot->tts_tupleDescriptor->natts); + ExecStoreVirtualTuple(slot); + + /* Load the row into the tuplesort object */ + tuplesort_puttupleslot(osastate->sortstate, slot); + osastate->number_of_rows++; + + PG_RETURN_POINTER(osastate); +} + + +/* + * Common code to sanity-check args for hypothetical-set functions. No need + * for friendly errors, these can only happen if someone's messing up the + * aggregate definitions. The checks are needed for security, however. + */ +static void hypothetical_check_argtypes(FunctionCallInfo fcinfo, int nargs, + TupleDesc tupdesc) +{ + int i; + + /* check that we have an int4 flag column */ + if (!tupdesc || + (nargs + 1) != tupdesc->natts || + TupleDescAttr(tupdesc, nargs)->atttypid != INT4OID) + ereport(ERROR, + (errcode(ERRCODE_INVALID_STATUS), errmsg("type mismatch in hypothetical-set function"))); + /* check that direct args match in type with aggregated args */ + for (i = 0; i < nargs; i++) { + Form_pg_attribute attr = TupleDescAttr(tupdesc, i); + if (get_fn_expr_argtype(fcinfo->flinfo, i + 1) != attr->atttypid) + ereport(ERROR, + (errcode(ERRCODE_INVALID_STATUS), errmsg("type mismatch in hypothetical-set function"))); + } +} + +/* + * compute rank of hypothetical row + * + * flag should be -1 to sort hypothetical row ahead of its peers, or +1 + * to sort behind. + * total number of regular rows is returned into *number_of_rows. + */ +static int64 hypothetical_rank_common(FunctionCallInfo fcinfo, int flag, + int64 *number_of_rows) +{ + int nargs = PG_NARGS() - 1; + int64 rank = 1; + OrderedSetAggState *osastate; + TupleTableSlot *slot; + int i; + + /* safety check */ + if (AggCheckCallContext(fcinfo, NULL) != AGG_CONTEXT_AGGREGATE) + ereport( + ERROR, (errcode(ERRCODE_INVALID_STATUS), errmsg("ordered-set aggregate called in non-aggregate context"))); + + /* If there were no regular rows, the rank is always 1 */ + if (PG_ARGISNULL(0)) { + *number_of_rows = 0; + return 1; + } + + osastate = (OrderedSetAggState *) PG_GETARG_POINTER(0); + *number_of_rows = osastate->number_of_rows; + + /* Adjust nargs to be the number of direct (or aggregated) args */ + if (nargs % HYPOFUNC_ARGS_FACTOR != 0) + ereport(ERROR, + (errcode(ERRCODE_INVALID_STATUS), errmsg("wrong number of arguments in hypothetical-set function"))); + nargs /= HYPOFUNC_ARGS_FACTOR; + + hypothetical_check_argtypes(fcinfo, nargs, osastate->tupdesc); + + /* insert the hypothetical row into the sort */ + slot = osastate->tupslot; + ExecClearTuple(slot); + for (i = 0; i < nargs; i++) { + slot->tts_values[i] = PG_GETARG_DATUM(i + 1); + slot->tts_isnull[i] = PG_ARGISNULL(i + 1); + } + slot->tts_values[i] = Int32GetDatum(flag); + slot->tts_isnull[i] = false; + ExecStoreVirtualTuple(slot); + + tuplesort_puttupleslot(osastate->sortstate, slot); + + /* finish the sort */ + tuplesort_performsort(osastate->sortstate); + + /* iterate till we find the hypothetical row */ + while (tuplesort_gettupleslot(osastate->sortstate, true, slot, NULL)) { + bool isnull; + Datum d = tableam_tslot_getattr(slot, nargs + 1, &isnull); + if (!isnull && DatumGetInt32(d) != 0) { + break; + } + rank++; + + CHECK_FOR_INTERRUPTS(); + } + + ExecClearTuple(slot); + + /* Might as well clean up the tuplesort object immediately */ + tuplesort_end(osastate->sortstate); + osastate->sortstate = NULL; + + return rank; +} + +/* + * cume_dist() - cumulative distribution of hypothetical row + */ +Datum hypothetical_cume_dist_final(PG_FUNCTION_ARGS) +{ + int64 rank; + int64 rowcount; + double resultval; + + rank = hypothetical_rank_common(fcinfo, 1, &rowcount); + + resultval = (double) (rank) / (double) (rowcount + 1); + + PG_RETURN_FLOAT8(resultval); +} + +/* rank() - rank of hypothetical row + */ +Datum hypothetical_rank_final(PG_FUNCTION_ARGS) +{ + int64 rank; + int64 rowcount; + + rank = hypothetical_rank_common(fcinfo, -1, &rowcount); + + PG_RETURN_INT64(rank); +} + +/* + * dense_rank() - rank of hypothetical row without gaps in ranking + */ +Datum hypothetical_dense_rank_final(PG_FUNCTION_ARGS) +{ + int nargs = PG_NARGS() - 1; + int64 rank = 1; + int64 duplicate_count = 0; + OrderedSetAggState *osastate; + List *sortlist; + int numDistinctCols; + AttrNumber *sortColIdx; + FmgrInfo *equalfns; + TupleTableSlot *slot; + TupleTableSlot *extraslot; + TupleTableSlot *slot2; + MemoryContext tmpcontext; + ListCell *lc; + int i; + + /* safety check */ + if (AggCheckCallContext(fcinfo, NULL) != AGG_CONTEXT_AGGREGATE) + ereport(ERROR, + (errcode(ERRCODE_INVALID_STATUS), errmsg("ordered-set aggregate called in non-aggregate context"))); + + /* If there were no regular rows, the rank is always 1 */ + if (PG_ARGISNULL(0)) + PG_RETURN_INT64(rank); + + osastate = (OrderedSetAggState *) PG_GETARG_POINTER(0); + + /* Adjust nargs to be the number of direct (or aggregated) args */ + if (nargs % HYPOFUNC_ARGS_FACTOR != 0) + ereport(ERROR, + (errcode(ERRCODE_INVALID_STATUS), + errmsg("wrong number of arguments in hypothetical-set function"))); + + nargs /= HYPOFUNC_ARGS_FACTOR; + hypothetical_check_argtypes(fcinfo, nargs, osastate->tupdesc); + + /* + * Construct list of columns to compare for uniqueness. We can omit the + * flag column since we will only compare rows with flag == 0. + */ + sortlist = osastate->aggref->aggorder; + numDistinctCols = list_length(sortlist); + sortColIdx = (AttrNumber *) palloc(numDistinctCols * sizeof(AttrNumber)); + equalfns = (FmgrInfo *) palloc(numDistinctCols * sizeof(FmgrInfo)); + + i = 0; + foreach(lc, sortlist) { + SortGroupClause *sortcl = (SortGroupClause *) lfirst(lc); + TargetEntry *tle = get_sortgroupclause_tle(sortcl, + osastate->aggref->args); + + sortColIdx[i] = tle->resno; + fmgr_info(get_opcode(sortcl->eqop), &equalfns[i]); + i++; + } + + /* Get short-term context we can use for execTuplesMatch */ + tmpcontext = AggGetPerTupleEContext(fcinfo)->ecxt_per_tuple_memory; + + /* insert the hypothetical row into the sort */ + slot = osastate->tupslot; + ExecClearTuple(slot); + for (i = 0; i < nargs; i++) { + slot->tts_values[i] = PG_GETARG_DATUM(i + 1); + slot->tts_isnull[i] = PG_ARGISNULL(i + 1); + } + slot->tts_values[i] = Int32GetDatum(-1); + slot->tts_isnull[i] = false; + ExecStoreVirtualTuple(slot); + + tuplesort_puttupleslot(osastate->sortstate, slot); + + /* finish the sort */ + tuplesort_performsort(osastate->sortstate); + + /* + * We alternate fetching into osastate->tupslot and extraslot so that we + * have the previous row available for comparisons. This is accomplished + * by swapping the slot pointer variables after each row. + */ + extraslot = MakeSingleTupleTableSlot(osastate->tupdesc); + slot2 = extraslot; + + /* iterate till we find the hypothetical row */ + while (tuplesort_gettupleslot(osastate->sortstate, true, slot, nullptr)) { + bool isnull; + Datum d = tableam_tslot_getattr(slot, nargs + 1, &isnull); + TupleTableSlot *tmpslot; + + if (!isnull && DatumGetInt32(d) != 0) { + break; + } + /* count non-distinct tuples */ + if (!TupIsNull(slot2) && + execTuplesMatch(slot, + slot2, + numDistinctCols, + sortColIdx, + equalfns, + tmpcontext, + nullptr)) { + duplicate_count++; + } + tmpslot = slot2; + slot2 = slot; + slot = tmpslot; + + rank++; + + CHECK_FOR_INTERRUPTS(); + } + + ExecClearTuple(slot); + ExecClearTuple(slot2); + + ExecDropSingleTupleTableSlot(extraslot); + + /* Might as well clean up the tuplesort object immediately */ + tuplesort_end(osastate->sortstate); + osastate->sortstate = NULL; + + rank = rank - duplicate_count; + + PG_RETURN_INT64(rank); +} + +/* + * percent_rank() - percentile rank of hypothetical row + */ +Datum hypothetical_percent_rank_final(PG_FUNCTION_ARGS) +{ + int64 rank; + int64 rowcount; + double resultval; + + rank = hypothetical_rank_common(fcinfo, -1, &rowcount); + + if (rowcount == 0) { + PG_RETURN_FLOAT8(0); + } + + resultval = (double) (rank - 1) / (double) (rowcount); + + PG_RETURN_FLOAT8(resultval); +} diff --git a/src/common/backend/utils/init/globals.cpp b/src/common/backend/utils/init/globals.cpp index 184ffd51e..10953e360 100644 --- a/src/common/backend/utils/init/globals.cpp +++ b/src/common/backend/utils/init/globals.cpp @@ -77,7 +77,7 @@ bool will_shutdown = false; * ********************************************/ -const uint32 GRAND_VERSION_NUM = 93021; +const uint32 GRAND_VERSION_NUM = 93022; /******************************************** * 2.VERSION NUM FOR EACH FEATURE diff --git a/src/common/backend/utils/misc/guc.cpp b/src/common/backend/utils/misc/guc.cpp index 574f758f5..7e05d6b9b 100755 --- a/src/common/backend/utils/misc/guc.cpp +++ b/src/common/backend/utils/misc/guc.cpp @@ -2144,6 +2144,17 @@ static void InitConfigureNamesBool() NULL, NULL }, + {{"enable_aggr_coerce_type", + PGC_USERSET, + NODE_ALL, + ERROR_HANDLING_OPTIONS, + gettext_noop("Enable some aggregate coerce type, otherwise error"), + NULL}, + &u_sess->attr.attr_common.enable_aggr_coerce_type, + false, + NULL, + NULL, + NULL}, #ifdef ENABLE_HTAP {{"enable_parallel_populate", PGC_USERSET, diff --git a/src/gausskernel/optimizer/commands/aggregatecmds.cpp b/src/gausskernel/optimizer/commands/aggregatecmds.cpp index 7d7e31b76..a7e508560 100644 --- a/src/gausskernel/optimizer/commands/aggregatecmds.cpp +++ b/src/gausskernel/optimizer/commands/aggregatecmds.cpp @@ -124,6 +124,8 @@ ObjectAddress DefineAggregate(List* name, List* args, bool oldstyle, List* param initval = defGetString(defel); else if (pg_strcasecmp(defel->defname, "initcond1") == 0) initval = defGetString(defel); + else if (pg_strcasecmp(defel->defname, "hypothetical") == 0) + aggKind = AGGKIND_HYPOTHETICAL; #ifdef PGXC else if (pg_strcasecmp(defel->defname, "cfunc") == 0) collectfuncName = defGetQualifiedName(defel); diff --git a/src/gausskernel/runtime/executor/nodeAgg.cpp b/src/gausskernel/runtime/executor/nodeAgg.cpp index ebcb71028..f730a08e8 100644 --- a/src/gausskernel/runtime/executor/nodeAgg.cpp +++ b/src/gausskernel/runtime/executor/nodeAgg.cpp @@ -4740,3 +4740,62 @@ static void exec_lookups_agg_flattened(AggState *aggstate, Agg *node, EState *es phase->evaltrans = ExecBuildAggTrans(aggstate, phase, dosort, dohash); } } + +/* + * AggGetAggref - allow an aggregate support function to get its Aggref + * + * If the function is being called as an aggregate support function, + * return the Aggref node for the aggregate call. Otherwise, return NULL. + * + * Note that if an aggregate is being used as a window function, this will + * return NULL. We could provide a similar function to return the relevant + * WindowFunc node in such cases, but it's not needed yet. + */ +Aggref *AggGetAggref(FunctionCallInfo fcinfo) +{ + if (fcinfo->context && IsA(fcinfo->context, AggState)) { + AggStatePerAgg curperagg = ((AggState *) fcinfo->context)->curperagg; + + if (curperagg) + return curperagg->aggref; + } + return NULL; +} + + +/* + * AggGetPerAggEContext - fetch per-output-tuple ExprContext + * + * This is useful for aggs to register shutdown callbacks, which will ensure + * that non-memory resources are freed. + * + * As above, this is currently not useful for aggs called as window functions. + */ +ExprContext *AggGetPerAggEContext(FunctionCallInfo fcinfo) +{ + if (fcinfo->context && IsA(fcinfo->context, AggState)) { + AggState *aggstate = (AggState *) fcinfo->context; + + return aggstate->ss.ps.ps_ExprContext; + } + return NULL; +} + +/* + * AggGetPerTupleEContext - fetch per-input-tuple ExprContext + * + * This is useful in agg final functions; the econtext returned is the + * same per-tuple context that the transfn was called in (which can + * safely get reset during the final function). + * + * As above, this is currently not useful for aggs called as window functions. + */ +ExprContext *AggGetPerTupleEContext(FunctionCallInfo fcinfo) +{ + if (fcinfo->context && IsA(fcinfo->context, AggState)) { + AggState *aggstate = (AggState *) fcinfo->context; + + return aggstate->tmpcontext; + } + return NULL; +} \ No newline at end of file diff --git a/src/gausskernel/storage/access/common/heaptuple.cpp b/src/gausskernel/storage/access/common/heaptuple.cpp index 7ecf8bcbe..9d0644450 100644 --- a/src/gausskernel/storage/access/common/heaptuple.cpp +++ b/src/gausskernel/storage/access/common/heaptuple.cpp @@ -3681,4 +3681,3 @@ void HeapTupleSetUid(HeapTuple tup, uint64 uid, int nattrs) HeapTupleHeaderSetDatumLength(tup->t_data, hoff + data_len); HeapTupleHeaderSetUid(tup->t_data, uid, uidLen); } - diff --git a/src/gausskernel/storage/access/common/tupdesc.cpp b/src/gausskernel/storage/access/common/tupdesc.cpp index 61d0c554e..bac1bee02 100644 --- a/src/gausskernel/storage/access/common/tupdesc.cpp +++ b/src/gausskernel/storage/access/common/tupdesc.cpp @@ -1261,3 +1261,46 @@ TupleDesc BuildDescFromLists(List *names, List *types, List *typmods, List *coll return desc; } + +/* + * TupleDescCopyEntry + * This function copies a single attribute structure from one tuple + * descriptor to another. + * + * !!! Constraints and defaults are not copied !!! + */ +void TupleDescCopyEntry(TupleDesc dst, AttrNumber dstAttno, + TupleDesc src, AttrNumber srcAttno) +{ + Form_pg_attribute dstAtt = TupleDescAttr(dst, dstAttno - 1); + Form_pg_attribute srcAtt = TupleDescAttr(src, srcAttno - 1); + + /* + * sanity checks + */ + Assert(PointerIsValid(src)); + Assert(PointerIsValid(dst)); + Assert(srcAttno >= 1); + Assert(srcAttno <= src->natts); + Assert(dstAttno >= 1); + Assert(dstAttno <= dst->natts); + + errno_t rc = EOK; + rc = memcpy_s(dstAtt, ATTRIBUTE_FIXED_PART_SIZE, srcAtt, ATTRIBUTE_FIXED_PART_SIZE); + securec_check(rc, "\0", "\0"); + + /* + * Aside from updating the attno, we'd better reset attcacheoff. + * + * XXX Actually, to be entirely safe we'd need to reset the attcacheoff of + * all following columns in dst as well. Current usage scenarios don't + * require that though, because all following columns will get initialized + * by other uses of this function or TupleDescInitEntry. So we cheat a + * bit to avoid a useless O(N^2) penalty. + */ + dstAtt->attnum = dstAttno; + dstAtt->attcacheoff = -1; + /* since we're not copying constraints or defaults, clear these */ + dstAtt->attnotnull = false; + dstAtt->atthasdef = false; +} diff --git a/src/include/access/tupdesc.h b/src/include/access/tupdesc.h index 63c9c315c..2cfbc5c9b 100644 --- a/src/include/access/tupdesc.h +++ b/src/include/access/tupdesc.h @@ -221,6 +221,9 @@ extern char GetGeneratedCol(TupleDesc tupdesc, int atti); extern TupleConstr *TupleConstrCopy(const TupleDesc tupdesc); extern TupInitDefVal *tupInitDefValCopy(TupInitDefVal *pInitDefVal, int nAttr); +extern void TupleDescCopyEntry(TupleDesc dst, AttrNumber dstAttno, + TupleDesc src, AttrNumber srcAttno); + #define RelHasAutoInc(rel) ((rel)->rd_att->constr && (rel)->rd_att->constr->cons_autoinc) #define RelAutoIncSeqOid(rel) (RelHasAutoInc(rel) ? (rel)->rd_att->constr->cons_autoinc->seqoid : InvalidOid) #define RelAutoIncAttrNum(rel) (RelHasAutoInc(rel) ? (rel)->rd_att->constr->cons_autoinc->attnum : 0) diff --git a/src/include/catalog/pg_aggregate.h b/src/include/catalog/pg_aggregate.h index bb12c2c93..2d739de3f 100644 --- a/src/include/catalog/pg_aggregate.h +++ b/src/include/catalog/pg_aggregate.h @@ -103,7 +103,8 @@ typedef FormData_pg_aggregate *Form_pg_aggregate; #define AGGKIND_NORMAL 'n' #define AGGKIND_DEFAULT 'n' #define AGGKIND_ORDERED_SET 'o' -#define AGGKIND_IS_ORDERED_SET(kind) ((kind) == AGGKIND_ORDERED_SET) +#define AGGKIND_HYPOTHETICAL 'h' +#define AGGKIND_IS_ORDERED_SET(kind) ((kind) != AGGKIND_NORMAL) #define AGGNUMDIRECTARGS_DEFAULT 0 /* ---------------- * initial contents of pg_aggregate @@ -476,6 +477,11 @@ DATA(insert ( 4452 ordered_set_transition - percentile_cont_float8_final DATA(insert ( 4454 ordered_set_transition - percentile_cont_interval_final 0 2281 _null_ _null_ o 1)); DATA(insert (4461 ordered_set_transition - mode_final 0 2281 _null_ _null_ o 0)); +DATA(insert ( 3148 ordered_set_transition_multi - cume_dist_final 0 2281 _null_ _null_ h 1)); +DATA(insert ( 3248 ordered_set_transition_multi - rank_final 0 2281 _null_ _null_ h 1)); +DATA(insert ( 4082 ordered_set_transition_multi - dense_rank_final 0 2281 _null_ _null_ h 1)); +DATA(insert ( 4083 ordered_set_transition_multi - percent_rank_final 0 2281 _null_ _null_ h 1)); + DATA(insert (5555 median_transfn - median_float8_finalfn 0 2281 _null_ _null_ n 0)); DATA(insert (5556 median_transfn - median_interval_finalfn 0 2281 _null_ _null_ n 0)); diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index 2c627ceef..621301a71 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -440,6 +440,8 @@ typedef FormData_pg_proc *Form_pg_proc; #define UNDEFINEDOUTPUT 5707 #define UNDEFINEDSEND 5709 #define UNDEFINEDRECV 5710 +#define RANKFUNCHYPOOID 3248 +#define RANKFUNCHYPFINALOOID 3249 /* * Symbolic values for prokind column, use highest bit to identify whether this procedure belongs to an object type. diff --git a/src/include/catalog/pg_proc.h_for_llt b/src/include/catalog/pg_proc.h_for_llt index 9b4acc40f..e2a362e47 100755 --- a/src/include/catalog/pg_proc.h_for_llt +++ b/src/include/catalog/pg_proc.h_for_llt @@ -2718,6 +2718,9 @@ DATA(insert OID = 4098 ( group_concat_finalfn PGNSP PGUID 12 1 0 0 0 f f f f f DESCR("aggregate final function"); DATA(insert OID = 4099 ( group_concat_transfn PGNSP PGUID 12 1 0 2276 0 f f f f f f i 3 0 2281 "2281 25 2276" "{2281,25,2276}" "{i,i,v}" _null_ _null_ group_concat_transfn _null_ _null_ _null_ "" f)); DESCR("aggregate transition function"); +DATA(insert OID = 4099 ( group_concat_transfn PGNSP PGUID 12 1 0 2276 0 f f f f f f i 3 0 2281 "2281 25 2276" "{2281,25,2276}" "{i,i,v}" _null_ _null_ group_concat_transfn _null_ _null_ _null_ "" f)); +DESCR("aggregate transition function"); + /* To ASCII conversion */ @@ -5106,13 +5109,29 @@ DESCR("row number within partition"); DATA(insert OID = 3101 ( rank PGNSP PGUID 12 1 0 0 0 f t f f f f i 0 0 20 "" _null_ _null_ _null_ _null_ window_rank _null_ _null_ _null_ "" f)); DESCR("integer rank with gaps"); #define RANKFUNCOID 3101 +DATA(insert OID = 3248 ( rank PGNSP PGUID 12 1 0 2276 0 t f f f f f i 1 0 20 "2276" "{2276}" "{v}" _null_ _null_ aggregate_dummy _null_ _null_ _null_ "" f)); +DESCR("rank of hypothetical row"); +DATA(insert OID = 3249 ( rank_final PGNSP PGUID 12 1 0 2276 0 f f f f f f i 2 0 20 "2281 2276" "{2281,2276}" "{i,v}" _null_ _null_ hypothetical_rank_final _null_ _null_ _null_ "" f)); +DESCR("aggregate final function"); DATA(insert OID = 3102 ( dense_rank PGNSP PGUID 12 1 0 0 0 f t f f f f i 0 0 20 "" _null_ _null_ _null_ _null_ window_dense_rank _null_ _null_ _null_ "" f)); DESCR("integer rank without gaps"); #define DENSERANKFUNCOID 3102 +DATA(insert OID = 4082 ( dense_rank PGNSP PGUID 12 1 0 2276 0 t f f f f f i 1 0 20 "2276" "{2276}" "{v}" _null_ _null_ aggregate_dummy _null_ _null_ _null_ "" f)); +DESCR("rank of hypothetical row without gaps"); +DATA(insert OID = 4084 ( dense_rank_final PGNSP PGUID 12 1 0 2276 0 f f f f f f i 2 0 20 "2281 2276" "{2281,2276}" "{i,v}" _null_ _null_ hypothetical_dense_rank_final _null_ _null_ _null_ "" f)); +DESCR("aggregate final function"); DATA(insert OID = 3103 ( percent_rank PGNSP PGUID 12 1 0 0 0 f t f f f f i 0 0 701 "" _null_ _null_ _null_ _null_ window_percent_rank _null_ _null_ _null_ "" f)); DESCR("fractional rank within partition"); +DATA(insert OID = 4083 ( percent_rank PGNSP PGUID 12 1 0 0 0 t f f f f f i 1 0 701 "2276" "{2276}" "{v}" _null_ _null_ aggregate_dummy _null_ _null_ _null_ "" f)); +DESCR("fractional rank of hypothetical row"); +DATA(insert OID = 4083 ( percent_rank_final PGNSP PGUID 12 1 0 0 0 f f f f f f i 2 0 701 "2281 2276" "{2281,2276}" "{i,v}" _null_ _null_ hypothetical_percent_rank_final _null_ _null_ _null_ "" f)); +DESCR("aggregate final function"); DATA(insert OID = 3104 ( cume_dist PGNSP PGUID 12 1 0 0 0 f t f f f f i 0 0 701 "" _null_ _null_ _null_ _null_ window_cume_dist _null_ _null_ _null_ "" f)); DESCR("fractional row number within partition"); +DATA(insert OID = 3148 ( cume_dist PGNSP PGUID 12 1 0 2276 0 f f f f f f i 1 0 701 "2276" "{2276}" "{v}" _null_ _null_ aggregate_dummy _null_ _null_ _null_ "" f)); +DESCR("cumulative distribution of hypothetical row"); +DATA(insert OID = 3148 ( cume_dist_final PGNSP PGUID 12 1 0 2276 0 t f f f f f i 2 0 701 "2281 2276" "{2281,2276}" "{i,v}" _null_ _null_ hypothetical_cume_dist_final _null_ _null_ _null_ "" f)); +DESCR("aggregate final function"); DATA(insert OID = 3105 ( ntile PGNSP PGUID 12 1 0 0 0 f t f f t f i 1 0 23 "23" _null_ _null_ _null_ _null_ window_ntile _null_ _null_ _null_ "" f)); DESCR("split rows into N groups"); DATA(insert OID = 3106 ( lag PGNSP PGUID 12 1 0 0 0 f t f f t f i 1 0 2283 "2283" _null_ _null_ _null_ _null_ window_lag _null_ _null_ _null_ "" f)); diff --git a/src/include/catalog/upgrade_sql/rollback_catalog_maindb/rollback-post_catalog_maindb_93_022.sql b/src/include/catalog/upgrade_sql/rollback_catalog_maindb/rollback-post_catalog_maindb_93_022.sql new file mode 100644 index 000000000..59e72abe7 --- /dev/null +++ b/src/include/catalog/upgrade_sql/rollback_catalog_maindb/rollback-post_catalog_maindb_93_022.sql @@ -0,0 +1,9 @@ +DROP FUNCTION IF EXISTS pg_catalog.cume_dist_final(internal, VARIADIC "any") CASCADE; +DROP FUNCTION IF EXISTS pg_catalog.rank_final(internal, VARIADIC "any") CASCADE; +DROP FUNCTION IF EXISTS pg_catalog.dense_rank_final(internal, VARIADIC "any") CASCADE; +DROP FUNCTION IF EXISTS pg_catalog.percent_rank_final(internal, VARIADIC "any") CASCADE; +DROP FUNCTION IF EXISTS pg_catalog.ordered_set_transition_multi(internal, VARIADIC "any") CASCADE; +DROP AGGREGATE IF EXISTS pg_catalog.cume_dist("any"); +DROP AGGREGATE IF EXISTS pg_catalog.rank("any"); +DROP AGGREGATE IF EXISTS pg_catalog.dense_rank("any"); +DROP AGGREGATE IF EXISTS pg_catalog.percent_rank("any"); diff --git a/src/include/catalog/upgrade_sql/rollback_catalog_otherdb/rollback-post_catalog_otherdb_93_022.sql b/src/include/catalog/upgrade_sql/rollback_catalog_otherdb/rollback-post_catalog_otherdb_93_022.sql new file mode 100644 index 000000000..59e72abe7 --- /dev/null +++ b/src/include/catalog/upgrade_sql/rollback_catalog_otherdb/rollback-post_catalog_otherdb_93_022.sql @@ -0,0 +1,9 @@ +DROP FUNCTION IF EXISTS pg_catalog.cume_dist_final(internal, VARIADIC "any") CASCADE; +DROP FUNCTION IF EXISTS pg_catalog.rank_final(internal, VARIADIC "any") CASCADE; +DROP FUNCTION IF EXISTS pg_catalog.dense_rank_final(internal, VARIADIC "any") CASCADE; +DROP FUNCTION IF EXISTS pg_catalog.percent_rank_final(internal, VARIADIC "any") CASCADE; +DROP FUNCTION IF EXISTS pg_catalog.ordered_set_transition_multi(internal, VARIADIC "any") CASCADE; +DROP AGGREGATE IF EXISTS pg_catalog.cume_dist("any"); +DROP AGGREGATE IF EXISTS pg_catalog.rank("any"); +DROP AGGREGATE IF EXISTS pg_catalog.dense_rank("any"); +DROP AGGREGATE IF EXISTS pg_catalog.percent_rank("any"); diff --git a/src/include/catalog/upgrade_sql/upgrade_catalog_maindb/upgrade-post_catalog_maindb_93_022.sql b/src/include/catalog/upgrade_sql/upgrade_catalog_maindb/upgrade-post_catalog_maindb_93_022.sql new file mode 100644 index 000000000..624aa5ba8 --- /dev/null +++ b/src/include/catalog/upgrade_sql/upgrade_catalog_maindb/upgrade-post_catalog_maindb_93_022.sql @@ -0,0 +1,49 @@ +DROP FUNCTION IF EXISTS pg_catalog.cume_dist_final(internal, VARIADIC "any") CASCADE; +SET LOCAL inplace_upgrade_next_system_object_oids = IUO_PROC, 4465; +CREATE FUNCTION pg_catalog.cume_dist_final( +internal, VARIADIC "any" +) RETURNS float8 LANGUAGE INTERNAL IMMUTABLE as 'hypothetical_cume_dist_final'; + +DROP FUNCTION IF EXISTS pg_catalog.rank_final(internal, VARIADIC "any") CASCADE; +SET LOCAL inplace_upgrade_next_system_object_oids = IUO_PROC, 3249; +CREATE FUNCTION pg_catalog.rank_final( +internal, VARIADIC "any" +) RETURNS int8 LANGUAGE INTERNAL IMMUTABLE as 'hypothetical_rank_final'; + +DROP FUNCTION IF EXISTS pg_catalog.dense_rank_final(internal, VARIADIC "any") CASCADE; +SET LOCAL inplace_upgrade_next_system_object_oids = IUO_PROC, 4084; +CREATE FUNCTION pg_catalog.dense_rank_final( +internal, VARIADIC "any" +) RETURNS int8 LANGUAGE INTERNAL IMMUTABLE as 'hypothetical_dense_rank_final'; + +DROP FUNCTION IF EXISTS pg_catalog.percent_rank_final(internal, VARIADIC "any") CASCADE; +SET LOCAL inplace_upgrade_next_system_object_oids = IUO_PROC, 4085; +CREATE FUNCTION pg_catalog.percent_rank_final( +internal, VARIADIC "any" +) RETURNS int8 LANGUAGE INTERNAL IMMUTABLE as 'hypothetical_percent_rank_final'; + +DROP FUNCTION IF EXISTS pg_catalog.ordered_set_transition_multi(internal, VARIADIC "any") CASCADE; +SET LOCAL inplace_upgrade_next_system_object_oids = IUO_PROC, 4464; +CREATE FUNCTION pg_catalog.ordered_set_transition_multi( +internal, VARIADIC "any" +) RETURNS internal LANGUAGE INTERNAL IMMUTABLE as 'ordered_set_transition_multi'; + +DROP AGGREGATE IF EXISTS pg_catalog.cume_dist("any"); +SET LOCAL inplace_upgrade_next_system_object_oids=IUO_PROC, 3148; +CREATE AGGREGATE pg_catalog.cume_dist("any") (SFUNC=ordered_set_transition_multi, STYPE= internal, finalfunc = cume_dist_final, hypothetical); +UPDATE pg_catalog.pg_proc SET provariadic = 2276, proallargtypes=ARRAY[2276], proargmodes=ARRAY['v'] WHERE oid=3148; + +DROP AGGREGATE IF EXISTS pg_catalog.rank("any"); +SET LOCAL inplace_upgrade_next_system_object_oids=IUO_PROC, 3248; +CREATE AGGREGATE pg_catalog.rank("any") (SFUNC=ordered_set_transition_multi, STYPE= internal, finalfunc = rank_final, hypothetical); +UPDATE pg_catalog.pg_proc SET provariadic = 2276, proallargtypes=ARRAY[2276], proargmodes=ARRAY['v'] WHERE oid=3248; + +DROP AGGREGATE IF EXISTS pg_catalog.dense_rank("any"); +SET LOCAL inplace_upgrade_next_system_object_oids=IUO_PROC, 4082; +CREATE AGGREGATE pg_catalog.dense_rank("any") (SFUNC=ordered_set_transition_multi, STYPE= internal, finalfunc = dense_rank_final, hypothetical); +UPDATE pg_catalog.pg_proc SET provariadic = 2276, proallargtypes=ARRAY[2276], proargmodes=ARRAY['v'] WHERE oid=4082; + +DROP AGGREGATE IF EXISTS pg_catalog.percent_rank("any"); +SET LOCAL inplace_upgrade_next_system_object_oids=IUO_PROC, 4083; +CREATE AGGREGATE pg_catalog.percent_rank("any") (SFUNC=ordered_set_transition_multi, STYPE= internal, finalfunc = percent_rank_final, hypothetical); +UPDATE pg_catalog.pg_proc SET provariadic = 2276, proallargtypes=ARRAY[2276], proargmodes=ARRAY['v'] WHERE oid=4083; diff --git a/src/include/catalog/upgrade_sql/upgrade_catalog_otherdb/upgrade-post_catalog_otherdb_93_022.sql b/src/include/catalog/upgrade_sql/upgrade_catalog_otherdb/upgrade-post_catalog_otherdb_93_022.sql new file mode 100644 index 000000000..624aa5ba8 --- /dev/null +++ b/src/include/catalog/upgrade_sql/upgrade_catalog_otherdb/upgrade-post_catalog_otherdb_93_022.sql @@ -0,0 +1,49 @@ +DROP FUNCTION IF EXISTS pg_catalog.cume_dist_final(internal, VARIADIC "any") CASCADE; +SET LOCAL inplace_upgrade_next_system_object_oids = IUO_PROC, 4465; +CREATE FUNCTION pg_catalog.cume_dist_final( +internal, VARIADIC "any" +) RETURNS float8 LANGUAGE INTERNAL IMMUTABLE as 'hypothetical_cume_dist_final'; + +DROP FUNCTION IF EXISTS pg_catalog.rank_final(internal, VARIADIC "any") CASCADE; +SET LOCAL inplace_upgrade_next_system_object_oids = IUO_PROC, 3249; +CREATE FUNCTION pg_catalog.rank_final( +internal, VARIADIC "any" +) RETURNS int8 LANGUAGE INTERNAL IMMUTABLE as 'hypothetical_rank_final'; + +DROP FUNCTION IF EXISTS pg_catalog.dense_rank_final(internal, VARIADIC "any") CASCADE; +SET LOCAL inplace_upgrade_next_system_object_oids = IUO_PROC, 4084; +CREATE FUNCTION pg_catalog.dense_rank_final( +internal, VARIADIC "any" +) RETURNS int8 LANGUAGE INTERNAL IMMUTABLE as 'hypothetical_dense_rank_final'; + +DROP FUNCTION IF EXISTS pg_catalog.percent_rank_final(internal, VARIADIC "any") CASCADE; +SET LOCAL inplace_upgrade_next_system_object_oids = IUO_PROC, 4085; +CREATE FUNCTION pg_catalog.percent_rank_final( +internal, VARIADIC "any" +) RETURNS int8 LANGUAGE INTERNAL IMMUTABLE as 'hypothetical_percent_rank_final'; + +DROP FUNCTION IF EXISTS pg_catalog.ordered_set_transition_multi(internal, VARIADIC "any") CASCADE; +SET LOCAL inplace_upgrade_next_system_object_oids = IUO_PROC, 4464; +CREATE FUNCTION pg_catalog.ordered_set_transition_multi( +internal, VARIADIC "any" +) RETURNS internal LANGUAGE INTERNAL IMMUTABLE as 'ordered_set_transition_multi'; + +DROP AGGREGATE IF EXISTS pg_catalog.cume_dist("any"); +SET LOCAL inplace_upgrade_next_system_object_oids=IUO_PROC, 3148; +CREATE AGGREGATE pg_catalog.cume_dist("any") (SFUNC=ordered_set_transition_multi, STYPE= internal, finalfunc = cume_dist_final, hypothetical); +UPDATE pg_catalog.pg_proc SET provariadic = 2276, proallargtypes=ARRAY[2276], proargmodes=ARRAY['v'] WHERE oid=3148; + +DROP AGGREGATE IF EXISTS pg_catalog.rank("any"); +SET LOCAL inplace_upgrade_next_system_object_oids=IUO_PROC, 3248; +CREATE AGGREGATE pg_catalog.rank("any") (SFUNC=ordered_set_transition_multi, STYPE= internal, finalfunc = rank_final, hypothetical); +UPDATE pg_catalog.pg_proc SET provariadic = 2276, proallargtypes=ARRAY[2276], proargmodes=ARRAY['v'] WHERE oid=3248; + +DROP AGGREGATE IF EXISTS pg_catalog.dense_rank("any"); +SET LOCAL inplace_upgrade_next_system_object_oids=IUO_PROC, 4082; +CREATE AGGREGATE pg_catalog.dense_rank("any") (SFUNC=ordered_set_transition_multi, STYPE= internal, finalfunc = dense_rank_final, hypothetical); +UPDATE pg_catalog.pg_proc SET provariadic = 2276, proallargtypes=ARRAY[2276], proargmodes=ARRAY['v'] WHERE oid=4082; + +DROP AGGREGATE IF EXISTS pg_catalog.percent_rank("any"); +SET LOCAL inplace_upgrade_next_system_object_oids=IUO_PROC, 4083; +CREATE AGGREGATE pg_catalog.percent_rank("any") (SFUNC=ordered_set_transition_multi, STYPE= internal, finalfunc = percent_rank_final, hypothetical); +UPDATE pg_catalog.pg_proc SET provariadic = 2276, proallargtypes=ARRAY[2276], proargmodes=ARRAY['v'] WHERE oid=4083; diff --git a/src/include/executor/tuptable.h b/src/include/executor/tuptable.h index fbb076f74..3f636c11f 100644 --- a/src/include/executor/tuptable.h +++ b/src/include/executor/tuptable.h @@ -248,6 +248,7 @@ extern void heap_slot_getsomeattrs(TupleTableSlot* slot, int attnum); extern bool heap_slot_attisnull(TupleTableSlot* slot, int attnum); extern void heap_slot_formbatch(TupleTableSlot* slot, struct VectorBatch* batch, int cur_rows, int attnum); + #ifdef USE_SPQ extern Datum slot_getattr(TupleTableSlot *slot, int attnum, bool *isnull); extern void slot_getsomeattrs(TupleTableSlot *slot, int attnum); diff --git a/src/include/fmgr.h b/src/include/fmgr.h index 127b5d36d..eededd208 100644 --- a/src/include/fmgr.h +++ b/src/include/fmgr.h @@ -623,6 +623,11 @@ extern void** find_rendezvous_variable(const char* varName); extern int AggCheckCallContext(FunctionCallInfo fcinfo, MemoryContext* aggcontext); +typedef struct Aggref *fmAggrefPtr; +typedef struct ExprContext *fmExprContextPtr; +extern fmAggrefPtr AggGetAggref(FunctionCallInfo fcinfo); +extern fmExprContextPtr AggGetPerTupleEContext(FunctionCallInfo fcinfo); +extern fmExprContextPtr AggGetPerAggEContext(FunctionCallInfo fcinfo); /* * We allow plugin modules to hook function entry/exit. This is intended * as support for loadable security policy modules, which may want to diff --git a/src/include/knl/knl_guc/knl_session_attr_common.h b/src/include/knl/knl_guc/knl_session_attr_common.h index 98d34a37f..7ea52b11c 100644 --- a/src/include/knl/knl_guc/knl_session_attr_common.h +++ b/src/include/knl/knl_guc/knl_session_attr_common.h @@ -256,6 +256,7 @@ typedef struct knl_session_attr_common { #ifdef ENABLE_HTAP bool enable_parallel_populate; #endif + bool enable_aggr_coerce_type; } knl_session_attr_common; #endif /* SRC_INCLUDE_KNL_KNL_SESSION_ATTR_COMMON_H_ */ diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index 67feec616..6e375f677 100755 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -2702,6 +2702,7 @@ typedef struct OrderedSetAggState { Tuplesortstate* sortstate; /* Used for accumulate sort datum */ int64 number_of_rows; /* Number of normal datum inside sortstate */ TupleDesc tupdesc; /* Tuple descriptor for datum inside sortstate */ + TupleTableSlot *tupslot; /* Tuple slot we can use for inserting/extracting tuples: */ Oid datumtype; /* Datatype of datums being sorted */ int16 typLen; diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index 13e1f9072..4807e94b8 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -1774,7 +1774,11 @@ extern Datum tdigest_mergep(PG_FUNCTION_ARGS); extern Datum calculate_value_at(PG_FUNCTION_ARGS); extern Datum tdigest_out(PG_FUNCTION_ARGS); extern Datum tdigest_in(PG_FUNCTION_ARGS); - +extern Datum ordered_set_transition_multi(PG_FUNCTION_ARGS); +extern Datum hypothetical_cume_dist_final(PG_FUNCTION_ARGS); +extern Datum hypothetical_rank_final(PG_FUNCTION_ARGS); +extern Datum hypothetical_dense_rank_final(PG_FUNCTION_ARGS); +extern Datum hypothetical_percent_rank_final(PG_FUNCTION_ARGS); /* AI */ extern Datum db4ai_predict_by(PG_FUNCTION_ARGS); extern Datum db4ai_explain_model(PG_FUNCTION_ARGS); diff --git a/src/test/regress/expected/aggregates_hypothetical.out b/src/test/regress/expected/aggregates_hypothetical.out new file mode 100644 index 000000000..9e4c06ed2 --- /dev/null +++ b/src/test/regress/expected/aggregates_hypothetical.out @@ -0,0 +1,154 @@ +create schema aggregate; +set current_schema='aggregate'; +create table test_aggregate(c1 int, c2 NUMBER(8,2), c3 varchar(20), c4 timestamp); +insert into test_aggregate values(1,0.1,'1','2024-09-01 09:22:00'), +(2,0.2,'2','2024-09-02 09:22:00'), +(3,0.1,'3','2024-09-03 09:22:00'), +(3,0.2,'3','2024-09-04 09:22:00'), +(3,0.3,'3','2024-09-05 09:22:00'), +(3,0.3,'3','2024-09-05 09:22:00'), +(4,0.2,'4','2024-09-06 09:22:00'), +(5,0.2,'5','2024-09-07 09:22:00'), +(6,0.2,'6','2024-09-08 09:22:00'), +(7,0.2,'7','2024-09-09 09:22:00'), +(8,0.2,'8','2024-09-10 09:22:00'), +(9,0.2,'9','2024-09-11 09:22:00'), +(10,0.2,'10','2024-09-12 09:22:00'); +--cume_dist +select cume_dist(3,0.2) within group (order by c1,c2) from test_aggregate; + cume_dist +------------------ + .357142857142857 +(1 row) + +--percent_rank +select percent_rank(3,0.2) within group (order by c1,c2) from test_aggregate; + percent_rank +------------------ + .230769230769231 +(1 row) + +--dense_rank +select dense_rank(4,0.2) within group (order by c1,c2) from test_aggregate; + dense_rank +------------ + 6 +(1 row) + +--rank +select rank(4,0.2) within group (order by c1,c2) from test_aggregate; + rank +------ + 7 +(1 row) + +-- divide by zero check +select percent_rank(0) within group (order by x) from generate_series(1,0) x; + percent_rank +-------------- + 0 +(1 row) + +--error, The number of parameters does not match +select cume_dist(3,0.2) within group (order by c1) from test_aggregate; +ERROR: function cume_dist(integer, numeric, integer) does not exist +LINE 1: select cume_dist(3,0.2) within group (order by c1) from test... + ^ +HINT: To use the hypothetical-set aggregate cume_dist, the number of hypothetical direct arguments (here 2) must match the number of ordering columns (here 1). +CONTEXT: referenced column: cume_dist +select cume_dist(3) within group (order by c1,c2) from test_aggregate; +ERROR: function cume_dist(integer, integer, numeric) does not exist +LINE 1: select cume_dist(3) within group (order by c1,c2) from test_... + ^ +HINT: To use the hypothetical-set aggregate cume_dist, the number of hypothetical direct arguments (here 1) must match the number of ordering columns (here 2). +CONTEXT: referenced column: cume_dist +-- error, ordered-set aggs can't use ungrouped vars in direct args: +select rank(x) within group (order by x) from generate_series(1,5) x; +ERROR: column "x.x" must appear in the GROUP BY clause or be used in an aggregate function +LINE 1: select rank(x) within group (order by x) from generate_serie... + ^ +DETAIL: Direct arguments of an ordered-set aggregate must use only grouped columns. +-- enable_aggr_coerce_type = off, type conversion test +--error +select cume_dist(3) within group (order by c3) from test_aggregate; +ERROR: WITHIN GROUP types character varying and integer cannot be matched +LINE 1: select cume_dist(3) within group (order by c3) from test_agg... + ^ +CONTEXT: referenced column: cume_dist +--error +select cume_dist('a') within group (order by c1) from test_aggregate; +ERROR: invalid input syntax for integer: "a" +LINE 1: select cume_dist('a') within group (order by c1) from test_a... + ^ +CONTEXT: referenced column: cume_dist +--error +select cume_dist('2024') within group (order by c4) from test_aggregate; +ERROR: invalid input syntax for type timestamp: "2024" +LINE 1: select cume_dist('2024') within group (order by c4) from tes... + ^ +CONTEXT: referenced column: cume_dist +--success +select cume_dist('2024-12-12') within group (order by c4) from test_aggregate; + cume_dist +----------- + 1 +(1 row) + +--success +select cume_dist('1') within group (order by c1) from test_aggregate; + cume_dist +------------------ + .142857142857143 +(1 row) + +--error boolean +select rank(1) within group (order by x) from (values (true),(false)) v(x); +ERROR: WITHIN GROUP types boolean and integer cannot be matched +LINE 1: select rank(1) within group (order by x) from (values (true)... + ^ +CONTEXT: referenced column: rank +-- enable_aggr_coerce_type = on, type conversion test +set enable_aggr_coerce_type = on; +--success +select cume_dist(3) within group (order by c3) from test_aggregate; + cume_dist +------------------ + .571428571428571 +(1 row) + +--error +select cume_dist('a') within group (order by c1) from test_aggregate; +ERROR: invalid input syntax for integer: "a" +LINE 1: select cume_dist('a') within group (order by c1) from test_a... + ^ +CONTEXT: referenced column: cume_dist +--error +select cume_dist('2024') within group (order by c4) from test_aggregate; +ERROR: invalid input syntax for type timestamp: "2024" +LINE 1: select cume_dist('2024') within group (order by c4) from tes... + ^ +CONTEXT: referenced column: cume_dist +--success +select cume_dist('2024-12-12') within group (order by c4) from test_aggregate; + cume_dist +----------- + 1 +(1 row) + +--success +select cume_dist('1') within group (order by c1) from test_aggregate; + cume_dist +------------------ + .142857142857143 +(1 row) + +--sucdess boolean +select rank(1) within group (order by x) from (values (true),(false)) v(x); + rank +------ + 2 +(1 row) + +set enable_aggr_coerce_type = off; +drop table test_aggregate; +drop schema aggregate CASCADE; diff --git a/src/test/regress/output/pg_proc_test.source b/src/test/regress/output/pg_proc_test.source index 1eda0cdf8..ae5d1cbbb 100644 --- a/src/test/regress/output/pg_proc_test.source +++ b/src/test/regress/output/pg_proc_test.source @@ -5,19 +5,28 @@ select provariadic,oid, proname from pg_proc where arraycontains(proargmodes::ch 2276 | 3058 | concat 2276 | 3059 | concat_ws 1185 | 3119 | standby_statement_history + 2276 | 3148 | cume_dist 2276 | 3239 | json_build_array + 2276 | 3248 | rank + 2276 | 3249 | rank_final 2276 | 3261 | json_build_object 25 | 3262 | json_extract_path 25 | 3264 | json_extract_path_text 25 | 3425 | jsonb_extract_path 25 | 3426 | jsonb_extract_path_text 2276 | 3539 | format + 2276 | 4082 | dense_rank + 2276 | 4083 | percent_rank + 2276 | 4084 | dense_rank_final + 2276 | 4085 | percent_rank_final 2276 | 4097 | group_concat 2276 | 4099 | group_concat_transfn 25 | 4216 | pg_logical_slot_get_changes 25 | 4217 | pg_logical_slot_get_binary_changes 25 | 4218 | pg_logical_slot_peek_changes 25 | 4219 | pg_logical_slot_peek_binary_changes + 0 | 4464 | ordered_set_transition_multi + 2276 | 4465 | cume_dist_final 25 | 4978 | pg_logical_get_area_changes 2276 | 7101 | db4ai_predict_by_bool 2276 | 7102 | db4ai_predict_by_int32 @@ -27,7 +36,7 @@ select provariadic,oid, proname from pg_proc where arraycontains(proargmodes::ch 2276 | 7107 | db4ai_predict_by_numeric 2276 | 7108 | db4ai_predict_by_text 2276 | 7109 | db4ai_predict_by_float8_array -(26 rows) +(35 rows) select prokind,length(prokind),count(*) from pg_proc where oid < 16384 group by prokind; prokind | length | count diff --git a/src/test/regress/parallel_schedule0 b/src/test/regress/parallel_schedule0 index 34b6393c2..dac405274 100644 --- a/src/test/regress/parallel_schedule0 +++ b/src/test/regress/parallel_schedule0 @@ -716,6 +716,7 @@ test: a_outerjoin_conversion test: setrefs test: agg window_agg_stream_test +test: aggregates_hypothetical # test sql by pass test: bypass_simplequery_support diff --git a/src/test/regress/parallel_schedule0B b/src/test/regress/parallel_schedule0B index 3957ed56b..d3203fcfb 100644 --- a/src/test/regress/parallel_schedule0B +++ b/src/test/regress/parallel_schedule0B @@ -232,6 +232,7 @@ test: a_outerjoin_conversion test: setrefs test: agg window_agg_stream_test +test: aggregates_hypothetical # test sql by pass test: bypass_simplequery_support diff --git a/src/test/regress/sql/aggregates_hypothetical.sql b/src/test/regress/sql/aggregates_hypothetical.sql new file mode 100644 index 000000000..4d58ab9fd --- /dev/null +++ b/src/test/regress/sql/aggregates_hypothetical.sql @@ -0,0 +1,87 @@ +create schema aggregate; +set current_schema='aggregate'; + +create table test_aggregate(c1 int, c2 NUMBER(8,2), c3 varchar(20), c4 timestamp); + +insert into test_aggregate values(1,0.1,'1','2024-09-01 09:22:00'), +(2,0.2,'2','2024-09-02 09:22:00'), +(3,0.1,'3','2024-09-03 09:22:00'), +(3,0.2,'3','2024-09-04 09:22:00'), +(3,0.3,'3','2024-09-05 09:22:00'), +(3,0.3,'3','2024-09-05 09:22:00'), +(4,0.2,'4','2024-09-06 09:22:00'), +(5,0.2,'5','2024-09-07 09:22:00'), +(6,0.2,'6','2024-09-08 09:22:00'), +(7,0.2,'7','2024-09-09 09:22:00'), +(8,0.2,'8','2024-09-10 09:22:00'), +(9,0.2,'9','2024-09-11 09:22:00'), +(10,0.2,'10','2024-09-12 09:22:00'); + +--cume_dist +select cume_dist(3,0.2) within group (order by c1,c2) from test_aggregate; + +--percent_rank +select percent_rank(3,0.2) within group (order by c1,c2) from test_aggregate; + +--dense_rank +select dense_rank(4,0.2) within group (order by c1,c2) from test_aggregate; + +--rank +select rank(4,0.2) within group (order by c1,c2) from test_aggregate; + +-- divide by zero check +select percent_rank(0) within group (order by x) from generate_series(1,0) x; + +--error, The number of parameters does not match +select cume_dist(3,0.2) within group (order by c1) from test_aggregate; +select cume_dist(3) within group (order by c1,c2) from test_aggregate; + +-- error, ordered-set aggs can't use ungrouped vars in direct args: +select rank(x) within group (order by x) from generate_series(1,5) x; + + +-- enable_aggr_coerce_type = off, type conversion test + +--error +select cume_dist(3) within group (order by c3) from test_aggregate; + +--error +select cume_dist('a') within group (order by c1) from test_aggregate; + +--error +select cume_dist('2024') within group (order by c4) from test_aggregate; + +--success +select cume_dist('2024-12-12') within group (order by c4) from test_aggregate; + +--success +select cume_dist('1') within group (order by c1) from test_aggregate; + +--error boolean +select rank(1) within group (order by x) from (values (true),(false)) v(x); + +-- enable_aggr_coerce_type = on, type conversion test + +set enable_aggr_coerce_type = on; +--success +select cume_dist(3) within group (order by c3) from test_aggregate; + +--error +select cume_dist('a') within group (order by c1) from test_aggregate; + +--error +select cume_dist('2024') within group (order by c4) from test_aggregate; + +--success +select cume_dist('2024-12-12') within group (order by c4) from test_aggregate; + +--success +select cume_dist('1') within group (order by c1) from test_aggregate; + +--sucdess boolean +select rank(1) within group (order by x) from (values (true),(false)) v(x); + + +set enable_aggr_coerce_type = off; +drop table test_aggregate; +drop schema aggregate CASCADE;