📄 opr_sanity.sql
字号:
---- 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...-- Helper functions to deal with cases where binary-coercible matches are-- allowed.-- This should match IsBinaryCoercible() in parse_coerce.c.create function binary_coercible(oid, oid) returns bool as'SELECT ($1 = $2) OR EXISTS(select 1 from pg_cast where castsource = $1 and casttarget = $2 and castfunc = 0 and castcontext = ''i'')'language sql;-- This one ignores castcontext, so it considers only physical equivalence-- and not whether the coercion can be invoked implicitly.create function physically_coercible(oid, oid) returns bool as'SELECT ($1 = $2) OR EXISTS(select 1 from pg_cast where castsource = $1 and casttarget = $2 and castfunc = 0)'language sql;-- **************** pg_proc ****************-- Look for illegal values in pg_proc fields.SELECT p1.oid, p1.pronameFROM pg_proc as p1WHERE p1.prolang = 0 OR p1.prorettype = 0 OR p1.pronargs < 0 OR array_lower(p1.proargtypes, 1) != 0 OR array_upper(p1.proargtypes, 1) != p1.pronargs-1 OR 0::oid = ANY (p1.proargtypes);-- 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.pronameFROM pg_proc AS p1, pg_proc AS p2WHERE p1.oid != p2.oid AND p1.proname = p2.proname AND p1.pronargs = p2.pronargs AND p1.proargtypes = p2.proargtypes;-- 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.pronameFROM pg_proc AS p1, pg_proc AS p2WHERE 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);-- 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.prorettypeFROM pg_proc AS p1, pg_proc AS p2WHERE 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);SELECT DISTINCT p1.proargtypes[0], p2.proargtypes[0]FROM pg_proc AS p1, pg_proc AS p2WHERE 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]);SELECT DISTINCT p1.proargtypes[1], p2.proargtypes[1]FROM pg_proc AS p1, pg_proc AS p2WHERE 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]);SELECT DISTINCT p1.proargtypes[2], p2.proargtypes[2]FROM pg_proc AS p1, pg_proc AS p2WHERE 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]);SELECT DISTINCT p1.proargtypes[3], p2.proargtypes[3]FROM pg_proc AS p1, pg_proc AS p2WHERE 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]);SELECT DISTINCT p1.proargtypes[4], p2.proargtypes[4]FROM pg_proc AS p1, pg_proc AS p2WHERE 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]);SELECT DISTINCT p1.proargtypes[5], p2.proargtypes[5]FROM pg_proc AS p1, pg_proc AS p2WHERE 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]);SELECT DISTINCT p1.proargtypes[6], p2.proargtypes[6]FROM pg_proc AS p1, pg_proc AS p2WHERE 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]);SELECT DISTINCT p1.proargtypes[7], p2.proargtypes[7]FROM pg_proc AS p1, pg_proc AS p2WHERE 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]);-- 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.pronameFROM pg_proc as p1WHERE p1.prorettype = 'internal'::regtype AND NOT 'internal'::regtype = ANY (p1.proargtypes);-- **************** pg_cast ****************-- Catch bogus values in pg_cast columns (other than cases detected by-- oidjoins test).SELECT *FROM pg_cast cWHERE castsource = 0 OR casttarget = 0 OR castcontext NOT IN ('e', 'a', 'i');-- Look for casts to/from the same type that aren't length coercion functions.-- (We assume they are length coercions if they take multiple arguments.)-- Such entries are not necessarily harmful, but they are useless.SELECT *FROM pg_cast cWHERE castsource = casttarget AND castfunc = 0;SELECT c.*FROM pg_cast c, pg_proc pWHERE c.castfunc = p.oid AND p.pronargs < 2 AND castsource = casttarget;-- 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.-- As a special case, we allow casts from CHAR(n) that use functions-- declared to take TEXT. This does not pass the binary-coercibility test-- because CHAR(n)-to-TEXT normally invokes rtrim(). However, the results-- are the same, so long as the function is one that ignores trailing blanks.SELECT c.*FROM pg_cast c, pg_proc pWHERE c.castfunc = p.oid AND (p.pronargs < 1 OR p.pronargs > 3 OR NOT (binary_coercible(c.castsource, p.proargtypes[0]) OR (c.castsource = 'character'::regtype AND p.proargtypes[0] = 'text'::regtype)) OR NOT binary_coercible(p.prorettype, c.casttarget));SELECT c.*FROM pg_cast c, pg_proc pWHERE c.castfunc = p.oid AND ((p.pronargs > 1 AND p.proargtypes[1] != 'int4'::regtype) OR (p.pronargs > 2 AND p.proargtypes[2] != 'bool'::regtype));-- 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 usually not intended.-- As of 7.4, this finds the casts from text and varchar to bpchar, because-- those are binary-compatible while the reverse way goes through rtrim().SELECT *FROM pg_cast cWHERE 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);-- **************** pg_operator ****************-- Look for illegal values in pg_operator fields.SELECT p1.oid, p1.oprnameFROM pg_operator as p1WHERE (p1.oprkind != 'b' AND p1.oprkind != 'l' AND p1.oprkind != 'r') OR p1.oprresult = 0 OR p1.oprcode = 0;-- Look for missing or unwanted operand typesSELECT p1.oid, p1.oprnameFROM pg_operator as p1WHERE (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');-- Look for conflicting operator definitions (same names and input datatypes).SELECT p1.oid, p1.oprcode, p2.oid, p2.oprcodeFROM pg_operator AS p1, pg_operator AS p2WHERE p1.oid != p2.oid AND p1.oprname = p2.oprname AND p1.oprkind = p2.oprkind AND p1.oprleft = p2.oprleft AND p1.oprright = p2.oprright;-- 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.oprcodeFROM pg_operator AS p1, pg_operator AS p2WHERE 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);-- Look for negatory operators that don't agree.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -