diff --git a/src/common/backend/nodes/outfuncs.cpp b/src/common/backend/nodes/outfuncs.cpp index 1bd1ccb61..dbb4adb3d 100755 --- a/src/common/backend/nodes/outfuncs.cpp +++ b/src/common/backend/nodes/outfuncs.cpp @@ -678,6 +678,9 @@ static void _outPruningResult(StringInfo str, PruningResult* node) if (t_thrd.proc->workingVersionNum >= num) { WRITE_NODE_FIELD(expr); } + if (t_thrd.proc->workingVersionNum >= PBESINGLEPARTITION_VERSION_NUM) { + WRITE_BOOL_FIELD(isPbeSinlePartition); + } } static void _outSubPartitionPruningResult(StringInfo str, SubPartitionPruningResult* node) diff --git a/src/common/backend/nodes/readfuncs.cpp b/src/common/backend/nodes/readfuncs.cpp index 01d04dad2..e16993a4b 100755 --- a/src/common/backend/nodes/readfuncs.cpp +++ b/src/common/backend/nodes/readfuncs.cpp @@ -3312,6 +3312,9 @@ static PruningResult* _readPruningResult(PruningResult* local_node) if (t_thrd.proc->workingVersionNum >= num) { READ_NODE_FIELD(expr); } + IF_EXIST(isPbeSinlePartition) { + READ_BOOL_FIELD(isPbeSinlePartition); + } READ_DONE(); } diff --git a/src/common/backend/utils/init/globals.cpp b/src/common/backend/utils/init/globals.cpp index 558c4b4ca..8946ce230 100644 --- a/src/common/backend/utils/init/globals.cpp +++ b/src/common/backend/utils/init/globals.cpp @@ -65,6 +65,7 @@ const uint32 PREDPUSH_SAME_LEVEL_VERSION_NUM = 92522; const uint32 UPSERT_WHERE_VERSION_NUM = 92514; const uint32 FUNC_PARAM_COL_VERSION_NUM = 92500; const uint32 SUBPARTITION_VERSION_NUM = 92436; +const uint32 PBESINGLEPARTITION_VERSION_NUM = 92523; const uint32 DEFAULT_MAT_CTE_NUM = 92429; const uint32 MATERIALIZED_CTE_NUM = 92424; const uint32 HINT_ENHANCEMENT_VERSION_NUM = 92359; diff --git a/src/gausskernel/optimizer/path/allpaths.cpp b/src/gausskernel/optimizer/path/allpaths.cpp index 51dc7d2ab..6c5435d35 100755 --- a/src/gausskernel/optimizer/path/allpaths.cpp +++ b/src/gausskernel/optimizer/path/allpaths.cpp @@ -873,6 +873,31 @@ static void SetPlainReSizeWithPruningRatio(RelOptInfo *rel, double pruningRatio) } } +/* + * This function applies only to single partition key of range partitioned tables in PBE mode. + */ +static bool IsPbeSinglePartition(Relation rel, RelOptInfo* relInfo) +{ + if (relInfo->pruning_result->paramArg == NULL) { + return false; + } + if (RelationIsSubPartitioned(rel)) { + return false; + } + if (rel->partMap->type != PART_TYPE_RANGE) { + return false; + } + RangePartitionMap* partMap = (RangePartitionMap*)rel->partMap; + int partKeyNum = partMap->partitionKey->dim1; + if (partKeyNum > 1) { + return false; + } + if (relInfo->pruning_result->isPbeSinlePartition) { + return true; + } + return false; +} + /* * set_plain_rel_size * Set size estimates for a plain relation (no subquery, no inheritance) @@ -896,8 +921,7 @@ static void set_plain_rel_size(PlannerInfo* root, RelOptInfo* rel, RangeTblEntry Assert(rel->pruning_result); - - if (rel->pruning_result->expr != NULL) { + if (IsPbeSinglePartition(relation, rel)) { rel->partItrs = 1; } else { /* set flag for dealing with partintioned table */ diff --git a/src/gausskernel/optimizer/util/pruning.cpp b/src/gausskernel/optimizer/util/pruning.cpp index 2b1f51165..753b176b8 100644 --- a/src/gausskernel/optimizer/util/pruning.cpp +++ b/src/gausskernel/optimizer/util/pruning.cpp @@ -460,17 +460,21 @@ PruningResult* partitionPruningForExpr(PlannerInfo* root, RangeTblEntry* rte, Re context->pruningType = PruningPartition; if (rel->partMap != NULL && (rel->partMap->type == PART_TYPE_LIST || rel->partMap->type == PART_TYPE_HASH)) { + // for List/Hash partitioned table result = partitionEqualPruningWalker(rel->partMap->type, expr, context); } else { + // for Range/Interval partitioned table result = partitionPruningWalker(expr, context); } if (result->exprPart != NULL || result->paramArg != NULL) { Param* paramArg = (Param *)copyObject(result->paramArg); + bool isPbeSinlePartition = result->isPbeSinlePartition; destroyPruningResult(result); result = getFullPruningResult(rel); result->expr = expr; result->paramArg = paramArg; + result->isPbeSinlePartition = isPbeSinlePartition; return result; } /* Never happen, just to be self-contained */ @@ -535,10 +539,12 @@ PruningResult* partitionPruningWalker(Expr* expr, PruningContext* pruningCtx) result = makeNode(PruningResult); result->state = PRUNING_RESULT_FULL; } + result->isPbeSinlePartition = false; } break; default: { result = makeNode(PruningResult); result->state = PRUNING_RESULT_FULL; + result->isPbeSinlePartition = false; } break; } @@ -619,6 +625,7 @@ static PruningResult* partitionPruningFromBoolExpr(const BoolExpr* expr, Pruning if (expr->boolop == NOT_EXPR) { result = makeNode(PruningResult); result->state = PRUNING_RESULT_FULL; + result->isPbeSinlePartition = false; return result; } @@ -638,6 +645,7 @@ static PruningResult* partitionPruningFromBoolExpr(const BoolExpr* expr, Pruning break; case OR_EXPR: result = unionChildPruningResult(resultList, context); + result->isPbeSinlePartition = false; break; case NOT_EXPR: default: @@ -750,6 +758,7 @@ static PruningResult* partitionPruningFromNullTest(NullTest* expr, PruningContex } result->state = PRUNING_RESULT_SUBSET; + result->isPbeSinlePartition = true; result->bm_rangeSelectedPartitions = bms_make_singleton(partMap->rangeElementsNum - 1); @@ -832,6 +841,7 @@ static PruningResult* intersectChildPruningResult(const List* resultList, Prunin AssertEreport(iteratorResult, MOD_OPT, "iteratorResult context is NNULL."); if (iteratorResult->state == PRUNING_RESULT_EMPTY) { result->state = PRUNING_RESULT_EMPTY; + result->isPbeSinlePartition = false; return result; } else if (iteratorResult->state == PRUNING_RESULT_FULL) { continue; @@ -875,17 +885,22 @@ static PruningResult* intersectChildPruningResult(const List* resultList, Prunin if (BoundaryIsEmpty(result->boundary)) { result->state = PRUNING_RESULT_EMPTY; + result->isPbeSinlePartition = false; break; } result->state = PRUNING_RESULT_SUBSET; } + if (result->state != PRUNING_RESULT_EMPTY && iteratorResult->isPbeSinlePartition) { + result->isPbeSinlePartition = true; + } } if (PruningResultIsEmpty(result)) { destroyPruningResult(result); result = makeNode(PruningResult); result->state = PRUNING_RESULT_EMPTY; + result->isPbeSinlePartition = false; result->intervalOffset = -1; } @@ -981,6 +996,7 @@ static PruningResult* partitionPruningFromScalarArrayOpExpr if (T_Var != nodeTag(larg) || (T_ArrayExpr != nodeTag(rarg) && T_Const != nodeTag(rarg))) { result = makeNode(PruningResult); result->state = PRUNING_RESULT_FULL; + result->isPbeSinlePartition = false; return result; } @@ -1079,6 +1095,7 @@ static PruningResult* partitionPruningFromScalarArrayOpExpr } else { result = makeNode(PruningResult); result->state = PRUNING_RESULT_FULL; + result->isPbeSinlePartition = false; return result; } } @@ -1258,6 +1275,7 @@ static PruningResult* recordBoundaryFromOpExpr(const OpExpr* expr, PruningContex /* length of args MUST be 2 */ if (!PointerIsValid(expr) || list_length(expr->args) != 2 || !PointerIsValid(opName = get_opname(expr->opno))) { result->state = PRUNING_RESULT_FULL; + result->isPbeSinlePartition = false; return result; } @@ -1296,6 +1314,7 @@ static PruningResult* recordBoundaryFromOpExpr(const OpExpr* expr, PruningContex ((T_Const == nodeTag(rightArg) || T_Param == nodeTag(rightArg) || T_OpExpr == nodeTag(rightArg)) && T_Var == nodeTag(leftArg)))) { result->state = PRUNING_RESULT_FULL; + result->isPbeSinlePartition = false; return result; } @@ -1325,6 +1344,7 @@ static PruningResult* recordBoundaryFromOpExpr(const OpExpr* expr, PruningContex if (context->rte != NULL && context->rte->relid != context->relation->rd_id) { result->state = PRUNING_RESULT_FULL; + result->isPbeSinlePartition = false; return result; } } else { @@ -1334,6 +1354,7 @@ static PruningResult* recordBoundaryFromOpExpr(const OpExpr* expr, PruningContex paramArg != NULL || exprPart != NULL) { result->state = PRUNING_RESULT_FULL; + result->isPbeSinlePartition = false; return result; } } @@ -1351,25 +1372,32 @@ static PruningResult* recordBoundaryFromOpExpr(const OpExpr* expr, PruningContex if (exprPart != NULL) { if (!PartitionMapIsRange(partMap)) { result->state = PRUNING_RESULT_FULL; + result->isPbeSinlePartition = false; return result; } else { result->exprPart = exprPart; result->state = PRUNING_RESULT_SUBSET; + result->isPbeSinlePartition = false; return result; } } else if (paramArg != NULL) { if (paramArg->paramkind != PARAM_EXTERN || !PartitionMapIsRange(partMap)) { result->state = PRUNING_RESULT_FULL; + result->isPbeSinlePartition = false; return result; } else { result->paramArg = paramArg; result->state = PRUNING_RESULT_SUBSET; + if (0 == strcmp("=", opName)) { + result->isPbeSinlePartition = true; + } return result; } } if (constArg->constisnull) { result->state = PRUNING_RESULT_EMPTY; + result->isPbeSinlePartition = false; return result; } @@ -1377,6 +1405,7 @@ static PruningResult* recordBoundaryFromOpExpr(const OpExpr* expr, PruningContex result->boundary = makePruningBoundary(partKeyNum); boundary = result->boundary; + result->isPbeSinlePartition = false; /* decide the const is the top or bottom of boundary */ if ((0 == strcmp(">", opName) && rightArgIsConst) || (0 == strcmp("<", opName) && !rightArgIsConst)) { @@ -1409,6 +1438,7 @@ static PruningResult* recordBoundaryFromOpExpr(const OpExpr* expr, PruningContex boundary->state = PRUNING_RESULT_SUBSET; result->state = PRUNING_RESULT_SUBSET; + result->isPbeSinlePartition = true; } else if ((0 == strcmp("<=", opName) && rightArgIsConst) || (0 == strcmp(">=", opName) && !rightArgIsConst)) { boundary->maxClose[attrOffset] = true; boundary->max[attrOffset] = PointerGetDatum(constArg); diff --git a/src/gausskernel/runtime/executor/nodeTidscan.cpp b/src/gausskernel/runtime/executor/nodeTidscan.cpp index 2c3f48b73..c238155f0 100644 --- a/src/gausskernel/runtime/executor/nodeTidscan.cpp +++ b/src/gausskernel/runtime/executor/nodeTidscan.cpp @@ -768,7 +768,11 @@ static void ExecInitPartitionForTidScan(TidScanState* tidstate, EState* estate) lock = (relistarget ? RowExclusiveLock : AccessShareLock); tidstate->ss.lockMode = lock; - Assert(plan->scan.itrs == plan->scan.pruningInfo->ls_rangeSelectedPartitions->length); + if (plan->scan.pruningInfo->ls_rangeSelectedPartitions != NULL) { + plan->scan.itrs = plan->scan.pruningInfo->ls_rangeSelectedPartitions->length; + } else { + plan->scan.itrs = 0; + } foreach (cell, part_seqs) { Oid table_partitionid = InvalidOid; diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h index f2f96ee14..f0890a0ac 100644 --- a/src/include/miscadmin.h +++ b/src/include/miscadmin.h @@ -44,6 +44,7 @@ extern const uint32 PREDPUSH_SAME_LEVEL_VERSION_NUM; extern const uint32 UPSERT_WHERE_VERSION_NUM; extern const uint32 FUNC_PARAM_COL_VERSION_NUM; extern const uint32 SUBPARTITION_VERSION_NUM; +extern const uint32 PBESINGLEPARTITION_VERSION_NUM; extern const uint32 COMMENT_PROC_VERSION_NUM; extern const uint32 COMMENT_ROWTYPE_TABLEOF_VERSION_NUM; extern const uint32 COMMENT_PCT_TYPE_VERSION_NUM; diff --git a/src/include/utils/partitionmap_gs.h b/src/include/utils/partitionmap_gs.h index 8bad10886..cc59c7d3a 100644 --- a/src/include/utils/partitionmap_gs.h +++ b/src/include/utils/partitionmap_gs.h @@ -470,6 +470,8 @@ typedef struct PruningResult { Param* paramArg; OpExpr* exprPart; Expr* expr; + /* This variable applies only to single-partition key range partition tables in PBE mode. */ + bool isPbeSinlePartition = false; } PruningResult; extern Oid partIDGetPartOid(Relation relation, PartitionIdentifier* partID); diff --git a/src/test/regress/expected/sqlbypass_partition.out b/src/test/regress/expected/sqlbypass_partition.out index 07a405197..e2ef975c5 100755 --- a/src/test/regress/expected/sqlbypass_partition.out +++ b/src/test/regress/expected/sqlbypass_partition.out @@ -2641,5 +2641,95 @@ delete from test_bypass_sql_partition where col1 <= 11 and col1 >= 15; delete from test_bypass_sql_partition where col1 > 10; delete from test_bypass_sql_partition where col1 < 10; delete from test_bypass_sql_partition where col1 >= 10 and col1 <= 30; +create table t1( +crcrd_acg_setl_dt char(8) not null, +cst_id char(18), +multi_tenancy_id char(5) +) +partition by range (multi_tenancy_id, crcrd_acg_setl_dt) +( + partition p1 values less than ('CN000', '20191201'), + partition p2 values less than ('CN000', '20200201'), + partition p3 values less than ('CN000', '20200202'), + partition p4 values less than ('CN000', '20200203'), + partition p5 values less than ('CN000', '20200204'), + partition p6 values less than ('ZZZZZ', '21000101') +) +enable row movement +; + +create index on t1(crcrd_acg_setl_dt, cst_id, multi_tenancy_id) local; + +insert into t1 values('20200201', '107190000103394943', 'CN000'); +insert into t1 values('20200225', '107190000103394943', 'CN000'); +insert into t1 values('20200228', '107190000103394943', 'CN000'); +insert into t1 values('20200301', '107190000103394943', 'CN000'); +insert into t1 values('20200310', '107190000103394943', 'CN000'); + +set enable_seqscan = off; + +select max(crcrd_acg_setl_dt) from t1 where cst_id='107190000103394943' and multi_tenancy_id = 'CN000'; + max +---------- + 20200310 +(1 row) + + +prepare p1 as select max(crcrd_acg_setl_dt) from t1 where cst_id=$1 and multi_tenancy_id = $2; + +execute p1 ('107190000103394943','CN000'); + max +---------- + 20200310 +(1 row) + +deallocate p1; +drop table t1; +drop table test_range_pt; +ERROR: table "test_range_pt" does not exist +create table test_range_pt (a int, b int, c int) +partition by range(a) +( + partition p1 values less than (2000), + partition p2 values less than (3000), + partition p3 values less than (4000), + partition p4 values less than (5000), + partition p5 values less than (maxvalue) +)ENABLE ROW MOVEMENT; +insert into test_range_pt values(1,1),(2001,2),(3001,3),(4001,4),(5001,5); + +create index idx1 on test_range_pt(a) local; +prepare p1 as select max(a) from test_range_pt where a>$1; +execute p1 (1); + max +------ + 5001 +(1 row) + +deallocate p1; +select max(a) from test_range_pt where a>b+1; + max +------ + 5001 +(1 row) + +drop table test_range_pt; +drop table test_list_lt1; +ERROR: table "test_list_lt1" does not exist +create table test_list_lt1 (a int, b int ) +partition by list(a) +( + partition p1 values (2000), + partition p2 values (3000), + partition p3 values (4000) +) ; +prepare p1 as select * from test_list_lt1 where a = $1 and ctid = '(0,1)'; +execute p1 (1); + a | b +---+--- +(0 rows) + +deallocate p1; +drop table test_list_lt1; reset enable_partition_opfusion; drop table test_bypass_sql_partition; diff --git a/src/test/regress/sql/sqlbypass_partition.sql b/src/test/regress/sql/sqlbypass_partition.sql index d929e76b3..cfbafc6e6 100755 --- a/src/test/regress/sql/sqlbypass_partition.sql +++ b/src/test/regress/sql/sqlbypass_partition.sql @@ -250,6 +250,73 @@ delete from test_bypass_sql_partition where col1 <= 11 and col1 >= 15; delete from test_bypass_sql_partition where col1 > 10; delete from test_bypass_sql_partition where col1 < 10; delete from test_bypass_sql_partition where col1 >= 10 and col1 <= 30; + +create table t1( +crcrd_acg_setl_dt char(8) not null, +cst_id char(18), +multi_tenancy_id char(5) +) +partition by range (multi_tenancy_id, crcrd_acg_setl_dt) +( + partition p1 values less than ('CN000', '20191201'), + partition p2 values less than ('CN000', '20200201'), + partition p3 values less than ('CN000', '20200202'), + partition p4 values less than ('CN000', '20200203'), + partition p5 values less than ('CN000', '20200204'), + partition p6 values less than ('ZZZZZ', '21000101') +) +enable row movement +; + +create index on t1(crcrd_acg_setl_dt, cst_id, multi_tenancy_id) local; + +insert into t1 values('20200201', '107190000103394943', 'CN000'); +insert into t1 values('20200225', '107190000103394943', 'CN000'); +insert into t1 values('20200228', '107190000103394943', 'CN000'); +insert into t1 values('20200301', '107190000103394943', 'CN000'); +insert into t1 values('20200310', '107190000103394943', 'CN000'); + +set enable_seqscan = off; + +select max(crcrd_acg_setl_dt) from t1 where cst_id='107190000103394943' and multi_tenancy_id = 'CN000'; + +prepare p1 as select max(crcrd_acg_setl_dt) from t1 where cst_id=$1 and multi_tenancy_id = $2; + +execute p1 ('107190000103394943','CN000'); +deallocate p1; + +drop table t1; +drop table test_range_pt; +create table test_range_pt (a int, b int, c int) +partition by range(a) +( + partition p1 values less than (2000), + partition p2 values less than (3000), + partition p3 values less than (4000), + partition p4 values less than (5000), + partition p5 values less than (maxvalue) +)ENABLE ROW MOVEMENT; +insert into test_range_pt values(1,1),(2001,2),(3001,3),(4001,4),(5001,5); + +create index idx1 on test_range_pt(a) local; +prepare p1 as select max(a) from test_range_pt where a>$1; +execute p1 (1); +deallocate p1; +select max(a) from test_range_pt where a>b+1; +drop table test_range_pt; +drop table test_list_lt1; +create table test_list_lt1 (a int, b int ) +partition by list(a) +( + partition p1 values (2000), + partition p2 values (3000), + partition p3 values (4000) +) ; +prepare p1 as select * from test_list_lt1 where a = $1 and ctid = '(0,1)'; +execute p1 (1); +deallocate p1; +drop table test_list_lt1; + reset enable_partition_opfusion; drop table test_bypass_sql_partition;