diff --git a/src/backend/distributed/executor/multi_utility.c b/src/backend/distributed/executor/multi_utility.c index 849b7093c..5e21a2c09 100644 --- a/src/backend/distributed/executor/multi_utility.c +++ b/src/backend/distributed/executor/multi_utility.c @@ -227,6 +227,9 @@ multi_ProcessUtility(Node *parsetree, if (IsA(parsetree, CopyStmt)) { + /* copy parse tree since we might scribble on it to fix the schema name */ + parsetree = copyObject(parsetree); + parsetree = ProcessCopyStmt((CopyStmt *) parsetree, completionTag, &commandMustRunAsOwner); @@ -261,6 +264,8 @@ multi_ProcessUtility(Node *parsetree, if (IsA(parsetree, IndexStmt)) { + /* copy parse tree since we might scribble on it to fix the schema name */ + parsetree = copyObject(parsetree); parsetree = ProcessIndexStmt((IndexStmt *) parsetree, queryString, isTopLevel); } @@ -698,7 +703,13 @@ ProcessIndexStmt(IndexStmt *createIndexStatement, const char *createIndexCommand isDistributedRelation = IsDistributedTable(relationId); - /* ensure future lookups hit the same relation */ + /* + * Before we do any further processing, fix the schema name to make sure + * that a (distributed) table with the same name does not appear on the + * search path in front of the current schema. We do this even if the + * table is not distributed, since a distributed table may appear on the + * search path by the time postgres starts processing this statement. + */ namespaceName = get_namespace_name(RelationGetNamespace(relation)); createIndexStatement->relation->schemaname = namespaceName; diff --git a/src/test/regress/expected/multi_prepare_plsql.out b/src/test/regress/expected/multi_prepare_plsql.out index f56a7c9ce..dcd362f45 100644 --- a/src/test/regress/expected/multi_prepare_plsql.out +++ b/src/test/regress/expected/multi_prepare_plsql.out @@ -1106,6 +1106,58 @@ BEGIN END; $$; DROP TABLE execute_parameter_test; +-- test prepared DDL, mainly to verify we don't mess up the query tree +SET citus.multi_shard_commit_protocol TO '2pc'; +CREATE TABLE prepare_ddl (x int, y int); +SELECT create_distributed_table('prepare_ddl', 'x'); + create_distributed_table +-------------------------- + +(1 row) + +CREATE OR REPLACE FUNCTION ddl_in_plpgsql() +RETURNS VOID AS +$BODY$ +BEGIN + CREATE INDEX prepared_index ON public.prepare_ddl(x); + DROP INDEX prepared_index; +END; +$BODY$ LANGUAGE plpgsql; +SELECT ddl_in_plpgsql(); + ddl_in_plpgsql +---------------- + +(1 row) + +SELECT ddl_in_plpgsql(); + ddl_in_plpgsql +---------------- + +(1 row) + +-- test prepared COPY +CREATE OR REPLACE FUNCTION copy_in_plpgsql() +RETURNS VOID AS +$BODY$ +BEGIN + COPY prepare_ddl (x) FROM PROGRAM 'echo 1' WITH CSV; +END; +$BODY$ LANGUAGE plpgsql; +SELECT copy_in_plpgsql(); + copy_in_plpgsql +----------------- + +(1 row) + +SELECT copy_in_plpgsql(); + copy_in_plpgsql +----------------- + +(1 row) + +DROP FUNCTION ddl_in_plpgsql(); +DROP FUNCTION copy_in_plpgsql(); +DROP TABLE prepare_ddl; -- clean-up functions DROP FUNCTION plpgsql_test_1(); DROP FUNCTION plpgsql_test_2(); diff --git a/src/test/regress/sql/multi_prepare_plsql.sql b/src/test/regress/sql/multi_prepare_plsql.sql index 5018c2cb8..9634d736b 100644 --- a/src/test/regress/sql/multi_prepare_plsql.sql +++ b/src/test/regress/sql/multi_prepare_plsql.sql @@ -497,6 +497,39 @@ END; $$; DROP TABLE execute_parameter_test; +-- test prepared DDL, mainly to verify we don't mess up the query tree +SET citus.multi_shard_commit_protocol TO '2pc'; +CREATE TABLE prepare_ddl (x int, y int); +SELECT create_distributed_table('prepare_ddl', 'x'); + +CREATE OR REPLACE FUNCTION ddl_in_plpgsql() +RETURNS VOID AS +$BODY$ +BEGIN + CREATE INDEX prepared_index ON public.prepare_ddl(x); + DROP INDEX prepared_index; +END; +$BODY$ LANGUAGE plpgsql; + +SELECT ddl_in_plpgsql(); +SELECT ddl_in_plpgsql(); + +-- test prepared COPY +CREATE OR REPLACE FUNCTION copy_in_plpgsql() +RETURNS VOID AS +$BODY$ +BEGIN + COPY prepare_ddl (x) FROM PROGRAM 'echo 1' WITH CSV; +END; +$BODY$ LANGUAGE plpgsql; + +SELECT copy_in_plpgsql(); +SELECT copy_in_plpgsql(); + +DROP FUNCTION ddl_in_plpgsql(); +DROP FUNCTION copy_in_plpgsql(); +DROP TABLE prepare_ddl; + -- clean-up functions DROP FUNCTION plpgsql_test_1(); DROP FUNCTION plpgsql_test_2();