2000-01-05 07:06:23 +01:00
|
|
|
--
|
|
|
|
-- TYPE_SANITY
|
|
|
|
-- Sanity checks for common errors in making type-related system tables:
|
2011-11-17 00:21:34 +01:00
|
|
|
-- pg_type, pg_class, pg_attribute, pg_range.
|
2000-01-05 07:06:23 +01:00
|
|
|
--
|
|
|
|
-- 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
|
2002-08-22 02:01:51 +02:00
|
|
|
WHERE p1.typnamespace = 0 OR
|
2002-08-24 17:00:47 +02:00
|
|
|
(p1.typlen <= 0 AND p1.typlen != -1 AND p1.typlen != -2) OR
|
2011-11-03 12:16:28 +01:00
|
|
|
(p1.typtype not in ('b', 'c', 'd', 'e', 'p', 'r')) OR
|
1999-03-28 04:06:23 +02:00
|
|
|
NOT p1.typisdefined OR
|
2002-08-22 02:01:51 +02:00
|
|
|
(p1.typalign not in ('c', 's', 'i', 'd')) OR
|
|
|
|
(p1.typstorage not in ('p', 'x', 'e', '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
|
2008-04-21 02:26:47 +02:00
|
|
|
(p1.typlen != 4 OR p1.typalign != 'i') AND
|
|
|
|
(p1.typlen != 8 OR p1.typalign != 'd');
|
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)
|
|
|
|
|
2011-11-19 00:23:55 +01:00
|
|
|
-- 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.
|
Implement multivariate n-distinct coefficients
Add support for explicitly declared statistic objects (CREATE
STATISTICS), allowing collection of statistics on more complex
combinations that individual table columns. Companion commands DROP
STATISTICS and ALTER STATISTICS ... OWNER TO / SET SCHEMA / RENAME are
added too. All this DDL has been designed so that more statistic types
can be added later on, such as multivariate most-common-values and
multivariate histograms between columns of a single table, leaving room
for permitting columns on multiple tables, too, as well as expressions.
This commit only adds support for collection of n-distinct coefficient
on user-specified sets of columns in a single table. This is useful to
estimate number of distinct groups in GROUP BY and DISTINCT clauses;
estimation errors there can cause over-allocation of memory in hashed
aggregates, for instance, so it's a worthwhile problem to solve. A new
special pseudo-type pg_ndistinct is used.
(num-distinct estimation was deemed sufficiently useful by itself that
this is worthwhile even if no further statistic types are added
immediately; so much so that another version of essentially the same
functionality was submitted by Kyotaro Horiguchi:
https://postgr.es/m/20150828.173334.114731693.horiguchi.kyotaro@lab.ntt.co.jp
though this commit does not use that code.)
Author: Tomas Vondra. Some code rework by Álvaro.
Reviewed-by: Dean Rasheed, David Rowley, Kyotaro Horiguchi, Jeff Janes,
Ideriha Takeshi
Discussion: https://postgr.es/m/543AFA15.4080608@fuzzy.cz
https://postgr.es/m/20170320190220.ixlaueanxegqd5gr@alvherre.pgsql
2017-03-24 18:06:10 +01:00
|
|
|
-- NOTE: as of v10, this check finds pg_node_tree, pg_ndistinct, smgr.
|
2002-04-25 04:56:56 +02:00
|
|
|
SELECT p1.oid, p1.typname
|
|
|
|
FROM pg_type as p1
|
2011-11-19 00:23:55 +01:00
|
|
|
WHERE p1.typtype not in ('c','d','p') AND p1.typname NOT LIKE E'\\_%'
|
|
|
|
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
|
2007-10-14 00:33:38 +02:00
|
|
|
p2.typelem = p1.oid and p1.typarray = p2.oid);
|
2017-04-06 00:00:42 +02:00
|
|
|
oid | typname
|
|
|
|
------+-----------------
|
Implement multivariate n-distinct coefficients
Add support for explicitly declared statistic objects (CREATE
STATISTICS), allowing collection of statistics on more complex
combinations that individual table columns. Companion commands DROP
STATISTICS and ALTER STATISTICS ... OWNER TO / SET SCHEMA / RENAME are
added too. All this DDL has been designed so that more statistic types
can be added later on, such as multivariate most-common-values and
multivariate histograms between columns of a single table, leaving room
for permitting columns on multiple tables, too, as well as expressions.
This commit only adds support for collection of n-distinct coefficient
on user-specified sets of columns in a single table. This is useful to
estimate number of distinct groups in GROUP BY and DISTINCT clauses;
estimation errors there can cause over-allocation of memory in hashed
aggregates, for instance, so it's a worthwhile problem to solve. A new
special pseudo-type pg_ndistinct is used.
(num-distinct estimation was deemed sufficiently useful by itself that
this is worthwhile even if no further statistic types are added
immediately; so much so that another version of essentially the same
functionality was submitted by Kyotaro Horiguchi:
https://postgr.es/m/20150828.173334.114731693.horiguchi.kyotaro@lab.ntt.co.jp
though this commit does not use that code.)
Author: Tomas Vondra. Some code rework by Álvaro.
Reviewed-by: Dean Rasheed, David Rowley, Kyotaro Horiguchi, Jeff Janes,
Ideriha Takeshi
Discussion: https://postgr.es/m/543AFA15.4080608@fuzzy.cz
https://postgr.es/m/20170320190220.ixlaueanxegqd5gr@alvherre.pgsql
2017-03-24 18:06:10 +01:00
|
|
|
194 | pg_node_tree
|
|
|
|
3361 | pg_ndistinct
|
2017-04-06 00:00:42 +02:00
|
|
|
3402 | pg_dependencies
|
Implement multivariate n-distinct coefficients
Add support for explicitly declared statistic objects (CREATE
STATISTICS), allowing collection of statistics on more complex
combinations that individual table columns. Companion commands DROP
STATISTICS and ALTER STATISTICS ... OWNER TO / SET SCHEMA / RENAME are
added too. All this DDL has been designed so that more statistic types
can be added later on, such as multivariate most-common-values and
multivariate histograms between columns of a single table, leaving room
for permitting columns on multiple tables, too, as well as expressions.
This commit only adds support for collection of n-distinct coefficient
on user-specified sets of columns in a single table. This is useful to
estimate number of distinct groups in GROUP BY and DISTINCT clauses;
estimation errors there can cause over-allocation of memory in hashed
aggregates, for instance, so it's a worthwhile problem to solve. A new
special pseudo-type pg_ndistinct is used.
(num-distinct estimation was deemed sufficiently useful by itself that
this is worthwhile even if no further statistic types are added
immediately; so much so that another version of essentially the same
functionality was submitted by Kyotaro Horiguchi:
https://postgr.es/m/20150828.173334.114731693.horiguchi.kyotaro@lab.ntt.co.jp
though this commit does not use that code.)
Author: Tomas Vondra. Some code rework by Álvaro.
Reviewed-by: Dean Rasheed, David Rowley, Kyotaro Horiguchi, Jeff Janes,
Ideriha Takeshi
Discussion: https://postgr.es/m/543AFA15.4080608@fuzzy.cz
https://postgr.es/m/20170320190220.ixlaueanxegqd5gr@alvherre.pgsql
2017-03-24 18:06:10 +01:00
|
|
|
210 | smgr
|
2017-04-06 00:00:42 +02:00
|
|
|
(4 rows)
|
2002-04-25 04:56:56 +02:00
|
|
|
|
Support arrays of composite types, including the rowtypes of regular tables
and views (but not system catalogs, nor sequences or toast tables). Get rid
of the hardwired convention that a type's array type is named exactly "_type",
instead using a new column pg_type.typarray to provide the linkage. (It still
will be named "_type", though, except in odd corner cases such as
maximum-length type names.)
Along the way, make tracking of owner and schema dependencies for types more
uniform: a type directly created by the user has these dependencies, while a
table rowtype or auto-generated array type does not have them, but depends on
its parent object instead.
David Fetter, Andrew Dunstan, Tom Lane
2007-05-11 19:57:14 +02:00
|
|
|
-- Make sure typarray points to a varlena array type of our own base
|
2010-11-23 21:27:50 +01:00
|
|
|
SELECT p1.oid, p1.typname as basetype, p2.typname as arraytype,
|
Support arrays of composite types, including the rowtypes of regular tables
and views (but not system catalogs, nor sequences or toast tables). Get rid
of the hardwired convention that a type's array type is named exactly "_type",
instead using a new column pg_type.typarray to provide the linkage. (It still
will be named "_type", though, except in odd corner cases such as
maximum-length type names.)
Along the way, make tracking of owner and schema dependencies for types more
uniform: a type directly created by the user has these dependencies, while a
table rowtype or auto-generated array type does not have them, but depends on
its parent object instead.
David Fetter, Andrew Dunstan, Tom Lane
2007-05-11 19:57:14 +02:00
|
|
|
p2.typelem, p2.typlen
|
|
|
|
FROM pg_type p1 LEFT JOIN pg_type p2 ON (p1.typarray = p2.oid)
|
|
|
|
WHERE p1.typarray <> 0 AND
|
|
|
|
(p2.oid IS NULL OR p2.typelem <> p1.oid OR p2.typlen <> -1);
|
|
|
|
oid | basetype | arraytype | typelem | typlen
|
|
|
|
-----+----------+-----------+---------+--------
|
|
|
|
(0 rows)
|
|
|
|
|
2011-11-15 03:42:04 +01:00
|
|
|
-- Look for range types that do not have a pg_range entry
|
|
|
|
SELECT p1.oid, p1.typname
|
|
|
|
FROM pg_type as p1
|
|
|
|
WHERE p1.typtype = 'r' AND
|
|
|
|
NOT EXISTS(SELECT 1 FROM pg_range r WHERE rngtypid = p1.oid);
|
|
|
|
oid | typname
|
|
|
|
-----+---------
|
|
|
|
(0 rows)
|
|
|
|
|
|
|
|
-- Look for range types whose typalign isn't sufficient
|
|
|
|
SELECT p1.oid, p1.typname, p1.typalign, p2.typname, p2.typalign
|
|
|
|
FROM pg_type as p1
|
|
|
|
LEFT JOIN pg_range as r ON rngtypid = p1.oid
|
|
|
|
LEFT JOIN pg_type as p2 ON rngsubtype = p2.oid
|
|
|
|
WHERE p1.typtype = 'r' AND
|
|
|
|
(p1.typalign != (CASE WHEN p2.typalign = 'd' THEN 'd'::"char"
|
|
|
|
ELSE 'i'::"char" END)
|
|
|
|
OR p2.oid IS NULL);
|
|
|
|
oid | typname | typalign | typname | typalign
|
|
|
|
-----+---------+----------+---------+----------
|
|
|
|
(0 rows)
|
|
|
|
|
2005-07-10 23:14:00 +02:00
|
|
|
-- Text conversion routines must be provided.
|
2000-01-05 07:06:23 +01:00
|
|
|
SELECT p1.oid, p1.typname
|
1999-03-28 04:06:23 +02:00
|
|
|
FROM pg_type as p1
|
2005-07-10 23:14:00 +02:00
|
|
|
WHERE (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
|
|
|
|
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
|
2013-02-13 22:20:01 +01:00
|
|
|
WHERE p1.typinput = p2.oid AND NOT
|
2002-08-22 02:01:51 +02:00
|
|
|
((p2.pronargs = 1 AND p2.proargtypes[0] = 'cstring'::regtype) OR
|
2013-02-13 22:20:01 +01:00
|
|
|
(p2.pronargs = 2 AND p2.proargtypes[0] = 'cstring'::regtype AND
|
|
|
|
p2.proargtypes[1] = 'oid'::regtype) OR
|
2002-08-22 02:01:51 +02:00
|
|
|
(p2.pronargs = 3 AND p2.proargtypes[0] = 'cstring'::regtype AND
|
|
|
|
p2.proargtypes[1] = 'oid'::regtype AND
|
|
|
|
p2.proargtypes[2] = 'int4'::regtype));
|
|
|
|
oid | typname | oid | proname
|
|
|
|
-----+---------+-----+---------
|
|
|
|
(0 rows)
|
|
|
|
|
2017-10-31 05:22:39 +01:00
|
|
|
-- Check for type of the variadic array parameter's elements.
|
|
|
|
-- provariadic should be ANYOID if the type of the last element is ANYOID,
|
|
|
|
-- ANYELEMENTOID if the type of the last element is ANYARRAYOID, and otherwise
|
|
|
|
-- the element type corresponding to the array type.
|
|
|
|
SELECT oid::regprocedure, provariadic::regtype, proargtypes::regtype[]
|
|
|
|
FROM pg_proc
|
|
|
|
WHERE provariadic != 0
|
|
|
|
AND case proargtypes[array_length(proargtypes, 1)-1]
|
|
|
|
WHEN 2276 THEN 2276 -- any -> any
|
|
|
|
WHEN 2277 THEN 2283 -- anyarray -> anyelement
|
|
|
|
ELSE (SELECT t.oid
|
|
|
|
FROM pg_type t
|
|
|
|
WHERE t.typarray = proargtypes[array_length(proargtypes, 1)-1])
|
|
|
|
END != provariadic;
|
|
|
|
oid | provariadic | proargtypes
|
|
|
|
-----+-------------+-------------
|
|
|
|
(0 rows)
|
|
|
|
|
2017-11-17 17:53:00 +01:00
|
|
|
-- Check that all and only those functions with a variadic type have
|
|
|
|
-- a variadic argument.
|
|
|
|
SELECT oid::regprocedure, proargmodes, provariadic
|
|
|
|
FROM pg_proc
|
|
|
|
WHERE (proargmodes IS NOT NULL AND 'v' = any(proargmodes))
|
|
|
|
IS DISTINCT FROM
|
|
|
|
(provariadic != 0);
|
|
|
|
oid | proargmodes | provariadic
|
|
|
|
-----+-------------+-------------
|
|
|
|
(0 rows)
|
|
|
|
|
2004-08-04 23:34:35 +02:00
|
|
|
-- As of 8.0, this check finds refcursor, which is borrowing
|
2002-08-22 02:01:51 +02:00
|
|
|
-- other types' I/O routines
|
|
|
|
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 in ('b', 'p') AND NOT
|
|
|
|
(p1.typelem != 0 AND p1.typlen < 0) AND NOT
|
2003-01-15 20:35:48 +01:00
|
|
|
(p2.prorettype = p1.oid AND NOT p2.proretset)
|
|
|
|
ORDER BY 1;
|
2004-06-06 21:07:02 +02:00
|
|
|
oid | typname | oid | proname
|
|
|
|
------+-----------+-----+---------
|
2002-08-22 02:01:51 +02:00
|
|
|
1790 | refcursor | 46 | textin
|
2004-06-06 21:07:02 +02:00
|
|
|
(1 row)
|
2002-08-22 02:01:51 +02:00
|
|
|
|
|
|
|
-- Varlena array types will point to array_in
|
2005-03-29 02:17:27 +02:00
|
|
|
-- Exception as of 8.1: int2vector and oidvector have their own I/O routines
|
2002-08-22 02:01:51 +02:00
|
|
|
SELECT p1.oid, p1.typname, p2.oid, p2.proname
|
|
|
|
FROM pg_type AS p1, pg_proc AS p2
|
2013-02-13 22:20:01 +01:00
|
|
|
WHERE p1.typinput = p2.oid AND
|
2002-08-22 02:01:51 +02:00
|
|
|
(p1.typelem != 0 AND p1.typlen < 0) AND NOT
|
2005-03-29 02:17:27 +02:00
|
|
|
(p2.oid = 'array_in'::regproc)
|
|
|
|
ORDER BY 1;
|
|
|
|
oid | typname | oid | proname
|
|
|
|
-----+------------+-----+--------------
|
|
|
|
22 | int2vector | 40 | int2vectorin
|
|
|
|
30 | oidvector | 54 | oidvectorin
|
|
|
|
(2 rows)
|
1999-03-28 04:06:23 +02:00
|
|
|
|
2014-10-23 21:59:40 +02:00
|
|
|
-- typinput routines should not be volatile
|
|
|
|
SELECT p1.oid, p1.typname, p2.oid, p2.proname
|
|
|
|
FROM pg_type AS p1, pg_proc AS p2
|
|
|
|
WHERE p1.typinput = p2.oid AND p2.provolatile NOT IN ('i', 's');
|
|
|
|
oid | typname | oid | proname
|
|
|
|
-----+---------+-----+---------
|
|
|
|
(0 rows)
|
|
|
|
|
2011-11-19 00:23:55 +01:00
|
|
|
-- 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)
|
|
|
|
|
2000-01-05 07:06:23 +01:00
|
|
|
-- Check for bogus typoutput routines
|
2004-08-04 23:34:35 +02:00
|
|
|
-- As of 8.0, this check finds refcursor, which is borrowing
|
2002-08-22 02:01:51 +02:00
|
|
|
-- other types' I/O routines
|
|
|
|
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 in ('b', 'p') AND NOT
|
2005-04-30 22:31:39 +02:00
|
|
|
(p2.pronargs = 1 AND
|
|
|
|
(p2.proargtypes[0] = p1.oid OR
|
|
|
|
(p2.oid = 'array_out'::regproc AND
|
|
|
|
p1.typelem != 0 AND p1.typlen = -1)))
|
2003-01-15 20:35:48 +01:00
|
|
|
ORDER BY 1;
|
2004-06-06 21:07:02 +02:00
|
|
|
oid | typname | oid | proname
|
|
|
|
------+-----------+-----+---------
|
2002-08-22 02:01:51 +02:00
|
|
|
1790 | refcursor | 47 | textout
|
2004-06-06 21:07:02 +02:00
|
|
|
(1 row)
|
2002-08-22 02:01:51 +02:00
|
|
|
|
2000-01-05 07:06:23 +01:00
|
|
|
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
|
2013-02-13 22:20:01 +01:00
|
|
|
WHERE p1.typoutput = p2.oid AND NOT
|
2002-08-22 02:01:51 +02:00
|
|
|
(p2.prorettype = 'cstring'::regtype AND NOT p2.proretset);
|
2003-05-09 00:19:58 +02:00
|
|
|
oid | typname | oid | proname
|
|
|
|
-----+---------+-----+---------
|
|
|
|
(0 rows)
|
|
|
|
|
2014-10-23 21:59:40 +02:00
|
|
|
-- typoutput routines should not be volatile
|
|
|
|
SELECT p1.oid, p1.typname, p2.oid, p2.proname
|
|
|
|
FROM pg_type AS p1, pg_proc AS p2
|
|
|
|
WHERE p1.typoutput = p2.oid AND p2.provolatile NOT IN ('i', 's');
|
|
|
|
oid | typname | oid | proname
|
|
|
|
-----+---------+-----+---------
|
|
|
|
(0 rows)
|
|
|
|
|
2011-11-19 00:23:55 +01:00
|
|
|
-- 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)
|
|
|
|
|
2003-05-09 00:19:58 +02:00
|
|
|
-- Check for bogus typreceive routines
|
|
|
|
SELECT p1.oid, p1.typname, p2.oid, p2.proname
|
|
|
|
FROM pg_type AS p1, pg_proc AS p2
|
2013-02-13 22:20:01 +01:00
|
|
|
WHERE p1.typreceive = p2.oid AND NOT
|
2003-05-10 01:01:45 +02:00
|
|
|
((p2.pronargs = 1 AND p2.proargtypes[0] = 'internal'::regtype) OR
|
2013-02-13 22:20:01 +01:00
|
|
|
(p2.pronargs = 2 AND p2.proargtypes[0] = 'internal'::regtype AND
|
|
|
|
p2.proargtypes[1] = 'oid'::regtype) OR
|
2005-07-10 23:14:00 +02:00
|
|
|
(p2.pronargs = 3 AND p2.proargtypes[0] = 'internal'::regtype AND
|
|
|
|
p2.proargtypes[1] = 'oid'::regtype AND
|
|
|
|
p2.proargtypes[2] = 'int4'::regtype));
|
2003-05-09 00:19:58 +02:00
|
|
|
oid | typname | oid | proname
|
|
|
|
-----+---------+-----+---------
|
|
|
|
(0 rows)
|
|
|
|
|
2003-05-09 17:44:42 +02:00
|
|
|
-- As of 7.4, this check finds refcursor, which is borrowing
|
|
|
|
-- other types' I/O routines
|
2003-05-09 00:19:58 +02:00
|
|
|
SELECT p1.oid, p1.typname, p2.oid, p2.proname
|
|
|
|
FROM pg_type AS p1, pg_proc AS p2
|
|
|
|
WHERE p1.typreceive = p2.oid AND p1.typtype in ('b', 'p') AND NOT
|
|
|
|
(p1.typelem != 0 AND p1.typlen < 0) AND NOT
|
2003-05-09 17:44:42 +02:00
|
|
|
(p2.prorettype = p1.oid AND NOT p2.proretset)
|
|
|
|
ORDER BY 1;
|
|
|
|
oid | typname | oid | proname
|
|
|
|
------+-----------+------+----------
|
|
|
|
1790 | refcursor | 2414 | textrecv
|
|
|
|
(1 row)
|
2003-05-09 00:19:58 +02:00
|
|
|
|
|
|
|
-- Varlena array types will point to array_recv
|
2005-03-29 02:17:27 +02:00
|
|
|
-- Exception as of 8.1: int2vector and oidvector have their own I/O routines
|
2003-05-09 00:19:58 +02:00
|
|
|
SELECT p1.oid, p1.typname, p2.oid, p2.proname
|
|
|
|
FROM pg_type AS p1, pg_proc AS p2
|
2013-02-13 22:20:01 +01:00
|
|
|
WHERE p1.typreceive = p2.oid AND
|
2003-05-09 00:19:58 +02:00
|
|
|
(p1.typelem != 0 AND p1.typlen < 0) AND NOT
|
2005-03-29 02:17:27 +02:00
|
|
|
(p2.oid = 'array_recv'::regproc)
|
|
|
|
ORDER BY 1;
|
|
|
|
oid | typname | oid | proname
|
|
|
|
-----+------------+------+----------------
|
|
|
|
22 | int2vector | 2410 | int2vectorrecv
|
|
|
|
30 | oidvector | 2420 | oidvectorrecv
|
|
|
|
(2 rows)
|
2003-05-09 00:19:58 +02:00
|
|
|
|
2005-07-10 23:14:00 +02:00
|
|
|
-- Suspicious if typreceive doesn't take same number of args as typinput
|
|
|
|
SELECT p1.oid, p1.typname, p2.oid, p2.proname, p3.oid, p3.proname
|
|
|
|
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;
|
|
|
|
oid | typname | oid | proname | oid | proname
|
|
|
|
-----+---------+-----+---------+-----+---------
|
|
|
|
(0 rows)
|
|
|
|
|
2014-10-23 21:59:40 +02:00
|
|
|
-- typreceive routines should not be volatile
|
|
|
|
SELECT p1.oid, p1.typname, p2.oid, p2.proname
|
|
|
|
FROM pg_type AS p1, pg_proc AS p2
|
|
|
|
WHERE p1.typreceive = p2.oid AND p2.provolatile NOT IN ('i', 's');
|
|
|
|
oid | typname | oid | proname
|
|
|
|
-----+---------+-----+---------
|
|
|
|
(0 rows)
|
|
|
|
|
2011-11-19 00:23:55 +01:00
|
|
|
-- 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)
|
|
|
|
|
2003-05-09 00:19:58 +02:00
|
|
|
-- Check for bogus typsend routines
|
2003-05-09 17:44:42 +02:00
|
|
|
-- As of 7.4, this check finds refcursor, which is borrowing
|
|
|
|
-- other types' I/O routines
|
2003-05-09 00:19:58 +02:00
|
|
|
SELECT p1.oid, p1.typname, p2.oid, p2.proname
|
|
|
|
FROM pg_type AS p1, pg_proc AS p2
|
|
|
|
WHERE p1.typsend = p2.oid AND p1.typtype in ('b', 'p') AND NOT
|
2005-04-30 22:31:39 +02:00
|
|
|
(p2.pronargs = 1 AND
|
|
|
|
(p2.proargtypes[0] = p1.oid OR
|
|
|
|
(p2.oid = 'array_send'::regproc AND
|
|
|
|
p1.typelem != 0 AND p1.typlen = -1)))
|
2003-05-09 17:44:42 +02:00
|
|
|
ORDER BY 1;
|
|
|
|
oid | typname | oid | proname
|
|
|
|
------+-----------+------+----------
|
|
|
|
1790 | refcursor | 2415 | textsend
|
|
|
|
(1 row)
|
2003-05-09 00:19:58 +02:00
|
|
|
|
|
|
|
SELECT p1.oid, p1.typname, p2.oid, p2.proname
|
|
|
|
FROM pg_type AS p1, pg_proc AS p2
|
2013-02-13 22:20:01 +01:00
|
|
|
WHERE p1.typsend = p2.oid AND NOT
|
2003-05-09 00:19:58 +02:00
|
|
|
(p2.prorettype = 'bytea'::regtype AND NOT p2.proretset);
|
2006-12-30 22:21:56 +01:00
|
|
|
oid | typname | oid | proname
|
|
|
|
-----+---------+-----+---------
|
|
|
|
(0 rows)
|
|
|
|
|
2014-10-23 21:59:40 +02:00
|
|
|
-- typsend routines should not be volatile
|
|
|
|
SELECT p1.oid, p1.typname, p2.oid, p2.proname
|
|
|
|
FROM pg_type AS p1, pg_proc AS p2
|
|
|
|
WHERE p1.typsend = p2.oid AND p2.provolatile NOT IN ('i', 's');
|
|
|
|
oid | typname | oid | proname
|
|
|
|
-----+---------+-----+---------
|
|
|
|
(0 rows)
|
|
|
|
|
2011-11-19 00:23:55 +01:00
|
|
|
-- 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)
|
|
|
|
|
2006-12-30 22:21:56 +01:00
|
|
|
-- Check for bogus typmodin routines
|
|
|
|
SELECT p1.oid, p1.typname, p2.oid, p2.proname
|
|
|
|
FROM pg_type AS p1, pg_proc AS p2
|
2011-11-19 00:23:55 +01:00
|
|
|
WHERE p1.typmodin = p2.oid AND NOT
|
2006-12-30 22:21:56 +01:00
|
|
|
(p2.pronargs = 1 AND
|
2007-06-15 22:56:52 +02:00
|
|
|
p2.proargtypes[0] = 'cstring[]'::regtype AND
|
2006-12-30 22:21:56 +01:00
|
|
|
p2.prorettype = 'int4'::regtype AND NOT p2.proretset);
|
|
|
|
oid | typname | oid | proname
|
|
|
|
-----+---------+-----+---------
|
|
|
|
(0 rows)
|
|
|
|
|
2014-10-23 21:59:40 +02:00
|
|
|
-- typmodin routines should not be volatile
|
|
|
|
SELECT p1.oid, p1.typname, p2.oid, p2.proname
|
|
|
|
FROM pg_type AS p1, pg_proc AS p2
|
|
|
|
WHERE p1.typmodin = p2.oid AND p2.provolatile NOT IN ('i', 's');
|
|
|
|
oid | typname | oid | proname
|
|
|
|
-----+---------+-----+---------
|
|
|
|
(0 rows)
|
|
|
|
|
2006-12-30 22:21:56 +01:00
|
|
|
-- Check for bogus typmodout routines
|
|
|
|
SELECT p1.oid, p1.typname, p2.oid, p2.proname
|
|
|
|
FROM pg_type AS p1, pg_proc AS p2
|
2011-11-19 00:23:55 +01:00
|
|
|
WHERE p1.typmodout = p2.oid AND NOT
|
2006-12-30 22:21:56 +01:00
|
|
|
(p2.pronargs = 1 AND
|
|
|
|
p2.proargtypes[0] = 'int4'::regtype AND
|
|
|
|
p2.prorettype = 'cstring'::regtype AND NOT p2.proretset);
|
|
|
|
oid | typname | oid | proname
|
|
|
|
-----+---------+-----+---------
|
|
|
|
(0 rows)
|
|
|
|
|
2014-10-23 21:59:40 +02:00
|
|
|
-- typmodout routines should not be volatile
|
|
|
|
SELECT p1.oid, p1.typname, p2.oid, p2.proname
|
|
|
|
FROM pg_type AS p1, pg_proc AS p2
|
|
|
|
WHERE p1.typmodout = p2.oid AND p2.provolatile NOT IN ('i', 's');
|
|
|
|
oid | typname | oid | proname
|
|
|
|
-----+---------+-----+---------
|
|
|
|
(0 rows)
|
|
|
|
|
2006-12-30 22:21:56 +01:00
|
|
|
-- Array types should have same typmodin/out as their element types
|
|
|
|
SELECT p1.oid, p1.typname, p2.oid, p2.typname
|
|
|
|
FROM pg_type AS p1, pg_type AS p2
|
|
|
|
WHERE p1.typelem = p2.oid AND NOT
|
|
|
|
(p1.typmodin = p2.typmodin AND p1.typmodout = p2.typmodout);
|
|
|
|
oid | typname | oid | typname
|
|
|
|
-----+---------+-----+---------
|
|
|
|
(0 rows)
|
|
|
|
|
2008-09-25 05:28:56 +02:00
|
|
|
-- Array types should have same typdelim as their element types
|
|
|
|
SELECT p1.oid, p1.typname, p2.oid, p2.typname
|
|
|
|
FROM pg_type AS p1, pg_type AS p2
|
|
|
|
WHERE p1.typarray = p2.oid AND NOT (p1.typdelim = p2.typdelim);
|
|
|
|
oid | typname | oid | typname
|
|
|
|
-----+---------+-----+---------
|
|
|
|
(0 rows)
|
|
|
|
|
2011-11-15 03:42:04 +01:00
|
|
|
-- Look for array types whose typalign isn't sufficient
|
|
|
|
SELECT p1.oid, p1.typname, p1.typalign, p2.typname, p2.typalign
|
|
|
|
FROM pg_type AS p1, pg_type AS p2
|
|
|
|
WHERE p1.typarray = p2.oid AND
|
|
|
|
p2.typalign != (CASE WHEN p1.typalign = 'd' THEN 'd'::"char"
|
|
|
|
ELSE 'i'::"char" END);
|
|
|
|
oid | typname | typalign | typname | typalign
|
|
|
|
-----+---------+----------+---------+----------
|
|
|
|
(0 rows)
|
|
|
|
|
2006-12-30 22:21:56 +01:00
|
|
|
-- Check for bogus typanalyze routines
|
|
|
|
SELECT p1.oid, p1.typname, p2.oid, p2.proname
|
|
|
|
FROM pg_type AS p1, pg_proc AS p2
|
2011-11-19 00:23:55 +01:00
|
|
|
WHERE p1.typanalyze = p2.oid AND NOT
|
2006-12-30 22:21:56 +01:00
|
|
|
(p2.pronargs = 1 AND
|
|
|
|
p2.proargtypes[0] = 'internal'::regtype AND
|
|
|
|
p2.prorettype = 'bool'::regtype AND NOT p2.proretset);
|
2000-01-05 07:06:23 +01:00
|
|
|
oid | typname | oid | proname
|
|
|
|
-----+---------+-----+---------
|
1999-03-28 04:06:23 +02:00
|
|
|
(0 rows)
|
|
|
|
|
2014-10-23 21:59:40 +02:00
|
|
|
-- there does not seem to be a reason to care about volatility of typanalyze
|
2012-03-04 02:20:19 +01:00
|
|
|
-- domains inherit their base type's typanalyze
|
|
|
|
SELECT d.oid, d.typname, d.typanalyze, t.oid, t.typname, t.typanalyze
|
|
|
|
FROM pg_type d JOIN pg_type t ON d.typbasetype = t.oid
|
|
|
|
WHERE d.typanalyze != t.typanalyze;
|
|
|
|
oid | typname | typanalyze | oid | typname | typanalyze
|
|
|
|
-----+---------+------------+-----+---------+------------
|
|
|
|
(0 rows)
|
|
|
|
|
|
|
|
-- range_typanalyze should be used for all and only range types
|
|
|
|
-- (but exclude domains, which we checked above)
|
|
|
|
SELECT t.oid, t.typname, t.typanalyze
|
|
|
|
FROM pg_type t LEFT JOIN pg_range r on t.oid = r.rngtypid
|
|
|
|
WHERE t.typbasetype = 0 AND
|
|
|
|
(t.typanalyze = 'range_typanalyze'::regproc) != (r.rngtypid IS NOT NULL);
|
|
|
|
oid | typname | typanalyze
|
|
|
|
-----+---------+------------
|
|
|
|
(0 rows)
|
|
|
|
|
|
|
|
-- array_typanalyze should be used for all and only array types
|
|
|
|
-- (but exclude domains, which we checked above)
|
|
|
|
-- As of 9.2 this finds int2vector and oidvector, which are weird anyway
|
|
|
|
SELECT t.oid, t.typname, t.typanalyze
|
|
|
|
FROM pg_type t
|
|
|
|
WHERE t.typbasetype = 0 AND
|
|
|
|
(t.typanalyze = 'array_typanalyze'::regproc) !=
|
|
|
|
(typelem != 0 AND typlen < 0)
|
|
|
|
ORDER BY 1;
|
|
|
|
oid | typname | typanalyze
|
|
|
|
-----+------------+------------
|
|
|
|
22 | int2vector | -
|
|
|
|
30 | oidvector | -
|
|
|
|
(2 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
|
2017-03-10 19:15:47 +01:00
|
|
|
WHERE relkind NOT IN ('r', 'i', 'S', 't', 'v', 'm', 'c', 'f', 'p') OR
|
2016-01-09 23:20:58 +01:00
|
|
|
relpersistence NOT IN ('p', 'u', 't') OR
|
|
|
|
relreplident NOT IN ('d', 'n', 'f', 'i');
|
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
|
2002-09-22 21:42:52 +02:00
|
|
|
p1.attcacheoff != -1 OR p1.attinhcount < 0 OR
|
|
|
|
(p1.attinhcount = 0 AND NOT p1.attislocal);
|
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)
|
|
|
|
|
2011-11-17 00:21:34 +01:00
|
|
|
-- **************** pg_range ****************
|
|
|
|
-- Look for illegal values in pg_range fields.
|
|
|
|
SELECT p1.rngtypid, p1.rngsubtype
|
|
|
|
FROM pg_range as p1
|
|
|
|
WHERE p1.rngtypid = 0 OR p1.rngsubtype = 0 OR p1.rngsubopc = 0;
|
|
|
|
rngtypid | rngsubtype
|
|
|
|
----------+------------
|
|
|
|
(0 rows)
|
|
|
|
|
|
|
|
-- rngcollation should be specified iff subtype is collatable
|
|
|
|
SELECT p1.rngtypid, p1.rngsubtype, p1.rngcollation, t.typcollation
|
|
|
|
FROM pg_range p1 JOIN pg_type t ON t.oid = p1.rngsubtype
|
|
|
|
WHERE (rngcollation = 0) != (typcollation = 0);
|
|
|
|
rngtypid | rngsubtype | rngcollation | typcollation
|
|
|
|
----------+------------+--------------+--------------
|
|
|
|
(0 rows)
|
|
|
|
|
|
|
|
-- opclass had better be a btree opclass accepting the subtype.
|
|
|
|
-- We must allow anyarray matches, cf opr_sanity's binary_coercible()
|
|
|
|
SELECT p1.rngtypid, p1.rngsubtype, o.opcmethod, o.opcname
|
|
|
|
FROM pg_range p1 JOIN pg_opclass o ON o.oid = p1.rngsubopc
|
|
|
|
WHERE o.opcmethod != 403 OR
|
|
|
|
((o.opcintype != p1.rngsubtype) AND NOT
|
|
|
|
(o.opcintype = 'pg_catalog.anyarray'::regtype AND
|
|
|
|
EXISTS(select 1 from pg_catalog.pg_type where
|
|
|
|
oid = p1.rngsubtype and typelem != 0 and typlen = -1)));
|
|
|
|
rngtypid | rngsubtype | opcmethod | opcname
|
|
|
|
----------+------------+-----------+---------
|
|
|
|
(0 rows)
|
|
|
|
|
|
|
|
-- canonical function, if any, had better match the range type
|
|
|
|
SELECT p1.rngtypid, p1.rngsubtype, p.proname
|
|
|
|
FROM pg_range p1 JOIN pg_proc p ON p.oid = p1.rngcanonical
|
|
|
|
WHERE pronargs != 1 OR proargtypes[0] != rngtypid OR prorettype != rngtypid;
|
|
|
|
rngtypid | rngsubtype | proname
|
|
|
|
----------+------------+---------
|
|
|
|
(0 rows)
|
|
|
|
|
|
|
|
-- subdiff function, if any, had better match the subtype
|
|
|
|
SELECT p1.rngtypid, p1.rngsubtype, p.proname
|
|
|
|
FROM pg_range p1 JOIN pg_proc p ON p.oid = p1.rngsubdiff
|
|
|
|
WHERE pronargs != 2
|
|
|
|
OR proargtypes[0] != rngsubtype OR proargtypes[1] != rngsubtype
|
|
|
|
OR prorettype != 'pg_catalog.float8'::regtype;
|
|
|
|
rngtypid | rngsubtype | proname
|
|
|
|
----------+------------+---------
|
|
|
|
(0 rows)
|
|
|
|
|