diff --git a/src/common/backend/utils/misc/guc/guc_sql.cpp b/src/common/backend/utils/misc/guc/guc_sql.cpp index 1638943a3..3d25df15a 100755 --- a/src/common/backend/utils/misc/guc/guc_sql.cpp +++ b/src/common/backend/utils/misc/guc/guc_sql.cpp @@ -390,7 +390,8 @@ static const struct behavior_compat_entry behavior_compat_options[OPT_MAX] = { {"select_into_return_null", OPT_SELECT_INTO_RETURN_NULL}, {"accept_empty_str", OPT_ACCEPT_EMPTY_STR}, {"plpgsql_dependency", OPT_PLPGSQL_DEPENDENCY}, - {"proc_uncheck_default_param", OPT_PROC_UNCHECK_DEFAULT_PARAM} + {"proc_uncheck_default_param", OPT_PROC_UNCHECK_DEFAULT_PARAM}, + {"update_unusable_unique_index_on_iud", OPT_UPDATE_UNUSABLE_UNIQUE_INDEX_ON_IUD} }; // increase SQL_IGNORE_STRATEGY_NUM if we need more strategy diff --git a/src/gausskernel/runtime/executor/execUtils.cpp b/src/gausskernel/runtime/executor/execUtils.cpp index d47926ffc..3b0254c6e 100644 --- a/src/gausskernel/runtime/executor/execUtils.cpp +++ b/src/gausskernel/runtime/executor/execUtils.cpp @@ -1184,6 +1184,82 @@ Partition ExecOpenScanParitition(EState* estate, Relation parent, PartitionIdent return partitionOpen(parent, partoid, lockmode); } +void ExecOpenUnusedIndices(ResultRelInfo* resultRelInfo, bool speculative) +{ + Relation resultRelation = resultRelInfo->ri_RelationDesc; + List* indexoidlist = NIL; + ListCell* l = NULL; + int len, i; + RelationPtr relationDescs; + IndexInfo** indexInfoArray; + + /* fast path if no indexes */ + if (!RelationGetForm(resultRelation)->relhasindex) + return; + + /* + * Get cached list of index OIDs + */ + indexoidlist = RelationGetIndexList(resultRelation, true); + len = list_length(indexoidlist); + if (len == 0) { + return; + } + + /* + * allocate space for result arrays + */ + relationDescs = (RelationPtr)palloc(len * sizeof(Relation)); + indexInfoArray = (IndexInfo**)palloc(len * sizeof(IndexInfo*)); + + resultRelInfo->ri_UnusableIndexRelationDescs = relationDescs; + resultRelInfo->ri_UnusableIndexRelationInfo = indexInfoArray; + + /* + * For each index, open the index relation and save pg_index info. We + * acquire RowExclusiveLock, signifying we will update the index. + * + * Note: we do this even if the index is not IndexIsReady; it's not worth + * the trouble to optimize for the case where it isn't. + */ + i = 0; + foreach (l, indexoidlist) { + Oid indexOid = lfirst_oid(l); + Relation indexDesc; + IndexInfo* ii = NULL; + + indexDesc = index_open(indexOid, RowExclusiveLock); + + if (IndexIsUsable(indexDesc->rd_index) || !IndexIsUnique(indexDesc->rd_index)) { + index_close(indexDesc, RowExclusiveLock); + continue; + } + + /* extract index key information from the index's pg_index info */ + ii = BuildIndexInfo(indexDesc); + + /* + * If the indexes are to be used for speculative insertion, add extra + * information required by unique index entries. + */ + if (speculative) { + BuildSpeculativeIndexInfo(indexDesc, ii); + } + relationDescs[i] = indexDesc; + indexInfoArray[i] = ii; + i++; + } + // remember to set the number of unusable indexes + resultRelInfo->ri_NumUnusableIndices = i; + + if (resultRelInfo->ri_NumUnusableIndices == 0) { + ExecCloseUnsedIndices(resultRelInfo); + } + + list_free_ext(indexoidlist); +} + + /* ---------------------------------------------------------------- * ExecInsertIndexTuples support * ---------------------------------------------------------------- @@ -1209,6 +1285,10 @@ void ExecOpenIndices(ResultRelInfo* resultRelInfo, bool speculative) resultRelInfo->ri_NumIndices = 0; resultRelInfo->ri_ContainGPI = false; + + resultRelInfo->ri_NumUnusableIndices = 0; + resultRelInfo->ri_UnusableIndexRelationDescs = NULL; + resultRelInfo->ri_UnusableIndexRelationInfo = NULL; /* fast path if no indexes */ if (!RelationGetForm(resultRelation)->relhasindex) @@ -1275,9 +1355,38 @@ void ExecOpenIndices(ResultRelInfo* resultRelInfo, bool speculative) // remember to set the number of usable indexes resultRelInfo->ri_NumIndices = i; + if (UPDATE_UNUSABLE_UNIQUE_INDEX_ON_IUD) { + ExecOpenUnusedIndices(resultRelInfo, speculative); + } + list_free_ext(indexoidlist); } +void ExecCloseUnsedIndices(ResultRelInfo* resultRelInfo) +{ + int i; + int numIndices = resultRelInfo->ri_NumUnusableIndices; + RelationPtr indexDescs = resultRelInfo->ri_UnusableIndexRelationDescs; + for (i = 0; i < numIndices; i++) { + if (indexDescs[i] == NULL) + continue; /* shouldn't happen? */ + + /* Drop lock acquired by ExecOpenIndices */ + index_close(indexDescs[i], RowExclusiveLock); + } + pfree_ext(resultRelInfo->ri_UnusableIndexRelationDescs); + + if (resultRelInfo->ri_UnusableIndexRelationInfo) { + for (i = 0; i < numIndices; i++) { + pfree_ext(resultRelInfo->ri_UnusableIndexRelationInfo[i]); + } + pfree_ext(resultRelInfo->ri_UnusableIndexRelationInfo); + } + resultRelInfo->ri_UnusableIndexRelationDescs = NULL; + resultRelInfo->ri_UnusableIndexRelationInfo = NULL; +} + + /* ---------------------------------------------------------------- * ExecCloseIndices * @@ -1308,6 +1417,11 @@ void ExecCloseIndices(ResultRelInfo* resultRelInfo) } pfree_ext(resultRelInfo->ri_IndexRelationInfo); } + + if (UPDATE_UNUSABLE_UNIQUE_INDEX_ON_IUD && resultRelInfo->ri_NumUnusableIndices > 0) { + ExecCloseUnsedIndices(resultRelInfo); + } + } /* @@ -1873,9 +1987,12 @@ List* ExecInsertIndexTuples(TupleTableSlot* slot, ItemPointer tupleid, EState* e ResultRelInfo* resultRelInfo = NULL; int i; int numIndices; + int numUnusedIndices; RelationPtr relationDescs; + RelationPtr unusedRelationDescs; Relation heapRelation; IndexInfo** indexInfoArray; + IndexInfo** unusedindexInfoArray; ExprContext* econtext = NULL; Datum values[INDEX_MAX_KEYS]; bool isnull[INDEX_MAX_KEYS]; @@ -1883,6 +2000,7 @@ List* ExecInsertIndexTuples(TupleTableSlot* slot, ItemPointer tupleid, EState* e bool ispartitionedtable = false; bool containGPI; List* partitionIndexOidList = NIL; + int totalIndices; /* * Get information from the result relation info structure. @@ -1891,6 +2009,13 @@ List* ExecInsertIndexTuples(TupleTableSlot* slot, ItemPointer tupleid, EState* e numIndices = resultRelInfo->ri_NumIndices; relationDescs = resultRelInfo->ri_IndexRelationDescs; indexInfoArray = resultRelInfo->ri_IndexRelationInfo; + + numUnusedIndices = resultRelInfo->ri_NumUnusableIndices; + unusedRelationDescs = resultRelInfo->ri_UnusableIndexRelationDescs; + unusedindexInfoArray = resultRelInfo->ri_UnusableIndexRelationInfo; + + totalIndices = numIndices + numUnusedIndices; + heapRelation = resultRelInfo->ri_RelationDesc; containGPI = resultRelInfo->ri_ContainGPI; @@ -1936,8 +2061,8 @@ List* ExecInsertIndexTuples(TupleTableSlot* slot, ItemPointer tupleid, EState* e /* * for each index, form and insert the index tuple */ - for (i = 0; i < numIndices; i++) { - Relation indexRelation = relationDescs[i]; + for (i = 0; i < totalIndices; i++) { + Relation indexRelation = i < numIndices ? relationDescs[i] : unusedRelationDescs[i - numIndices]; IndexInfo* indexInfo = NULL; IndexUniqueCheck checkUnique; bool satisfiesConstraint = false; @@ -1950,7 +2075,7 @@ List* ExecInsertIndexTuples(TupleTableSlot* slot, ItemPointer tupleid, EState* e continue; } - indexInfo = indexInfoArray[i]; + indexInfo = i < numIndices ? indexInfoArray[i] : unusedindexInfoArray[i - numIndices]; /* If the index is marked as read-only, ignore it */ if (!indexInfo->ii_ReadyForInserts) { diff --git a/src/include/catalog/pg_index.h b/src/include/catalog/pg_index.h index bc80a5721..dd27cdfbf 100644 --- a/src/include/catalog/pg_index.h +++ b/src/include/catalog/pg_index.h @@ -111,6 +111,7 @@ typedef FormData_pg_index *Form_pg_index; * the less ugly representation used after 9.2. */ #define IndexIsUsable(indexForm) ((indexForm)->indisusable) +#define IndexIsUnique(indexForm) ((indexForm)->indisunique) #define IndexIsReady(indexForm) ((indexForm)->indisready) #define IndexIsValid(indexForm) (((indexForm)->indisvalid && (indexForm)->indisready) && ((indexForm)->indisusable)) #define IndexIsLive(indexForm) (((indexForm)->indisready || !(indexForm)->indisvalid) && ((indexForm)->indisusable)) diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h index b3691a242..ebb1489ec 100755 --- a/src/include/executor/executor.h +++ b/src/include/executor/executor.h @@ -643,6 +643,8 @@ static inline Datum autoinc2datum(ConstrAutoInc *cons_autoinc, int128 autoinc) extern Partition ExecOpenScanParitition( EState* estate, Relation parent, PartitionIdentifier* partID, LOCKMODE lockmode); +extern void ExecOpenUnusedIndices(ResultRelInfo* resultRelInfo, bool speculative); +extern void ExecCloseUnsedIndices(ResultRelInfo* resultRelInfo); extern void ExecOpenIndices(ResultRelInfo* resultRelInfo, bool speculative); extern void ExecCloseIndices(ResultRelInfo* resultRelInfo); extern List* ExecInsertIndexTuples( diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h index a4eebacef..87029db45 100644 --- a/src/include/miscadmin.h +++ b/src/include/miscadmin.h @@ -206,7 +206,8 @@ extern bool contain_backend_version(uint32 version_number); #define OPT_ACCEPT_EMPTY_STR 134217728 #define OPT_PLPGSQL_DEPENDENCY 268435456 #define OPT_PROC_UNCHECK_DEFAULT_PARAM 536870912 -#define OPT_MAX 30 +#define OPT_UPDATE_UNUSABLE_UNIQUE_INDEX_ON_IUD 1073741824 +#define OPT_MAX 31 #define PLPSQL_OPT_FOR_LOOP 1 #define PLPSQL_OPT_OUTPARAM 2 @@ -250,6 +251,7 @@ extern bool contain_backend_version(uint32 version_number); #define SELECT_INTO_RETURN_NULL (u_sess->utils_cxt.behavior_compat_flags & OPT_SELECT_INTO_RETURN_NULL) #define PLPGSQL_DEPENDENCY (u_sess->utils_cxt.behavior_compat_flags & OPT_PLPGSQL_DEPENDENCY) #define PROC_UNCHECK_DEFAULT_PARAM (u_sess->utils_cxt.behavior_compat_flags & OPT_PROC_UNCHECK_DEFAULT_PARAM) +#define UPDATE_UNUSABLE_UNIQUE_INDEX_ON_IUD (u_sess->utils_cxt.behavior_compat_flags & OPT_UPDATE_UNUSABLE_UNIQUE_INDEX_ON_IUD) /* define database compatibility Attribute */ typedef struct { diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index ed3906472..a70c4efad 100755 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -593,6 +593,11 @@ typedef struct ResultRelInfo { #ifdef USE_SPQ AttrNumber ri_actionAttno; /* is this an INSERT or DELETE ? */ #endif + + /* number of the unusable index*/ + int ri_NumUnusableIndices; + RelationPtr ri_UnusableIndexRelationDescs; + IndexInfo** ri_UnusableIndexRelationInfo; } ResultRelInfo; /* bloom filter controller */ diff --git a/src/test/regress/expected/gpi_set_index_unusable.out b/src/test/regress/expected/gpi_set_index_unusable.out index 421cb1a8a..87e13b171 100644 --- a/src/test/regress/expected/gpi_set_index_unusable.out +++ b/src/test/regress/expected/gpi_set_index_unusable.out @@ -509,4 +509,131 @@ select * from test_drop_llt where a=40; set enable_bitmapscan=on; set enable_seqscan=on; drop table if exists test_drop_llt; --- End. Clean up +--astore +CREATE TABLE web_returns_p_a +( + sk_date INTEGER, + cm_num INTEGER, + nv_num INTEGER, + cn_name INTEGER +) +with (STORAGE_TYPE=ASTORE) +PARTITION BY RANGE(sk_date) +( + PARTITION P1 VALUES LESS THAN(1), + PARTITION P2 VALUES LESS THAN(2), + PARTITION P3 VALUES LESS THAN(3), + PARTITION P4 VALUES LESS THAN(4), + PARTITION P5 VALUES LESS THAN(5), + PARTITION P6 VALUES LESS THAN(6), + PARTITION P7 VALUES LESS THAN(7), + PARTITION P8 VALUES LESS THAN(8), + PARTITION P9 VALUES LESS THAN(9), + PARTITION Pmax VALUES LESS THAN(MAXVALUE) +); +insert into web_returns_p_a values (1,1,1,1); +insert into web_returns_p_a values (2,2,2,2); +insert into web_returns_p_a values (3,3,3,3); +insert into web_returns_p_a values (4,4,4,4); +insert into web_returns_p_a values (5,5,5,5); +insert into web_returns_p_a values (6,6,6,6); +insert into web_returns_p_a values (7,7,7,7); +insert into web_returns_p_a values (8,8,8,8); +insert into web_returns_p_a values (9,9,9,9); +create index idx_cm_num_a on web_returns_p_a(cm_num) global; +create index idx_nv_num_a on web_returns_p_a(nv_num) local; +create unique index idx_uq_a on web_returns_p_a(sk_date) global; +set behavior_compat_options = 'update_unusable_unique_index_on_iud'; +alter table web_returns_p_a drop partition p2; +insert into web_returns_p_a values (1,1,1,1); +insert into web_returns_p_a values (1,1,1,1); +ERROR: duplicate key value violates unique constraint "idx_uq_a" +DETAIL: Key (sk_date)=(1) already exists. +update web_returns_p_a set sk_date = 1 where true; +ERROR: duplicate key value violates unique constraint "idx_uq_a" +DETAIL: Key (sk_date)=(1) already exists. +set enable_opfusion = off; +insert into web_returns_p_a values (1,1,1,1); +ERROR: duplicate key value violates unique constraint "idx_uq_a" +DETAIL: Key (sk_date)=(1) already exists. +insert into web_returns_p_a values (1,1,1,1); +ERROR: duplicate key value violates unique constraint "idx_uq_a" +DETAIL: Key (sk_date)=(1) already exists. +update web_returns_p_a set sk_date = 1 where true; +ERROR: duplicate key value violates unique constraint "idx_uq_a" +DETAIL: Key (sk_date)=(1) already exists. +set enable_opfusion = on; +alter index idx_uq_a rebuild; +alter table web_returns_p_a drop partition p3; +reset behavior_compat_options; +insert into web_returns_p_a values (2,2,2,2); +insert into web_returns_p_a values (2,2,2,2); +reset behavior_compat_options; +-- ustore +CREATE TABLE web_returns_p_u +( + sk_date INTEGER, + cm_num INTEGER, + nv_num INTEGER, + cn_name INTEGER +) +with (STORAGE_TYPE=ASTORE) +PARTITION BY RANGE(sk_date) +( + PARTITION P1 VALUES LESS THAN(1), + PARTITION P2 VALUES LESS THAN(2), + PARTITION P3 VALUES LESS THAN(3), + PARTITION P4 VALUES LESS THAN(4), + PARTITION P5 VALUES LESS THAN(5), + PARTITION P6 VALUES LESS THAN(6), + PARTITION P7 VALUES LESS THAN(7), + PARTITION P8 VALUES LESS THAN(8), + PARTITION P9 VALUES LESS THAN(9), + PARTITION Pmax VALUES LESS THAN(MAXVALUE) +); +insert into web_returns_p_u values (1,1,1,1); +insert into web_returns_p_u values (2,2,2,2); +insert into web_returns_p_u values (3,3,3,3); +insert into web_returns_p_u values (4,4,4,4); +insert into web_returns_p_u values (5,5,5,5); +insert into web_returns_p_u values (6,6,6,6); +insert into web_returns_p_u values (7,7,7,7); +insert into web_returns_p_u values (8,8,8,8); +insert into web_returns_p_u values (9,9,9,9); +create index idx_cm_num_u on web_returns_p_u(cm_num) global; +create index idx_nv_num_u on web_returns_p_u(nv_num) local; +create unique index idx_uq_u on web_returns_p_u(sk_date) global; +set behavior_compat_options = 'update_unusable_unique_index_on_iud'; +alter table web_returns_p_u drop partition p2; +insert into web_returns_p_u values (1,1,1,1); +insert into web_returns_p_u values (1,1,1,1); +ERROR: duplicate key value violates unique constraint "idx_uq_u" +DETAIL: Key (sk_date)=(1) already exists. +update web_returns_p_u set sk_date = 1 where true; +ERROR: duplicate key value violates unique constraint "idx_uq_u" +DETAIL: Key (sk_date)=(1) already exists. +set enable_opfusion = off; +insert into web_returns_p_u values (1,1,1,1); +ERROR: duplicate key value violates unique constraint "idx_uq_u" +DETAIL: Key (sk_date)=(1) already exists. +insert into web_returns_p_u values (1,1,1,1); +ERROR: duplicate key value violates unique constraint "idx_uq_u" +DETAIL: Key (sk_date)=(1) already exists. +update web_returns_p_u set sk_date = 1 where true; +ERROR: duplicate key value violates unique constraint "idx_uq_u" +DETAIL: Key (sk_date)=(1) already exists. +set enable_opfusion = on; +alter index idx_uq_u rebuild; +alter table web_returns_p_u drop partition p3; +reset behavior_compat_options; +insert into web_returns_p_u values (2,2,2,2); +insert into web_returns_p_u values (2,2,2,2); +drop index idx_cm_num_a; +drop index idx_nv_num_a; +drop index idx_uq_a; +drop table web_returns_p_a; +drop index idx_cm_num_u; +drop index idx_nv_num_u; +drop index idx_uq_u; +drop table web_returns_p_u; +-- End. Clean u diff --git a/src/test/regress/sql/gpi_set_index_unusable.sql b/src/test/regress/sql/gpi_set_index_unusable.sql index feb94b8e8..ba15740e4 100644 --- a/src/test/regress/sql/gpi_set_index_unusable.sql +++ b/src/test/regress/sql/gpi_set_index_unusable.sql @@ -223,4 +223,121 @@ set enable_bitmapscan=on; set enable_seqscan=on; drop table if exists test_drop_llt; --- End. Clean up +--astore +CREATE TABLE web_returns_p_a +( + sk_date INTEGER, + cm_num INTEGER, + nv_num INTEGER, + cn_name INTEGER +) +with (STORAGE_TYPE=ASTORE) +PARTITION BY RANGE(sk_date) +( + PARTITION P1 VALUES LESS THAN(1), + PARTITION P2 VALUES LESS THAN(2), + PARTITION P3 VALUES LESS THAN(3), + PARTITION P4 VALUES LESS THAN(4), + PARTITION P5 VALUES LESS THAN(5), + PARTITION P6 VALUES LESS THAN(6), + PARTITION P7 VALUES LESS THAN(7), + PARTITION P8 VALUES LESS THAN(8), + PARTITION P9 VALUES LESS THAN(9), + PARTITION Pmax VALUES LESS THAN(MAXVALUE) +); + +insert into web_returns_p_a values (1,1,1,1); +insert into web_returns_p_a values (2,2,2,2); +insert into web_returns_p_a values (3,3,3,3); +insert into web_returns_p_a values (4,4,4,4); +insert into web_returns_p_a values (5,5,5,5); +insert into web_returns_p_a values (6,6,6,6); +insert into web_returns_p_a values (7,7,7,7); +insert into web_returns_p_a values (8,8,8,8); +insert into web_returns_p_a values (9,9,9,9); + +create index idx_cm_num_a on web_returns_p_a(cm_num) global; +create index idx_nv_num_a on web_returns_p_a(nv_num) local; +create unique index idx_uq_a on web_returns_p_a(sk_date) global; + +set behavior_compat_options = 'update_unusable_unique_index_on_iud'; +alter table web_returns_p_a drop partition p2; +insert into web_returns_p_a values (1,1,1,1); +insert into web_returns_p_a values (1,1,1,1); +update web_returns_p_a set sk_date = 1 where true; +set enable_opfusion = off; +insert into web_returns_p_a values (1,1,1,1); +insert into web_returns_p_a values (1,1,1,1); +update web_returns_p_a set sk_date = 1 where true; +set enable_opfusion = on; +alter index idx_uq_a rebuild; +alter table web_returns_p_a drop partition p3; +reset behavior_compat_options; +insert into web_returns_p_a values (2,2,2,2); +insert into web_returns_p_a values (2,2,2,2); +reset behavior_compat_options; + +-- ustore +CREATE TABLE web_returns_p_u +( + sk_date INTEGER, + cm_num INTEGER, + nv_num INTEGER, + cn_name INTEGER +) +with (STORAGE_TYPE=ASTORE) +PARTITION BY RANGE(sk_date) +( + PARTITION P1 VALUES LESS THAN(1), + PARTITION P2 VALUES LESS THAN(2), + PARTITION P3 VALUES LESS THAN(3), + PARTITION P4 VALUES LESS THAN(4), + PARTITION P5 VALUES LESS THAN(5), + PARTITION P6 VALUES LESS THAN(6), + PARTITION P7 VALUES LESS THAN(7), + PARTITION P8 VALUES LESS THAN(8), + PARTITION P9 VALUES LESS THAN(9), + PARTITION Pmax VALUES LESS THAN(MAXVALUE) +); + +insert into web_returns_p_u values (1,1,1,1); +insert into web_returns_p_u values (2,2,2,2); +insert into web_returns_p_u values (3,3,3,3); +insert into web_returns_p_u values (4,4,4,4); +insert into web_returns_p_u values (5,5,5,5); +insert into web_returns_p_u values (6,6,6,6); +insert into web_returns_p_u values (7,7,7,7); +insert into web_returns_p_u values (8,8,8,8); +insert into web_returns_p_u values (9,9,9,9); + +create index idx_cm_num_u on web_returns_p_u(cm_num) global; +create index idx_nv_num_u on web_returns_p_u(nv_num) local; +create unique index idx_uq_u on web_returns_p_u(sk_date) global; + +set behavior_compat_options = 'update_unusable_unique_index_on_iud'; +alter table web_returns_p_u drop partition p2; +insert into web_returns_p_u values (1,1,1,1); +insert into web_returns_p_u values (1,1,1,1); +update web_returns_p_u set sk_date = 1 where true; +set enable_opfusion = off; +insert into web_returns_p_u values (1,1,1,1); +insert into web_returns_p_u values (1,1,1,1); +update web_returns_p_u set sk_date = 1 where true; +set enable_opfusion = on; +alter index idx_uq_u rebuild; + +alter table web_returns_p_u drop partition p3; +reset behavior_compat_options; +insert into web_returns_p_u values (2,2,2,2); +insert into web_returns_p_u values (2,2,2,2); + +drop index idx_cm_num_a; +drop index idx_nv_num_a; +drop index idx_uq_a; +drop table web_returns_p_a; +drop index idx_cm_num_u; +drop index idx_nv_num_u; +drop index idx_uq_u; +drop table web_returns_p_u; + +-- End. Clean u