Replace opr_sanity test's binary_coercible() function with C code.

opr_sanity's binary_coercible() function has always been meant
to match the parser's notion of binary coercibility, but it also
has always been a rather poor approximation of the parser's
real rules (as embodied in IsBinaryCoercible()).  That hasn't
bit us so far, but it's predictable that it will eventually.

It also now emerges that implementing this check in plpgsql
performs absolutely horribly in clobber-cache-always testing.
(Perhaps we could do something about that, but I suspect it just
means that plpgsql is exploiting catalog caching to the hilt.)

Hence, let's replace binary_coercible() with a C shim that directly
invokes IsBinaryCoercible(), eliminating both the semantic hazard
and the performance issue.

Most of regress.c's C functions are declared in create_function_1,
but we can't simply move that to before opr_sanity/type_sanity
since those tests would complain about the resulting shell types.
I chose to split it into create_function_0 and create_function_1.
Since create_function_0 now runs as part of a parallel group while
create_function_1 doesn't, reduce the latter to create just those
functions that opr_sanity and type_sanity would whine about.

To make room for create_function_0 in the second parallel group
of tests, move tstypes to the third parallel group.

In passing, clean up some ordering deviations between
parallel_schedule and serial_schedule.

Discussion: https://postgr.es/m/292305.1620503097@sss.pgh.pa.us
This commit is contained in:
Tom Lane 2021-05-11 14:28:11 -04:00
parent 6d177e2813
commit 6303a57309
15 changed files with 216 additions and 295 deletions

View File

@ -1,5 +1,6 @@
/constraints.out
/copy.out
/create_function_0.out
/create_function_1.out
/create_function_2.out
/largeobject.out

View File

