From ca44bc145f3311d328ccb772bf63709b6846a677 Mon Sep 17 00:00:00 2001 From: wuyuechuan Date: Tue, 25 Jun 2024 19:50:49 +0800 Subject: [PATCH] dolphin: add null first policy api --- .../utils/misc/postgresql_single.conf.sample | 6 +++ .../cbb/utils/partition/partrouting.cpp | 4 +- src/gausskernel/optimizer/path/allpaths.cpp | 12 ++++- src/gausskernel/optimizer/path/pathkeys.cpp | 12 ++--- src/include/knl/knl_session.h | 1 + src/include/utils/partitionmap_gs.h | 9 ++++ .../regress/expected/null_in_partition.out | 44 +++++++++---------- .../expected/partition_dml_operations.out | 32 ++++++-------- src/test/regress/sql/null_in_partition.sql | 12 ++--- 9 files changed, 75 insertions(+), 57 deletions(-) diff --git a/src/common/backend/utils/misc/postgresql_single.conf.sample b/src/common/backend/utils/misc/postgresql_single.conf.sample index 67570e55c..f23618c82 100644 --- a/src/common/backend/utils/misc/postgresql_single.conf.sample +++ b/src/common/backend/utils/misc/postgresql_single.conf.sample @@ -870,6 +870,12 @@ job_queue_processes = 10 # Number of concurrent jobs, optional: [0..1000] #ss_fi_process_fault_entries = '' #ss_fi_custom_fault_entries = '' + +#------------------------------------------------------------------------------ +# DOLPHIN OPTIONS +#------------------------------------------------------------------------------ +dolphin.nulls_minimal_policy = on # the inverse of the default configuration value ! do not change ! + #------------------------------------------------------------------------------ # UWAL OPTIONS #------------------------------------------------------------------------------ diff --git a/src/gausskernel/cbb/utils/partition/partrouting.cpp b/src/gausskernel/cbb/utils/partition/partrouting.cpp index 4c9ac4c19..606598bc1 100644 --- a/src/gausskernel/cbb/utils/partition/partrouting.cpp +++ b/src/gausskernel/cbb/utils/partition/partrouting.cpp @@ -385,9 +385,9 @@ void partitionKeyCompareForRouting(Const **partkey_value, Const **partkey_bound, ereport(ERROR, (errcode(ERRCODE_UNEXPECTED_NULL_VALUE), errmsg("null value can not be compared with null value."))); } else if (kv->constisnull) { - compare = DB_IS_CMPT(B_FORMAT) ? -1 : 1; + compare = CheckPluginNullsPolicy() ? -1 : 1; } else { - compare = DB_IS_CMPT(B_FORMAT) ? 1 : -1; + compare = CheckPluginNullsPolicy() ? 1 : -1; } break; } diff --git a/src/gausskernel/optimizer/path/allpaths.cpp b/src/gausskernel/optimizer/path/allpaths.cpp index e1ee31512..40050c018 100755 --- a/src/gausskernel/optimizer/path/allpaths.cpp +++ b/src/gausskernel/optimizer/path/allpaths.cpp @@ -3973,9 +3973,17 @@ static void make_partiterator_pathkey( * we do partitionkey comparison just as ''order by ASC NULL LAST'', and pathkey * must follow the same rules. If sortcluase is ether ''ASC NULL FIRST'' or "DESC * NULL LAST", just abandon pathkeys + * in B database, nulls was the min value */ - if (!(pk_strategy == BTLessStrategyNumber && pk_nulls_first == false) && - !(pk_strategy == BTGreaterStrategyNumber && pk_nulls_first == true)) { + bool invalid_path_key= false; + if (CheckPluginNullsPolicy()) { + invalid_path_key = !(pk_strategy == BTLessStrategyNumber && pk_nulls_first == true) && + !(pk_strategy == BTGreaterStrategyNumber && pk_nulls_first == false); + } else { + invalid_path_key = !(pk_strategy == BTLessStrategyNumber && pk_nulls_first == false) && + !(pk_strategy == BTGreaterStrategyNumber && pk_nulls_first == true); + } + if (invalid_path_key) { OPT_LOG(DEBUG2, "partiterator fails to inherit pathkeys since sort strategy is" " nether ASC NULL LAST nor DESC DESC NULL FIRST"); diff --git a/src/gausskernel/optimizer/path/pathkeys.cpp b/src/gausskernel/optimizer/path/pathkeys.cpp index 3c8f20c5d..2c67b3b98 100644 --- a/src/gausskernel/optimizer/path/pathkeys.cpp +++ b/src/gausskernel/optimizer/path/pathkeys.cpp @@ -567,12 +567,12 @@ List* build_index_pathkeys(PlannerInfo* root, IndexOptInfo* index, ScanDirection } /* - * in B format, null value in insert into the minimal partition - * if index is default nulls last, set to nulls first - * if index is nulls first, dothing - * */ - if (index->ispartitionedindex && !index->isGlobal && DB_IS_CMPT(B_FORMAT)) { - if (!index->nulls_first[i]) { + * in B format, null value in insert into the minimal partition + * desc default: nulls first -> nulls last + * asc default: nulls last -> nulls + */ + if (index->ispartitionedindex && !index->isGlobal && CheckPluginNullsPolicy()) { + if ((!reverse_sort && !nulls_first) || (reverse_sort && nulls_first)) { nulls_first = !nulls_first; } } diff --git a/src/include/knl/knl_session.h b/src/include/knl/knl_session.h index cbf61fb97..ac8ef4f28 100644 --- a/src/include/knl/knl_session.h +++ b/src/include/knl/knl_session.h @@ -2929,6 +2929,7 @@ typedef struct knl_u_hook_context { void *pluginPlannerHook; void *groupingplannerHook; void *replaceNullOrNotHook; + void *nullsMinimalPolicyHook; } knl_u_hook_context; typedef struct knl_u_libsw_context { diff --git a/src/include/utils/partitionmap_gs.h b/src/include/utils/partitionmap_gs.h index 637b27fcf..54c63f2f9 100755 --- a/src/include/utils/partitionmap_gs.h +++ b/src/include/utils/partitionmap_gs.h @@ -473,6 +473,15 @@ extern void DestroyPartitionMap(PartitionMap* partMap); extern bool trySearchFakeReationForPartitionOid(HTAB** fakeRels, MemoryContext cxt, Relation rel, Oid partOid, int partitionno, Relation* fakeRelation, Partition* partition, LOCKMODE lmode, bool checkSubPart = true); +#ifndef FRONTEND +typedef bool (*nullsMinimalPolicy)(); +extern inline bool CheckPluginNullsPolicy() +{ + return DB_IS_CMPT(B_FORMAT) && (u_sess->hook_cxt.nullsMinimalPolicyHook != NULL ? + ((nullsMinimalPolicy)(u_sess->hook_cxt.nullsMinimalPolicyHook))() : false); +} +#endif + /* partitoin map copy functions */ extern ListPartitionMap *CopyListPartitionMap(ListPartitionMap *src_lpm); /* more! other hash/range and its underlaying element data structores will add here later */ diff --git a/src/test/regress/expected/null_in_partition.out b/src/test/regress/expected/null_in_partition.out index 4b034e272..200ae3c8f 100644 --- a/src/test/regress/expected/null_in_partition.out +++ b/src/test/regress/expected/null_in_partition.out @@ -156,13 +156,13 @@ insert into base_partition_tbl values(null, 'test'); select * from base_partition_tbl partition (num1); num | data1 -----+------- - | test -(1 row) +(0 rows) select * from base_partition_tbl partition (num4); num | data1 -----+------- -(0 rows) + | test +(1 row) create table base_partition_tbl_sub_partition ( @@ -193,41 +193,39 @@ insert into base_partition_tbl_sub_partition values(null, 'test'); select * from base_partition_tbl_sub_partition subpartition (num1_1); num | data1 -----+------- - | test -(1 row) +(0 rows) select * from base_partition_tbl_sub_partition subpartition (num5_2); num | data1 -----+------- -(0 rows) + | test +(1 row) create table t_range (c1 int, c2 int) partition by range(c1) (partition p1 values less than (10), partition p2 values less than(maxvalue)); insert into t_range values(null),(5),(100); create index t_range_c1_idx on t_range (c1 nulls last) local; -explain (costs off) select /*+ indexscan(t_range) */* from t_range order by c1 nulls first; -- INDEX - QUERY PLAN --------------------------------------------------------------------- - Sort - Sort Key: c1 NULLS FIRST - -> Partition Iterator - Iterations: 2 - -> Partitioned Index Scan using t_range_c1_idx on t_range - Selected Partitions: 1..2 -(6 rows) - -explain (costs off) select /*+ indexscan(t_range) */* from t_range order by c1 nulls last; -- NO INDEX +explain (costs off) select /*+ indexscan(t_range) */* from t_range order by c1 nulls first; -- NO INDEX WARNING: unused hint: IndexScan(t_range) QUERY PLAN --------------------------------------------- Sort - Sort Key: c1 + Sort Key: c1 NULLS FIRST -> Partition Iterator Iterations: 2 -> Partitioned Seq Scan on t_range Selected Partitions: 1..2 (6 rows) -select /*+ indexscan(t_range) */* from t_range order by c1 nulls first; -- INDEX +explain (costs off) select /*+ indexscan(t_range) */* from t_range order by c1 nulls last; -- INDEX + QUERY PLAN +-------------------------------------------------------------- + Partition Iterator + Iterations: 2 + -> Partitioned Index Scan using t_range_c1_idx on t_range + Selected Partitions: 1..2 +(4 rows) + +select /*+ indexscan(t_range) */* from t_range order by c1 nulls first; -- NO INDEX c1 | c2 -----+---- | @@ -235,7 +233,7 @@ select /*+ indexscan(t_range) */* from t_range order by c1 nulls first; -- INDEX 100 | (3 rows) -select /*+ indexscan(t_range) */* from t_range order by c1 nulls last; -- NO INDEX +select /*+ indexscan(t_range) */* from t_range order by c1 nulls last; -- INDEX c1 | c2 -----+---- 5 | @@ -245,7 +243,7 @@ select /*+ indexscan(t_range) */* from t_range order by c1 nulls last; -- NO IND drop index t_range_c1_idx; create index on t_range (c1 nulls first) local; -explain (costs off) select /*+ indexscan(t_range) */* from t_range order by c1 nulls first; -- INDEX +explain (costs off) select /*+ indexscan(t_range) */* from t_range order by c1 nulls first; -- NO INDEX QUERY PLAN -------------------------------------------------------------------- Sort @@ -268,7 +266,7 @@ WARNING: unused hint: IndexScan(t_range) Selected Partitions: 1..2 (6 rows) -select /*+ indexscan(t_range) */* from t_range order by c1 nulls first; -- INDEX +select /*+ indexscan(t_range) */* from t_range order by c1 nulls first; -- NO INDEX c1 | c2 -----+---- | diff --git a/src/test/regress/expected/partition_dml_operations.out b/src/test/regress/expected/partition_dml_operations.out index 49a0d0a75..c53a32925 100644 --- a/src/test/regress/expected/partition_dml_operations.out +++ b/src/test/regress/expected/partition_dml_operations.out @@ -1685,16 +1685,14 @@ select * from t_multi_parts_order partition (pd) order by col limit 10; rollback; explain (costs off) delete from t_multi_parts_order partition(pd, p1) order by col limit 10; - QUERY PLAN ---------------------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------------------------------------- Delete on t_multi_parts_order - -> Sort - Sort Key: col - -> Partition Iterator - Iterations: 2 - -> Partitioned Seq Scan on t_multi_parts_order - Selected Partitions: 1..2 -(7 rows) + -> Partition Iterator + Iterations: 2 + -> Partitioned Index Scan using tbl_idx_t_multi_parts_order on t_multi_parts_order + Selected Partitions: 1..2 +(5 rows) begin; delete from t_multi_parts_order partition(p1, pd) order by col desc limit 10; @@ -1761,16 +1759,14 @@ select * from t_multi_parts_order partition (pd) order by col desc limit 10; rollback; explain (costs off) delete from t_multi_parts_order partition(pd, p1) order by col desc limit 10; - QUERY PLAN ---------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------------------------------------------ Delete on t_multi_parts_order - -> Sort - Sort Key: col DESC - -> Partition Iterator - Iterations: 2 - -> Partitioned Seq Scan on t_multi_parts_order - Selected Partitions: 1..2 -(7 rows) + -> Partition Iterator Scan Backward + Iterations: 2 + -> Partitioned Index Scan Backward using tbl_idx_t_multi_parts_order on t_multi_parts_order + Selected Partitions: 1..2 +(5 rows) drop table if exists t_multi_parts_order; -- range partitions with global index, single column diff --git a/src/test/regress/sql/null_in_partition.sql b/src/test/regress/sql/null_in_partition.sql index b12f35132..08e656451 100644 --- a/src/test/regress/sql/null_in_partition.sql +++ b/src/test/regress/sql/null_in_partition.sql @@ -105,15 +105,15 @@ select * from base_partition_tbl_sub_partition subpartition (num5_2); create table t_range (c1 int, c2 int) partition by range(c1) (partition p1 values less than (10), partition p2 values less than(maxvalue)); insert into t_range values(null),(5),(100); create index t_range_c1_idx on t_range (c1 nulls last) local; -explain (costs off) select /*+ indexscan(t_range) */* from t_range order by c1 nulls first; -- INDEX -explain (costs off) select /*+ indexscan(t_range) */* from t_range order by c1 nulls last; -- NO INDEX -select /*+ indexscan(t_range) */* from t_range order by c1 nulls first; -- INDEX -select /*+ indexscan(t_range) */* from t_range order by c1 nulls last; -- NO INDEX +explain (costs off) select /*+ indexscan(t_range) */* from t_range order by c1 nulls first; -- NO INDEX +explain (costs off) select /*+ indexscan(t_range) */* from t_range order by c1 nulls last; -- INDEX +select /*+ indexscan(t_range) */* from t_range order by c1 nulls first; -- NO INDEX +select /*+ indexscan(t_range) */* from t_range order by c1 nulls last; -- INDEX drop index t_range_c1_idx; create index on t_range (c1 nulls first) local; -explain (costs off) select /*+ indexscan(t_range) */* from t_range order by c1 nulls first; -- INDEX +explain (costs off) select /*+ indexscan(t_range) */* from t_range order by c1 nulls first; -- NO INDEX explain (costs off) select /*+ indexscan(t_range) */* from t_range order by c1 nulls last; -- NO INDEX -select /*+ indexscan(t_range) */* from t_range order by c1 nulls first; -- INDEX +select /*+ indexscan(t_range) */* from t_range order by c1 nulls first; -- NO INDEX select /*+ indexscan(t_range) */* from t_range order by c1 nulls last; -- NO INDEX \c regression