From 8a87c14084cee2f574203f099878d2ac286d10ac Mon Sep 17 00:00:00 2001 From: yujiang Date: Tue, 28 Jul 2020 09:28:46 +0800 Subject: [PATCH] [patch] support interval partition table --- src/common/backend/catalog/heap.cpp | 436 ++++++++++++++++-- src/common/backend/catalog/pg_partition.cpp | 13 +- src/common/backend/parser/parse_utilcmd.cpp | 64 ++- src/common/backend/utils/adt/dbsize.cpp | 1 + src/common/backend/utils/adt/timestamp.cpp | 70 ++- src/common/backend/utils/cache/partcache.cpp | 30 ++ .../cbb/utils/partition/partitionmap.cpp | 301 ++++++++---- .../optimizer/commands/tablecmds.cpp | 113 ++++- src/gausskernel/optimizer/commands/vacuum.cpp | 2 +- src/gausskernel/optimizer/util/plancat.cpp | 23 +- src/gausskernel/optimizer/util/pruning.cpp | 50 +- .../runtime/executor/nodeModifyTable.cpp | 4 +- .../storage/access/heap/heapam.cpp | 13 +- .../storage/cstore/cstore_rewrite.cpp | 2 - src/gausskernel/storage/lmgr/lmgr.cpp | 33 +- src/include/catalog/heap.h | 3 +- src/include/catalog/pg_partition_fn.h | 7 +- src/include/commands/tablecmds.h | 3 +- src/include/utils/partcache.h | 3 + src/include/utils/partitionmap.h | 4 +- src/include/utils/partitionmap_gs.h | 94 ++-- src/include/utils/timestamp.h | 4 + .../regress/expected/hw_partition_cross.out | 2 +- .../hw_partition_interval_exchange.out | 217 +++++++++ .../expected/hw_partition_interval_index.out | 426 +++++++++++++++++ .../hw_partition_interval_movement.out | 106 +++++ .../hw_partition_interval_parallel_end.out | 25 + .../hw_partition_interval_parallel_insert.out | 58 +++ ..._partition_interval_parallel_insert_01.out | 56 +++ ..._partition_interval_parallel_insert_02.out | 56 +++ ...hw_partition_interval_parallel_prepare.out | 21 + .../hw_partition_interval_reindex.out | 168 +++++++ .../expected/hw_partition_interval_select.out | 145 ++++++ .../hw_partition_interval_unusable_index.out | 409 ++++++++++++++++ .../regress/expected/hw_partition_nodes.out | 15 +- .../input/hw_partition_insert_01.source | 10 - .../input/hw_partition_interval.source | 229 +++++++++ .../output/hw_partition_insert_01.source | 51 +- .../output/hw_partition_interval.source | 428 +++++++++++++++++ .../output/hw_partition_sql_adapt0.source | 4 +- .../output/hw_partition_sql_adapt2.source | 15 +- src/test/regress/parallel_schedule18 | 25 + .../sql/hw_partition_interval_exchange.sql | 99 ++++ .../sql/hw_partition_interval_index.sql | 336 ++++++++++++++ .../sql/hw_partition_interval_movement.sql | 64 +++ .../hw_partition_interval_parallel_end.sql | 7 + .../hw_partition_interval_parallel_insert.sql | 23 + ..._partition_interval_parallel_insert_01.sql | 23 + ..._partition_interval_parallel_insert_02.sql | 23 + ...hw_partition_interval_parallel_prepare.sql | 20 + .../sql/hw_partition_interval_reindex.sql | 65 +++ .../sql/hw_partition_interval_select.sql | 54 +++ .../hw_partition_interval_unusable_index.sql | 256 ++++++++++ 53 files changed, 4325 insertions(+), 384 deletions(-) mode change 100755 => 100644 src/common/backend/catalog/pg_partition.cpp mode change 100755 => 100644 src/gausskernel/cbb/utils/partition/partitionmap.cpp create mode 100644 src/test/regress/expected/hw_partition_interval_exchange.out create mode 100644 src/test/regress/expected/hw_partition_interval_index.out create mode 100644 src/test/regress/expected/hw_partition_interval_movement.out create mode 100644 src/test/regress/expected/hw_partition_interval_parallel_end.out create mode 100644 src/test/regress/expected/hw_partition_interval_parallel_insert.out create mode 100644 src/test/regress/expected/hw_partition_interval_parallel_insert_01.out create mode 100644 src/test/regress/expected/hw_partition_interval_parallel_insert_02.out create mode 100644 src/test/regress/expected/hw_partition_interval_parallel_prepare.out create mode 100644 src/test/regress/expected/hw_partition_interval_reindex.out create mode 100644 src/test/regress/expected/hw_partition_interval_select.out create mode 100644 src/test/regress/expected/hw_partition_interval_unusable_index.out create mode 100644 src/test/regress/input/hw_partition_interval.source create mode 100644 src/test/regress/output/hw_partition_interval.source create mode 100644 src/test/regress/parallel_schedule18 create mode 100644 src/test/regress/sql/hw_partition_interval_exchange.sql create mode 100644 src/test/regress/sql/hw_partition_interval_index.sql create mode 100644 src/test/regress/sql/hw_partition_interval_movement.sql create mode 100644 src/test/regress/sql/hw_partition_interval_parallel_end.sql create mode 100644 src/test/regress/sql/hw_partition_interval_parallel_insert.sql create mode 100644 src/test/regress/sql/hw_partition_interval_parallel_insert_01.sql create mode 100644 src/test/regress/sql/hw_partition_interval_parallel_insert_02.sql create mode 100644 src/test/regress/sql/hw_partition_interval_parallel_prepare.sql create mode 100644 src/test/regress/sql/hw_partition_interval_reindex.sql create mode 100644 src/test/regress/sql/hw_partition_interval_select.sql create mode 100644 src/test/regress/sql/hw_partition_interval_unusable_index.sql diff --git a/src/common/backend/catalog/heap.cpp b/src/common/backend/catalog/heap.cpp index d3533450dc..0e7bcaca38 100755 --- a/src/common/backend/catalog/heap.cpp +++ b/src/common/backend/catalog/heap.cpp @@ -31,6 +31,7 @@ #include "postgres.h" #include "knl/knl_variable.h" +#include "access/reloptions.h" #include "access/sysattr.h" #include "access/transam.h" #include "access/xact.h" @@ -110,7 +111,7 @@ static void AddNewRelationTuple(Relation pg_class_desc, Relation new_rel_desc, Oid new_rel_oid, Oid new_type_oid, Oid reloftype, Oid relowner, char relkind, Datum relacl, Datum reloptions, int2vector* bucketcol, bool ispartrel); -static oidvector* buldIntervalTablespace(IntervalPartitionDefState* intervalPartDef); +static oidvector* BuildIntervalTablespace(const IntervalPartitionDefState* intervalPartDef); static void deletePartitionTuple(Oid part_id); static void addNewPartitionTuplesForPartition(Relation pg_partition_rel, Oid relid, List *filenodelist, Oid reltablespace, Oid bucketOid, PartitionState* partTableState, Oid ownerid, Datum reloptions, const TupleDesc tupledesc); @@ -4087,7 +4088,6 @@ int2vector* buildPartitionKey(List* keys, TupleDesc tupledsc) columName = ((Value*)linitial(col->fields))->val.str; finded = false; for (j = 0; j < attnum; j++) { - if (strcmp(columName, attrs[j]->attname.data) == 0) { partkey->values[i] = attrs[j]->attnum; finded = true; @@ -4106,16 +4106,44 @@ int2vector* buildPartitionKey(List* keys, TupleDesc tupledsc) return partkey; } -/* - * @@GaussDB@@ - * Target : data partition - * Brief : - * Description : - * Notes : - */ -static oidvector* buldIntervalTablespace(IntervalPartitionDefState* intervalPartDef) +static oidvector* BuildIntervalTablespace(const IntervalPartitionDefState* intervalPartDef) { - return (oidvector*)NULL; + if (intervalPartDef->intervalTablespaces == NULL || intervalPartDef->intervalTablespaces->length == 0) { + return NULL; + } + oidvector* tablespaceVec = buildoidvector(NULL, intervalPartDef->intervalTablespaces->length); + ListCell* cell = NULL; + int i = 0; + const char* tablespaceName; + Oid tableSpaceOid; + AclResult aclresult; + + foreach (cell, intervalPartDef->intervalTablespaces) { + tablespaceName = ((Value*)lfirst(cell))->val.str; + tableSpaceOid = get_tablespace_oid(tablespaceName, false); + + if (tableSpaceOid != u_sess->proc_cxt.MyDatabaseTableSpace) { + aclresult = pg_tablespace_aclcheck(tableSpaceOid, GetUserId(), ACL_CREATE); + if (aclresult != ACLCHECK_OK) { + aclcheck_error(aclresult, ACL_KIND_TABLESPACE, tablespaceName); + } + } + tablespaceVec->values[i] = tableSpaceOid; + i++; + } + return tablespaceVec; +} + +static Datum BuildInterval(Node* partInterval) +{ + Assert(IsA(partInterval, A_Const)); + A_Const* constNode = (A_Const*)partInterval; + Assert(IsA(&constNode->val, String)); + + ArrayBuildState* astate = NULL; + astate = accumArrayResult( + astate, PointerGetDatum(cstring_to_text(constNode->val.val.str)), false, TEXTOID, CurrentMemoryContext); + return makeArrayResult(astate, CurrentMemoryContext); } /* @@ -4702,7 +4730,7 @@ Oid heapAddRangePartition(Relation pgPartRel, Oid partTableOid, Oid partrelfileO } } - /*create partition */ + /* create partition */ if (!OidIsValid(partrelfileOid) && u_sess->proc_cxt.IsBinaryUpgrade && binary_upgrade_is_next_part_pg_partition_oid_valid()) { newPartitionOid = binary_upgrade_get_next_part_pg_partition_oid(); @@ -4710,7 +4738,7 @@ Oid heapAddRangePartition(Relation pgPartRel, Oid partTableOid, Oid partrelfileO } else if (!OidIsValid(partrelfileOid)) { newPartitionOid = GetNewRelFileNode(newPartitionTableSpaceOid, pgPartRel, - RELPERSISTENCE_PERMANENT); /* partition's persistence only can be 'p'(permanent table)*/ + RELPERSISTENCE_PERMANENT); /* partition's persistence only can be 'p'(permanent table) */ } else { Assert(t_thrd.xact_cxt.inheritFileNode); ereport(NOTICE, @@ -4742,14 +4770,14 @@ Oid heapAddRangePartition(Relation pgPartRel, Oid partTableOid, Oid partrelfileO newPartition->pd_part->relcudescidx = InvalidOid; newPartition->pd_part->indisusable = true; - /*step 3: insert into pg_partition tuple*/ + /* step 3: insert into pg_partition tuple */ addNewPartitionTuple(pgPartRel, /* RelationData pointer for pg_partition */ newPartition, /* PartitionData pointer for partition */ NULL, /* */ NULL, - (Datum)0, /*interval*/ - boundaryValue, /*max values */ - (Datum)0, /*transition point*/ + (Datum)0, /* interval*/ + boundaryValue, /* max values */ + (Datum)0, /* transition point */ reloptions); relation = relation_open(partTableOid, NoLock); @@ -4760,6 +4788,353 @@ Oid heapAddRangePartition(Relation pgPartRel, Oid partTableOid, Oid partrelfileO return newPartitionOid; } +#define IsDigital(_ch) (((_ch) >= '0') && ((_ch) <= '9')) + +static unsigned ExtractIntervalPartNameSuffix(const char* partName) +{ + if (partName == NULL) { + return 0; + } + + size_t len = strlen(partName); + size_t constPartLen = strlen(INTERVAL_PARTITION_NAME_PREFIX); + /* 5 is length of MAX_PARTITION_NUM */ + if (len <= constPartLen || len > constPartLen + INTERVAL_PARTITION_NAME_SUFFIX_LEN) { + return 0; + } + + if (strncmp(partName, INTERVAL_PARTITION_NAME_PREFIX, constPartLen) != 0) { + return 0; + } + + for (size_t i = constPartLen; i < len; ++i) { + if (!IsDigital(partName[i])) { + return 0; + } + } + + return (unsigned)atoi(partName + constPartLen); +} + +int RangeElementOidCmp(const void* a, const void* b) +{ + const RangeElement* rea = (const RangeElement*)a; + const RangeElement* reb = (const RangeElement*)b; + + if (rea->partitionOid < reb->partitionOid) { + return 1; + } + + if (rea->partitionOid == reb->partitionOid) { + return 0; + } + + return -1; +} + +char* GenIntervalPartitionName(Relation rel) +{ + unsigned suffix = 0; + Oid existingPartOid; + RangePartitionMap* partMap = (RangePartitionMap*)rel->partMap; + RangeElement* eles = CopyRangeElementsWithoutBoundary(partMap->rangeElements, partMap->rangeElementsNum); + /* sort desc by oid */ + qsort(eles, partMap->rangeElementsNum, sizeof(RangeElement), RangeElementOidCmp); + for (int i = 0; i < partMap->rangeElementsNum; ++i) { + /* merge or split may result in range oid bigger than interval range oid */ + if (!eles[i].isInterval) { + continue; + } + + char* name = PartitionOidGetName(eles[i].partitionOid); + if ((suffix = ExtractIntervalPartNameSuffix(name)) != 0) { + pfree(name); + break; + } + } + pfree(eles); + + char* partName = (char*)palloc0(NAMEDATALEN); + error_t rc; + while (true) { + ++suffix; + suffix = (suffix % MAX_PARTITION_NUM == 0 ? MAX_PARTITION_NUM : suffix % MAX_PARTITION_NUM); + rc = snprintf_s(partName, NAMEDATALEN, NAMEDATALEN - 1, INTERVAL_PARTITION_NAME_PREFIX_FMT, suffix); + securec_check_ss(rc, "\0", "\0"); + existingPartOid = partitionNameGetPartitionOid( + rel->rd_id, partName, PART_OBJ_TYPE_TABLE_PARTITION, AccessExclusiveLock, true, false, NULL, NULL, NoLock); + if (!OidIsValid(existingPartOid)) { + return partName; + } + } +} + +Oid GetRecentUsedTablespace(Relation rel) +{ + RangePartitionMap* partMap = (RangePartitionMap*)rel->partMap; + Assert(partMap->rangeElementsNum >= 1); + RangeElement* maxOidEle = &partMap->rangeElements[0]; + for (int i = 1; i < partMap->rangeElementsNum; ++i) { + if (partMap->rangeElements[i].partitionOid > maxOidEle->partitionOid) { + maxOidEle = &partMap->rangeElements[i]; + } + } + + /* no interval partition yet */ + if (!maxOidEle->isInterval) { + return InvalidOid; + } + return PartitionOidGetTablespace(maxOidEle->partitionOid); +} + +Oid ChooseIntervalTablespace(Relation rel) +{ + const oidvector* tablespaceVec = ((RangePartitionMap*)rel->partMap)->intervalTablespace; + Assert(tablespaceVec->dim1 >= 1); + if (tablespaceVec->dim1 == 1) { + return tablespaceVec->values[0]; + } + + const Oid recentUsed = GetRecentUsedTablespace(rel); + if (!OidIsValid(recentUsed)) { + return tablespaceVec->values[0]; + } + + int i = 0; + for (; i < tablespaceVec->dim1; ++i) { + if (tablespaceVec->values[i] == recentUsed) { + break; + } + } + + return tablespaceVec->values[(i + 1) % tablespaceVec->dim1]; +} + +Oid HeapAddIntervalPartition(Relation pgPartRel, Relation rel, Oid partTableOid, Oid partrelfileOid, Oid partTablespace, + Oid bucketOid, Datum boundaryValue, Oid ownerid, Datum reloptions) +{ + Oid newPartitionOid = InvalidOid; + Oid newPartitionTableSpaceOid = InvalidOid; + Relation relation; + Partition newPartition; + + if (((RangePartitionMap*)rel->partMap)->intervalTablespace != NULL) { + newPartitionTableSpaceOid = ChooseIntervalTablespace(rel); + } + + if (!OidIsValid(newPartitionTableSpaceOid)) { + newPartitionTableSpaceOid = partTablespace; + } + + /* Check permissions except when using database's default */ + if (OidIsValid(newPartitionTableSpaceOid) && newPartitionTableSpaceOid != u_sess->proc_cxt.MyDatabaseTableSpace) { + AclResult aclresult = pg_tablespace_aclcheck(newPartitionTableSpaceOid, GetUserId(), ACL_CREATE); + if (aclresult != ACLCHECK_OK) { + aclcheck_error(aclresult, ACL_KIND_TABLESPACE, get_tablespace_name(newPartitionTableSpaceOid)); + } + } + + /* create partition */ + if (!OidIsValid(partrelfileOid) && u_sess->proc_cxt.IsBinaryUpgrade && + binary_upgrade_is_next_part_pg_partition_oid_valid()) { + newPartitionOid = binary_upgrade_get_next_part_pg_partition_oid(); + partrelfileOid = binary_upgrade_get_next_part_pg_partition_rfoid(); + } else if (!OidIsValid(partrelfileOid)) { + newPartitionOid = GetNewRelFileNode(newPartitionTableSpaceOid, + pgPartRel, + RELPERSISTENCE_PERMANENT); /* partition's persistence only can be 'p'(permanent table) */ + } else { + Assert(t_thrd.xact_cxt.inheritFileNode); + ereport(NOTICE, (errmsg("Define inheritFileNode %u for new interval partition", partrelfileOid))); + } + + LockPartitionOid(partTableOid, (uint32)newPartitionOid, AccessExclusiveLock); + char* partName = GenIntervalPartitionName(rel); + newPartition = heapCreatePartition(partName, /* partition's name */ + false, /* false for partition */ + newPartitionTableSpaceOid, /* partition's tablespace */ + newPartitionOid, /* partition's oid */ + partrelfileOid, + bucketOid, + ownerid); + pfree(partName); + + Assert(newPartitionOid == PartitionGetPartid(newPartition)); + newPartition->pd_part->parttype = PART_OBJ_TYPE_TABLE_PARTITION; + newPartition->pd_part->parentid = partTableOid; + newPartition->pd_part->rangenum = 0; + newPartition->pd_part->intervalnum = 0; + newPartition->pd_part->partstrategy = PART_STRATEGY_INTERVAL; + newPartition->pd_part->reltoastrelid = InvalidOid; + newPartition->pd_part->reltoastidxid = InvalidOid; + newPartition->pd_part->indextblid = InvalidOid; + newPartition->pd_part->reldeltarelid = InvalidOid; + newPartition->pd_part->reldeltaidx = InvalidOid; + newPartition->pd_part->relcudescrelid = InvalidOid; + newPartition->pd_part->relcudescidx = InvalidOid; + newPartition->pd_part->indisusable = true; + + /* step 3: insert into pg_partition tuple*/ + addNewPartitionTuple(pgPartRel, /* RelationData pointer for pg_partition */ + newPartition, /* PartitionData pointer for partition */ + NULL, + NULL, + (Datum)0, /* interval */ + boundaryValue, /* max values */ + (Datum)0, /* transition point */ + reloptions); + + relation = relation_open(partTableOid, NoLock); + PartitionCloseSmgr(newPartition); + + partitionClose(relation, newPartition, NoLock); + relation_close(relation, NoLock); + return newPartitionOid; +} + +Timestamp Align2UpBoundary(Timestamp value, Interval* intervalValue, Timestamp boundary) +{ + Timestamp nearbyBoundary = boundary; + Interval* diff = DatumGetIntervalP(timestamp_mi(value, boundary)); + /* approximate multiple */ + int multiple = (int)(INTERVAL_TO_USEC(diff) / INTERVAL_TO_USEC(intervalValue)); + pfree(diff); + if (multiple != 0) { + Interval* integerInterval = DatumGetIntervalP(interval_mul(intervalValue, (float8)multiple)); + nearbyBoundary = DatumGetTimestamp(timestamp_pl_interval(boundary, integerInterval)); + pfree(integerInterval); + } + if (nearbyBoundary <= value) { + while (true) { + nearbyBoundary = DatumGetTimestamp(timestamp_pl_interval(nearbyBoundary, intervalValue)); + if (nearbyBoundary > value) { + return nearbyBoundary; + } + } + } else { + while (true) { + Timestamp res = DatumGetTimestamp(timestamp_mi_interval(nearbyBoundary, intervalValue)); + if (res <= value) { + return nearbyBoundary; + } + nearbyBoundary = res; + } + } +} + +Datum Timestamp2Boundarys(Relation rel, Timestamp ts) +{ + Const consts; + RangePartitionMap* partMap = (RangePartitionMap*)rel->partMap; + bool isTimestamptz = partMap->rangeElements[partMap->rangeElementsNum - 1].boundary[0]->consttype == TIMESTAMPTZOID; + Datum columnRaw = TimestampGetDatum(ts); + int2vector* partKeyColumn = partMap->partitionKey; + Assert(partKeyColumn->dim1 == 1); + + (void)transformDatum2Const(rel->rd_att, partKeyColumn->values[0], columnRaw, false, &consts); + List* bondary = list_make1(&consts); + Datum res = transformPartitionBoundary(bondary, &isTimestamptz); + list_free(bondary); + return res; +} + +Datum GetPartBoundaryByTuple(Relation rel, HeapTuple tuple) +{ + RangePartitionMap* partMap = (RangePartitionMap*)rel->partMap; + int2vector* partKeyColumn = partMap->partitionKey; + Assert(partKeyColumn->dim1 == 1); + Assert(partMap->type.type == PART_TYPE_INTERVAL); + Assert(partMap->rangeElementsNum >= 1); + Assert(partMap->rangeElements[partMap->rangeElementsNum - 1].boundary[0]->consttype == TIMESTAMPOID || + partMap->rangeElements[partMap->rangeElementsNum - 1].boundary[0]->consttype == TIMESTAMPTZOID); + + bool isNull = false; + Datum columnRaw = fastgetattr(tuple, partKeyColumn->values[0], rel->rd_att, &isNull); + Timestamp value = DatumGetTimestamp(columnRaw); + Timestamp boundaryTs = + DatumGetTimestamp(partMap->rangeElements[partMap->rangeElementsNum - 1].boundary[0]->constvalue); + return Timestamp2Boundarys(rel, Align2UpBoundary(value, partMap->intervalValue, boundaryTs)); +} + +Oid AddNewIntervalPartition(Relation rel, HeapTuple insertTuple) +{ + Relation pgPartRel = NULL; + Oid newPartOid = InvalidOid; + Datum newRelOptions; + Datum relOptions; + HeapTuple tuple; + bool isNull = false; + List* oldRelOptions = NIL; + Oid bucketOid; + + lockRelationForAddIntervalPartition(rel); + RelationInitPartitionMap(rel); + partitionRoutingForTuple(rel, insertTuple, u_sess->catalog_cxt.route); + + /* if the partition exists, return partition's oid */ + if (u_sess->catalog_cxt.route->fileExist) { + Assert(OidIsValid(u_sess->catalog_cxt.route->partitionId)); + unLockRelationForAddIntervalPartition(rel); + return u_sess->catalog_cxt.route->partitionId; + } + + /* check 1: can not add more partition, because more enough */ + if ((getNumberOfPartitions(rel) + 1) > MAX_PARTITION_NUM) { + ereport(ERROR, + (errcode(ERRCODE_INVALID_TABLE_DEFINITION), + errmsg("too many partitions for partitioned table"), + errhint("Number of partitions can not be more than %d", MAX_PARTITION_NUM))); + } + + /* check 5: whether has the unusable local index */ + if (!checkRelationLocalIndexesUsable(rel)) { + ereport(ERROR, + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), + errmsg("can't add partition bacause the relation %s has unusable local index", + NameStr(rel->rd_rel->relname)), + errhint("please reindex the unusable index first."))); + } + + pgPartRel = relation_open(PartitionRelationId, RowExclusiveLock); + + /* step 2: add new partition entry in pg_partition */ + /* TRANSFORM into target first */ + tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(rel->rd_id)); + relOptions = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_reloptions, &isNull); + + oldRelOptions = untransformRelOptions(relOptions); + newRelOptions = transformRelOptions((Datum)0, oldRelOptions, NULL, NULL, false, false); + ReleaseSysCache(tuple); + + if (oldRelOptions != NIL) { + list_free_ext(oldRelOptions); + } + + bucketOid = RelationGetBucketOid(rel); + newPartOid = HeapAddIntervalPartition(pgPartRel, + rel, + rel->rd_id, + InvalidOid, + rel->rd_rel->reltablespace, + bucketOid, + GetPartBoundaryByTuple(rel, insertTuple), + rel->rd_rel->relowner, + (Datum)newRelOptions); + + CommandCounterIncrement(); + addIndexForPartition(rel, newPartOid); + + addToastTableForNewPartition(rel, newPartOid); + /* step 4: invalidate relation */ + CacheInvalidateRelcache(rel); + RelationInitPartitionMap(rel); + + /* close relation, done */ + relation_close(pgPartRel, NoLock); + + return newPartOid; +} + static void addNewPartitionTupleForValuePartitionedTable(Relation pg_partition_rel, const char* relname, const Oid reloid, const Oid reltablespaceid, const TupleDesc reltupledesc, const PartitionState* partTableState, Datum reloptions) @@ -4872,10 +5247,10 @@ static void addNewPartitionTupleForTable(Relation pg_partition_rel, const char* } partition_key_attr_no = buildPartitionKey(partTableState->partitionKey, reltupledesc); - interval_talespace = buldIntervalTablespace(partTableState->intervalPartDef); - - interval = (Datum)0; - transition_point = (Datum)0; + if (partTableState->intervalPartDef != NULL) { + interval_talespace = BuildIntervalTablespace(partTableState->intervalPartDef); + interval = BuildInterval(partTableState->intervalPartDef->partInterval); + } /*step1: create partition relation, initialize and set tuple properties*/ if (u_sess->proc_cxt.IsBinaryUpgrade && OidIsValid(u_sess->upg_cxt.binary_upgrade_next_partrel_pg_partition_oid)) { @@ -4930,6 +5305,10 @@ static void addNewPartitionTupleForTable(Relation pg_partition_rel, const char* if (interval_talespace != NULL) { pfree(interval_talespace); } + + if (interval != 0) { + pfree(DatumGetPointer(interval)); + } } /* @@ -5160,6 +5539,9 @@ Oid heapTupleGetPartitionId(Relation rel, HeapTuple tuple) ereport(ERROR, (errcode(ERRCODE_NO_DATA_FOUND), errmsg("inserted partition key does not map to any table partition"))); } break; + case PART_AREA_INTERVAL: { + return AddNewIntervalPartition(rel, tuple); + } break; /* never happen; just to be self-contained */ default: { ereport(ERROR, @@ -5302,18 +5684,6 @@ static Oid binary_upgrade_get_next_part_toast_pg_class_rfoid() return old_part_toast_pg_class_rfoid; } -/* - * @@GaussDB@@ - * Target : data partition - * Brief : create a interval partition. - * Description : - * Notes : - */ -Oid createNewIntervalFile(Relation rel, int seqNum) -{ - return InvalidOid; -} - static int TransformClusterColNameList(Oid relId, List* colList, int16* attnums) { ListCell* l = NULL; diff --git a/src/common/backend/catalog/pg_partition.cpp b/src/common/backend/catalog/pg_partition.cpp old mode 100755 new mode 100644 index 3f25628414..7cac74a6c5 --- a/src/common/backend/catalog/pg_partition.cpp +++ b/src/common/backend/catalog/pg_partition.cpp @@ -41,7 +41,8 @@ #include "utils/snapmgr.h" void insertPartitionEntry(Relation pg_partition_desc, Partition new_part_desc, Oid new_part_id, int2vector* pkey, - oidvector* intablespace, Datum interval, Datum maxValues, Datum transitionPoint, Datum reloptions, char parttype) + const oidvector* tablespaces, Datum interval, Datum maxValues, Datum transitionPoint, Datum reloptions, + char parttype) { Datum values[Natts_pg_partition]; bool nulls[Natts_pg_partition]; @@ -88,7 +89,13 @@ void insertPartitionEntry(Relation pg_partition_desc, Partition new_part_desc, O nulls[Anum_pg_partition_partkey - 1] = true; } - nulls[Anum_pg_partition_intablespace - 1] = true; + /* interval tablespaces */ + if (tablespaces != NULL) { + values[Anum_pg_partition_intablespace - 1] = PointerGetDatum(tablespaces); + } else { + nulls[Anum_pg_partition_intablespace - 1] = true; + } + nulls[Anum_pg_partition_intspnum - 1] = true; /* interval */ @@ -586,7 +593,7 @@ static Oid getPartitionIndexFormData(Oid indexid, Oid partitionid, Form_pg_parti heap_close(pg_partition, AccessShareLock); /* If drop index occur before this function and after pg_get_indexdef_partitions, */ - /* the index has been deleted now. Ext. If drop patition occur, the partition might be deleted. + /* the index has been deleted now. Ext. If drop patition occur, the partition might be deleted. * Drop partition just use RowExclusiveLock for parellel performance. */ if (!found) { ereport(ERROR, diff --git a/src/common/backend/parser/parse_utilcmd.cpp b/src/common/backend/parser/parse_utilcmd.cpp index 81d3ed9206..7744e21325 100644 --- a/src/common/backend/parser/parse_utilcmd.cpp +++ b/src/common/backend/parser/parse_utilcmd.cpp @@ -166,6 +166,7 @@ static void transformTableLikeClause( CreateStmtContext* cxt, TableLikeClause* table_like_clause, bool preCheck, bool isFirstNode = false); static void transformTableLikePartitionProperty(Relation relation, HeapTuple partitionTableTuple, List** partKeyColumns, List* partitionList, List** partitionDefinitions); +static IntervalPartitionDefState* TransformTableLikeIntervalPartitionDef(HeapTuple partitionTableTuple); static void transformTableLikePartitionKeys( Relation relation, HeapTuple partitionTableTuple, List** partKeyColumns, List** partKeyPosList); static void transformTableLikePartitionBoundaries( @@ -220,6 +221,7 @@ static List* divide_start_end_every_internal(ParseState* pstate, char* partName, static List* DividePartitionStartEndInterval(ParseState* pstate, Form_pg_attribute attr, char* partName, Const* startVal, Const* endVal, Const* everyVal, Node* everyExpr, int* numPart, int maxNum); static void TryReuseFilenode(Relation rel, CreateStmtContext *ctx, bool clonepart); +extern Node* makeAConst(Value* v, int location); /* * transformCreateStmt - @@ -1537,14 +1539,12 @@ static void transformTableLikeClause( n = makeNode(PartitionState); n->partitionKey = partKeyColumns; n->partitionList = partitionDefinitions; -#ifdef PGXC - // in mppdb, we do not support interval partition - n->intervalPartDef = NULL; - n->partitionStrategy = partitionForm->partstrategy; -#else - n->intervalPartDef = NULL; n->partitionStrategy = partitionForm->partstrategy; -#endif + if (partitionForm->partstrategy == PART_STRATEGY_INTERVAL) { + n->intervalPartDef = TransformTableLikeIntervalPartitionDef(partitionTableTuple); + } else { + n->intervalPartDef = NULL; + } n->rowMovement = relation->rd_rel->relrowmovement ? ROWMOVEMENT_ENABLE : ROWMOVEMENT_DISABLE; // store the produced partition state in CreateStmtContext @@ -1683,6 +1683,32 @@ static void transformTableLikePartitionProperty(Relation relation, HeapTuple par transformTableLikePartitionBoundaries(relation, partKeyPosList, partitionList, partitionDefinitions); } +static IntervalPartitionDefState* TransformTableLikeIntervalPartitionDef(HeapTuple partitionTableTuple) +{ + IntervalPartitionDefState* intervalPartDef = makeNode(IntervalPartitionDefState); + Relation partitionRel = relation_open(PartitionRelationId, RowExclusiveLock); + char* intervalStr = ReadIntervalStr(partitionTableTuple, RelationGetDescr(partitionRel)); + Assert(intervalStr != NULL); + intervalPartDef->partInterval = makeAConst(makeString(intervalStr), -1); + oidvector* tablespaceIdVec = ReadIntervalTablespace(partitionTableTuple, RelationGetDescr(partitionRel)); + intervalPartDef->intervalTablespaces = NULL; + if (tablespaceIdVec != NULL && tablespaceIdVec->dim1 > 0) { + for (int i = 0; i < tablespaceIdVec->dim1; ++i) { + char* tablespaceName = get_tablespace_name(tablespaceIdVec->values[i]); + if (tablespaceName == NULL) { + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("tablespace with OID %u does not exist", tablespaceIdVec->values[i]))); + } + intervalPartDef->intervalTablespaces = + lappend(intervalPartDef->intervalTablespaces, makeString(tablespaceName)); + } + } + + relation_close(partitionRel, RowExclusiveLock); + return intervalPartDef; +} + static void transformTableLikePartitionKeys( Relation relation, HeapTuple partitionTableTuple, List** partKeyColumns, List** partKeyPosList) { @@ -1789,6 +1815,11 @@ static void transformTableLikePartitionBoundaries( foreach (partitionCell, orderedPartitionList) { HeapTuple partitionTuple = (HeapTuple)lfirst(partitionCell); Form_pg_partition partitionForm = (Form_pg_partition)GETSTRUCT(partitionTuple); + /* no need to copy interval partition */ + if (partitionForm->partstrategy == PART_STRATEGY_INTERVAL) { + continue; + } + bool attIsNull = false; Datum tableSpace = (Datum)0; Datum boundaries = (Datum)0; @@ -4161,19 +4192,24 @@ void checkPartitionSynax(CreateStmt* stmt) /* check interval synax */ if (stmt->partTableState->intervalPartDef) { -#ifdef PGXC - /* in mpp version, we close interval partition feature */ - ereport(ERROR, - (errcode(ERRCODE_INVALID_TABLE_DEFINITION), - errmsg("Range partitioned table with INTERVAL was forbidden"), - errhint("Only support pure range partitioned table"))); -#endif if (stmt->partTableState->partitionKey->length > 1) { ereport(ERROR, (errcode(ERRCODE_INVALID_TABLE_DEFINITION), errmsg("Range partitioned table with INTERVAL clause has more than one column"), errhint("Only support one partition key for interval partition"))); } + if (!IsA(stmt->partTableState->intervalPartDef->partInterval, A_Const) || + ((A_Const*)stmt->partTableState->intervalPartDef->partInterval)->val.type != T_String) { + ereport(ERROR, + (errcode(ERRCODE_INVALID_DATETIME_FORMAT), + // errmsg("invalid input syntax for type %s: \"%s\"", datatype, str))); + errmsg("invalid input syntax for type interval"))); + } + int32 typmod = -1; + Interval* interval = NULL; + A_Const* node = (A_Const*)stmt->partTableState->intervalPartDef->partInterval; + interval = char_to_interval(node->val.val.str, typmod); + pfree(interval); } } diff --git a/src/common/backend/utils/adt/dbsize.cpp b/src/common/backend/utils/adt/dbsize.cpp index 2e744874da..2f4e3f3d2b 100755 --- a/src/common/backend/utils/adt/dbsize.cpp +++ b/src/common/backend/utils/adt/dbsize.cpp @@ -1391,6 +1391,7 @@ static int64 calculate_partition_indexes_size(Oid part_table_oid, Oid part_oid) } list_free_ext(indexOids); + relation_close(part_table_rel, AccessShareLock); return size; } diff --git a/src/common/backend/utils/adt/timestamp.cpp b/src/common/backend/utils/adt/timestamp.cpp index b81a09a6b3..6ffe5b5f2b 100755 --- a/src/common/backend/utils/adt/timestamp.cpp +++ b/src/common/backend/utils/adt/timestamp.cpp @@ -2546,10 +2546,8 @@ Datum timestamp_larger(PG_FUNCTION_ARGS) PG_RETURN_TIMESTAMP(result); } -Datum timestamp_mi(PG_FUNCTION_ARGS) +Datum timestamp_mi(Timestamp dt1, Timestamp dt2) { - Timestamp dt1 = PG_GETARG_TIMESTAMP(0); - Timestamp dt2 = PG_GETARG_TIMESTAMP(1); Interval* result = NULL; result = (Interval*)palloc(sizeof(Interval)); @@ -2593,6 +2591,13 @@ Datum timestamp_mi(PG_FUNCTION_ARGS) PG_RETURN_INTERVAL_P(result); } +Datum timestamp_mi(PG_FUNCTION_ARGS) +{ + Timestamp dt1 = PG_GETARG_TIMESTAMP(0); + Timestamp dt2 = PG_GETARG_TIMESTAMP(1); + return timestamp_mi(dt1, dt2); +} + /* * interval_justify_interval() * @@ -2732,20 +2737,8 @@ Datum interval_justify_days(PG_FUNCTION_ARGS) PG_RETURN_INTERVAL_P(result); } -/* timestamp_pl_interval() - * Add a interval to a timestamp data type. - * Note that interval has provisions for qualitative year/month and day - * units, so try to do the right thing with them. - * To add a month, increment the month, and use the same day of month. - * Then, if the next month has fewer days, set the day of month - * to the last day of month. - * To add a day, increment the mday, and use the same time of day. - * Lastly, add in the "quantitative time". - */ -Datum timestamp_pl_interval(PG_FUNCTION_ARGS) +Datum timestamp_pl_interval(Timestamp timestamp, Interval* span) { - Timestamp timestamp = PG_GETARG_TIMESTAMP(0); - Interval* span = PG_GETARG_INTERVAL_P(1); Timestamp result; if (TIMESTAMP_NOT_FINITE(timestamp)) { @@ -2803,10 +2796,25 @@ Datum timestamp_pl_interval(PG_FUNCTION_ARGS) PG_RETURN_TIMESTAMP(result); } -Datum timestamp_mi_interval(PG_FUNCTION_ARGS) +/* timestamp_pl_interval() + * Add a interval to a timestamp data type. + * Note that interval has provisions for qualitative year/month and day + * units, so try to do the right thing with them. + * To add a month, increment the month, and use the same day of month. + * Then, if the next month has fewer days, set the day of month + * to the last day of month. + * To add a day, increment the mday, and use the same time of day. + * Lastly, add in the "quantitative time". + */ +Datum timestamp_pl_interval(PG_FUNCTION_ARGS) { Timestamp timestamp = PG_GETARG_TIMESTAMP(0); Interval* span = PG_GETARG_INTERVAL_P(1); + return timestamp_pl_interval(timestamp, span); +} + +Datum timestamp_mi_interval(Timestamp timestamp, Interval* span) +{ Interval tspan; tspan.month = -span->month; @@ -2816,6 +2824,13 @@ Datum timestamp_mi_interval(PG_FUNCTION_ARGS) return DirectFunctionCall2(timestamp_pl_interval, TimestampGetDatum(timestamp), PointerGetDatum(&tspan)); } +Datum timestamp_mi_interval(PG_FUNCTION_ARGS) +{ + Timestamp timestamp = PG_GETARG_TIMESTAMP(0); + Interval* span = PG_GETARG_INTERVAL_P(1); + return timestamp_mi_interval(timestamp, span); +} + /* timestamptz_pl_interval() * Add a interval to a timestamp with time zone data type. * Note that interval has provisions for qualitative year/month @@ -2981,15 +2996,8 @@ Datum interval_mi(PG_FUNCTION_ARGS) PG_RETURN_INTERVAL_P(result); } -/* - * There is no interval_abs(): it is unclear what value to return: - * http://archives.postgresql.org/pgsql-general/2009-10/msg01031.php - * http://archives.postgresql.org/pgsql-general/2009-11/msg00041.php - */ -Datum interval_mul(PG_FUNCTION_ARGS) +Datum interval_mul(Interval* span, float8 factor) { - Interval* span = PG_GETARG_INTERVAL_P(0); - float8 factor = PG_GETARG_FLOAT8(1); double month_remainder_days, sec_remainder; int32 orig_month = span->month; int32 orig_day = span->day; @@ -3051,6 +3059,18 @@ Datum interval_mul(PG_FUNCTION_ARGS) PG_RETURN_INTERVAL_P(result); } +/* + * There is no interval_abs(): it is unclear what value to return: + * http://archives.postgresql.org/pgsql-general/2009-10/msg01031.php + * http://archives.postgresql.org/pgsql-general/2009-11/msg00041.php + */ +Datum interval_mul(PG_FUNCTION_ARGS) +{ + Interval* span = PG_GETARG_INTERVAL_P(0); + float8 factor = PG_GETARG_FLOAT8(1); + return interval_mul(span, factor); +} + Datum mul_d_interval(PG_FUNCTION_ARGS) { /* Args are float8 and Interval *, but leave them as generic Datum */ diff --git a/src/common/backend/utils/cache/partcache.cpp b/src/common/backend/utils/cache/partcache.cpp index b405926f3d..af16c316da 100755 --- a/src/common/backend/utils/cache/partcache.cpp +++ b/src/common/backend/utils/cache/partcache.cpp @@ -368,6 +368,36 @@ Partition PartitionIdGetPartition(Oid partitionId) return pd; } +char* PartitionOidGetName(Oid partOid) +{ + HeapTuple tuple = ScanPgPartition(partOid, true); + if (!HeapTupleIsValid(tuple)) { + return NULL; + } + + Form_pg_partition part = (Form_pg_partition)GETSTRUCT(tuple); + char* relName = (char*)palloc0(NAMEDATALEN); + error_t rc = strncpy_s(relName, NAMEDATALEN, part->relname.data, NAMEDATALEN - 1); + securec_check_ss(rc, "\0", "\0"); + heap_freetuple_ext(tuple); + + return relName; +} + +Oid PartitionOidGetTablespace(Oid partOid) +{ + HeapTuple tuple = ScanPgPartition(partOid, true); + if (!HeapTupleIsValid(tuple)) { + return InvalidOid; + } + + Form_pg_partition part = (Form_pg_partition)GETSTRUCT(tuple); + Oid tablespaceOid = part->reltablespace; + heap_freetuple_ext(tuple); + + return tablespaceOid; +} + void PartitionClose(Partition partition) { /* Note: no locking manipulations needed */ diff --git a/src/gausskernel/cbb/utils/partition/partitionmap.cpp b/src/gausskernel/cbb/utils/partition/partitionmap.cpp old mode 100755 new mode 100644 index 93d788e139..d12d97cad8 --- a/src/gausskernel/cbb/utils/partition/partitionmap.cpp +++ b/src/gausskernel/cbb/utils/partition/partitionmap.cpp @@ -20,7 +20,7 @@ * * IDENTIFICATION * src/gausskernel/cbb/utils/partition/partitionmap.cpp - * + * * ------------------------------------------------------------------------- */ #include "postgres.h" @@ -379,33 +379,32 @@ static inline void constCompare(Const* value1, Const* value2, int& compare) } \ } while (0) -#define buildRangeElement(range, type, typelen, relid, attrno, tuple, desc) \ - do { \ - Assert(PointerIsValid(range)); \ - Assert(PointerIsValid(type) && PointerIsValid(attrno)); \ - Assert(PointerIsValid(tuple) && PointerIsValid(desc)); \ - Assert((attrno)->dim1 <= RANGE_PARTKEYMAXNUM); \ - Assert((attrno)->dim1 == (typelen)); \ - unserializePartitionStringAttribute((range)->boundary, \ - RANGE_PARTKEYMAXNUM, \ - (type), \ - (typelen), \ - (relid), \ - (attrno), \ - (tuple), \ - Anum_pg_partition_boundaries, \ - (desc)); \ - (range)->partitionOid = HeapTupleGetOid(tuple); \ - (range)->len = (typelen); \ +#define BuildRangeElement(range, type, typelen, relid, attrno, tuple, desc, isInter) \ + do { \ + Assert(PointerIsValid(range)); \ + Assert(PointerIsValid(type) && PointerIsValid(attrno)); \ + Assert(PointerIsValid(tuple) && PointerIsValid(desc)); \ + Assert((attrno)->dim1 <= RANGE_PARTKEYMAXNUM); \ + Assert((attrno)->dim1 == (typelen)); \ + unserializePartitionStringAttribute((range)->boundary, \ + RANGE_PARTKEYMAXNUM, \ + (type), \ + (typelen), \ + (relid), \ + (attrno), \ + (tuple), \ + Anum_pg_partition_boundaries, \ + (desc)); \ + (range)->partitionOid = HeapTupleGetOid(tuple); \ + (range)->len = (typelen); \ + (range)->isInterval = (isInter); \ } while (0) static void RebuildRangePartitionMap(RangePartitionMap* oldMap, RangePartitionMap* newMap); -static void RebuildIntervalPartitionMap(IntervalPartitionMap* oldMap, IntervalPartitionMap* newMap); - /* these routines are partition map related */ static void buildRangePartitionMap(Relation relation, Form_pg_partition partitioned_form, HeapTuple partitioned_tuple, - Relation pg_partition, List* partition_list); + Relation pg_partition, const List* partition_list); static RangeElement* copyRangeElements(RangeElement* src, int elementNum, int partkeyNum); @@ -635,7 +634,6 @@ void RelationInitPartitionMap(Relation relation) } partitioned_form = (Form_pg_partition)GETSTRUCT(partitioned_tuple); - /* * For value based partition-table, we only have to retrieve partkeys */ @@ -694,6 +692,7 @@ void RelationInitPartitionMap(Relation relation) switch (partitioned_form->partstrategy) { case PART_STRATEGY_RANGE: + case PART_STRATEGY_INTERVAL: buildRangePartitionMap(relation, partitioned_form, partitioned_tuple, pg_partition, partition_list); break; default: @@ -765,11 +764,7 @@ void RebuildPartitonMap(PartitionMap* oldMap, PartitionMap* newMap) // when the map is referenced, don't rebuild the partitionmap if (oldMap->refcount == 0) { - if (PartitionMapIsRange(oldMap)) { - RebuildRangePartitionMap((RangePartitionMap*)oldMap, (RangePartitionMap*)newMap); - } else { - RebuildIntervalPartitionMap((IntervalPartitionMap*)oldMap, (IntervalPartitionMap*)newMap); - } + RebuildRangePartitionMap((RangePartitionMap*)oldMap, (RangePartitionMap*)newMap); } else { oldMap->isDirty = true; elog(LOG, "map refcount is not zero when RebuildPartitonMap "); @@ -799,9 +794,6 @@ static void RebuildRangePartitionMap(RangePartitionMap* oldMap, RangePartitionMa PARTITIONMAP_SWAPFIELD(Oid*, partitionKeyDataType); } -static void RebuildIntervalPartitionMap(IntervalPartitionMap* oldMap, IntervalPartitionMap* newMap) -{} - /* * copy the rangeElement */ @@ -826,6 +818,79 @@ static RangeElement* copyRangeElements(RangeElement* src, int elementNum, int pa return ret; } +RangeElement* CopyRangeElementsWithoutBoundary(const RangeElement* src, int elementNum) +{ + Size size_ret = sizeof(RangeElement) * elementNum; + RangeElement* ret = (RangeElement*)palloc0(size_ret); + errno_t rc = memcpy_s(ret, size_ret, src, size_ret); + securec_check(rc, "\0", "\0"); + return ret; +} + +char* ReadIntervalStr(HeapTuple tuple, TupleDesc tupleDesc) +{ + bool isNull = true; + Oid elemType; + int16 elemLen; + bool elemByval = false; + char elemAlign; + int numElems; + Datum* elemValues = NULL; + bool* elemNulls = NULL; + Datum attrRawValue = heap_getattr(tuple, (uint32)Anum_pg_partition_interval, tupleDesc, &isNull); + ArrayType* array = DatumGetArrayTypeP(attrRawValue); + + elemType = ARR_ELEMTYPE(array); + Assert(elemType == TEXTOID); + get_typlenbyvalalign(elemType, &elemLen, &elemByval, &elemAlign); + deconstruct_array(array, elemType, elemLen, elemByval, elemAlign, &elemValues, &elemNulls, &numElems); + Assert(numElems == 1); + Assert(!elemNulls[0]); + char* intervalStr = text_to_cstring(DatumGetTextP(*elemValues)); + pfree(elemValues); + pfree(elemNulls); + return intervalStr; +} + +static Interval* ReadInterval(HeapTuple tuple, TupleDesc tupleDesc) +{ + int32 typmod = -1; + char* intervalStr = ReadIntervalStr(tuple, tupleDesc); + Interval* res = char_to_interval(intervalStr, typmod); + pfree(intervalStr); + return res; +} + +oidvector* ReadIntervalTablespace(HeapTuple tuple, TupleDesc tupleDesc) +{ + Datum tablespaceRaw; + ArrayType* tablespaceArray = NULL; + bool isNull = false; + Oid* values = NULL; + int arraySize; + + /* Get the raw data which contain interval tablespace's columns */ + tablespaceRaw = heap_getattr(tuple, Anum_pg_partition_intablespace, tupleDesc, &isNull); + + if (isNull) { + return NULL; + } + + /* convert Datum to ArrayType */ + tablespaceArray = DatumGetArrayTypeP(tablespaceRaw); + arraySize = ARR_DIMS(tablespaceArray)[0]; + + /* CHECK: the ArrayType of interval tablespace is valid */ + if (ARR_NDIM(tablespaceArray) != 1 || arraySize <= 0 || ARR_HASNULL(tablespaceArray) || + ARR_ELEMTYPE(tablespaceArray) != OIDOID) { + ereport(ERROR, + (errcode(ERRCODE_ARRAY_ELEMENT_ERROR), errmsg("interval tablespace column's number is not a oid array"))); + } + + values = (Oid*)ARR_DATA_PTR(tablespaceArray); + return buildoidvector(values, arraySize); +} + /* * @@GaussDB@@ * Target : data partition @@ -834,7 +899,7 @@ static RangeElement* copyRangeElements(RangeElement* src, int elementNum, int pa * Notes : */ static void buildRangePartitionMap(Relation relation, Form_pg_partition partitioned_form, HeapTuple partitioned_tuple, - Relation pg_partition, List* partition_list) + Relation pg_partition, const List* partition_list) { int range_itr = 0; RangePartitionMap* range_map = NULL; @@ -870,6 +935,14 @@ static void buildRangePartitionMap(Relation relation, Form_pg_partition partitio partitionKeyDataType, sizeof(Oid) * partitionKey->dim1); securec_check(rc, "\0", "\0"); + + if (partitioned_form->partstrategy == PART_STRATEGY_INTERVAL) { + range_map->type.type = PART_TYPE_INTERVAL; + /* the interval partition only supports one partition key */ + Assert(partitionKey->dim1 == 1); + range_map->intervalValue = ReadInterval(partitioned_tuple, RelationGetDescr(pg_partition)); + range_map->intervalTablespace = ReadIntervalTablespace(partitioned_tuple, RelationGetDescr(pg_partition)); + } (void)MemoryContextSwitchTo(old_context); /* allocate range element array */ @@ -881,7 +954,8 @@ static void buildRangePartitionMap(Relation relation, Form_pg_partition partitio partition_tuple = (HeapTuple)lfirst(tuple_cell); partition_form = (Form_pg_partition)GETSTRUCT(partition_tuple); - if (PART_STRATEGY_RANGE != partition_form->partstrategy) { + if (partition_form->partstrategy != PART_STRATEGY_RANGE && + partition_form->partstrategy != PART_STRATEGY_INTERVAL) { pfree_ext(range_eles); pfree_ext(range_map); @@ -891,14 +965,14 @@ static void buildRangePartitionMap(Relation relation, Form_pg_partition partitio errdetail("Incorrect partition strategy for partition %u", HeapTupleGetOid(partition_tuple)))); } - buildRangeElement(&(range_eles[range_itr]), + BuildRangeElement(&(range_eles[range_itr]), range_map->partitionKeyDataType, range_map->partitionKey->dim1, RelationGetRelid(relation), range_map->partitionKey, partition_tuple, - RelationGetDescr(pg_partition)); - + RelationGetDescr(pg_partition), + partition_form->partstrategy == PART_STRATEGY_INTERVAL); range_itr++; } @@ -1017,7 +1091,7 @@ Oid getRangePartitionOid(Relation relation, Const** partKeyValue, int32* partSeq RangeElement* rangeElementIterator = NULL; RangePartitionMap* rangePartMap = NULL; Oid result = InvalidOid; - int keyNums = 0; + int keyNums; int hit = -1; int min_part_id = 0; int max_part_id = 0; @@ -1084,13 +1158,39 @@ Oid getRangePartitionOid(Relation relation, Const** partKeyValue, int32* partSeq return result; } -/* - * return value: InvalidOid---when requested partition not created yet - */ -Oid getIntervalPartitionOid(IntervalPartitionMap* intervalPartMap, Const** partKeyValue, int32* partIndex, - PartitionArea* partArea, bool topClosed, bool missIsOk) +inline Const* CalcLowBoundary(const Const* upBoundary, Interval* intervalValue) { - return InvalidOid; + Assert(upBoundary->consttype == TIMESTAMPOID || upBoundary->consttype == TIMESTAMPTZOID); + Timestamp lowTs = timestamp_mi_interval(DatumGetTimestamp(upBoundary->constvalue), intervalValue); + return makeConst(upBoundary->consttype, + upBoundary->consttypmod, + upBoundary->constcollid, + upBoundary->constlen, + TimestampGetDatum(lowTs), + upBoundary->constisnull, + upBoundary->constbyval); +} + +inline int ValueCmpLowBoudary(Const** partKeyValue, const RangeElement* partition, Interval* intervalValue) +{ + Assert(partition->isInterval); + Assert(partition->len == 1); + int compare = 0; + Const* lowBoundary = CalcLowBoundary(partition->boundary[0], intervalValue); + partitonKeyCompareForRouting(partKeyValue, &lowBoundary, partition->len, compare); + pfree(lowBoundary); + return compare; +} + +/* the low boundary is close */ +bool ValueSatisfyLowBoudary(Const** partKeyValue, RangeElement* partition, Interval* intervalValue, bool topClosed) +{ + int compare = ValueCmpLowBoudary(partKeyValue, partition, intervalValue); + if (compare > 0 || (compare == 0 && topClosed)) { + return true; + } + + return false; } /* @@ -1110,7 +1210,7 @@ int getNumberOfRangePartitions(Relation rel) errmsg("CAN NOT get number of partition against NON-PARTITIONED relation"))); } - if (rel->partMap->type == PART_TYPE_RANGE) { + if (rel->partMap->type == PART_TYPE_RANGE || rel->partMap->type == PART_TYPE_INTERVAL) { RangePartitionMap* rangeMap = NULL; rangeMap = (RangePartitionMap*)(rel->partMap); @@ -1121,33 +1221,9 @@ int getNumberOfRangePartitions(Relation rel) return ret; } -/* - * @@GaussDB@@ - * Target : data partition - * Brief : - * Description : - * Notes : - */ -int getNumberOfIntervalPartitions(Relation rel) -{ - return 0; -} - int getNumberOfPartitions(Relation rel) { - int ranges = 0; - int intervals = 0; - - if (!RELATION_IS_PARTITIONED(rel)) { - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("CAN NOT get number of partition against NON-PARTITIONED relation"))); - } - - ranges = getNumberOfRangePartitions(rel); - intervals = getNumberOfIntervalPartitions(rel); - - return (ranges + intervals); + return getNumberOfRangePartitions(rel); } Oid partIDGetPartOid(Relation relation, PartitionIdentifier* partID) @@ -1164,9 +1240,7 @@ Oid partIDGetPartOid(Relation relation, PartitionIdentifier* partID) return InvalidOid; } - if (relation->partMap->type == PART_TYPE_RANGE) { - Assert(partID->partArea == PART_AREA_RANGE); - + if (relation->partMap->type == PART_TYPE_RANGE || relation->partMap->type == PART_TYPE_INTERVAL) { rang_map = (RangePartitionMap*)(relation->partMap); if (partID->partSeq <= rang_map->rangeElementsNum) { @@ -1201,13 +1275,17 @@ PartitionIdentifier* partOidGetPartID(Relation rel, Oid partOid) } result = (PartitionIdentifier*)palloc0(sizeof(PartitionIdentifier)); - if (PART_TYPE_RANGE == rel->partMap->type) { + if (rel->partMap->type == PART_TYPE_RANGE || rel->partMap->type == PART_TYPE_INTERVAL) { int i; RangePartitionMap* rangeMap = (RangePartitionMap*)rel->partMap; for (i = 0; i < rangeMap->rangeElementsNum; i++) { if (partOid == rangeMap->rangeElements[i].partitionOid) { - result->partArea = PART_AREA_RANGE; + if (rangeMap->rangeElements[i].isInterval) { + result->partArea = PART_AREA_INTERVAL; + } else { + result->partArea = PART_AREA_RANGE; + } result->partSeq = i; result->fileExist = true; result->partitionId = partOid; @@ -1237,9 +1315,7 @@ int partOidGetPartSequence(Relation rel, Oid partOid) } else if (false == resultPartID->fileExist || PART_AREA_NONE == resultPartID->partArea) { resultPartSequence = -1; } else { - if (resultPartID->partArea == PART_AREA_RANGE) { - resultPartSequence = resultPartID->partSeq + 1; - } + resultPartSequence = resultPartID->partSeq + 1; } pfree_ext(resultPartID); @@ -1346,34 +1422,19 @@ void releasePartitionList(Relation relation, List** partList, LOCKMODE lockmode) List* relationGetPartitionOidList(Relation rel) { List* result = NIL; - int conuter = 0; - int sumtotal = -1; - int rangeNumber = -1; - Bitmapset* mapset = NULL; - PartitionMap* map = NULL; - Oid partitionid = InvalidOid; + Oid partitionId = InvalidOid; if (rel == NULL || rel->partMap == NULL) { return NIL; } - map = rel->partMap; - sumtotal = getPartitionNumber(map); - rangeNumber = ((RangePartitionMap*)map)->rangeElementsNum; - - if (sumtotal > rangeNumber) { - mapset = bms_copy(((IntervalPartitionMap*)map)->sequenceMap); - } - - for (conuter = 0; conuter < sumtotal; ++conuter) { - if (conuter < rangeNumber) { /* range partition */ - partitionid = ((RangePartitionMap*)map)->rangeElements[conuter].partitionOid; - } - result = lappend_oid(result, partitionid); + PartitionMap* map = rel->partMap; + int sumTotal = getPartitionNumber(map); + for (int conuter = 0; conuter < sumTotal; ++conuter) { + partitionId = ((RangePartitionMap*)map)->rangeElements[conuter].partitionOid; + result = lappend_oid(result, partitionId); } - bms_free_ext(mapset); - return result; } @@ -1533,7 +1594,7 @@ int getPartitionNumber(PartitionMap* map) { int result = -1; - if (map->type == PART_TYPE_RANGE) { + if (map->type == PART_TYPE_RANGE || map->type == PART_TYPE_INTERVAL) { result = ((RangePartitionMap*)map)->rangeElementsNum; } else { ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), errmsg("unsupported partitioned strategy"))); @@ -1708,3 +1769,45 @@ void decre_partmap_refcount(PartitionMap* map) if (!IsBootstrapProcessingMode()) ResourceOwnerForgetPartitionMapRef(t_thrd.utils_cxt.CurrentResourceOwner, map); } + +/* + * Get the oid of the partition which is a interval partition and next to the droped range partition which is + * specificed by partOid. If the droped partition is a interval partition, the next partition no need to + * be changed to range partition, return InvalidOid. If the next partition is a range partition, nothing need + * to do, return InvalidOid. + */ +Oid GetNeedDegradToRangePartOid(Relation rel, Oid partOid) +{ + /* never happen */ + if (!PointerIsValid(rel) || !OidIsValid(partOid)) { + ereport(ERROR, + (errcode(ERRCODE_FETCH_DATA_FAILED), errmsg("invalid partitioned table relaiton or partition table oid"))); + } + Assert(rel->partMap->type == PART_TYPE_RANGE || rel->partMap->type == PART_TYPE_INTERVAL); + + /* In normal range partitioned tabel, there has no interval ranges. */ + if (rel->partMap->type == PART_TYPE_RANGE) { + return InvalidOid; + } + + RangePartitionMap* rangeMap = (RangePartitionMap*)rel->partMap; + for (int i = 0; i < rangeMap->rangeElementsNum; i++) { + if (rangeMap->rangeElements[i].partitionOid == partOid) { + /* + * 1. the droped range is interval range + * 2. there is no more ranges + * 3. the next partition is a range partition + */ + if (rangeMap->rangeElements[i].isInterval || (i == rangeMap->rangeElementsNum - 1) || + !rangeMap->rangeElements[i + 1].isInterval) { + return InvalidOid; + } + + return rangeMap->rangeElements[i + 1].partitionOid; + } + } + /* It must never happened. */ + ereport(ERROR, (errcode(ERRCODE_CASE_NOT_FOUND), errmsg("Not find the target partiton %u", partOid))); + return InvalidOid; +} + diff --git a/src/gausskernel/optimizer/commands/tablecmds.cpp b/src/gausskernel/optimizer/commands/tablecmds.cpp index 8320200d16..a285b4b089 100644 --- a/src/gausskernel/optimizer/commands/tablecmds.cpp +++ b/src/gausskernel/optimizer/commands/tablecmds.cpp @@ -522,18 +522,19 @@ static void RangeVarCallbackForAlterRelation( const RangeVar* rv, Oid relid, Oid oldrelid, bool target_is_partition, void* arg); static bool CheckRangePartitionKeyType(Oid typoid); +static void CheckRangePartitionKeyType(Form_pg_attribute* attrs, List* pos); +static void CheckIntervalPartitionKeyType(Form_pg_attribute* attrs, List* pos); static void CheckPartitionTablespace(const char* spcname, Oid owner); static void ComparePartitionValue(List* pos, Form_pg_attribute* attrs, PartitionState* partTableState); static bool ConfirmTypeInfo(Oid* target_oid, int* target_mod, Const* src, Form_pg_attribute attrs, bool isinterval); -static void addToastTableForNewPartition(Relation relation, Oid newPartId); +void addToastTableForNewPartition(Relation relation, Oid newPartId); static void ATPrepAddPartition(Relation rel); static void ATPrepDropPartition(Relation rel); static void ATPrepUnusableIndexPartition(Relation rel); static void ATPrepUnusableAllIndexOnPartition(Relation rel); static void ATExecAddPartition(Relation rel, AddPartitionState* partState); static void ATExecDropPartition(Relation rel, AlterTableCmd* cmd); -void fastDropPartition(Relation rel, Oid partOid, const char* stmt); static void ATExecUnusableIndexPartition(Relation rel, const char* partition_name); static void ATExecUnusableIndex(Relation rel); static void ATExecUnusableAllIndexOnPartition(Relation rel, const char* partition_name); @@ -1722,16 +1723,18 @@ Oid DefineRelation(CreateStmt* stmt, char relkind, Oid ownerId) if (stmt->partTableState) { List* pos = NIL; - bool is_interval = false; /* get partitionkey's position */ pos = GetPartitionkeyPos(stmt->partTableState->partitionKey, schema); /* check partitionkey's datatype */ - if (stmt->partTableState->partitionStrategy == PART_STRATEGY_VALUE) + if (stmt->partTableState->partitionStrategy == PART_STRATEGY_VALUE) { CheckValuePartitionKeyType(descriptor->attrs, pos); - else - CheckPartitionKeyType(descriptor->attrs, pos, is_interval); + } else if (stmt->partTableState->partitionStrategy == PART_STRATEGY_INTERVAL) { + CheckIntervalPartitionKeyType(descriptor->attrs, pos); + } else { + CheckRangePartitionKeyType(descriptor->attrs, pos); + } /* * Check partitionkey's value for none value-partition table as for value @@ -12465,7 +12468,7 @@ static void ATExecSetTableSpaceForPartitionP2(AlteredTableInfo* tab, Relation re rangePartDef = (RangePartitionDefState*)partition; transformRangePartitionValue(make_parsestate(NULL), (Node*)rangePartDef, false); rangePartDef->boundary = transformConstIntoTargetType(rel->rd_att->attrs, - ((IntervalPartitionMap*)rel->partMap)->rangePartitionMap.partitionKey, + ((RangePartitionMap*)rel->partMap)->partitionKey, rangePartDef->boundary); partOid = partitionValuesGetPartitionOid(rel, rangePartDef->boundary, AccessExclusiveLock, true, false, false); @@ -15549,17 +15552,11 @@ List* GetPartitionkeyPos(List* partitionkeys, List* schema) * Description : * Notes : */ -void CheckPartitionKeyType(Form_pg_attribute* attrs, List* pos, bool is_interval) +static void CheckRangePartitionKeyType(Form_pg_attribute* attrs, List* pos) { int location = 0; ListCell* cell = NULL; Oid typoid = InvalidOid; - /* must be one partitionkey for interval partition */ - if (is_interval && pos->length != 1) { - list_free_ext(pos); - ereport( - ERROR, (errcode(ERRCODE_INVALID_OPERATION), errmsg("must be one partition key for interval partition"))); - } foreach (cell, pos) { bool result = false; location = lfirst_int(cell); @@ -15577,6 +15574,23 @@ void CheckPartitionKeyType(Form_pg_attribute* attrs, List* pos, bool is_interval } } +static void CheckIntervalPartitionKeyType(Form_pg_attribute* attrs, List* pos) +{ + /* must be one partitionkey for interval partition, have checked before */ + Assert(pos->length == 1); + + ListCell* cell = list_head(pos); + int location = lfirst_int(cell); + Oid typoid = attrs[location]->atttypid; + if (typoid != TIMESTAMPOID && typoid != TIMESTAMPTZOID) { + list_free_ext(pos); + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("column %s cannot serve as a interval partitioning column because of its datatype", + NameStr(attrs[location]->attname)))); + } +} + /* * @@GaussDB@@ * Target : value-partition type check @@ -15953,6 +15967,11 @@ static void ATPrepAddPartition(Relation rel) ereport( ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("can not add partition against NON-PARTITIONED table"))); } + + if (rel->partMap->type == PART_TYPE_INTERVAL) { + ereport(ERROR, (errcode(ERRCODE_OPERATE_NOT_SUPPORTED), + errmsg("can not add partition against interval partitioned table"))); + } } /* @@ -16063,6 +16082,11 @@ static void ATPrepMergePartition(Relation rel) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("can not merge partition against NON-PARTITIONED table"))); } + + if (rel->partMap->type == PART_TYPE_INTERVAL) { + ereport(ERROR, (errcode(ERRCODE_OPERATE_NOT_SUPPORTED), + errmsg("can not merge partition against interval partitioned table"))); + } } static void ATPrepSplitPartition(Relation rel) @@ -16071,6 +16095,11 @@ static void ATPrepSplitPartition(Relation rel) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("can not split partition against NON-PARTITIONED table"))); } + + if (rel->partMap->type == PART_TYPE_INTERVAL) { + ereport(ERROR, (errcode(ERRCODE_OPERATE_NOT_SUPPORTED), + errmsg("can not split partition against interval partitioned table"))); + } } /* @@ -16224,8 +16253,43 @@ static void ATExecAddPartition(Relation rel, AddPartitionState* partState) pfree_ext(isTimestamptz); } -// assume caller already hold AccessExclusiveLock on the partition being dropped -void fastDropPartition(Relation rel, Oid partOid, const char* stmt) +/* Assume the caller has already hold RowExclusiveLock on the pg_partition. */ +static void UpdateIntervalPartToRange(Relation relPartition, Oid partOid, const char* stmt) +{ + bool dirty = false; + /* Fetch a copy of the tuple to scribble on */ + HeapTuple parttup = SearchSysCacheCopy1(PARTRELID, ObjectIdGetDatum(partOid)); + if (!HeapTupleIsValid(parttup)) { + ereport(ERROR, + (errcode(ERRCODE_SQL_ROUTINE_EXCEPTION), + errmsg("pg_partition entry for partid %u vanished during %s.", partOid, stmt))); + } + Form_pg_partition partform = (Form_pg_partition)GETSTRUCT(parttup); + + /* Apply required updates, if any, to copied tuple */ + if (partform->partstrategy == PART_STRATEGY_INTERVAL) { + partform->partstrategy = PART_STRATEGY_RANGE; + dirty = true; + } else { + ereport(LOG, + (errcode(ERRCODE_SQL_ROUTINE_EXCEPTION), + errmsg("pg_partition entry for partid %u is not a interval " + "partition when execute %s .", + partOid, + stmt))); + } + + /* If anything changed, write out the tuple. */ + if (dirty) { + heap_inplace_update(relPartition, parttup); + } +} + +/* assume caller already hold AccessExclusiveLock on the partition being dropped + * if the intervalPartOid is not InvalidOid, the interval partition which is specificed by it + * need to be changed to normal range partition. + */ +void fastDropPartition(Relation rel, Oid partOid, const char* stmt, Oid intervalPartOid) { Partition part = NULL; Relation pg_partition = NULL; @@ -16240,6 +16304,7 @@ void fastDropPartition(Relation rel, Oid partOid, const char* stmt) getPartitionName(partOid, false), stmt))); } + /* drop toast table, index, and finally the partition iteselt */ dropIndexForPartition(partOid); dropToastTableOnPartition(partOid); @@ -16249,6 +16314,10 @@ void fastDropPartition(Relation rel, Oid partOid, const char* stmt) } heapDropPartition(rel, part); + if (intervalPartOid) { + UpdateIntervalPartToRange(pg_partition, intervalPartOid, stmt); + } + /* step 3: no need to update number of partitions in pg_partition */ /* step 4: invalidate relation */ CacheInvalidateRelcache(rel); @@ -16291,8 +16360,7 @@ static void ATExecDropPartition(Relation rel, AlterTableCmd* cmd) /* next IS the DROP PARTITION FOR (MAXVALUELIST) branch */ rangePartDef = (RangePartitionDefState*)cmd->def; rangePartDef->boundary = transformConstIntoTargetType(rel->rd_att->attrs, - ((IntervalPartitionMap*)rel->partMap)->rangePartitionMap.partitionKey, - rangePartDef->boundary); + ((RangePartitionMap*)rel->partMap)->partitionKey, rangePartDef->boundary); partOid = partitionValuesGetPartitionOid(rel, rangePartDef->boundary, AccessExclusiveLock, @@ -16311,7 +16379,9 @@ static void ATExecDropPartition(Relation rel, AlterTableCmd* cmd) ereport(ERROR, (errcode(ERRCODE_INVALID_OPERATION), errmsg("Cannot drop the only partition of a partitioned table"))); } - fastDropPartition(rel, partOid, "DROP PARTITION"); + + Oid changeToRangePartOid = GetNeedDegradToRangePartOid(rel, partOid); + fastDropPartition(rel, partOid, "DROP PARTITION", changeToRangePartOid); } /* @@ -16565,7 +16635,6 @@ static void ATExecModifyRowMovement(Relation rel, bool rowMovement) /* get the tuple of partitioned table */ tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid)); if (!HeapTupleIsValid(tuple)) { - ereport(ERROR, (errcode(ERRCODE_CACHE_LOOKUP_FAILED), errmsg("could not find tuple for relation %u", relid))); } @@ -16671,7 +16740,7 @@ static void ATExecTruncatePartition(Relation rel, AlterTableCmd* cmd) } else { rangePartDef = (RangePartitionDefState*)cmd->def; rangePartDef->boundary = transformConstIntoTargetType(rel->rd_att->attrs, - ((IntervalPartitionMap*)rel->partMap)->rangePartitionMap.partitionKey, + ((RangePartitionMap*)rel->partMap)->partitionKey, rangePartDef->boundary); partOid = partitionValuesGetPartitionOid(rel, rangePartDef->boundary, @@ -19298,7 +19367,7 @@ List* transformConstIntoTargetType(Form_pg_attribute* attrs, int2vector* partiti * Return : * Notes : */ -static void addToastTableForNewPartition(Relation relation, Oid newPartId) +void addToastTableForNewPartition(Relation relation, Oid newPartId) { Oid firstPartitionId = InvalidOid; Oid firstPartitionToastId = InvalidOid; diff --git a/src/gausskernel/optimizer/commands/vacuum.cpp b/src/gausskernel/optimizer/commands/vacuum.cpp index a1a48cd9fc..a88eee3f4a 100755 --- a/src/gausskernel/optimizer/commands/vacuum.cpp +++ b/src/gausskernel/optimizer/commands/vacuum.cpp @@ -1610,7 +1610,7 @@ static bool vacuum_rel(Oid relid, VacuumStmt* vacstmt, bool do_toast) if (onepartrel) { if (onepartrel->rd_rel->relkind == RELKIND_RELATION) { partID = partOidGetPartID(onepartrel, relid); - if (partID->partArea == PART_AREA_RANGE) { + if (partID->partArea == PART_AREA_RANGE || partID->partArea == PART_AREA_INTERVAL) { if (ConditionalLockPartition(onepartrel->rd_id, relid, lmode, PARTITION_LOCK)) { GetLock = true; } diff --git a/src/gausskernel/optimizer/util/plancat.cpp b/src/gausskernel/optimizer/util/plancat.cpp index f6783b9f01..3a0ae0f8b3 100644 --- a/src/gausskernel/optimizer/util/plancat.cpp +++ b/src/gausskernel/optimizer/util/plancat.cpp @@ -73,9 +73,7 @@ static void acquireSamplesForPartitionedRelation( if (RelationIsPartitioned(relation)) { if (relation->rd_rel->relkind == RELKIND_RELATION) { RangePartitionMap* partMap = (RangePartitionMap*)(relation->partMap); - int totalRangePartitionNumber = getNumberOfRangePartitions(relation); - int totalInervalPartitionNumber = getNumberOfIntervalPartitions(relation); - int totalPartitionNumber = totalRangePartitionNumber + totalInervalPartitionNumber; + int totalPartitionNumber = getNumberOfRangePartitions(relation); int partitionNumber = 0; int nonzeroPartitionNumber = 0; BlockNumber partPages = 0; @@ -83,24 +81,7 @@ static void acquireSamplesForPartitionedRelation( Partition part = NULL; for (partitionNumber = 0; partitionNumber < totalPartitionNumber; partitionNumber++) { - Oid partitionOid = InvalidOid; -#ifdef PGXC // open range partition - partitionOid = partMap->rangeElements[partitionNumber].partitionOid; -#else // open range partition or interval partition - if (partitionNumber < totalRangePartitionNumber) { - partitionOid = partMap->rangeElements[partitionNumber].partitionOid; - } else { - IntervalPartitionMap* intervalPartMap = NULL; - int intervalPartitionIndex = partitionNumber - totalRangePartitionNumber; - - AssertEreport(relation->partMap->type == PART_TYPE_INTERVAL, - MOD_OPT, - "Expected interval partition type but exception occurred."); - intervalPartMap = (IntervalPartitionMap*)(relation->partMap); - - partitionOid = intervalPartMap->intervalElements[intervalPartitionIndex].partitionOid; - } -#endif + Oid partitionOid = partMap->rangeElements[partitionNumber].partitionOid; if (!OidIsValid(partitionOid)) continue; diff --git a/src/gausskernel/optimizer/util/pruning.cpp b/src/gausskernel/optimizer/util/pruning.cpp index ae58fe81d2..682157bc57 100755 --- a/src/gausskernel/optimizer/util/pruning.cpp +++ b/src/gausskernel/optimizer/util/pruning.cpp @@ -140,7 +140,7 @@ bool checkPartitionIndexUnusable(Oid indexOid, int partItrs, PruningResult* prun heapRel = relation_open(heapRelOid, NoLock); indexRel = relation_open(indexOid, NoLock); if (!RelationIsPartitioned(heapRel) || !RelationIsPartitioned(indexRel) || - heapRel->partMap->type != PART_TYPE_RANGE) { + (heapRel->partMap->type != PART_TYPE_RANGE && heapRel->partMap->type != PART_TYPE_INTERVAL)) { ereport(ERROR, (errmodule(MOD_OPT), errcode(ERRCODE_OPTIMIZER_INCONSISTENT_STATE), @@ -226,8 +226,7 @@ IndexesUsableType eliminate_partition_index_unusable(Oid indexOid, PruningResult heapRel = relation_open(heapRelOid, NoLock); indexRel = relation_open(indexOid, NoLock); - if (!RelationIsPartitioned(heapRel) || !RelationIsPartitioned(indexRel) || - heapRel->partMap->type != PART_TYPE_RANGE) { + if (!RelationIsPartitioned(heapRel) || !RelationIsPartitioned(indexRel)) { ereport(ERROR, (errmodule(MOD_OPT), (errcode(ERRCODE_OPTIMIZER_INCONSISTENT_STATE), @@ -438,7 +437,7 @@ PruningResult* singlePartitionPruningForRestrictInfo(Oid partitionOid, Relation pruningRes->state = PRUNING_RESULT_SUBSET; /* it's a pattitioned table without interval */ - if (rel->partMap->type == PART_TYPE_RANGE) { + if (rel->partMap->type == PART_TYPE_RANGE || rel->partMap->type == PART_TYPE_INTERVAL) { rangePartMap = (RangePartitionMap*)rel->partMap; for (counter = 0; counter < rangePartMap->rangeElementsNum; counter++) { @@ -1152,13 +1151,13 @@ int varIsInPartitionKey(int attrNo, int2vector* partKeyAttrs, int partKeyNum) (PruningResultIsFull(pruningResult) || PruningResultIsEmpty(pruningResult) || \ !PointerIsValid((pruningResult)->boundary)) -#define IsCleanPruningBottom(bottomSeqPtr, pruningResult, bottomValue) \ - ((bottomSeqPtr)->partArea == PART_AREA_RANGE && (pruningResult)->boundary->partitionKeyNum > 1 && \ - PointerIsValid((bottomValue)[0]) && !(pruningResult)->boundary->minClose[0]) +#define IsCleanPruningBottom(bottomSeqPtr, pruningResult, bottomValue) \ + ((pruningResult)->boundary->partitionKeyNum > 1 && PointerIsValid((bottomValue)[0]) && \ + !(pruningResult)->boundary->minClose[0]) -#define IsCleanPruningTop(topSeqPtr, pruningResult, topValue) \ - ((topSeqPtr)->partArea == PART_AREA_RANGE && (pruningResult)->boundary->partitionKeyNum > 1 && (topValue) && \ - PointerIsValid((topValue)[0]) && !(pruningResult)->boundary->maxClose[0]) +#define IsCleanPruningTop(topSeqPtr, pruningResult, topValue) \ + ((pruningResult)->boundary->partitionKeyNum > 1 && (topValue) && PointerIsValid((topValue)[0]) && \ + !(pruningResult)->boundary->maxClose[0]) /* * @@GaussDB@@ @@ -1209,13 +1208,14 @@ static void partitionPruningFromBoundary(Relation relation, PruningResult* pruni // compare the bottom and the intervalMax, if the bottom is large than or equal than intervalMax, pruning result is // empty. - partitionRoutingForValue( + partitionRoutingForValueRange( relation, bottomValue, pruningResult->boundary->partitionKeyNum, true, true, u_sess->opt_cxt.bottom_seq); if (IsCleanPruningBottom(u_sess->opt_cxt.bottom_seq, pruningResult, bottomValue)) { cleanPruningBottom(relation, u_sess->opt_cxt.bottom_seq, bottomValue[0]); } - partitionRoutingForValue( - relation, topValue, pruningResult->boundary->partitionKeyNum, isTopClosed, true, u_sess->opt_cxt.top_seq); + + partitionRoutingForValueRange( + relation, topValue, pruningResult->boundary->partitionKeyNum, isTopClosed, false, u_sess->opt_cxt.top_seq); if (IsCleanPruningTop(u_sess->opt_cxt.top_seq, pruningResult, topValue)) { cleanPruningTop(relation, u_sess->opt_cxt.top_seq, topValue[0]); } @@ -1226,22 +1226,14 @@ static void partitionPruningFromBoundary(Relation relation, PruningResult* pruni if (!PartitionLogicalExist(u_sess->opt_cxt.bottom_seq) && !PartitionLogicalExist(u_sess->opt_cxt.top_seq)) { /* pruning failed or result contains all partition */ pruningResult->state = PRUNING_RESULT_EMPTY; - } else if (!PartitionLogicalExist(u_sess->opt_cxt.bottom_seq) && - u_sess->opt_cxt.top_seq->partArea == PART_AREA_RANGE) { + } else if (!PartitionLogicalExist(u_sess->opt_cxt.bottom_seq)) { rangeStart = 0; rangeEnd = u_sess->opt_cxt.top_seq->partSeq; - } else if (u_sess->opt_cxt.bottom_seq->partArea == PART_AREA_RANGE && - !PartitionLogicalExist(u_sess->opt_cxt.top_seq)) { + } else if (!PartitionLogicalExist(u_sess->opt_cxt.top_seq)) { rangeStart = u_sess->opt_cxt.bottom_seq->partSeq; - } else if (u_sess->opt_cxt.bottom_seq->partArea == PART_AREA_RANGE && - u_sess->opt_cxt.top_seq->partArea == PART_AREA_RANGE) { + } else { rangeStart = u_sess->opt_cxt.bottom_seq->partSeq; rangeEnd = u_sess->opt_cxt.top_seq->partSeq; - } else { - ereport(ERROR, - (errmodule(MOD_OPT), - errcode(ERRCODE_OPTIMIZER_INCONSISTENT_STATE), - errmsg("pruning result(PartitionIdentifier) is invalid"))); } if (0 <= rangeStart) { @@ -1655,8 +1647,8 @@ static void cleanPruningBottom(Relation relation, PartitionIdentifier* bottomSeq int i = 0; RangePartitionMap* partMap = NULL; - if (bottomSeq->partArea != PART_AREA_RANGE || bottomSeq->partSeq < 0 || - bottomSeq->partSeq >= ((RangePartitionMap*)relation->partMap)->rangeElementsNum || value == NULL) { + if (bottomSeq->partSeq < 0 || bottomSeq->partSeq >= ((RangePartitionMap*)relation->partMap)->rangeElementsNum || + value == NULL) { return; } @@ -1688,8 +1680,8 @@ static void cleanPruningTop(Relation relation, PartitionIdentifier* topSeq, Cons int i = 0; RangePartitionMap* partMap = NULL; - if (topSeq->partArea != PART_AREA_RANGE || topSeq->partSeq < 0 || - topSeq->partSeq >= ((RangePartitionMap*)relation->partMap)->rangeElementsNum || value == NULL) { + if (topSeq->partSeq < 0 || topSeq->partSeq >= ((RangePartitionMap*)relation->partMap)->rangeElementsNum || + value == NULL) { return; } @@ -1853,7 +1845,7 @@ Oid getPartitionOidFromSequence(Relation relation, int partSeq) AssertEreport(PointerIsValid(relation), MOD_OPT, "Unexpected NULL pointer for relation."); AssertEreport(PointerIsValid(relation->partMap), MOD_OPT, "Unexpected NULL pointer for relation->partMap."); - if (relation->partMap->type == PART_TYPE_RANGE) { + if (relation->partMap->type == PART_TYPE_RANGE || relation->partMap->type == PART_TYPE_INTERVAL) { int rangeElementsNum = ((RangePartitionMap*)(relation->partMap))->rangeElementsNum; if (partSeq < rangeElementsNum) { result = ((RangePartitionMap*)(relation->partMap))->rangeElements[partSeq].partitionOid; diff --git a/src/gausskernel/runtime/executor/nodeModifyTable.cpp b/src/gausskernel/runtime/executor/nodeModifyTable.cpp index 9da69df6df..5dea813247 100644 --- a/src/gausskernel/runtime/executor/nodeModifyTable.cpp +++ b/src/gausskernel/runtime/executor/nodeModifyTable.cpp @@ -1216,7 +1216,6 @@ TupleTableSlot* ExecUpdate(ItemPointer tupleid, /* for partitioned table */ bool row_movement = false; bool need_create_file = false; - int seq_num = -1; if (!partKeyUpdate) { row_movement = false; @@ -1257,7 +1256,6 @@ TupleTableSlot* ExecUpdate(ItemPointer tupleid, if (result_relation_desc->rd_rel->relrowmovement) { row_movement = true; need_create_file = true; - seq_num = u_sess->exec_cxt.route->partSeq; } else { ereport(ERROR, (errmodule(MOD_EXECUTOR), @@ -1519,7 +1517,7 @@ TupleTableSlot* ExecUpdate(ItemPointer tupleid, Relation fake_insert_relation = NULL; if (need_create_file) { - new_partId = createNewIntervalFile(result_relation_desc, seq_num); + new_partId = AddNewIntervalPartition(result_relation_desc, tuple); } searchFakeReationForPartitionOid(estate->esfRelations, diff --git a/src/gausskernel/storage/access/heap/heapam.cpp b/src/gausskernel/storage/access/heap/heapam.cpp index d58d598aed..aa9fcde365 100644 --- a/src/gausskernel/storage/access/heap/heapam.cpp +++ b/src/gausskernel/storage/access/heap/heapam.cpp @@ -7362,10 +7362,6 @@ Partition partitionOpen(Relation relation, Oid partition_id, LOCKMODE lockmode, /* Get the lock before trying to open the relcache entry */ if (lockmode != NoLock) { if (relation->rd_rel->relkind == RELKIND_RELATION) { - /* - * assume the partition is in PART_AREA_RANGE, if we support interval partition, - * we have to find a quick way to find the area it belongs to. - */ LockPartition(relation->rd_id, partition_id, lockmode, PARTITION_LOCK); } else if (relation->rd_rel->relkind == RELKIND_INDEX) { LockPartition(relation->rd_id, partition_id, lockmode, PARTITION_LOCK); @@ -7427,6 +7423,9 @@ Partition tryPartitionOpen(Relation relation, Oid partition_id, LOCKMODE lockmod case PART_AREA_RANGE: LockPartition(relation->rd_id, partition_id, lockmode, PARTITION_LOCK); break; + case PART_AREA_INTERVAL: + LockPartition(relation->rd_id, partition_id, lockmode, PARTITION_LOCK); + break; default: break; } @@ -7456,6 +7455,9 @@ Partition tryPartitionOpen(Relation relation, Oid partition_id, LOCKMODE lockmod case PART_AREA_RANGE: UnlockPartition(relation->rd_id, partition_id, lockmode, PARTITION_LOCK); break; + case PART_AREA_INTERVAL: + UnlockPartition(relation->rd_id, partition_id, lockmode, PARTITION_LOCK); + break; default: break; } @@ -7524,6 +7526,9 @@ void partitionClose(Relation relation, Partition partition, LOCKMODE lockmode) case PART_AREA_RANGE: UnlockPartition(relation->rd_id, part->pd_id, lockmode, PARTITION_LOCK); break; + case PART_AREA_INTERVAL: + UnlockPartition(relation->rd_id, part->pd_id, lockmode, PARTITION_LOCK); + break; default: break; } diff --git a/src/gausskernel/storage/cstore/cstore_rewrite.cpp b/src/gausskernel/storage/cstore/cstore_rewrite.cpp index 4837280853..9022fe5f05 100755 --- a/src/gausskernel/storage/cstore/cstore_rewrite.cpp +++ b/src/gausskernel/storage/cstore/cstore_rewrite.cpp @@ -37,8 +37,6 @@ #include "catalog/index.h" #include "storage/remote_read.h" -extern void fastDropPartition(Relation rel, Oid partOid, const char* stmt); - #define IsBitmapSet(_bitmap, _i) (((_bitmap)[(_i) >> 3] & (1 << ((_i) % 8))) != 0) #define ARRAY_2_LEN 2 diff --git a/src/gausskernel/storage/lmgr/lmgr.cpp b/src/gausskernel/storage/lmgr/lmgr.cpp index a82cfbac03..ef371ba871 100755 --- a/src/gausskernel/storage/lmgr/lmgr.cpp +++ b/src/gausskernel/storage/lmgr/lmgr.cpp @@ -941,7 +941,7 @@ void LockPartitionVacuum(Relation prel, Oid partId, LOCKMODE lockmode) Assert(PointerIsValid(prel) && prel->rd_rel->relkind == RELKIND_RELATION); partIdentifier = partOidGetPartID(prel, partId); - if (partIdentifier->partArea == PART_AREA_RANGE) { + if (partIdentifier->partArea == PART_AREA_RANGE || partIdentifier->partArea == PART_AREA_INTERVAL) { LockPartition(prel->rd_id, partId, lockmode, PARTITION_LOCK); } @@ -951,29 +951,16 @@ void LockPartitionVacuum(Relation prel, Oid partId, LOCKMODE lockmode) bool ConditionalLockPartitionWithRetry(Relation relation, Oid partitionId, LOCKMODE lockmode) { Oid relationId = relation->rd_id; - char relkind = relation->rd_rel->relkind; - PartitionIdentifier *partIdentifier = NULL; int lock_retry = 0; int lock_retry_limit = u_sess->attr.attr_storage.partition_lock_upgrade_timeout * (1000000 / PARTITION_RETRY_LOCK_WAIT_INTERVAL); - if (relkind == RELKIND_RELATION) - partIdentifier = partOidGetPartID(relation, partitionId); while (true) { /* step 1.1: try to lock partition */ - if (relkind == RELKIND_RELATION) { - if (partIdentifier->partArea == PART_AREA_RANGE) { - if (ConditionalLockPartition(relationId, partitionId, lockmode, PARTITION_LOCK)) - break; - } else if (partIdentifier->partArea == PART_AREA_INTERVAL) { - if (ConditionalLockPartition(relationId, partIdentifier->partSeq, lockmode, PARTITION_SEQUENCE_LOCK)) - break; - } - } else if (relkind == RELKIND_INDEX) { - if (ConditionalLockPartition(relationId, partitionId, lockmode, PARTITION_LOCK)) - break; + if (ConditionalLockPartition(relationId, partitionId, lockmode, PARTITION_LOCK)) { + break; } - + /* step 1.2: examine the try count */ if (lock_retry_limit < 0) { /* do nothing, infinite loop */ @@ -982,15 +969,12 @@ bool ConditionalLockPartitionWithRetry(Relation relation, Oid partitionId, LOCKM * We failed to establish the lock in the specified timeout * . This means we give up. */ - pfree(partIdentifier); return false; } /* step 1.3: just sleep for a while, then re-enter this loop */ pg_usleep(PARTITION_RETRY_LOCK_WAIT_INTERVAL); } - if (partIdentifier != NULL) - pfree(partIdentifier); return true; } @@ -1003,7 +987,7 @@ bool ConditionalLockPartitionVacuum(Relation prel, Oid partId, LOCKMODE lockmode Assert(PointerIsValid(prel) && prel->rd_rel->relkind == RELKIND_RELATION); partIdentifier = partOidGetPartID(prel, partId); - if (partIdentifier->partArea == PART_AREA_RANGE) { + if (partIdentifier->partArea == PART_AREA_RANGE || partIdentifier->partArea == PART_AREA_INTERVAL) { if (ConditionalLockPartition(prel->rd_id, partId, lockmode, PARTITION_LOCK)) { getLock = true; } @@ -1022,6 +1006,9 @@ void UnLockPartitionVacuum(Relation prel, Oid partId, LOCKMODE lockmode) case PART_AREA_RANGE: UnlockPartition(prel->rd_id, partId, lockmode, PARTITION_LOCK); break; + case PART_AREA_INTERVAL: + UnlockPartition(prel->rd_id, partId, lockmode, PARTITION_LOCK); + break; default: Assert(0); break; @@ -1046,7 +1033,7 @@ void LockPartitionVacuumForSession(PartitionIdentifier *partIdtf, Oid partrelid, { LOCKTAG tag; - if (partIdtf->partArea == PART_AREA_RANGE) { + if (partIdtf->partArea == PART_AREA_RANGE || partIdtf->partArea == PART_AREA_INTERVAL) { SetLocktagPartitionOid(&tag, partrelid, partid); } @@ -1059,7 +1046,7 @@ void UnLockPartitionVacuumForSession(PartitionIdentifier *partIdtf, Oid partreli { LOCKTAG tag; - if (partIdtf->partArea == PART_AREA_RANGE) { + if (partIdtf->partArea == PART_AREA_RANGE || partIdtf->partArea == PART_AREA_INTERVAL) { SetLocktagPartitionOid(&tag, partrelid, partid); } diff --git a/src/include/catalog/heap.h b/src/include/catalog/heap.h index c06ef6b878..c0cca8ef7d 100755 --- a/src/include/catalog/heap.h +++ b/src/include/catalog/heap.h @@ -76,7 +76,6 @@ extern void addNewPartitionTuple(Relation pg_part_desc, Partition new_part_desc, extern void heap_truncate_one_part(Relation rel , Oid partOid); extern Oid heapTupleGetPartitionId(Relation rel, HeapTuple tuple); -extern Oid createNewIntervalFile(Relation rel, int seqNum); extern void heap_truncate(List *relids); extern void heap_truncate_one_rel(Relation rel); extern void heap_truncate_check_FKs(List *relations, bool tempTables); @@ -144,4 +143,6 @@ extern char* make_column_map(TupleDesc tuple_desc); */ extern bool* check_partkey_has_timestampwithzone(Relation partTableRel); +extern Oid AddNewIntervalPartition(Relation rel, HeapTuple insertTuple); + #endif /* HEAP_H */ diff --git a/src/include/catalog/pg_partition_fn.h b/src/include/catalog/pg_partition_fn.h index db12315671..f11ee12fe2 100644 --- a/src/include/catalog/pg_partition_fn.h +++ b/src/include/catalog/pg_partition_fn.h @@ -42,7 +42,10 @@ #define MAX_PARTITIONKEY_NUM 4 #define MAX_PARTITION_NUM 32767 /* update LEN_PARTITION_PREFIX as well ! */ - +#define INTERVAL_PARTITION_NAME_PREFIX "sys_p" +#define INTERVAL_PARTITION_NAME_PREFIX_FMT "sys_p%u" +#define INTERVAL_PARTITION_NAME_SUFFIX_LEN 5 /* max length of partitio num */ + /* * In start/end syntax, partition name is of form: * PARTITION_PREFIX_NUM, @@ -72,7 +75,7 @@ typedef void (*PartitionNameGetPartidCallback) (Oid partitioned_relation, const char *partition_name, Oid partId, Oid oldPartId, char partition_type, void *callback_arg, LOCKMODE callbackobj_lockMode); extern void insertPartitionEntry(Relation pg_partition_desc, Partition new_part_desc, Oid new_part_id, - int2vector *pkey, oidvector *inttablespace, Datum interval, + int2vector *pkey, const oidvector *inttablespace, Datum interval, Datum maxValues, Datum transitionPoint, Datum reloptions, char parttype); extern bool isPartitionedObject(Oid relid, char relkind, bool missing_ok); extern bool isPartitionObject(Oid partid, char partkind, bool missing_ok); diff --git a/src/include/commands/tablecmds.h b/src/include/commands/tablecmds.h index 125489e0a1..5350a04890 100755 --- a/src/include/commands/tablecmds.h +++ b/src/include/commands/tablecmds.h @@ -123,7 +123,6 @@ extern void ATExecSetIndexUsableState(Oid objclassOid, Oid objOid, bool newState extern bool checkPartitionLocalIndexesUsable(Oid partitionOid); extern bool checkRelationLocalIndexesUsable(Relation relation); extern List* GetPartitionkeyPos(List* partitionkeys, List* schema); -extern void CheckPartitionKeyType(Form_pg_attribute* attrs, List* pos, bool is_interval); extern void clearAttrInitDefVal(Oid relid); @@ -140,5 +139,7 @@ extern Node* GetTargetValue(Form_pg_attribute attrs, Const* src, bool isinterval extern void ATExecEnableDisableRls(Relation rel, RelationRlsStatus changeType, LOCKMODE lockmode); extern void create_part_policy_if_needed(CreateStmt *stmt, char relkind); +extern void addToastTableForNewPartition(Relation relation, Oid newPartId); +extern void fastDropPartition(Relation rel, Oid partOid, const char* stmt, Oid intervalPartOid = InvalidOid); #endif /* TABLECMDS_H */ diff --git a/src/include/utils/partcache.h b/src/include/utils/partcache.h index 72d4ffecfa..d70bb5eacb 100755 --- a/src/include/utils/partcache.h +++ b/src/include/utils/partcache.h @@ -47,6 +47,9 @@ extern Partition PartitionIdGetPartition(Oid partitionId); extern void PartitionClose(Partition partition); +extern char* PartitionOidGetName(Oid partOid); +extern Oid PartitionOidGetTablespace(Oid partOid); + /* * Routines for flushing/rebuilding relcache entries in various scenarios */ diff --git a/src/include/utils/partitionmap.h b/src/include/utils/partitionmap.h index ee658fd4ee..26291665d7 100755 --- a/src/include/utils/partitionmap.h +++ b/src/include/utils/partitionmap.h @@ -56,8 +56,7 @@ typedef struct PartitionMap { #define VALUE_PARTKEYMAXNUM 4 #define INTERVAL_PARTKEYMAXNUM 1 -#define PartitionLogicalExist(partitionIdentifier) \ - ((partitionIdentifier)->partSeq >= 0 && (partitionIdentifier)->partArea != PART_AREA_NONE) +#define PartitionLogicalExist(partitionIdentifier) ((partitionIdentifier)->partSeq >= 0) #define PartitionPhysicalExist(partitionIdentifier) \ ((partitionIdentifier)->partArea != PART_AREA_NONE && ((partitionIdentifier)->fileExist) @@ -98,7 +97,6 @@ extern Oid getRangePartitionOid(Relation relation, Const** partKeyValue, int* pa extern List* getPartitionBoundaryList(Relation rel, int sequence); extern Oid partitionKeyValueListGetPartitionOid(Relation rel, List* partKeyValueList, bool topClosed); extern int getNumberOfRangePartitions(Relation rel); -extern int getNumberOfIntervalPartitions(Relation rel); extern int getNumberOfPartitions(Relation rel); extern Const* transformDatum2Const(TupleDesc tupledesc, int16 attnum, Datum datumValue, bool isnull, Const* cnst); diff --git a/src/include/utils/partitionmap_gs.h b/src/include/utils/partitionmap_gs.h index 024f5bb0e4..5fe3a13360 100755 --- a/src/include/utils/partitionmap_gs.h +++ b/src/include/utils/partitionmap_gs.h @@ -69,6 +69,7 @@ typedef struct RangeElement { Oid partitionOid; /*the oid of partition*/ int len; /*the length of partition key number*/ Const* boundary[RANGE_PARTKEYMAXNUM]; /*upper bond of partition */ + bool isInterval; /* is interval partition */ } RangeElement; typedef struct IntervalElement { @@ -90,29 +91,13 @@ typedef struct RangePartitionMap { int2vector* partitionKey; /*partition key*/ Oid* partitionKeyDataType; /*the data type of partition key*/ /*section 1: range partition specific*/ - int rangeElementsNum; /*the number of range partition*/ - RangeElement* rangeElements; /*array of RangeElement*/ + int rangeElementsNum; /*the number of range partition*/ + RangeElement* rangeElements; /*array of RangeElement*/ + Interval* intervalValue; /* valid for interval partition */ + oidvector* intervalTablespace; /* valid for interval partition */ } RangePartitionMap; -/* - * describe partition info of Interval Partitioned-Table - * intervalElements: starting from min existing interval partition, to max existing interval partition. - and holes for un-created between them - * sequenceMap: bitmap representation of intervalElements - */ -typedef struct IntervalPartitionMap { - RangePartitionMap rangePartitionMap; - /*section 2: interval partition specific*/ - int intervalElementsNum; - IntervalElement* intervalElements; /*array of IntervalElement, it's bitmap represetation is sequenceMap belowing*/ - Datum transitionPoint; /*the low boundary of interval part*/ - Datum intervalValue; - int intervalMaxSeq; /*sequence number of last interval element in intervalElements*/ - int intervalMinSeq; /*sequence number of first interval element in intervalElements*/ - Bitmapset* sequenceMap; /*a bit map represent which interval partition is created*/ - bool transitionPointByVal; - bool intervalValuePointByVal; -} IntervalPartitionMap; +bool ValueSatisfyLowBoudary(Const** partKeyValue, RangeElement* partition, Interval* intervalValue, bool topClosed); #define PartitionkeyTypeGetIntervalType(type) \ do { \ @@ -153,29 +138,57 @@ typedef struct IntervalPartitionMap { do { \ if ((rel)->partMap->type == PART_TYPE_RANGE) { \ (result)->partArea = PART_AREA_RANGE; \ - (result)->partitionId = getRangePartitionOid((rel), (keyValue), &((result)->partSeq), topClosed); \ - if ((result)->partSeq < 0) { \ - (result)->fileExist = false; \ - } else { \ - (result)->fileExist = true; \ - } \ } else if (rel->partMap->type == PART_TYPE_INTERVAL) { \ Assert((valueLen) == 1); \ - (result)->partitionId = getIntervalPartitionOid((IntervalPartitionMap*)((rel)->partMap), \ - (keyValue), \ - &((result)->partSeq), \ - &((result)->partArea), \ - topClosed, \ - missIsOk); \ - if (OidIsValid((result)->partitionId)) { \ - (result)->fileExist = true; \ - } else { \ + (result)->partArea = PART_AREA_INTERVAL; \ + } else { \ + ereport(ERROR, \ + (errcode(ERRCODE_INTERNAL_ERROR), errmsg("Unsupported partition strategy:%d", (rel)->partMap->type))); \ + } \ + (result)->partitionId = getRangePartitionOid((rel), (keyValue), &((result)->partSeq), topClosed); \ + if ((result)->partSeq < 0) { \ + (result)->fileExist = false; \ + } else { \ + (result)->fileExist = true; \ + RangePartitionMap* partMap = (RangePartitionMap*)((rel)->partMap); \ + if (partMap->rangeElements[(result)->partSeq].isInterval && \ + !ValueSatisfyLowBoudary( \ + keyValue, &partMap->rangeElements[(result)->partSeq], partMap->intervalValue, topClosed)) { \ + (result)->partSeq = -1; \ + (result)->partitionId = InvalidOid; \ (result)->fileExist = false; \ } \ + } \ + } while (0) + +/* + * search >/>= keyValue partition if direction is true + * search partMap->type == PART_TYPE_RANGE) { \ + (result)->partArea = PART_AREA_RANGE; \ + } else if (rel->partMap->type == PART_TYPE_INTERVAL) { \ + Assert((valueLen) == 1); \ + (result)->partArea = PART_AREA_INTERVAL; \ } else { \ ereport(ERROR, \ (errcode(ERRCODE_INTERNAL_ERROR), errmsg("Unsupported partition strategy:%d", (rel)->partMap->type))); \ } \ + (result)->partitionId = getRangePartitionOid((rel), (keyValue), &((result)->partSeq), topClosed); \ + if ((result)->partSeq < 0) { \ + (result)->fileExist = false; \ + } else { \ + (result)->fileExist = true; \ + RangePartitionMap* partMap = (RangePartitionMap*)((rel)->partMap); \ + if (partMap->rangeElements[(result)->partSeq].isInterval && !direction && \ + !ValueSatisfyLowBoudary( \ + keyValue, &partMap->rangeElements[(result)->partSeq], partMap->intervalValue, topClosed)) { \ + --((result)->partSeq); \ + (result)->partitionId = partMap->rangeElements[(result)->partSeq].partitionOid; \ + } \ + } \ } while (0) typedef enum PruningResultState { PRUNING_RESULT_EMPTY, PRUNING_RESULT_SUBSET, PRUNING_RESULT_FULL } PruningResultState; @@ -338,8 +351,6 @@ extern Oid partIDGetPartOid(Relation relation, PartitionIdentifier* partID); extern PartitionIdentifier* partOidGetPartID(Relation rel, Oid partOid); extern void RebuildPartitonMap(PartitionMap* oldMap, PartitionMap* newMap); -extern Oid getIntervalPartitionOid(IntervalPartitionMap* intervalPartMap, Const** partKeyValue, int32* partIndex, - PartitionArea* partArea, bool topClosed, bool missIsOk); bool isPartKeyValuesInPartition(RangePartitionMap* partMap, Const** partKeyValues, int partkeyColumnNum, int partSeq); extern int comparePartitionKey(RangePartitionMap* partMap, Const** values1, Const** values2, int partKeyNum); @@ -347,5 +358,10 @@ extern int comparePartitionKey(RangePartitionMap* partMap, Const** values1, Cons extern int lookupHBucketid(oidvector *buckets, int low, int2 bucket_id); extern int2 computeTupleBucketId(Relation rel, HeapTuple tuple); - + +extern Oid GetNeedDegradToRangePartOid(Relation rel, Oid partOid); +extern RangeElement* CopyRangeElementsWithoutBoundary(const RangeElement* src, int elementNum); +extern char* ReadIntervalStr(HeapTuple tuple, TupleDesc tupleDesc); +extern oidvector* ReadIntervalTablespace(HeapTuple tuple, TupleDesc tupleDesc); + #endif /* PARTITIONMAP_GS_H_ */ diff --git a/src/include/utils/timestamp.h b/src/include/utils/timestamp.h index 1aebe36731..e35bd87075 100755 --- a/src/include/utils/timestamp.h +++ b/src/include/utils/timestamp.h @@ -189,6 +189,7 @@ extern Datum timestamptz_timestamptz(PG_FUNCTION_ARGS); extern Datum interval_um(PG_FUNCTION_ARGS); extern Datum interval_pl(PG_FUNCTION_ARGS); extern Datum interval_mi(PG_FUNCTION_ARGS); +extern Datum interval_mul(Interval* span, float8 factor); extern Datum interval_mul(PG_FUNCTION_ARGS); extern Datum mul_d_interval(PG_FUNCTION_ARGS); extern Datum interval_div(PG_FUNCTION_ARGS); @@ -198,8 +199,11 @@ extern Datum interval_collect(PG_FUNCTION_ARGS); #endif extern Datum interval_avg(PG_FUNCTION_ARGS); +extern Datum timestamp_mi(Timestamp dt1, Timestamp dt2); extern Datum timestamp_mi(PG_FUNCTION_ARGS); +extern Datum timestamp_pl_interval(Timestamp timestamp, Interval* span); extern Datum timestamp_pl_interval(PG_FUNCTION_ARGS); +extern Datum timestamp_mi_interval(Timestamp timestamp, Interval* span); extern Datum timestamp_mi_interval(PG_FUNCTION_ARGS); extern Datum timestamp_age(PG_FUNCTION_ARGS); extern Datum timestamp_diff(PG_FUNCTION_ARGS); diff --git a/src/test/regress/expected/hw_partition_cross.out b/src/test/regress/expected/hw_partition_cross.out index ef18cd43b2..95b69d0285 100644 --- a/src/test/regress/expected/hw_partition_cross.out +++ b/src/test/regress/expected/hw_partition_cross.out @@ -140,7 +140,7 @@ create index cross_test_table_index on cross_test_table(c1) local; delete from cross_test_table where c1 = 149; rollback; select * from cross_test_table order by 1; -ERROR: relation "cross_test_table" does not exist +ERROR: relation "cross_test_table" does not exist on datanode1 LINE 1: select * from cross_test_table order by 1; ^ --table not exist diff --git a/src/test/regress/expected/hw_partition_interval_exchange.out b/src/test/regress/expected/hw_partition_interval_exchange.out new file mode 100644 index 0000000000..4de0545da5 --- /dev/null +++ b/src/test/regress/expected/hw_partition_interval_exchange.out @@ -0,0 +1,217 @@ +-- +-- Test exchange operator for interval partitioned table +-- +-- +---- create interval partitioned table +-- +CREATE TABLE interval_normal_exchange (logdate date not null) +PARTITION BY RANGE (logdate) +INTERVAL ('1 month') +( + PARTITION interval_normal_exchange_p1 VALUES LESS THAN ('2020-03-01'), + PARTITION interval_normal_exchange_p2 VALUES LESS THAN ('2020-04-01'), + PARTITION interval_normal_exchange_p3 VALUES LESS THAN ('2020-05-01') +); +-- see about the info of the partitioned table in pg_partition +select relname, parttype, partstrategy, boundaries from pg_partition + where parentid = (select oid from pg_class where relname = 'interval_normal_exchange') + order by relname; + relname | parttype | partstrategy | boundaries +-----------------------------+----------+--------------+-------------- + interval_normal_exchange | r | i | + interval_normal_exchange_p1 | p | r | {2020-03-01} + interval_normal_exchange_p2 | p | r | {2020-04-01} + interval_normal_exchange_p3 | p | r | {2020-05-01} +(4 rows) + +-- insert the record that is smaller than the lower boundary +insert into interval_normal_exchange values ('2020-02-21'); +insert into interval_normal_exchange values ('2020-02-22'); +insert into interval_normal_exchange values ('2020-02-23'); +insert into interval_normal_exchange values ('2020-5-01'); +insert into interval_normal_exchange values ('2020-5-02'); +insert into interval_normal_exchange values ('2020-5-03'); +-- see about the info of the partitioned table in pg_partition +select relname, parttype, partstrategy, boundaries from pg_partition + where parentid = (select oid from pg_class where relname = 'interval_normal_exchange') + order by relname; + relname | parttype | partstrategy | boundaries +-----------------------------+----------+--------------+------------------------------ + interval_normal_exchange | r | i | + interval_normal_exchange_p1 | p | r | {2020-03-01} + interval_normal_exchange_p2 | p | r | {2020-04-01} + interval_normal_exchange_p3 | p | r | {2020-05-01} + sys_p1 | p | i | {"Mon Jun 01 00:00:00 2020"} +(5 rows) + +-- +---- create to be exchanged table and test range partition exchange +-- +CREATE TABLE interval_exchange_test (logdate date not null); +insert into interval_exchange_test values ('2020-02-24'); +insert into interval_exchange_test values ('2020-02-25'); +insert into interval_exchange_test values ('2020-02-26'); +-- do exchange partition interval_normal_exchange_p1 and interval_exchange_test +-- The data they have belongs to the same range. +ALTER TABLE interval_normal_exchange EXCHANGE PARTITION (interval_normal_exchange_p1) + WITH TABLE interval_exchange_test; +select * from interval_normal_exchange partition (interval_normal_exchange_p1)order by logdate; + logdate +-------------------------- + Mon Feb 24 00:00:00 2020 + Tue Feb 25 00:00:00 2020 + Wed Feb 26 00:00:00 2020 +(3 rows) + +select * from interval_exchange_test order by logdate; + logdate +-------------------------- + Fri Feb 21 00:00:00 2020 + Sat Feb 22 00:00:00 2020 + Sun Feb 23 00:00:00 2020 +(3 rows) + +-- exchange back +ALTER TABLE interval_normal_exchange EXCHANGE PARTITION (interval_normal_exchange_p1) + WITH TABLE interval_exchange_test; +select * from interval_normal_exchange partition (interval_normal_exchange_p1)order by logdate; + logdate +-------------------------- + Fri Feb 21 00:00:00 2020 + Sat Feb 22 00:00:00 2020 + Sun Feb 23 00:00:00 2020 +(3 rows) + +select * from interval_exchange_test order by logdate; + logdate +-------------------------- + Mon Feb 24 00:00:00 2020 + Tue Feb 25 00:00:00 2020 + Wed Feb 26 00:00:00 2020 +(3 rows) + +-- Insert a new record not belongs to interval_normal_exchange_p1 +insert into interval_exchange_test values ('2020-3-05'); +-- defaut is WITH VALIDATION, and the exchange will be failed +ALTER TABLE interval_normal_exchange EXCHANGE PARTITION (interval_normal_exchange_p1) + WITH TABLE interval_exchange_test; +ERROR: some rows in table do not qualify for specified partition +-- WITHOUT VALIDATION and the exchange will be success, but some date will in the wrong range; +ALTER TABLE interval_normal_exchange EXCHANGE PARTITION (interval_normal_exchange_p1) + WITH TABLE interval_exchange_test WITHOUT VALIDATION; +select * from interval_normal_exchange partition (interval_normal_exchange_p1)order by logdate; + logdate +-------------------------- + Mon Feb 24 00:00:00 2020 + Tue Feb 25 00:00:00 2020 + Wed Feb 26 00:00:00 2020 + Thu Mar 05 00:00:00 2020 +(4 rows) + +select * from interval_exchange_test order by logdate; + logdate +-------------------------- + Fri Feb 21 00:00:00 2020 + Sat Feb 22 00:00:00 2020 + Sun Feb 23 00:00:00 2020 +(3 rows) + +-- not include '2020-3-05' +select * from interval_normal_exchange where logdate > '2020-03-01' order by logdate; + logdate +-------------------------- + Fri May 01 00:00:00 2020 + Sat May 02 00:00:00 2020 + Sun May 03 00:00:00 2020 +(3 rows) + +-- +---- clean the data and test interval partition exchange +-- +truncate table interval_exchange_test; +insert into interval_exchange_test values ('2020-5-04'); +insert into interval_exchange_test values ('2020-5-05'); +insert into interval_exchange_test values ('2020-5-06'); +-- exchange table +ALTER TABLE interval_normal_exchange EXCHANGE PARTITION (sys_p1) + WITH TABLE interval_exchange_test; +select * from interval_normal_exchange partition (sys_p1)order by logdate; + logdate +-------------------------- + Mon May 04 00:00:00 2020 + Tue May 05 00:00:00 2020 + Wed May 06 00:00:00 2020 +(3 rows) + +select * from interval_exchange_test order by logdate; + logdate +-------------------------- + Fri May 01 00:00:00 2020 + Sat May 02 00:00:00 2020 + Sun May 03 00:00:00 2020 +(3 rows) + +-- exchange back +ALTER TABLE interval_normal_exchange EXCHANGE PARTITION (sys_p1) + WITH TABLE interval_exchange_test; +select * from interval_normal_exchange partition (sys_p1)order by logdate; + logdate +-------------------------- + Fri May 01 00:00:00 2020 + Sat May 02 00:00:00 2020 + Sun May 03 00:00:00 2020 +(3 rows) + +select * from interval_exchange_test order by logdate; + logdate +-------------------------- + Mon May 04 00:00:00 2020 + Tue May 05 00:00:00 2020 + Wed May 06 00:00:00 2020 +(3 rows) + +insert into interval_exchange_test values ('2020-6-05'); +-- defaut is WITH VALIDATION, and the exchange will be failed +ALTER TABLE interval_normal_exchange EXCHANGE PARTITION (interval_normal_exchange_p1) + WITH TABLE interval_exchange_test; +ERROR: some rows in table do not qualify for specified partition +-- WITHOUT VALIDATION and the exchange will be success, but some date will in the wrong range; +ALTER TABLE interval_normal_exchange EXCHANGE PARTITION (interval_normal_exchange_p1) + WITH TABLE interval_exchange_test WITHOUT VALIDATION; +select * from interval_normal_exchange partition (interval_normal_exchange_p1)order by logdate; + logdate +-------------------------- + Mon May 04 00:00:00 2020 + Tue May 05 00:00:00 2020 + Wed May 06 00:00:00 2020 + Fri Jun 05 00:00:00 2020 +(4 rows) + +select * from interval_exchange_test order by logdate; + logdate +-------------------------- + Mon Feb 24 00:00:00 2020 + Tue Feb 25 00:00:00 2020 + Wed Feb 26 00:00:00 2020 + Thu Mar 05 00:00:00 2020 +(4 rows) + +-- not include '2020-6-05' +select * from interval_normal_exchange order by logdate; + logdate +-------------------------- + Fri May 01 00:00:00 2020 + Sat May 02 00:00:00 2020 + Sun May 03 00:00:00 2020 + Mon May 04 00:00:00 2020 + Tue May 05 00:00:00 2020 + Wed May 06 00:00:00 2020 + Fri Jun 05 00:00:00 2020 +(7 rows) + +select * from interval_normal_exchange where logdate > '2020-06-01' order by logdate; + logdate +--------- +(0 rows) + +drop table interval_normal_exchange; diff --git a/src/test/regress/expected/hw_partition_interval_index.out b/src/test/regress/expected/hw_partition_interval_index.out new file mode 100644 index 0000000000..4768b3cfad --- /dev/null +++ b/src/test/regress/expected/hw_partition_interval_index.out @@ -0,0 +1,426 @@ +-- +---- test interval partitioned index +-- +drop table if exists hw_partition_index_ip; +NOTICE: table "hw_partition_index_ip" does not exist, skipping +create table hw_partition_index_ip +( + c1 int, + c2 int, + logdate date not null +) +partition by range (logdate) +INTERVAL ('1 month') +( + PARTITION hw_partition_index_ip_p0 VALUES LESS THAN ('2020-03-01'), + PARTITION hw_partition_index_ip_p1 VALUES LESS THAN ('2020-04-01'), + PARTITION hw_partition_index_ip_p2 VALUES LESS THAN ('2020-05-01') +); +--succeed +create index ip_index_local1 on hw_partition_index_ip (c1) local; +--succeed +create index ip_index_local2 on hw_partition_index_ip (logdate) local +( + partition, + partition, + partition +); +ERROR: syntax error at or near "," +LINE 3: partition, + ^ +--fail , the gram.y is not support opt_index_name +create index ip_index_local3 on hw_partition_index_ip (logdate) local +( + partition sip1_index_local, + partition sip2_index_local, + partition sip3_index_local +); +--succeed +create index ip_index_local4 on hw_partition_index_ip (logdate) local +( + partition sip1_index_local tablespace PG_DEFAULT, + partition sip2_index_local tablespace PG_DEFAULT, + partition sip3_index_local tablespace PG_DEFAULT +); +--succeed +create index ip_index_local6 on hw_partition_index_ip (logdate) local +( + partition sip1_index_local, + partition sip2_index_local tablespace PG_DEFAULT, + partition sip3_index_local tablespace PG_DEFAULT +); +--succeed +create unique index ip_index_local7 on hw_partition_index_ip (logdate) local +( + partition sip1_index_local tablespace PG_DEFAULT, + partition sip2_index_local tablespace PG_DEFAULT, + partition sip3_index_local tablespace PG_DEFAULT +); +--succeed +create unique index on hw_partition_index_ip (logdate) local +( + partition sip1_index_local tablespace PG_DEFAULT, + partition sip2_index_local tablespace PG_DEFAULT, + partition sip3_index_local tablespace PG_DEFAULT +); +-- fail same partition name +create unique index on hw_partition_index_ip (logdate) local +( + partition sip1_index_local tablespace PG_DEFAULT, + partition sip2_index_local tablespace PG_DEFAULT, + partition sip2_index_local tablespace PG_DEFAULT +); +ERROR: index partition with name "sip2_index_local" already exists +-- +---- expression, only test sample expression for inter1, more info see hw_partition_index.sql +-- +create index on hw_partition_index_ip ((c1+c2)) local +( + partition sip1_index_local tablespace PG_DEFAULT, + partition sip2_index_local tablespace PG_DEFAULT, + partition sip3_index_local tablespace PG_DEFAULT +); +--succeed +create index on hw_partition_index_ip ((c1-c2)) local +( + partition sip1_index_local tablespace PG_DEFAULT, + partition sip2_index_local tablespace PG_DEFAULT, + partition sip3_index_local tablespace PG_DEFAULT +); +--succeed +--not support CONCURRENTLY +create unique index CONCURRENTLY on hw_partition_index_ip (logdate) local +( + partition sip1_index_local tablespace PG_DEFAULT, + partition sip2_index_local tablespace PG_DEFAULT, + partition sip3_index_local tablespace PG_DEFAULT +); +ERROR: PGXC does not support concurrent INDEX yet +DETAIL: The feature is not currently supported +-- Not enough index partition defined +create unique index on hw_partition_index_ip (logdate) local +( + partition sip1_index_local tablespace PG_DEFAULT, + partition sip2_index_local tablespace PG_DEFAULT +); +ERROR: Not enough index partition defined +-- number of partitions of LOCAL index must equal that of the underlying table +create unique index on hw_partition_index_ip (logdate) local +( + partition sip1_index_local tablespace PG_DEFAULT, + partition sip2_index_local tablespace PG_DEFAULT, + partition sip3_index_local tablespace PG_DEFAULT, + partition sip4_index_local tablespace PG_DEFAULT +); +ERROR: number of partitions of LOCAL index must equal that of the underlying table +create unique index on hw_partition_index_ip (logdate); +ERROR: partitioned table does not support global index +--fail wrong syntax +drop table hw_partition_index_ip; +--unique index , index para must contain partition key +create table hw_partition_index_ip +( + c1 int, + c2 int, + logdate date not null +) +partition by range (logdate) +INTERVAL ('1 month') +( + PARTITION hw_partition_index_ip_p0 VALUES LESS THAN ('2020-03-01'), + PARTITION hw_partition_index_ip_p1 VALUES LESS THAN ('2020-04-01'), + PARTITION hw_partition_index_ip_p2 VALUES LESS THAN ('2020-05-01') +); +-- succeed +create unique index ip_index_local on hw_partition_index_ip (c1,logdate) local +( + partition sip1_index_local tablespace PG_DEFAULT, + partition sip2_index_local tablespace PG_DEFAULT, + partition sip3_index_local tablespace PG_DEFAULT +); +-- fail without logdate +create unique index ip_index_local2 on hw_partition_index_ip (c1) local +( + partition sip1_index_local tablespace PG_DEFAULT , + partition sip2_index_local tablespace PG_DEFAULT, + partition sip3_index_local tablespace PG_DEFAULT +); +ERROR: unique index columns must contain the partition key and collation must be default collation +create unique index ip_index_local3 on hw_partition_index_ip (c2, c1) local +( + partition sip1_index_local tablespace PG_DEFAULT, + partition sip2_index_local tablespace PG_DEFAULT, + partition sip3_index_local tablespace PG_DEFAULT +); +ERROR: unique index columns must contain the partition key and collation must be default collation +--insert into table +insert into hw_partition_index_ip values(7,2,'2020-03-01'); +insert into hw_partition_index_ip values(3,1,'2020-04-01'); +insert into hw_partition_index_ip values(5,3,'2020-05-01'); +insert into hw_partition_index_ip values(7,5,'2020-06-01'); +insert into hw_partition_index_ip values(1,4,'2020-07-01'); +--succeed +select * from hw_partition_index_ip order by 1, 2; + c1 | c2 | logdate +----+----+-------------------------- + 1 | 4 | Wed Jul 01 00:00:00 2020 + 3 | 1 | Wed Apr 01 00:00:00 2020 + 5 | 3 | Fri May 01 00:00:00 2020 + 7 | 2 | Sun Mar 01 00:00:00 2020 + 7 | 5 | Mon Jun 01 00:00:00 2020 +(5 rows) + +--to select all index object +select part.relname, part.parttype, part.rangenum, + part.intervalnum, + part.partstrategy, + part.relallvisible, + part.reltoastrelid, + part.partkey, + part.interval, + part.boundaries + from pg_class class , pg_partition part , pg_index ind where class.relname = 'hw_partition_index_ip' and ind.indrelid = class.oid and part.parentid = ind.indexrelid order by 1, 2, 3, 4, 5, 6, 7, 8, 9, 10; + relname | parttype | rangenum | intervalnum | partstrategy | relallvisible | reltoastrelid | partkey | interval | boundaries +-----------------------+----------+----------+-------------+--------------+---------------+---------------+---------+----------+------------ + sip1_index_local | x | 0 | 0 | n | 0 | 0 | | | + sip2_index_local | x | 0 | 0 | n | 0 | 0 | | | + sip3_index_local | x | 0 | 0 | n | 0 | 0 | | | + sys_p1_c1_logdate_idx | x | 0 | 0 | n | 0 | 0 | | | + sys_p2_c1_logdate_idx | x | 0 | 0 | n | 0 | 0 | | | + sys_p3_c1_logdate_idx | x | 0 | 0 | n | 0 | 0 | | | +(6 rows) + +drop index ip_index_local; +drop table if exists hw_partition_index_ip; +select count(*) from pg_class class , pg_partition part , pg_index ind where class.relname = 'hw_partition_index_ip' and ind.indrelid = class.oid and part.parentid = ind.indexrelid; + count +------- + 0 +(1 row) + +-- +---- test input for unique index +-- +create table interval_partition_table_001 +( + c1 int, + logdate date not null +) +partition by range (logdate) +INTERVAL ('1 month') +( + PARTITION interval_partition_table_001_p0 VALUES LESS THAN ('2020-03-01'), + PARTITION interval_partition_table_001_p1 VALUES LESS THAN ('2020-04-01'), + PARTITION interval_partition_table_001_p2 VALUES LESS THAN ('2020-05-01') +); +create unique index index_interval_partition_table_001 on interval_partition_table_001(logdate) local; +--fail: unique index +insert into interval_partition_table_001 values(10, '2020-06-01'); +insert into interval_partition_table_001 values(10, '2020-06-01'); +ERROR: duplicate key value violates unique constraint "index_interval_partition_table_001" +DETAIL: Key (logdate)=(Mon Jun 01 00:00:00 2020) already exists. +analyze interval_partition_table_001; +drop table interval_partition_table_001; +-- +---- test with primary key +-- +create table interval_partition_table_002( + c1 int, + c2 int, + logdate date not null, + CONSTRAINT interval_partition_table_CONSTRAINT PRIMARY KEY(c2,logdate) +) +partition by range (logdate) +INTERVAL ('1 month') +( + PARTITION interval_partition_table_002_p0 VALUES LESS THAN ('2020-03-01'), + PARTITION interval_partition_table_002_p1 VALUES LESS THAN ('2020-04-01'), + PARTITION interval_partition_table_002_p2 VALUES LESS THAN ('2020-05-01') +); +NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "interval_partition_table_constraint" for table "interval_partition_table_002" +insert into interval_partition_table_002 values(10, 10, '2020-06-01'); +insert into interval_partition_table_002 values(10, 10, '2020-06-01'); +ERROR: duplicate key value violates unique constraint "interval_partition_table_constraint" +DETAIL: Key (c2, logdate)=(10, Mon Jun 01 00:00:00 2020) already exists. +analyze interval_partition_table_002; +drop table interval_partition_table_002; +-- +---- test with hash index, not support hash index yet; +-- +create table interval_partition_table_003( + c1 int, + c2 int, + logdate date not null, + PRIMARY KEY(c2,logdate) +) +partition by range (logdate) +INTERVAL ('1 month') +( + PARTITION interval_partition_table_003_p0 VALUES LESS THAN ('2020-03-01'), + PARTITION interval_partition_table_003_p1 VALUES LESS THAN ('2020-04-01'), + PARTITION interval_partition_table_003_p2 VALUES LESS THAN ('2020-05-01') +); +NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "interval_partition_table_003_pkey" for table "interval_partition_table_003" +create index interval_partition_table_003_1 ON interval_partition_table_003 USING HASH (logdate) LOCAL; +ERROR: access method "hash" does not support row store +create index interval_partition_table_003_2 ON interval_partition_table_003 USING HASH (c2) LOCAL; +ERROR: access method "hash" does not support row store +create index interval_partition_table_003_3 ON interval_partition_table_003 USING HASH (c1) LOCAL; +ERROR: access method "hash" does not support row store +select relname from pg_partition where INDEXTBLID=(select RELFILENODE from pg_partition where relname='interval_partition_table_003_1') order by 1; + relname +--------- +(0 rows) + +select relname from pg_partition where INDEXTBLID=(select RELFILENODE from pg_partition where relname='interval_partition_table_003_2') order by 1; + relname +--------- +(0 rows) + +select relname from pg_partition where INDEXTBLID=(select RELFILENODE from pg_partition where relname='interval_partition_table_003_3') order by 1; + relname +--------- +(0 rows) + +insert into interval_partition_table_003 values(1,2,'2020-03-01'); +insert into interval_partition_table_003 values(1,2,'2020-04-01'); +insert into interval_partition_table_003 values(1,2,'2020-05-01'); +insert into interval_partition_table_003 values(1,2,'2020-06-01'); +insert into interval_partition_table_003 values(1,2,'2020-07-01'); +alter table interval_partition_table_003 drop column C2; +insert into interval_partition_table_003 values(1,2,'2020-07-01'); +ERROR: INSERT has more expressions than target columns +LINE 1: ...sert into interval_partition_table_003 values(1,2,'2020-07-0... + ^ +insert into interval_partition_table_003 values(1,'2020-07-01'); +select relname from pg_partition where INDEXTBLID=(select RELFILENODE from pg_partition where relname='interval_partition_table_003_1') order by 1; + relname +--------- +(0 rows) + +select relname from pg_partition where INDEXTBLID=(select RELFILENODE from pg_partition where relname='interval_partition_table_003_2') order by 1; + relname +--------- +(0 rows) + +select relname from pg_partition where INDEXTBLID=(select RELFILENODE from pg_partition where relname='interval_partition_table_003_3') order by 1; + relname +--------- +(0 rows) + +select relname, parttype, partstrategy, boundaries from pg_partition + where parentid = (select oid from pg_class where relname = 'interval_partition_table_003') + order by relname; + relname | parttype | partstrategy | boundaries +---------------------------------+----------+--------------+------------------------------ + interval_partition_table_003 | r | i | + interval_partition_table_003_p0 | p | r | {2020-03-01} + interval_partition_table_003_p1 | p | r | {2020-04-01} + interval_partition_table_003_p2 | p | r | {2020-05-01} + sys_p1 | p | i | {"Mon Jun 01 00:00:00 2020"} + sys_p2 | p | i | {"Wed Jul 01 00:00:00 2020"} + sys_p3 | p | i | {"Sat Aug 01 00:00:00 2020"} +(7 rows) + +analyze interval_partition_table_003; +drop table interval_partition_table_003; +-- +---- test partition BTREE index +-- +create table interval_partition_table_004( + c1 int, + c2 int, + logdate date not null, + PRIMARY KEY(c2,logdate) +) +partition by range (logdate) +INTERVAL ('1 month') +( + PARTITION interval_partition_table_004_p0 VALUES LESS THAN ('2020-03-01'), + PARTITION interval_partition_table_004_p1 VALUES LESS THAN ('2020-04-01'), + PARTITION interval_partition_table_004_p2 VALUES LESS THAN ('2020-05-01') +); +NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "interval_partition_table_004_pkey" for table "interval_partition_table_004" +-- expression index +CREATE INDEX interval_partition_table_004_index_01 on interval_partition_table_004 using btree(c2) local; +CREATE INDEX interval_partition_table_004_index_02 on interval_partition_table_004 using btree(logdate) local; +CREATE INDEX interval_partition_table_004_index_03 on interval_partition_table_004 using btree(c1) local; +insert into interval_partition_table_004 values(7,2,'2020-03-01'); +insert into interval_partition_table_004 values(3,1,'2020-04-01'); +insert into interval_partition_table_004 values(5,3,'2020-05-01'); +insert into interval_partition_table_004 values(7,5,'2020-06-01'); +insert into interval_partition_table_004 values(1,4,'2020-07-01'); +SELECT * FROM interval_partition_table_004 ORDER BY logdate; + c1 | c2 | logdate +----+----+-------------------------- + 7 | 2 | Sun Mar 01 00:00:00 2020 + 3 | 1 | Wed Apr 01 00:00:00 2020 + 5 | 3 | Fri May 01 00:00:00 2020 + 7 | 5 | Mon Jun 01 00:00:00 2020 + 1 | 4 | Wed Jul 01 00:00:00 2020 +(5 rows) + +SELECT * FROM interval_partition_table_004 ORDER BY 1; + c1 | c2 | logdate +----+----+-------------------------- + 1 | 4 | Wed Jul 01 00:00:00 2020 + 3 | 1 | Wed Apr 01 00:00:00 2020 + 5 | 3 | Fri May 01 00:00:00 2020 + 7 | 2 | Sun Mar 01 00:00:00 2020 + 7 | 5 | Mon Jun 01 00:00:00 2020 +(5 rows) + +SELECT * FROM interval_partition_table_004 ORDER BY 2; + c1 | c2 | logdate +----+----+-------------------------- + 3 | 1 | Wed Apr 01 00:00:00 2020 + 7 | 2 | Sun Mar 01 00:00:00 2020 + 5 | 3 | Fri May 01 00:00:00 2020 + 1 | 4 | Wed Jul 01 00:00:00 2020 + 7 | 5 | Mon Jun 01 00:00:00 2020 +(5 rows) + +DROP TABLE interval_partition_table_004; +-- test interval table with toast table and index +CREATE TABLE interval_sales +(prod_id NUMBER(6), +cust_id NUMBER, +time_id DATE, +channel_id CHAR(1), +promo_id NUMBER(6), +quantity_sold NUMBER(3), +amount_sold NUMBER(10,2) +) +PARTITION BY RANGE (time_id) +INTERVAL('1 MONTH') +( PARTITION p0 VALUES LESS THAN (TO_DATE('1-1-2008', 'DD-MM-YYYY')), + PARTITION p1 VALUES LESS THAN (TO_DATE('6-5-2008', 'DD-MM-YYYY')) +); +select relname, parentid, reltoastrelid, boundaries from pg_partition; + relname | parentid | reltoastrelid | boundaries +----------------+----------+---------------+------------------------------ + interval_sales | 19348 | 0 | + p0 | 19348 | 19354 | {"Tue Jan 01 00:00:00 2008"} + p1 | 19348 | 19357 | {"Tue May 06 00:00:00 2008"} +(3 rows) + +insert into interval_sales values (generate_series(1,10), generate_series(1,10), generate_series(TO_DATE('2020-01-01', 'YYYY-MM-DD'),TO_DATE('2020-07-01', 'YYYY-MM-DD'),'1 day'), 1, 1, 1, 1); +select relname, parentid, reltoastrelid, boundaries from pg_partition; + relname | parentid | reltoastrelid | boundaries +----------------+----------+---------------+------------------------------ + interval_sales | 19348 | 0 | + p0 | 19348 | 19354 | {"Tue Jan 01 00:00:00 2008"} + p1 | 19348 | 19357 | {"Tue May 06 00:00:00 2008"} + sys_p1 | 19348 | 19361 | {"Mon Jan 06 00:00:00 2020"} + sys_p2 | 19348 | 19365 | {"Thu Feb 06 00:00:00 2020"} + sys_p3 | 19348 | 19369 | {"Fri Mar 06 00:00:00 2020"} + sys_p4 | 19348 | 19373 | {"Mon Apr 06 00:00:00 2020"} + sys_p5 | 19348 | 19377 | {"Wed May 06 00:00:00 2020"} + sys_p6 | 19348 | 19381 | {"Sat Jun 06 00:00:00 2020"} + sys_p7 | 19348 | 19385 | {"Mon Jul 06 00:00:00 2020"} +(10 rows) + +drop table interval_sales; +-- +---- test exchange table whit index +-- diff --git a/src/test/regress/expected/hw_partition_interval_movement.out b/src/test/regress/expected/hw_partition_interval_movement.out new file mode 100644 index 0000000000..068ce25a8a --- /dev/null +++ b/src/test/regress/expected/hw_partition_interval_movement.out @@ -0,0 +1,106 @@ +-- +---- test row movement +-- +drop table if exists hw_partition_interval_movement; +NOTICE: table "hw_partition_interval_movement" does not exist, skipping +create table hw_partition_interval_movement +( + c1 int, + c2 int, + C3 date not null +) +partition by range (C3) +INTERVAL ('1 month') +( + PARTITION hw_partition_interval_movement_p0 VALUES LESS THAN ('2020-03-01'), + PARTITION hw_partition_interval_movement_p1 VALUES LESS THAN ('2020-04-01'), + PARTITION hw_partition_interval_movement_p2 VALUES LESS THAN ('2020-05-01') +) DISABLE ROW MOVEMENT; + +create index hw_partition_interval_movement_ind1 on hw_partition_interval_movement(c1) local; +create index hw_partition_interval_movement_ind2 on hw_partition_interval_movement(c2) local; +create index hw_partition_interval_movement_ind3 on hw_partition_interval_movement(c3) local; + +--insert into table +insert into hw_partition_interval_movement values(7,2,'2020-02-01'); +insert into hw_partition_interval_movement values(3,1,'2020-03-01'); +insert into hw_partition_interval_movement values(5,3,'2020-04-01'); +insert into hw_partition_interval_movement values(7,5,'2020-05-01'); +insert into hw_partition_interval_movement values(1,4,'2020-06-01'); + +select relname, parttype, partstrategy, boundaries from pg_partition + where parentid = (select oid from pg_class where relname = 'hw_partition_interval_movement') + order by 1; + relname | parttype | partstrategy | boundaries +-----------------------------------+----------+--------------+------------------------------ + hw_partition_interval_movement | r | i | + hw_partition_interval_movement_p0 | p | r | {2020-03-01} + hw_partition_interval_movement_p1 | p | r | {2020-04-01} + hw_partition_interval_movement_p2 | p | r | {2020-05-01} + sys_p1 | p | i | {"Mon Jun 01 00:00:00 2020"} + sys_p2 | p | i | {"Wed Jul 01 00:00:00 2020"} +(6 rows) + + +-- fail: update record belongs to a range partition which will be move to other range partition +update hw_partition_interval_movement set C3 = '2020-04-22' where C3 = '2020-03-01'; +ERROR: fail to update partitioned table "hw_partition_interval_movement" +DETAIL: disable row movement +-- fail: update record belongs to a range partition which will be move to an existed interval partition +update hw_partition_interval_movement set C3 = '2020-05-22' where C3 = '2020-03-01'; +ERROR: fail to update partitioned table "hw_partition_interval_movement" +DETAIL: disable row movement +-- fail: update record belongs to a range partition which will be move to a not existed interval partition +update hw_partition_interval_movement set C3 = '2020-07-22' where C3 = '2020-03-01'; +ERROR: fail to update partitioned table "hw_partition_interval_movement" +DETAIL: disable row movement +-- fail: update record belongs to a interval partition which will be move to a range partition +update hw_partition_interval_movement set C3 = '2020-03-22' where C3 = '2020-05-01'; +ERROR: fail to update partitioned table "hw_partition_interval_movement" +DETAIL: disable row movement +-- fail: update record belongs to a interval partition which will be move to a not existed interval partition +update hw_partition_interval_movement set C3 = '2020-07-22' where C3 = '2020-05-01'; +ERROR: fail to update partitioned table "hw_partition_interval_movement" +DETAIL: disable row movement + +-- enable row movement +alter table hw_partition_interval_movement ENABLE ROW MOVEMENT; + +-- succeed: update record belongs to a range partition which will be move to other range partition +update hw_partition_interval_movement set C3 = '2020-04-22' where C3 = '2020-03-01'; +-- succeed: update record belongs to a range partition which will be move to an existed interval partition +update hw_partition_interval_movement set C3 = '2020-05-22' where C3 = '2020-04-22'; +-- succeed: update record belongs to a range partition which will be move to a not existed interval partition +update hw_partition_interval_movement set C3 = '2020-07-22' where C3 = '2020-04-01'; +-- succeed: update record belongs to a interval partition which will be move to a range partition +update hw_partition_interval_movement set C3 = '2020-03-22' where C3 = '2020-05-01'; +-- succeed: update record belongs to a interval partition which will be move to a not existed interval partition +update hw_partition_interval_movement set C3 = '2020-08-22' where C3 = '2020-06-01'; + +select * from hw_partition_interval_movement; + c1 | c2 | c3 +----+----+-------------------------- + 7 | 2 | Sat Feb 01 00:00:00 2020 + 7 | 5 | Sun Mar 22 00:00:00 2020 + 3 | 1 | Fri May 22 00:00:00 2020 + 5 | 3 | Wed Jul 22 00:00:00 2020 + 1 | 4 | Sat Aug 22 00:00:00 2020 +(5 rows) + +-- add two new interval ranges +select relname, parttype, partstrategy, boundaries from pg_partition + where parentid = (select oid from pg_class where relname = 'hw_partition_interval_movement') + order by 1; + relname | parttype | partstrategy | boundaries +-----------------------------------+----------+--------------+------------------------------ + hw_partition_interval_movement | r | i | + hw_partition_interval_movement_p0 | p | r | {2020-03-01} + hw_partition_interval_movement_p1 | p | r | {2020-04-01} + hw_partition_interval_movement_p2 | p | r | {2020-05-01} + sys_p1 | p | i | {"Mon Jun 01 00:00:00 2020"} + sys_p2 | p | i | {"Wed Jul 01 00:00:00 2020"} + sys_p3 | p | i | {"Sat Aug 01 00:00:00 2020"} + sys_p4 | p | i | {"Tue Sep 01 00:00:00 2020"} +(8 rows) + +drop table hw_partition_interval_movement; diff --git a/src/test/regress/expected/hw_partition_interval_parallel_end.out b/src/test/regress/expected/hw_partition_interval_parallel_end.out new file mode 100644 index 0000000000..9a7c8aad44 --- /dev/null +++ b/src/test/regress/expected/hw_partition_interval_parallel_end.out @@ -0,0 +1,25 @@ +-- check results and clean +select count(*) from partition_interval_parallel; + count +------- + 10500 +(1 row) + +select relname, parttype, partstrategy, boundaries, indisusable from pg_partition + where parentid = (select oid from pg_class where relname = 'partition_interval_parallel') + order by 1; + relname | parttype | partstrategy | boundaries | indisusable +--------------------------------+----------+--------------+------------------------------+------------- + partition_interval_parallel | r | i | | t + partition_interval_parallel_p1 | p | r | {2020-05-01} | t + partition_interval_parallel_p2 | p | r | {2020-06-01} | t + sys_p1 | p | i | {"Wed Jul 01 00:00:00 2020"} | t + sys_p2 | p | i | {"Sat Aug 01 00:00:00 2020"} | t + sys_p3 | p | i | {"Tue Sep 01 00:00:00 2020"} | t + sys_p4 | p | i | {"Thu Oct 01 00:00:00 2020"} | t + sys_p5 | p | i | {"Sun Nov 01 00:00:00 2020"} | t + sys_p6 | p | i | {"Tue Dec 01 00:00:00 2020"} | t +(9 rows) + +--cleanup +DROP TABLE partition_interval_parallel; diff --git a/src/test/regress/expected/hw_partition_interval_parallel_insert.out b/src/test/regress/expected/hw_partition_interval_parallel_insert.out new file mode 100644 index 0000000000..7988422a71 --- /dev/null +++ b/src/test/regress/expected/hw_partition_interval_parallel_insert.out @@ -0,0 +1,58 @@ +--insert data +create or replace function insert_mm(dat text) returns void as $$ +declare + times integer :=1; +begin + loop + insert into partition_interval_parallel values(1, 1, dat); + times = times + 1; + if times > 500 then + exit; + end if; + end loop; +end; +$$ language plpgsql; + + +select insert_mm('2020-05-1'); + insert_mm +----------- + +(1 row) + +select insert_mm('2020-06-1'); + insert_mm +----------- + +(1 row) + +select insert_mm('2020-07-1'); + insert_mm +----------- + +(1 row) + +select insert_mm('2020-08-1'); + insert_mm +----------- + +(1 row) + +select insert_mm('2020-09-1'); + insert_mm +----------- + +(1 row) + +select insert_mm('2020-10-1'); + insert_mm +----------- + +(1 row) + +select insert_mm('2020-11-1'); + insert_mm +----------- + +(1 row) + diff --git a/src/test/regress/expected/hw_partition_interval_parallel_insert_01.out b/src/test/regress/expected/hw_partition_interval_parallel_insert_01.out new file mode 100644 index 0000000000..414aba926c --- /dev/null +++ b/src/test/regress/expected/hw_partition_interval_parallel_insert_01.out @@ -0,0 +1,56 @@ +--insert data +create or replace function insert_mm_01(dat text) returns void as $$ +declare + times integer :=1; +begin + loop + insert into partition_interval_parallel values(1, 1, dat); + times = times + 1; + if times > 500 then + exit; + end if; + end loop; +end; +$$ language plpgsql; +select insert_mm_01('2020-05-1'); + insert_mm_01 +-------------- + +(1 row) + +select insert_mm_01('2020-06-1'); + insert_mm_01 +-------------- + +(1 row) + +select insert_mm_01('2020-07-1'); + insert_mm_01 +-------------- + +(1 row) + +select insert_mm_01('2020-08-1'); + insert_mm_01 +-------------- + +(1 row) + +select insert_mm_01('2020-09-1'); + insert_mm_01 +-------------- + +(1 row) + +select insert_mm_01('2020-10-1'); + insert_mm_01 +-------------- + +(1 row) + +select insert_mm_01('2020-11-1'); + insert_mm_01 +-------------- + +(1 row) + diff --git a/src/test/regress/expected/hw_partition_interval_parallel_insert_02.out b/src/test/regress/expected/hw_partition_interval_parallel_insert_02.out new file mode 100644 index 0000000000..c1ccad7410 --- /dev/null +++ b/src/test/regress/expected/hw_partition_interval_parallel_insert_02.out @@ -0,0 +1,56 @@ +--insert data +create or replace function insert_mm_02(dat text) returns void as $$ +declare + times integer :=1; +begin + loop + insert into partition_interval_parallel values(1, 1, dat); + times = times + 1; + if times > 500 then + exit; + end if; + end loop; +end; +$$ language plpgsql; +select insert_mm_02('2020-05-1'); + insert_mm_02 +-------------- + +(1 row) + +select insert_mm_02('2020-06-1'); + insert_mm_02 +-------------- + +(1 row) + +select insert_mm_02('2020-07-1'); + insert_mm_02 +-------------- + +(1 row) + +select insert_mm_02('2020-08-1'); + insert_mm_02 +-------------- + +(1 row) + +select insert_mm_02('2020-09-1'); + insert_mm_02 +-------------- + +(1 row) + +select insert_mm_02('2020-10-1'); + insert_mm_02 +-------------- + +(1 row) + +select insert_mm_02('2020-11-1'); + insert_mm_02 +-------------- + +(1 row) + diff --git a/src/test/regress/expected/hw_partition_interval_parallel_prepare.out b/src/test/regress/expected/hw_partition_interval_parallel_prepare.out new file mode 100644 index 0000000000..5565590756 --- /dev/null +++ b/src/test/regress/expected/hw_partition_interval_parallel_prepare.out @@ -0,0 +1,21 @@ +-- prepare the parrallel modifed table; +DROP TABLE IF EXISTS partition_interval_parallel; +NOTICE: table "partition_interval_parallel" does not exist, skipping +create table partition_interval_parallel +( + c1 int, + c2 int, + c3 date not null +) +partition by range (c3) +INTERVAL ('1 month') +( + PARTITION partition_interval_parallel_p1 VALUES LESS THAN ('2020-05-01'), + PARTITION partition_interval_parallel_p2 VALUES LESS THAN ('2020-06-01') +); +CREATE INDEX idx1_partition_interval_parallel on partition_interval_parallel(c3) local ; + + + + + diff --git a/src/test/regress/expected/hw_partition_interval_reindex.out b/src/test/regress/expected/hw_partition_interval_reindex.out new file mode 100644 index 0000000000..0fef4454c4 --- /dev/null +++ b/src/test/regress/expected/hw_partition_interval_reindex.out @@ -0,0 +1,168 @@ +--01-------------------------------------------------------------------- +--prepare table , index +drop table if exists partition_reindex_table3; +NOTICE: table "partition_reindex_table3" does not exist, skipping +create table partition_reindex_table3 +( + c1 int, + c2 int, + C3 date not null +) +partition by range (C3) +INTERVAL ('1 month') +( + PARTITION partition_reindex_table3_p0 VALUES LESS THAN ('2020-02-01'), + PARTITION partition_reindex_table3_p1 VALUES LESS THAN ('2020-05-01'), + PARTITION partition_reindex_table3_p2 VALUES LESS THAN ('2020-06-01') +) +enable row movement; +create index partition_reindex_table3_ind1 on partition_reindex_table3(c1) local; +create index partition_reindex_table3_ind2 on partition_reindex_table3(c2) local; +create index partition_reindex_table3_ind3 on partition_reindex_table3(c3) local; +--02-------------------------------------------------------------------- +--reindex index, cross test with insert +insert into partition_reindex_table3 values (generate_series(1,10), generate_series(1,10), generate_series(TO_DATE('2020-01-01', 'YYYY-MM-DD'),TO_DATE('2020-07-01', 'YYYY-MM-DD'),'1, day')); +select count(*) from partition_reindex_table3; + count +------- + 1830 +(1 row) + +select relname, parttype, partstrategy, boundaries from pg_partition + where parentid = (select oid from pg_class where relname = 'partition_reindex_table3') + order by 1; + relname | parttype | partstrategy | boundaries +-----------------------------+----------+--------------+------------------------------ + partition_reindex_table3 | r | i | + partition_reindex_table3_p0 | p | r | {2020-02-01} + partition_reindex_table3_p1 | p | r | {2020-05-01} + partition_reindex_table3_p2 | p | r | {2020-06-01} + sys_p1 | p | i | {"Wed Jul 01 00:00:00 2020"} + sys_p2 | p | i | {"Sat Aug 01 00:00:00 2020"} +(6 rows) + +truncate table partition_reindex_table3; +insert into partition_reindex_table3 values (generate_series(1,10), generate_series(1,10), generate_series(TO_DATE('2020-01-01', 'YYYY-MM-DD'),TO_DATE('2020-07-01', 'YYYY-MM-DD'),'1, day')); +select count(*) from partition_reindex_table3; + count +------- + 1830 +(1 row) + +select relname, parttype, partstrategy, boundaries from pg_partition + where parentid = (select oid from pg_class where relname = 'partition_reindex_table3') + order by 1; + relname | parttype | partstrategy | boundaries +-----------------------------+----------+--------------+------------------------------ + partition_reindex_table3 | r | i | + partition_reindex_table3_p0 | p | r | {2020-02-01} + partition_reindex_table3_p1 | p | r | {2020-05-01} + partition_reindex_table3_p2 | p | r | {2020-06-01} + sys_p1 | p | i | {"Wed Jul 01 00:00:00 2020"} + sys_p2 | p | i | {"Sat Aug 01 00:00:00 2020"} +(6 rows) + +analyze partition_reindex_table3; +select c.relname,c.relpages > 0 as relpagesgtzero, c.reltuples > 0 as reltuplesgtzero,i.indisunique, i.indisvalid, i.indcheckxmin, i.indisready from pg_index i, pg_class c where c.relname = 'partition_reindex_table3_ind1' and c.oid = i.indexrelid; + relname | relpagesgtzero | reltuplesgtzero | indisunique | indisvalid | indcheckxmin | indisready +-------------------------------+----------------+-----------------+-------------+------------+--------------+------------ + partition_reindex_table3_ind1 | t | t | f | t | f | t +(1 row) + +explain (costs off, nodes off) select * from partition_reindex_table3 where c3 = TO_DATE('2020-04-21', 'YYYY-MM-DD') and c2 = 8; + QUERY PLAN +---------------------------------------------------------------------------------------------- + Partition Iterator + Iterations: 1 + -> Partitioned Index Scan using partition_reindex_table3_ind3 on partition_reindex_table3 + Index Cond: (c3 = to_date('2020-04-21'::text, 'YYYY-MM-DD'::text)) + Filter: (c2 = 8) + Selected Partitions: 2 +(6 rows) + +select * from partition_reindex_table3 where c3 = TO_DATE('2020-04-21', 'YYYY-MM-DD') and c2 = 8; + c1 | c2 | c3 +----+----+-------------------------- + 8 | 8 | Tue Apr 21 00:00:00 2020 +(1 row) + +reindex index partition_reindex_table3_ind1; +select c.relname,c.relpages > 0 as relpagesgtzero, c.reltuples > 0 as reltuplesgtzero,i.indisunique, i.indisvalid, i.indcheckxmin, i.indisready from pg_index i, pg_class c where c.relname = 'partition_reindex_table3_ind1' and c.oid = i.indexrelid; + relname | relpagesgtzero | reltuplesgtzero | indisunique | indisvalid | indcheckxmin | indisready +-------------------------------+----------------+-----------------+-------------+------------+--------------+------------ + partition_reindex_table3_ind1 | t | t | f | t | f | t +(1 row) + +explain (costs off, nodes off) select * from partition_reindex_table3 where c3 = TO_DATE('2020-04-21', 'YYYY-MM-DD') and c2 = 8; + QUERY PLAN +---------------------------------------------------------------------------------------------- + Partition Iterator + Iterations: 1 + -> Partitioned Index Scan using partition_reindex_table3_ind3 on partition_reindex_table3 + Index Cond: (c3 = to_date('2020-04-21'::text, 'YYYY-MM-DD'::text)) + Filter: (c2 = 8) + Selected Partitions: 2 +(6 rows) + +--the plan before reindex and after reindex should be same +select * from partition_reindex_table3 where c3 = TO_DATE('2020-04-21', 'YYYY-MM-DD') and c2 = 8; + c1 | c2 | c3 +----+----+-------------------------- + 8 | 8 | Tue Apr 21 00:00:00 2020 +(1 row) + +--03-------------------------------------------------------------------- +--reindex table cross test with truncate +truncate table partition_reindex_table3; +insert into partition_reindex_table3 values (generate_series(1,10), generate_series(1,10), generate_series(TO_DATE('2020-01-01', 'YYYY-MM-DD'),TO_DATE('2020-07-01', 'YYYY-MM-DD'),'1, day')); +analyze partition_reindex_table3; +select c.relname,c.relpages > 0 as relpagesgtzero, c.reltuples > 0 as reltuplesgtzero,i.indisunique, i.indisvalid, i.indcheckxmin, i.indisready from pg_index i, pg_class c where c.relname = 'partition_reindex_table3_ind1' and c.oid = i.indexrelid; + relname | relpagesgtzero | reltuplesgtzero | indisunique | indisvalid | indcheckxmin | indisready +-------------------------------+----------------+-----------------+-------------+------------+--------------+------------ + partition_reindex_table3_ind1 | t | t | f | t | f | t +(1 row) + +explain (costs off, nodes off) select * from partition_reindex_table3 where c3 = TO_DATE('2020-04-21', 'YYYY-MM-DD') and c2 = 8; + QUERY PLAN +---------------------------------------------------------------------------------------------- + Partition Iterator + Iterations: 1 + -> Partitioned Index Scan using partition_reindex_table3_ind3 on partition_reindex_table3 + Index Cond: (c3 = to_date('2020-04-21'::text, 'YYYY-MM-DD'::text)) + Filter: (c2 = 8) + Selected Partitions: 2 +(6 rows) + +select * from partition_reindex_table3 where c3 = TO_DATE('2020-04-21', 'YYYY-MM-DD') and c2 = 8; + c1 | c2 | c3 +----+----+-------------------------- + 8 | 8 | Tue Apr 21 00:00:00 2020 +(1 row) + +reindex index partition_reindex_table3_ind1; +select c.relname,c.relpages > 0 as relpagesgtzero, c.reltuples > 0 as reltuplesgtzero,i.indisunique, i.indisvalid, i.indcheckxmin, i.indisready from pg_index i, pg_class c where c.relname = 'partition_reindex_table3_ind1' and c.oid = i.indexrelid; + relname | relpagesgtzero | reltuplesgtzero | indisunique | indisvalid | indcheckxmin | indisready +-------------------------------+----------------+-----------------+-------------+------------+--------------+------------ + partition_reindex_table3_ind1 | t | t | f | t | f | t +(1 row) + +explain (costs off, nodes off) select * from partition_reindex_table3 where c3 = TO_DATE('2020-04-21', 'YYYY-MM-DD') and c2 = 8; + QUERY PLAN +---------------------------------------------------------------------------------------------- + Partition Iterator + Iterations: 1 + -> Partitioned Index Scan using partition_reindex_table3_ind3 on partition_reindex_table3 + Index Cond: (c3 = to_date('2020-04-21'::text, 'YYYY-MM-DD'::text)) + Filter: (c2 = 8) + Selected Partitions: 2 +(6 rows) + +--the plan before reindex and after reindex should be same +select * from partition_reindex_table3 where c3 = TO_DATE('2020-04-21', 'YYYY-MM-DD') and c2 = 8; + c1 | c2 | c3 +----+----+-------------------------- + 8 | 8 | Tue Apr 21 00:00:00 2020 +(1 row) + +--clean +drop table partition_reindex_table3; diff --git a/src/test/regress/expected/hw_partition_interval_select.out b/src/test/regress/expected/hw_partition_interval_select.out new file mode 100644 index 0000000000..316f439285 --- /dev/null +++ b/src/test/regress/expected/hw_partition_interval_select.out @@ -0,0 +1,145 @@ +CREATE TABLE interval_tab1 ( + city_id int not null, + logdate date not null, + peaktemp int, + unitsales int +) +PARTITION BY RANGE (logdate) +INTERVAL ('1 day') +( + PARTITION p1 VALUES LESS THAN (('2020-03-01')) +); +insert into interval_tab1 values(1,'2020-4-7 2:0:0', 1, 1); +insert into interval_tab1 values(1,'2020-4-8 2:0:0', 1, 1); +select relname, boundaries from pg_partition; + relname | boundaries +---------------+------------------------------ + interval_tab1 | + p1 | {2020-03-01} + sys_p1 | {"Wed Apr 08 00:00:00 2020"} + sys_p2 | {"Thu Apr 09 00:00:00 2020"} +(4 rows) + +select * from interval_tab1 where logdate < '2020-4-7 0:0:0'; + city_id | logdate | peaktemp | unitsales +---------+---------+----------+----------- +(0 rows) + +explain (costs off, verbose on, nodes off) select * from interval_tab1 where logdate < '2020-4-7 0:0:0'; + QUERY PLAN +--------------------------------------------------------------------------------------------------- + Partition Iterator + Output: city_id, logdate, peaktemp, unitsales + Iterations: 1 + -> Partitioned Seq Scan on public.interval_tab1 + Output: city_id, logdate, peaktemp, unitsales + Filter: (interval_tab1.logdate < 'Tue Apr 07 00:00:00 2020'::timestamp without time zone) + Selected Partitions: 1 +(7 rows) + +select * from interval_tab1 where logdate > '2020-4-6'; + city_id | logdate | peaktemp | unitsales +---------+--------------------------+----------+----------- + 1 | Tue Apr 07 02:00:00 2020 | 1 | 1 + 1 | Wed Apr 08 02:00:00 2020 | 1 | 1 +(2 rows) + +explain (costs off, verbose on, nodes off) select * from interval_tab1 where logdate > '2020-4-6'; + QUERY PLAN +--------------------------------------------------------------------------------------------------- + Partition Iterator + Output: city_id, logdate, peaktemp, unitsales + Iterations: 2 + -> Partitioned Seq Scan on public.interval_tab1 + Output: city_id, logdate, peaktemp, unitsales + Filter: (interval_tab1.logdate > 'Mon Apr 06 00:00:00 2020'::timestamp without time zone) + Selected Partitions: 2..3 +(7 rows) + +select * from interval_tab1 where logdate = '2020-4-7 2:0:0'; + city_id | logdate | peaktemp | unitsales +---------+--------------------------+----------+----------- + 1 | Tue Apr 07 02:00:00 2020 | 1 | 1 +(1 row) + +insert into interval_tab1 values(1,'2020-4-7 0:0:0', 1, 1); +select * from interval_tab1 where logdate = '2020-4-7 0:0:0'; + city_id | logdate | peaktemp | unitsales +---------+--------------------------+----------+----------- + 1 | Tue Apr 07 00:00:00 2020 | 1 | 1 +(1 row) + +select * from interval_tab1 where logdate != '2020-4-7 0:0:0'; + city_id | logdate | peaktemp | unitsales +---------+--------------------------+----------+----------- + 1 | Tue Apr 07 02:00:00 2020 | 1 | 1 + 1 | Wed Apr 08 02:00:00 2020 | 1 | 1 +(2 rows) + +select * from interval_tab1 where logdate >= '2020-4-7 0:0:0'; + city_id | logdate | peaktemp | unitsales +---------+--------------------------+----------+----------- + 1 | Tue Apr 07 02:00:00 2020 | 1 | 1 + 1 | Tue Apr 07 00:00:00 2020 | 1 | 1 + 1 | Wed Apr 08 02:00:00 2020 | 1 | 1 +(3 rows) + +insert into interval_tab1 values(1,'2020-4-5 2:0:0', 1, 1); +select relname, boundaries from pg_partition; + relname | boundaries +---------------+------------------------------ + interval_tab1 | + p1 | {2020-03-01} + sys_p1 | {"Wed Apr 08 00:00:00 2020"} + sys_p2 | {"Thu Apr 09 00:00:00 2020"} + sys_p3 | {"Mon Apr 06 00:00:00 2020"} +(5 rows) + +insert into interval_tab1 values(1,'2020-4-9 0:0:0', 1, 1); +select * from interval_tab1 where logdate >= '2020-4-7 0:0:0' and logdate < '2020-4-9 0:0:0'; + city_id | logdate | peaktemp | unitsales +---------+--------------------------+----------+----------- + 1 | Tue Apr 07 02:00:00 2020 | 1 | 1 + 1 | Tue Apr 07 00:00:00 2020 | 1 | 1 + 1 | Wed Apr 08 02:00:00 2020 | 1 | 1 +(3 rows) + +select * from interval_tab1 where logdate > '2020-4-7 0:0:0' and logdate <= '2020-4-9 0:0:0'; + city_id | logdate | peaktemp | unitsales +---------+--------------------------+----------+----------- + 1 | Tue Apr 07 02:00:00 2020 | 1 | 1 + 1 | Wed Apr 08 02:00:00 2020 | 1 | 1 + 1 | Thu Apr 09 00:00:00 2020 | 1 | 1 +(3 rows) + +select * from interval_tab1 where logdate >= '2020-4-7 0:0:0' and logdate <= '2020-4-9 0:0:0'; + city_id | logdate | peaktemp | unitsales +---------+--------------------------+----------+----------- + 1 | Tue Apr 07 02:00:00 2020 | 1 | 1 + 1 | Tue Apr 07 00:00:00 2020 | 1 | 1 + 1 | Wed Apr 08 02:00:00 2020 | 1 | 1 + 1 | Thu Apr 09 00:00:00 2020 | 1 | 1 +(4 rows) + +select * from interval_tab1 where logdate > '2020-4-6 0:0:0' and logdate <= '2020-4-9 0:0:0'; + city_id | logdate | peaktemp | unitsales +---------+--------------------------+----------+----------- + 1 | Tue Apr 07 02:00:00 2020 | 1 | 1 + 1 | Tue Apr 07 00:00:00 2020 | 1 | 1 + 1 | Wed Apr 08 02:00:00 2020 | 1 | 1 + 1 | Thu Apr 09 00:00:00 2020 | 1 | 1 +(4 rows) + +explain (costs off, verbose on, nodes off) select * from interval_tab1 where logdate >= '2020-4-10 0:0:0'; + QUERY PLAN +---------------------------------------------------------------------------------------------------- + Partition Iterator + Output: city_id, logdate, peaktemp, unitsales + Iterations: 0 + -> Partitioned Seq Scan on public.interval_tab1 + Output: city_id, logdate, peaktemp, unitsales + Filter: (interval_tab1.logdate >= 'Fri Apr 10 00:00:00 2020'::timestamp without time zone) + Selected Partitions: NONE +(7 rows) + +drop table interval_tab1; diff --git a/src/test/regress/expected/hw_partition_interval_unusable_index.out b/src/test/regress/expected/hw_partition_interval_unusable_index.out new file mode 100644 index 0000000000..88d1407f04 --- /dev/null +++ b/src/test/regress/expected/hw_partition_interval_unusable_index.out @@ -0,0 +1,409 @@ +--create table +DROP TABLE IF EXISTS partition_unsable_index_1; +NOTICE: table "partition_unsable_index_1" does not exist, skipping +create table partition_unsable_index_1 +( + c1 int, + c2 int, + c3 date not null +) +partition by range (c3) +INTERVAL ('1 month') +( + PARTITION partition_unsable_index_1_p0 VALUES LESS THAN ('2020-03-01'), + PARTITION partition_unsable_index_1_p1 VALUES LESS THAN ('2020-04-01'), + PARTITION partition_unsable_index_1_p2 VALUES LESS THAN ('2020-05-01') +); +-- create 3 indexes, and specify it's partition name +CREATE INDEX idx1_partition_unsable_index_1 on partition_unsable_index_1(c3) local +( + partition idx1_partition_unsable_index_1_p1, + partition idx1_partition_unsable_index_1_p2, + partition idx1_partition_unsable_index_1_p3 +); +CREATE INDEX idx2_partition_unsable_index_1 on partition_unsable_index_1(c2, c3) local +( + partition idx2_partition_unsable_index_1_p1, + partition idx2_partition_unsable_index_1_p2, + partition idx2_partition_unsable_index_1_p3 +); +CREATE INDEX idx3_partition_unsable_index_1 on partition_unsable_index_1(c1, c2, c3) local +( + partition idx3_partition_unsable_index_1_p1, + partition idx3_partition_unsable_index_1_p2, + partition idx3_partition_unsable_index_1_p3 +); +--insert data +insert into partition_unsable_index_1 values(7,2,'2020-03-01'); +insert into partition_unsable_index_1 values(3,1,'2020-04-01'); +insert into partition_unsable_index_1 values(5,3,'2020-05-01'); +insert into partition_unsable_index_1 values(7,5,'2020-06-01'); +insert into partition_unsable_index_1 values(1,4,'2020-07-01'); +-- query all index partitions +select relname, parttype, partstrategy, indisusable from pg_partition + where parentid = (select oid from pg_class where relname = 'idx1_partition_unsable_index_1') + order by relname; + relname | parttype | partstrategy | indisusable +-----------------------------------+----------+--------------+------------- + idx1_partition_unsable_index_1_p1 | x | n | t + idx1_partition_unsable_index_1_p2 | x | n | t + idx1_partition_unsable_index_1_p3 | x | n | t + sys_p1_c3_idx | x | n | t + sys_p2_c3_idx | x | n | t + sys_p3_c3_idx | x | n | t +(6 rows) + +-- 1. alter index, modify one of it's partition to unusable state +ALTER INDEX idx1_partition_unsable_index_1 MODIFY PARTITION idx1_partition_unsable_index_1_p1 UNUSABLE; +-- check indunusable info +select relname, parttype, partstrategy, boundaries, indisusable from pg_partition + where parentid = (select oid from pg_class where relname = 'idx1_partition_unsable_index_1') + order by 1; + relname | parttype | partstrategy | boundaries | indisusable +-----------------------------------+----------+--------------+------------+------------- + idx1_partition_unsable_index_1_p1 | x | n | | f + idx1_partition_unsable_index_1_p2 | x | n | | t + idx1_partition_unsable_index_1_p3 | x | n | | t + sys_p1_c3_idx | x | n | | t + sys_p2_c3_idx | x | n | | t + sys_p3_c3_idx | x | n | | t +(6 rows) + +-- rebuild index partition +ALTER INDEX idx1_partition_unsable_index_1 REBUILD PARTITION idx1_partition_unsable_index_1_p1; +-- check indunusable info +select relname, parttype, partstrategy, indisusable from pg_partition + where parentid = (select oid from pg_class where relname = 'idx1_partition_unsable_index_1') + order by 1; + relname | parttype | partstrategy | indisusable +-----------------------------------+----------+--------------+------------- + idx1_partition_unsable_index_1_p1 | x | n | t + idx1_partition_unsable_index_1_p2 | x | n | t + idx1_partition_unsable_index_1_p3 | x | n | t + sys_p1_c3_idx | x | n | t + sys_p2_c3_idx | x | n | t + sys_p3_c3_idx | x | n | t +(6 rows) + +--2.ALTER INDEX unusable +select relname, parttype, partstrategy, indisusable from pg_partition + where parentid = (select oid from pg_class where relname = 'idx1_partition_unsable_index_1') + order by 1; + relname | parttype | partstrategy | indisusable +-----------------------------------+----------+--------------+------------- + idx1_partition_unsable_index_1_p1 | x | n | t + idx1_partition_unsable_index_1_p2 | x | n | t + idx1_partition_unsable_index_1_p3 | x | n | t + sys_p1_c3_idx | x | n | t + sys_p2_c3_idx | x | n | t + sys_p3_c3_idx | x | n | t +(6 rows) + +ALTER INDEX idx1_partition_unsable_index_1 UNUSABLE; +select relname, parttype, partstrategy, indisusable from pg_partition + where parentid = (select oid from pg_class where relname = 'idx1_partition_unsable_index_1') + order by 1; + relname | parttype | partstrategy | indisusable +-----------------------------------+----------+--------------+------------- + idx1_partition_unsable_index_1_p1 | x | n | f + idx1_partition_unsable_index_1_p2 | x | n | f + idx1_partition_unsable_index_1_p3 | x | n | f + sys_p1_c3_idx | x | n | f + sys_p2_c3_idx | x | n | f + sys_p3_c3_idx | x | n | f +(6 rows) + +ALTER INDEX idx1_partition_unsable_index_1 REBUILD; +select relname, parttype, partstrategy, indisusable from pg_partition + where parentid = (select oid from pg_class where relname = 'idx1_partition_unsable_index_1') + order by 1; + relname | parttype | partstrategy | indisusable +-----------------------------------+----------+--------------+------------- + idx1_partition_unsable_index_1_p1 | x | n | t + idx1_partition_unsable_index_1_p2 | x | n | t + idx1_partition_unsable_index_1_p3 | x | n | t + sys_p1_c3_idx | x | n | t + sys_p2_c3_idx | x | n | t + sys_p3_c3_idx | x | n | t +(6 rows) + +--test for reindex partition +ALTER INDEX idx1_partition_unsable_index_1 UNUSABLE; +select relname, parttype, partstrategy, indisusable from pg_partition + where parentid = (select oid from pg_class where relname = 'idx1_partition_unsable_index_1') + order by 1; + relname | parttype | partstrategy | indisusable +-----------------------------------+----------+--------------+------------- + idx1_partition_unsable_index_1_p1 | x | n | f + idx1_partition_unsable_index_1_p2 | x | n | f + idx1_partition_unsable_index_1_p3 | x | n | f + sys_p1_c3_idx | x | n | f + sys_p2_c3_idx | x | n | f + sys_p3_c3_idx | x | n | f +(6 rows) + +REINDEX INDEX idx1_partition_unsable_index_1 PARTITION idx1_partition_unsable_index_1_p1; +select relname, parttype, partstrategy, indisusable from pg_partition + where parentid = (select oid from pg_class where relname = 'idx1_partition_unsable_index_1') + order by 1; + relname | parttype | partstrategy | indisusable +-----------------------------------+----------+--------------+------------- + idx1_partition_unsable_index_1_p1 | x | n | t + idx1_partition_unsable_index_1_p2 | x | n | f + idx1_partition_unsable_index_1_p3 | x | n | f + sys_p1_c3_idx | x | n | f + sys_p2_c3_idx | x | n | f + sys_p3_c3_idx | x | n | f +(6 rows) + +ALTER INDEX idx1_partition_unsable_index_1 REBUILD; +select relname, parttype, partstrategy, indisusable from pg_partition + where parentid = (select oid from pg_class where relname = 'idx1_partition_unsable_index_1') + order by 1; + relname | parttype | partstrategy | indisusable +-----------------------------------+----------+--------------+------------- + idx1_partition_unsable_index_1_p1 | x | n | t + idx1_partition_unsable_index_1_p2 | x | n | t + idx1_partition_unsable_index_1_p3 | x | n | t + sys_p1_c3_idx | x | n | t + sys_p2_c3_idx | x | n | t + sys_p3_c3_idx | x | n | t +(6 rows) + + +-- 3. alter table, modify one of it's partition's all indexes to unusable state +ALTER TABLE partition_unsable_index_1 MODIFY PARTITION partition_unsable_index_1_p0 UNUSABLE LOCAL INDEXES; +-- check indunusable info +select relname, indisusable from pg_partition + where relname = 'idx1_partition_unsable_index_1_p1' + or relname = 'idx2_partition_unsable_index_1_p1' + or relname = 'idx3_partition_unsable_index_1_p1' + or relname = 'p1_partition_unsable_index_1' + order by 1; + relname | indisusable +-----------------------------------+------------- + idx1_partition_unsable_index_1_p1 | f + idx2_partition_unsable_index_1_p1 | f + idx3_partition_unsable_index_1_p1 | f +(3 rows) + +-- rebuild +ALTER TABLE partition_unsable_index_1 MODIFY PARTITION partition_unsable_index_1_p0 REBUILD UNUSABLE LOCAL INDEXES; +-- check again +select relname, indisusable from pg_partition + where relname = 'idx1_partition_unsable_index_1_p1' + or relname = 'idx2_partition_unsable_index_1_p1' + or relname = 'idx3_partition_unsable_index_1_p1' + or relname = 'p1_partition_unsable_index_1' + order by 1; + relname | indisusable +-----------------------------------+------------- + idx1_partition_unsable_index_1_p1 | t + idx2_partition_unsable_index_1_p1 | t + idx3_partition_unsable_index_1_p1 | t +(3 rows) + +ALTER INDEX idx1_partition_unsable_index_1 MODIFY PARTITION idx1_partition_unsable_index_1_p1 UNUSABLE; +-- idx1_partition_unsable_index_1_p1 is unusable +select part.relname, part.indisusable + from pg_class class , pg_partition part , pg_index ind + where class.relname = 'partition_unsable_index_1' + and ind.indrelid = class.oid + and part.parentid = ind.indexrelid + order by 1; + relname | indisusable +-----------------------------------+------------- + idx1_partition_unsable_index_1_p1 | f + idx1_partition_unsable_index_1_p2 | t + idx1_partition_unsable_index_1_p3 | t + idx2_partition_unsable_index_1_p1 | t + idx2_partition_unsable_index_1_p2 | t + idx2_partition_unsable_index_1_p3 | t + idx3_partition_unsable_index_1_p1 | t + idx3_partition_unsable_index_1_p2 | t + idx3_partition_unsable_index_1_p3 | t + sys_p1_c1_c2_c3_idx | t + sys_p1_c2_c3_idx | t + sys_p1_c3_idx | t + sys_p2_c1_c2_c3_idx | t + sys_p2_c2_c3_idx | t + sys_p2_c3_idx | t + sys_p3_c1_c2_c3_idx | t + sys_p3_c2_c3_idx | t + sys_p3_c3_idx | t +(18 rows) + +-- can not cluster partition bacause of unusable local index +CLUSTER partition_unsable_index_1 PARTITION (partition_unsable_index_1_p0) USING idx1_partition_unsable_index_1; +ERROR: can not cluster partition partition_unsable_index_1_p0 using idx1_partition_unsable_index_1 bacause of unusable local index +CLUSTER partition_unsable_index_1 USING idx1_partition_unsable_index_1; +ERROR: can not cluster partition partition_unsable_index_1_p0 using idx1_partition_unsable_index_1 bacause of unusable local index +-- indisclustered is false +select class.relname, ind.indisclustered + from pg_class class , pg_index ind + where class.relname = 'partition_unsable_index_1' + and ind.indrelid = class.oid + order by 2; + relname | indisclustered +---------------------------+---------------- + partition_unsable_index_1 | f + partition_unsable_index_1 | f + partition_unsable_index_1 | f +(3 rows) + +-- cluster ok +ALTER INDEX idx1_partition_unsable_index_1 REBUILD; +CLUSTER partition_unsable_index_1 USING idx1_partition_unsable_index_1; +-- idx1_partition_unsable_index_1_p1 is usable +select part.relname, part.indisusable + from pg_class class , pg_partition part , pg_index ind + where class.relname = 'partition_unsable_index_1' + and ind.indrelid = class.oid + and part.parentid = ind.indexrelid + order by 1; + relname | indisusable +-----------------------------------+------------- + idx1_partition_unsable_index_1_p1 | t + idx1_partition_unsable_index_1_p2 | t + idx1_partition_unsable_index_1_p3 | t + idx2_partition_unsable_index_1_p1 | t + idx2_partition_unsable_index_1_p2 | t + idx2_partition_unsable_index_1_p3 | t + idx3_partition_unsable_index_1_p1 | t + idx3_partition_unsable_index_1_p2 | t + idx3_partition_unsable_index_1_p3 | t + sys_p1_c1_c2_c3_idx | t + sys_p1_c2_c3_idx | t + sys_p1_c3_idx | t + sys_p2_c1_c2_c3_idx | t + sys_p2_c2_c3_idx | t + sys_p2_c3_idx | t + sys_p3_c1_c2_c3_idx | t + sys_p3_c2_c3_idx | t + sys_p3_c3_idx | t +(18 rows) + +-- indisclustered is true +select class.relname, ind.indisclustered + from pg_class class , pg_index ind + where class.relname = 'partition_unsable_index_1' + and ind.indrelid = class.oid + order by 2; + relname | indisclustered +---------------------------+---------------- + partition_unsable_index_1 | f + partition_unsable_index_1 | f + partition_unsable_index_1 | t +(3 rows) + +-- cluster other index +ALTER INDEX idx2_partition_unsable_index_1 MODIFY PARTITION idx2_partition_unsable_index_1_p1 UNUSABLE; +ALTER INDEX idx2_partition_unsable_index_1 REBUILD; +CLUSTER partition_unsable_index_1 USING idx2_partition_unsable_index_1; +select class.relname, ind.indisclustered + from pg_class class , pg_index ind + where class.relname = 'partition_unsable_index_1' + and ind.indrelid = class.oid + order by 2; + relname | indisclustered +---------------------------+---------------- + partition_unsable_index_1 | f + partition_unsable_index_1 | f + partition_unsable_index_1 | t +(3 rows) + +-- cluster a partition +ALTER INDEX idx1_partition_unsable_index_1 MODIFY PARTITION idx1_partition_unsable_index_1_p1 UNUSABLE; +ALTER INDEX idx1_partition_unsable_index_1 REBUILD PARTITION idx1_partition_unsable_index_1_p1; +CLUSTER partition_unsable_index_1 PARTITION (partition_unsable_index_1_p0) USING idx1_partition_unsable_index_1; +CLUSTER partition_unsable_index_1 USING idx1_partition_unsable_index_1; +select class.relname, ind.indisclustered + from pg_class class , pg_index ind + where class.relname = 'partition_unsable_index_1' + and ind.indrelid = class.oid + order by 2; + relname | indisclustered +---------------------------+---------------- + partition_unsable_index_1 | f + partition_unsable_index_1 | f + partition_unsable_index_1 | t +(3 rows) + +--5.2 merge (not support yet, keep the case hear for support in the future) +-- merge failed due to unusable index partition +ALTER INDEX idx1_partition_unsable_index_1 MODIFY PARTITION idx1_partition_unsable_index_1_p1 UNUSABLE; +ALTER TABLE partition_unsable_index_1 MERGE PARTITIONS partition_unsable_index_1_p0, p2_partition_unsable_index_3 + INTO PARTITION px_partition_unsable_index_3; +ERROR: can not merge partition against interval partitioned table +--rebuild unusable index partition +ALTER INDEX idx1_partition_unsable_index_1 REBUILD PARTITION idx1_partition_unsable_index_1_p1; +--5.3 exchange +-- create plain table and index +CREATE TABLE table_unusable_index_exchange (c1 int, c2 int, c3 date not null); +CREATE INDEX idx1_table_unusable_index_exchange on table_unusable_index_exchange(c3); +CREATE INDEX idx2_table_unusable_index_exchange on table_unusable_index_exchange(c2, c3); +CREATE INDEX idx3_table_unusable_index_exchange on table_unusable_index_exchange(c1, c2, c3); +--- unusable non-partitioned-index +ALTER INDEX idx1_table_unusable_index_exchange UNUSABLE; +ALTER TABLE partition_unsable_index_1 EXCHANGE PARTITION (partition_unsable_index_1_p0) + WITH TABLE table_unusable_index_exchange; +ERROR: tables in ALTER TABLE EXCHANGE PARTITION must have the same number of indexs +ALTER INDEX idx1_table_unusable_index_exchange REBUILD; +-- unusable partitioned-index +ALTER INDEX idx1_partition_unsable_index_1 UNUSABLE; +ALTER TABLE partition_unsable_index_1 EXCHANGE PARTITION (partition_unsable_index_1_p0) + WITH TABLE table_unusable_index_exchange; +ERROR: index mismatch for tables in ALTER TABLE EXCHANGE PARTITION +ALTER INDEX idx1_partition_unsable_index_1 REBUILD; +-- modify one index partition unusable +-- exchange failed due to unusable index partition +ALTER INDEX idx1_partition_unsable_index_1 MODIFY PARTITION idx1_partition_unsable_index_1_p1 UNUSABLE; +ALTER TABLE partition_unsable_index_1 EXCHANGE PARTITION (partition_unsable_index_1_p0) + WITH TABLE table_unusable_index_exchange; +ERROR: index mismatch for tables in ALTER TABLE EXCHANGE PARTITION +-- exchange ok +ALTER INDEX idx1_partition_unsable_index_1 REBUILD PARTITION idx1_partition_unsable_index_1_p1; +ALTER TABLE partition_unsable_index_1 EXCHANGE PARTITION (partition_unsable_index_1_p0) + WITH TABLE table_unusable_index_exchange; +-- clean table_unusable_index_exchange +DROP TABLE table_unusable_index_exchange; +DROP TABLE partition_unsable_index_1; +--6. index and unique index check +create table partition_unsable_index_1 +( + c1 int, + c2 int, + c3 date not null +) +partition by range (c3) +INTERVAL ('1 month') +( + PARTITION partition_unsable_index_1_p0 VALUES LESS THAN ('2020-03-01'), + PARTITION partition_unsable_index_1_p1 VALUES LESS THAN ('2020-04-01'), + PARTITION partition_unsable_index_1_p2 VALUES LESS THAN ('2020-05-01') +); +-- create a unique index +CREATE UNIQUE INDEX idx_unique_partition_unsable_index_1 on partition_unsable_index_1(c2, c3) LOCAL +( + partition idx_unique_partition_unsable_index_1_p1, + partition idx_unique_partition_unsable_index_1_p2, + partition idx_unique_partition_unsable_index_1_p3 +); +--insert duplicated rows should report error +insert into partition_unsable_index_1 values(3,3,'2020-02-01'); +insert into partition_unsable_index_1 values(5,3,'2020-02-01'); -- fail +ERROR: duplicate key value violates unique constraint "idx_unique_partition_unsable_index_1" +DETAIL: Key (c2, c3)=(3, Sat Feb 01 00:00:00 2020) already exists. +-- set local index unusable +ALTER INDEX idx_unique_partition_unsable_index_1 MODIFY PARTITION idx_unique_partition_unsable_index_1_p1 UNUSABLE; +-- bypass the unique index check +insert into partition_unsable_index_1 values(5,3,'2020-02-01'); -- success +--but report unique check error here +ALTER INDEX idx_unique_partition_unsable_index_1 REBUILD PARTITION idx_unique_partition_unsable_index_1_p1; +ERROR: could not create unique index "idx_unique_partition_unsable_index_1" +DETAIL: Key (c2, c3)=(3, Sat Feb 01 00:00:00 2020) is duplicated. +-- cleanup +DROP INDEX idx_unique_partition_unsable_index_1; +insert into partition_unsable_index_1 values(5,3,'2020-02-01'); -- success +--cleanup +DROP TABLE partition_unsable_index_1; diff --git a/src/test/regress/expected/hw_partition_nodes.out b/src/test/regress/expected/hw_partition_nodes.out index 673fbcfda8..082b49d693 100644 --- a/src/test/regress/expected/hw_partition_nodes.out +++ b/src/test/regress/expected/hw_partition_nodes.out @@ -27,14 +27,13 @@ SET ENABLE_SEQSCAN = FALSE; SET ENABLE_BITMAPSCAN = FALSE; EXPLAIN (COSTS off, NODES off) SELECT * FROM TEST1_P WHERE TEST1_F1 > 5000; QUERY PLAN ---------------------------------------------------------------------------- - Streaming (type: GATHER) - -> Partition Iterator - Iterations: 0 - -> Partitioned Index Only Scan using index_on_test1_p on test1_p - Index Cond: (test1_f1 > 5000) - Selected Partitions: NONE -(6 rows) +--------------------------------------------------------------------- + Partition Iterator + Iterations: 0 + -> Partitioned Index Only Scan using index_on_test1_p on test1_p + Index Cond: (test1_f1 > 5000) + Selected Partitions: NONE +(5 rows) RESET ENABLE_SEQSCAN; RESET ENABLE_BITMAPSCAN; diff --git a/src/test/regress/input/hw_partition_insert_01.source b/src/test/regress/input/hw_partition_insert_01.source index 559b893707..4b72338d90 100644 --- a/src/test/regress/input/hw_partition_insert_01.source +++ b/src/test/regress/input/hw_partition_insert_01.source @@ -96,16 +96,6 @@ drop table insert_without_index_without_interval_with_maxvalue_tz; -- ---- MAX_PARTITION_NUM(32767) -- ---date -create table insert_max_partition_num_date(col_date date) -partition by range(col_date) -interval (interval '1' day) store in (hw_partition_insert_tsp4, hw_partition_insert_tsp5, hw_partition_insert_tsp6) -( - partition insert_max_partition_num_date_p1 values less than ('2012-1-25') tablespace hw_partition_insert_tsp4, - partition insert_max_partition_num_date_p2 values less than ('2012-2-25') tablespace hw_partition_insert_tsp5, - partition insert_max_partition_num_date_p3 values less than ('2012-3-25') tablespace hw_partition_insert_tsp6 -); - -- ---- test for null, int2 -- diff --git a/src/test/regress/input/hw_partition_interval.source b/src/test/regress/input/hw_partition_interval.source new file mode 100644 index 0000000000..71fb886c76 --- /dev/null +++ b/src/test/regress/input/hw_partition_interval.source @@ -0,0 +1,229 @@ +-- +-- prepare: create tablespace dir +-- +\! mkdir '@testtablespace@/hw_partition_interval_tsp4' +\! mkdir '@testtablespace@/hw_partition_interval_tsp5' +\! mkdir '@testtablespace@/hw_partition_interval_tsp6' +set timezone = 'PRC'; +create tablespace hw_partition_interval_tsp4 location '@testtablespace@/hw_partition_interval_tsp4'; +create tablespace hw_partition_interval_tsp5 location '@testtablespace@/hw_partition_interval_tsp5'; +create tablespace hw_partition_interval_tsp6 location '@testtablespace@/hw_partition_interval_tsp6'; + +-- +---- normal operates : create, insert, auto create and drop without table space +-- +CREATE TABLE interval_normal_date (logdate date not null) +PARTITION BY RANGE (logdate) +INTERVAL ('1 day') +( + PARTITION interval_normal_date_p1 VALUES LESS THAN ('2020-03-01'), + PARTITION interval_normal_date_p2 VALUES LESS THAN ('2020-05-01'), + PARTITION interval_normal_date_p3 VALUES LESS THAN ('2020-06-01') +); + +-- see about the info of the partitioned table in pg_partition +select relname, parttype, partstrategy, boundaries from pg_partition + where parentid = (select oid from pg_class where relname = 'interval_normal_date') + order by relname; + +-- insert the record that is smaller than the lower boundary +insert into interval_normal_date values ('2020-02-20'); +insert into interval_normal_date values ('2020-3-01'); +insert into interval_normal_date values ('2020-3-02'); +insert into interval_normal_date values ('2020-5-02'); + +-- no new interval range created +select relname, parttype, partstrategy, boundaries from pg_partition + where parentid = (select oid from pg_class where relname = 'interval_normal_date') + order by relname; + +-- insert the record that is smaller than the lower boundary +insert into interval_normal_date values ('2020-6-01'); +insert into interval_normal_date values ('2020-6-02'); +insert into interval_normal_date values ('2020-6-03'); + +-- created two new interval ranges +select relname, parttype, partstrategy, boundaries from pg_partition + where parentid = (select oid from pg_class where relname = 'interval_normal_date') + order by relname; + +-- inquire about data of the partition and the partitioned table +select * from interval_normal_date order by logdate; +select * from interval_normal_date partition (interval_normal_date_p1) order by logdate; +select * from interval_normal_date partition (interval_normal_date_p2) order by logdate; +select * from interval_normal_date partition (interval_normal_date_p3) order by logdate; +-- first created interval range +select * from interval_normal_date partition (sys_p1) order by logdate; +-- second created interval range +select * from interval_normal_date partition (sys_p2) order by logdate; +-- third created interval range +select * from interval_normal_date partition (sys_p3) order by logdate; + +-- drop range partition which is not next to interval range. +ALTER TABLE interval_normal_date DROP PARTITION interval_normal_date_p2; +-- see about the info of the partitioned table in pg_partition +select relname, parttype, partstrategy, boundaries from pg_partition + where parentid = (select oid from pg_class where relname = 'interval_normal_date') + order by relname; + +-- drop interval range partition +ALTER TABLE interval_normal_date DROP PARTITION sys_p2; +-- see the info of the partitioned table in pg_partition, only reduce a interval range partition instance. +select relname, parttype, partstrategy, boundaries from pg_partition + where parentid = (select oid from pg_class where relname = 'interval_normal_date') + order by relname; + +-- drop range partition which is next to interval range. +ALTER TABLE interval_normal_date DROP PARTITION interval_normal_date_p3; +-- the interval parttition will changed to range partition +select relname, parttype, partstrategy, boundaries from pg_partition + where parentid = (select oid from pg_class where relname = 'interval_normal_date') + order by relname; + +-- insert the record to create droped range sys_p2, which will have a new relname. +insert into interval_normal_date values ('2020-6-02'); +-- will add the new created interval partition. +select relname, parttype, partstrategy, boundaries from pg_partition + where parentid = (select oid from pg_class where relname = 'interval_normal_date') + order by relname; + +-- insert the record that is smaller than the lower boundary +insert into interval_normal_date values ('2020-3-02'); +insert into interval_normal_date values ('2020-5-02'); + +-- inquire about data of the partition and the partitioned table +select * from interval_normal_date order by logdate; +select * from interval_normal_date partition (interval_normal_date_p1) order by logdate; +-- first created interval range +select * from interval_normal_date partition (sys_p1) order by logdate; +-- third created interval range +select * from interval_normal_date partition (sys_p3) order by logdate; +-- fourth created interval range +select * from interval_normal_date partition (sys_p4) order by logdate; + +-- Insert a future data +insert into interval_normal_date values ('2030-3-01'); +insert into interval_normal_date values ('2040-06-20'); + +-- see about the info of the partitioned table in pg_partition +select relname, parttype, partstrategy, boundaries from pg_partition + where parentid = (select oid from pg_class where relname = 'interval_normal_date') + order by relname; + +-- inquire about data of the partition and the partitioned table +select * from interval_normal_date order by logdate; +select * from interval_normal_date partition (sys_p5) order by logdate; +select * from interval_normal_date partition (sys_p6) order by logdate; + +-- +---- test truncate partitions without index +-- + +-- truncate a range partition +ALTER TABLE interval_normal_date truncate PARTITION interval_normal_date_p1; +select * from interval_normal_date partition (interval_normal_date_p1) order by logdate; + +-- truncate a interval partition +ALTER TABLE interval_normal_date truncate PARTITION sys_p4; +select * from interval_normal_date partition (sys_p4) order by logdate; + +-- truncate the partitioned table +truncate table interval_normal_date; +select * from interval_normal_date order by logdate; + +-- +---- merge and split partition are not supported yet; +-- + +-- split partition +ALTER TABLE interval_normal_date SPLIT PARTITION sys_p1 AT ('2020-04-01 00:00:00') INTO +( + PARTITION sys_p6, + PARTITION sys_p7 +); + +-- mgerge partition +ALTER TABLE interval_normal_date MERGE PARTITIONS interval_normal_date_p1, sys_p1 into PARTITION sys_p8; +ALTER TABLE interval_normal_date MERGE PARTITIONS sys_p1, sys_p4 into PARTITION sys_p9; + +-- +---- add partition is not supported; +-- +ALTER TABLE interval_normal_date ADD PARTITION sys_10 VALUES LESS THAN ('2020-07-01'); + +-- +---- alter partition name +-- +ALTER TABLE interval_normal_date RENAME PARTITION sys_p5 To my_sys_p5; +ALTER TABLE interval_normal_date RENAME PARTITION FOR ('2020-06-02') To my_sys_p4; +select relname, parttype, partstrategy, boundaries from pg_partition + where parentid = (select oid from pg_class where relname = 'interval_normal_date') + order by relname; + +ALTER TABLE interval_normal_date RENAME PARTITION sys_p6 To my_sys_p6; +insert into interval_normal_date values ('2040-06-21'); +select relname, parttype, partstrategy, boundaries from pg_partition + where parentid = (select oid from pg_class where relname = 'interval_normal_date') + order by relname; + +ALTER TABLE interval_normal_date RENAME PARTITION sys_p4 To sys_p32767; +insert into interval_normal_date values ('2040-06-22'); +select relname, parttype, partstrategy, boundaries from pg_partition + where parentid = (select oid from pg_class where relname = 'interval_normal_date') + order by relname; + +ALTER TABLE interval_normal_date RENAME PARTITION sys_p2 To sys_p32780; +insert into interval_normal_date values ('2040-06-24'); +select relname, parttype, partstrategy, boundaries from pg_partition + where parentid = (select oid from pg_class where relname = 'interval_normal_date') + order by relname; + +--clean up +drop table interval_normal_date; + +-- +---- tablespace +-- +--date +--create table insert_max_partition_num_date(col_date date) +--partition by range(col_date) +--interval ('1' day) store in (hw_partition_insert_tsp4, hw_partition_insert_tsp5, hw_partition_insert_tsp6) +--( +-- partition insert_max_partition_num_date_p1 values less than ('2012-1-25') tablespace hw_partition_insert_tsp4, +-- partition insert_max_partition_num_date_p2 values less than ('2012-2-25') tablespace hw_partition_insert_tsp5, +-- partition insert_max_partition_num_date_p3 values less than ('2012-3-25') tablespace hw_partition_insert_tsp6 +--); + +-- +---- test with where conditions +-- +--select * from interval_normal_date where logdate < '2020-06-01'; +--ERROR: pruning result(PartitionIdentifier) is invalid + +-- +---- test with maxvalue +-- + +-- +---- test with null +-- + +-- +---- test support interval type maxvalue +-- Hour, Day, month, timestamp, timestamptz, date +-- + + +-- +---- test month interval increase, specific Feb +-- + +-- +-- clean up +-- +drop tablespace hw_partition_interval_tsp4; +drop tablespace hw_partition_interval_tsp5; +drop tablespace hw_partition_interval_tsp6; +\! rm -fr '@testtablespace@/hw_partition_interval_tsp4' +\! rm -fr '@testtablespace@/hw_partition_interval_tsp5' +\! rm -fr '@testtablespace@/hw_partition_interval_tsp6' \ No newline at end of file diff --git a/src/test/regress/output/hw_partition_insert_01.source b/src/test/regress/output/hw_partition_insert_01.source index deaec85f08..3c305dc20f 100644 --- a/src/test/regress/output/hw_partition_insert_01.source +++ b/src/test/regress/output/hw_partition_insert_01.source @@ -60,29 +60,29 @@ select p.relname, p.boundaries, t.spcname from pg_partition p left join pg_table select * from insert_without_index_without_interval_without_maxvalue_tz order by col_timestamptz; col_timestamptz ------------------------------ - Sat Feb 26 14:00:00 2011 CST - Wed Jan 25 14:00:00 2012 CST - Mon Feb 20 14:00:00 2012 CST - Sat Feb 25 14:00:00 2012 CST + Sat Feb 26 00:00:00 2011 CST + Wed Jan 25 00:00:00 2012 CST + Mon Feb 20 00:00:00 2012 CST + Sat Feb 25 00:00:00 2012 CST (4 rows) select * from insert_without_index_without_interval_without_maxvalue_tz partition (insert_without_index_without_interval_without_maxvalue_tz_p1) order by 1; col_timestamptz ------------------------------ - Sat Feb 26 14:00:00 2011 CST + Sat Feb 26 00:00:00 2011 CST (1 row) select * from insert_without_index_without_interval_without_maxvalue_tz partition (insert_without_index_without_interval_without_maxvalue_tz_p2) order by 1; col_timestamptz ------------------------------ - Wed Jan 25 14:00:00 2012 CST - Mon Feb 20 14:00:00 2012 CST + Wed Jan 25 00:00:00 2012 CST + Mon Feb 20 00:00:00 2012 CST (2 rows) select * from insert_without_index_without_interval_without_maxvalue_tz partition (insert_without_index_without_interval_without_maxvalue_tz_p3) order by 1; col_timestamptz ------------------------------ - Sat Feb 25 14:00:00 2012 CST + Sat Feb 25 00:00:00 2012 CST (1 row) --clean up @@ -137,33 +137,33 @@ select p.relname, p.boundaries, t.spcname from pg_partition p left join pg_table select * from insert_without_index_without_interval_with_maxvalue_tz order by col_timestamptz; col_timestamptz ------------------------------ - Sat Feb 26 14:00:00 2011 CST - Wed Jan 25 14:00:00 2012 CST - Mon Feb 20 14:00:00 2012 CST - Sat Feb 25 14:00:00 2012 CST - Sun Mar 25 14:00:00 2012 CST - Mon Mar 25 14:00:00 2013 CST + Sat Feb 26 00:00:00 2011 CST + Wed Jan 25 00:00:00 2012 CST + Mon Feb 20 00:00:00 2012 CST + Sat Feb 25 00:00:00 2012 CST + Sun Mar 25 00:00:00 2012 CST + Mon Mar 25 00:00:00 2013 CST (6 rows) select * from insert_without_index_without_interval_with_maxvalue_tz partition (insert_without_index_without_interval_with_maxvalue_tz_p1) order by 1; col_timestamptz ------------------------------ - Sat Feb 26 14:00:00 2011 CST + Sat Feb 26 00:00:00 2011 CST (1 row) select * from insert_without_index_without_interval_with_maxvalue_tz partition (insert_without_index_without_interval_with_maxvalue_tz_p2) order by 1; col_timestamptz ------------------------------ - Wed Jan 25 14:00:00 2012 CST - Mon Feb 20 14:00:00 2012 CST + Wed Jan 25 00:00:00 2012 CST + Mon Feb 20 00:00:00 2012 CST (2 rows) select * from insert_without_index_without_interval_with_maxvalue_tz partition (insert_without_index_without_interval_with_maxvalue_tz_p3) order by 1; col_timestamptz ------------------------------ - Sat Feb 25 14:00:00 2012 CST - Sun Mar 25 14:00:00 2012 CST - Mon Mar 25 14:00:00 2013 CST + Sat Feb 25 00:00:00 2012 CST + Sun Mar 25 00:00:00 2012 CST + Mon Mar 25 00:00:00 2013 CST (3 rows) --clean up @@ -171,17 +171,6 @@ drop table insert_without_index_without_interval_with_maxvalue_tz; -- ---- MAX_PARTITION_NUM(32767) -- ---date -create table insert_max_partition_num_date(col_date date) -partition by range(col_date) -interval (interval '1' day) store in (hw_partition_insert_tsp4, hw_partition_insert_tsp5, hw_partition_insert_tsp6) -( - partition insert_max_partition_num_date_p1 values less than ('2012-1-25') tablespace hw_partition_insert_tsp4, - partition insert_max_partition_num_date_p2 values less than ('2012-2-25') tablespace hw_partition_insert_tsp5, - partition insert_max_partition_num_date_p3 values less than ('2012-3-25') tablespace hw_partition_insert_tsp6 -); -ERROR: Range partitioned table with INTERVAL was forbidden -HINT: Only support pure range partitioned table -- ---- test for null, int2 -- diff --git a/src/test/regress/output/hw_partition_interval.source b/src/test/regress/output/hw_partition_interval.source new file mode 100644 index 0000000000..0e4316ac8d --- /dev/null +++ b/src/test/regress/output/hw_partition_interval.source @@ -0,0 +1,428 @@ +-- +-- prepare: create tablespace dir +-- +\! mkdir '@testtablespace@/hw_partition_interval_tsp4' +\! mkdir '@testtablespace@/hw_partition_interval_tsp5' +\! mkdir '@testtablespace@/hw_partition_interval_tsp6' +set timezone = 'PRC'; +create tablespace hw_partition_interval_tsp4 location '@testtablespace@/hw_partition_interval_tsp4'; +create tablespace hw_partition_interval_tsp5 location '@testtablespace@/hw_partition_interval_tsp5'; +create tablespace hw_partition_interval_tsp6 location '@testtablespace@/hw_partition_interval_tsp6'; +-- +---- normal operates : create, insert, auto create and drop without table space +-- +CREATE TABLE interval_normal_date (logdate date not null) +PARTITION BY RANGE (logdate) +INTERVAL ('1 day') +( + PARTITION interval_normal_date_p1 VALUES LESS THAN ('2020-03-01'), + PARTITION interval_normal_date_p2 VALUES LESS THAN ('2020-05-01'), + PARTITION interval_normal_date_p3 VALUES LESS THAN ('2020-06-01') +); +-- see about the info of the partitioned table in pg_partition +select relname, parttype, partstrategy, boundaries from pg_partition + where parentid = (select oid from pg_class where relname = 'interval_normal_date') + order by relname; + relname | parttype | partstrategy | boundaries +-------------------------+----------+--------------+-------------- + interval_normal_date | r | i | + interval_normal_date_p1 | p | r | {2020-03-01} + interval_normal_date_p2 | p | r | {2020-05-01} + interval_normal_date_p3 | p | r | {2020-06-01} +(4 rows) + +-- insert the record that is smaller than the lower boundary +insert into interval_normal_date values ('2020-02-20'); +insert into interval_normal_date values ('2020-3-01'); +insert into interval_normal_date values ('2020-3-02'); +insert into interval_normal_date values ('2020-5-02'); +-- no new interval range created +select relname, parttype, partstrategy, boundaries from pg_partition + where parentid = (select oid from pg_class where relname = 'interval_normal_date') + order by relname; + relname | parttype | partstrategy | boundaries +-------------------------+----------+--------------+-------------- + interval_normal_date | r | i | + interval_normal_date_p1 | p | r | {2020-03-01} + interval_normal_date_p2 | p | r | {2020-05-01} + interval_normal_date_p3 | p | r | {2020-06-01} +(4 rows) + +-- insert the record that is smaller than the lower boundary +insert into interval_normal_date values ('2020-6-01'); +insert into interval_normal_date values ('2020-6-02'); +insert into interval_normal_date values ('2020-6-03'); +-- created two new interval ranges +select relname, parttype, partstrategy, boundaries from pg_partition + where parentid = (select oid from pg_class where relname = 'interval_normal_date') + order by relname; + relname | parttype | partstrategy | boundaries +-------------------------+----------+--------------+------------------------------ + interval_normal_date | r | i | + interval_normal_date_p1 | p | r | {2020-03-01} + interval_normal_date_p2 | p | r | {2020-05-01} + interval_normal_date_p3 | p | r | {2020-06-01} + sys_p1 | p | i | {"Tue Jun 02 00:00:00 2020"} + sys_p2 | p | i | {"Wed Jun 03 00:00:00 2020"} + sys_p3 | p | i | {"Thu Jun 04 00:00:00 2020"} +(7 rows) + +-- inquire about data of the partition and the partitioned table +select * from interval_normal_date order by logdate; + logdate +-------------------------- + Thu Feb 20 00:00:00 2020 + Sun Mar 01 00:00:00 2020 + Mon Mar 02 00:00:00 2020 + Sat May 02 00:00:00 2020 + Mon Jun 01 00:00:00 2020 + Tue Jun 02 00:00:00 2020 + Wed Jun 03 00:00:00 2020 +(7 rows) + +select * from interval_normal_date partition (interval_normal_date_p1) order by logdate; + logdate +-------------------------- + Thu Feb 20 00:00:00 2020 +(1 row) + +select * from interval_normal_date partition (interval_normal_date_p2) order by logdate; + logdate +-------------------------- + Sun Mar 01 00:00:00 2020 + Mon Mar 02 00:00:00 2020 +(2 rows) + +select * from interval_normal_date partition (interval_normal_date_p3) order by logdate; + logdate +-------------------------- + Sat May 02 00:00:00 2020 +(1 row) + +-- first created interval range +select * from interval_normal_date partition (sys_p1) order by logdate; + logdate +-------------------------- + Mon Jun 01 00:00:00 2020 +(1 row) + +-- second created interval range +select * from interval_normal_date partition (sys_p2) order by logdate; + logdate +-------------------------- + Tue Jun 02 00:00:00 2020 +(1 row) + +-- third created interval range +select * from interval_normal_date partition (sys_p3) order by logdate; + logdate +-------------------------- + Wed Jun 03 00:00:00 2020 +(1 row) + +-- drop range partition which is not next to interval range. +ALTER TABLE interval_normal_date DROP PARTITION interval_normal_date_p2; +-- see about the info of the partitioned table in pg_partition +select relname, parttype, partstrategy, boundaries from pg_partition + where parentid = (select oid from pg_class where relname = 'interval_normal_date') + order by relname; + relname | parttype | partstrategy | boundaries +-------------------------+----------+--------------+------------------------------ + interval_normal_date | r | i | + interval_normal_date_p1 | p | r | {2020-03-01} + interval_normal_date_p3 | p | r | {2020-06-01} + sys_p1 | p | i | {"Tue Jun 02 00:00:00 2020"} + sys_p2 | p | i | {"Wed Jun 03 00:00:00 2020"} + sys_p3 | p | i | {"Thu Jun 04 00:00:00 2020"} +(6 rows) + +-- drop interval range partition +ALTER TABLE interval_normal_date DROP PARTITION sys_p2; +-- see the info of the partitioned table in pg_partition, only reduce a interval range partition instance. +select relname, parttype, partstrategy, boundaries from pg_partition + where parentid = (select oid from pg_class where relname = 'interval_normal_date') + order by relname; + relname | parttype | partstrategy | boundaries +-------------------------+----------+--------------+------------------------------ + interval_normal_date | r | i | + interval_normal_date_p1 | p | r | {2020-03-01} + interval_normal_date_p3 | p | r | {2020-06-01} + sys_p1 | p | i | {"Tue Jun 02 00:00:00 2020"} + sys_p3 | p | i | {"Thu Jun 04 00:00:00 2020"} +(5 rows) + +-- drop range partition which is next to interval range. +ALTER TABLE interval_normal_date DROP PARTITION interval_normal_date_p3; +-- the interval parttition will changed to range partition +select relname, parttype, partstrategy, boundaries from pg_partition + where parentid = (select oid from pg_class where relname = 'interval_normal_date') + order by relname; + relname | parttype | partstrategy | boundaries +-------------------------+----------+--------------+------------------------------ + interval_normal_date | r | i | + interval_normal_date_p1 | p | r | {2020-03-01} + sys_p1 | p | r | {"Tue Jun 02 00:00:00 2020"} + sys_p3 | p | i | {"Thu Jun 04 00:00:00 2020"} +(4 rows) + +-- insert the record to create droped range sys_p2, which will have a new relname. +insert into interval_normal_date values ('2020-6-02'); +-- will add the new created interval partition. +select relname, parttype, partstrategy, boundaries from pg_partition + where parentid = (select oid from pg_class where relname = 'interval_normal_date') + order by relname; + relname | parttype | partstrategy | boundaries +-------------------------+----------+--------------+------------------------------ + interval_normal_date | r | i | + interval_normal_date_p1 | p | r | {2020-03-01} + sys_p1 | p | r | {"Tue Jun 02 00:00:00 2020"} + sys_p3 | p | i | {"Thu Jun 04 00:00:00 2020"} + sys_p4 | p | i | {"Wed Jun 03 00:00:00 2020"} +(5 rows) + +-- insert the record that is smaller than the lower boundary +insert into interval_normal_date values ('2020-3-02'); +insert into interval_normal_date values ('2020-5-02'); +-- inquire about data of the partition and the partitioned table +select * from interval_normal_date order by logdate; + logdate +-------------------------- + Thu Feb 20 00:00:00 2020 + Mon Mar 02 00:00:00 2020 + Sat May 02 00:00:00 2020 + Mon Jun 01 00:00:00 2020 + Tue Jun 02 00:00:00 2020 + Wed Jun 03 00:00:00 2020 +(6 rows) + +select * from interval_normal_date partition (interval_normal_date_p1) order by logdate; + logdate +-------------------------- + Thu Feb 20 00:00:00 2020 +(1 row) + +-- first created interval range +select * from interval_normal_date partition (sys_p1) order by logdate; + logdate +-------------------------- + Mon Mar 02 00:00:00 2020 + Sat May 02 00:00:00 2020 + Mon Jun 01 00:00:00 2020 +(3 rows) + +-- third created interval range +select * from interval_normal_date partition (sys_p3) order by logdate; + logdate +-------------------------- + Wed Jun 03 00:00:00 2020 +(1 row) + +-- fourth created interval range +select * from interval_normal_date partition (sys_p4) order by logdate; + logdate +-------------------------- + Tue Jun 02 00:00:00 2020 +(1 row) + +-- Insert a future data +insert into interval_normal_date values ('2030-3-01'); +insert into interval_normal_date values ('2040-06-20'); +-- see about the info of the partitioned table in pg_partition +select relname, parttype, partstrategy, boundaries from pg_partition + where parentid = (select oid from pg_class where relname = 'interval_normal_date') + order by relname; + relname | parttype | partstrategy | boundaries +-------------------------+----------+--------------+------------------------------ + interval_normal_date | r | i | + interval_normal_date_p1 | p | r | {2020-03-01} + sys_p1 | p | r | {"Tue Jun 02 00:00:00 2020"} + sys_p3 | p | i | {"Thu Jun 04 00:00:00 2020"} + sys_p4 | p | i | {"Wed Jun 03 00:00:00 2020"} + sys_p5 | p | i | {"Sat Mar 02 00:00:00 2030"} + sys_p6 | p | i | {"Thu Jun 21 00:00:00 2040"} +(7 rows) + +-- inquire about data of the partition and the partitioned table +select * from interval_normal_date order by logdate; + logdate +-------------------------- + Thu Feb 20 00:00:00 2020 + Mon Mar 02 00:00:00 2020 + Sat May 02 00:00:00 2020 + Mon Jun 01 00:00:00 2020 + Tue Jun 02 00:00:00 2020 + Wed Jun 03 00:00:00 2020 + Fri Mar 01 00:00:00 2030 + Wed Jun 20 00:00:00 2040 +(8 rows) + +select * from interval_normal_date partition (sys_p5) order by logdate; + logdate +-------------------------- + Fri Mar 01 00:00:00 2030 +(1 row) + +select * from interval_normal_date partition (sys_p6) order by logdate; + logdate +-------------------------- + Wed Jun 20 00:00:00 2040 +(1 row) + +-- +---- test truncate partitions without index +-- +-- truncate a range partition +ALTER TABLE interval_normal_date truncate PARTITION interval_normal_date_p1; +select * from interval_normal_date partition (interval_normal_date_p1) order by logdate; + logdate +--------- +(0 rows) + +-- truncate a interval partition +ALTER TABLE interval_normal_date truncate PARTITION sys_p4; +select * from interval_normal_date partition (sys_p4) order by logdate; + logdate +--------- +(0 rows) + +-- truncate the partitioned table +truncate table interval_normal_date; +select * from interval_normal_date order by logdate; + logdate +--------- +(0 rows) + +-- +---- merge and split partition are not supported yet; +-- +-- split partition +ALTER TABLE interval_normal_date SPLIT PARTITION sys_p1 AT ('2020-04-01 00:00:00') INTO +( + PARTITION sys_p6, + PARTITION sys_p7 +); +ERROR: can not split partition against interval partitioned table +-- mgerge partition +ALTER TABLE interval_normal_date MERGE PARTITIONS interval_normal_date_p1, sys_p1 into PARTITION sys_p8; +ERROR: can not merge partition against interval partitioned table +ALTER TABLE interval_normal_date MERGE PARTITIONS sys_p1, sys_p4 into PARTITION sys_p9; +ERROR: can not merge partition against interval partitioned table +-- +---- add partition is not supported; +-- +ALTER TABLE interval_normal_date ADD PARTITION sys_10 VALUES LESS THAN ('2020-07-01'); +ERROR: can not add partition against interval partitioned table +-- +---- alter partition name +-- +ALTER TABLE interval_normal_date RENAME PARTITION sys_p5 To my_sys_p5; +ALTER TABLE interval_normal_date RENAME PARTITION FOR ('2020-06-02') To my_sys_p4; +select relname, parttype, partstrategy, boundaries from pg_partition + where parentid = (select oid from pg_class where relname = 'interval_normal_date') + order by relname; + relname | parttype | partstrategy | boundaries +-------------------------+----------+--------------+------------------------------ + interval_normal_date | r | i | + interval_normal_date_p1 | p | r | {2020-03-01} + my_sys_p4 | p | i | {"Wed Jun 03 00:00:00 2020"} + my_sys_p5 | p | i | {"Sat Mar 02 00:00:00 2030"} + sys_p1 | p | r | {"Tue Jun 02 00:00:00 2020"} + sys_p3 | p | i | {"Thu Jun 04 00:00:00 2020"} + sys_p6 | p | i | {"Thu Jun 21 00:00:00 2040"} +(7 rows) + +ALTER TABLE interval_normal_date RENAME PARTITION sys_p6 To my_sys_p6; +insert into interval_normal_date values ('2040-06-21'); +select relname, parttype, partstrategy, boundaries from pg_partition + where parentid = (select oid from pg_class where relname = 'interval_normal_date') + order by relname; + relname | parttype | partstrategy | boundaries +-------------------------+----------+--------------+------------------------------ + interval_normal_date | r | i | + interval_normal_date_p1 | p | r | {2020-03-01} + my_sys_p4 | p | i | {"Wed Jun 03 00:00:00 2020"} + my_sys_p5 | p | i | {"Sat Mar 02 00:00:00 2030"} + my_sys_p6 | p | i | {"Thu Jun 21 00:00:00 2040"} + sys_p1 | p | r | {"Tue Jun 02 00:00:00 2020"} + sys_p3 | p | i | {"Thu Jun 04 00:00:00 2020"} + sys_p4 | p | i | {"Fri Jun 22 00:00:00 2040"} +(8 rows) + +ALTER TABLE interval_normal_date RENAME PARTITION sys_p4 To sys_p32767; +insert into interval_normal_date values ('2040-06-22'); +select relname, parttype, partstrategy, boundaries from pg_partition + where parentid = (select oid from pg_class where relname = 'interval_normal_date') + order by relname; + relname | parttype | partstrategy | boundaries +-------------------------+----------+--------------+------------------------------ + interval_normal_date | r | i | + interval_normal_date_p1 | p | r | {2020-03-01} + my_sys_p4 | p | i | {"Wed Jun 03 00:00:00 2020"} + my_sys_p5 | p | i | {"Sat Mar 02 00:00:00 2030"} + my_sys_p6 | p | i | {"Thu Jun 21 00:00:00 2040"} + sys_p1 | p | r | {"Tue Jun 02 00:00:00 2020"} + sys_p2 | p | i | {"Sat Jun 23 00:00:00 2040"} + sys_p3 | p | i | {"Thu Jun 04 00:00:00 2020"} + sys_p32767 | p | i | {"Fri Jun 22 00:00:00 2040"} +(9 rows) + +ALTER TABLE interval_normal_date RENAME PARTITION sys_p2 To sys_p32780; +insert into interval_normal_date values ('2040-06-24'); +select relname, parttype, partstrategy, boundaries from pg_partition + where parentid = (select oid from pg_class where relname = 'interval_normal_date') + order by relname; + relname | parttype | partstrategy | boundaries +-------------------------+----------+--------------+------------------------------ + interval_normal_date | r | i | + interval_normal_date_p1 | p | r | {2020-03-01} + my_sys_p4 | p | i | {"Wed Jun 03 00:00:00 2020"} + my_sys_p5 | p | i | {"Sat Mar 02 00:00:00 2030"} + my_sys_p6 | p | i | {"Thu Jun 21 00:00:00 2040"} + sys_p1 | p | r | {"Tue Jun 02 00:00:00 2020"} + sys_p14 | p | i | {"Mon Jun 25 00:00:00 2040"} + sys_p3 | p | i | {"Thu Jun 04 00:00:00 2020"} + sys_p32767 | p | i | {"Fri Jun 22 00:00:00 2040"} + sys_p32780 | p | i | {"Sat Jun 23 00:00:00 2040"} +(10 rows) + +--clean up +drop table interval_normal_date; +-- +---- tablespace +-- +--date +--create table insert_max_partition_num_date(col_date date) +--partition by range(col_date) +--interval ('1' day) store in (hw_partition_insert_tsp4, hw_partition_insert_tsp5, hw_partition_insert_tsp6) +--( +-- partition insert_max_partition_num_date_p1 values less than ('2012-1-25') tablespace hw_partition_insert_tsp4, +-- partition insert_max_partition_num_date_p2 values less than ('2012-2-25') tablespace hw_partition_insert_tsp5, +-- partition insert_max_partition_num_date_p3 values less than ('2012-3-25') tablespace hw_partition_insert_tsp6 +--); +-- +---- test with where conditions +-- +--select * from interval_normal_date where logdate < '2020-06-01'; +--ERROR: pruning result(PartitionIdentifier) is invalid +-- +---- test with maxvalue +-- +-- +---- test with null +-- +-- +---- test support interval type maxvalue +-- Hour, Day, month, timestamp, timestamptz, date +-- +-- +---- test month interval increase, specific Feb +-- +-- +-- clean up +-- +drop tablespace hw_partition_interval_tsp4; +drop tablespace hw_partition_interval_tsp5; +drop tablespace hw_partition_interval_tsp6; +\! rm -fr '@testtablespace@/hw_partition_interval_tsp4' +\! rm -fr '@testtablespace@/hw_partition_interval_tsp5' +\! rm -fr '@testtablespace@/hw_partition_interval_tsp6' diff --git a/src/test/regress/output/hw_partition_sql_adapt0.source b/src/test/regress/output/hw_partition_sql_adapt0.source index d3d17c5a31..996e8aa3c8 100644 --- a/src/test/regress/output/hw_partition_sql_adapt0.source +++ b/src/test/regress/output/hw_partition_sql_adapt0.source @@ -279,8 +279,8 @@ NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "test_pkey" for t insert into test values (0); -- failed alter table test_add_column_constraint add foreign key (a) references test(a) ; -ERROR: FOREIGN KEY ... REFERENCES constraint is not yet supported. drop table test cascade; +NOTICE: drop cascades to constraint test_add_column_constraint_a_fkey on table test_add_column_constraint -- d.deferrable -- failed alter table test_add_column_constraint add column c4 int deferrable; @@ -827,7 +827,7 @@ select * from test_drop_column_view order by 1,2; -- failed select * from temp_view order by 1,2; -ERROR: relation "temp_view" does not exist +ERROR: relation "temp_view" does not exist on datanode1 LINE 1: select * from temp_view order by 1,2; ^ -- failed diff --git a/src/test/regress/output/hw_partition_sql_adapt2.source b/src/test/regress/output/hw_partition_sql_adapt2.source index c7482dc78a..ce04988e18 100644 --- a/src/test/regress/output/hw_partition_sql_adapt2.source +++ b/src/test/regress/output/hw_partition_sql_adapt2.source @@ -964,8 +964,6 @@ Indexes: Range partition by(a) Number of partition: 3 (View pg_partition to check each partition range.) Has OIDs: no -Distribute By: HASH(a) -Location Nodes: ALL DATANODES Options: orientation=row, compression=no -- clean @@ -1031,18 +1029,25 @@ partition by range (a, b) partition test_partition_foreign_key_p2 values less than (4, 'e'), partition test_partition_foreign_key_p3 values less than (7, 'h') ); -ERROR: FOREIGN KEY ... REFERENCES constraint is not yet supported. -- failed drop user temp_user; ERROR: cannot drop schema temp_user because other objects depend on it DETAIL: table temp_user.test_ordinary_reftable depends on schema temp_user +constraint test_partition_foreign_key_a_fkey on table test_partition_foreign_key depends on table temp_user.test_ordinary_reftable HINT: Use DROP ... CASCADE to drop the dependent objects too. -- failed drop owned by temp_user; +ERROR: cannot drop desired object(s) because other objects depend on them +DETAIL: constraint test_partition_foreign_key_a_fkey on table test_partition_foreign_key depends on table temp_user.test_ordinary_reftable +HINT: Use DROP ... CASCADE to drop the dependent objects too. -- failed drop owned by temp_user restrict; +ERROR: cannot drop desired object(s) because other objects depend on them +DETAIL: constraint test_partition_foreign_key_a_fkey on table test_partition_foreign_key depends on table temp_user.test_ordinary_reftable +HINT: Use DROP ... CASCADE to drop the dependent objects too. -- success drop owned by temp_user cascade; +NOTICE: drop cascades to constraint test_partition_foreign_key_a_fkey on table test_partition_foreign_key select relname, rolname from pg_class, pg_roles where relname='test_ordinary_reftable' and pg_class.relowner=pg_roles.oid; relname | rolname ---------+--------- @@ -1050,14 +1055,10 @@ select relname, rolname from pg_class, pg_roles where relname='test_ordinary_ref -- success insert into test_partition_foreign_key values (0, 'a', 0, 'a'); -ERROR: relation "test_partition_foreign_key" does not exist -LINE 1: insert into test_partition_foreign_key values (0, 'a', 0, 'a... - ^ -- success drop user temp_user; -- clean drop table test_partition_foreign_key; -ERROR: table "test_partition_foreign_key" does not exist ---------------------- -- test alter table set tablespace on ordinary table \! rm -fr '@testtablespace@/hw_partition_sql_adapt_ts1' diff --git a/src/test/regress/parallel_schedule18 b/src/test/regress/parallel_schedule18 new file mode 100644 index 0000000000..acc596dfb3 --- /dev/null +++ b/src/test/regress/parallel_schedule18 @@ -0,0 +1,25 @@ +test: hw_partition_index +test: hw_partition_unusable_index_1 hw_partition_unusable_index_3 +test: hw_partition_insert hw_partition_insert_01 hw_partition_dml +test: hw_partition_grant hw_partition_of_type +test: hw_partition_nodes hw_partition_size hw_partition_compare hw_partition_storage_parameters hw_partition_storage_parameters_index hw_partition_toast hw_partition_cross hw_partition_maxvalue +test: hw_partition_sql_adapt1 hw_partition_update1 +test: hw_partition_sql_adapt0 hw_partition_update0 +test: hw_partition_sql_adapt2 +test: hw_partition_interval +test: hw_partition_interval_exchange +test: hw_partition_interval_index +test: hw_partition_interval_unusable_index +test: hw_partition_interval_reindex +test: hw_partition_interval_movement +# To check create interval partition parallel +test: hw_partition_interval_parallel_prepare +test: hw_partition_interval_parallel_insert hw_partition_interval_parallel_insert_01 hw_partition_interval_parallel_insert_02 +test: hw_partition_interval_parallel_end +test: hw_partition_interval_select +#test: hw_partition_lock +#test: hw_partition_llt +# FIXME: move me back to the parallel test when the refcnt issue is fixed +# Below two teste are unstable, temporarily ignoring. This is same to distribute_dattistic, relallvisible, Dongwang will solve the problem. +#test: hw_partition_vacuum_full +#test: hw_partition_vacuum diff --git a/src/test/regress/sql/hw_partition_interval_exchange.sql b/src/test/regress/sql/hw_partition_interval_exchange.sql new file mode 100644 index 0000000000..f8c88c316b --- /dev/null +++ b/src/test/regress/sql/hw_partition_interval_exchange.sql @@ -0,0 +1,99 @@ +-- +-- Test exchange operator for interval partitioned table +-- + +-- +---- create interval partitioned table +-- +CREATE TABLE interval_normal_exchange (logdate date not null) +PARTITION BY RANGE (logdate) +INTERVAL ('1 month') +( + PARTITION interval_normal_exchange_p1 VALUES LESS THAN ('2020-03-01'), + PARTITION interval_normal_exchange_p2 VALUES LESS THAN ('2020-04-01'), + PARTITION interval_normal_exchange_p3 VALUES LESS THAN ('2020-05-01') +); + +-- see about the info of the partitioned table in pg_partition +select relname, parttype, partstrategy, boundaries from pg_partition + where parentid = (select oid from pg_class where relname = 'interval_normal_exchange') + order by relname; + +-- insert the record that is smaller than the lower boundary +insert into interval_normal_exchange values ('2020-02-21'); +insert into interval_normal_exchange values ('2020-02-22'); +insert into interval_normal_exchange values ('2020-02-23'); +insert into interval_normal_exchange values ('2020-5-01'); +insert into interval_normal_exchange values ('2020-5-02'); +insert into interval_normal_exchange values ('2020-5-03'); + +-- see about the info of the partitioned table in pg_partition +select relname, parttype, partstrategy, boundaries from pg_partition + where parentid = (select oid from pg_class where relname = 'interval_normal_exchange') + order by relname; + +-- +---- create to be exchanged table and test range partition exchange +-- +CREATE TABLE interval_exchange_test (logdate date not null); +insert into interval_exchange_test values ('2020-02-24'); +insert into interval_exchange_test values ('2020-02-25'); +insert into interval_exchange_test values ('2020-02-26'); + +-- do exchange partition interval_normal_exchange_p1 and interval_exchange_test +-- The data they have belongs to the same range. +ALTER TABLE interval_normal_exchange EXCHANGE PARTITION (interval_normal_exchange_p1) + WITH TABLE interval_exchange_test; +select * from interval_normal_exchange partition (interval_normal_exchange_p1)order by logdate; +select * from interval_exchange_test order by logdate; +-- exchange back +ALTER TABLE interval_normal_exchange EXCHANGE PARTITION (interval_normal_exchange_p1) + WITH TABLE interval_exchange_test; +select * from interval_normal_exchange partition (interval_normal_exchange_p1)order by logdate; +select * from interval_exchange_test order by logdate; + +-- Insert a new record not belongs to interval_normal_exchange_p1 +insert into interval_exchange_test values ('2020-3-05'); +-- defaut is WITH VALIDATION, and the exchange will be failed +ALTER TABLE interval_normal_exchange EXCHANGE PARTITION (interval_normal_exchange_p1) + WITH TABLE interval_exchange_test; +-- WITHOUT VALIDATION and the exchange will be success, but some date will in the wrong range; +ALTER TABLE interval_normal_exchange EXCHANGE PARTITION (interval_normal_exchange_p1) + WITH TABLE interval_exchange_test WITHOUT VALIDATION; +select * from interval_normal_exchange partition (interval_normal_exchange_p1)order by logdate; +select * from interval_exchange_test order by logdate; +-- not include '2020-3-05' +select * from interval_normal_exchange where logdate > '2020-03-01' order by logdate; + +-- +---- clean the data and test interval partition exchange +-- +truncate table interval_exchange_test; +insert into interval_exchange_test values ('2020-5-04'); +insert into interval_exchange_test values ('2020-5-05'); +insert into interval_exchange_test values ('2020-5-06'); + +-- exchange table +ALTER TABLE interval_normal_exchange EXCHANGE PARTITION (sys_p1) + WITH TABLE interval_exchange_test; +select * from interval_normal_exchange partition (sys_p1)order by logdate; +select * from interval_exchange_test order by logdate; +-- exchange back +ALTER TABLE interval_normal_exchange EXCHANGE PARTITION (sys_p1) + WITH TABLE interval_exchange_test; +select * from interval_normal_exchange partition (sys_p1)order by logdate; +select * from interval_exchange_test order by logdate; + +insert into interval_exchange_test values ('2020-6-05'); +-- defaut is WITH VALIDATION, and the exchange will be failed +ALTER TABLE interval_normal_exchange EXCHANGE PARTITION (interval_normal_exchange_p1) + WITH TABLE interval_exchange_test; +-- WITHOUT VALIDATION and the exchange will be success, but some date will in the wrong range; +ALTER TABLE interval_normal_exchange EXCHANGE PARTITION (interval_normal_exchange_p1) + WITH TABLE interval_exchange_test WITHOUT VALIDATION; +select * from interval_normal_exchange partition (interval_normal_exchange_p1)order by logdate; +select * from interval_exchange_test order by logdate; +-- not include '2020-6-05' +select * from interval_normal_exchange order by logdate; +select * from interval_normal_exchange where logdate > '2020-06-01' order by logdate; +drop table interval_normal_exchange; diff --git a/src/test/regress/sql/hw_partition_interval_index.sql b/src/test/regress/sql/hw_partition_interval_index.sql new file mode 100644 index 0000000000..d23157b6e4 --- /dev/null +++ b/src/test/regress/sql/hw_partition_interval_index.sql @@ -0,0 +1,336 @@ +-- +---- test interval partitioned index +-- +drop table if exists hw_partition_index_ip; +create table hw_partition_index_ip +( + c1 int, + c2 int, + logdate date not null +) +partition by range (logdate) +INTERVAL ('1 month') +( + PARTITION hw_partition_index_ip_p0 VALUES LESS THAN ('2020-03-01'), + PARTITION hw_partition_index_ip_p1 VALUES LESS THAN ('2020-04-01'), + PARTITION hw_partition_index_ip_p2 VALUES LESS THAN ('2020-05-01') +); +--succeed + +create index ip_index_local1 on hw_partition_index_ip (c1) local; +--succeed + +create index ip_index_local2 on hw_partition_index_ip (logdate) local +( + partition, + partition, + partition +); +--fail , the gram.y is not support opt_index_name + +create index ip_index_local3 on hw_partition_index_ip (logdate) local +( + partition sip1_index_local, + partition sip2_index_local, + partition sip3_index_local +); +--succeed + +create index ip_index_local4 on hw_partition_index_ip (logdate) local +( + partition sip1_index_local tablespace PG_DEFAULT, + partition sip2_index_local tablespace PG_DEFAULT, + partition sip3_index_local tablespace PG_DEFAULT +); +--succeed + +create index ip_index_local6 on hw_partition_index_ip (logdate) local +( + partition sip1_index_local, + partition sip2_index_local tablespace PG_DEFAULT, + partition sip3_index_local tablespace PG_DEFAULT +); +--succeed + +create unique index ip_index_local7 on hw_partition_index_ip (logdate) local +( + partition sip1_index_local tablespace PG_DEFAULT, + partition sip2_index_local tablespace PG_DEFAULT, + partition sip3_index_local tablespace PG_DEFAULT +); +--succeed + +create unique index on hw_partition_index_ip (logdate) local +( + partition sip1_index_local tablespace PG_DEFAULT, + partition sip2_index_local tablespace PG_DEFAULT, + partition sip3_index_local tablespace PG_DEFAULT +); +-- fail same partition name +create unique index on hw_partition_index_ip (logdate) local +( + partition sip1_index_local tablespace PG_DEFAULT, + partition sip2_index_local tablespace PG_DEFAULT, + partition sip2_index_local tablespace PG_DEFAULT +); + +-- +---- expression, only test sample expression for inter1, more info see hw_partition_index.sql +-- +create index on hw_partition_index_ip ((c1+c2)) local +( + partition sip1_index_local tablespace PG_DEFAULT, + partition sip2_index_local tablespace PG_DEFAULT, + partition sip3_index_local tablespace PG_DEFAULT +); +--succeed + +create index on hw_partition_index_ip ((c1-c2)) local +( + partition sip1_index_local tablespace PG_DEFAULT, + partition sip2_index_local tablespace PG_DEFAULT, + partition sip3_index_local tablespace PG_DEFAULT +); +--succeed + +--not support CONCURRENTLY +create unique index CONCURRENTLY on hw_partition_index_ip (logdate) local +( + partition sip1_index_local tablespace PG_DEFAULT, + partition sip2_index_local tablespace PG_DEFAULT, + partition sip3_index_local tablespace PG_DEFAULT +); + +-- Not enough index partition defined +create unique index on hw_partition_index_ip (logdate) local +( + partition sip1_index_local tablespace PG_DEFAULT, + partition sip2_index_local tablespace PG_DEFAULT +); + +-- number of partitions of LOCAL index must equal that of the underlying table +create unique index on hw_partition_index_ip (logdate) local +( + partition sip1_index_local tablespace PG_DEFAULT, + partition sip2_index_local tablespace PG_DEFAULT, + partition sip3_index_local tablespace PG_DEFAULT, + partition sip4_index_local tablespace PG_DEFAULT +); + +create unique index on hw_partition_index_ip (logdate); +--fail wrong syntax + +drop table hw_partition_index_ip; + +--unique index , index para must contain partition key +create table hw_partition_index_ip +( + c1 int, + c2 int, + logdate date not null +) +partition by range (logdate) +INTERVAL ('1 month') +( + PARTITION hw_partition_index_ip_p0 VALUES LESS THAN ('2020-03-01'), + PARTITION hw_partition_index_ip_p1 VALUES LESS THAN ('2020-04-01'), + PARTITION hw_partition_index_ip_p2 VALUES LESS THAN ('2020-05-01') +); +-- succeed +create unique index ip_index_local on hw_partition_index_ip (c1,logdate) local +( + partition sip1_index_local tablespace PG_DEFAULT, + partition sip2_index_local tablespace PG_DEFAULT, + partition sip3_index_local tablespace PG_DEFAULT +); +-- fail without logdate +create unique index ip_index_local2 on hw_partition_index_ip (c1) local +( + partition sip1_index_local tablespace PG_DEFAULT , + partition sip2_index_local tablespace PG_DEFAULT, + partition sip3_index_local tablespace PG_DEFAULT +); +create unique index ip_index_local3 on hw_partition_index_ip (c2, c1) local +( + partition sip1_index_local tablespace PG_DEFAULT, + partition sip2_index_local tablespace PG_DEFAULT, + partition sip3_index_local tablespace PG_DEFAULT +); + +--insert into table +insert into hw_partition_index_ip values(7,2,'2020-03-01'); +insert into hw_partition_index_ip values(3,1,'2020-04-01'); +insert into hw_partition_index_ip values(5,3,'2020-05-01'); +insert into hw_partition_index_ip values(7,5,'2020-06-01'); +insert into hw_partition_index_ip values(1,4,'2020-07-01'); + +--succeed +select * from hw_partition_index_ip order by 1, 2; + +--to select all index object +select part.relname, part.parttype, part.rangenum, + part.intervalnum, + part.partstrategy, + part.relallvisible, + part.reltoastrelid, + part.partkey, + part.interval, + part.boundaries + from pg_class class , pg_partition part , pg_index ind where class.relname = 'hw_partition_index_ip' and ind.indrelid = class.oid and part.parentid = ind.indexrelid order by 1, 2, 3, 4, 5, 6, 7, 8, 9, 10; + +drop index ip_index_local; + +drop table if exists hw_partition_index_ip; + +select count(*) from pg_class class , pg_partition part , pg_index ind where class.relname = 'hw_partition_index_ip' and ind.indrelid = class.oid and part.parentid = ind.indexrelid; + +-- +---- test input for unique index +-- +create table interval_partition_table_001 +( + c1 int, + logdate date not null +) +partition by range (logdate) +INTERVAL ('1 month') +( + PARTITION interval_partition_table_001_p0 VALUES LESS THAN ('2020-03-01'), + PARTITION interval_partition_table_001_p1 VALUES LESS THAN ('2020-04-01'), + PARTITION interval_partition_table_001_p2 VALUES LESS THAN ('2020-05-01') +); + +create unique index index_interval_partition_table_001 on interval_partition_table_001(logdate) local; +--fail: unique index +insert into interval_partition_table_001 values(10, '2020-06-01'); +insert into interval_partition_table_001 values(10, '2020-06-01'); +analyze interval_partition_table_001; +drop table interval_partition_table_001; + +-- +---- test with primary key +-- +create table interval_partition_table_002( + c1 int, + c2 int, + logdate date not null, + CONSTRAINT interval_partition_table_CONSTRAINT PRIMARY KEY(c2,logdate) +) +partition by range (logdate) +INTERVAL ('1 month') +( + PARTITION interval_partition_table_002_p0 VALUES LESS THAN ('2020-03-01'), + PARTITION interval_partition_table_002_p1 VALUES LESS THAN ('2020-04-01'), + PARTITION interval_partition_table_002_p2 VALUES LESS THAN ('2020-05-01') +); + +insert into interval_partition_table_002 values(10, 10, '2020-06-01'); +insert into interval_partition_table_002 values(10, 10, '2020-06-01'); +analyze interval_partition_table_002; +drop table interval_partition_table_002; + +-- +---- test with hash index, not support hash index yet; +-- +create table interval_partition_table_003( + c1 int, + c2 int, + logdate date not null, + PRIMARY KEY(c2,logdate) +) +partition by range (logdate) +INTERVAL ('1 month') +( + PARTITION interval_partition_table_003_p0 VALUES LESS THAN ('2020-03-01'), + PARTITION interval_partition_table_003_p1 VALUES LESS THAN ('2020-04-01'), + PARTITION interval_partition_table_003_p2 VALUES LESS THAN ('2020-05-01') +); + +create index interval_partition_table_003_1 ON interval_partition_table_003 USING HASH (logdate) LOCAL; +create index interval_partition_table_003_2 ON interval_partition_table_003 USING HASH (c2) LOCAL; +create index interval_partition_table_003_3 ON interval_partition_table_003 USING HASH (c1) LOCAL; + +select relname from pg_partition where INDEXTBLID=(select RELFILENODE from pg_partition where relname='interval_partition_table_003_1') order by 1; +select relname from pg_partition where INDEXTBLID=(select RELFILENODE from pg_partition where relname='interval_partition_table_003_2') order by 1; +select relname from pg_partition where INDEXTBLID=(select RELFILENODE from pg_partition where relname='interval_partition_table_003_3') order by 1; + +insert into interval_partition_table_003 values(1,2,'2020-03-01'); +insert into interval_partition_table_003 values(1,2,'2020-04-01'); +insert into interval_partition_table_003 values(1,2,'2020-05-01'); +insert into interval_partition_table_003 values(1,2,'2020-06-01'); +insert into interval_partition_table_003 values(1,2,'2020-07-01'); + +alter table interval_partition_table_003 drop column C2; +insert into interval_partition_table_003 values(1,2,'2020-07-01'); +insert into interval_partition_table_003 values(1,'2020-07-01'); + +select relname from pg_partition where INDEXTBLID=(select RELFILENODE from pg_partition where relname='interval_partition_table_003_1') order by 1; +select relname from pg_partition where INDEXTBLID=(select RELFILENODE from pg_partition where relname='interval_partition_table_003_2') order by 1; +select relname from pg_partition where INDEXTBLID=(select RELFILENODE from pg_partition where relname='interval_partition_table_003_3') order by 1; + +select relname, parttype, partstrategy, boundaries from pg_partition + where parentid = (select oid from pg_class where relname = 'interval_partition_table_003') + order by relname; + +analyze interval_partition_table_003; +drop table interval_partition_table_003; + +-- +---- test partition BTREE index +-- +create table interval_partition_table_004( + c1 int, + c2 int, + logdate date not null, + PRIMARY KEY(c2,logdate) +) +partition by range (logdate) +INTERVAL ('1 month') +( + PARTITION interval_partition_table_004_p0 VALUES LESS THAN ('2020-03-01'), + PARTITION interval_partition_table_004_p1 VALUES LESS THAN ('2020-04-01'), + PARTITION interval_partition_table_004_p2 VALUES LESS THAN ('2020-05-01') +); + +-- expression index +CREATE INDEX interval_partition_table_004_index_01 on interval_partition_table_004 using btree(c2) local; +CREATE INDEX interval_partition_table_004_index_02 on interval_partition_table_004 using btree(logdate) local; +CREATE INDEX interval_partition_table_004_index_03 on interval_partition_table_004 using btree(c1) local; + +insert into interval_partition_table_004 values(7,2,'2020-03-01'); +insert into interval_partition_table_004 values(3,1,'2020-04-01'); +insert into interval_partition_table_004 values(5,3,'2020-05-01'); +insert into interval_partition_table_004 values(7,5,'2020-06-01'); +insert into interval_partition_table_004 values(1,4,'2020-07-01'); +SELECT * FROM interval_partition_table_004 ORDER BY logdate; +SELECT * FROM interval_partition_table_004 ORDER BY 1; +SELECT * FROM interval_partition_table_004 ORDER BY 2; +DROP TABLE interval_partition_table_004; + +-- test interval table with toast table and index +CREATE TABLE interval_sales +(prod_id NUMBER(6), +cust_id NUMBER, +time_id DATE, +channel_id CHAR(1), +promo_id NUMBER(6), +quantity_sold NUMBER(3), +amount_sold NUMBER(10,2) +) +PARTITION BY RANGE (time_id) +INTERVAL('1 MONTH') +( PARTITION p0 VALUES LESS THAN (TO_DATE('1-1-2008', 'DD-MM-YYYY')), + PARTITION p1 VALUES LESS THAN (TO_DATE('6-5-2008', 'DD-MM-YYYY')) +); + +select relname, parentid, reltoastrelid, boundaries from pg_partition; + +insert into interval_sales values (generate_series(1,10), generate_series(1,10), generate_series(TO_DATE('2020-01-01', 'YYYY-MM-DD'),TO_DATE('2020-07-01', 'YYYY-MM-DD'),'1 day'), 1, 1, 1, 1); + +select relname, parentid, reltoastrelid, boundaries from pg_partition; + +drop table interval_sales; + +-- +---- test exchange table whit index +-- diff --git a/src/test/regress/sql/hw_partition_interval_movement.sql b/src/test/regress/sql/hw_partition_interval_movement.sql new file mode 100644 index 0000000000..471fdd3d5e --- /dev/null +++ b/src/test/regress/sql/hw_partition_interval_movement.sql @@ -0,0 +1,64 @@ +-- +---- test row movement +-- +drop table if exists hw_partition_interval_movement; +create table hw_partition_interval_movement +( + c1 int, + c2 int, + C3 date not null +) +partition by range (C3) +INTERVAL ('1 month') +( + PARTITION hw_partition_interval_movement_p0 VALUES LESS THAN ('2020-03-01'), + PARTITION hw_partition_interval_movement_p1 VALUES LESS THAN ('2020-04-01'), + PARTITION hw_partition_interval_movement_p2 VALUES LESS THAN ('2020-05-01') +) DISABLE ROW MOVEMENT; + +create index hw_partition_interval_movement_ind1 on hw_partition_interval_movement(c1) local; +create index hw_partition_interval_movement_ind2 on hw_partition_interval_movement(c2) local; +create index hw_partition_interval_movement_ind3 on hw_partition_interval_movement(c3) local; + +--insert into table +insert into hw_partition_interval_movement values(7,2,'2020-02-01'); +insert into hw_partition_interval_movement values(3,1,'2020-03-01'); +insert into hw_partition_interval_movement values(5,3,'2020-04-01'); +insert into hw_partition_interval_movement values(7,5,'2020-05-01'); +insert into hw_partition_interval_movement values(1,4,'2020-06-01'); + +select relname, parttype, partstrategy, boundaries from pg_partition + where parentid = (select oid from pg_class where relname = 'hw_partition_interval_movement') + order by 1; + +-- fail: update record belongs to a range partition which will be move to other range partition +update hw_partition_interval_movement set C3 = '2020-04-22' where C3 = '2020-03-01'; +-- fail: update record belongs to a range partition which will be move to an existed interval partition +update hw_partition_interval_movement set C3 = '2020-05-22' where C3 = '2020-03-01'; +-- fail: update record belongs to a range partition which will be move to a not existed interval partition +update hw_partition_interval_movement set C3 = '2020-07-22' where C3 = '2020-03-01'; +-- fail: update record belongs to a interval partition which will be move to a range partition +update hw_partition_interval_movement set C3 = '2020-03-22' where C3 = '2020-05-01'; +-- fail: update record belongs to a interval partition which will be move to a not existed interval partition +update hw_partition_interval_movement set C3 = '2020-07-22' where C3 = '2020-05-01'; + +-- enable row movement +alter table hw_partition_interval_movement ENABLE ROW MOVEMENT; + +-- succeed: update record belongs to a range partition which will be move to other range partition +update hw_partition_interval_movement set C3 = '2020-04-22' where C3 = '2020-03-01'; +-- succeed: update record belongs to a range partition which will be move to an existed interval partition +update hw_partition_interval_movement set C3 = '2020-05-22' where C3 = '2020-04-22'; +-- succeed: update record belongs to a range partition which will be move to a not existed interval partition +update hw_partition_interval_movement set C3 = '2020-07-22' where C3 = '2020-04-01'; +-- succeed: update record belongs to a interval partition which will be move to a range partition +update hw_partition_interval_movement set C3 = '2020-03-22' where C3 = '2020-05-01'; +-- succeed: update record belongs to a interval partition which will be move to a not existed interval partition +update hw_partition_interval_movement set C3 = '2020-08-22' where C3 = '2020-06-01'; + +select * from hw_partition_interval_movement; +-- add two new interval ranges +select relname, parttype, partstrategy, boundaries from pg_partition + where parentid = (select oid from pg_class where relname = 'hw_partition_interval_movement') + order by 1; +drop table hw_partition_interval_movement; diff --git a/src/test/regress/sql/hw_partition_interval_parallel_end.sql b/src/test/regress/sql/hw_partition_interval_parallel_end.sql new file mode 100644 index 0000000000..210b26d499 --- /dev/null +++ b/src/test/regress/sql/hw_partition_interval_parallel_end.sql @@ -0,0 +1,7 @@ +-- check results and clean +select count(*) from partition_interval_parallel; +select relname, parttype, partstrategy, boundaries, indisusable from pg_partition + where parentid = (select oid from pg_class where relname = 'partition_interval_parallel') + order by 1; +--cleanup +DROP TABLE partition_interval_parallel; diff --git a/src/test/regress/sql/hw_partition_interval_parallel_insert.sql b/src/test/regress/sql/hw_partition_interval_parallel_insert.sql new file mode 100644 index 0000000000..b8fcd3fa7c --- /dev/null +++ b/src/test/regress/sql/hw_partition_interval_parallel_insert.sql @@ -0,0 +1,23 @@ +--insert data +create or replace function insert_mm(dat text) returns void as $$ +declare + times integer :=1; +begin + loop + insert into partition_interval_parallel values(1, 1, dat); + times = times + 1; + if times > 500 then + exit; + end if; + end loop; +end; +$$ language plpgsql; + + +select insert_mm('2020-05-1'); +select insert_mm('2020-06-1'); +select insert_mm('2020-07-1'); +select insert_mm('2020-08-1'); +select insert_mm('2020-09-1'); +select insert_mm('2020-10-1'); +select insert_mm('2020-11-1'); \ No newline at end of file diff --git a/src/test/regress/sql/hw_partition_interval_parallel_insert_01.sql b/src/test/regress/sql/hw_partition_interval_parallel_insert_01.sql new file mode 100644 index 0000000000..4a36d7f5e4 --- /dev/null +++ b/src/test/regress/sql/hw_partition_interval_parallel_insert_01.sql @@ -0,0 +1,23 @@ +--insert data +create or replace function insert_mm_01(dat text) returns void as $$ +declare + times integer :=1; +begin + loop + insert into partition_interval_parallel values(1, 1, dat); + times = times + 1; + if times > 500 then + exit; + end if; + end loop; +end; +$$ language plpgsql; + + +select insert_mm_01('2020-05-1'); +select insert_mm_01('2020-06-1'); +select insert_mm_01('2020-07-1'); +select insert_mm_01('2020-08-1'); +select insert_mm_01('2020-09-1'); +select insert_mm_01('2020-10-1'); +select insert_mm_01('2020-11-1'); diff --git a/src/test/regress/sql/hw_partition_interval_parallel_insert_02.sql b/src/test/regress/sql/hw_partition_interval_parallel_insert_02.sql new file mode 100644 index 0000000000..019f8caf77 --- /dev/null +++ b/src/test/regress/sql/hw_partition_interval_parallel_insert_02.sql @@ -0,0 +1,23 @@ +--insert data +create or replace function insert_mm_02(dat text) returns void as $$ +declare + times integer :=1; +begin + loop + insert into partition_interval_parallel values(1, 1, dat); + times = times + 1; + if times > 500 then + exit; + end if; + end loop; +end; +$$ language plpgsql; + + +select insert_mm_02('2020-05-1'); +select insert_mm_02('2020-06-1'); +select insert_mm_02('2020-07-1'); +select insert_mm_02('2020-08-1'); +select insert_mm_02('2020-09-1'); +select insert_mm_02('2020-10-1'); +select insert_mm_02('2020-11-1'); diff --git a/src/test/regress/sql/hw_partition_interval_parallel_prepare.sql b/src/test/regress/sql/hw_partition_interval_parallel_prepare.sql new file mode 100644 index 0000000000..696fc778db --- /dev/null +++ b/src/test/regress/sql/hw_partition_interval_parallel_prepare.sql @@ -0,0 +1,20 @@ +-- prepare the parrallel modifed table; +DROP TABLE IF EXISTS partition_interval_parallel; +create table partition_interval_parallel +( + c1 int, + c2 int, + c3 date not null +) +partition by range (c3) +INTERVAL ('1 month') +( + PARTITION partition_interval_parallel_p1 VALUES LESS THAN ('2020-05-01'), + PARTITION partition_interval_parallel_p2 VALUES LESS THAN ('2020-06-01') +); +CREATE INDEX idx1_partition_interval_parallel on partition_interval_parallel(c3) local ; + + + + + diff --git a/src/test/regress/sql/hw_partition_interval_reindex.sql b/src/test/regress/sql/hw_partition_interval_reindex.sql new file mode 100644 index 0000000000..9298de3a78 --- /dev/null +++ b/src/test/regress/sql/hw_partition_interval_reindex.sql @@ -0,0 +1,65 @@ +--01-------------------------------------------------------------------- +--prepare table , index + +drop table if exists partition_reindex_table3; +create table partition_reindex_table3 +( + c1 int, + c2 int, + C3 date not null +) +partition by range (C3) +INTERVAL ('1 month') +( + PARTITION partition_reindex_table3_p0 VALUES LESS THAN ('2020-02-01'), + PARTITION partition_reindex_table3_p1 VALUES LESS THAN ('2020-05-01'), + PARTITION partition_reindex_table3_p2 VALUES LESS THAN ('2020-06-01') +) +enable row movement; + +create index partition_reindex_table3_ind1 on partition_reindex_table3(c1) local; +create index partition_reindex_table3_ind2 on partition_reindex_table3(c2) local; +create index partition_reindex_table3_ind3 on partition_reindex_table3(c3) local; + +--02-------------------------------------------------------------------- +--reindex index, cross test with insert +insert into partition_reindex_table3 values (generate_series(1,10), generate_series(1,10), generate_series(TO_DATE('2020-01-01', 'YYYY-MM-DD'),TO_DATE('2020-07-01', 'YYYY-MM-DD'),'1, day')); +select count(*) from partition_reindex_table3; +select relname, parttype, partstrategy, boundaries from pg_partition + where parentid = (select oid from pg_class where relname = 'partition_reindex_table3') + order by 1; +truncate table partition_reindex_table3; +insert into partition_reindex_table3 values (generate_series(1,10), generate_series(1,10), generate_series(TO_DATE('2020-01-01', 'YYYY-MM-DD'),TO_DATE('2020-07-01', 'YYYY-MM-DD'),'1, day')); +select count(*) from partition_reindex_table3; +select relname, parttype, partstrategy, boundaries from pg_partition + where parentid = (select oid from pg_class where relname = 'partition_reindex_table3') + order by 1; + +analyze partition_reindex_table3; +select c.relname,c.relpages > 0 as relpagesgtzero, c.reltuples > 0 as reltuplesgtzero,i.indisunique, i.indisvalid, i.indcheckxmin, i.indisready from pg_index i, pg_class c where c.relname = 'partition_reindex_table3_ind1' and c.oid = i.indexrelid; +explain (costs off, nodes off) select * from partition_reindex_table3 where c3 = TO_DATE('2020-04-21', 'YYYY-MM-DD') and c2 = 8; +select * from partition_reindex_table3 where c3 = TO_DATE('2020-04-21', 'YYYY-MM-DD') and c2 = 8; +reindex index partition_reindex_table3_ind1; +select c.relname,c.relpages > 0 as relpagesgtzero, c.reltuples > 0 as reltuplesgtzero,i.indisunique, i.indisvalid, i.indcheckxmin, i.indisready from pg_index i, pg_class c where c.relname = 'partition_reindex_table3_ind1' and c.oid = i.indexrelid; +explain (costs off, nodes off) select * from partition_reindex_table3 where c3 = TO_DATE('2020-04-21', 'YYYY-MM-DD') and c2 = 8; +--the plan before reindex and after reindex should be same +select * from partition_reindex_table3 where c3 = TO_DATE('2020-04-21', 'YYYY-MM-DD') and c2 = 8; + +--03-------------------------------------------------------------------- +--reindex table cross test with truncate + +truncate table partition_reindex_table3; + +insert into partition_reindex_table3 values (generate_series(1,10), generate_series(1,10), generate_series(TO_DATE('2020-01-01', 'YYYY-MM-DD'),TO_DATE('2020-07-01', 'YYYY-MM-DD'),'1, day')); +analyze partition_reindex_table3; +select c.relname,c.relpages > 0 as relpagesgtzero, c.reltuples > 0 as reltuplesgtzero,i.indisunique, i.indisvalid, i.indcheckxmin, i.indisready from pg_index i, pg_class c where c.relname = 'partition_reindex_table3_ind1' and c.oid = i.indexrelid; +explain (costs off, nodes off) select * from partition_reindex_table3 where c3 = TO_DATE('2020-04-21', 'YYYY-MM-DD') and c2 = 8; +select * from partition_reindex_table3 where c3 = TO_DATE('2020-04-21', 'YYYY-MM-DD') and c2 = 8; +reindex index partition_reindex_table3_ind1; +select c.relname,c.relpages > 0 as relpagesgtzero, c.reltuples > 0 as reltuplesgtzero,i.indisunique, i.indisvalid, i.indcheckxmin, i.indisready from pg_index i, pg_class c where c.relname = 'partition_reindex_table3_ind1' and c.oid = i.indexrelid; +explain (costs off, nodes off) select * from partition_reindex_table3 where c3 = TO_DATE('2020-04-21', 'YYYY-MM-DD') and c2 = 8; +--the plan before reindex and after reindex should be same +select * from partition_reindex_table3 where c3 = TO_DATE('2020-04-21', 'YYYY-MM-DD') and c2 = 8; + +--clean +drop table partition_reindex_table3; diff --git a/src/test/regress/sql/hw_partition_interval_select.sql b/src/test/regress/sql/hw_partition_interval_select.sql new file mode 100644 index 0000000000..5e05367023 --- /dev/null +++ b/src/test/regress/sql/hw_partition_interval_select.sql @@ -0,0 +1,54 @@ +CREATE TABLE interval_tab1 ( + city_id int not null, + logdate date not null, + peaktemp int, + unitsales int +) +PARTITION BY RANGE (logdate) +INTERVAL ('1 day') +( + PARTITION p1 VALUES LESS THAN (('2020-03-01')) +); + +insert into interval_tab1 values(1,'2020-4-7 2:0:0', 1, 1); + +insert into interval_tab1 values(1,'2020-4-8 2:0:0', 1, 1); + +select relname, boundaries from pg_partition; + +select * from interval_tab1 where logdate < '2020-4-7 0:0:0'; + +explain (costs off, verbose on, nodes off) select * from interval_tab1 where logdate < '2020-4-7 0:0:0'; + +select * from interval_tab1 where logdate > '2020-4-6'; + +explain (costs off, verbose on, nodes off) select * from interval_tab1 where logdate > '2020-4-6'; + +select * from interval_tab1 where logdate = '2020-4-7 2:0:0'; + +insert into interval_tab1 values(1,'2020-4-7 0:0:0', 1, 1); + +select * from interval_tab1 where logdate = '2020-4-7 0:0:0'; + +select * from interval_tab1 where logdate != '2020-4-7 0:0:0'; + +select * from interval_tab1 where logdate >= '2020-4-7 0:0:0'; + +insert into interval_tab1 values(1,'2020-4-5 2:0:0', 1, 1); + +select relname, boundaries from pg_partition; + +insert into interval_tab1 values(1,'2020-4-9 0:0:0', 1, 1); + + +select * from interval_tab1 where logdate >= '2020-4-7 0:0:0' and logdate < '2020-4-9 0:0:0'; + +select * from interval_tab1 where logdate > '2020-4-7 0:0:0' and logdate <= '2020-4-9 0:0:0'; + +select * from interval_tab1 where logdate >= '2020-4-7 0:0:0' and logdate <= '2020-4-9 0:0:0'; + +select * from interval_tab1 where logdate > '2020-4-6 0:0:0' and logdate <= '2020-4-9 0:0:0'; + +explain (costs off, verbose on, nodes off) select * from interval_tab1 where logdate >= '2020-4-10 0:0:0'; + +drop table interval_tab1; diff --git a/src/test/regress/sql/hw_partition_interval_unusable_index.sql b/src/test/regress/sql/hw_partition_interval_unusable_index.sql new file mode 100644 index 0000000000..49a7b236a7 --- /dev/null +++ b/src/test/regress/sql/hw_partition_interval_unusable_index.sql @@ -0,0 +1,256 @@ + +--create table +DROP TABLE IF EXISTS partition_unsable_index_1; +create table partition_unsable_index_1 +( + c1 int, + c2 int, + c3 date not null +) +partition by range (c3) +INTERVAL ('1 month') +( + PARTITION partition_unsable_index_1_p0 VALUES LESS THAN ('2020-03-01'), + PARTITION partition_unsable_index_1_p1 VALUES LESS THAN ('2020-04-01'), + PARTITION partition_unsable_index_1_p2 VALUES LESS THAN ('2020-05-01') +); + +-- create 3 indexes, and specify it's partition name +CREATE INDEX idx1_partition_unsable_index_1 on partition_unsable_index_1(c3) local +( + partition idx1_partition_unsable_index_1_p1, + partition idx1_partition_unsable_index_1_p2, + partition idx1_partition_unsable_index_1_p3 +); +CREATE INDEX idx2_partition_unsable_index_1 on partition_unsable_index_1(c2, c3) local +( + partition idx2_partition_unsable_index_1_p1, + partition idx2_partition_unsable_index_1_p2, + partition idx2_partition_unsable_index_1_p3 +); +CREATE INDEX idx3_partition_unsable_index_1 on partition_unsable_index_1(c1, c2, c3) local +( + partition idx3_partition_unsable_index_1_p1, + partition idx3_partition_unsable_index_1_p2, + partition idx3_partition_unsable_index_1_p3 +); + +--insert data +insert into partition_unsable_index_1 values(7,2,'2020-03-01'); +insert into partition_unsable_index_1 values(3,1,'2020-04-01'); +insert into partition_unsable_index_1 values(5,3,'2020-05-01'); +insert into partition_unsable_index_1 values(7,5,'2020-06-01'); +insert into partition_unsable_index_1 values(1,4,'2020-07-01'); + +-- query all index partitions +select relname, parttype, partstrategy, indisusable from pg_partition + where parentid = (select oid from pg_class where relname = 'idx1_partition_unsable_index_1') + order by relname; + +-- 1. alter index, modify one of it's partition to unusable state +ALTER INDEX idx1_partition_unsable_index_1 MODIFY PARTITION idx1_partition_unsable_index_1_p1 UNUSABLE; + +-- check indunusable info +select relname, parttype, partstrategy, boundaries, indisusable from pg_partition + where parentid = (select oid from pg_class where relname = 'idx1_partition_unsable_index_1') + order by 1; + +-- rebuild index partition +ALTER INDEX idx1_partition_unsable_index_1 REBUILD PARTITION idx1_partition_unsable_index_1_p1; + +-- check indunusable info +select relname, parttype, partstrategy, indisusable from pg_partition + where parentid = (select oid from pg_class where relname = 'idx1_partition_unsable_index_1') + order by 1; + +--2.ALTER INDEX unusable +select relname, parttype, partstrategy, indisusable from pg_partition + where parentid = (select oid from pg_class where relname = 'idx1_partition_unsable_index_1') + order by 1; + +ALTER INDEX idx1_partition_unsable_index_1 UNUSABLE; + +select relname, parttype, partstrategy, indisusable from pg_partition + where parentid = (select oid from pg_class where relname = 'idx1_partition_unsable_index_1') + order by 1; + +ALTER INDEX idx1_partition_unsable_index_1 REBUILD; + +select relname, parttype, partstrategy, indisusable from pg_partition + where parentid = (select oid from pg_class where relname = 'idx1_partition_unsable_index_1') + order by 1; + +--test for reindex partition +ALTER INDEX idx1_partition_unsable_index_1 UNUSABLE; +select relname, parttype, partstrategy, indisusable from pg_partition + where parentid = (select oid from pg_class where relname = 'idx1_partition_unsable_index_1') + order by 1; + +REINDEX INDEX idx1_partition_unsable_index_1 PARTITION idx1_partition_unsable_index_1_p1; +select relname, parttype, partstrategy, indisusable from pg_partition + where parentid = (select oid from pg_class where relname = 'idx1_partition_unsable_index_1') + order by 1; + +ALTER INDEX idx1_partition_unsable_index_1 REBUILD; +select relname, parttype, partstrategy, indisusable from pg_partition + where parentid = (select oid from pg_class where relname = 'idx1_partition_unsable_index_1') + order by 1; + +-- 3. alter table, modify one of it's partition's all indexes to unusable state +ALTER TABLE partition_unsable_index_1 MODIFY PARTITION partition_unsable_index_1_p0 UNUSABLE LOCAL INDEXES; + +-- check indunusable info +select relname, indisusable from pg_partition + where relname = 'idx1_partition_unsable_index_1_p1' + or relname = 'idx2_partition_unsable_index_1_p1' + or relname = 'idx3_partition_unsable_index_1_p1' + or relname = 'p1_partition_unsable_index_1' + order by 1; + +-- rebuild +ALTER TABLE partition_unsable_index_1 MODIFY PARTITION partition_unsable_index_1_p0 REBUILD UNUSABLE LOCAL INDEXES; + +-- check again +select relname, indisusable from pg_partition + where relname = 'idx1_partition_unsable_index_1_p1' + or relname = 'idx2_partition_unsable_index_1_p1' + or relname = 'idx3_partition_unsable_index_1_p1' + or relname = 'p1_partition_unsable_index_1' + order by 1; + +ALTER INDEX idx1_partition_unsable_index_1 MODIFY PARTITION idx1_partition_unsable_index_1_p1 UNUSABLE; +-- idx1_partition_unsable_index_1_p1 is unusable +select part.relname, part.indisusable + from pg_class class , pg_partition part , pg_index ind + where class.relname = 'partition_unsable_index_1' + and ind.indrelid = class.oid + and part.parentid = ind.indexrelid + order by 1; +-- can not cluster partition bacause of unusable local index +CLUSTER partition_unsable_index_1 PARTITION (partition_unsable_index_1_p0) USING idx1_partition_unsable_index_1; +CLUSTER partition_unsable_index_1 USING idx1_partition_unsable_index_1; + +-- indisclustered is false +select class.relname, ind.indisclustered + from pg_class class , pg_index ind + where class.relname = 'partition_unsable_index_1' + and ind.indrelid = class.oid + order by 2; + +-- cluster ok +ALTER INDEX idx1_partition_unsable_index_1 REBUILD; +CLUSTER partition_unsable_index_1 USING idx1_partition_unsable_index_1; + +-- idx1_partition_unsable_index_1_p1 is usable +select part.relname, part.indisusable + from pg_class class , pg_partition part , pg_index ind + where class.relname = 'partition_unsable_index_1' + and ind.indrelid = class.oid + and part.parentid = ind.indexrelid + order by 1; + +-- indisclustered is true +select class.relname, ind.indisclustered + from pg_class class , pg_index ind + where class.relname = 'partition_unsable_index_1' + and ind.indrelid = class.oid + order by 2; + +-- cluster other index +ALTER INDEX idx2_partition_unsable_index_1 MODIFY PARTITION idx2_partition_unsable_index_1_p1 UNUSABLE; +ALTER INDEX idx2_partition_unsable_index_1 REBUILD; +CLUSTER partition_unsable_index_1 USING idx2_partition_unsable_index_1; +select class.relname, ind.indisclustered + from pg_class class , pg_index ind + where class.relname = 'partition_unsable_index_1' + and ind.indrelid = class.oid + order by 2; + +-- cluster a partition +ALTER INDEX idx1_partition_unsable_index_1 MODIFY PARTITION idx1_partition_unsable_index_1_p1 UNUSABLE; +ALTER INDEX idx1_partition_unsable_index_1 REBUILD PARTITION idx1_partition_unsable_index_1_p1; +CLUSTER partition_unsable_index_1 PARTITION (partition_unsable_index_1_p0) USING idx1_partition_unsable_index_1; +CLUSTER partition_unsable_index_1 USING idx1_partition_unsable_index_1; +select class.relname, ind.indisclustered + from pg_class class , pg_index ind + where class.relname = 'partition_unsable_index_1' + and ind.indrelid = class.oid + order by 2; + +--5.2 merge (not support yet, keep the case hear for support in the future) +-- merge failed due to unusable index partition +ALTER INDEX idx1_partition_unsable_index_1 MODIFY PARTITION idx1_partition_unsable_index_1_p1 UNUSABLE; +ALTER TABLE partition_unsable_index_1 MERGE PARTITIONS partition_unsable_index_1_p0, p2_partition_unsable_index_3 + INTO PARTITION px_partition_unsable_index_3; +--rebuild unusable index partition +ALTER INDEX idx1_partition_unsable_index_1 REBUILD PARTITION idx1_partition_unsable_index_1_p1; + +--5.3 exchange +-- create plain table and index +CREATE TABLE table_unusable_index_exchange (c1 int, c2 int, c3 date not null); +CREATE INDEX idx1_table_unusable_index_exchange on table_unusable_index_exchange(c3); +CREATE INDEX idx2_table_unusable_index_exchange on table_unusable_index_exchange(c2, c3); +CREATE INDEX idx3_table_unusable_index_exchange on table_unusable_index_exchange(c1, c2, c3); + +--- unusable non-partitioned-index +ALTER INDEX idx1_table_unusable_index_exchange UNUSABLE; +ALTER TABLE partition_unsable_index_1 EXCHANGE PARTITION (partition_unsable_index_1_p0) + WITH TABLE table_unusable_index_exchange; +ALTER INDEX idx1_table_unusable_index_exchange REBUILD; + +-- unusable partitioned-index +ALTER INDEX idx1_partition_unsable_index_1 UNUSABLE; +ALTER TABLE partition_unsable_index_1 EXCHANGE PARTITION (partition_unsable_index_1_p0) + WITH TABLE table_unusable_index_exchange; +ALTER INDEX idx1_partition_unsable_index_1 REBUILD; + +-- modify one index partition unusable +-- exchange failed due to unusable index partition +ALTER INDEX idx1_partition_unsable_index_1 MODIFY PARTITION idx1_partition_unsable_index_1_p1 UNUSABLE; +ALTER TABLE partition_unsable_index_1 EXCHANGE PARTITION (partition_unsable_index_1_p0) + WITH TABLE table_unusable_index_exchange; +-- exchange ok +ALTER INDEX idx1_partition_unsable_index_1 REBUILD PARTITION idx1_partition_unsable_index_1_p1; +ALTER TABLE partition_unsable_index_1 EXCHANGE PARTITION (partition_unsable_index_1_p0) + WITH TABLE table_unusable_index_exchange; + +-- clean table_unusable_index_exchange +DROP TABLE table_unusable_index_exchange; +DROP TABLE partition_unsable_index_1; + +--6. index and unique index check +create table partition_unsable_index_1 +( + c1 int, + c2 int, + c3 date not null +) +partition by range (c3) +INTERVAL ('1 month') +( + PARTITION partition_unsable_index_1_p0 VALUES LESS THAN ('2020-03-01'), + PARTITION partition_unsable_index_1_p1 VALUES LESS THAN ('2020-04-01'), + PARTITION partition_unsable_index_1_p2 VALUES LESS THAN ('2020-05-01') +); + +-- create a unique index +CREATE UNIQUE INDEX idx_unique_partition_unsable_index_1 on partition_unsable_index_1(c2, c3) LOCAL +( + partition idx_unique_partition_unsable_index_1_p1, + partition idx_unique_partition_unsable_index_1_p2, + partition idx_unique_partition_unsable_index_1_p3 +); +--insert duplicated rows should report error +insert into partition_unsable_index_1 values(3,3,'2020-02-01'); +insert into partition_unsable_index_1 values(5,3,'2020-02-01'); -- fail +-- set local index unusable +ALTER INDEX idx_unique_partition_unsable_index_1 MODIFY PARTITION idx_unique_partition_unsable_index_1_p1 UNUSABLE; +-- bypass the unique index check +insert into partition_unsable_index_1 values(5,3,'2020-02-01'); -- success +--but report unique check error here +ALTER INDEX idx_unique_partition_unsable_index_1 REBUILD PARTITION idx_unique_partition_unsable_index_1_p1; +-- cleanup +DROP INDEX idx_unique_partition_unsable_index_1; +insert into partition_unsable_index_1 values(5,3,'2020-02-01'); -- success +--cleanup +DROP TABLE partition_unsable_index_1; \ No newline at end of file -- Gitee