diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c index e7ecc4ed7e..1235ac8019 100644 --- a/src/backend/commands/typecmds.c +++ b/src/backend/commands/typecmds.c @@ -87,8 +87,10 @@ Oid binary_upgrade_next_array_pg_type_oid = InvalidOid; static void makeRangeConstructors(const char *name, Oid namespace, Oid rangeOid, Oid subtype); -static Oid findTypeInputFunction(List *procname, Oid typeOid); -static Oid findTypeOutputFunction(List *procname, Oid typeOid); +static Oid findTypeInputFunction(List *procname, Oid typeOid, + bool *updatedType); +static Oid findTypeOutputFunction(List *procname, Oid typeOid, + bool *updatedType); static Oid findTypeReceiveFunction(List *procname, Oid typeOid); static Oid findTypeSendFunction(List *procname, Oid typeOid); static Oid findTypeTypmodinFunction(List *procname); @@ -165,6 +167,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 @@ -436,8 +440,8 @@ DefineType(ParseState *pstate, List *names, List *parameters) /* * Convert I/O proc names to OIDs */ - inputOid = findTypeInputFunction(inputName, typoid); - outputOid = findTypeOutputFunction(outputName, typoid); + inputOid = findTypeInputFunction(inputName, typoid, &updated_input); + outputOid = findTypeOutputFunction(outputName, typoid, &updated_output); if (receiveName) receiveOid = findTypeReceiveFunction(receiveName, typoid); if (sendName) @@ -457,6 +461,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 +479,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 +685,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; } @@ -1631,11 +1656,12 @@ makeRangeConstructors(const char *name, Oid namespace, * Find suitable I/O functions for a type. * * typeOid is the type's OID (which will already exist, if only as a shell - * type). + * type). updatedType tracks if the type of the function found has been + * changed. */ static Oid -findTypeInputFunction(List *procname, Oid typeOid) +findTypeInputFunction(List *procname, Oid typeOid, bool *updatedType) { Oid argList[3]; Oid procOid; @@ -1680,6 +1706,7 @@ findTypeInputFunction(List *procname, Oid typeOid) (errmsg("changing argument type of function %s from \"opaque\" to \"cstring\"", NameListToString(procname)))); SetFunctionArgType(procOid, 0, CSTRINGOID); + *updatedType = true; /* * Need CommandCounterIncrement since DefineType will likely try to @@ -1702,7 +1729,7 @@ findTypeInputFunction(List *procname, Oid typeOid) } static Oid -findTypeOutputFunction(List *procname, Oid typeOid) +findTypeOutputFunction(List *procname, Oid typeOid, bool *updatedType) { Oid argList[1]; Oid procOid; @@ -1731,6 +1758,7 @@ findTypeOutputFunction(List *procname, Oid typeOid) (errmsg("changing argument type of function %s from \"opaque\" to %s", NameListToString(procname), format_type_be(typeOid)))); SetFunctionArgType(procOid, 0, typeOid); + *updatedType = true; /* * Need CommandCounterIncrement since DefineType will likely try to diff --git a/src/test/regress/expected/create_type.out b/src/test/regress/expected/create_type.out index 7bdad4e9bb..ed539ec6d7 100644 --- a/src/test/regress/expected/create_type.out +++ b/src/test/regress/expected/create_type.out @@ -115,6 +115,76 @@ 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 type_arg_opaque_in(opaque) RETURNS opaque AS 'boolin' + LANGUAGE internal IMMUTABLE STRICT; +CREATE FUNCTION type_arg_opaque_out(opaque) RETURNS cstring AS 'boolout' + LANGUAGE internal IMMUTABLE STRICT; +CREATE FUNCTION type_return_opaque_in(cstring) RETURNS opaque AS 'boolin' + LANGUAGE internal IMMUTABLE STRICT; +CREATE FUNCTION type_return_opaque_out(opaque) RETURNS opaque AS 'boolout' + LANGUAGE internal IMMUTABLE STRICT; +CREATE TYPE type_arg_opaque(INPUT = type_arg_opaque_in, + OUTPUT = type_arg_opaque_out); +WARNING: changing argument type of function type_arg_opaque_in from "opaque" to "cstring" +WARNING: changing argument type of function type_arg_opaque_out from "opaque" to type_arg_opaque +WARNING: changing return type of function type_arg_opaque_in from opaque to type_arg_opaque +CREATE TYPE type_return_opaque(INPUT = type_return_opaque_in, + OUTPUT = type_return_opaque_out); +WARNING: changing argument type of function type_return_opaque_out from "opaque" to type_return_opaque +WARNING: changing return type of function type_return_opaque_in from opaque to type_return_opaque +WARNING: changing return type of function type_return_opaque_out from opaque to cstring +DROP FUNCTION type_arg_opaque_in; -- error +ERROR: cannot drop function type_arg_opaque_in(cstring) because other objects depend on it +DETAIL: type type_arg_opaque depends on function type_arg_opaque_in(cstring) +function type_arg_opaque_out(type_arg_opaque) depends on type type_arg_opaque +HINT: Use DROP ... CASCADE to drop the dependent objects too. +DROP FUNCTION type_arg_opaque_out; -- error +ERROR: cannot drop function type_arg_opaque_out(type_arg_opaque) because other objects depend on it +DETAIL: type type_arg_opaque depends on function type_arg_opaque_out(type_arg_opaque) +function type_arg_opaque_in(cstring) depends on type type_arg_opaque +HINT: Use DROP ... CASCADE to drop the dependent objects too. +DROP FUNCTION type_return_opaque_in; -- error +ERROR: cannot drop function type_return_opaque_in(cstring) because other objects depend on it +DETAIL: type type_return_opaque depends on function type_return_opaque_in(cstring) +function type_return_opaque_out(type_return_opaque) depends on type type_return_opaque +HINT: Use DROP ... CASCADE to drop the dependent objects too. +DROP FUNCTION type_return_opaque_out; -- error +ERROR: cannot drop function type_return_opaque_out(type_return_opaque) because other objects depend on it +DETAIL: type type_return_opaque depends on function type_return_opaque_out(type_return_opaque) +function type_return_opaque_in(cstring) depends on type type_return_opaque +HINT: Use DROP ... CASCADE to drop the dependent objects too. +DROP TYPE type_arg_opaque; -- error +ERROR: cannot drop type type_arg_opaque because other objects depend on it +DETAIL: function type_arg_opaque_in(cstring) depends on type type_arg_opaque +function type_arg_opaque_out(type_arg_opaque) depends on type type_arg_opaque +HINT: Use DROP ... CASCADE to drop the dependent objects too. +DROP TYPE type_return_opaque; -- error +ERROR: cannot drop type type_return_opaque because other objects depend on it +DETAIL: function type_return_opaque_in(cstring) depends on type type_return_opaque +function type_return_opaque_out(type_return_opaque) depends on type type_return_opaque +HINT: Use DROP ... CASCADE to drop the dependent objects too. +DROP TYPE type_arg_opaque CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to function type_arg_opaque_in(cstring) +drop cascades to function type_arg_opaque_out(type_arg_opaque) +DROP TYPE type_return_opaque CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to function type_return_opaque_in(cstring) +drop cascades to function type_return_opaque_out(type_return_opaque) +-- both should report no objects and work +\df type_arg* + List of functions + Schema | Name | Result data type | Argument data types | Type +--------+------+------------------+---------------------+------ +(0 rows) + +\df type_return* + List of functions + Schema | Name | Result data type | Argument data types | Type +--------+------+------------------+---------------------+------ +(0 rows) + -- 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..2c62fffbda 100644 --- a/src/test/regress/sql/create_type.sql +++ b/src/test/regress/sql/create_type.sql @@ -115,6 +115,31 @@ 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 type_arg_opaque_in(opaque) RETURNS opaque AS 'boolin' + LANGUAGE internal IMMUTABLE STRICT; +CREATE FUNCTION type_arg_opaque_out(opaque) RETURNS cstring AS 'boolout' + LANGUAGE internal IMMUTABLE STRICT; +CREATE FUNCTION type_return_opaque_in(cstring) RETURNS opaque AS 'boolin' + LANGUAGE internal IMMUTABLE STRICT; +CREATE FUNCTION type_return_opaque_out(opaque) RETURNS opaque AS 'boolout' + LANGUAGE internal IMMUTABLE STRICT; +CREATE TYPE type_arg_opaque(INPUT = type_arg_opaque_in, + OUTPUT = type_arg_opaque_out); +CREATE TYPE type_return_opaque(INPUT = type_return_opaque_in, + OUTPUT = type_return_opaque_out); +DROP FUNCTION type_arg_opaque_in; -- error +DROP FUNCTION type_arg_opaque_out; -- error +DROP FUNCTION type_return_opaque_in; -- error +DROP FUNCTION type_return_opaque_out; -- error +DROP TYPE type_arg_opaque; -- error +DROP TYPE type_return_opaque; -- error +DROP TYPE type_arg_opaque CASCADE; +DROP TYPE type_return_opaque CASCADE; +-- both should report no objects and work +\df type_arg* +\df type_return* + -- Check usage of typmod with a user-defined type -- (we have borrowed numeric's typmod functions)