Commit 30681c83 authored by Heikki Linnakangas's avatar Heikki Linnakangas

Fix dependency, when changing a function's argument/return type.

When a new base type is created using the old-style procedure of first
creating the input/output functions with "opaque" in place of the base
type, the "opaque" argument/return type is changed to the final base type,
on CREATE TYPE. However, we did not create a pg_depend record when doing
that, so the functions were left not depending on the type.

Fixes bug #14706, reported by Karen Huddleston.

Discussion: https://www.postgresql.org/message-id/20170614232259.1424.82774@wrigleys.postgresql.org
parent 39ac5591
......@@ -1316,6 +1316,8 @@ SetFunctionReturnType(Oid funcOid, Oid newRetType)
Relation pg_proc_rel;
HeapTuple tup;
Form_pg_proc procForm;
ObjectAddress func_address;
ObjectAddress type_address;
pg_proc_rel = heap_open(ProcedureRelationId, RowExclusiveLock);
......@@ -1334,6 +1336,14 @@ SetFunctionReturnType(Oid funcOid, Oid newRetType)
CatalogTupleUpdate(pg_proc_rel, &tup->t_self, tup);
heap_close(pg_proc_rel, RowExclusiveLock);
/*
* Also update the dependency to the new type. Opaque is a pinned type, so
* there is no old dependency record for it that we would need to remove.
*/
ObjectAddressSet(type_address, TypeRelationId, newRetType);
ObjectAddressSet(func_address, ProcedureRelationId, funcOid);
recordDependencyOn(&func_address, &type_address, DEPENDENCY_NORMAL);
}
......@@ -1348,6 +1358,8 @@ SetFunctionArgType(Oid funcOid, int argIndex, Oid newArgType)
Relation pg_proc_rel;
HeapTuple tup;
Form_pg_proc procForm;
ObjectAddress func_address;
ObjectAddress type_address;
pg_proc_rel = heap_open(ProcedureRelationId, RowExclusiveLock);
......@@ -1367,6 +1379,14 @@ SetFunctionArgType(Oid funcOid, int argIndex, Oid newArgType)
CatalogTupleUpdate(pg_proc_rel, &tup->t_self, tup);
heap_close(pg_proc_rel, RowExclusiveLock);
/*
* Also update the dependency to the new type. Opaque is a pinned type, so
* there is no old dependency record for it that we would need to remove.
*/
ObjectAddressSet(type_address, TypeRelationId, newArgType);
ObjectAddressSet(func_address, ProcedureRelationId, funcOid);
recordDependencyOn(&func_address, &type_address, DEPENDENCY_NORMAL);
}
......
......@@ -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_out(base_type) depends on type base_type
function base_fn_in(cstring) 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_out(base_type)
drop cascades to function base_fn_in(cstring)
-- 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
......
......@@ -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)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment