From 82e5faa1905b2acbe3551455a97ee685f206646a Mon Sep 17 00:00:00 2001 From: Samay Sharma Date: Fri, 28 Oct 2016 17:16:58 -0700 Subject: [PATCH] Avoid error during CREATE INDEX IF NOT EXISTS Previously, we threw an error when we ran CREATE INDEX IF NOT EXISTS with an already existing index. This change enables expected behavior by checking if the statement has IF NOT EXISTS before throwing the error. We also ensure that we don't execute the command on the workers, if an index already exists on the master. --- .../distributed/executor/multi_utility.c | 31 +++++++++++-------- .../expected/multi_index_statements.out | 20 ++++++++++-- .../regress/sql/multi_index_statements.sql | 10 ++++++ 3 files changed, 45 insertions(+), 16 deletions(-) diff --git a/src/backend/distributed/executor/multi_utility.c b/src/backend/distributed/executor/multi_utility.c index 8f4917459..30f432d5a 100644 --- a/src/backend/distributed/executor/multi_utility.c +++ b/src/backend/distributed/executor/multi_utility.c @@ -630,10 +630,26 @@ ProcessIndexStmt(IndexStmt *createIndexStatement, const char *createIndexCommand if (isDistributedRelation) { + Oid namespaceId = InvalidOid; + Oid indexRelationId = InvalidOid; + char *indexName = createIndexStatement->idxname; + ErrorIfUnsupportedIndexStmt(createIndexStatement); - /* if it is supported, go ahead and execute the command */ - ExecuteDistributedDDLCommand(relationId, createIndexCommand, isTopLevel); + namespaceId = get_namespace_oid(namespaceName, false); + indexRelationId = get_relname_relid(indexName, namespaceId); + + /* if index does not exist, send the command to workers */ + if (!OidIsValid(indexRelationId)) + { + ExecuteDistributedDDLCommand(relationId, createIndexCommand, isTopLevel); + } + else if (!createIndexStatement->if_not_exists) + { + /* if the index exists and there is no IF NOT EXISTS clause, error */ + ereport(ERROR, (errcode(ERRCODE_DUPLICATE_TABLE), + errmsg("relation \"%s\" already exists", indexName))); + } } } @@ -807,10 +823,7 @@ ProcessAlterObjectSchemaStmt(AlterObjectSchemaStmt *alterObjectSchemaStmt, static void ErrorIfUnsupportedIndexStmt(IndexStmt *createIndexStatement) { - Oid namespaceId; - Oid indexRelationId; char *indexRelationName = createIndexStatement->idxname; - if (indexRelationName == NULL) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), @@ -818,14 +831,6 @@ ErrorIfUnsupportedIndexStmt(IndexStmt *createIndexStatement) "currently unsupported"))); } - namespaceId = get_namespace_oid(createIndexStatement->relation->schemaname, false); - indexRelationId = get_relname_relid(indexRelationName, namespaceId); - if (indexRelationId != InvalidOid) - { - ereport(ERROR, (errcode(ERRCODE_DUPLICATE_TABLE), - errmsg("relation \"%s\" already exists", indexRelationName))); - } - if (createIndexStatement->tableSpace != NULL) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), diff --git a/src/test/regress/expected/multi_index_statements.out b/src/test/regress/expected/multi_index_statements.out index 21bbb3502..100ce2d05 100644 --- a/src/test/regress/expected/multi_index_statements.out +++ b/src/test/regress/expected/multi_index_statements.out @@ -80,6 +80,17 @@ CREATE UNIQUE INDEX index_test_hash_index_a_b ON index_test_hash(a,b); CREATE UNIQUE INDEX index_test_hash_index_a_b_partial ON index_test_hash(a,b) WHERE c IS NOT NULL; CREATE UNIQUE INDEX index_test_range_index_a_b_partial ON index_test_range(a,b) WHERE c IS NOT NULL; RESET client_min_messages; +-- Verify that we handle if not exists statements correctly +CREATE INDEX lineitem_orderkey_index on lineitem(l_orderkey); +ERROR: relation "lineitem_orderkey_index" already exists +CREATE INDEX IF NOT EXISTS lineitem_orderkey_index on lineitem(l_orderkey); +NOTICE: relation "lineitem_orderkey_index" already exists, skipping +CREATE INDEX IF NOT EXISTS lineitem_orderkey_index_new on lineitem(l_orderkey); +-- Verify if not exists behavior with an index with same name on a different table +CREATE INDEX lineitem_orderkey_index on index_test_hash(a); +ERROR: relation "lineitem_orderkey_index" already exists +CREATE INDEX IF NOT EXISTS lineitem_orderkey_index on index_test_hash(a); +NOTICE: relation "lineitem_orderkey_index" already exists, skipping -- Verify that all indexes got created on the master node and one of the workers SELECT * FROM pg_indexes WHERE tablename = 'lineitem' or tablename like 'index_test_%' ORDER BY indexname; schemaname | tablename | indexname | tablespace | indexdef @@ -93,17 +104,18 @@ SELECT * FROM pg_indexes WHERE tablename = 'lineitem' or tablename like 'index_t public | lineitem | lineitem_colref_index | | CREATE INDEX lineitem_colref_index ON lineitem USING btree (record_ne(lineitem.*, NULL::record)) public | lineitem | lineitem_orderkey_hash_index | | CREATE INDEX lineitem_orderkey_hash_index ON lineitem USING hash (l_partkey) public | lineitem | lineitem_orderkey_index | | CREATE INDEX lineitem_orderkey_index ON lineitem USING btree (l_orderkey) + public | lineitem | lineitem_orderkey_index_new | | CREATE INDEX lineitem_orderkey_index_new ON lineitem USING btree (l_orderkey) public | lineitem | lineitem_partial_index | | CREATE INDEX lineitem_partial_index ON lineitem USING btree (l_shipdate) WHERE (l_shipdate < '01-01-1995'::date) public | lineitem | lineitem_partkey_desc_index | | CREATE INDEX lineitem_partkey_desc_index ON lineitem USING btree (l_partkey DESC) public | lineitem | lineitem_pkey | | CREATE UNIQUE INDEX lineitem_pkey ON lineitem USING btree (l_orderkey, l_linenumber) public | lineitem | lineitem_time_index | | CREATE INDEX lineitem_time_index ON lineitem USING btree (l_shipdate) -(13 rows) +(14 rows) \c - - - :worker_1_port SELECT count(*) FROM pg_indexes WHERE tablename = (SELECT relname FROM pg_class WHERE relname LIKE 'lineitem%' ORDER BY relname LIMIT 1); count ------- - 7 + 8 (1 row) SELECT count(*) FROM pg_indexes WHERE tablename LIKE 'index_test_hash%'; @@ -174,11 +186,12 @@ SELECT * FROM pg_indexes WHERE tablename = 'lineitem' or tablename like 'index_t public | lineitem | lineitem_colref_index | | CREATE INDEX lineitem_colref_index ON lineitem USING btree (record_ne(lineitem.*, NULL::record)) public | lineitem | lineitem_orderkey_hash_index | | CREATE INDEX lineitem_orderkey_hash_index ON lineitem USING hash (l_partkey) public | lineitem | lineitem_orderkey_index | | CREATE INDEX lineitem_orderkey_index ON lineitem USING btree (l_orderkey) + public | lineitem | lineitem_orderkey_index_new | | CREATE INDEX lineitem_orderkey_index_new ON lineitem USING btree (l_orderkey) public | lineitem | lineitem_partial_index | | CREATE INDEX lineitem_partial_index ON lineitem USING btree (l_shipdate) WHERE (l_shipdate < '01-01-1995'::date) public | lineitem | lineitem_partkey_desc_index | | CREATE INDEX lineitem_partkey_desc_index ON lineitem USING btree (l_partkey DESC) public | lineitem | lineitem_pkey | | CREATE UNIQUE INDEX lineitem_pkey ON lineitem USING btree (l_orderkey, l_linenumber) public | lineitem | lineitem_time_index | | CREATE INDEX lineitem_time_index ON lineitem USING btree (l_shipdate) -(13 rows) +(14 rows) -- -- DROP INDEX @@ -192,6 +205,7 @@ DROP INDEX CONCURRENTLY lineitem_orderkey_index; ERROR: dropping indexes concurrently on distributed tables is currently unsupported -- Verify that we can succesfully drop indexes DROP INDEX lineitem_orderkey_index; +DROP INDEX lineitem_orderkey_index_new; DROP INDEX lineitem_partkey_desc_index; DROP INDEX lineitem_partial_index; DROP INDEX lineitem_colref_index; diff --git a/src/test/regress/sql/multi_index_statements.sql b/src/test/regress/sql/multi_index_statements.sql index 1cb4916e5..58e52a20f 100644 --- a/src/test/regress/sql/multi_index_statements.sql +++ b/src/test/regress/sql/multi_index_statements.sql @@ -55,6 +55,15 @@ CREATE UNIQUE INDEX index_test_hash_index_a_b_partial ON index_test_hash(a,b) WH CREATE UNIQUE INDEX index_test_range_index_a_b_partial ON index_test_range(a,b) WHERE c IS NOT NULL; RESET client_min_messages; +-- Verify that we handle if not exists statements correctly +CREATE INDEX lineitem_orderkey_index on lineitem(l_orderkey); +CREATE INDEX IF NOT EXISTS lineitem_orderkey_index on lineitem(l_orderkey); +CREATE INDEX IF NOT EXISTS lineitem_orderkey_index_new on lineitem(l_orderkey); + +-- Verify if not exists behavior with an index with same name on a different table +CREATE INDEX lineitem_orderkey_index on index_test_hash(a); +CREATE INDEX IF NOT EXISTS lineitem_orderkey_index on index_test_hash(a); + -- Verify that all indexes got created on the master node and one of the workers SELECT * FROM pg_indexes WHERE tablename = 'lineitem' or tablename like 'index_test_%' ORDER BY indexname; \c - - - :worker_1_port @@ -101,6 +110,7 @@ DROP INDEX CONCURRENTLY lineitem_orderkey_index; -- Verify that we can succesfully drop indexes DROP INDEX lineitem_orderkey_index; +DROP INDEX lineitem_orderkey_index_new; DROP INDEX lineitem_partkey_desc_index; DROP INDEX lineitem_partial_index; DROP INDEX lineitem_colref_index;