diff --git a/doc/src/sgml/ref/create_index.sgml b/doc/src/sgml/ref/create_index.sgml index bb7505d171b..50aa2729329 100644 --- a/doc/src/sgml/ref/create_index.sgml +++ b/doc/src/sgml/ref/create_index.sgml @@ -142,7 +142,9 @@ CREATE [ UNIQUE ] INDEX [ CONCURRENTLY ] [ [ IF NOT EXISTS ] Do not throw an error if a relation with the same name already exists. - A notice is issued in this case. Note that there is no guarantee that + A notice is issued in this case, with additional detail if the existing + relation is an invalid index. The existing index is not rebuilt or + validated. Note that there is no guarantee that the existing index is anything like the one that would have been created. Index name is required when IF NOT EXISTS is specified. diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index ec21b83b6b8..c3f93ae26f0 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -763,6 +763,7 @@ index_create(Relation heapRelation, bool mapped_relation; bool is_exclusion; Oid namespaceId; + Oid existingRelationId; int i; char relpersistence; bool isprimary = (flags & INDEX_CREATE_IS_PRIMARY) != 0; @@ -895,14 +896,30 @@ index_create(Relation heapRelation, * catalogs' unique indexes anyway, but we prefer to give a friendlier * error message. */ - if (get_relname_relid(indexRelationName, namespaceId)) + existingRelationId = get_relname_relid(indexRelationName, namespaceId); + if (OidIsValid(existingRelationId)) { if ((flags & INDEX_CREATE_IF_NOT_EXISTS) != 0) { + HeapTuple indexTuple; + bool existingIndexInvalid = false; + + /* The conflicting relation need not be an index. */ + indexTuple = SearchSysCache1(INDEXRELID, + ObjectIdGetDatum(existingRelationId)); + if (HeapTupleIsValid(indexTuple)) + { + existingIndexInvalid = + !((Form_pg_index) GETSTRUCT(indexTuple))->indisvalid; + ReleaseSysCache(indexTuple); + } + ereport(NOTICE, (errcode(ERRCODE_DUPLICATE_TABLE), errmsg("relation \"%s\" already exists, skipping", - indexRelationName))); + indexRelationName), + existingIndexInvalid ? + errdetail("The existing index is invalid.") : 0)); table_close(pg_class, RowExclusiveLock); return InvalidOid; } diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out index 7b2640f0e04..831386a2eae 100644 --- a/src/test/regress/expected/create_index.out +++ b/src/test/regress/expected/create_index.out @@ -10,6 +10,9 @@ CREATE INDEX onek_unique1 ON onek USING btree(unique1 int4_ops); CREATE INDEX IF NOT EXISTS onek_unique1 ON onek USING btree(unique1 int4_ops); NOTICE: relation "onek_unique1" already exists, skipping +-- The conflicting relation need not be an index. +CREATE INDEX IF NOT EXISTS onek ON onek USING btree(unique1 int4_ops); +NOTICE: relation "onek" already exists, skipping CREATE INDEX IF NOT EXISTS ON onek USING btree(unique1 int4_ops); ERROR: syntax error at or near "ON" LINE 1: CREATE INDEX IF NOT EXISTS ON onek USING btree(unique1 int4_... @@ -1447,6 +1450,13 @@ DETAIL: Key (f1)=(b) already exists. CREATE UNIQUE INDEX CONCURRENTLY concur_index3 ON concur_heap(f2); ERROR: could not create unique index "concur_index3" DETAIL: Key (f2)=(b) is duplicated. +-- IF NOT EXISTS reports that the existing index is invalid, without rebuilding it. +CREATE UNIQUE INDEX IF NOT EXISTS concur_index3 ON concur_heap(f2); +NOTICE: relation "concur_index3" already exists, skipping +DETAIL: The existing index is invalid. +CREATE UNIQUE INDEX CONCURRENTLY IF NOT EXISTS concur_index3 ON concur_heap(f2); +NOTICE: relation "concur_index3" already exists, skipping +DETAIL: The existing index is invalid. -- test that expression indexes and partial indexes work concurrently CREATE INDEX CONCURRENTLY concur_index4 on concur_heap(f2) WHERE f1='a'; CREATE INDEX CONCURRENTLY concur_index5 on concur_heap(f2) WHERE f1='x'; @@ -1565,6 +1575,15 @@ Indexes: "std_index" btree (f2) DROP TABLE concur_heap; +-- An index created on ONLY a partitioned table is also invalid. +CREATE TABLE invalid_index_heap (a int) PARTITION BY RANGE (a); +CREATE TABLE invalid_index_partition PARTITION OF invalid_index_heap + FOR VALUES FROM (0) TO (10); +CREATE INDEX invalid_index ON ONLY invalid_index_heap (a); +CREATE INDEX IF NOT EXISTS invalid_index ON invalid_index_heap (a); +NOTICE: relation "invalid_index" already exists, skipping +DETAIL: The existing index is invalid. +DROP TABLE invalid_index_heap; -- -- Test ADD CONSTRAINT USING INDEX -- diff --git a/src/test/regress/sql/create_index.sql b/src/test/regress/sql/create_index.sql index 88ca3c80875..8549a4bd417 100644 --- a/src/test/regress/sql/create_index.sql +++ b/src/test/regress/sql/create_index.sql @@ -13,6 +13,9 @@ CREATE INDEX onek_unique1 ON onek USING btree(unique1 int4_ops); CREATE INDEX IF NOT EXISTS onek_unique1 ON onek USING btree(unique1 int4_ops); +-- The conflicting relation need not be an index. +CREATE INDEX IF NOT EXISTS onek ON onek USING btree(unique1 int4_ops); + CREATE INDEX IF NOT EXISTS ON onek USING btree(unique1 int4_ops); CREATE INDEX onek_unique2 ON onek USING btree(unique2 int4_ops); @@ -507,6 +510,9 @@ CREATE UNIQUE INDEX CONCURRENTLY IF NOT EXISTS concur_index2 ON concur_heap(f1); INSERT INTO concur_heap VALUES ('b','x'); -- check if constraint is enforced properly at build time CREATE UNIQUE INDEX CONCURRENTLY concur_index3 ON concur_heap(f2); +-- IF NOT EXISTS reports that the existing index is invalid, without rebuilding it. +CREATE UNIQUE INDEX IF NOT EXISTS concur_index3 ON concur_heap(f2); +CREATE UNIQUE INDEX CONCURRENTLY IF NOT EXISTS concur_index3 ON concur_heap(f2); -- test that expression indexes and partial indexes work concurrently CREATE INDEX CONCURRENTLY concur_index4 on concur_heap(f2) WHERE f1='a'; CREATE INDEX CONCURRENTLY concur_index5 on concur_heap(f2) WHERE f1='x'; @@ -591,6 +597,14 @@ DROP INDEX CONCURRENTLY "concur_heap_f2_f1_idx"; DROP TABLE concur_heap; +-- An index created on ONLY a partitioned table is also invalid. +CREATE TABLE invalid_index_heap (a int) PARTITION BY RANGE (a); +CREATE TABLE invalid_index_partition PARTITION OF invalid_index_heap + FOR VALUES FROM (0) TO (10); +CREATE INDEX invalid_index ON ONLY invalid_index_heap (a); +CREATE INDEX IF NOT EXISTS invalid_index ON invalid_index_heap (a); +DROP TABLE invalid_index_heap; + -- -- Test ADD CONSTRAINT USING INDEX --