diff --git a/src/backend/distributed/commands/type.c b/src/backend/distributed/commands/type.c index c124388d4..a245217c0 100644 --- a/src/backend/distributed/commands/type.c +++ b/src/backend/distributed/commands/type.c @@ -57,6 +57,7 @@ #include "distributed/commands/utility_hook.h" #include "distributed/deparser.h" #include "distributed/listutils.h" +#include "distributed/metadata/dependency.h" #include "distributed/metadata/distobject.h" #include "distributed/metadata_sync.h" #include "distributed/multi_executor.h" @@ -132,28 +133,7 @@ PreprocessCompositeTypeStmt(Node *node, const char *queryString, /* fully qualify before lookup and later deparsing */ QualifyTreeNode(node); - /* - * reconstruct creation statement in a portable fashion. The create_or_replace helper - * function will be used to create the type in an idempotent manner on the workers. - * - * Types could exist on the worker prior to being created on the coordinator when the - * type previously has been attempted to be created in a transaction which did not - * commit on the coordinator. - */ - const char *compositeTypeStmtSql = DeparseCompositeTypeStmt(node); - compositeTypeStmtSql = WrapCreateOrReplace(compositeTypeStmtSql); - - /* - * when we allow propagation within a transaction block we should make sure to only - * allow this in sequential mode - */ - EnsureSequentialMode(OBJECT_TYPE); - - List *commands = list_make3(DISABLE_DDL_PROPAGATION, - (void *) compositeTypeStmtSql, - ENABLE_DDL_PROPAGATION); - - return NodeDDLTaskList(NON_COORDINATOR_NODES, commands); + return NIL; } @@ -176,9 +156,39 @@ PostprocessCompositeTypeStmt(Node *node, const char *queryString) * locally it can't be missing */ ObjectAddress typeAddress = GetObjectAddressFromParseTree(node, false); + + /* If the type has any unsupported dependency, create it locally */ + DeferredErrorMessage *errMsg = DeferErrorIfHasUnsupportedDependency(&typeAddress); + if (errMsg != NULL) + { + RaiseDeferredError(errMsg, WARNING); + return NIL; + } + + /* + * when we allow propagation within a transaction block we should make sure to only + * allow this in sequential mode + */ + EnsureSequentialMode(OBJECT_TYPE); + EnsureDependenciesExistOnAllNodes(&typeAddress); - return NIL; + /* + * reconstruct creation statement in a portable fashion. The create_or_replace helper + * function will be used to create the type in an idempotent manner on the workers. + * + * Types could exist on the worker prior to being created on the coordinator when the + * type previously has been attempted to be created in a transaction which did not + * commit on the coordinator. + */ + const char *compositeTypeStmtSql = DeparseCompositeTypeStmt(node); + compositeTypeStmtSql = WrapCreateOrReplace(compositeTypeStmtSql); + + List *commands = list_make3(DISABLE_DDL_PROPAGATION, + (void *) compositeTypeStmtSql, + ENABLE_DDL_PROPAGATION); + + return NodeDDLTaskList(NON_COORDINATOR_NODES, commands); } diff --git a/src/backend/distributed/metadata/dependency.c b/src/backend/distributed/metadata/dependency.c index 38fe29c4d..c56539d75 100644 --- a/src/backend/distributed/metadata/dependency.c +++ b/src/backend/distributed/metadata/dependency.c @@ -776,10 +776,11 @@ DeferErrorIfHasUnsupportedDependency(const ObjectAddress *objectAddress) #endif /* - * If the given object is a procedure, we want to create it locally, + * If the given object is a procedure or type, we want to create it locally, * so provide that information in the error detail. */ - if (getObjectClass(objectAddress) == OCLASS_PROC) + if (getObjectClass(objectAddress) == OCLASS_PROC || + getObjectClass(objectAddress) == OCLASS_TYPE) { appendStringInfo(detailInfo, "\"%s\" will be created only locally", objectDescription); diff --git a/src/test/regress/expected/distributed_types.out b/src/test/regress/expected/distributed_types.out index ca1e5671e..155fa758a 100644 --- a/src/test/regress/expected/distributed_types.out +++ b/src/test/regress/expected/distributed_types.out @@ -566,6 +566,37 @@ CREATE TYPE circ_type1 AS (a int); CREATE TYPE circ_type2 AS (a int, b circ_type1); ALTER TYPE circ_type1 ADD ATTRIBUTE b circ_type2; ERROR: composite type circ_type1 cannot be made a member of itself +-- Show that types can be created locally if has unsupported dependency +CREATE TYPE text_local_def; +CREATE FUNCTION text_local_def_in(cstring) + RETURNS text_local_def + AS 'textin' + LANGUAGE internal STRICT IMMUTABLE; +NOTICE: return type text_local_def is only a shell +WARNING: "function text_local_def_in(cstring)" has dependency on unsupported object "type text_local_def" +DETAIL: "function text_local_def_in(cstring)" will be created only locally +CREATE FUNCTION text_local_def_out(text_local_def) + RETURNS cstring + AS 'textout' + LANGUAGE internal STRICT IMMUTABLE; +NOTICE: argument type text_local_def is only a shell +WARNING: "function text_local_def_out(text_local_def)" has dependency on unsupported object "type text_local_def" +DETAIL: "function text_local_def_out(text_local_def)" will be created only locally +CREATE TYPE text_local_def ( + internallength = variable, + input = text_local_def_in, + output = text_local_def_out, + alignment = int4, + default = 'zippo' +); +-- It should be created locally as it has unsupported dependency +CREATE TYPE default_test_row AS (f1 text_local_def, f2 int4); +WARNING: "type default_test_row" has dependency on unsupported object "type text_local_def" +DETAIL: "type default_test_row" will be created only locally +-- Distributing table depending on that type should error out +CREATE TABLE table_text_local_def(id int, col_1 default_test_row); +SELECT create_distributed_table('table_text_local_def','id'); +ERROR: "table table_text_local_def" has dependency on unsupported object "type text_local_def" -- clear objects SET client_min_messages TO error; -- suppress cascading objects dropping DROP SCHEMA type_tests CASCADE; diff --git a/src/test/regress/sql/distributed_types.sql b/src/test/regress/sql/distributed_types.sql index 2e465c94e..adddde84d 100644 --- a/src/test/regress/sql/distributed_types.sql +++ b/src/test/regress/sql/distributed_types.sql @@ -334,6 +334,31 @@ CREATE TYPE circ_type1 AS (a int); CREATE TYPE circ_type2 AS (a int, b circ_type1); ALTER TYPE circ_type1 ADD ATTRIBUTE b circ_type2; +-- Show that types can be created locally if has unsupported dependency +CREATE TYPE text_local_def; +CREATE FUNCTION text_local_def_in(cstring) + RETURNS text_local_def + AS 'textin' + LANGUAGE internal STRICT IMMUTABLE; +CREATE FUNCTION text_local_def_out(text_local_def) + RETURNS cstring + AS 'textout' + LANGUAGE internal STRICT IMMUTABLE; +CREATE TYPE text_local_def ( + internallength = variable, + input = text_local_def_in, + output = text_local_def_out, + alignment = int4, + default = 'zippo' +); + +-- It should be created locally as it has unsupported dependency +CREATE TYPE default_test_row AS (f1 text_local_def, f2 int4); + +-- Distributing table depending on that type should error out +CREATE TABLE table_text_local_def(id int, col_1 default_test_row); +SELECT create_distributed_table('table_text_local_def','id'); + -- clear objects SET client_min_messages TO error; -- suppress cascading objects dropping DROP SCHEMA type_tests CASCADE;