From a1a233af66ed14d225ac2d5e7948a5cc8ed2cde6 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Fri, 18 Nov 2011 18:23:55 -0500 Subject: Further review of range-types patch. Lots of documentation cleanup today, and still more type_sanity tests. --- src/bin/pg_dump/pg_dump.c | 10 ++-- src/bin/pg_dump/pg_dump_sort.c | 7 +-- src/include/catalog/pg_range.h | 2 +- src/include/catalog/pg_type.h | 5 +- src/test/regress/expected/type_sanity.out | 79 +++++++++++++++++++++++++++++-- src/test/regress/sql/type_sanity.sql | 47 ++++++++++++++++-- 6 files changed, 131 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 973f0b335d7..d2005c1e809 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -2986,7 +2986,8 @@ getTypes(int *numTypes) /* * If it's a base type, make a DumpableObject representing a shell * definition of the type. We will need to dump that ahead of the I/O - * functions for the type. + * functions for the type. Similarly, range types need a shell + * definition in case they have a canonicalize function. * * Note: the shell type doesn't have a catId. You might think it * should copy the base type's catId, but then it might capture the @@ -3006,8 +3007,8 @@ getTypes(int *numTypes) /* * Initially mark the shell type as not to be dumped. We'll only - * dump it if the I/O functions need to be dumped; this is taken - * care of while sorting dependencies. + * dump it if the I/O or canonicalize functions need to be dumped; + * this is taken care of while sorting dependencies. */ stinfo->dobj.dump = false; @@ -7340,6 +7341,9 @@ dumpType(Archive *fout, TypeInfo *tyinfo) dumpEnumType(fout, tyinfo); else if (tyinfo->typtype == TYPTYPE_RANGE) dumpRangeType(fout, tyinfo); + else + write_msg(NULL, "WARNING: typtype of data type \"%s\" appears to be invalid\n", + tyinfo->dobj.name); } /* diff --git a/src/bin/pg_dump/pg_dump_sort.c b/src/bin/pg_dump/pg_dump_sort.c index efde0d0026b..6b6c073eb6a 100644 --- a/src/bin/pg_dump/pg_dump_sort.c +++ b/src/bin/pg_dump/pg_dump_sort.c @@ -636,7 +636,8 @@ findLoop(DumpableObject *obj, /* * A user-defined datatype will have a dependency loop with each of its * I/O functions (since those have the datatype as input or output). - * Break the loop and make the I/O function depend on the associated + * Similarly, a range type will have a loop with its canonicalize function, + * if any. Break the loop by making the function depend on the associated * shell type, instead. */ static void @@ -651,7 +652,7 @@ repairTypeFuncLoop(DumpableObject *typeobj, DumpableObject *funcobj) if (typeInfo->shellType) { addObjectDependency(funcobj, typeInfo->shellType->dobj.dumpId); - /* Mark shell type as to be dumped if any I/O function is */ + /* Mark shell type as to be dumped if any such function is */ if (funcobj->dump) typeInfo->shellType->dobj.dump = true; } @@ -789,7 +790,7 @@ repairDependencyLoop(DumpableObject **loop, int i, j; - /* Datatype and one of its I/O functions */ + /* Datatype and one of its I/O or canonicalize functions */ if (nLoop == 2 && loop[0]->objType == DO_TYPE && loop[1]->objType == DO_FUNC) diff --git a/src/include/catalog/pg_range.h b/src/include/catalog/pg_range.h index cc9ba293c14..4fbde166b39 100644 --- a/src/include/catalog/pg_range.h +++ b/src/include/catalog/pg_range.h @@ -34,7 +34,7 @@ CATALOG(pg_range,3541) BKI_WITHOUT_OIDS { Oid rngtypid; /* OID of owning range type */ - Oid rngsubtype; /* OID of range's subtype */ + Oid rngsubtype; /* OID of range's element type (subtype) */ Oid rngcollation; /* collation for this range type, or 0 */ Oid rngsubopc; /* subtype's btree opclass */ regproc rngcanonical; /* canonicalize range, or 0 */ diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h index 1806985b69a..f2a32507908 100644 --- a/src/include/catalog/pg_type.h +++ b/src/include/catalog/pg_type.h @@ -61,8 +61,9 @@ CATALOG(pg_type,1247) BKI_BOOTSTRAP BKI_ROWTYPE_OID(71) BKI_SCHEMA_MACRO /* * typtype is 'b' for a base type, 'c' for a composite type (e.g., a - * table's rowtype), 'd' for a domain type, 'e' for an enum type, or 'p' - * for a pseudo-type. (Use the TYPTYPE macros below.) + * table's rowtype), 'd' for a domain, 'e' for an enum type, + * 'p' for a pseudo-type, or 'r' for a range type. + * (Use the TYPTYPE macros below.) * * If typtype is 'c', typrelid is the OID of the class' entry in pg_class. */ diff --git a/src/test/regress/expected/type_sanity.out b/src/test/regress/expected/type_sanity.out index 19d437ade50..0e1dfd84861 100644 --- a/src/test/regress/expected/type_sanity.out +++ b/src/test/regress/expected/type_sanity.out @@ -56,11 +56,14 @@ WHERE (p1.typtype = 'c' AND p1.typrelid = 0) OR -----+--------- (0 rows) --- Look for basic or enum types that don't have an array type. +-- Look for types that should have an array type according to their typtype, +-- but don't. We exclude composites here because we have not bothered to +-- make array types corresponding to the system catalogs' rowtypes. -- NOTE: as of 9.1, this check finds pg_node_tree, smgr, and unknown. SELECT p1.oid, p1.typname FROM pg_type as p1 -WHERE p1.typtype in ('b','e') AND p1.typname NOT LIKE E'\\_%' AND NOT EXISTS +WHERE p1.typtype not in ('c','d','p') AND p1.typname NOT LIKE E'\\_%' + AND NOT EXISTS (SELECT 1 FROM pg_type as p2 WHERE p2.typname = ('_' || p1.typname)::name AND p2.typelem = p1.oid and p1.typarray = p2.oid); @@ -150,6 +153,19 @@ ORDER BY 1; 30 | oidvector | 54 | oidvectorin (2 rows) +-- Composites, domains, enums, ranges should all use the same input routines +SELECT DISTINCT typtype, typinput +FROM pg_type AS p1 +WHERE p1.typtype not in ('b', 'p') +ORDER BY 1; + typtype | typinput +---------+----------- + c | record_in + d | domain_in + e | enum_in + r | range_in +(4 rows) + -- Check for bogus typoutput routines -- As of 8.0, this check finds refcursor, which is borrowing -- other types' I/O routines @@ -174,6 +190,26 @@ WHERE p1.typoutput = p2.oid AND p1.typtype in ('b', 'p') AND NOT -----+---------+-----+--------- (0 rows) +-- Composites, enums, ranges should all use the same output routines +SELECT DISTINCT typtype, typoutput +FROM pg_type AS p1 +WHERE p1.typtype not in ('b', 'd', 'p') +ORDER BY 1; + typtype | typoutput +---------+------------ + c | record_out + e | enum_out + r | range_out +(3 rows) + +-- Domains should have same typoutput as their base types +SELECT p1.oid, p1.typname, p2.oid, p2.typname +FROM pg_type AS p1 LEFT JOIN pg_type AS p2 ON p1.typbasetype = p2.oid +WHERE p1.typtype = 'd' AND p1.typoutput IS DISTINCT FROM p2.typoutput; + oid | typname | oid | typname +-----+---------+-----+--------- +(0 rows) + -- Check for bogus typreceive routines SELECT p1.oid, p1.typname, p2.oid, p2.proname FROM pg_type AS p1, pg_proc AS p2 @@ -222,6 +258,19 @@ WHERE p1.typinput = p2.oid AND p1.typreceive = p3.oid AND -----+---------+-----+---------+-----+--------- (0 rows) +-- Composites, domains, enums, ranges should all use the same receive routines +SELECT DISTINCT typtype, typreceive +FROM pg_type AS p1 +WHERE p1.typtype not in ('b', 'p') +ORDER BY 1; + typtype | typreceive +---------+------------- + c | record_recv + d | domain_recv + e | enum_recv + r | range_recv +(4 rows) + -- Check for bogus typsend routines -- As of 7.4, this check finds refcursor, which is borrowing -- other types' I/O routines @@ -246,10 +295,30 @@ WHERE p1.typsend = p2.oid AND p1.typtype in ('b', 'p') AND NOT -----+---------+-----+--------- (0 rows) +-- Composites, enums, ranges should all use the same send routines +SELECT DISTINCT typtype, typsend +FROM pg_type AS p1 +WHERE p1.typtype not in ('b', 'd', 'p') +ORDER BY 1; + typtype | typsend +---------+------------- + c | record_send + e | enum_send + r | range_send +(3 rows) + +-- Domains should have same typsend as their base types +SELECT p1.oid, p1.typname, p2.oid, p2.typname +FROM pg_type AS p1 LEFT JOIN pg_type AS p2 ON p1.typbasetype = p2.oid +WHERE p1.typtype = 'd' AND p1.typsend IS DISTINCT FROM p2.typsend; + oid | typname | oid | typname +-----+---------+-----+--------- +(0 rows) + -- Check for bogus typmodin routines SELECT p1.oid, p1.typname, p2.oid, p2.proname FROM pg_type AS p1, pg_proc AS p2 -WHERE p1.typmodin = p2.oid AND p1.typtype in ('b', 'p') AND NOT +WHERE p1.typmodin = p2.oid AND NOT (p2.pronargs = 1 AND p2.proargtypes[0] = 'cstring[]'::regtype AND p2.prorettype = 'int4'::regtype AND NOT p2.proretset); @@ -260,7 +329,7 @@ WHERE p1.typmodin = p2.oid AND p1.typtype in ('b', 'p') AND NOT -- Check for bogus typmodout routines SELECT p1.oid, p1.typname, p2.oid, p2.proname FROM pg_type AS p1, pg_proc AS p2 -WHERE p1.typmodout = p2.oid AND p1.typtype in ('b', 'p') AND NOT +WHERE p1.typmodout = p2.oid AND NOT (p2.pronargs = 1 AND p2.proargtypes[0] = 'int4'::regtype AND p2.prorettype = 'cstring'::regtype AND NOT p2.proretset); @@ -298,7 +367,7 @@ WHERE p1.typarray = p2.oid AND -- Check for bogus typanalyze routines SELECT p1.oid, p1.typname, p2.oid, p2.proname FROM pg_type AS p1, pg_proc AS p2 -WHERE p1.typanalyze = p2.oid AND p1.typtype in ('b', 'p') AND NOT +WHERE p1.typanalyze = p2.oid AND NOT (p2.pronargs = 1 AND p2.proargtypes[0] = 'internal'::regtype AND p2.prorettype = 'bool'::regtype AND NOT p2.proretset); diff --git a/src/test/regress/sql/type_sanity.sql b/src/test/regress/sql/type_sanity.sql index d7d9cea5dc5..c6a70ad14c5 100644 --- a/src/test/regress/sql/type_sanity.sql +++ b/src/test/regress/sql/type_sanity.sql @@ -50,12 +50,15 @@ FROM pg_type as p1 WHERE (p1.typtype = 'c' AND p1.typrelid = 0) OR (p1.typtype != 'c' AND p1.typrelid != 0); --- Look for basic or enum types that don't have an array type. +-- Look for types that should have an array type according to their typtype, +-- but don't. We exclude composites here because we have not bothered to +-- make array types corresponding to the system catalogs' rowtypes. -- NOTE: as of 9.1, this check finds pg_node_tree, smgr, and unknown. SELECT p1.oid, p1.typname FROM pg_type as p1 -WHERE p1.typtype in ('b','e') AND p1.typname NOT LIKE E'\\_%' AND NOT EXISTS +WHERE p1.typtype not in ('c','d','p') AND p1.typname NOT LIKE E'\\_%' + AND NOT EXISTS (SELECT 1 FROM pg_type as p2 WHERE p2.typname = ('_' || p1.typname)::name AND p2.typelem = p1.oid and p1.typarray = p2.oid); @@ -117,6 +120,12 @@ WHERE p1.typinput = p2.oid AND p1.typtype in ('b', 'p') AND (p2.oid = 'array_in'::regproc) ORDER BY 1; +-- Composites, domains, enums, ranges should all use the same input routines +SELECT DISTINCT typtype, typinput +FROM pg_type AS p1 +WHERE p1.typtype not in ('b', 'p') +ORDER BY 1; + -- Check for bogus typoutput routines -- As of 8.0, this check finds refcursor, which is borrowing @@ -135,6 +144,17 @@ FROM pg_type AS p1, pg_proc AS p2 WHERE p1.typoutput = p2.oid AND p1.typtype in ('b', 'p') AND NOT (p2.prorettype = 'cstring'::regtype AND NOT p2.proretset); +-- Composites, enums, ranges should all use the same output routines +SELECT DISTINCT typtype, typoutput +FROM pg_type AS p1 +WHERE p1.typtype not in ('b', 'd', 'p') +ORDER BY 1; + +-- Domains should have same typoutput as their base types +SELECT p1.oid, p1.typname, p2.oid, p2.typname +FROM pg_type AS p1 LEFT JOIN pg_type AS p2 ON p1.typbasetype = p2.oid +WHERE p1.typtype = 'd' AND p1.typoutput IS DISTINCT FROM p2.typoutput; + -- Check for bogus typreceive routines SELECT p1.oid, p1.typname, p2.oid, p2.proname @@ -169,6 +189,12 @@ FROM pg_type AS p1, pg_proc AS p2, pg_proc AS p3 WHERE p1.typinput = p2.oid AND p1.typreceive = p3.oid AND p2.pronargs != p3.pronargs; +-- Composites, domains, enums, ranges should all use the same receive routines +SELECT DISTINCT typtype, typreceive +FROM pg_type AS p1 +WHERE p1.typtype not in ('b', 'p') +ORDER BY 1; + -- Check for bogus typsend routines -- As of 7.4, this check finds refcursor, which is borrowing @@ -187,11 +213,22 @@ FROM pg_type AS p1, pg_proc AS p2 WHERE p1.typsend = p2.oid AND p1.typtype in ('b', 'p') AND NOT (p2.prorettype = 'bytea'::regtype AND NOT p2.proretset); +-- Composites, enums, ranges should all use the same send routines +SELECT DISTINCT typtype, typsend +FROM pg_type AS p1 +WHERE p1.typtype not in ('b', 'd', 'p') +ORDER BY 1; + +-- Domains should have same typsend as their base types +SELECT p1.oid, p1.typname, p2.oid, p2.typname +FROM pg_type AS p1 LEFT JOIN pg_type AS p2 ON p1.typbasetype = p2.oid +WHERE p1.typtype = 'd' AND p1.typsend IS DISTINCT FROM p2.typsend; + -- Check for bogus typmodin routines SELECT p1.oid, p1.typname, p2.oid, p2.proname FROM pg_type AS p1, pg_proc AS p2 -WHERE p1.typmodin = p2.oid AND p1.typtype in ('b', 'p') AND NOT +WHERE p1.typmodin = p2.oid AND NOT (p2.pronargs = 1 AND p2.proargtypes[0] = 'cstring[]'::regtype AND p2.prorettype = 'int4'::regtype AND NOT p2.proretset); @@ -200,7 +237,7 @@ WHERE p1.typmodin = p2.oid AND p1.typtype in ('b', 'p') AND NOT SELECT p1.oid, p1.typname, p2.oid, p2.proname FROM pg_type AS p1, pg_proc AS p2 -WHERE p1.typmodout = p2.oid AND p1.typtype in ('b', 'p') AND NOT +WHERE p1.typmodout = p2.oid AND NOT (p2.pronargs = 1 AND p2.proargtypes[0] = 'int4'::regtype AND p2.prorettype = 'cstring'::regtype AND NOT p2.proretset); @@ -230,7 +267,7 @@ WHERE p1.typarray = p2.oid AND SELECT p1.oid, p1.typname, p2.oid, p2.proname FROM pg_type AS p1, pg_proc AS p2 -WHERE p1.typanalyze = p2.oid AND p1.typtype in ('b', 'p') AND NOT +WHERE p1.typanalyze = p2.oid AND NOT (p2.pronargs = 1 AND p2.proargtypes[0] = 'internal'::regtype AND p2.prorettype = 'bool'::regtype AND NOT p2.proretset); -- cgit v1.2.3