diff --git a/_codeql_detected_source_root b/_codeql_detected_source_root new file mode 120000 index 00000000000..945c9b46d68 --- /dev/null +++ b/_codeql_detected_source_root @@ -0,0 +1 @@ +. \ No newline at end of file diff --git a/src/backend/distributed/commands/index.c b/src/backend/distributed/commands/index.c index 0538f51b3b7..682e18cef71 100644 --- a/src/backend/distributed/commands/index.c +++ b/src/backend/distributed/commands/index.c @@ -19,6 +19,7 @@ #include "catalog/index.h" #include "catalog/namespace.h" #include "catalog/pg_class.h" +#include "catalog/pg_index.h" #include "catalog/pg_namespace.h" #include "commands/defrem.h" #include "commands/tablecmds.h" @@ -853,8 +854,41 @@ PostprocessIndexStmt(Node *node, const char *queryString) PushActiveSnapshot(GetTransactionSnapshot()); + /* + * If IF NOT EXISTS was used and the index already exists (is valid), + * skip invalidating it to prevent invalidating pre-existing indexes. + */ + bool index_was_already_valid = false; + if (indexStmt->if_not_exists) + { + /* + * Check the current validity state of the index. If it's already valid, + * it means the index existed before this command and PostgreSQL skipped + * creation. We should not invalidate it in this case. + * + * Note: SearchSysCache1 returns NULL if the index doesn't exist in the + * catalog yet, indicating it was just created. HeapTupleIsValid handles + * this case by returning false. + */ + HeapTuple indexTuple = SearchSysCache1(INDEXRELID, + ObjectIdGetDatum(indexRelationId)); + if (HeapTupleIsValid(indexTuple)) + { + Form_pg_index indexForm = (Form_pg_index) GETSTRUCT(indexTuple); + if (indexForm->indisvalid) + { + /* Index was already valid, so it existed before this command */ + index_was_already_valid = true; + } + ReleaseSysCache(indexTuple); + } + } + /* mark index as invalid, in-place (cannot be rolled back) */ - index_set_state_flags(indexRelationId, INDEX_DROP_CLEAR_VALID); + if (!index_was_already_valid) + { + index_set_state_flags(indexRelationId, INDEX_DROP_CLEAR_VALID); + } PopActiveSnapshot(); /* re-open a transaction command from here on out */ diff --git a/src/test/regress/expected/multi_index_statements.out b/src/test/regress/expected/multi_index_statements.out index 0a08ede3784..642278e3993 100644 --- a/src/test/regress/expected/multi_index_statements.out +++ b/src/test/regress/expected/multi_index_statements.out @@ -136,6 +136,25 @@ CREATE INDEX lineitem_orderkey_index on public.nation(n_nationkey); ERROR: relation "lineitem_orderkey_index" already exists CREATE INDEX IF NOT EXISTS lineitem_orderkey_index on public.nation(n_nationkey); NOTICE: relation "lineitem_orderkey_index" already exists, skipping +-- Verify that CREATE INDEX CONCURRENTLY IF NOT EXISTS doesn't invalidate existing index +CREATE INDEX CONCURRENTLY lineitem_concurrent_if_not_exists_test ON public.lineitem (l_partkey); +-- Verify the index is valid +SELECT indisvalid FROM pg_index WHERE indexrelid = 'public.lineitem_concurrent_if_not_exists_test'::regclass; + indisvalid +--------------------------------------------------------------------- + t +(1 row) + +-- Run the same command again with IF NOT EXISTS +CREATE INDEX CONCURRENTLY IF NOT EXISTS lineitem_concurrent_if_not_exists_test ON public.lineitem (l_partkey); +NOTICE: relation "lineitem_concurrent_if_not_exists_test" already exists, skipping +-- Verify the index is still valid (not invalidated) +SELECT indisvalid FROM pg_index WHERE indexrelid = 'public.lineitem_concurrent_if_not_exists_test'::regclass; + indisvalid +--------------------------------------------------------------------- + t +(1 row) + -- Verify that we can create indexes concurrently CREATE INDEX CONCURRENTLY lineitem_concurrently_index ON public.lineitem (l_orderkey); -- Verify that no-name local CREATE INDEX CONCURRENTLY works diff --git a/src/test/regress/sql/multi_index_statements.sql b/src/test/regress/sql/multi_index_statements.sql index e6e7dd60744..152e926b774 100644 --- a/src/test/regress/sql/multi_index_statements.sql +++ b/src/test/regress/sql/multi_index_statements.sql @@ -104,6 +104,15 @@ CREATE INDEX IF NOT EXISTS lineitem_orderkey_index_new on public.lineitem(l_orde CREATE INDEX lineitem_orderkey_index on public.nation(n_nationkey); CREATE INDEX IF NOT EXISTS lineitem_orderkey_index on public.nation(n_nationkey); +-- Verify that CREATE INDEX CONCURRENTLY IF NOT EXISTS doesn't invalidate existing index +CREATE INDEX CONCURRENTLY lineitem_concurrent_if_not_exists_test ON public.lineitem (l_partkey); +-- Verify the index is valid +SELECT indisvalid FROM pg_index WHERE indexrelid = 'public.lineitem_concurrent_if_not_exists_test'::regclass; +-- Run the same command again with IF NOT EXISTS +CREATE INDEX CONCURRENTLY IF NOT EXISTS lineitem_concurrent_if_not_exists_test ON public.lineitem (l_partkey); +-- Verify the index is still valid (not invalidated) +SELECT indisvalid FROM pg_index WHERE indexrelid = 'public.lineitem_concurrent_if_not_exists_test'::regclass; + -- Verify that we can create indexes concurrently CREATE INDEX CONCURRENTLY lineitem_concurrently_index ON public.lineitem (l_orderkey);