summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>2017-06-15 10:42:10 +0300
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>2017-06-16 11:46:11 +0300
commitb47e2f7a94631c9dc8374339de2f668d898cd1c6 (patch)
tree7a88dd9af6b02d45c63058e9c141a1d45ee859d7 /src
parent99090e977d51107b25ba1670801975d6d1495d74 (diff)
downloadpostgresql-b47e2f7a94631c9dc8374339de2f668d898cd1c6.tar.gz
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
Diffstat (limited to 'src')
-rw-r--r--src/backend/commands/functioncmds.c32
-rw-r--r--src/test/regress/expected/create_type.out31
-rw-r--r--src/test/regress/sql/create_type.sql17
3 files changed, 80 insertions, 0 deletions
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index 53c4ab359d..93d1065198 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -1189,6 +1189,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);
@@ -1209,6 +1211,20 @@ 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.
+ */
+ type_address.classId = TypeRelationId;
+ type_address.objectId = newRetType;
+ type_address.objectSubId = 0;
+
+ func_address.classId = ProcedureRelationId;
+ func_address.objectId = funcOid;
+ func_address.objectSubId = 0;
+
+ recordDependencyOn(&func_address, &type_address, DEPENDENCY_NORMAL);
}
@@ -1223,6 +1239,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);
@@ -1244,6 +1262,20 @@ 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.
+ */
+ type_address.classId = TypeRelationId;
+ type_address.objectId = newArgType;
+ type_address.objectSubId = 0;
+
+ func_address.classId = ProcedureRelationId;
+ func_address.objectId = funcOid;
+ func_address.objectSubId = 0;
+
+ recordDependencyOn(&func_address, &type_address, DEPENDENCY_NORMAL);
}
diff --git a/src/test/regress/expected/create_type.out b/src/test/regress/expected/create_type.out
index 09459adc3f..670b03c624 100644
--- a/src/test/regress/expected/create_type.out
+++ b/src/test/regress/expected/create_type.out
@@ -109,6 +109,37 @@ ERROR: type "text_w_default" already exists
DROP TYPE default_test_row CASCADE;
NOTICE: drop cascades to function get_default_test()
DROP TABLE default_test;
+-- Check type create with input/output incompatibility
+CREATE TYPE not_existing_type (INPUT = array_in,
+ OUTPUT = array_out,
+ 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
diff --git a/src/test/regress/sql/create_type.sql b/src/test/regress/sql/create_type.sql
index 62bd53cfba..7297c077df 100644
--- a/src/test/regress/sql/create_type.sql
+++ b/src/test/regress/sql/create_type.sql
@@ -109,6 +109,23 @@ DROP TYPE default_test_row CASCADE;
DROP TABLE default_test;
+-- Check type create with input/output incompatibility
+CREATE TYPE not_existing_type (INPUT = array_in,
+ OUTPUT = array_out,
+ 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)