1
0
mirror of https://github.com/postgres/postgres.git synced 2025-12-12 02:37:31 +03:00

Make PL/Python handle domain-type conversions correctly.

Fix PL/Python so that it can handle domains over composite, and so that
it enforces domain constraints correctly in other cases that were not
always done properly before.  Notably, it didn't do arrays of domains
right (oversight in commit c12d570fa), and it failed to enforce domain
constraints when returning a composite type containing a domain field,
and if a transform function is being used for a domain's base type then
it failed to enforce domain constraints on the result.  Also, in many
places it missed checking domain constraints on null values, because
the plpy_typeio code simply wasn't called for Py_None.

Rather than try to band-aid these problems, I made a significant
refactoring of the plpy_typeio logic.  The existing design of recursing
for array and composite members is extended to also treat domains as
containers requiring recursion, and the APIs for the module are cleaned
up and simplified.

The patch also modifies plpy_typeio to rely on the typcache more than
it did before (which was pretty much not at all).  This reduces the
need for repetitive lookups, and lets us get rid of an ad-hoc scheme
for detecting changes in composite types.  I added a couple of small
features to typcache to help with that.

Although some of this is fixing bugs that long predate v11, I don't
think we should risk a back-patch: it's a significant amount of code
churn, and there've been no complaints from the field about the bugs.

Tom Lane, reviewed by Anthony Bykov

Discussion: https://postgr.es/m/24449.1509393613@sss.pgh.pa.us
This commit is contained in:
Tom Lane
2017-11-16 16:22:57 -05:00
parent 575cead991
commit 687f096ea9
17 changed files with 1412 additions and 963 deletions

View File

@@ -387,6 +387,55 @@ $$ LANGUAGE plpythonu;
SELECT * FROM test_type_conversion_array_domain_check_violation();
--
-- Arrays of domains
--
CREATE FUNCTION test_read_uint2_array(x uint2[]) RETURNS uint2 AS $$
plpy.info(x, type(x))
return x[0]
$$ LANGUAGE plpythonu;
select test_read_uint2_array(array[1::uint2]);
CREATE FUNCTION test_build_uint2_array(x int2) RETURNS uint2[] AS $$
return [x, x]
$$ LANGUAGE plpythonu;
select test_build_uint2_array(1::int2);
select test_build_uint2_array(-1::int2); -- fail
--
-- ideally this would work, but for now it doesn't, because the return value
-- is [[2,4], [2,4]] which our conversion code thinks should become a 2-D
-- integer array, not an array of arrays.
--
CREATE FUNCTION test_type_conversion_domain_array(x integer[])
RETURNS ordered_pair_domain[] AS $$
return [x, x]
$$ LANGUAGE plpythonu;
select test_type_conversion_domain_array(array[2,4]);
select test_type_conversion_domain_array(array[4,2]); -- fail
CREATE FUNCTION test_type_conversion_domain_array2(x ordered_pair_domain)
RETURNS integer AS $$
plpy.info(x, type(x))
return x[1]
$$ LANGUAGE plpythonu;
select test_type_conversion_domain_array2(array[2,4]);
select test_type_conversion_domain_array2(array[4,2]); -- fail
CREATE FUNCTION test_type_conversion_array_domain_array(x ordered_pair_domain[])
RETURNS ordered_pair_domain AS $$
plpy.info(x, type(x))
return x[0]
$$ LANGUAGE plpythonu;
select test_type_conversion_array_domain_array(array[array[2,4]::ordered_pair_domain]);
---
--- Composite types
---
@@ -430,6 +479,48 @@ ALTER TYPE named_pair RENAME TO named_pair_2;
SELECT test_composite_type_input(row(1, 2));
--
-- Domains within composite
--
CREATE TYPE nnint_container AS (f1 int, f2 nnint);
CREATE FUNCTION nnint_test(x int, y int) RETURNS nnint_container AS $$
return {'f1': x, 'f2': y}
$$ LANGUAGE plpythonu;
SELECT nnint_test(null, 3);
SELECT nnint_test(3, null); -- fail
--
-- Domains of composite
--
CREATE DOMAIN ordered_named_pair AS named_pair_2 CHECK((VALUE).i <= (VALUE).j);
CREATE FUNCTION read_ordered_named_pair(p ordered_named_pair) RETURNS integer AS $$
return p['i'] + p['j']
$$ LANGUAGE plpythonu;
SELECT read_ordered_named_pair(row(1, 2));
SELECT read_ordered_named_pair(row(2, 1)); -- fail
CREATE FUNCTION build_ordered_named_pair(i int, j int) RETURNS ordered_named_pair AS $$
return {'i': i, 'j': j}
$$ LANGUAGE plpythonu;
SELECT build_ordered_named_pair(1,2);
SELECT build_ordered_named_pair(2,1); -- fail
CREATE FUNCTION build_ordered_named_pairs(i int, j int) RETURNS ordered_named_pair[] AS $$
return [{'i': i, 'j': j}, {'i': i, 'j': j+1}]
$$ LANGUAGE plpythonu;
SELECT build_ordered_named_pairs(1,2);
SELECT build_ordered_named_pairs(2,1); -- fail
--
-- Prepared statements
--