postgresql/src/test/regress/expected/type_sanity.out

179 lines
5.7 KiB
Plaintext
Raw Normal View History

--
-- TYPE_SANITY
-- Sanity checks for common errors in making type-related system tables:
-- pg_type, pg_class, pg_attribute.
--
-- None of the SELECTs here should ever find any matching entries,
-- so the expected output is easy to maintain ;-).
-- A test failure indicates someone messed up an entry in the system tables.
--
-- NB: we assume the oidjoins test will have caught any dangling links,
-- that is OID or REGPROC fields that are not zero and do not match some
-- row in the linked-to table. However, if we want to enforce that a link
-- field can't be 0, we have to check it here.
-- **************** pg_type ****************
-- Look for illegal values in pg_type fields.
SELECT p1.oid, p1.typname
FROM pg_type as p1
WHERE (p1.typlen <= 0 AND p1.typlen != -1) OR
Attached are two patches to implement and document anonymous composite types for Table Functions, as previously proposed on HACKERS. Here is a brief explanation: 1. Creates a new pg_type typtype: 'p' for pseudo type (currently either 'b' for base or 'c' for catalog, i.e. a class). 2. Creates new builtin type of typtype='p' named RECORD. This is the first of potentially several pseudo types. 3. Modify FROM clause grammer to accept: SELECT * FROM my_func() AS m(colname1 type1, colname2 type1, ...) where m is the table alias, colname1, etc are the column names, and type1, etc are the column types. 4. When typtype == 'p' and the function return type is RECORD, a list of column defs is required, and when typtype != 'p', it is disallowed. 5. A check was added to ensure that the tupdesc provide via the parser and the actual return tupdesc match in number and type of attributes. When creating a function you can do: CREATE FUNCTION foo(text) RETURNS setof RECORD ... When using it you can do: SELECT * from foo(sqlstmt) AS (f1 int, f2 text, f3 timestamp) or SELECT * from foo(sqlstmt) AS f(f1 int, f2 text, f3 timestamp) or SELECT * from foo(sqlstmt) f(f1 int, f2 text, f3 timestamp) Included in the patches are adjustments to the regression test sql and expected files, and documentation. p.s. This potentially solves (or at least improves) the issue of builtin Table Functions. They can be bootstrapped as returning RECORD, and we can wrap system views around them with properly specified column defs. For example: CREATE VIEW pg_settings AS SELECT s.name, s.setting FROM show_all_settings()AS s(name text, setting text); Then we can also add the UPDATE RULE that I previously posted to pg_settings, and have pg_settings act like a virtual table, allowing settings to be queried and set. Joe Conway
2002-08-04 21:48:11 +02:00
(p1.typtype != 'b' AND p1.typtype != 'c' AND p1.typtype != 'p') OR
NOT p1.typisdefined OR
(p1.typalign != 'c' AND p1.typalign != 's' AND
p1.typalign != 'i' AND p1.typalign != 'd') OR
(p1.typstorage != 'p' AND p1.typstorage != 'x' AND
p1.typstorage != 'e' AND p1.typstorage != 'm');
oid | typname
-----+---------
(0 rows)
-- Look for "pass by value" types that can't be passed by value.
SELECT p1.oid, p1.typname
FROM pg_type as p1
WHERE p1.typbyval AND
(p1.typlen != 1 OR p1.typalign != 'c') AND
(p1.typlen != 2 OR p1.typalign != 's') AND
(p1.typlen != 4 OR p1.typalign != 'i');
oid | typname
-----+---------
(0 rows)
-- Look for "toastable" types that aren't varlena.
SELECT p1.oid, p1.typname
FROM pg_type as p1
WHERE p1.typstorage != 'p' AND
(p1.typbyval OR p1.typlen != -1);
oid | typname
-----+---------
(0 rows)
-- Look for complex types that do not have a typrelid entry,
-- or basic types that do.
SELECT p1.oid, p1.typname
FROM pg_type as p1
WHERE (p1.typtype = 'c' AND p1.typrelid = 0) OR
(p1.typtype != 'c' AND p1.typrelid != 0);
oid | typname
-----+---------
(0 rows)
-- Look for basic types that don't have an array type.
-- NOTE: as of 7.3, this check finds SET, smgr, and unknown.
SELECT p1.oid, p1.typname
FROM pg_type as p1
Attached are two patches to implement and document anonymous composite types for Table Functions, as previously proposed on HACKERS. Here is a brief explanation: 1. Creates a new pg_type typtype: 'p' for pseudo type (currently either 'b' for base or 'c' for catalog, i.e. a class). 2. Creates new builtin type of typtype='p' named RECORD. This is the first of potentially several pseudo types. 3. Modify FROM clause grammer to accept: SELECT * FROM my_func() AS m(colname1 type1, colname2 type1, ...) where m is the table alias, colname1, etc are the column names, and type1, etc are the column types. 4. When typtype == 'p' and the function return type is RECORD, a list of column defs is required, and when typtype != 'p', it is disallowed. 5. A check was added to ensure that the tupdesc provide via the parser and the actual return tupdesc match in number and type of attributes. When creating a function you can do: CREATE FUNCTION foo(text) RETURNS setof RECORD ... When using it you can do: SELECT * from foo(sqlstmt) AS (f1 int, f2 text, f3 timestamp) or SELECT * from foo(sqlstmt) AS f(f1 int, f2 text, f3 timestamp) or SELECT * from foo(sqlstmt) f(f1 int, f2 text, f3 timestamp) Included in the patches are adjustments to the regression test sql and expected files, and documentation. p.s. This potentially solves (or at least improves) the issue of builtin Table Functions. They can be bootstrapped as returning RECORD, and we can wrap system views around them with properly specified column defs. For example: CREATE VIEW pg_settings AS SELECT s.name, s.setting FROM show_all_settings()AS s(name text, setting text); Then we can also add the UPDATE RULE that I previously posted to pg_settings, and have pg_settings act like a virtual table, allowing settings to be queried and set. Joe Conway
2002-08-04 21:48:11 +02:00
WHERE p1.typtype = 'b' AND p1.typname NOT LIKE '\\_%' AND NOT EXISTS
(SELECT 1 FROM pg_type as p2
WHERE p2.typname = ('_' || p1.typname)::name AND
p2.typelem = p1.oid);
oid | typname
-----+---------
32 | SET
210 | smgr
705 | unknown
(3 rows)
-- Look for array types that don't have an equality operator.
SELECT p1.oid, p1.typname
FROM pg_type as p1
WHERE p1.typtype != 'c' AND p1.typname LIKE '\\_%' AND NOT EXISTS
(SELECT 1 FROM pg_operator
WHERE oprname = '=' AND oprleft = p1.oid AND oprright = p1.oid);
oid | typname
-----+---------
(0 rows)
-- Conversion routines must be provided except in 'c' entries.
SELECT p1.oid, p1.typname
FROM pg_type as p1
WHERE p1.typtype != 'c' AND
(p1.typinput = 0 OR p1.typoutput = 0);
oid | typname
-----+---------
(0 rows)
-- Check for bogus typinput routines
-- FIXME: ought to check prorettype, but there are special cases that make it
-- hard: prorettype might be binary-compatible with the type but not the same,
-- and for array types array_in's result has nothing to do with anything.
SELECT p1.oid, p1.typname, p2.oid, p2.proname
FROM pg_type AS p1, pg_proc AS p2
WHERE p1.typinput = p2.oid AND p1.typtype = 'b' AND
(p2.pronargs != 1 OR p2.proretset) AND
(p2.pronargs != 3 OR p2.proretset OR p2.proargtypes[2] != 'int4'::regtype);
oid | typname | oid | proname
-----+---------+-----+---------
(0 rows)
-- Check for bogus typoutput routines
-- The first OR subclause detects bogus non-array cases,
-- the second one detects bogus array cases.
-- FIXME: ought to check prorettype, but not clear what it should be.
SELECT p1.oid, p1.typname, p2.oid, p2.proname
FROM pg_type AS p1, pg_proc AS p2
WHERE p1.typoutput = p2.oid AND p1.typtype = 'b' AND
(p2.pronargs != 1 OR p2.proretset) AND
(p2.pronargs != 2 OR p2.proretset OR p1.typelem = 0);
oid | typname | oid | proname
-----+---------+-----+---------
(0 rows)
-- **************** pg_class ****************
-- Look for illegal values in pg_class fields
SELECT p1.oid, p1.relname
FROM pg_class as p1
WHERE p1.relkind NOT IN ('r', 'i', 's', 'S', 't', 'v');
oid | relname
-----+---------
(0 rows)
-- Indexes should have an access method, others not.
SELECT p1.oid, p1.relname
FROM pg_class as p1
WHERE (p1.relkind = 'i' AND p1.relam = 0) OR
(p1.relkind != 'i' AND p1.relam != 0);
oid | relname
-----+---------
(0 rows)
-- **************** pg_attribute ****************
-- Look for illegal values in pg_attribute fields
SELECT p1.attrelid, p1.attname
FROM pg_attribute as p1
WHERE p1.attrelid = 0 OR p1.atttypid = 0 OR p1.attnum = 0 OR
p1.attcacheoff != -1;
attrelid | attname
----------+---------
(0 rows)
-- Cross-check attnum against parent relation
SELECT p1.attrelid, p1.attname, p2.oid, p2.relname
FROM pg_attribute AS p1, pg_class AS p2
WHERE p1.attrelid = p2.oid AND p1.attnum > p2.relnatts;
attrelid | attname | oid | relname
----------+---------+-----+---------
(0 rows)
-- Detect missing pg_attribute entries: should have as many non-system
-- attributes as parent relation expects
SELECT p1.oid, p1.relname
FROM pg_class AS p1
WHERE p1.relnatts != (SELECT count(*) FROM pg_attribute AS p2
WHERE p2.attrelid = p1.oid AND p2.attnum > 0);
oid | relname
-----+---------
(0 rows)
-- Cross-check against pg_type entry
-- NOTE: we allow attstorage to be 'plain' even when typstorage is not;
-- this is mainly for toast tables.
SELECT p1.attrelid, p1.attname, p2.oid, p2.typname
FROM pg_attribute AS p1, pg_type AS p2
WHERE p1.atttypid = p2.oid AND
(p1.attlen != p2.typlen OR
p1.attalign != p2.typalign OR
p1.attbyval != p2.typbyval OR
(p1.attstorage != p2.typstorage AND p1.attstorage != 'p'));
attrelid | attname | oid | typname
----------+---------+-----+---------
(0 rows)