@ -41,7 +41,7 @@ DROP USER regress_conversion_user;
-- Test built-in conversion functions.
--
-- Helper function to test a conversion. Uses the test_enc_conversion function
-- that was created in the create_function_1 test.
-- that was created in the create_function_0 test.
create or replace function test_conv(
input IN bytea,
src_encoding IN text,

View File

@ -16,61 +16,6 @@
--
-- 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.
-- It doesn't currently know about some cases, notably domains, anyelement,
-- anynonarray, anyenum, or record, but it doesn't need to (yet).
create function binary_coercible(oid, oid) returns bool as $$
begin
if $1 = $2 then return true; end if;
if EXISTS(select 1 from pg_catalog.pg_cast where
castsource = $1 and casttarget = $2 and
castmethod = 'b' and castcontext = 'i')
then return true; end if;
if $2 = 'pg_catalog.any'::pg_catalog.regtype then return true; end if;
if $2 = 'pg_catalog.anyarray'::pg_catalog.regtype then
if EXISTS(select 1 from pg_catalog.pg_type where
oid = $1 and typelem != 0 and
typsubscript = 'pg_catalog.array_subscript_handler'::pg_catalog.regproc)
then return true; end if;
end if;
if $2 = 'pg_catalog.anyrange'::pg_catalog.regtype then
if (select typtype from pg_catalog.pg_type where oid = $1) = 'r'
then return true; end if;
end if;
if $2 = 'pg_catalog.anymultirange'::pg_catalog.regtype then
if (select typtype from pg_catalog.pg_type where oid = $1) = 'm'
then return true; end if;
end if;
return false;
end
$$ language plpgsql strict stable;
-- This one ignores castcontext, so it will allow cases where an explicit
-- (but still binary) cast would be required to convert the input type.
-- We don't currently use this for any tests in this file, but it is a
-- reasonable alternative definition for some scenarios.
create function explicitly_binary_coercible(oid, oid) returns bool as $$
begin
if $1 = $2 then return true; end if;
if EXISTS(select 1 from pg_catalog.pg_cast where
castsource = $1 and casttarget = $2 and
castmethod = 'b')
then return true; end if;
if $2 = 'pg_catalog.any'::pg_catalog.regtype then return true; end if;
if $2 = 'pg_catalog.anyarray'::pg_catalog.regtype then
if EXISTS(select 1 from pg_catalog.pg_type where
oid = $1 and typelem != 0 and
typsubscript = 'pg_catalog.array_subscript_handler'::pg_catalog.regproc)
then return true; end if;
end if;
if $2 = 'pg_catalog.anyrange'::pg_catalog.regtype then
if (select typtype from pg_catalog.pg_type where oid = $1) = 'r'
then return true; end if;
end if;
return false;
end
$$ language plpgsql strict stable;
-- **************** pg_proc ****************
-- Look for illegal values in pg_proc fields.
SELECT p1.oid, p1.proname

View File

@ -635,7 +635,7 @@ WHERE (rngcollation = 0) != (typcollation = 0);
(0 rows)
-- opclass had better be a btree opclass accepting the subtype.
-- We must allow anyarray matches, cf opr_sanity's binary_coercible()
-- We must allow anyarray matches, cf IsBinaryCoercible()
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

View File

@ -0,0 +1,95 @@
--
-- CREATE_FUNCTION_0
--
-- Create a bunch of C functions that will be used by later tests:
CREATE FUNCTION check_primary_key ()
RETURNS trigger
AS '@libdir@/refint@DLSUFFIX@'
LANGUAGE C;
CREATE FUNCTION check_foreign_key ()
RETURNS trigger
AS '@libdir@/refint@DLSUFFIX@'
LANGUAGE C;
CREATE FUNCTION autoinc ()
RETURNS trigger
AS '@libdir@/autoinc@DLSUFFIX@'
LANGUAGE C;
CREATE FUNCTION trigger_return_old ()
RETURNS trigger
AS '@libdir@/regress@DLSUFFIX@'
LANGUAGE C;
CREATE FUNCTION ttdummy ()
RETURNS trigger
AS '@libdir@/regress@DLSUFFIX@'
LANGUAGE C;
CREATE FUNCTION set_ttdummy (int4)
RETURNS int4
AS '@libdir@/regress@DLSUFFIX@'
LANGUAGE C STRICT;
CREATE FUNCTION make_tuple_indirect (record)
RETURNS record
AS '@libdir@/regress@DLSUFFIX@'
LANGUAGE C STRICT;
CREATE FUNCTION test_atomic_ops()
RETURNS bool
AS '@libdir@/regress@DLSUFFIX@'
LANGUAGE C;
CREATE FUNCTION test_fdw_handler()
RETURNS fdw_handler
AS '@libdir@/regress@DLSUFFIX@', 'test_fdw_handler'
LANGUAGE C;
CREATE FUNCTION test_support_func(internal)
RETURNS internal
AS '@libdir@/regress@DLSUFFIX@', 'test_support_func'
LANGUAGE C STRICT;
CREATE FUNCTION test_opclass_options_func(internal)
RETURNS void
AS '@libdir@/regress@DLSUFFIX@', 'test_opclass_options_func'
LANGUAGE C;
CREATE FUNCTION test_enc_conversion(bytea, name, name, bool, validlen OUT int, result OUT bytea)
AS '@libdir@/regress@DLSUFFIX@', 'test_enc_conversion'
LANGUAGE C STRICT;
CREATE FUNCTION binary_coercible(oid, oid)
RETURNS bool
AS '@libdir@/regress@DLSUFFIX@', 'binary_coercible'
LANGUAGE C STRICT STABLE PARALLEL SAFE;
-- Things that shouldn't work:
CREATE FUNCTION test1 (int) RETURNS int LANGUAGE SQL
AS 'SELECT ''not an integer'';';
CREATE FUNCTION test1 (int) RETURNS int LANGUAGE SQL
AS 'not even SQL';
CREATE FUNCTION test1 (int) RETURNS int LANGUAGE SQL
AS 'SELECT 1, 2, 3;';
CREATE FUNCTION test1 (int) RETURNS int LANGUAGE SQL
AS 'SELECT $2;';
CREATE FUNCTION test1 (int) RETURNS int LANGUAGE SQL
AS 'a', 'b';
CREATE FUNCTION test1 (int) RETURNS int LANGUAGE C
AS 'nosuchfile';
CREATE FUNCTION test1 (int) RETURNS int LANGUAGE C
AS '@libdir@/regress@DLSUFFIX@', 'nosuchsymbol';
CREATE FUNCTION test1 (int) RETURNS int LANGUAGE internal
AS 'nosuch';

View File

@ -2,6 +2,8 @@
-- CREATE_FUNCTION_1
--
-- Create C functions needed by create_type.sql
CREATE FUNCTION widget_in(cstring)
RETURNS widget
AS '@libdir@/regress@DLSUFFIX@'
@ -21,89 +23,3 @@ CREATE FUNCTION int44out(city_budget)
RETURNS cstring
AS '@libdir@/regress@DLSUFFIX@'
LANGUAGE C STRICT IMMUTABLE;
CREATE FUNCTION check_primary_key ()
RETURNS trigger
AS '@libdir@/refint@DLSUFFIX@'
LANGUAGE C;
CREATE FUNCTION check_foreign_key ()
RETURNS trigger
AS '@libdir@/refint@DLSUFFIX@'
LANGUAGE C;
CREATE FUNCTION autoinc ()
RETURNS trigger
AS '@libdir@/autoinc@DLSUFFIX@'
LANGUAGE C;
CREATE FUNCTION trigger_return_old ()
RETURNS trigger
AS '@libdir@/regress@DLSUFFIX@'
LANGUAGE C;
CREATE FUNCTION ttdummy ()
RETURNS trigger
AS '@libdir@/regress@DLSUFFIX@'
LANGUAGE C;
CREATE FUNCTION set_ttdummy (int4)
RETURNS int4
AS '@libdir@/regress@DLSUFFIX@'
LANGUAGE C STRICT;
CREATE FUNCTION make_tuple_indirect (record)
RETURNS record
AS '@libdir@/regress@DLSUFFIX@'
LANGUAGE C STRICT;
CREATE FUNCTION test_atomic_ops()
RETURNS bool
AS '@libdir@/regress@DLSUFFIX@'
LANGUAGE C;
-- Tests creating a FDW handler
CREATE FUNCTION test_fdw_handler()
RETURNS fdw_handler
AS '@libdir@/regress@DLSUFFIX@', 'test_fdw_handler'
LANGUAGE C;
CREATE FUNCTION test_support_func(internal)
RETURNS internal
AS '@libdir@/regress@DLSUFFIX@', 'test_support_func'
LANGUAGE C STRICT;
CREATE FUNCTION test_opclass_options_func(internal)
RETURNS void
AS '@libdir@/regress@DLSUFFIX@', 'test_opclass_options_func'
LANGUAGE C;
CREATE FUNCTION test_enc_conversion(bytea, name, name, bool, validlen OUT int, result OUT bytea)
AS '@libdir@/regress@DLSUFFIX@', 'test_enc_conversion'
LANGUAGE C STRICT;
-- Things that shouldn't work:
CREATE FUNCTION test1 (int) RETURNS int LANGUAGE SQL
AS 'SELECT ''not an integer'';';
CREATE FUNCTION test1 (int) RETURNS int LANGUAGE SQL
AS 'not even SQL';
CREATE FUNCTION test1 (int) RETURNS int LANGUAGE SQL
AS 'SELECT 1, 2, 3;';
CREATE FUNCTION test1 (int) RETURNS int LANGUAGE SQL
AS 'SELECT $2;';
CREATE FUNCTION test1 (int) RETURNS int LANGUAGE SQL
AS 'a', 'b';
CREATE FUNCTION test1 (int) RETURNS int LANGUAGE C
AS 'nosuchfile';
CREATE FUNCTION test1 (int) RETURNS int LANGUAGE C
AS '@libdir@/regress@DLSUFFIX@', 'nosuchsymbol';
CREATE FUNCTION test1 (int) RETURNS int LANGUAGE internal
AS 'nosuch';

View File

@ -0,0 +1,88 @@
--
-- CREATE_FUNCTION_0
--
-- Create a bunch of C functions that will be used by later tests:
CREATE FUNCTION check_primary_key ()
RETURNS trigger
AS '@libdir@/refint@DLSUFFIX@'
LANGUAGE C;
CREATE FUNCTION check_foreign_key ()
RETURNS trigger
AS '@libdir@/refint@DLSUFFIX@'
LANGUAGE C;
CREATE FUNCTION autoinc ()
RETURNS trigger
AS '@libdir@/autoinc@DLSUFFIX@'
LANGUAGE C;
CREATE FUNCTION trigger_return_old ()
RETURNS trigger
AS '@libdir@/regress@DLSUFFIX@'
LANGUAGE C;
CREATE FUNCTION ttdummy ()
RETURNS trigger
AS '@libdir@/regress@DLSUFFIX@'
LANGUAGE C;
CREATE FUNCTION set_ttdummy (int4)
RETURNS int4
AS '@libdir@/regress@DLSUFFIX@'
LANGUAGE C STRICT;
CREATE FUNCTION make_tuple_indirect (record)
RETURNS record
AS '@libdir@/regress@DLSUFFIX@'
LANGUAGE C STRICT;
CREATE FUNCTION test_atomic_ops()
RETURNS bool
AS '@libdir@/regress@DLSUFFIX@'
LANGUAGE C;
CREATE FUNCTION test_fdw_handler()
RETURNS fdw_handler
AS '@libdir@/regress@DLSUFFIX@', 'test_fdw_handler'
LANGUAGE C;
CREATE FUNCTION test_support_func(internal)
RETURNS internal
AS '@libdir@/regress@DLSUFFIX@', 'test_support_func'
LANGUAGE C STRICT;
CREATE FUNCTION test_opclass_options_func(internal)
RETURNS void
AS '@libdir@/regress@DLSUFFIX@', 'test_opclass_options_func'
LANGUAGE C;
CREATE FUNCTION test_enc_conversion(bytea, name, name, bool, validlen OUT int, result OUT bytea)
AS '@libdir@/regress@DLSUFFIX@', 'test_enc_conversion'
LANGUAGE C STRICT;
CREATE FUNCTION binary_coercible(oid, oid)
RETURNS bool
AS '@libdir@/regress@DLSUFFIX@', 'binary_coercible'
LANGUAGE C STRICT STABLE PARALLEL SAFE;
-- Things that shouldn't work:
CREATE FUNCTION test1 (int) RETURNS int LANGUAGE SQL
AS 'SELECT ''not an integer'';';
ERROR: return type mismatch in function declared to return integer
DETAIL: Actual return type is text.
CONTEXT: SQL function "test1"
CREATE FUNCTION test1 (int) RETURNS int LANGUAGE SQL
AS 'not even SQL';
ERROR: syntax error at or near "not"
LINE 2: AS 'not even SQL';
^
CREATE FUNCTION test1 (int) RETURNS int LANGUAGE SQL
AS 'SELECT 1, 2, 3;';
ERROR: return type mismatch in function declared to return integer
DETAIL: Final statement must return exactly one column.
CONTEXT: SQL function "test1"
CREATE FUNCTION test1 (int) RETURNS int LANGUAGE SQL
AS 'SELECT $2;';
ERROR: there is no parameter $2
LINE 2: AS 'SELECT $2;';
^
CREATE FUNCTION test1 (int) RETURNS int LANGUAGE SQL
AS 'a', 'b';
ERROR: only one AS item needed for language "sql"
CREATE FUNCTION test1 (int) RETURNS int LANGUAGE C
AS 'nosuchfile';
ERROR: could not access file "nosuchfile": No such file or directory
CREATE FUNCTION test1 (int) RETURNS int LANGUAGE C
AS '@libdir@/regress@DLSUFFIX@', 'nosuchsymbol';
ERROR: could not find function "nosuchsymbol" in file "@libdir@/regress@DLSUFFIX@"
CREATE FUNCTION test1 (int) RETURNS int LANGUAGE internal
AS 'nosuch';
ERROR: there is no built-in function named "nosuch"

View File

@ -1,6 +1,7 @@
--
-- CREATE_FUNCTION_1
--
-- Create C functions needed by create_type.sql
CREATE FUNCTION widget_in(cstring)
RETURNS widget
AS '@libdir@/regress@DLSUFFIX@'
@ -23,84 +24,3 @@ CREATE FUNCTION int44out(city_budget)
AS '@libdir@/regress@DLSUFFIX@'
LANGUAGE C STRICT IMMUTABLE;
NOTICE: argument type city_budget is only a shell
CREATE FUNCTION check_primary_key ()
RETURNS trigger
AS '@libdir@/refint@DLSUFFIX@'
LANGUAGE C;
CREATE FUNCTION check_foreign_key ()
RETURNS trigger
AS '@libdir@/refint@DLSUFFIX@'
LANGUAGE C;
CREATE FUNCTION autoinc ()
RETURNS trigger
AS '@libdir@/autoinc@DLSUFFIX@'
LANGUAGE C;
CREATE FUNCTION trigger_return_old ()
RETURNS trigger
AS '@libdir@/regress@DLSUFFIX@'
LANGUAGE C;
CREATE FUNCTION ttdummy ()
RETURNS trigger
AS '@libdir@/regress@DLSUFFIX@'
LANGUAGE C;
CREATE FUNCTION set_ttdummy (int4)
RETURNS int4
AS '@libdir@/regress@DLSUFFIX@'
LANGUAGE C STRICT;
CREATE FUNCTION make_tuple_indirect (record)
RETURNS record
AS '@libdir@/regress@DLSUFFIX@'
LANGUAGE C STRICT;
CREATE FUNCTION test_atomic_ops()
RETURNS bool
AS '@libdir@/regress@DLSUFFIX@'
LANGUAGE C;
-- Tests creating a FDW handler
CREATE FUNCTION test_fdw_handler()
RETURNS fdw_handler
AS '@libdir@/regress@DLSUFFIX@', 'test_fdw_handler'
LANGUAGE C;
CREATE FUNCTION test_support_func(internal)
RETURNS internal
AS '@libdir@/regress@DLSUFFIX@', 'test_support_func'
LANGUAGE C STRICT;
CREATE FUNCTION test_opclass_options_func(internal)
RETURNS void
AS '@libdir@/regress@DLSUFFIX@', 'test_opclass_options_func'
LANGUAGE C;
CREATE FUNCTION test_enc_conversion(bytea, name, name, bool, validlen OUT int, result OUT bytea)
AS '@libdir@/regress@DLSUFFIX@', 'test_enc_conversion'
LANGUAGE C STRICT;
-- Things that shouldn't work:
CREATE FUNCTION test1 (int) RETURNS int LANGUAGE SQL
AS 'SELECT ''not an integer'';';
ERROR: return type mismatch in function declared to return integer
DETAIL: Actual return type is text.
CONTEXT: SQL function "test1"
CREATE FUNCTION test1 (int) RETURNS int LANGUAGE SQL
AS 'not even SQL';
ERROR: syntax error at or near "not"
LINE 2: AS 'not even SQL';
^
CREATE FUNCTION test1 (int) RETURNS int LANGUAGE SQL
AS 'SELECT 1, 2, 3;';
ERROR: return type mismatch in function declared to return integer
DETAIL: Final statement must return exactly one column.
CONTEXT: SQL function "test1"
CREATE FUNCTION test1 (int) RETURNS int LANGUAGE SQL
AS 'SELECT $2;';
ERROR: there is no parameter $2
LINE 2: AS 'SELECT $2;';
^
CREATE FUNCTION test1 (int) RETURNS int LANGUAGE SQL
AS 'a', 'b';
ERROR: only one AS item needed for language "sql"
CREATE FUNCTION test1 (int) RETURNS int LANGUAGE C
AS 'nosuchfile';
ERROR: could not access file "nosuchfile": No such file or directory
CREATE FUNCTION test1 (int) RETURNS int LANGUAGE C
AS '@libdir@/regress@DLSUFFIX@', 'nosuchsymbol';
ERROR: could not find function "nosuchsymbol" in file "@libdir@/regress@DLSUFFIX@"
CREATE FUNCTION test1 (int) RETURNS int LANGUAGE internal
AS 'nosuch';
ERROR: there is no built-in function named "nosuch"

View File

@ -20,16 +20,17 @@ test: boolean char name varchar text int2 int4 int8 oid float4 float8 bit numeri
# strings depends on char, varchar and text
# numerology depends on int2, int4, int8, float4, float8
# multirangetypes depends on rangetypes
# multirangetypes shouldn't be in the one group with type_sanity
# multirangetypes shouldn't run concurrently with type_sanity
# ----------
test: strings numerology point lseg line box path polygon circle date time timetz timestamp timestamptz interval inet macaddr macaddr8 tstypes multirangetypes
test: strings numerology point lseg line box path polygon circle date time timetz timestamp timestamptz interval inet macaddr macaddr8 multirangetypes create_function_0
# ----------
# Another group of parallel tests
# geometry depends on point, lseg, box, path, polygon and circle
# horology depends on interval, timetz, timestamp, timestamptz
# opr_sanity depends on create_function_0
# ----------
test: geometry horology regex type_sanity opr_sanity misc_sanity comments expressions unicode xid mvcc
test: geometry horology tstypes regex type_sanity opr_sanity misc_sanity comments expressions unicode xid mvcc
# ----------
# These four each depend on the previous one

View File

@ -36,6 +36,7 @@
#include "nodes/supportnodes.h"
#include "optimizer/optimizer.h"
#include "optimizer/plancat.h"
#include "parser/parse_coerce.h"
#include "port/atomics.h"
#include "storage/spin.h"
#include "utils/builtins.h"
@ -1194,3 +1195,14 @@ test_enc_conversion(PG_FUNCTION_ARGS)
PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
}
/* Provide SQL access to IsBinaryCoercible() */
PG_FUNCTION_INFO_V1(binary_coercible);
Datum
binary_coercible(PG_FUNCTION_ARGS)
{
Oid srctype = PG_GETARG_OID(0);
Oid targettype = PG_GETARG_OID(1);
PG_RETURN_BOOL(IsBinaryCoercible(srctype, targettype));
}

