]> granicus.if.org Git - postgresql/commitdiff
Fix dependency, when changing a function's argument/return type.
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>
Thu, 15 Jun 2017 07:42:10 +0000 (10:42 +0300)
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>
Fri, 16 Jun 2017 08:39:45 +0000 (11:39 +0300)
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

src/backend/commands/functioncmds.c
src/test/regress/expected/create_type.out
src/test/regress/sql/create_type.sql

index e161cd9fcd8e9e6feb87eebaafccdaedad558e49..6f8900ac4996d18432c9471c9383d7e933e9b667 100644 (file)
@@ -1318,6 +1318,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);
 
@@ -1338,6 +1340,14 @@ SetFunctionReturnType(Oid funcOid, Oid newRetType)
        CatalogUpdateIndexes(pg_proc_rel, 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);
 }
 
 
@@ -1352,6 +1362,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);
 
@@ -1373,6 +1385,14 @@ SetFunctionArgType(Oid funcOid, int argIndex, Oid newArgType)
        CatalogUpdateIndexes(pg_proc_rel, 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);
 }
 
 
index 7bdad4e9bb5e3c14d8807856fec2320aeaf43b00..5886a1f37f3d947289140b2c28bb9520c6e996e3 100644 (file)
@@ -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
index a1839ef9e7ff847dc5dfbd74d9249e517dd82255..a28303aa6a98c11066f894dc803d8dcb567d7b7f 100644 (file)
@@ -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)