From c2767550b5ae322b54b4eec3b6556e6bc03d7b0d 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 59aa01d17..968c7bd18 100644 --- a/src/backend/distributed/executor/multi_utility.c +++ b/src/backend/distributed/executor/multi_utility.c @@ -577,10 +577,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))); + } } } @@ -754,10 +770,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), @@ -765,14 +778,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 2a77a0e83..14b116a89 100644 --- a/src/test/regress/expected/multi_index_statements.out +++ b/src/test/regress/expected/multi_index_statements.out @@ -77,6 +77,17 @@ CREATE UNIQUE INDEX index_test_range_index_a_b ON index_test_range(a,b); CREATE UNIQUE INDEX index_test_hash_index_a ON index_test_hash(a); CREATE UNIQUE INDEX index_test_hash_index_a_b ON index_test_hash(a,b); 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 @@ -87,17 +98,18 @@ SELECT * FROM pg_indexes WHERE tablename = 'lineitem' or tablename like 'index_t public | index_test_range | index_test_range_index_a_b | | CREATE UNIQUE INDEX index_test_range_index_a_b ON index_test_range USING btree (a, b) 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) -(10 rows) +(11 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 ------- - 6 + 7 (1 row) SELECT count(*) FROM pg_indexes WHERE tablename LIKE 'index_test_hash%'; @@ -163,11 +175,12 @@ SELECT * FROM pg_indexes WHERE tablename = 'lineitem' or tablename like 'index_t public | index_test_range | index_test_range_index_a_b | | CREATE UNIQUE INDEX index_test_range_index_a_b ON index_test_range USING btree (a, b) 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) -(10 rows) +(11 rows) -- -- DROP INDEX @@ -181,6 +194,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; -- Verify that we handle if exists statements correctly diff --git a/src/test/regress/sql/multi_index_statements.sql b/src/test/regress/sql/multi_index_statements.sql index a71d5b82d..0aa2bf0e9 100644 --- a/src/test/regress/sql/multi_index_statements.sql +++ b/src/test/regress/sql/multi_index_statements.sql @@ -51,6 +51,15 @@ CREATE UNIQUE INDEX index_test_hash_index_a ON index_test_hash(a); CREATE UNIQUE INDEX index_test_hash_index_a_b ON index_test_hash(a,b); 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 @@ -95,6 +104,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;