diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c index e7ecc4ed7e..758a9c1520 100644 --- a/src/backend/commands/typecmds.c +++ b/src/backend/commands/typecmds.c @@ -165,6 +165,8 @@ DefineType(ParseState *pstate, List *names, List *parameters) Oid resulttype; ListCell *pl; ObjectAddress address; + bool updated_input = false, + updated_output = false; /* * As of Postgres 8.4, we require superuser privilege to create a base @@ -457,6 +459,7 @@ DefineType(ParseState *pstate, List *names, List *parameters) (errmsg("changing return type of function %s from %s to %s", NameListToString(inputName), "opaque", typeName))); SetFunctionReturnType(inputOid, typoid); + updated_input = true; } else ereport(ERROR, @@ -474,6 +477,7 @@ DefineType(ParseState *pstate, List *names, List *parameters) (errmsg("changing return type of function %s from %s to %s", NameListToString(outputName), "opaque", "cstring"))); SetFunctionReturnType(outputOid, CSTRINGOID); + updated_output = true; } else ereport(ERROR, @@ -679,6 +683,25 @@ DefineType(ParseState *pstate, List *names, List *parameters) pfree(array_type); + /* + * If type of an OPAQUE function has been changed, add cross-dependencies + * with the new type created. + */ + if (updated_input) + { + ObjectAddress input_address; + + ObjectAddressSet(input_address, ProcedureRelationId, inputOid); + recordDependencyOn(&input_address, &address, DEPENDENCY_NORMAL); + } + if (updated_output) + { + ObjectAddress output_address; + + ObjectAddressSet(output_address, ProcedureRelationId, outputOid); + recordDependencyOn(&output_address, &address, DEPENDENCY_NORMAL); + } + return address; } diff --git a/src/test/regress/expected/create_type.out b/src/test/regress/expected/create_type.out index 7bdad4e9bb..b2fa8061f3 100644 --- a/src/test/regress/expected/create_type.out +++ b/src/test/regress/expected/create_type.out @@ -115,6 +115,31 @@ CREATE TYPE not_existing_type (INPUT = array_in, ELEMENT = int, INTERNALLENGTH = 32); ERROR: function array_out(not_existing_type) does not exist +-- Check dependency transfer of opaque functions when creating a new type +CREATE FUNCTION base_fn_in(cstring) RETURNS opaque AS 'boolin' + LANGUAGE internal IMMUTABLE STRICT; +CREATE FUNCTION base_fn_out(opaque) RETURNS opaque AS 'boolout' + LANGUAGE internal IMMUTABLE STRICT; +CREATE TYPE base_type(INPUT = base_fn_in, OUTPUT = base_fn_out); +WARNING: changing argument type of function base_fn_out from "opaque" to base_type +WARNING: changing return type of function base_fn_in from opaque to base_type +WARNING: changing return type of function base_fn_out from opaque to cstring +DROP FUNCTION base_fn_in(cstring); -- error +ERROR: cannot drop function base_fn_in(cstring) because other objects depend on it +DETAIL: type base_type depends on function base_fn_in(cstring) +function base_fn_out(base_type) depends on type base_type +HINT: Use DROP ... CASCADE to drop the dependent objects too. +DROP FUNCTION base_fn_out(opaque); -- error +ERROR: function base_fn_out(opaque) does not exist +DROP TYPE base_type; -- error +ERROR: cannot drop type base_type because other objects depend on it +DETAIL: function base_fn_in(cstring) depends on type base_type +function base_fn_out(base_type) depends on type base_type +HINT: Use DROP ... CASCADE to drop the dependent objects too. +DROP TYPE base_type CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to function base_fn_in(cstring) +drop cascades to function base_fn_out(base_type) -- Check usage of typmod with a user-defined type -- (we have borrowed numeric's typmod functions) CREATE TEMP TABLE mytab (foo widget(42,13,7)); -- should fail diff --git a/src/test/regress/sql/create_type.sql b/src/test/regress/sql/create_type.sql index a1839ef9e7..a28303aa6a 100644 --- a/src/test/regress/sql/create_type.sql +++ b/src/test/regress/sql/create_type.sql @@ -115,6 +115,17 @@ CREATE TYPE not_existing_type (INPUT = array_in, ELEMENT = int, INTERNALLENGTH = 32); +-- Check dependency transfer of opaque functions when creating a new type +CREATE FUNCTION base_fn_in(cstring) RETURNS opaque AS 'boolin' + LANGUAGE internal IMMUTABLE STRICT; +CREATE FUNCTION base_fn_out(opaque) RETURNS opaque AS 'boolout' + LANGUAGE internal IMMUTABLE STRICT; +CREATE TYPE base_type(INPUT = base_fn_in, OUTPUT = base_fn_out); +DROP FUNCTION base_fn_in(cstring); -- error +DROP FUNCTION base_fn_out(opaque); -- error +DROP TYPE base_type; -- error +DROP TYPE base_type CASCADE; + -- Check usage of typmod with a user-defined type -- (we have borrowed numeric's typmod functions)