diff --git a/src/common/backend/nodes/equalfuncs.cpp b/src/common/backend/nodes/equalfuncs.cpp index 7c1a12bcc..cd621d6bc 100755 --- a/src/common/backend/nodes/equalfuncs.cpp +++ b/src/common/backend/nodes/equalfuncs.cpp @@ -1268,6 +1268,7 @@ static bool _equalIndexStmt(const IndexStmt* a, const IndexStmt* b) COMPARE_SCALAR_FIELD(oldNode); COMPARE_NODE_FIELD(partClause); COMPARE_SCALAR_FIELD(isPartitioned); + COMPARE_SCALAR_FIELD(isGlobal); COMPARE_SCALAR_FIELD(unique); COMPARE_SCALAR_FIELD(primary); COMPARE_SCALAR_FIELD(isconstraint); diff --git a/src/common/backend/nodes/outfuncs.cpp b/src/common/backend/nodes/outfuncs.cpp index c4b11f52e..ab85460e0 100755 --- a/src/common/backend/nodes/outfuncs.cpp +++ b/src/common/backend/nodes/outfuncs.cpp @@ -3293,6 +3293,7 @@ static void _outIndexStmt(StringInfo str, IndexStmt* node) WRITE_OID_FIELD(oldNode); WRITE_NODE_FIELD(partClause); WRITE_BOOL_FIELD(isPartitioned); + WRITE_BOOL_FIELD(isGlobal); WRITE_BOOL_FIELD(unique); WRITE_BOOL_FIELD(primary); WRITE_BOOL_FIELD(isconstraint); diff --git a/src/common/backend/nodes/readfuncs.cpp b/src/common/backend/nodes/readfuncs.cpp index 44b614579..ae1059864 100644 --- a/src/common/backend/nodes/readfuncs.cpp +++ b/src/common/backend/nodes/readfuncs.cpp @@ -4628,6 +4628,7 @@ static IndexStmt* _readIndexStmt() READ_OID_FIELD(oldNode); READ_NODE_FIELD(partClause); READ_BOOL_FIELD(isPartitioned); + READ_BOOL_FIELD(isGlobal); READ_BOOL_FIELD(unique); READ_BOOL_FIELD(primary); READ_BOOL_FIELD(isconstraint); @@ -4674,18 +4675,21 @@ static Constraint* _readConstraint() } else if (MATCH_TYPE("PRIMARY_KEY")) { local_node->contype = CONSTR_PRIMARY; READ_NODE_FIELD(keys); + READ_NODE_FIELD(including); READ_NODE_FIELD(options); READ_STRING_FIELD(indexname); READ_STRING_FIELD(indexspace); } else if (MATCH_TYPE("UNIQUE")) { local_node->contype = CONSTR_UNIQUE; READ_NODE_FIELD(keys); + READ_NODE_FIELD(including); READ_NODE_FIELD(options); READ_STRING_FIELD(indexname); READ_STRING_FIELD(indexspace); } else if (MATCH_TYPE("EXCLUSION")) { local_node->contype = CONSTR_EXCLUSION; READ_NODE_FIELD(exclusions); + READ_NODE_FIELD(including); READ_NODE_FIELD(options); READ_STRING_FIELD(indexname); READ_STRING_FIELD(indexspace); diff --git a/src/common/backend/nodes/tidbitmap.cpp b/src/common/backend/nodes/tidbitmap.cpp index 647bdcbc2..811bd9644 100755 --- a/src/common/backend/nodes/tidbitmap.cpp +++ b/src/common/backend/nodes/tidbitmap.cpp @@ -322,9 +322,9 @@ void tbm_add_tuples(TIDBitmap* tbm, const ItemPointer tids, int ntids, bool rech * This causes the whole page to be reported (with the recheck flag) * when the TIDBitmap is scanned. */ -void tbm_add_page(TIDBitmap* tbm, BlockNumber pageno) +void tbm_add_page(TIDBitmap* tbm, BlockNumber pageno, Oid partitionOid) { - PagetableEntryNode pnode = {pageno, InvalidOid}; + PagetableEntryNode pnode = {pageno, partitionOid}; /* Enter the page in the bitmap, or mark it lossy if already present */ tbm_mark_page_lossy(tbm, pnode); /* If we went over the memory limit, lossify some more pages */ diff --git a/src/common/backend/parser/parse_utilcmd.cpp b/src/common/backend/parser/parse_utilcmd.cpp index 9b3dd39c8..b694387b5 100644 --- a/src/common/backend/parser/parse_utilcmd.cpp +++ b/src/common/backend/parser/parse_utilcmd.cpp @@ -3159,6 +3159,12 @@ IndexStmt* transformIndexStmt(Oid relid, IndexStmt* stmt, const char* queryStrin stmt->internal_flag = true; } + /* default partition index is set to Global index */ + if (RELATION_IS_PARTITIONED(rel) && !stmt->isPartitioned) { + stmt->isPartitioned = true; + stmt->isGlobal = true; + } + bool isColStore = RelationIsColStore(rel); if (stmt->accessMethod == NULL) { if (!isColStore) { diff --git a/src/common/backend/utils/cache/relcache.cpp b/src/common/backend/utils/cache/relcache.cpp index 3be4cf835..ecf6e9ebf 100644 --- a/src/common/backend/utils/cache/relcache.cpp +++ b/src/common/backend/utils/cache/relcache.cpp @@ -4703,9 +4703,10 @@ List* RelationGetSpecificKindIndexList(Relation relation, bool isGlobal) { ListCell* indList = NULL; List* result = NULL; + List* indexOidList = RelationGetIndexList(relation); /* Ask the relcache to produce a list of the indexes of the rel */ - foreach (indList, RelationGetIndexList(relation)) { + foreach (indList, indexOidList) { Oid indexId = lfirst_oid(indList); Relation currentIndex; @@ -4723,6 +4724,7 @@ List* RelationGetSpecificKindIndexList(Relation relation, bool isGlobal) index_close(currentIndex, AccessShareLock); } + list_free_ext(indexOidList); return result; } diff --git a/src/gausskernel/optimizer/commands/indexcmds.cpp b/src/gausskernel/optimizer/commands/indexcmds.cpp index 581522229..b56915c35 100755 --- a/src/gausskernel/optimizer/commands/indexcmds.cpp +++ b/src/gausskernel/optimizer/commands/indexcmds.cpp @@ -433,6 +433,12 @@ Oid DefineIndex(Oid relationId, IndexStmt* stmt, Oid indexRelationId, bool is_al ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot create concurrent partitioned indexes "))); } + if (stmt->isGlobal && (list_length(stmt->indexParams) > INDEX_MAX_KEYS - 1)) { + ereport(ERROR, + (errcode(ERRCODE_TOO_MANY_COLUMNS), + errmsg("cannot use more than %d columns in an global partition index", INDEX_MAX_KEYS - 1))); + } + /* Add special index columns tableoid to global partition index */ if (stmt->isGlobal) { AddIndexColumnForGpi(stmt); @@ -3067,8 +3073,7 @@ static bool CheckGlobalIndexCompatible(Oid relOid, bool isGlobal, const IndexInf /* only check index of different type(local and global) */ if (currIdxKind != tarIdxKind) { if (!CheckIndexMethodConsistency(tarTuple, indexRelation, currMethodOid)) { - ret = false; - break; + continue; } heap_getattr(tarTuple, Anum_pg_index_indexprs, RelationGetDescr(indexRelation), &isNull); diff --git a/src/gausskernel/optimizer/commands/tablecmds.cpp b/src/gausskernel/optimizer/commands/tablecmds.cpp index a2fe4f5b7..d9d4f04f4 100644 --- a/src/gausskernel/optimizer/commands/tablecmds.cpp +++ b/src/gausskernel/optimizer/commands/tablecmds.cpp @@ -8904,7 +8904,7 @@ static void ATExecAddIndex(AlteredTableInfo* tab, Relation rel, IndexStmt* stmt, if (OidIsValid(stmt->oldNode)) { Relation irel = index_open(new_index, NoLock); - if (!stmt->isPartitioned) { + if (!stmt->isPartitioned || stmt->isGlobal) { RelationPreserveStorage(irel->rd_node, true); } else { List* partOids = NIL; @@ -11316,7 +11316,7 @@ static void ATCutOffPSortDependency(List* oldIndexPassList, LOCKMODE lockmode) // if the index is a partition table, handle all the // psort info for each partition. - if (istmt->isPartitioned) { + if (istmt->isPartitioned && !istmt->isGlobal) { Relation hrel = relation_openrv(istmt->relation, lockmode); Relation irel = index_open(istmt->indexOid, lockmode); List* partHeapOids = relationGetPartitionOidList(hrel); @@ -11492,7 +11492,7 @@ static void ATPostAlterTypeParse( AlterTableCmd* newcmd = NULL; if (!rewrite) { - if (!stmt->isPartitioned) { + if (!stmt->isPartitioned || stmt->isGlobal) { TryReuseIndex(oldId, stmt); } else { tryReusePartedIndex(oldId, stmt, rel); diff --git a/src/gausskernel/runtime/executor/nodeBitmapHeapscan.cpp b/src/gausskernel/runtime/executor/nodeBitmapHeapscan.cpp index 7c8753634..3dd4173fd 100755 --- a/src/gausskernel/runtime/executor/nodeBitmapHeapscan.cpp +++ b/src/gausskernel/runtime/executor/nodeBitmapHeapscan.cpp @@ -57,6 +57,8 @@ static TupleTableSlot* BitmapHeapTblNext(BitmapHeapScanState* node); static void bitgetpage(HeapScanDesc scan, TBMIterateResult* tbmres); static void ExecInitPartitionForBitmapHeapScan(BitmapHeapScanState* scanstate, EState* estate); static void ExecInitNextPartitionForBitmapHeapScan(BitmapHeapScanState* node); +static void BitmapHeapPrefetchNext( + BitmapHeapScanState* node, HeapScanDesc scan, const TIDBitmap* tbm, TBMIterator** prefetch_iterator); /* This struct is used for partition switch while prefetch pages */ typedef struct PrefetchNode { @@ -182,18 +184,6 @@ static TupleTableSlot* BitmapHeapTblNext(BitmapHeapScanState* node) break; } - /* Check whether switch partition-fake-rel, use rd_rel save */ - if (BitmapNodeNeedSwitchPartRel(node)) { - GPISetCurrPartOid(node->gpi_scan, node->tbmres->partitionOid); - if (!GPIGetNextPartRelation(node->gpi_scan, CurrentMemoryContext, AccessShareLock)) { - /* If the current partition is invalid, the next page is directly processed */ - tbmres = NULL; - continue; - } - scan->rs_rd = node->gpi_scan->fakePartRelation; - scan->rs_nblocks = RelationGetNumberOfBlocks(scan->rs_rd); - } - #ifdef USE_PREFETCH if (node->prefetch_pages > 0) { /* The main iterator has closed the distance by one page */ @@ -211,6 +201,21 @@ static TupleTableSlot* BitmapHeapTblNext(BitmapHeapScanState* node) } #endif /* USE_PREFETCH */ + /* Check whether switch partition-fake-rel, use rd_rel save */ + if (BitmapNodeNeedSwitchPartRel(node)) { + GPISetCurrPartOid(node->gpi_scan, node->tbmres->partitionOid); + if (!GPIGetNextPartRelation(node->gpi_scan, CurrentMemoryContext, AccessShareLock)) { + /* If the current partition is invalid, the next page is directly processed */ + tbmres = NULL; +#ifdef USE_PREFETCH + BitmapHeapPrefetchNext(node, scan, tbm, &prefetch_iterator); +#endif /* USE_PREFETCH */ + continue; + } + scan->rs_rd = node->gpi_scan->fakePartRelation; + scan->rs_nblocks = RelationGetNumberOfBlocks(scan->rs_rd); + } + /* * Ignore any claimed entries past what we think is the end of the * relation. (This is probably not necessary given that we got at @@ -286,126 +291,7 @@ static TupleTableSlot* BitmapHeapTblNext(BitmapHeapScanState* node) } #ifdef USE_PREFETCH - - /* - * We issue prefetch requests *after* fetching the current page to try - * to avoid having prefetching interfere with the main I/O. Also, this - * should happen only when we have determined there is still something - * to do on the current page, else we may uselessly prefetch the same - * page we are just about to request for real. - */ - if (prefetch_iterator != NULL) { - ADIO_RUN() - { - BlockNumber* blockList = NULL; - BlockNumber* blockListPtr = NULL; - PrefetchNode* prefetchNode = NULL; - PrefetchNode* prefetchNodePtr = NULL; - int prefetchNow = 0; - int prefetchWindow = node->prefetch_target - node->prefetch_pages; - - /* We expect to prefetch at most prefetchWindow pages */ - if (prefetchWindow > 0) { - if (tbm_is_global(tbm)) { - prefetchNode = (PrefetchNode*)malloc(sizeof(PrefetchNode) * prefetchWindow); - prefetchNodePtr = prefetchNode; - } - blockList = (BlockNumber*)palloc(sizeof(BlockNumber) * prefetchWindow); - blockListPtr = blockList; - } - while (node->prefetch_pages < node->prefetch_target) { - TBMIterateResult* tbmpre = tbm_iterate(prefetch_iterator); - - if (tbmpre == NULL) { - /* No more pages to prefetch */ - tbm_end_iterate(prefetch_iterator); - node->prefetch_iterator = prefetch_iterator = NULL; - break; - } - node->prefetch_pages++; - /* we use PrefetchNode here to store relations between blockno and partition Oid */ - if (tbm_is_global(tbm)) { - prefetchNodePtr->blockNum = tbmpre->blockno; - prefetchNodePtr->partOid = tbmpre->partitionOid; - prefetchNodePtr++; - } - /* For Async Direct I/O we accumulate a list and send it */ - *blockListPtr++ = tbmpre->blockno; - prefetchNow++; - } - - /* Send the list we generated and free it */ - if (prefetchNow) { - if (tbm_is_global(tbm)) { - /* - * we must save part Oid before switch relation, and recover it after prefetch. - * The reason for this is to assure correctness while getting a new tbmres. - */ - Oid oldOid = GPIGetCurrPartOid(node->gpi_scan); - int blkCount = 0; - Oid prevOid = prefetchNode[0].partOid; - for (int i = 0; i < prefetchNow; i++) { - if (prefetchNode[i].partOid == prevOid) { - blockList[blkCount++] = prefetchNode[i].blockNum; - } else { - GPISetCurrPartOid(node->gpi_scan, prevOid); - if (GPIGetNextPartRelation(node->gpi_scan, CurrentMemoryContext, AccessShareLock)) { - PageListPrefetch( - node->gpi_scan->fakePartRelation, MAIN_FORKNUM, blockList, blkCount, 0, 0); - } - blkCount = 0; - prevOid = prefetchNode[i].partOid; - blockList[blkCount++] = prefetchNode[i].blockNum; - } - } - GPISetCurrPartOid(node->gpi_scan, prevOid); - if (GPIGetNextPartRelation(node->gpi_scan, CurrentMemoryContext, AccessShareLock)) { - PageListPrefetch(node->gpi_scan->fakePartRelation, MAIN_FORKNUM, blockList, blkCount, 0, 0); - } - /* recover old oid after prefetch switch */ - GPISetCurrPartOid(node->gpi_scan, oldOid); - } else { - PageListPrefetch(scan->rs_rd, MAIN_FORKNUM, blockList, prefetchNow, 0, 0); - } - } - if (prefetchWindow > 0) { - pfree_ext(blockList); - if (tbm_is_global(tbm)) { - pfree_ext(prefetchNode); - } - } - } - ADIO_ELSE() - { - Oid oldOid = GPIGetCurrPartOid(node->gpi_scan); - while (node->prefetch_pages < node->prefetch_target) { - TBMIterateResult* tbmpre = tbm_iterate(prefetch_iterator); - Relation prefetchRel = scan->rs_rd; - if (tbmpre == NULL) { - /* No more pages to prefetch */ - tbm_end_iterate(prefetch_iterator); - node->prefetch_iterator = prefetch_iterator = NULL; - break; - } - node->prefetch_pages++; - if (tbm_is_global(node->tbm) && GPIScanCheckPartOid(node->gpi_scan, tbmpre->partitionOid)) { - GPISetCurrPartOid(node->gpi_scan, tbmpre->partitionOid); - if (!GPIGetNextPartRelation(node->gpi_scan, CurrentMemoryContext, AccessShareLock)) { - /* If the current partition is invalid, the next page is directly processed */ - tbmpre = NULL; - continue; - } else { - prefetchRel = node->gpi_scan->fakePartRelation; - } - } - /* For posix_fadvise() we just send the one request */ - PrefetchBuffer(prefetchRel, MAIN_FORKNUM, tbmpre->blockno); - } - /* recover old oid after prefetch switch */ - GPISetCurrPartOid(node->gpi_scan, oldOid); - } - ADIO_END(); - } + BitmapHeapPrefetchNext(node, scan, tbm, &prefetch_iterator); #endif /* USE_PREFETCH */ /* @@ -908,3 +794,127 @@ static void ExecInitPartitionForBitmapHeapScan(BitmapHeapScanState* scanstate, E } } } + +/* + * We issue prefetch requests *after* fetching the current page to try + * to avoid having prefetching interfere with the main I/O. Also, this + * should happen only when we have determined there is still something + * to do on the current page, else we may uselessly prefetch the same + * page we are just about to request for real. + */ +void BitmapHeapPrefetchNext( + BitmapHeapScanState* node, HeapScanDesc scan, const TIDBitmap* tbm, TBMIterator** prefetch_iterator) +{ + if (*prefetch_iterator == NULL) { + return; + } + ADIO_RUN() + { + BlockNumber* blockList = NULL; + BlockNumber* blockListPtr = NULL; + PrefetchNode* prefetchNode = NULL; + PrefetchNode* prefetchNodePtr = NULL; + int prefetchNow = 0; + int prefetchWindow = node->prefetch_target - node->prefetch_pages; + + /* We expect to prefetch at most prefetchWindow pages */ + if (prefetchWindow > 0) { + if (tbm_is_global(tbm)) { + prefetchNode = (PrefetchNode*)malloc(sizeof(PrefetchNode) * prefetchWindow); + prefetchNodePtr = prefetchNode; + } + blockList = (BlockNumber*)palloc(sizeof(BlockNumber) * prefetchWindow); + blockListPtr = blockList; + } + while (node->prefetch_pages < node->prefetch_target) { + TBMIterateResult* tbmpre = tbm_iterate(*prefetch_iterator); + + if (tbmpre == NULL) { + /* No more pages to prefetch */ + tbm_end_iterate(*prefetch_iterator); + node->prefetch_iterator = *prefetch_iterator = NULL; + break; + } + node->prefetch_pages++; + /* we use PrefetchNode here to store relations between blockno and partition Oid */ + if (tbm_is_global(tbm)) { + prefetchNodePtr->blockNum = tbmpre->blockno; + prefetchNodePtr->partOid = tbmpre->partitionOid; + prefetchNodePtr++; + } + /* For Async Direct I/O we accumulate a list and send it */ + *blockListPtr++ = tbmpre->blockno; + prefetchNow++; + } + + /* Send the list we generated and free it */ + if (prefetchNow) { + if (tbm_is_global(tbm)) { + /* + * we must save part Oid before switch relation, and recover it after prefetch. + * The reason for this is to assure correctness while getting a new tbmres. + */ + Oid oldOid = GPIGetCurrPartOid(node->gpi_scan); + int blkCount = 0; + Oid prevOid = prefetchNode[0].partOid; + for (int i = 0; i < prefetchNow; i++) { + if (prefetchNode[i].partOid == prevOid) { + blockList[blkCount++] = prefetchNode[i].blockNum; + } else { + GPISetCurrPartOid(node->gpi_scan, prevOid); + if (GPIGetNextPartRelation(node->gpi_scan, CurrentMemoryContext, AccessShareLock)) { + PageListPrefetch(node->gpi_scan->fakePartRelation, MAIN_FORKNUM, blockList, blkCount, 0, 0); + } + blkCount = 0; + prevOid = prefetchNode[i].partOid; + blockList[blkCount++] = prefetchNode[i].blockNum; + } + } + GPISetCurrPartOid(node->gpi_scan, prevOid); + if (GPIGetNextPartRelation(node->gpi_scan, CurrentMemoryContext, AccessShareLock)) { + PageListPrefetch(node->gpi_scan->fakePartRelation, MAIN_FORKNUM, blockList, blkCount, 0, 0); + } + /* recover old oid after prefetch switch */ + GPISetCurrPartOid(node->gpi_scan, oldOid); + } else { + PageListPrefetch(scan->rs_rd, MAIN_FORKNUM, blockList, prefetchNow, 0, 0); + } + } + if (prefetchWindow > 0) { + pfree_ext(blockList); + if (tbm_is_global(tbm)) { + pfree_ext(prefetchNode); + } + } + } + ADIO_ELSE() + { + Oid oldOid = GPIGetCurrPartOid(node->gpi_scan); + while (node->prefetch_pages < node->prefetch_target) { + TBMIterateResult* tbmpre = tbm_iterate(*prefetch_iterator); + Relation prefetchRel = scan->rs_rd; + if (tbmpre == NULL) { + /* No more pages to prefetch */ + tbm_end_iterate(*prefetch_iterator); + node->prefetch_iterator = *prefetch_iterator = NULL; + break; + } + node->prefetch_pages++; + if (tbm_is_global(node->tbm) && GPIScanCheckPartOid(node->gpi_scan, tbmpre->partitionOid)) { + GPISetCurrPartOid(node->gpi_scan, tbmpre->partitionOid); + if (!GPIGetNextPartRelation(node->gpi_scan, CurrentMemoryContext, AccessShareLock)) { + /* If the current partition is invalid, the next page is directly processed */ + tbmpre = NULL; + continue; + } else { + prefetchRel = node->gpi_scan->fakePartRelation; + } + } + /* For posix_fadvise() we just send the one request */ + PrefetchBuffer(prefetchRel, MAIN_FORKNUM, tbmpre->blockno); + } + /* recover old oid after prefetch switch */ + GPISetCurrPartOid(node->gpi_scan, oldOid); + } + ADIO_END(); +} diff --git a/src/gausskernel/storage/access/gin/ginget.cpp b/src/gausskernel/storage/access/gin/ginget.cpp index 50fba3a9c..d7a004143 100755 --- a/src/gausskernel/storage/access/gin/ginget.cpp +++ b/src/gausskernel/storage/access/gin/ginget.cpp @@ -1582,6 +1582,7 @@ static void scanPendingInsert(IndexScanDesc scan, TIDBitmap* tbm, int64* ntids) pendingPosition pos; Buffer metabuffer = ReadBuffer(scan->indexRelation, GIN_METAPAGE_BLKNO); BlockNumber blkno; + Oid partHeapOid = IndexScanGetPartHeapOid(scan); *ntids = 0; @@ -1640,7 +1641,7 @@ static void scanPendingInsert(IndexScanDesc scan, TIDBitmap* tbm, int64* ntids) MemoryContextReset(so->tempCtx); if (match) { - tbm_add_tuples(tbm, &pos.item, 1, recheck); + tbm_add_tuples(tbm, &pos.item, 1, recheck, partHeapOid); (*ntids)++; } } @@ -1664,6 +1665,7 @@ Datum gingetbitmap(PG_FUNCTION_ARGS) int64 ntids; ItemPointerData iptr; bool recheck = false; + Oid partHeapOid = IndexScanGetPartHeapOid(scan); /* * Set up the scan keys, and check for unsatisfiable query. @@ -1702,9 +1704,9 @@ Datum gingetbitmap(PG_FUNCTION_ARGS) break; if (ItemPointerIsLossyPage(&iptr)) - tbm_add_page(tbm, ItemPointerGetBlockNumber(&iptr)); + tbm_add_page(tbm, ItemPointerGetBlockNumber(&iptr), partHeapOid); else - tbm_add_tuples(tbm, &iptr, 1, recheck); + tbm_add_tuples(tbm, &iptr, 1, recheck, partHeapOid); ntids++; } diff --git a/src/gausskernel/storage/access/gist/gistget.cpp b/src/gausskernel/storage/access/gist/gistget.cpp index 051657603..38ab6f9fc 100644 --- a/src/gausskernel/storage/access/gist/gistget.cpp +++ b/src/gausskernel/storage/access/gist/gistget.cpp @@ -215,6 +215,7 @@ static void gistScanPage(IndexScanDesc scan, const GISTSearchItem *pageItem, con bool isNew = false; MemoryContext oldcxt; errno_t ret = EOK; + Oid partHeapOid = IndexScanGetPartHeapOid(scan); Assert(!GISTSearchItemIsHeap(*pageItem)); @@ -290,7 +291,7 @@ static void gistScanPage(IndexScanDesc scan, const GISTSearchItem *pageItem, con * getbitmap scan, so just push heap tuple TIDs into the bitmap * without worrying about ordering */ - tbm_add_tuples(tbm, &it->t_tid, 1, recheck); + tbm_add_tuples(tbm, &it->t_tid, 1, recheck, partHeapOid); (*ntids)++; } else if (scan->numberOfOrderBys == 0 && GistPageIsLeaf(page)) { /* diff --git a/src/gausskernel/storage/access/hash/hash.cpp b/src/gausskernel/storage/access/hash/hash.cpp index d3782b43d..a8b80203a 100644 --- a/src/gausskernel/storage/access/hash/hash.cpp +++ b/src/gausskernel/storage/access/hash/hash.cpp @@ -303,6 +303,7 @@ Datum hashgetbitmap(PG_FUNCTION_ARGS) HashScanOpaque so = (HashScanOpaque)scan->opaque; bool res = false; int64 ntids = 0; + Oid partHeapOid = IndexScanGetPartHeapOid(scan); res = _hash_first(scan, ForwardScanDirection); @@ -325,7 +326,7 @@ Datum hashgetbitmap(PG_FUNCTION_ARGS) /* Save tuple ID, and continue scanning */ if (add_tuple) { /* Note we mark the tuple ID as requiring recheck */ - tbm_add_tuples(tbm, &(so->hashso_heappos), 1, true); + tbm_add_tuples(tbm, &(so->hashso_heappos), 1, true, partHeapOid); ntids++; } diff --git a/src/gausskernel/storage/access/index/genam.cpp b/src/gausskernel/storage/access/index/genam.cpp index 1c49f1347..b980a6fe8 100755 --- a/src/gausskernel/storage/access/index/genam.cpp +++ b/src/gausskernel/storage/access/index/genam.cpp @@ -664,6 +664,7 @@ bool GPIGetNextPartRelation(GPIScanDesc gpiScan, MemoryContext cxt, LOCKMODE lmo if (bms_is_member(gpiScan->currPartOid, gpiScan->invisiblePartMap)) { gpiScan->fakePartRelation = NULL; gpiScan->partition = NULL; + gpiScan->currPartOid = InvalidOid; return false; } @@ -679,6 +680,7 @@ bool GPIGetNextPartRelation(GPIScanDesc gpiScan, MemoryContext cxt, LOCKMODE lmo if (currStatus == PART_METADATA_INVISIBLE) { /* If current partition metadata is invisible, add current partition oid into invisiblePartMap */ gpiScan->invisiblePartMap = bms_add_member(gpiScan->invisiblePartMap, gpiScan->currPartOid); + gpiScan->currPartOid = InvalidOid; result = false; } else { /* If current partition metadata is invisible, add current partition oid into fakeRelationTable */ diff --git a/src/gausskernel/storage/access/nbtree/nbtinsert.cpp b/src/gausskernel/storage/access/nbtree/nbtinsert.cpp index 6f4d4cfad..d9ccb9403 100644 --- a/src/gausskernel/storage/access/nbtree/nbtinsert.cpp +++ b/src/gausskernel/storage/access/nbtree/nbtinsert.cpp @@ -411,7 +411,6 @@ static TransactionId _bt_check_unique(Relation rel, IndexTuple itup, Relation he * everyone, so we may as well mark the index entry * killed. */ - /* okay, we gotta fetch the heap tuple ... */ ItemIdMarkDead(curitemid); opaque->btpo_flags |= BTP_HAS_GARBAGE; diff --git a/src/gausskernel/storage/access/spgist/spgscan.cpp b/src/gausskernel/storage/access/spgist/spgscan.cpp index cec0fdc7b..fb5d9e3bb 100644 --- a/src/gausskernel/storage/access/spgist/spgscan.cpp +++ b/src/gausskernel/storage/access/spgist/spgscan.cpp @@ -497,7 +497,7 @@ static void spgWalk(Relation index, SpGistScanOpaque so, bool scanWholeIndex, st /* storeRes subroutine for getbitmap case */ static void storeBitmap(SpGistScanOpaque so, ItemPointer heapPtr, Datum leafValue, bool isnull, bool recheck) { - tbm_add_tuples(so->tbm, heapPtr, 1, recheck); + tbm_add_tuples(so->tbm, heapPtr, 1, recheck, so->partHeapOid); so->ntids++; } @@ -511,6 +511,7 @@ Datum spggetbitmap(PG_FUNCTION_ARGS) so->want_itup = false; so->tbm = tbm; so->ntids = 0; + so->partHeapOid = IndexScanGetPartHeapOid(scan); spgWalk(scan->indexRelation, so, true, storeBitmap); diff --git a/src/include/access/spgist_private.h b/src/include/access/spgist_private.h index d1605135d..acdae9b94 100755 --- a/src/include/access/spgist_private.h +++ b/src/include/access/spgist_private.h @@ -136,8 +136,9 @@ typedef struct SpGistScanOpaqueData { List* scanStack; /* List of ScanStackEntrys */ /* These fields are only used in amgetbitmap scans: */ - TIDBitmap* tbm; /* bitmap being filled */ - int64 ntids; /* number of TIDs passed to bitmap */ + TIDBitmap* tbm; /* bitmap being filled */ + int64 ntids; /* number of TIDs passed to bitmap */ + Oid partHeapOid; /* partition oid passed to bitmap */ /* These fields are only used in amgettuple scans: */ bool want_itup; /* are we reconstructing tuples? */ diff --git a/src/include/nodes/tidbitmap.h b/src/include/nodes/tidbitmap.h index 5f2942f1d..1440eb66b 100755 --- a/src/include/nodes/tidbitmap.h +++ b/src/include/nodes/tidbitmap.h @@ -49,7 +49,7 @@ extern void tbm_free(TIDBitmap* tbm); extern void tbm_add_tuples( TIDBitmap* tbm, const ItemPointer tids, int ntids, bool recheck, Oid partitionOid = InvalidOid); -extern void tbm_add_page(TIDBitmap* tbm, BlockNumber pageno); +extern void tbm_add_page(TIDBitmap* tbm, BlockNumber pageno, Oid partitionOid = InvalidOid); extern void tbm_union(TIDBitmap* a, const TIDBitmap* b); extern void tbm_intersect(TIDBitmap* a, const TIDBitmap* b); diff --git a/src/test/regress/expected/gpi_bitmapscan.out b/src/test/regress/expected/gpi_bitmapscan.out index 309eb2d5c..7886ef28d 100644 --- a/src/test/regress/expected/gpi_bitmapscan.out +++ b/src/test/regress/expected/gpi_bitmapscan.out @@ -227,3 +227,172 @@ ERROR: "idx1_gpi_bitmap_table2" is not a table HINT: Use DROP INDEX to remove an global partition index. SET enable_seqscan=on; SET enable_indexscan=on; +drop table if exists test_part_bitmapand_ginst_btree; +NOTICE: table "test_part_bitmapand_ginst_btree" does not exist, skipping +CREATE TABLE test_part_bitmapand_ginst_btree (a int, txtkeyword TEXT, txtsample TEXT) partition by range(a) (partition p1 values less than (1001), partition p2 values less than (2001), partition p3 values less than (3001)); +insert into test_part_bitmapand_ginst_btree values (10, $$'New York'$$, 'new & york | big & apple | nyc'); +insert into test_part_bitmapand_ginst_btree values (1010, 'Moscow', 'moskva | moscow'); +insert into test_part_bitmapand_ginst_btree values (1020, $$'Sanct Peter'$$, $$Peterburg | peter | 'Sanct Peterburg'$$); +insert into test_part_bitmapand_ginst_btree values (1030, $$'foo bar qq'$$, 'foo & (bar | qq) & city'); +ALTER TABLE test_part_bitmapand_ginst_btree ADD COLUMN keyword tsquery; +UPDATE test_part_bitmapand_ginst_btree SET keyword = to_tsquery('english', txtkeyword); +ALTER TABLE test_part_bitmapand_ginst_btree ADD COLUMN sample tsquery; +UPDATE test_part_bitmapand_ginst_btree SET sample = to_tsquery('english', txtsample::text); +CREATE UNIQUE INDEX ON test_part_bitmapand_ginst_btree (a) local; +-- failed +CREATE INDEX qq ON test_part_bitmapand_ginst_btree USING gist (keyword tsquery_ops); +ERROR: Global partition index only support btree. +CREATE INDEX qq ON test_part_bitmapand_ginst_btree USING gist (keyword tsquery_ops) local; +CREATE INDEX ON test_part_bitmapand_ginst_btree USING gist (keyword tsquery_ops); +ERROR: Global partition index only support btree. +explain (costs off) SELECT keyword FROM test_part_bitmapand_ginst_btree WHERE keyword @> 'new' and a = 10; + QUERY PLAN +-------------------------------------------------------------------------- + Partition Iterator + Iterations: 1 + -> Partitioned Index Scan using qq on test_part_bitmapand_ginst_btree + Index Cond: (keyword @> '''new'''::tsquery) + Filter: (a = 10) + Selected Partitions: 1 +(6 rows) + +SELECT keyword FROM test_part_bitmapand_ginst_btree WHERE keyword @> 'new' and a = 10; + keyword +---------------- + 'new' & 'york' +(1 row) + +set force_bitmapand = on; +set enable_seqscan = off; +set enable_indexscan = off; +--bitmapand scan +explain (costs off) SELECT keyword FROM test_part_bitmapand_ginst_btree WHERE keyword @> 'new' and a = 10; + QUERY PLAN +------------------------------------------------------------------------------------------ + Partition Iterator + Iterations: 1 + -> Partitioned Bitmap Heap Scan on test_part_bitmapand_ginst_btree + Recheck Cond: ((keyword @> '''new'''::tsquery) AND (a = 10)) + Selected Partitions: 1 + -> BitmapAnd + -> Partitioned Bitmap Index Scan on qq + Index Cond: (keyword @> '''new'''::tsquery) + Selected Partitions: 1 + -> Partitioned Bitmap Index Scan on test_part_bitmapand_ginst_btree_a_idx + Index Cond: (a = 10) + Selected Partitions: 1 +(12 rows) + +SELECT keyword FROM test_part_bitmapand_ginst_btree WHERE keyword @> 'new' and a = 10; + keyword +---------------- + 'new' & 'york' +(1 row) + +drop index test_part_bitmapand_ginst_btree_a_idx; +CREATE UNIQUE INDEX ON test_part_bitmapand_ginst_btree (a); +--bitmapand scan +explain (costs off) SELECT keyword FROM test_part_bitmapand_ginst_btree WHERE keyword @> 'new' and a = 10; + QUERY PLAN +----------------------------------------------------------------------- + Partition Iterator + Iterations: 1 + -> Partitioned Bitmap Heap Scan on test_part_bitmapand_ginst_btree + Recheck Cond: (keyword @> '''new'''::tsquery) + Filter: (a = 10) + Selected Partitions: 1 + -> Partitioned Bitmap Index Scan on qq + Index Cond: (keyword @> '''new'''::tsquery) + Selected Partitions: 1 +(9 rows) + +SELECT keyword FROM test_part_bitmapand_ginst_btree WHERE keyword @> 'new' and a = 10; + keyword +---------------- + 'new' & 'york' +(1 row) + +drop table if exists test_part_bitmapand_gin_btree; +NOTICE: table "test_part_bitmapand_gin_btree" does not exist, skipping +create table test_part_bitmapand_gin_btree (a int, ts tsvector) partition by range(a) (partition p1 values less than (1001), partition p2 values less than (2001), partition p3 values less than (3001)); +insert into test_part_bitmapand_gin_btree values (10, to_tsvector('Lore ipsam')); +insert into test_part_bitmapand_gin_btree values (1010, to_tsvector('Lore ipsum')); +create index test_part_bitmapand_gin_btree_idx on test_part_bitmapand_gin_btree using gin(ts) local; +create index test_part_bitmapand_gin_btree_idx_a on test_part_bitmapand_gin_btree using btree(a) local; +set force_bitmapand = on; +set enable_seqscan = off; +set enable_indexscan = off; +explain (costs off) select * from test_part_bitmapand_gin_btree where 'ipsu:*'::tsquery @@ ts and a = 10; + QUERY PLAN +---------------------------------------------------------------------------------------- + Partition Iterator + Iterations: 1 + -> Partitioned Bitmap Heap Scan on test_part_bitmapand_gin_btree + Recheck Cond: ((a = 10) AND ('''ipsu'':*'::tsquery @@ ts)) + Selected Partitions: 1 + -> BitmapAnd + -> Partitioned Bitmap Index Scan on test_part_bitmapand_gin_btree_idx_a + Index Cond: (a = 10) + Selected Partitions: 1 + -> Partitioned Bitmap Index Scan on test_part_bitmapand_gin_btree_idx + Index Cond: ('''ipsu'':*'::tsquery @@ ts) + Selected Partitions: 1 +(12 rows) + +select * from test_part_bitmapand_gin_btree where 'ipsu:*'::tsquery @@ ts and a = 10; + a | ts +---+---- +(0 rows) + +explain (costs off) select * from test_part_bitmapand_gin_btree where 'ipsu:*'::tsquery @@ ts and a = 1010; + QUERY PLAN +---------------------------------------------------------------------------------------- + Partition Iterator + Iterations: 1 + -> Partitioned Bitmap Heap Scan on test_part_bitmapand_gin_btree + Recheck Cond: ((a = 1010) AND ('''ipsu'':*'::tsquery @@ ts)) + Selected Partitions: 2 + -> BitmapAnd + -> Partitioned Bitmap Index Scan on test_part_bitmapand_gin_btree_idx_a + Index Cond: (a = 1010) + Selected Partitions: 2 + -> Partitioned Bitmap Index Scan on test_part_bitmapand_gin_btree_idx + Index Cond: ('''ipsu'':*'::tsquery @@ ts) + Selected Partitions: 2 +(12 rows) + +select * from test_part_bitmapand_gin_btree where 'ipsu:*'::tsquery @@ ts and a = 1010; + a | ts +------+-------------------- + 1010 | 'ipsum':2 'lore':1 +(1 row) + +drop index test_part_bitmapand_gin_btree_idx_a; +create index test_part_bitmapand_gin_btree_idx_a on test_part_bitmapand_gin_btree using btree(a) global; +explain (costs off) select * from test_part_bitmapand_gin_btree where 'ipsu:*'::tsquery @@ ts and a = 1010; + QUERY PLAN +-------------------------------------------------------------------------------------- + Partition Iterator + Iterations: 1 + -> Partitioned Bitmap Heap Scan on test_part_bitmapand_gin_btree + Recheck Cond: ((a = 1010) AND ('''ipsu'':*'::tsquery @@ ts)) + Selected Partitions: 2 + -> BitmapAnd + -> Bitmap Index Scan on test_part_bitmapand_gin_btree_idx_a + Index Cond: (a = 1010) + -> Partitioned Bitmap Index Scan on test_part_bitmapand_gin_btree_idx + Index Cond: ('''ipsu'':*'::tsquery @@ ts) + Selected Partitions: 2 +(11 rows) + +select * from test_part_bitmapand_gin_btree where 'ipsu:*'::tsquery @@ ts and a = 1010; + a | ts +------+-------------------- + 1010 | 'ipsum':2 'lore':1 +(1 row) + +reset force_bitmapand; +reset enable_seqscan; +reset enable_indexscan; +drop table test_part_bitmapand_gin_btree; +drop table test_part_bitmapand_ginst_btree; \ No newline at end of file diff --git a/src/test/regress/expected/gpi_build_index.out b/src/test/regress/expected/gpi_build_index.out index fcf4f2a1f..e3dee897d 100644 --- a/src/test/regress/expected/gpi_build_index.out +++ b/src/test/regress/expected/gpi_build_index.out @@ -249,7 +249,7 @@ create table gpi_multi_cols(a0 int,a1 int,a2 int,a3 int,a4 int,a5 int,a6 int,a7 create index gpi_multi_cols_index on gpi_multi_cols(a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20,a21,a22,a23,a24,a25,a26,a27,a28,a29,a30) global; --failed create index gpi_multi_cols_index on gpi_multi_cols(a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20,a21,a22,a23,a24,a25,a26,a27,a28,a29,a30, a31) global; -ERROR: cannot use more than 32 columns in an index +ERROR: cannot use more than 31 columns in an global partition index --success create index gpi_multi_cols_index_local on gpi_multi_cols(a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20,a21,a22,a23,a24,a25,a26,a27,a28,a29,a30, a31) local; insert into gpi_multi_cols select r,r,r,r,r,r,r,r,r,r,r,r,r,r,r,r,r,r,r,r,r,r,r,r,r,r,r,r,r,r,r,r,r from generate_series(1,3000) as r; diff --git a/src/test/regress/sql/gpi_bitmapscan.sql b/src/test/regress/sql/gpi_bitmapscan.sql index 92b47a347..4a3081081 100644 --- a/src/test/regress/sql/gpi_bitmapscan.sql +++ b/src/test/regress/sql/gpi_bitmapscan.sql @@ -78,4 +78,69 @@ SELECT * FROM gpi_bitmap_table2 WHERE c1 = 10000 OR c2 = 30000; DROP TABLE idx1_gpi_bitmap_table1; DROP TABLE idx1_gpi_bitmap_table2; SET enable_seqscan=on; -SET enable_indexscan=on; \ No newline at end of file +SET enable_indexscan=on; + +drop table if exists test_part_bitmapand_ginst_btree; +CREATE TABLE test_part_bitmapand_ginst_btree (a int, txtkeyword TEXT, txtsample TEXT) partition by range(a) (partition p1 values less than (1001), partition p2 values less than (2001), partition p3 values less than (3001)); +insert into test_part_bitmapand_ginst_btree values (10, $$'New York'$$, 'new & york | big & apple | nyc'); +insert into test_part_bitmapand_ginst_btree values (1010, 'Moscow', 'moskva | moscow'); +insert into test_part_bitmapand_ginst_btree values (1020, $$'Sanct Peter'$$, $$Peterburg | peter | 'Sanct Peterburg'$$); +insert into test_part_bitmapand_ginst_btree values (1030, $$'foo bar qq'$$, 'foo & (bar | qq) & city'); + +ALTER TABLE test_part_bitmapand_ginst_btree ADD COLUMN keyword tsquery; +UPDATE test_part_bitmapand_ginst_btree SET keyword = to_tsquery('english', txtkeyword); +ALTER TABLE test_part_bitmapand_ginst_btree ADD COLUMN sample tsquery; +UPDATE test_part_bitmapand_ginst_btree SET sample = to_tsquery('english', txtsample::text); + +CREATE UNIQUE INDEX ON test_part_bitmapand_ginst_btree (a) local; +-- failed +CREATE INDEX qq ON test_part_bitmapand_ginst_btree USING gist (keyword tsquery_ops); +CREATE INDEX qq ON test_part_bitmapand_ginst_btree USING gist (keyword tsquery_ops) local; + +CREATE INDEX ON test_part_bitmapand_ginst_btree USING gist (keyword tsquery_ops); + +explain (costs off) SELECT keyword FROM test_part_bitmapand_ginst_btree WHERE keyword @> 'new' and a = 10; +SELECT keyword FROM test_part_bitmapand_ginst_btree WHERE keyword @> 'new' and a = 10; + +set force_bitmapand = on; +set enable_seqscan = off; +set enable_indexscan = off; + +--bitmapand scan +explain (costs off) SELECT keyword FROM test_part_bitmapand_ginst_btree WHERE keyword @> 'new' and a = 10; +SELECT keyword FROM test_part_bitmapand_ginst_btree WHERE keyword @> 'new' and a = 10; + +drop index test_part_bitmapand_ginst_btree_a_idx; +CREATE UNIQUE INDEX ON test_part_bitmapand_ginst_btree (a); + +--bitmapand scan +explain (costs off) SELECT keyword FROM test_part_bitmapand_ginst_btree WHERE keyword @> 'new' and a = 10; +SELECT keyword FROM test_part_bitmapand_ginst_btree WHERE keyword @> 'new' and a = 10; + +drop table if exists test_part_bitmapand_gin_btree; +create table test_part_bitmapand_gin_btree (a int, ts tsvector) partition by range(a) (partition p1 values less than (1001), partition p2 values less than (2001), partition p3 values less than (3001)); +insert into test_part_bitmapand_gin_btree values (10, to_tsvector('Lore ipsam')); +insert into test_part_bitmapand_gin_btree values (1010, to_tsvector('Lore ipsum')); +create index test_part_bitmapand_gin_btree_idx on test_part_bitmapand_gin_btree using gin(ts) local; +create index test_part_bitmapand_gin_btree_idx_a on test_part_bitmapand_gin_btree using btree(a) local; + +set force_bitmapand = on; +set enable_seqscan = off; +set enable_indexscan = off; +explain (costs off) select * from test_part_bitmapand_gin_btree where 'ipsu:*'::tsquery @@ ts and a = 10; +select * from test_part_bitmapand_gin_btree where 'ipsu:*'::tsquery @@ ts and a = 10; + +explain (costs off) select * from test_part_bitmapand_gin_btree where 'ipsu:*'::tsquery @@ ts and a = 1010; +select * from test_part_bitmapand_gin_btree where 'ipsu:*'::tsquery @@ ts and a = 1010; + +drop index test_part_bitmapand_gin_btree_idx_a; +create index test_part_bitmapand_gin_btree_idx_a on test_part_bitmapand_gin_btree using btree(a) global; +explain (costs off) select * from test_part_bitmapand_gin_btree where 'ipsu:*'::tsquery @@ ts and a = 1010; +select * from test_part_bitmapand_gin_btree where 'ipsu:*'::tsquery @@ ts and a = 1010; + +reset force_bitmapand; +reset enable_seqscan; +reset enable_indexscan; + +drop table test_part_bitmapand_gin_btree; +drop table test_part_bitmapand_ginst_btree; \ No newline at end of file