mirror of
https://github.com/postgres/postgres.git
synced 2025-07-30 11:03:19 +03:00
Restructure index access method API to hide most of it at the C level.
This patch reduces pg_am to just two columns, a name and a handler function. All the data formerly obtained from pg_am is now provided in a C struct returned by the handler function. This is similar to the designs we've adopted for FDWs and tablesample methods. There are multiple advantages. For one, the index AM's support functions are now simple C functions, making them faster to call and much less error-prone, since the C compiler can now check function signatures. For another, this will make it far more practical to define index access methods in installable extensions. A disadvantage is that SQL-level code can no longer see attributes of index AMs; in particular, some of the crosschecks in the opr_sanity regression test are no longer possible from SQL. We've addressed that by adding a facility for the index AM to perform such checks instead. (Much more could be done in that line, but for now we're content if the amvalidate functions more or less replace what opr_sanity used to do.) We might also want to expose some sort of reporting functionality, but this patch doesn't do that. Alexander Korotkov, reviewed by Petr Jelínek, and rather heavily editorialized on by me.
This commit is contained in:
@ -73,131 +73,11 @@ WHERE aggmtranstype != 0 AND
|
||||
------+---------------
|
||||
(0 rows)
|
||||
|
||||
SELECT ctid, amkeytype
|
||||
SELECT ctid, amhandler
|
||||
FROM pg_catalog.pg_am fk
|
||||
WHERE amkeytype != 0 AND
|
||||
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amkeytype);
|
||||
ctid | amkeytype
|
||||
------+-----------
|
||||
(0 rows)
|
||||
|
||||
SELECT ctid, aminsert
|
||||
FROM pg_catalog.pg_am fk
|
||||
WHERE aminsert != 0 AND
|
||||
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aminsert);
|
||||
ctid | aminsert
|
||||
------+----------
|
||||
(0 rows)
|
||||
|
||||
SELECT ctid, ambeginscan
|
||||
FROM pg_catalog.pg_am fk
|
||||
WHERE ambeginscan != 0 AND
|
||||
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambeginscan);
|
||||
ctid | ambeginscan
|
||||
------+-------------
|
||||
(0 rows)
|
||||
|
||||
SELECT ctid, amgettuple
|
||||
FROM pg_catalog.pg_am fk
|
||||
WHERE amgettuple != 0 AND
|
||||
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgettuple);
|
||||
ctid | amgettuple
|
||||
------+------------
|
||||
(0 rows)
|
||||
|
||||
SELECT ctid, amgetbitmap
|
||||
FROM pg_catalog.pg_am fk
|
||||
WHERE amgetbitmap != 0 AND
|
||||
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgetbitmap);
|
||||
ctid | amgetbitmap
|
||||
------+-------------
|
||||
(0 rows)
|
||||
|
||||
SELECT ctid, amrescan
|
||||
FROM pg_catalog.pg_am fk
|
||||
WHERE amrescan != 0 AND
|
||||
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amrescan);
|
||||
ctid | amrescan
|
||||
------+----------
|
||||
(0 rows)
|
||||
|
||||
SELECT ctid, amendscan
|
||||
FROM pg_catalog.pg_am fk
|
||||
WHERE amendscan != 0 AND
|
||||
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amendscan);
|
||||
ctid | amendscan
|
||||
------+-----------
|
||||
(0 rows)
|
||||
|
||||
SELECT ctid, ammarkpos
|
||||
FROM pg_catalog.pg_am fk
|
||||
WHERE ammarkpos != 0 AND
|
||||
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ammarkpos);
|
||||
ctid | ammarkpos
|
||||
------+-----------
|
||||
(0 rows)
|
||||
|
||||
SELECT ctid, amrestrpos
|
||||
FROM pg_catalog.pg_am fk
|
||||
WHERE amrestrpos != 0 AND
|
||||
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amrestrpos);
|
||||
ctid | amrestrpos
|
||||
------+------------
|
||||
(0 rows)
|
||||
|
||||
SELECT ctid, ambuild
|
||||
FROM pg_catalog.pg_am fk
|
||||
WHERE ambuild != 0 AND
|
||||
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambuild);
|
||||
ctid | ambuild
|
||||
------+---------
|
||||
(0 rows)
|
||||
|
||||
SELECT ctid, ambuildempty
|
||||
FROM pg_catalog.pg_am fk
|
||||
WHERE ambuildempty != 0 AND
|
||||
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambuildempty);
|
||||
ctid | ambuildempty
|
||||
------+--------------
|
||||
(0 rows)
|
||||
|
||||
SELECT ctid, ambulkdelete
|
||||
FROM pg_catalog.pg_am fk
|
||||
WHERE ambulkdelete != 0 AND
|
||||
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambulkdelete);
|
||||
ctid | ambulkdelete
|
||||
------+--------------
|
||||
(0 rows)
|
||||
|
||||
SELECT ctid, amvacuumcleanup
|
||||
FROM pg_catalog.pg_am fk
|
||||
WHERE amvacuumcleanup != 0 AND
|
||||
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amvacuumcleanup);
|
||||
ctid | amvacuumcleanup
|
||||
------+-----------------
|
||||
(0 rows)
|
||||
|
||||
SELECT ctid, amcanreturn
|
||||
FROM pg_catalog.pg_am fk
|
||||
WHERE amcanreturn != 0 AND
|
||||
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amcanreturn);
|
||||
ctid | amcanreturn
|
||||
------+-------------
|
||||
(0 rows)
|
||||
|
||||
SELECT ctid, amcostestimate
|
||||
FROM pg_catalog.pg_am fk
|
||||
WHERE amcostestimate != 0 AND
|
||||
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amcostestimate);
|
||||
ctid | amcostestimate
|
||||
------+----------------
|
||||
(0 rows)
|
||||
|
||||
SELECT ctid, amoptions
|
||||
FROM pg_catalog.pg_am fk
|
||||
WHERE amoptions != 0 AND
|
||||
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amoptions);
|
||||
ctid | amoptions
|
||||
WHERE amhandler != 0 AND
|
||||
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amhandler);
|
||||
ctid | amhandler
|
||||
------+-----------
|
||||
(0 rows)
|
||||
|
||||
@ -809,6 +689,14 @@ WHERE opfowner != 0 AND
|
||||
------+----------
|
||||
(0 rows)
|
||||
|
||||
SELECT ctid, polrelid
|
||||
FROM pg_catalog.pg_policy fk
|
||||
WHERE polrelid != 0 AND
|
||||
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.polrelid);
|
||||
ctid | polrelid
|
||||
------+----------
|
||||
(0 rows)
|
||||
|
||||
SELECT ctid, pronamespace
|
||||
FROM pg_catalog.pg_proc fk
|
||||
WHERE pronamespace != 0 AND
|
||||
|
@ -1565,6 +1565,32 @@ WHERE p1.oid != p2.oid AND
|
||||
-----+-----
|
||||
(0 rows)
|
||||
|
||||
-- Ask access methods to validate opclasses
|
||||
SELECT oid, opcname FROM pg_opclass WHERE NOT amvalidate(oid);
|
||||
oid | opcname
|
||||
-----+---------
|
||||
(0 rows)
|
||||
|
||||
-- **************** pg_am ****************
|
||||
-- Look for illegal values in pg_am fields
|
||||
SELECT p1.oid, p1.amname
|
||||
FROM pg_am AS p1
|
||||
WHERE p1.amhandler = 0;
|
||||
oid | amname
|
||||
-----+--------
|
||||
(0 rows)
|
||||
|
||||
-- Check for amhandler functions with the wrong signature
|
||||
SELECT p1.oid, p1.amname, p2.oid, p2.proname
|
||||
FROM pg_am AS p1, pg_proc AS p2
|
||||
WHERE p2.oid = p1.amhandler AND
|
||||
(p2.prorettype != 'index_am_handler'::regtype OR p2.proretset
|
||||
OR p2.pronargs != 1
|
||||
OR p2.proargtypes[0] != 'internal'::regtype);
|
||||
oid | amname | oid | proname
|
||||
-----+--------+-----+---------
|
||||
(0 rows)
|
||||
|
||||
-- **************** pg_amop ****************
|
||||
-- Look for illegal values in pg_amop fields
|
||||
SELECT p1.amopfamily, p1.amopstrategy
|
||||
@ -1610,49 +1636,6 @@ WHERE p1.amopsortfamily <> 0 AND NOT EXISTS
|
||||
------------+--------------
|
||||
(0 rows)
|
||||
|
||||
-- check for ordering operators not supported by parent AM
|
||||
SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
|
||||
FROM pg_amop AS p1, pg_am AS p2
|
||||
WHERE p1.amopmethod = p2.oid AND
|
||||
p1.amoppurpose = 'o' AND NOT p2.amcanorderbyop;
|
||||
amopfamily | amopopr | oid | amname
|
||||
------------+---------+-----+--------
|
||||
(0 rows)
|
||||
|
||||
-- Cross-check amopstrategy index against parent AM
|
||||
SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
|
||||
FROM pg_amop AS p1, pg_am AS p2
|
||||
WHERE p1.amopmethod = p2.oid AND
|
||||
p1.amopstrategy > p2.amstrategies AND p2.amstrategies <> 0;
|
||||
amopfamily | amopopr | oid | amname
|
||||
------------+---------+-----+--------
|
||||
(0 rows)
|
||||
|
||||
-- Detect missing pg_amop entries: should have as many strategy operators
|
||||
-- as AM expects for each datatype combination supported by the opfamily.
|
||||
-- We can't check this for AMs with variable strategy sets.
|
||||
SELECT p1.amname, p2.amoplefttype, p2.amoprighttype
|
||||
FROM pg_am AS p1, pg_amop AS p2
|
||||
WHERE p2.amopmethod = p1.oid AND
|
||||
p1.amstrategies <> 0 AND
|
||||
p1.amstrategies != (SELECT count(*) FROM pg_amop AS p3
|
||||
WHERE p3.amopfamily = p2.amopfamily AND
|
||||
p3.amoplefttype = p2.amoplefttype AND
|
||||
p3.amoprighttype = p2.amoprighttype AND
|
||||
p3.amoppurpose = 's');
|
||||
amname | amoplefttype | amoprighttype
|
||||
--------+--------------+---------------
|
||||
(0 rows)
|
||||
|
||||
-- Currently, none of the AMs with fixed strategy sets support ordering ops.
|
||||
SELECT p1.amname, p2.amopfamily, p2.amopstrategy
|
||||
FROM pg_am AS p1, pg_amop AS p2
|
||||
WHERE p2.amopmethod = p1.oid AND
|
||||
p1.amstrategies <> 0 AND p2.amoppurpose <> 's';
|
||||
amname | amopfamily | amopstrategy
|
||||
--------+------------+--------------
|
||||
(0 rows)
|
||||
|
||||
-- Check that amopopr points at a reasonable-looking operator, ie a binary
|
||||
-- operator. If it's a search operator it had better yield boolean,
|
||||
-- otherwise an input type of its sort opfamily.
|
||||
@ -1935,65 +1918,6 @@ WHERE p1.amprocfamily = 0 OR p1.amproclefttype = 0 OR p1.amprocrighttype = 0
|
||||
--------------+-----------
|
||||
(0 rows)
|
||||
|
||||
-- Cross-check amprocnum index against parent AM
|
||||
SELECT p1.amprocfamily, p1.amprocnum, p2.oid, p2.amname
|
||||
FROM pg_amproc AS p1, pg_am AS p2, pg_opfamily AS p3
|
||||
WHERE p1.amprocfamily = p3.oid AND p3.opfmethod = p2.oid AND
|
||||
p1.amprocnum > p2.amsupport;
|
||||
amprocfamily | amprocnum | oid | amname
|
||||
--------------+-----------+-----+--------
|
||||
(0 rows)
|
||||
|
||||
-- Detect missing pg_amproc entries: should have as many support functions
|
||||
-- as AM expects for each datatype combination supported by the opfamily.
|
||||
SELECT * FROM (
|
||||
SELECT p1.amname, p2.opfname, p3.amproclefttype, p3.amprocrighttype,
|
||||
array_agg(p3.amprocnum ORDER BY amprocnum) AS procnums
|
||||
FROM pg_am AS p1, pg_opfamily AS p2, pg_amproc AS p3
|
||||
WHERE p2.opfmethod = p1.oid AND p3.amprocfamily = p2.oid
|
||||
GROUP BY p1.amname, p2.opfname, p3.amproclefttype, p3.amprocrighttype
|
||||
) AS t
|
||||
WHERE NOT (
|
||||
-- btree has one mandatory and one optional support function.
|
||||
-- hash has one support function, which is mandatory.
|
||||
-- GiST has eight support functions, one of which is optional.
|
||||
-- GIN has six support functions. 1-3 are mandatory, 5 is optional, and
|
||||
-- at least one of 4 and 6 must be given.
|
||||
-- SP-GiST has five support functions, all mandatory
|
||||
-- BRIN has four mandatory support functions, and a bunch of optionals
|
||||
amname = 'btree' AND procnums @> '{1}' OR
|
||||
amname = 'hash' AND procnums = '{1}' OR
|
||||
amname = 'gist' AND procnums @> '{1, 2, 3, 4, 5, 6, 7}' OR
|
||||
amname = 'gin' AND (procnums @> '{1, 2, 3}' AND (procnums && '{4, 6}')) OR
|
||||
amname = 'spgist' AND procnums = '{1, 2, 3, 4, 5}' OR
|
||||
amname = 'brin' AND procnums @> '{1, 2, 3, 4}'
|
||||
);
|
||||
amname | opfname | amproclefttype | amprocrighttype | procnums
|
||||
--------+---------+----------------+-----------------+----------
|
||||
(0 rows)
|
||||
|
||||
-- Also, check if there are any pg_opclass entries that don't seem to have
|
||||
-- pg_amproc support.
|
||||
SELECT * FROM (
|
||||
SELECT amname, opcname, array_agg(amprocnum ORDER BY amprocnum) as procnums
|
||||
FROM pg_am am JOIN pg_opclass op ON opcmethod = am.oid
|
||||
LEFT JOIN pg_amproc p ON amprocfamily = opcfamily AND
|
||||
amproclefttype = amprocrighttype AND amproclefttype = opcintype
|
||||
GROUP BY amname, opcname, amprocfamily
|
||||
) AS t
|
||||
WHERE NOT (
|
||||
-- same per-AM rules as above
|
||||
amname = 'btree' AND procnums @> '{1}' OR
|
||||
amname = 'hash' AND procnums = '{1}' OR
|
||||
amname = 'gist' AND procnums @> '{1, 2, 3, 4, 5, 6, 7}' OR
|
||||
amname = 'gin' AND (procnums @> '{1, 2, 3}' AND (procnums && '{4, 6}')) OR
|
||||
amname = 'spgist' AND procnums = '{1, 2, 3, 4, 5}' OR
|
||||
amname = 'brin' AND procnums @> '{1, 2, 3, 4}'
|
||||
);
|
||||
amname | opcname | procnums
|
||||
--------+---------+----------
|
||||
(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.
|
||||
|
@ -37,70 +37,10 @@ SELECT ctid, aggmtranstype
|
||||
FROM pg_catalog.pg_aggregate fk
|
||||
WHERE aggmtranstype != 0 AND
|
||||
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.aggmtranstype);
|
||||
SELECT ctid, amkeytype
|
||||
SELECT ctid, amhandler
|
||||
FROM pg_catalog.pg_am fk
|
||||
WHERE amkeytype != 0 AND
|
||||
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type pk WHERE pk.oid = fk.amkeytype);
|
||||
SELECT ctid, aminsert
|
||||
FROM pg_catalog.pg_am fk
|
||||
WHERE aminsert != 0 AND
|
||||
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.aminsert);
|
||||
SELECT ctid, ambeginscan
|
||||
FROM pg_catalog.pg_am fk
|
||||
WHERE ambeginscan != 0 AND
|
||||
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambeginscan);
|
||||
SELECT ctid, amgettuple
|
||||
FROM pg_catalog.pg_am fk
|
||||
WHERE amgettuple != 0 AND
|
||||
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgettuple);
|
||||
SELECT ctid, amgetbitmap
|
||||
FROM pg_catalog.pg_am fk
|
||||
WHERE amgetbitmap != 0 AND
|
||||
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amgetbitmap);
|
||||
SELECT ctid, amrescan
|
||||
FROM pg_catalog.pg_am fk
|
||||
WHERE amrescan != 0 AND
|
||||
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amrescan);
|
||||
SELECT ctid, amendscan
|
||||
FROM pg_catalog.pg_am fk
|
||||
WHERE amendscan != 0 AND
|
||||
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amendscan);
|
||||
SELECT ctid, ammarkpos
|
||||
FROM pg_catalog.pg_am fk
|
||||
WHERE ammarkpos != 0 AND
|
||||
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ammarkpos);
|
||||
SELECT ctid, amrestrpos
|
||||
FROM pg_catalog.pg_am fk
|
||||
WHERE amrestrpos != 0 AND
|
||||
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amrestrpos);
|
||||
SELECT ctid, ambuild
|
||||
FROM pg_catalog.pg_am fk
|
||||
WHERE ambuild != 0 AND
|
||||
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambuild);
|
||||
SELECT ctid, ambuildempty
|
||||
FROM pg_catalog.pg_am fk
|
||||
WHERE ambuildempty != 0 AND
|
||||
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambuildempty);
|
||||
SELECT ctid, ambulkdelete
|
||||
FROM pg_catalog.pg_am fk
|
||||
WHERE ambulkdelete != 0 AND
|
||||
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.ambulkdelete);
|
||||
SELECT ctid, amvacuumcleanup
|
||||
FROM pg_catalog.pg_am fk
|
||||
WHERE amvacuumcleanup != 0 AND
|
||||
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amvacuumcleanup);
|
||||
SELECT ctid, amcanreturn
|
||||
FROM pg_catalog.pg_am fk
|
||||
WHERE amcanreturn != 0 AND
|
||||
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amcanreturn);
|
||||
SELECT ctid, amcostestimate
|
||||
FROM pg_catalog.pg_am fk
|
||||
WHERE amcostestimate != 0 AND
|
||||
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amcostestimate);
|
||||
SELECT ctid, amoptions
|
||||
FROM pg_catalog.pg_am fk
|
||||
WHERE amoptions != 0 AND
|
||||
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amoptions);
|
||||
WHERE amhandler != 0 AND
|
||||
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.amhandler);
|
||||
SELECT ctid, amopfamily
|
||||
FROM pg_catalog.pg_amop fk
|
||||
WHERE amopfamily != 0 AND
|
||||
@ -405,6 +345,10 @@ SELECT ctid, opfowner
|
||||
FROM pg_catalog.pg_opfamily fk
|
||||
WHERE opfowner != 0 AND
|
||||
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_authid pk WHERE pk.oid = fk.opfowner);
|
||||
SELECT ctid, polrelid
|
||||
FROM pg_catalog.pg_policy fk
|
||||
WHERE polrelid != 0 AND
|
||||
NOT EXISTS(SELECT 1 FROM pg_catalog.pg_class pk WHERE pk.oid = fk.polrelid);
|
||||
SELECT ctid, pronamespace
|
||||
FROM pg_catalog.pg_proc fk
|
||||
WHERE pronamespace != 0 AND
|
||||
|
@ -50,6 +50,7 @@ SELECT ($1 = $2) OR
|
||||
(select typtype from pg_catalog.pg_type where oid = $1) = 'r')
|
||||
$$ language sql strict stable;
|
||||
|
||||
|
||||
-- **************** pg_proc ****************
|
||||
|
||||
-- Look for illegal values in pg_proc fields.
|
||||
@ -1001,6 +1002,7 @@ SELECT p.oid, proname
|
||||
FROM pg_proc AS p JOIN pg_aggregate AS a ON a.aggfnoid = p.oid
|
||||
WHERE proisagg AND provariadic != 0 AND a.aggkind = 'n';
|
||||
|
||||
|
||||
-- **************** pg_opfamily ****************
|
||||
|
||||
-- Look for illegal values in pg_opfamily fields
|
||||
@ -1009,6 +1011,7 @@ SELECT p1.oid
|
||||
FROM pg_opfamily as p1
|
||||
WHERE p1.opfmethod = 0 OR p1.opfnamespace = 0;
|
||||
|
||||
|
||||
-- **************** pg_opclass ****************
|
||||
|
||||
-- Look for illegal values in pg_opclass fields
|
||||
@ -1033,6 +1036,29 @@ WHERE p1.oid != p2.oid AND
|
||||
p1.opcmethod = p2.opcmethod AND p1.opcintype = p2.opcintype AND
|
||||
p1.opcdefault AND p2.opcdefault;
|
||||
|
||||
-- Ask access methods to validate opclasses
|
||||
|
||||
SELECT oid, opcname FROM pg_opclass WHERE NOT amvalidate(oid);
|
||||
|
||||
|
||||
-- **************** pg_am ****************
|
||||
|
||||
-- Look for illegal values in pg_am fields
|
||||
|
||||
SELECT p1.oid, p1.amname
|
||||
FROM pg_am AS p1
|
||||
WHERE p1.amhandler = 0;
|
||||
|
||||
-- Check for amhandler functions with the wrong signature
|
||||
|
||||
SELECT p1.oid, p1.amname, p2.oid, p2.proname
|
||||
FROM pg_am AS p1, pg_proc AS p2
|
||||
WHERE p2.oid = p1.amhandler AND
|
||||
(p2.prorettype != 'index_am_handler'::regtype OR p2.proretset
|
||||
OR p2.pronargs != 1
|
||||
OR p2.proargtypes[0] != 'internal'::regtype);
|
||||
|
||||
|
||||
-- **************** pg_amop ****************
|
||||
|
||||
-- Look for illegal values in pg_amop fields
|
||||
@ -1068,41 +1094,6 @@ WHERE p1.amopsortfamily <> 0 AND NOT EXISTS
|
||||
(SELECT 1 from pg_opfamily op WHERE op.oid = p1.amopsortfamily
|
||||
AND op.opfmethod = (SELECT oid FROM pg_am WHERE amname = 'btree'));
|
||||
|
||||
-- check for ordering operators not supported by parent AM
|
||||
|
||||
SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
|
||||
FROM pg_amop AS p1, pg_am AS p2
|
||||
WHERE p1.amopmethod = p2.oid AND
|
||||
p1.amoppurpose = 'o' AND NOT p2.amcanorderbyop;
|
||||
|
||||
-- Cross-check amopstrategy index against parent AM
|
||||
|
||||
SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname
|
||||
FROM pg_amop AS p1, pg_am AS p2
|
||||
WHERE p1.amopmethod = p2.oid AND
|
||||
p1.amopstrategy > p2.amstrategies AND p2.amstrategies <> 0;
|
||||
|
||||
-- Detect missing pg_amop entries: should have as many strategy operators
|
||||
-- as AM expects for each datatype combination supported by the opfamily.
|
||||
-- We can't check this for AMs with variable strategy sets.
|
||||
|
||||
SELECT p1.amname, p2.amoplefttype, p2.amoprighttype
|
||||
FROM pg_am AS p1, pg_amop AS p2
|
||||
WHERE p2.amopmethod = p1.oid AND
|
||||
p1.amstrategies <> 0 AND
|
||||
p1.amstrategies != (SELECT count(*) FROM pg_amop AS p3
|
||||
WHERE p3.amopfamily = p2.amopfamily AND
|
||||
p3.amoplefttype = p2.amoplefttype AND
|
||||
p3.amoprighttype = p2.amoprighttype AND
|
||||
p3.amoppurpose = 's');
|
||||
|
||||
-- Currently, none of the AMs with fixed strategy sets support ordering ops.
|
||||
|
||||
SELECT p1.amname, p2.amopfamily, p2.amopstrategy
|
||||
FROM pg_am AS p1, pg_amop AS p2
|
||||
WHERE p2.amopmethod = p1.oid AND
|
||||
p1.amstrategies <> 0 AND p2.amoppurpose <> 's';
|
||||
|
||||
-- Check that amopopr points at a reasonable-looking operator, ie a binary
|
||||
-- operator. If it's a search operator it had better yield boolean,
|
||||
-- otherwise an input type of its sort opfamily.
|
||||
@ -1249,59 +1240,6 @@ FROM pg_amproc as p1
|
||||
WHERE p1.amprocfamily = 0 OR p1.amproclefttype = 0 OR p1.amprocrighttype = 0
|
||||
OR p1.amprocnum < 1 OR p1.amproc = 0;
|
||||
|
||||
-- Cross-check amprocnum index against parent AM
|
||||
|
||||
SELECT p1.amprocfamily, p1.amprocnum, p2.oid, p2.amname
|
||||
FROM pg_amproc AS p1, pg_am AS p2, pg_opfamily AS p3
|
||||
WHERE p1.amprocfamily = p3.oid AND p3.opfmethod = p2.oid AND
|
||||
p1.amprocnum > p2.amsupport;
|
||||
|
||||
-- Detect missing pg_amproc entries: should have as many support functions
|
||||
-- as AM expects for each datatype combination supported by the opfamily.
|
||||
|
||||
SELECT * FROM (
|
||||
SELECT p1.amname, p2.opfname, p3.amproclefttype, p3.amprocrighttype,
|
||||
array_agg(p3.amprocnum ORDER BY amprocnum) AS procnums
|
||||
FROM pg_am AS p1, pg_opfamily AS p2, pg_amproc AS p3
|
||||
WHERE p2.opfmethod = p1.oid AND p3.amprocfamily = p2.oid
|
||||
GROUP BY p1.amname, p2.opfname, p3.amproclefttype, p3.amprocrighttype
|
||||
) AS t
|
||||
WHERE NOT (
|
||||
-- btree has one mandatory and one optional support function.
|
||||
-- hash has one support function, which is mandatory.
|
||||
-- GiST has eight support functions, one of which is optional.
|
||||
-- GIN has six support functions. 1-3 are mandatory, 5 is optional, and
|
||||
-- at least one of 4 and 6 must be given.
|
||||
-- SP-GiST has five support functions, all mandatory
|
||||
-- BRIN has four mandatory support functions, and a bunch of optionals
|
||||
amname = 'btree' AND procnums @> '{1}' OR
|
||||
amname = 'hash' AND procnums = '{1}' OR
|
||||
amname = 'gist' AND procnums @> '{1, 2, 3, 4, 5, 6, 7}' OR
|
||||
amname = 'gin' AND (procnums @> '{1, 2, 3}' AND (procnums && '{4, 6}')) OR
|
||||
amname = 'spgist' AND procnums = '{1, 2, 3, 4, 5}' OR
|
||||
amname = 'brin' AND procnums @> '{1, 2, 3, 4}'
|
||||
);
|
||||
|
||||
-- Also, check if there are any pg_opclass entries that don't seem to have
|
||||
-- pg_amproc support.
|
||||
|
||||
SELECT * FROM (
|
||||
SELECT amname, opcname, array_agg(amprocnum ORDER BY amprocnum) as procnums
|
||||
FROM pg_am am JOIN pg_opclass op ON opcmethod = am.oid
|
||||
LEFT JOIN pg_amproc p ON amprocfamily = opcfamily AND
|
||||
amproclefttype = amprocrighttype AND amproclefttype = opcintype
|
||||
GROUP BY amname, opcname, amprocfamily
|
||||
) AS t
|
||||
WHERE NOT (
|
||||
-- same per-AM rules as above
|
||||
amname = 'btree' AND procnums @> '{1}' OR
|
||||
amname = 'hash' AND procnums = '{1}' OR
|
||||
amname = 'gist' AND procnums @> '{1, 2, 3, 4, 5, 6, 7}' OR
|
||||
amname = 'gin' AND (procnums @> '{1, 2, 3}' AND (procnums && '{4, 6}')) OR
|
||||
amname = 'spgist' AND procnums = '{1, 2, 3, 4, 5}' OR
|
||||
amname = 'brin' AND procnums @> '{1, 2, 3, 4}'
|
||||
);
|
||||
|
||||
-- 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.
|
||||
@ -1395,6 +1333,7 @@ WHERE p1.amproc = p2.oid AND
|
||||
p1.amproclefttype != p1.amprocrighttype AND
|
||||
p2.provolatile = 'v';
|
||||
|
||||
|
||||
-- **************** pg_index ****************
|
||||
|
||||
-- Look for illegal values in pg_index fields.
|
||||
|
Reference in New Issue
Block a user