2000-01-05 07:06:23 +01:00
|
|
|
--
|
|
|
|
-- 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
|
1999-03-28 04:06:23 +02:00
|
|
|
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
|
1999-03-28 04:06:23 +02:00
|
|
|
NOT p1.typisdefined OR
|
|
|
|
(p1.typalign != 'c' AND p1.typalign != 's' AND
|
2002-04-25 04:56:56 +02:00
|
|
|
p1.typalign != 'i' AND p1.typalign != 'd') OR
|
|
|
|
(p1.typstorage != 'p' AND p1.typstorage != 'x' AND
|
|
|
|
p1.typstorage != 'e' AND p1.typstorage != 'm');
|
2000-01-05 07:06:23 +01:00
|
|
|
oid | typname
|
|
|
|
-----+---------
|
1999-03-28 04:06:23 +02:00
|
|
|
(0 rows)
|
|
|
|
|
2000-01-05 07:06:23 +01:00
|
|
|
-- Look for "pass by value" types that can't be passed by value.
|
|
|
|
SELECT p1.oid, p1.typname
|
1999-03-28 04:06:23 +02:00
|
|
|
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');
|
2000-01-05 07:06:23 +01:00
|
|
|
oid | typname
|
|
|
|
-----+---------
|
1999-03-28 04:06:23 +02:00
|
|
|
(0 rows)
|
|
|
|
|
2002-04-25 04:56:56 +02:00
|
|
|
-- 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)
|
|
|
|
|
2000-01-05 07:06:23 +01:00
|
|
|
-- Look for complex types that do not have a typrelid entry,
|
|
|
|
-- or basic types that do.
|
|
|
|
SELECT p1.oid, p1.typname
|
1999-03-28 04:06:23 +02:00
|
|
|
FROM pg_type as p1
|
|
|
|
WHERE (p1.typtype = 'c' AND p1.typrelid = 0) OR
|
|
|
|
(p1.typtype != 'c' AND p1.typrelid != 0);
|
2000-01-05 07:06:23 +01:00
|
|
|
oid | typname
|
|
|
|
-----+---------
|
1999-03-28 04:06:23 +02:00
|
|
|
(0 rows)
|
|
|
|
|
2002-04-25 04:56:56 +02:00
|
|
|
-- 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
|
2002-04-25 04:56:56 +02:00
|
|
|
(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)
|
|
|
|
|
2000-01-05 07:06:23 +01:00
|
|
|
-- Conversion routines must be provided except in 'c' entries.
|
|
|
|
SELECT p1.oid, p1.typname
|
1999-03-28 04:06:23 +02:00
|
|
|
FROM pg_type as p1
|
|
|
|
WHERE p1.typtype != 'c' AND
|
2002-07-24 21:11:14 +02:00
|
|
|
(p1.typinput = 0 OR p1.typoutput = 0);
|
2000-01-05 07:06:23 +01:00
|
|
|
oid | typname
|
|
|
|
-----+---------
|
1999-03-28 04:06:23 +02:00
|
|
|
(0 rows)
|
|
|
|
|
2000-01-05 07:06:23 +01:00
|
|
|
-- 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
|
1999-03-28 04:06:23 +02:00
|
|
|
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
|
2002-04-25 04:56:56 +02:00
|
|
|
(p2.pronargs != 3 OR p2.proretset OR p2.proargtypes[2] != 'int4'::regtype);
|
2000-01-05 07:06:23 +01:00
|
|
|
oid | typname | oid | proname
|
|
|
|
-----+---------+-----+---------
|
1999-03-28 04:06:23 +02:00
|
|
|
(0 rows)
|
|
|
|
|
2000-01-05 07:06:23 +01:00
|
|
|
-- 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
|
1999-03-28 04:06:23 +02:00
|
|
|
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);
|
2000-01-05 07:06:23 +01:00
|
|
|
oid | typname | oid | proname
|
|
|
|
-----+---------+-----+---------
|
1999-03-28 04:06:23 +02:00
|
|
|
(0 rows)
|
|
|
|
|
2000-01-05 07:06:23 +01:00
|
|
|
-- **************** pg_class ****************
|
|
|
|
-- Look for illegal values in pg_class fields
|
|
|
|
SELECT p1.oid, p1.relname
|
1999-03-28 04:06:23 +02:00
|
|
|
FROM pg_class as p1
|
2000-09-12 06:49:17 +02:00
|
|
|
WHERE p1.relkind NOT IN ('r', 'i', 's', 'S', 't', 'v');
|
2000-01-05 07:06:23 +01:00
|
|
|
oid | relname
|
|
|
|
-----+---------
|
1999-03-28 04:06:23 +02:00
|
|
|
(0 rows)
|
|
|
|
|
2000-01-05 07:06:23 +01:00
|
|
|
-- Indexes should have an access method, others not.
|
|
|
|
SELECT p1.oid, p1.relname
|
1999-03-28 04:06:23 +02:00
|
|
|
FROM pg_class as p1
|
|
|
|
WHERE (p1.relkind = 'i' AND p1.relam = 0) OR
|
|
|
|
(p1.relkind != 'i' AND p1.relam != 0);
|
2000-01-05 07:06:23 +01:00
|
|
|
oid | relname
|
|
|
|
-----+---------
|
1999-03-28 04:06:23 +02:00
|
|
|
(0 rows)
|
|
|
|
|
2000-01-05 07:06:23 +01:00
|
|
|
-- **************** pg_attribute ****************
|
|
|
|
-- Look for illegal values in pg_attribute fields
|
2001-08-10 20:57:42 +02:00
|
|
|
SELECT p1.attrelid, p1.attname
|
1999-03-28 04:06:23 +02:00
|
|
|
FROM pg_attribute as p1
|
|
|
|
WHERE p1.attrelid = 0 OR p1.atttypid = 0 OR p1.attnum = 0 OR
|
|
|
|
p1.attcacheoff != -1;
|
2001-08-10 20:57:42 +02:00
|
|
|
attrelid | attname
|
|
|
|
----------+---------
|
1999-03-28 04:06:23 +02:00
|
|
|
(0 rows)
|
|
|
|
|
2000-01-05 07:06:23 +01:00
|
|
|
-- Cross-check attnum against parent relation
|
2001-08-10 20:57:42 +02:00
|
|
|
SELECT p1.attrelid, p1.attname, p2.oid, p2.relname
|
1999-03-28 04:06:23 +02:00
|
|
|
FROM pg_attribute AS p1, pg_class AS p2
|
|
|
|
WHERE p1.attrelid = p2.oid AND p1.attnum > p2.relnatts;
|
2001-08-10 20:57:42 +02:00
|
|
|
attrelid | attname | oid | relname
|
|
|
|
----------+---------+-----+---------
|
1999-03-28 04:06:23 +02:00
|
|
|
(0 rows)
|
|
|
|
|
2000-01-05 07:06:23 +01:00
|
|
|
-- Detect missing pg_attribute entries: should have as many non-system
|
|
|
|
-- attributes as parent relation expects
|
|
|
|
SELECT p1.oid, p1.relname
|
1999-03-28 04:06:23 +02:00
|
|
|
FROM pg_class AS p1
|
|
|
|
WHERE p1.relnatts != (SELECT count(*) FROM pg_attribute AS p2
|
|
|
|
WHERE p2.attrelid = p1.oid AND p2.attnum > 0);
|
2000-01-05 07:06:23 +01:00
|
|
|
oid | relname
|
|
|
|
-----+---------
|
1999-03-28 04:06:23 +02:00
|
|
|
(0 rows)
|
|
|
|
|
2000-01-05 07:06:23 +01:00
|
|
|
-- Cross-check against pg_type entry
|
2002-04-25 04:56:56 +02:00
|
|
|
-- NOTE: we allow attstorage to be 'plain' even when typstorage is not;
|
|
|
|
-- this is mainly for toast tables.
|
2001-08-10 20:57:42 +02:00
|
|
|
SELECT p1.attrelid, p1.attname, p2.oid, p2.typname
|
1999-03-28 04:06:23 +02:00
|
|
|
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
|
2002-04-25 04:56:56 +02:00
|
|
|
p1.attbyval != p2.typbyval OR
|
|
|
|
(p1.attstorage != p2.typstorage AND p1.attstorage != 'p'));
|
2001-08-10 20:57:42 +02:00
|
|
|
attrelid | attname | oid | typname
|
|
|
|
----------+---------+-----+---------
|
1999-03-28 04:06:23 +02:00
|
|
|
(0 rows)
|
|
|
|
|