View File

@ -10,8 +10,6 @@ test: int2
test: int4
test: int8
test: oid
test: xid
test: mvcc
test: float4
test: float8
test: bit
@ -21,7 +19,6 @@ test: uuid
test: enum
test: money
test: rangetypes
test: multirangetypes
test: pg_lsn
test: regproc
test: strings
@ -42,9 +39,11 @@ test: interval
test: inet
test: macaddr
test: macaddr8
test: tstypes
test: multirangetypes
test: create_function_0
test: geometry
test: horology
test: tstypes
test: regex
test: type_sanity
test: opr_sanity
@ -52,6 +51,8 @@ test: misc_sanity
test: comments
test: expressions
test: unicode
test: xid
test: mvcc
test: create_function_1
test: create_type
test: create_table
@ -92,7 +93,6 @@ test: select_distinct_on
test: select_implicit
test: select_having
test: subselect
test: incremental_sort
test: union
test: case
test: join
@ -109,8 +109,6 @@ test: delete
test: namespace
test: prepared_xacts
test: brin
test: brin_bloom
test: brin_multi
test: gin
test: gist
test: spgist
@ -130,6 +128,8 @@ test: password
test: identity
test: generated
test: join_hash
test: brin_bloom
test: brin_multi
test: create_table_like
test: alter_generic
test: alter_operator
@ -143,6 +143,7 @@ test: tid
test: tidscan
test: tidrangescan
test: collate.icu.utf8
test: incremental_sort
test: rules
test: psql
test: psql_crosstab

