mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-08-25 05:27:19 +02:00
expressions, ARRAY(sub-SELECT) expressions, some array functions. Polymorphic functions using ANYARRAY/ANYELEMENT argument and return types. Some regression tests in place, documentation is lacking. Joe Conway, with some kibitzing from Tom Lane.
767 lines
28 KiB
Plaintext
767 lines
28 KiB
Plaintext
--
|
|
-- OPR_SANITY
|
|
-- Sanity checks for common errors in making operator/procedure system tables:
|
|
-- pg_operator, pg_proc, pg_cast, pg_aggregate, pg_am, pg_amop, pg_amproc, pg_opclass.
|
|
--
|
|
-- 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.
|
|
--
|
|
-- NB: run this test earlier than the create_operator test, because
|
|
-- that test creates some bogus operators...
|
|
-- **************** pg_proc ****************
|
|
-- Look for illegal values in pg_proc fields.
|
|
-- NOTE: in reality pronargs could be more than 10, but I'm too lazy to put
|
|
-- a larger number of proargtypes check clauses in here. If we ever have
|
|
-- more-than-10-arg functions in the standard catalogs, extend this query.
|
|
SELECT p1.oid, p1.proname
|
|
FROM pg_proc as p1
|
|
WHERE p1.prolang = 0 OR p1.prorettype = 0 OR
|
|
p1.pronargs < 0 OR p1.pronargs > 10 OR
|
|
(p1.proargtypes[0] = 0 AND p1.pronargs > 0) OR
|
|
(p1.proargtypes[1] = 0 AND p1.pronargs > 1) OR
|
|
(p1.proargtypes[2] = 0 AND p1.pronargs > 2) OR
|
|
(p1.proargtypes[3] = 0 AND p1.pronargs > 3) OR
|
|
(p1.proargtypes[4] = 0 AND p1.pronargs > 4) OR
|
|
(p1.proargtypes[5] = 0 AND p1.pronargs > 5) OR
|
|
(p1.proargtypes[6] = 0 AND p1.pronargs > 6) OR
|
|
(p1.proargtypes[7] = 0 AND p1.pronargs > 7) OR
|
|
(p1.proargtypes[8] = 0 AND p1.pronargs > 8) OR
|
|
(p1.proargtypes[9] = 0 AND p1.pronargs > 9);
|
|
oid | proname
|
|
-----+---------
|
|
(0 rows)
|
|
|
|
-- Look for conflicting proc definitions (same names and input datatypes).
|
|
-- (This test should be dead code now that we have the unique index
|
|
-- pg_proc_proname_narg_type_index, but I'll leave it in anyway.)
|
|
SELECT p1.oid, p1.proname, p2.oid, p2.proname
|
|
FROM pg_proc AS p1, pg_proc AS p2
|
|
WHERE p1.oid != p2.oid AND
|
|
p1.proname = p2.proname AND
|
|
p1.pronargs = p2.pronargs AND
|
|
p1.proargtypes = p2.proargtypes;
|
|
oid | proname | oid | proname
|
|
-----+---------+-----+---------
|
|
(0 rows)
|
|
|
|
-- Considering only built-in procs (prolang = 12), look for multiple uses
|
|
-- of the same internal function (ie, matching prosrc fields). It's OK to
|
|
-- have several entries with different pronames for the same internal function,
|
|
-- but conflicts in the number of arguments and other critical items should
|
|
-- be complained of.
|
|
SELECT p1.oid, p1.proname, p2.oid, p2.proname
|
|
FROM pg_proc AS p1, pg_proc AS p2
|
|
WHERE p1.oid != p2.oid AND
|
|
p1.prosrc = p2.prosrc AND
|
|
p1.prolang = 12 AND p2.prolang = 12 AND
|
|
(p1.prolang != p2.prolang OR
|
|
p1.proisagg != p2.proisagg OR
|
|
p1.prosecdef != p2.prosecdef OR
|
|
p1.proisstrict != p2.proisstrict OR
|
|
p1.proretset != p2.proretset OR
|
|
p1.provolatile != p2.provolatile OR
|
|
p1.pronargs != p2.pronargs);
|
|
oid | proname | oid | proname
|
|
-----+---------+-----+---------
|
|
(0 rows)
|
|
|
|
-- Look for uses of different type OIDs in the argument/result type fields
|
|
-- for different aliases of the same built-in function.
|
|
-- This indicates that the types are being presumed to be binary-equivalent,
|
|
-- or that the built-in function is prepared to deal with different types.
|
|
-- That's not wrong, necessarily, but we make lists of all the types being
|
|
-- so treated. Note that the expected output of this part of the test will
|
|
-- need to be modified whenever new pairs of types are made binary-equivalent,
|
|
-- or when new polymorphic built-in functions are added!
|
|
-- Note: ignore aggregate functions here, since they all point to the same
|
|
-- dummy built-in function.
|
|
SELECT DISTINCT p1.prorettype, p2.prorettype
|
|
FROM pg_proc AS p1, pg_proc AS p2
|
|
WHERE p1.oid != p2.oid AND
|
|
p1.prosrc = p2.prosrc AND
|
|
p1.prolang = 12 AND p2.prolang = 12 AND
|
|
NOT p1.proisagg AND NOT p2.proisagg AND
|
|
(p1.prorettype < p2.prorettype);
|
|
prorettype | prorettype
|
|
------------+------------
|
|
25 | 1043
|
|
1114 | 1184
|
|
(2 rows)
|
|
|
|
SELECT DISTINCT p1.proargtypes[0], p2.proargtypes[0]
|
|
FROM pg_proc AS p1, pg_proc AS p2
|
|
WHERE p1.oid != p2.oid AND
|
|
p1.prosrc = p2.prosrc AND
|
|
p1.prolang = 12 AND p2.prolang = 12 AND
|
|
NOT p1.proisagg AND NOT p2.proisagg AND
|
|
(p1.proargtypes[0] < p2.proargtypes[0]);
|
|
proargtypes | proargtypes
|
|
-------------+-------------
|
|
25 | 1043
|
|
1114 | 1184
|
|
1560 | 1562
|
|
2277 | 2283
|
|
(4 rows)
|
|
|
|
SELECT DISTINCT p1.proargtypes[1], p2.proargtypes[1]
|
|
FROM pg_proc AS p1, pg_proc AS p2
|
|
WHERE p1.oid != p2.oid AND
|
|
p1.prosrc = p2.prosrc AND
|
|
p1.prolang = 12 AND p2.prolang = 12 AND
|
|
NOT p1.proisagg AND NOT p2.proisagg AND
|
|
(p1.proargtypes[1] < p2.proargtypes[1]);
|
|
proargtypes | proargtypes
|
|
-------------+-------------
|
|
1114 | 1184
|
|
1560 | 1562
|
|
2277 | 2283
|
|
(3 rows)
|
|
|
|
SELECT DISTINCT p1.proargtypes[2], p2.proargtypes[2]
|
|
FROM pg_proc AS p1, pg_proc AS p2
|
|
WHERE p1.oid != p2.oid AND
|
|
p1.prosrc = p2.prosrc AND
|
|
p1.prolang = 12 AND p2.prolang = 12 AND
|
|
NOT p1.proisagg AND NOT p2.proisagg AND
|
|
(p1.proargtypes[2] < p2.proargtypes[2]);
|
|
proargtypes | proargtypes
|
|
-------------+-------------
|
|
1114 | 1184
|
|
(1 row)
|
|
|
|
SELECT DISTINCT p1.proargtypes[3], p2.proargtypes[3]
|
|
FROM pg_proc AS p1, pg_proc AS p2
|
|
WHERE p1.oid != p2.oid AND
|
|
p1.prosrc = p2.prosrc AND
|
|
p1.prolang = 12 AND p2.prolang = 12 AND
|
|
NOT p1.proisagg AND NOT p2.proisagg AND
|
|
(p1.proargtypes[3] < p2.proargtypes[3]);
|
|
proargtypes | proargtypes
|
|
-------------+-------------
|
|
1114 | 1184
|
|
(1 row)
|
|
|
|
SELECT DISTINCT p1.proargtypes[4], p2.proargtypes[4]
|
|
FROM pg_proc AS p1, pg_proc AS p2
|
|
WHERE p1.oid != p2.oid AND
|
|
p1.prosrc = p2.prosrc AND
|
|
p1.prolang = 12 AND p2.prolang = 12 AND
|
|
NOT p1.proisagg AND NOT p2.proisagg AND
|
|
(p1.proargtypes[4] < p2.proargtypes[4]);
|
|
proargtypes | proargtypes
|
|
-------------+-------------
|
|
(0 rows)
|
|
|
|
SELECT DISTINCT p1.proargtypes[5], p2.proargtypes[5]
|
|
FROM pg_proc AS p1, pg_proc AS p2
|
|
WHERE p1.oid != p2.oid AND
|
|
p1.prosrc = p2.prosrc AND
|
|
p1.prolang = 12 AND p2.prolang = 12 AND
|
|
NOT p1.proisagg AND NOT p2.proisagg AND
|
|
(p1.proargtypes[5] < p2.proargtypes[5]);
|
|
proargtypes | proargtypes
|
|
-------------+-------------
|
|
(0 rows)
|
|
|
|
SELECT DISTINCT p1.proargtypes[6], p2.proargtypes[6]
|
|
FROM pg_proc AS p1, pg_proc AS p2
|
|
WHERE p1.oid != p2.oid AND
|
|
p1.prosrc = p2.prosrc AND
|
|
p1.prolang = 12 AND p2.prolang = 12 AND
|
|
NOT p1.proisagg AND NOT p2.proisagg AND
|
|
(p1.proargtypes[6] < p2.proargtypes[6]);
|
|
proargtypes | proargtypes
|
|
-------------+-------------
|
|
(0 rows)
|
|
|
|
SELECT DISTINCT p1.proargtypes[7], p2.proargtypes[7]
|
|
FROM pg_proc AS p1, pg_proc AS p2
|
|
WHERE p1.oid != p2.oid AND
|
|
p1.prosrc = p2.prosrc AND
|
|
p1.prolang = 12 AND p2.prolang = 12 AND
|
|
NOT p1.proisagg AND NOT p2.proisagg AND
|
|
(p1.proargtypes[7] < p2.proargtypes[7]);
|
|
proargtypes | proargtypes
|
|
-------------+-------------
|
|
(0 rows)
|
|
|
|
-- Look for functions that return type "internal" and do not have any
|
|
-- "internal" argument. Such a function would be a security hole since
|
|
-- it might be used to call an internal function from an SQL command.
|
|
-- As of 7.3 this query should find only internal_in.
|
|
SELECT p1.oid, p1.proname
|
|
FROM pg_proc as p1
|
|
WHERE p1.prorettype = 'internal'::regtype AND NOT
|
|
('(' || oidvectortypes(p1.proargtypes) || ')') ~ '[^a-z0-9_]internal[^a-z0-9_]';
|
|
oid | proname
|
|
------+-------------
|
|
2304 | internal_in
|
|
(1 row)
|
|
|
|
-- **************** pg_cast ****************
|
|
-- Look for casts from and to the same type. This is not harmful, but
|
|
-- useless. Also catch bogus values in pg_cast columns (other than
|
|
-- cases detected by oidjoins test).
|
|
SELECT *
|
|
FROM pg_cast c
|
|
WHERE castsource = casttarget OR castsource = 0 OR casttarget = 0
|
|
OR castcontext NOT IN ('e', 'a', 'i');
|
|
castsource | casttarget | castfunc | castcontext
|
|
------------+------------+----------+-------------
|
|
(0 rows)
|
|
|
|
-- Look for cast functions that don't have the right signature. The
|
|
-- argument and result types in pg_proc must be the same as, or binary
|
|
-- compatible with, what it says in pg_cast.
|
|
SELECT c.*
|
|
FROM pg_cast c, pg_proc p
|
|
WHERE c.castfunc = p.oid AND
|
|
(p.pronargs <> 1
|
|
OR NOT (c.castsource = p.proargtypes[0] OR
|
|
EXISTS (SELECT 1 FROM pg_cast k
|
|
WHERE k.castfunc = 0 AND
|
|
k.castsource = c.castsource AND
|
|
k.casttarget = p.proargtypes[0]))
|
|
OR NOT (p.prorettype = c.casttarget OR
|
|
EXISTS (SELECT 1 FROM pg_cast k
|
|
WHERE k.castfunc = 0 AND
|
|
k.castsource = p.prorettype AND
|
|
k.casttarget = c.casttarget)));
|
|
castsource | casttarget | castfunc | castcontext
|
|
------------+------------+----------+-------------
|
|
(0 rows)
|
|
|
|
-- Look for binary compatible casts that do not have the reverse
|
|
-- direction registered as well, or where the reverse direction is not
|
|
-- also binary compatible. This is legal, but probably not intended.
|
|
SELECT *
|
|
FROM pg_cast c
|
|
WHERE c.castfunc = 0 AND
|
|
NOT EXISTS (SELECT 1 FROM pg_cast k
|
|
WHERE k.castfunc = 0 AND
|
|
k.castsource = c.casttarget AND
|
|
k.casttarget = c.castsource);
|
|
castsource | casttarget | castfunc | castcontext
|
|
------------+------------+----------+-------------
|
|
(0 rows)
|
|
|
|
-- **************** pg_operator ****************
|
|
-- Look for illegal values in pg_operator fields.
|
|
SELECT p1.oid, p1.oprname
|
|
FROM pg_operator as p1
|
|
WHERE (p1.oprkind != 'b' AND p1.oprkind != 'l' AND p1.oprkind != 'r') OR
|
|
p1.oprresult = 0 OR p1.oprcode = 0;
|
|
oid | oprname
|
|
-----+---------
|
|
(0 rows)
|
|
|
|
-- Look for missing or unwanted operand types
|
|
SELECT p1.oid, p1.oprname
|
|
FROM pg_operator as p1
|
|
WHERE (p1.oprleft = 0 and p1.oprkind != 'l') OR
|
|
(p1.oprleft != 0 and p1.oprkind = 'l') OR
|
|
(p1.oprright = 0 and p1.oprkind != 'r') OR
|
|
(p1.oprright != 0 and p1.oprkind = 'r');
|
|
oid | oprname
|
|
-----+---------
|
|
(0 rows)
|
|
|
|
-- Look for conflicting operator definitions (same names and input datatypes).
|
|
SELECT p1.oid, p1.oprcode, p2.oid, p2.oprcode
|
|
FROM pg_operator AS p1, pg_operator AS p2
|
|
WHERE p1.oid != p2.oid AND
|
|
p1.oprname = p2.oprname AND
|
|
p1.oprkind = p2.oprkind AND
|
|
p1.oprleft = p2.oprleft AND
|
|
p1.oprright = p2.oprright;
|
|
oid | oprcode | oid | oprcode
|
|
-----+---------+-----+---------
|
|
(0 rows)
|
|
|
|
-- Look for commutative operators that don't commute.
|
|
-- DEFINITIONAL NOTE: If A.oprcom = B, then x A y has the same result as y B x.
|
|
-- We expect that B will always say that B.oprcom = A as well; that's not
|
|
-- inherently essential, but it would be inefficient not to mark it so.
|
|
SELECT p1.oid, p1.oprcode, p2.oid, p2.oprcode
|
|
FROM pg_operator AS p1, pg_operator AS p2
|
|
WHERE p1.oprcom = p2.oid AND
|
|
(p1.oprkind != 'b' OR
|
|
p1.oprleft != p2.oprright OR
|
|
p1.oprright != p2.oprleft OR
|
|
p1.oprresult != p2.oprresult OR
|
|
p1.oid != p2.oprcom);
|
|
oid | oprcode | oid | oprcode
|
|
-----+---------+-----+---------
|
|
(0 rows)
|
|
|
|
-- Look for negatory operators that don't agree.
|
|
-- DEFINITIONAL NOTE: If A.oprnegate = B, then both A and B must yield
|
|
-- boolean results, and (x A y) == ! (x B y), or the equivalent for
|
|
-- single-operand operators.
|
|
-- We expect that B will always say that B.oprnegate = A as well; that's not
|
|
-- inherently essential, but it would be inefficient not to mark it so.
|
|
-- Also, A and B had better not be the same operator.
|
|
SELECT p1.oid, p1.oprcode, p2.oid, p2.oprcode
|
|
FROM pg_operator AS p1, pg_operator AS p2
|
|
WHERE p1.oprnegate = p2.oid AND
|
|
(p1.oprkind != p2.oprkind OR
|
|
p1.oprleft != p2.oprleft OR
|
|
p1.oprright != p2.oprright OR
|
|
p1.oprresult != 'bool'::regtype OR
|
|
p2.oprresult != 'bool'::regtype OR
|
|
p1.oid != p2.oprnegate OR
|
|
p1.oid = p2.oid);
|
|
oid | oprcode | oid | oprcode
|
|
-----+---------+-----+---------
|
|
(0 rows)
|
|
|
|
-- Look for mergejoin operators that don't match their links.
|
|
-- An lsortop/rsortop link leads from an '=' operator to the
|
|
-- sort operator ('<' operator) that's appropriate for
|
|
-- its left-side or right-side data type.
|
|
-- An ltcmpop/gtcmpop link leads from an '=' operator to the
|
|
-- '<' or '>' operator of the same input datatypes.
|
|
-- (If the '=' operator has identical L and R input datatypes,
|
|
-- then lsortop, rsortop, and ltcmpop are all the same operator.)
|
|
SELECT p1.oid, p1.oprcode, p2.oid, p2.oprcode
|
|
FROM pg_operator AS p1, pg_operator AS p2
|
|
WHERE p1.oprlsortop = p2.oid AND
|
|
(p1.oprname != '=' OR p2.oprname != '<' OR
|
|
p1.oprkind != 'b' OR p2.oprkind != 'b' OR
|
|
p1.oprleft != p2.oprleft OR
|
|
p1.oprleft != p2.oprright OR
|
|
p1.oprresult != 'bool'::regtype OR
|
|
p2.oprresult != 'bool'::regtype);
|
|
oid | oprcode | oid | oprcode
|
|
-----+---------+-----+---------
|
|
(0 rows)
|
|
|
|
SELECT p1.oid, p1.oprcode, p2.oid, p2.oprcode
|
|
FROM pg_operator AS p1, pg_operator AS p2
|
|
WHERE p1.oprrsortop = p2.oid AND
|
|
(p1.oprname != '=' OR p2.oprname != '<' OR
|
|
p1.oprkind != 'b' OR p2.oprkind != 'b' OR
|
|
p1.oprright != p2.oprleft OR
|
|
p1.oprright != p2.oprright OR
|
|
p1.oprresult != 'bool'::regtype OR
|
|
p2.oprresult != 'bool'::regtype);
|
|
oid | oprcode | oid | oprcode
|
|
-----+---------+-----+---------
|
|
(0 rows)
|
|
|
|
SELECT p1.oid, p1.oprcode, p2.oid, p2.oprcode
|
|
FROM pg_operator AS p1, pg_operator AS p2
|
|
WHERE p1.oprltcmpop = p2.oid AND
|
|
(p1.oprname != '=' OR p2.oprname != '<' OR
|
|
p1.oprkind != 'b' OR p2.oprkind != 'b' OR
|
|
p1.oprleft != p2.oprleft OR
|
|
p1.oprright != p2.oprright OR
|
|
p1.oprresult != 'bool'::regtype OR
|
|
p2.oprresult != 'bool'::regtype);
|
|
oid | oprcode | oid | oprcode
|
|
-----+---------+-----+---------
|
|
(0 rows)
|
|
|
|
SELECT p1.oid, p1.oprcode, p2.oid, p2.oprcode
|
|
FROM pg_operator AS p1, pg_operator AS p2
|
|
WHERE p1.oprgtcmpop = p2.oid AND
|
|
(p1.oprname != '=' OR p2.oprname != '>' OR
|
|
p1.oprkind != 'b' OR p2.oprkind != 'b' OR
|
|
p1.oprleft != p2.oprleft OR
|
|
p1.oprright != p2.oprright OR
|
|
p1.oprresult != 'bool'::regtype OR
|
|
p2.oprresult != 'bool'::regtype);
|
|
oid | oprcode | oid | oprcode
|
|
-----+---------+-----+---------
|
|
(0 rows)
|
|
|
|
-- Make sure all four links are specified if any are.
|
|
SELECT p1.oid, p1.oprcode
|
|
FROM pg_operator AS p1
|
|
WHERE NOT ((oprlsortop = 0 AND oprrsortop = 0 AND
|
|
oprltcmpop = 0 AND oprgtcmpop = 0) OR
|
|
(oprlsortop != 0 AND oprrsortop != 0 AND
|
|
oprltcmpop != 0 AND oprgtcmpop != 0));
|
|
oid | oprcode
|
|
-----+---------
|
|
(0 rows)
|
|
|
|
-- A mergejoinable = operator must have a commutator (usually itself).
|
|
SELECT p1.oid, p1.oprname FROM pg_operator AS p1
|
|
WHERE p1.oprlsortop != 0 AND
|
|
p1.oprcom = 0;
|
|
oid | oprname
|
|
-----+---------
|
|
(0 rows)
|
|
|
|
-- Mergejoinable operators across datatypes must come in closed sets, that
|
|
-- is if you provide int2 = int4 and int4 = int8 then you must also provide
|
|
-- int2 = int8 (and commutators of all these). This is necessary because
|
|
-- the planner tries to deduce additional qual clauses from transitivity
|
|
-- of mergejoinable operators. If there are clauses int2var = int4var and
|
|
-- int4var = int8var, the planner will deduce int2var = int8var ... and it
|
|
-- had better have a way to represent it.
|
|
SELECT p1.oid, p2.oid FROM pg_operator AS p1, pg_operator AS p2
|
|
WHERE p1.oprlsortop != p1.oprrsortop AND
|
|
p1.oprrsortop = p2.oprlsortop AND
|
|
p2.oprlsortop != p2.oprrsortop AND
|
|
NOT EXISTS (SELECT 1 FROM pg_operator p3 WHERE
|
|
p3.oprlsortop = p1.oprlsortop AND p3.oprrsortop = p2.oprrsortop);
|
|
oid | oid
|
|
-----+-----
|
|
(0 rows)
|
|
|
|
-- Hashing only works on simple equality operators "type = sametype",
|
|
-- since the hash itself depends on the bitwise representation of the type.
|
|
-- Check that allegedly hashable operators look like they might be "=".
|
|
-- NOTE: in 7.3, this search finds xideqint4.
|
|
-- Until we have some cleaner way of dealing with binary-equivalent types,
|
|
-- just leave that tuple in the expected output.
|
|
SELECT p1.oid, p1.oprname
|
|
FROM pg_operator AS p1
|
|
WHERE p1.oprcanhash AND NOT
|
|
(p1.oprkind = 'b' AND p1.oprresult = 'bool'::regtype AND
|
|
p1.oprleft = p1.oprright AND p1.oprname = '=' AND p1.oprcom = p1.oid);
|
|
oid | oprname
|
|
-----+---------
|
|
353 | =
|
|
(1 row)
|
|
|
|
-- In 6.5 we accepted hashable array equality operators when the array element
|
|
-- type is hashable. However, what we actually need to make hashjoin work on
|
|
-- an array is a hashable element type *and* no padding between elements in
|
|
-- the array storage (or, perhaps, guaranteed-zero padding). Currently,
|
|
-- since the padding code in arrayfuncs.c is pretty bogus, it seems safest
|
|
-- to just forbid hashjoin on array equality ops.
|
|
-- This should be reconsidered someday.
|
|
-- -- Look for array equality operators that are hashable when the underlying
|
|
-- -- type is not, or vice versa. This is presumably bogus.
|
|
--
|
|
-- SELECT p1.oid, p1.oprcanhash, p2.oid, p2.oprcanhash, t1.typname, t2.typname
|
|
-- FROM pg_operator AS p1, pg_operator AS p2, pg_type AS t1, pg_type AS t2
|
|
-- WHERE p1.oprname = '=' AND p1.oprleft = p1.oprright AND
|
|
-- p2.oprname = '=' AND p2.oprleft = p2.oprright AND
|
|
-- p1.oprleft = t1.oid AND p2.oprleft = t2.oid AND t1.typelem = t2.oid AND
|
|
-- p1.oprcanhash != p2.oprcanhash;
|
|
-- Substitute check: forbid hashable array ops, period.
|
|
SELECT p1.oid, p1.oprname
|
|
FROM pg_operator AS p1, pg_proc AS p2
|
|
WHERE p1.oprcanhash AND p1.oprcode = p2.oid AND p2.proname = 'array_eq';
|
|
oid | oprname
|
|
-----+---------
|
|
(0 rows)
|
|
|
|
-- Check that each operator defined in pg_operator matches its oprcode entry
|
|
-- in pg_proc. Easiest to do this separately for each oprkind.
|
|
-- FIXME: want to check that argument/result types match, but how to do that
|
|
-- in the face of binary-compatible types?
|
|
SELECT p1.oid, p1.oprname, p2.oid, p2.proname
|
|
FROM pg_operator AS p1, pg_proc AS p2
|
|
WHERE p1.oprcode = p2.oid AND
|
|
p1.oprkind = 'b' AND
|
|
(p2.pronargs != 2
|
|
-- diked out until we find a way of marking binary-compatible types
|
|
-- OR
|
|
-- p1.oprresult != p2.prorettype OR
|
|
-- (p1.oprleft != p2.proargtypes[0] AND p2.proargtypes[0] != 0) OR
|
|
-- (p1.oprright != p2.proargtypes[1] AND p2.proargtypes[1] != 0)
|
|
);
|
|
oid | oprname | oid | proname
|
|
-----+---------+-----+---------
|
|
(0 rows)
|
|
|
|
-- These two selects can be left as-is because there are no binary-compatible
|
|
-- cases that they trip over, at least in 6.5:
|
|
SELECT p1.oid, p1.oprname, p2.oid, p2.proname
|
|
FROM pg_operator AS p1, pg_proc AS p2
|
|
WHERE p1.oprcode = p2.oid AND
|
|
p1.oprkind = 'l' AND
|
|
(p2.pronargs != 1 OR
|
|
p1.oprresult != p2.prorettype OR
|
|
(p1.oprright != p2.proargtypes[0] AND p2.proargtypes[0] != 0) OR
|
|
p1.oprleft != 0);
|
|
oid | oprname | oid | proname
|
|
-----+---------+-----+---------
|
|
(0 rows)
|
|
|
|
SELECT p1.oid, p1.oprname, p2.oid, p2.proname
|
|
FROM pg_operator AS p1, pg_proc AS p2
|
|
WHERE p1.oprcode = p2.oid AND
|
|
p1.oprkind = 'r' AND
|
|
(p2.pronargs != 1 OR
|
|
p1.oprresult != p2.prorettype OR
|
|
(p1.oprleft != p2.proargtypes[0] AND p2.proargtypes[0] != 0) OR
|
|
p1.oprright != 0);
|
|
oid | oprname | oid | proname
|
|
-----+---------+-----+---------
|
|
(0 rows)
|
|
|
|
-- If the operator is mergejoinable or hashjoinable, its underlying function
|
|
-- should not be volatile.
|
|
SELECT p1.oid, p1.oprname, p2.oid, p2.proname
|
|
FROM pg_operator AS p1, pg_proc AS p2
|
|
WHERE p1.oprcode = p2.oid AND
|
|
(p1.oprlsortop != 0 OR p1.oprcanhash) AND
|
|
p2.provolatile = 'v';
|
|
oid | oprname | oid | proname
|
|
-----+---------+-----+---------
|
|
(0 rows)
|
|
|
|
-- If oprrest is set, the operator must return boolean,
|
|
-- and it must link to a proc with the right signature
|
|
-- to be a restriction selectivity estimator.
|
|
-- The proc signature we want is: float8 proc(internal, oid, internal, int4)
|
|
SELECT p1.oid, p1.oprname, p2.oid, p2.proname
|
|
FROM pg_operator AS p1, pg_proc AS p2
|
|
WHERE p1.oprrest = p2.oid AND
|
|
(p1.oprresult != 'bool'::regtype OR
|
|
p2.prorettype != 'float8'::regtype OR p2.proretset OR
|
|
p2.pronargs != 4 OR
|
|
p2.proargtypes[0] != 'internal'::regtype OR
|
|
p2.proargtypes[1] != 'oid'::regtype OR
|
|
p2.proargtypes[2] != 'internal'::regtype OR
|
|
p2.proargtypes[3] != 'int4'::regtype);
|
|
oid | oprname | oid | proname
|
|
-----+---------+-----+---------
|
|
(0 rows)
|
|
|
|
-- If oprjoin is set, the operator must be a binary boolean op,
|
|
-- and it must link to a proc with the right signature
|
|
-- to be a join selectivity estimator.
|
|
-- The proc signature we want is: float8 proc(internal, oid, internal, int2)
|
|
SELECT p1.oid, p1.oprname, p2.oid, p2.proname
|
|
FROM pg_operator AS p1, pg_proc AS p2
|
|
WHERE p1.oprjoin = p2.oid AND
|
|
(p1.oprkind != 'b' OR p1.oprresult != 'bool'::regtype OR
|
|
p2.prorettype != 'float8'::regtype OR p2.proretset OR
|
|
p2.pronargs != 4 OR
|
|
p2.proargtypes[0] != 'internal'::regtype OR
|
|
p2.proargtypes[1] != 'oid'::regtype OR
|
|
p2.proargtypes[2] != 'internal'::regtype OR
|
|
p2.proargtypes[3] != 'int2'::regtype);
|
|
oid | oprname | oid | proname
|
|
-----+---------+-----+---------
|
|
(0 rows)
|
|
|
|
-- **************** pg_aggregate ****************
|
|
-- Look for illegal values in pg_aggregate fields.
|
|
SELECT ctid, aggfnoid::oid
|
|
FROM pg_aggregate as p1
|
|
WHERE aggfnoid = 0 OR aggtransfn = 0 OR aggtranstype = 0;
|
|
ctid | aggfnoid
|
|
------+----------
|
|
(0 rows)
|
|
|
|
-- Make sure the matching pg_proc entry is sensible, too.
|
|
SELECT a.aggfnoid::oid, p.proname
|
|
FROM pg_aggregate as a, pg_proc as p
|
|
WHERE a.aggfnoid = p.oid AND
|
|
(NOT p.proisagg OR p.pronargs != 1 OR p.proretset);
|
|
aggfnoid | proname
|
|
----------+---------
|
|
(0 rows)
|
|
|
|
-- Make sure there are no proisagg pg_proc entries without matches.
|
|
SELECT oid, proname
|
|
FROM pg_proc as p
|
|
WHERE p.proisagg AND
|
|
NOT EXISTS (SELECT 1 FROM pg_aggregate a WHERE a.aggfnoid = p.oid);
|
|
oid | proname
|
|
-----+---------
|
|
(0 rows)
|
|
|
|
-- If there is no finalfn then the output type must be the transtype.
|
|
SELECT a.aggfnoid::oid, p.proname
|
|
FROM pg_aggregate as a, pg_proc as p
|
|
WHERE a.aggfnoid = p.oid AND
|
|
a.aggfinalfn = 0 AND p.prorettype != a.aggtranstype;
|
|
aggfnoid | proname
|
|
----------+---------
|
|
(0 rows)
|
|
|
|
-- Cross-check transfn against its entry in pg_proc.
|
|
-- FIXME: what about binary-compatible types?
|
|
-- NOTE: in 7.1, this search finds max and min on abstime, which are
|
|
-- implemented using int4larger/int4smaller. Until we have
|
|
-- some cleaner way of dealing with binary-equivalent types, just leave
|
|
-- those two tuples in the expected output.
|
|
SELECT a.aggfnoid::oid, p.proname, p2.oid, p2.proname
|
|
FROM pg_aggregate AS a, pg_proc AS p, pg_proc AS p2
|
|
WHERE a.aggfnoid = p.oid AND
|
|
a.aggtransfn = p2.oid AND
|
|
(p2.proretset OR
|
|
a.aggtranstype != p2.prorettype OR
|
|
a.aggtranstype != p2.proargtypes[0] OR
|
|
NOT ((p2.pronargs = 2 AND p.proargtypes[0] = p2.proargtypes[1]) OR
|
|
(p2.pronargs = 1 AND p.proargtypes[0] = '"any"'::regtype)))
|
|
ORDER BY 1;
|
|
aggfnoid | proname | oid | proname
|
|
----------+---------+-----+-------------
|
|
2121 | max | 768 | int4larger
|
|
2137 | min | 769 | int4smaller
|
|
(2 rows)
|
|
|
|
-- Cross-check finalfn (if present) against its entry in pg_proc.
|
|
-- FIXME: what about binary-compatible types?
|
|
SELECT a.aggfnoid::oid, p.proname, p2.oid, p2.proname
|
|
FROM pg_aggregate AS a, pg_proc AS p, pg_proc AS p2
|
|
WHERE a.aggfnoid = p.oid AND
|
|
a.aggfinalfn = p2.oid AND
|
|
(p2.proretset OR p.prorettype != p2.prorettype OR
|
|
p2.pronargs != 1 OR
|
|
a.aggtranstype != p2.proargtypes[0]);
|
|
aggfnoid | proname | oid | proname
|
|
----------+---------+-----+---------
|
|
(0 rows)
|
|
|
|
-- If transfn is strict then either initval should be non-NULL, or
|
|
-- input type should equal transtype so that the first non-null input
|
|
-- can be assigned as the state value.
|
|
SELECT a.aggfnoid::oid, p.proname, p2.oid, p2.proname
|
|
FROM pg_aggregate AS a, pg_proc AS p, pg_proc AS p2
|
|
WHERE a.aggfnoid = p.oid AND
|
|
a.aggtransfn = p2.oid AND p2.proisstrict AND
|
|
a.agginitval IS NULL AND p.proargtypes[0] != a.aggtranstype;
|
|
aggfnoid | proname | oid | proname
|
|
----------+---------+-----+---------
|
|
(0 rows)
|
|
|
|
-- **************** pg_opclass ****************
|
|
-- Look for illegal values in pg_opclass fields
|
|
SELECT p1.oid
|
|
FROM pg_opclass as p1
|
|
WHERE p1.opcamid = 0 OR p1.opcintype = 0;
|
|
oid
|
|
-----
|
|
(0 rows)
|
|
|
|
-- There should not be multiple entries in pg_opclass with opcdefault true
|
|
-- and the same opcamid/opcintype combination.
|
|
SELECT p1.oid, p2.oid
|
|
FROM pg_opclass AS p1, pg_opclass AS p2
|
|
WHERE p1.oid != p2.oid AND
|
|
p1.opcamid = p2.opcamid AND p1.opcintype = p2.opcintype AND
|
|
p1.opcdefault AND p2.opcdefault;
|
|
oid | oid
|
|
-----+-----
|
|
(0 rows)
|
|
|
|
-- **************** pg_amop ****************
|
|
-- Look for illegal values in pg_amop fields
|
|
SELECT p1.amopclaid, p1.amopstrategy
|
|
FROM pg_amop as p1
|
|
WHERE p1.amopclaid = 0 OR p1.amopstrategy <= 0 OR p1.amopopr = 0;
|
|
amopclaid | amopstrategy
|
|
-----------+--------------
|
|
(0 rows)
|
|
|
|
-- Cross-check amopstrategy index against parent AM
|
|
SELECT p1.amopclaid, p1.amopopr, p2.oid, p2.amname
|
|
FROM pg_amop AS p1, pg_am AS p2, pg_opclass AS p3
|
|
WHERE p1.amopclaid = p3.oid AND p3.opcamid = p2.oid AND
|
|
p1.amopstrategy > p2.amstrategies;
|
|
amopclaid | amopopr | oid | amname
|
|
-----------+---------+-----+--------
|
|
(0 rows)
|
|
|
|
-- Detect missing pg_amop entries: should have as many strategy functions
|
|
-- as AM expects for each opclass for the AM
|
|
SELECT p1.oid, p1.amname, p2.oid, p2.opcname
|
|
FROM pg_am AS p1, pg_opclass AS p2
|
|
WHERE p2.opcamid = p1.oid AND
|
|
p1.amstrategies != (SELECT count(*) FROM pg_amop AS p3
|
|
WHERE p3.amopclaid = p2.oid);
|
|
oid | amname | oid | opcname
|
|
-----+--------+-----+---------
|
|
(0 rows)
|
|
|
|
-- Check that amopopr points at a reasonable-looking operator, ie a binary
|
|
-- operator yielding boolean.
|
|
-- NOTE: for 7.1, add restriction that operator inputs are of same type.
|
|
-- We used to have opclasses like "int24_ops" but these were broken.
|
|
SELECT p1.amopclaid, p1.amopopr, p2.oid, p2.oprname
|
|
FROM pg_amop AS p1, pg_operator AS p2
|
|
WHERE p1.amopopr = p2.oid AND
|
|
(p2.oprkind != 'b' OR p2.oprresult != 'bool'::regtype OR
|
|
p2.oprleft != p2.oprright);
|
|
amopclaid | amopopr | oid | oprname
|
|
-----------+---------+-----+---------
|
|
(0 rows)
|
|
|
|
-- Check that all operators linked to by opclass entries have selectivity
|
|
-- estimators. This is not absolutely required, but it seems a reasonable
|
|
-- thing to insist on for all standard datatypes.
|
|
SELECT p1.amopclaid, p1.amopopr, p2.oid, p2.oprname
|
|
FROM pg_amop AS p1, pg_operator AS p2
|
|
WHERE p1.amopopr = p2.oid AND
|
|
(p2.oprrest = 0 OR p2.oprjoin = 0);
|
|
amopclaid | amopopr | oid | oprname
|
|
-----------+---------+-----+---------
|
|
(0 rows)
|
|
|
|
-- Check that operator input types match the opclass
|
|
SELECT p1.amopclaid, p1.amopopr, p2.oid, p2.oprname, p3.opcname
|
|
FROM pg_amop AS p1, pg_operator AS p2, pg_opclass AS p3
|
|
WHERE p1.amopopr = p2.oid AND p1.amopclaid = p3.oid AND
|
|
(p3.opcintype != p2.oprleft OR p3.opcintype != p2.oprright);
|
|
amopclaid | amopopr | oid | oprname | opcname
|
|
-----------+---------+-----+---------+---------
|
|
(0 rows)
|
|
|
|
-- **************** pg_amproc ****************
|
|
-- Look for illegal values in pg_amproc fields
|
|
SELECT p1.amopclaid, p1.amprocnum
|
|
FROM pg_amproc as p1
|
|
WHERE p1.amopclaid = 0 OR p1.amprocnum <= 0 OR p1.amproc = 0;
|
|
amopclaid | amprocnum
|
|
-----------+-----------
|
|
(0 rows)
|
|
|
|
-- Cross-check amprocnum index against parent AM
|
|
SELECT p1.amopclaid, p1.amprocnum, p2.oid, p2.amname
|
|
FROM pg_amproc AS p1, pg_am AS p2, pg_opclass AS p3
|
|
WHERE p1.amopclaid = p3.oid AND p3.opcamid = p2.oid AND
|
|
p1.amprocnum > p2.amsupport;
|
|
amopclaid | amprocnum | oid | amname
|
|
-----------+-----------+-----+--------
|
|
(0 rows)
|
|
|
|
-- Detect missing pg_amproc entries: should have as many support functions
|
|
-- as AM expects for each opclass for the AM
|
|
SELECT p1.oid, p1.amname, p2.oid, p2.opcname
|
|
FROM pg_am AS p1, pg_opclass AS p2
|
|
WHERE p2.opcamid = p1.oid AND
|
|
p1.amsupport != (SELECT count(*) FROM pg_amproc AS p3
|
|
WHERE p3.amopclaid = p2.oid);
|
|
oid | amname | oid | opcname
|
|
-----+--------+-----+---------
|
|
(0 rows)
|
|
|
|
-- Unfortunately, we can't check the amproc link very well because the
|
|
-- signature of the function may be different for different support routines
|
|
-- or different base data types.
|
|
-- We can check that all the referenced instances of the same support
|
|
-- routine number take the same number of parameters, but that's about it...
|
|
SELECT p1.amopclaid, p1.amprocnum,
|
|
p2.oid, p2.proname,
|
|
p3.opcname,
|
|
p4.amopclaid, p4.amprocnum,
|
|
p5.oid, p5.proname,
|
|
p6.opcname
|
|
FROM pg_amproc AS p1, pg_proc AS p2, pg_opclass AS p3,
|
|
pg_amproc AS p4, pg_proc AS p5, pg_opclass AS p6
|
|
WHERE p1.amopclaid = p3.oid AND p4.amopclaid = p6.oid AND
|
|
p3.opcamid = p6.opcamid AND p1.amprocnum = p4.amprocnum AND
|
|
p1.amproc = p2.oid AND p4.amproc = p5.oid AND
|
|
(p2.proretset OR p5.proretset OR p2.pronargs != p5.pronargs);
|
|
amopclaid | amprocnum | oid | proname | opcname | amopclaid | amprocnum | oid | proname | opcname
|
|
-----------+-----------+-----+---------+---------+-----------+-----------+-----+---------+---------
|
|
(0 rows)
|
|
|