From 93b583dc37207bddaf9153133ced27a498c7e760 Mon Sep 17 00:00:00 2001 From: Mikhail Nikalayeu Date: Tue, 31 Dec 2024 14:36:31 +0100 Subject: [PATCH v26 6/8] Track and drop auxiliary indexes in DROP/REINDEX During concurrent index operations, auxiliary indexes may be left as orphaned objects when errors occur (junk auxiliary indexes). This patch improves the handling of such auxiliary indexes: - add auxiliaryForIndexId parameter to index_create() to track dependencies between main and auxiliary indexes - automatically drop auxiliary indexes when the main index is dropped - delete junk auxiliary indexes properly during REINDEX operations --- doc/src/sgml/ref/create_index.sgml | 14 ++- doc/src/sgml/ref/reindex.sgml | 8 +- src/backend/catalog/dependency.c | 2 +- src/backend/catalog/index.c | 71 ++++++++++---- src/backend/catalog/pg_depend.c | 57 +++++++++++ src/backend/catalog/toasting.c | 1 + src/backend/commands/indexcmds.c | 38 +++++++- src/backend/commands/tablecmds.c | 48 +++++++++- src/backend/nodes/makefuncs.c | 3 +- src/include/catalog/dependency.h | 1 + src/include/nodes/execnodes.h | 2 + src/include/nodes/makefuncs.h | 2 +- src/test/regress/expected/create_index.out | 105 +++++++++++++++++++-- src/test/regress/sql/create_index.sql | 57 ++++++++++- 14 files changed, 367 insertions(+), 42 deletions(-) diff --git a/doc/src/sgml/ref/create_index.sgml b/doc/src/sgml/ref/create_index.sgml index ba387f28977..bad0df105d2 100644 --- a/doc/src/sgml/ref/create_index.sgml +++ b/doc/src/sgml/ref/create_index.sgml @@ -668,10 +668,16 @@ Indexes: "idx_ccaux" stir (col) INVALID - The recommended recovery - method in such cases is to drop these indexes and try again to perform - CREATE INDEX CONCURRENTLY. (Another possibility is - to rebuild the index with REINDEX INDEX CONCURRENTLY). + The recommended recovery method in such cases is to drop the index with + DROP INDEX. The auxiliary index (suffixed with + ccaux) will be automatically dropped when the main + index is dropped. After dropping the indexes, you can try again to perform + CREATE INDEX CONCURRENTLY. (Another possibility is to + rebuild the index with REINDEX INDEX CONCURRENTLY, + which will also handle cleanup of any invalid auxiliary indexes.) + If the only invalid index is one suffixed ccaux + recommended recovery method is just DROP INDEX + for that index. diff --git a/doc/src/sgml/ref/reindex.sgml b/doc/src/sgml/ref/reindex.sgml index 97f551a55a6..025fe37a370 100644 --- a/doc/src/sgml/ref/reindex.sgml +++ b/doc/src/sgml/ref/reindex.sgml @@ -477,11 +477,15 @@ Indexes: _ccnew or _ccaux, then it corresponds to the transient or auxiliary index created during the concurrent operation, and the recommended recovery method is to drop these indexes using DROP INDEX, - then attempt REINDEX CONCURRENTLY again. + then attempt REINDEX CONCURRENTLY again. The auxiliary index + (suffixed with _ccaux) will be automatically dropped + along with its main index. If the invalid index is instead suffixed _ccold, it corresponds to the original index which could not be dropped; the recommended recovery method is to just drop said index, since the - rebuild proper has been successful. + rebuild proper has been successful. If the only + invalid index is one suffixed ccaux recommended + recovery method is just DROP INDEX for that index. A nonzero number may be appended to the suffix of the invalid index names to keep them unique, like _ccnew1, _ccold2, etc. diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c index 7dded634eb8..b579d26aff2 100644 --- a/src/backend/catalog/dependency.c +++ b/src/backend/catalog/dependency.c @@ -286,7 +286,7 @@ performDeletion(const ObjectAddress *object, * Acquire deletion lock on the target object. (Ideally the caller has * done this already, but many places are sloppy about it.) */ - AcquireDeletionLock(object, 0); + AcquireDeletionLock(object, flags); /* * Construct a list of objects to delete (ie, the given object plus diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index 6a4b348dd1b..fbebc6ed9ab 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -775,6 +775,8 @@ index_create(Relation heapRelation, ((flags & INDEX_CREATE_ADD_CONSTRAINT) != 0)); /* partitioned indexes must never be "built" by themselves */ Assert(!partitioned || (flags & INDEX_CREATE_SKIP_BUILD)); + /* ii_AuxiliaryForIndexId and INDEX_CREATE_AUXILIARY are required both or neither */ + Assert(OidIsValid(indexInfo->ii_AuxiliaryForIndexId) == auxiliary); relkind = partitioned ? RELKIND_PARTITIONED_INDEX : RELKIND_INDEX; is_exclusion = (indexInfo->ii_ExclusionOps != NULL); @@ -1180,6 +1182,15 @@ index_create(Relation heapRelation, recordDependencyOn(&myself, &referenced, DEPENDENCY_PARTITION_SEC); } + /* + * Record dependency on the main index in case of auxiliary index. + */ + if (OidIsValid(indexInfo->ii_AuxiliaryForIndexId)) + { + ObjectAddressSet(referenced, RelationRelationId, indexInfo->ii_AuxiliaryForIndexId); + recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO); + } + /* placeholder for normal dependencies */ addrs = new_object_addresses(); @@ -1412,7 +1423,8 @@ index_concurrently_create_copy(Relation heapRelation, Oid oldIndexId, true, indexRelation->rd_indam->amsummarizing, oldInfo->ii_WithoutOverlaps, - false); + false, + InvalidOid); /* * Extract the list of column names and the column numbers for the new @@ -1580,7 +1592,8 @@ index_concurrently_create_aux(Relation heapRelation, Oid mainIndexId, true, false, /* aux are not summarizing */ false, /* aux are not without overlaps */ - true /* auxiliary */); + true /* auxiliary */, + mainIndexId /* auxiliaryForIndexId */); /* * Extract the list of column names and the column numbers for the new @@ -2616,7 +2629,8 @@ BuildIndexInfo(Relation index) false, index->rd_indam->amsummarizing, indexStruct->indisexclusion && indexStruct->indisunique, - index->rd_rel->relam == STIR_AM_OID /* auxiliary iff STIR */); + index->rd_rel->relam == STIR_AM_OID /* auxiliary iff STIR */, + InvalidOid /* auxiliary_for_index_id is set only during build */); /* fill in attribute numbers */ for (i = 0; i < numAtts; i++) @@ -2677,7 +2691,8 @@ BuildDummyIndexInfo(Relation index) false, index->rd_indam->amsummarizing, indexStruct->indisexclusion && indexStruct->indisunique, - index->rd_rel->relam == STIR_AM_OID /* auxiliary iff STIR */); + index->rd_rel->relam == STIR_AM_OID /* auxiliary iff STIR */, + InvalidOid); /* fill in attribute numbers */ for (i = 0; i < numAtts; i++) @@ -3848,6 +3863,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId, heapRelation; Oid heapId; Oid save_userid; + Oid junkAuxIndexId; int save_sec_context; int save_nestlevel; IndexInfo *indexInfo; @@ -3904,6 +3920,19 @@ reindex_index(const ReindexStmt *stmt, Oid indexId, pgstat_progress_update_multi_param(2, progress_cols, progress_vals); } + /* Check for the auxiliary index for that index, it needs to dropped */ + junkAuxIndexId = get_auxiliary_index(indexId); + if (OidIsValid(junkAuxIndexId)) + { + ObjectAddress object; + object.classId = RelationRelationId; + object.objectId = junkAuxIndexId; + object.objectSubId = 0; + performDeletion(&object, DROP_RESTRICT, + PERFORM_DELETION_INTERNAL | + PERFORM_DELETION_QUIETLY); + } + /* * Open the target index relation and get an exclusive lock on it, to * ensure that no one else is touching this particular index. @@ -4192,7 +4221,8 @@ reindex_relation(const ReindexStmt *stmt, Oid relid, int flags, { Relation rel; Oid toast_relid; - List *indexIds; + List *indexIds, + *auxIndexIds = NIL; char persistence; bool result = false; ListCell *indexId; @@ -4281,13 +4311,30 @@ reindex_relation(const ReindexStmt *stmt, Oid relid, int flags, else persistence = rel->rd_rel->relpersistence; + foreach(indexId, indexIds) + { + Oid indexOid = lfirst_oid(indexId); + Oid indexAm = get_rel_relam(indexOid); + + /* All STIR indexes are auxiliary indexes */ + if (indexAm == STIR_AM_OID) + { + if (flags & REINDEX_REL_SUPPRESS_INDEX_USE) + RemoveReindexPending(indexOid); + auxIndexIds = lappend_oid(auxIndexIds, indexOid); + } + } + /* Reindex all the indexes. */ i = 1; foreach(indexId, indexIds) { Oid indexOid = lfirst_oid(indexId); Oid indexNamespaceId = get_rel_namespace(indexOid); - Oid indexAm = get_rel_relam(indexOid); + + /* Auxiliary indexes are going to be dropped during main index rebuild */ + if (list_member_oid(auxIndexIds, indexOid)) + continue; /* * Skip any invalid indexes on a TOAST table. These can only be @@ -4313,18 +4360,6 @@ reindex_relation(const ReindexStmt *stmt, Oid relid, int flags, continue; } - if (indexAm == STIR_AM_OID) - { - ereport(WARNING, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("skipping reindex of auxiliary index \"%s.%s\"", - get_namespace_name(indexNamespaceId), - get_rel_name(indexOid)))); - if (flags & REINDEX_REL_SUPPRESS_INDEX_USE) - RemoveReindexPending(indexOid); - continue; - } - reindex_index(stmt, indexOid, !(flags & REINDEX_REL_CHECK_CONSTRAINTS), persistence, params); diff --git a/src/backend/catalog/pg_depend.c b/src/backend/catalog/pg_depend.c index c8b11f887e2..1c275ef373f 100644 --- a/src/backend/catalog/pg_depend.c +++ b/src/backend/catalog/pg_depend.c @@ -1035,6 +1035,63 @@ get_index_constraint(Oid indexId) return constraintId; } +/* + * get_auxiliary_index + * Given the OID of an index, return the OID of its auxiliary + * index, or InvalidOid if there is no auxiliary index. + */ +Oid +get_auxiliary_index(Oid indexId) +{ + Oid auxiliaryIndexOid = InvalidOid; + Relation depRel; + ScanKeyData key[3]; + SysScanDesc scan; + HeapTuple tup; + + /* Search the dependency table for the index */ + depRel = table_open(DependRelationId, AccessShareLock); + + ScanKeyInit(&key[0], + Anum_pg_depend_refclassid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(RelationRelationId)); + ScanKeyInit(&key[1], + Anum_pg_depend_refobjid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(indexId)); + ScanKeyInit(&key[2], + Anum_pg_depend_refobjsubid, + BTEqualStrategyNumber, F_INT4EQ, + Int32GetDatum(0)); + + scan = systable_beginscan(depRel, DependReferenceIndexId, true, + NULL, 3, key); + + + while (HeapTupleIsValid(tup = systable_getnext(scan))) + { + Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup); + + /* + * We assume any AUTO dependency on index with rel_kind + * of RELKIND_INDEX is that we are looking for. + */ + if (deprec->classid == RelationRelationId && + (deprec->deptype == DEPENDENCY_AUTO) && + get_rel_relkind(deprec->objid) == RELKIND_INDEX) + { + auxiliaryIndexOid = deprec->objid; + break; + } + } + + systable_endscan(scan); + table_close(depRel, AccessShareLock); + + return auxiliaryIndexOid; +} + /* * get_index_ref_constraints * Given the OID of an index, return the OID of all foreign key diff --git a/src/backend/catalog/toasting.c b/src/backend/catalog/toasting.c index 9cc4f06da9f..3aa657c79cb 100644 --- a/src/backend/catalog/toasting.c +++ b/src/backend/catalog/toasting.c @@ -308,6 +308,7 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid, indexInfo->ii_Am = BTREE_AM_OID; indexInfo->ii_AmCache = NULL; indexInfo->ii_Auxiliary = false; + indexInfo->ii_AuxiliaryForIndexId = InvalidOid; indexInfo->ii_Context = CurrentMemoryContext; collationIds[0] = InvalidOid; diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index 9c34825e97d..ca4dc003d15 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -245,7 +245,7 @@ CheckIndexCompatible(Oid oldId, indexInfo = makeIndexInfo(numberOfAttributes, numberOfAttributes, accessMethodId, NIL, NIL, false, false, false, false, amsummarizing, - isWithoutOverlaps, isauxiliary); + isWithoutOverlaps, isauxiliary, InvalidOid); typeIds = palloc_array(Oid, numberOfAttributes); collationIds = palloc_array(Oid, numberOfAttributes); opclassIds = palloc_array(Oid, numberOfAttributes); @@ -943,7 +943,8 @@ DefineIndex(Oid tableId, concurrent, amissummarizing, stmt->iswithoutoverlaps, - false); + false, + InvalidOid); typeIds = palloc_array(Oid, numberOfAttributes); collationIds = palloc_array(Oid, numberOfAttributes); @@ -3683,6 +3684,7 @@ ReindexRelationConcurrently(const ReindexStmt *stmt, Oid relationOid, const Rein { Oid indexId; Oid auxIndexId; + Oid junkAuxIndexId; Oid tableId; Oid amId; bool safe; /* for set_indexsafe_procflags */ @@ -4032,6 +4034,7 @@ ReindexRelationConcurrently(const ReindexStmt *stmt, Oid relationOid, const Rein ReindexIndexInfo *newidx; Oid newIndexId; Oid auxIndexId; + Oid junkAuxIndexId; Relation indexRel; Relation heapRel; Oid save_userid; @@ -4039,6 +4042,7 @@ ReindexRelationConcurrently(const ReindexStmt *stmt, Oid relationOid, const Rein int save_nestlevel; Relation newIndexRel; Relation auxIndexRel; + Relation junkAuxIndexRel; LockRelId *lockrelid; Oid tablespaceid; @@ -4112,12 +4116,17 @@ ReindexRelationConcurrently(const ReindexStmt *stmt, Oid relationOid, const Rein tablespaceid, auxConcurrentName); + /* Search for auxiliary index for reindexed index, to drop it */ + junkAuxIndexId = get_auxiliary_index(idx->indexId); + /* * Now open the relation of the new index, a session-level lock is * also needed on it. */ newIndexRel = index_open(newIndexId, ShareUpdateExclusiveLock); auxIndexRel = index_open(auxIndexId, ShareUpdateExclusiveLock); + if (OidIsValid(junkAuxIndexId)) + junkAuxIndexRel = index_open(junkAuxIndexId, ShareUpdateExclusiveLock); /* * Save the list of OIDs and locks in private context @@ -4127,6 +4136,7 @@ ReindexRelationConcurrently(const ReindexStmt *stmt, Oid relationOid, const Rein newidx = palloc_object(ReindexIndexInfo); newidx->indexId = newIndexId; newidx->auxIndexId = auxIndexId; + newidx->junkAuxIndexId = junkAuxIndexId; newidx->safe = idx->safe; newidx->tableId = idx->tableId; newidx->amId = idx->amId; @@ -4148,10 +4158,18 @@ ReindexRelationConcurrently(const ReindexStmt *stmt, Oid relationOid, const Rein lockrelid = palloc_object(LockRelId); *lockrelid = auxIndexRel->rd_lockInfo.lockRelId; relationLocks = lappend(relationLocks, lockrelid); + if (OidIsValid(junkAuxIndexId)) + { + lockrelid = palloc_object(LockRelId); + *lockrelid = junkAuxIndexRel->rd_lockInfo.lockRelId; + relationLocks = lappend(relationLocks, lockrelid); + } MemoryContextSwitchTo(oldcontext); index_close(indexRel, NoLock); + if (OidIsValid(junkAuxIndexId)) + index_close(junkAuxIndexRel, NoLock); index_close(auxIndexRel, NoLock); index_close(newIndexRel, NoLock); @@ -4340,7 +4358,8 @@ ReindexRelationConcurrently(const ReindexStmt *stmt, Oid relationOid, const Rein /* * At this moment all target indexes are marked as "ready-to-insert". So, - * we are free to start process of dropping auxiliary indexes. + * we are free to start process of dropping auxiliary indexes - including + * just indexes detected earlier. */ foreach(lc, newIndexIds) { @@ -4363,6 +4382,9 @@ ReindexRelationConcurrently(const ReindexStmt *stmt, Oid relationOid, const Rein */ PushActiveSnapshot(GetTransactionSnapshot()); index_set_state_flags(newidx->auxIndexId, INDEX_DROP_CLEAR_READY); + /* Ensure just index is marked as non-ready */ + if (OidIsValid(newidx->junkAuxIndexId)) + index_set_state_flags(newidx->junkAuxIndexId, INDEX_DROP_CLEAR_READY); PopActiveSnapshot(); CommitTransactionCommand(); @@ -4581,6 +4603,8 @@ ReindexRelationConcurrently(const ReindexStmt *stmt, Oid relationOid, const Rein PushActiveSnapshot(GetTransactionSnapshot()); index_concurrently_set_dead(newidx->tableId, newidx->auxIndexId); + if (OidIsValid(newidx->junkAuxIndexId)) + index_concurrently_set_dead(newidx->tableId, newidx->junkAuxIndexId); PopActiveSnapshot(); } @@ -4632,6 +4656,14 @@ ReindexRelationConcurrently(const ReindexStmt *stmt, Oid relationOid, const Rein object.objectSubId = 0; add_exact_object_address(&object, objects); + + if (OidIsValid(idx->junkAuxIndexId)) + { + + object.objectId = idx->junkAuxIndexId; + object.objectSubId = 0; + add_exact_object_address(&object, objects); + } } /* diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 3aac459e483..d936d198e3a 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -1532,6 +1532,8 @@ RemoveRelations(DropStmt *drop) ListCell *cell; int flags = 0; LOCKMODE lockmode = AccessExclusiveLock; + MemoryContext private_context, + oldcontext; /* DROP CONCURRENTLY uses a weaker lock, and has some restrictions */ if (drop->concurrent) @@ -1592,9 +1594,20 @@ RemoveRelations(DropStmt *drop) relkind = 0; /* keep compiler quiet */ break; } + /* + * Create a memory context that will survive forced transaction commits we + * may need to do below (in case of concurrent index drop). + * Since it is a child of PortalContext, it will go away eventually even if + * we suffer an error; there's no need for special abort cleanup logic. + */ + private_context = AllocSetContextCreate(PortalContext, + "RemoveRelations", + ALLOCSET_SMALL_SIZES); + oldcontext = MemoryContextSwitchTo(private_context); /* Lock and validate each relation; build a list of object addresses */ objects = new_object_addresses(); + MemoryContextSwitchTo(oldcontext); foreach(cell, drop->objects) { @@ -1646,6 +1659,34 @@ RemoveRelations(DropStmt *drop) flags |= PERFORM_DELETION_CONCURRENTLY; } + /* + * Concurrent index drop requires to be the first transaction. But in + * case we have junk auxiliary index - we want to drop it too (and also + * in a concurrent way). In this case perform silent internal deletion + * of auxiliary index, and restore transaction state. It is fine to do it + * in the loop because there is only single element in drop->objects. + */ + if ((flags & PERFORM_DELETION_CONCURRENTLY) != 0 && + state.actual_relkind == RELKIND_INDEX) + { + Oid junkAuxIndexOid = get_auxiliary_index(relOid); + if (OidIsValid(junkAuxIndexOid)) + { + ObjectAddress object; + object.classId = RelationRelationId; + object.objectId = junkAuxIndexOid; + object.objectSubId = 0; + performDeletion(&object, DROP_RESTRICT, + PERFORM_DELETION_CONCURRENTLY | + PERFORM_DELETION_INTERNAL | + PERFORM_DELETION_QUIETLY); + CommitTransactionCommand(); + StartTransactionCommand(); + PushActiveSnapshot(GetTransactionSnapshot()); + PreventInTransactionBlock(true, "DROP INDEX CONCURRENTLY"); + } + } + /* * Concurrent index drop cannot be used with partitioned indexes, * either. @@ -1674,12 +1715,17 @@ RemoveRelations(DropStmt *drop) obj.objectId = relOid; obj.objectSubId = 0; + oldcontext = MemoryContextSwitchTo(private_context); add_exact_object_address(&obj, objects); + MemoryContextSwitchTo(oldcontext); } + /* Deletion may involve multiple commits, so, switch to memory context */ + oldcontext = MemoryContextSwitchTo(private_context); performMultipleDeletions(objects, drop->behavior, flags); + MemoryContextSwitchTo(oldcontext); - free_object_addresses(objects); + MemoryContextDelete(private_context); } /* diff --git a/src/backend/nodes/makefuncs.c b/src/backend/nodes/makefuncs.c index b556ba4817b..d7be8715d52 100644 --- a/src/backend/nodes/makefuncs.c +++ b/src/backend/nodes/makefuncs.c @@ -834,7 +834,7 @@ IndexInfo * makeIndexInfo(int numattrs, int numkeyattrs, Oid amoid, List *expressions, List *predicates, bool unique, bool nulls_not_distinct, bool isready, bool concurrent, bool summarizing, - bool withoutoverlaps, bool auxiliary) + bool withoutoverlaps, bool auxiliary, Oid auxiliary_for_index_id) { IndexInfo *n = makeNode(IndexInfo); @@ -851,6 +851,7 @@ makeIndexInfo(int numattrs, int numkeyattrs, Oid amoid, List *expressions, n->ii_Summarizing = summarizing; n->ii_WithoutOverlaps = withoutoverlaps; n->ii_Auxiliary = auxiliary; + n->ii_AuxiliaryForIndexId = auxiliary_for_index_id; /* summarizing indexes cannot contain non-key attributes */ Assert(!summarizing || (numkeyattrs == numattrs)); diff --git a/src/include/catalog/dependency.h b/src/include/catalog/dependency.h index 0ea7ccf5243..02bcf5e9315 100644 --- a/src/include/catalog/dependency.h +++ b/src/include/catalog/dependency.h @@ -180,6 +180,7 @@ extern List *getOwnedSequences(Oid relid); extern Oid getIdentitySequence(Relation rel, AttrNumber attnum, bool missing_ok); extern Oid get_index_constraint(Oid indexId); +extern Oid get_auxiliary_index(Oid indexId); extern List *get_index_ref_constraints(Oid indexId); diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index 84b32319fb3..5896c61a918 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -218,6 +218,8 @@ typedef struct IndexInfo int ii_ParallelWorkers; /* is auxiliary for concurrent index build? */ bool ii_Auxiliary; + /* if creating an auxiliary index, the OID of the main index; otherwise InvalidOid. */ + Oid ii_AuxiliaryForIndexId; /* Oid of index AM */ Oid ii_Am; /* private cache area for index AM */ diff --git a/src/include/nodes/makefuncs.h b/src/include/nodes/makefuncs.h index 4904748f5fc..35745bc521c 100644 --- a/src/include/nodes/makefuncs.h +++ b/src/include/nodes/makefuncs.h @@ -100,7 +100,7 @@ extern IndexInfo *makeIndexInfo(int numattrs, int numkeyattrs, Oid amoid, bool unique, bool nulls_not_distinct, bool isready, bool concurrent, bool summarizing, bool withoutoverlaps, - bool auxiliary); + bool auxiliary, Oid auxiliary_for_index_id); extern Node *makeStringConst(char *str, int location); extern DefElem *makeDefElem(char *name, Node *arg, int location); diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out index aa4fa76358a..3ed8999d74f 100644 --- a/src/test/regress/expected/create_index.out +++ b/src/test/regress/expected/create_index.out @@ -3265,20 +3265,109 @@ ERROR: reindex of auxiliary index "aux_index_ind6_ccaux" not supported REINDEX INDEX CONCURRENTLY aux_index_ind6_ccaux; ERROR: reindex of auxiliary index "aux_index_ind6_ccaux" not supported -- This makes the previous failure go away, so the index can become valid. -DELETE FROM concur_reindex_tab4 WHERE c1 = 1; -ERROR: relation "concur_reindex_tab4" does not exist -LINE 1: DELETE FROM concur_reindex_tab4 WHERE c1 = 1; - ^ +DELETE FROM aux_index_tab5 WHERE c1 = 1; +-- Should be skipped during reindex and dropped +REINDEX INDEX aux_index_ind6; +-- Make sure aux index is dropped +\d aux_index_tab5 + Table "public.aux_index_tab5" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + c1 | integer | | | +Indexes: + "aux_index_ind6" UNIQUE, btree (c1) + +DROP INDEX aux_index_ind6; +-- Insert duplicates again +INSERT INTO aux_index_tab5 VALUES (1), (1); +-- Create invalid index again +CREATE UNIQUE INDEX CONCURRENTLY aux_index_ind6 ON aux_index_tab5 (c1); +ERROR: could not create unique index "aux_index_ind6" +DETAIL: Key (c1)=(1) is duplicated. +-- This makes the previous failure go away, so the index can become valid. +DELETE FROM aux_index_tab5 WHERE c1 = 1; -- Should be skipped during reindex -REINDEX TABLE aux_index_tab5; -ERROR: could not create unique index "aux_index_ind6" -DETAIL: Key (c1)=(1) is duplicated. --- Should be skipped during concurrent reindex REINDEX TABLE CONCURRENTLY aux_index_tab5; WARNING: skipping reindex of invalid index "public.aux_index_ind6" HINT: Use DROP INDEX or REINDEX INDEX. WARNING: skipping reindex of auxiliary index "public.aux_index_ind6_ccaux" NOTICE: table "aux_index_tab5" has no indexes that can be reindexed concurrently +-- Make sure it is still exists +\d aux_index_tab5 + Table "public.aux_index_tab5" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + c1 | integer | | | +Indexes: + "aux_index_ind6" UNIQUE, btree (c1) INVALID + "aux_index_ind6_ccaux" stir (c1) INVALID + +-- Should be skipped during reindex and dropped +REINDEX TABLE aux_index_tab5; +-- Make sure aux index is dropped +\d aux_index_tab5 + Table "public.aux_index_tab5" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + c1 | integer | | | +Indexes: + "aux_index_ind6" UNIQUE, btree (c1) + +DROP INDEX aux_index_ind6; +-- Insert duplicates again +INSERT INTO aux_index_tab5 VALUES (1), (1); +-- Create invalid index again +CREATE UNIQUE INDEX CONCURRENTLY aux_index_ind6 ON aux_index_tab5 (c1); +ERROR: could not create unique index "aux_index_ind6" +DETAIL: Key (c1)=(1) is duplicated. +-- This makes the previous failure go away, so the index can become valid. +DELETE FROM aux_index_tab5 WHERE c1 = 1; +-- Should be skipped during reindex and dropped +REINDEX INDEX CONCURRENTLY aux_index_ind6; +-- Make sure aux index is dropped +\d aux_index_tab5 + Table "public.aux_index_tab5" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + c1 | integer | | | +Indexes: + "aux_index_ind6" UNIQUE, btree (c1) + +DROP INDEX aux_index_ind6; +-- Insert duplicates again +INSERT INTO aux_index_tab5 VALUES (1), (1); +-- Create invalid index again +CREATE UNIQUE INDEX CONCURRENTLY aux_index_ind6 ON aux_index_tab5 (c1); +ERROR: could not create unique index "aux_index_ind6" +DETAIL: Key (c1)=(1) is duplicated. +-- This makes the previous failure go away, so the index can become valid. +DELETE FROM aux_index_tab5 WHERE c1 = 1; +-- Drop main index CONCURRENTLY +DROP INDEX CONCURRENTLY aux_index_ind6; +-- Make sure auxiliary index dropped too +\d aux_index_tab5 + Table "public.aux_index_tab5" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + c1 | integer | | | + +DROP INDEX aux_index_ind6; +ERROR: index "aux_index_ind6" does not exist +-- Insert duplicates again +INSERT INTO aux_index_tab5 VALUES (1), (1); +-- Create invalid index again +CREATE UNIQUE INDEX CONCURRENTLY aux_index_ind6 ON aux_index_tab5 (c1); +ERROR: could not create unique index "aux_index_ind6" +DETAIL: Key (c1)=(1) is duplicated. +-- Drop main index +DROP INDEX aux_index_ind6; +-- Make sure auxiliary index dropped too +\d aux_index_tab5 + Table "public.aux_index_tab5" + Column | Type | Collation | Nullable | Default +--------+---------+-----------+----------+--------- + c1 | integer | | | + DROP TABLE aux_index_tab5; -- Check handling of indexes with expressions and predicates. The -- definitions of the rebuilt indexes should match the original diff --git a/src/test/regress/sql/create_index.sql b/src/test/regress/sql/create_index.sql index 7ae8e44019b..6d597790b56 100644 --- a/src/test/regress/sql/create_index.sql +++ b/src/test/regress/sql/create_index.sql @@ -1340,11 +1340,62 @@ REINDEX INDEX aux_index_ind6_ccaux; -- Concurrently also REINDEX INDEX CONCURRENTLY aux_index_ind6_ccaux; -- This makes the previous failure go away, so the index can become valid. -DELETE FROM concur_reindex_tab4 WHERE c1 = 1; +DELETE FROM aux_index_tab5 WHERE c1 = 1; +-- Should be skipped during reindex and dropped +REINDEX INDEX aux_index_ind6; +-- Make sure aux index is dropped +\d aux_index_tab5 +DROP INDEX aux_index_ind6; + +-- Insert duplicates again +INSERT INTO aux_index_tab5 VALUES (1), (1); +-- Create invalid index again +CREATE UNIQUE INDEX CONCURRENTLY aux_index_ind6 ON aux_index_tab5 (c1); +-- This makes the previous failure go away, so the index can become valid. +DELETE FROM aux_index_tab5 WHERE c1 = 1; -- Should be skipped during reindex -REINDEX TABLE aux_index_tab5; --- Should be skipped during concurrent reindex REINDEX TABLE CONCURRENTLY aux_index_tab5; +-- Make sure it is still exists +\d aux_index_tab5 +-- Should be skipped during reindex and dropped +REINDEX TABLE aux_index_tab5; +-- Make sure aux index is dropped +\d aux_index_tab5 +DROP INDEX aux_index_ind6; + +-- Insert duplicates again +INSERT INTO aux_index_tab5 VALUES (1), (1); +-- Create invalid index again +CREATE UNIQUE INDEX CONCURRENTLY aux_index_ind6 ON aux_index_tab5 (c1); +-- This makes the previous failure go away, so the index can become valid. +DELETE FROM aux_index_tab5 WHERE c1 = 1; +-- Should be skipped during reindex and dropped +REINDEX INDEX CONCURRENTLY aux_index_ind6; +-- Make sure aux index is dropped +\d aux_index_tab5 +DROP INDEX aux_index_ind6; + +-- Insert duplicates again +INSERT INTO aux_index_tab5 VALUES (1), (1); +-- Create invalid index again +CREATE UNIQUE INDEX CONCURRENTLY aux_index_ind6 ON aux_index_tab5 (c1); +-- This makes the previous failure go away, so the index can become valid. +DELETE FROM aux_index_tab5 WHERE c1 = 1; +-- Drop main index CONCURRENTLY +DROP INDEX CONCURRENTLY aux_index_ind6; +-- Make sure auxiliary index dropped too +\d aux_index_tab5 +DROP INDEX aux_index_ind6; + +-- Insert duplicates again +INSERT INTO aux_index_tab5 VALUES (1), (1); +-- Create invalid index again +CREATE UNIQUE INDEX CONCURRENTLY aux_index_ind6 ON aux_index_tab5 (c1); +-- Drop main index +DROP INDEX aux_index_ind6; +-- Make sure auxiliary index dropped too +\d aux_index_tab5 + DROP TABLE aux_index_tab5; -- Check handling of indexes with expressions and predicates. The -- 2.43.0