View File

@ -1,5 +1,6 @@
/constraints.sql
/copy.sql
/create_function_0.sql
/create_function_1.sql
/create_function_2.sql
/largeobject.sql

View File

@ -40,7 +40,7 @@ DROP USER regress_conversion_user;
--
-- Helper function to test a conversion. Uses the test_enc_conversion function
-- that was created in the create_function_1 test.
-- that was created in the create_function_0 test.
create or replace function test_conv(
input IN bytea,
src_encoding IN text,

View File

@ -18,65 +18,6 @@
-- 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.
-- It doesn't currently know about some cases, notably domains, anyelement,
-- anynonarray, anyenum, or record, but it doesn't need to (yet).
create function binary_coercible(oid, oid) returns bool as $$
begin
if $1 = $2 then return true; end if;
if EXISTS(select 1 from pg_catalog.pg_cast where
castsource = $1 and casttarget = $2 and
castmethod = 'b' and castcontext = 'i')
then return true; end if;
if $2 = 'pg_catalog.any'::pg_catalog.regtype then return true; end if;
if $2 = 'pg_catalog.anyarray'::pg_catalog.regtype then
if EXISTS(select 1 from pg_catalog.pg_type where
oid = $1 and typelem != 0 and
typsubscript = 'pg_catalog.array_subscript_handler'::pg_catalog.regproc)
then return true; end if;
end if;
if $2 = 'pg_catalog.anyrange'::pg_catalog.regtype then
if (select typtype from pg_catalog.pg_type where oid = $1) = 'r'
then return true; end if;
end if;
if $2 = 'pg_catalog.anymultirange'::pg_catalog.regtype then
if (select typtype from pg_catalog.pg_type where oid = $1) = 'm'
then return true; end if;
end if;
return false;
end
$$ language plpgsql strict stable;
-- This one ignores castcontext, so it will allow cases where an explicit
-- (but still binary) cast would be required to convert the input type.
-- We don't currently use this for any tests in this file, but it is a
-- reasonable alternative definition for some scenarios.
create function explicitly_binary_coercible(oid, oid) returns bool as $$
begin
if $1 = $2 then return true; end if;
if EXISTS(select 1 from pg_catalog.pg_cast where
castsource = $1 and casttarget = $2 and
castmethod = 'b')
then return true; end if;
if $2 = 'pg_catalog.any'::pg_catalog.regtype then return true; end if;
if $2 = 'pg_catalog.anyarray'::pg_catalog.regtype then
if EXISTS(select 1 from pg_catalog.pg_type where
oid = $1 and typelem != 0 and
typsubscript = 'pg_catalog.array_subscript_handler'::pg_catalog.regproc)
then return true; end if;
end if;
if $2 = 'pg_catalog.anyrange'::pg_catalog.regtype then
if (select typtype from pg_catalog.pg_type where oid = $1) = 'r'
then return true; end if;
end if;
return false;
end
$$ language plpgsql strict stable;
-- **************** pg_proc ****************
-- Look for illegal values in pg_proc fields.

View File

@ -465,7 +465,7 @@ FROM pg_range p1 JOIN pg_type t ON t.oid = p1.rngsubtype
WHERE (rngcollation = 0) != (typcollation = 0);
-- opclass had better be a btree opclass accepting the subtype.
-- We must allow anyarray matches, cf opr_sanity's binary_coercible()
-- We must allow anyarray matches, cf IsBinaryCoercible()
SELECT p1.rngtypid, p1.rngsubtype, o.opcmethod, o.opcname
FROM pg_range p1 JOIN pg_opclass o ON o.oid = p1.rngsubopc