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

PL/Python: Accept strings in functions returning composite types

Before 9.1, PL/Python functions returning composite types could return
a string and it would be parsed using record_in.  The 9.1 changes made
PL/Python only expect dictionaries, tuples, or objects supporting
getattr as output of composite functions, resulting in a regression
and a confusing error message, as the strings were interpreted as
sequences and the code for transforming lists to database tuples was
used.  Fix this by treating strings separately as before, before
checking for the other types.

The reason why it's important to support string to database tuple
conversion is that trigger functions on tables with composite columns
get the composite row passed in as a string (from record_out).
Without supporting converting this back using record_in, this makes it
impossible to implement pass-through behavior for these columns, as
PL/Python no longer accepts strings for composite values.

A better solution would be to fix the code that transforms composite
inputs into Python objects to produce dictionaries that would then be
correctly interpreted by the Python->PostgreSQL counterpart code.  But
that would be too invasive to backpatch to 9.1, and it is too late in
the 9.2 cycle to attempt it.  It should be revisited in the future,
though.

Reported as bug #6559 by Kirill Simonov.

Jan Urbański
This commit is contained in:
Peter Eisentraut
2012-04-26 21:03:48 +03:00
parent cc71ceab57
commit ba3e4157a7
7 changed files with 151 additions and 47 deletions

View File

@@ -43,6 +43,8 @@ elif typ == 'obj':
type_record.first = first
type_record.second = second
return type_record
elif typ == 'str':
return "('%s',%r)" % (first, second)
$$ LANGUAGE plpythonu;
CREATE FUNCTION test_in_out_params(first in text, second out text) AS $$
@@ -108,6 +110,8 @@ SELECT * FROM test_type_record_as('obj', null, 2, false);
SELECT * FROM test_type_record_as('obj', 'three', 3, false);
SELECT * FROM test_type_record_as('obj', null, null, true);
SELECT * FROM test_type_record_as('str', 'one', 1, false);
SELECT * FROM test_in_out_params('test_in');
SELECT * FROM test_in_out_params_multi('test_in');
SELECT * FROM test_inout_params('test_in');
@@ -151,3 +155,9 @@ CREATE FUNCTION test_type_record_error3() RETURNS type_record AS $$
$$ LANGUAGE plpythonu;
SELECT * FROM test_type_record_error3();
CREATE FUNCTION test_type_record_error4() RETURNS type_record AS $$
return 'foo'
$$ LANGUAGE plpythonu;
SELECT * FROM test_type_record_error4();

View File

@@ -346,3 +346,39 @@ CREATE TRIGGER composite_trigger BEFORE INSERT ON composite_trigger_test
INSERT INTO composite_trigger_test VALUES (NULL, NULL);
SELECT * FROM composite_trigger_test;
-- triggers with composite type columns (bug #6559)
CREATE TABLE composite_trigger_noop_test (f1 comp1, f2 comp2);
CREATE FUNCTION composite_trigger_noop_f() RETURNS trigger AS $$
return 'MODIFY'
$$ LANGUAGE plpythonu;
CREATE TRIGGER composite_trigger_noop BEFORE INSERT ON composite_trigger_noop_test
FOR EACH ROW EXECUTE PROCEDURE composite_trigger_noop_f();
INSERT INTO composite_trigger_noop_test VALUES (NULL, NULL);
INSERT INTO composite_trigger_noop_test VALUES (ROW(1, 'f'), NULL);
INSERT INTO composite_trigger_noop_test VALUES (ROW(NULL, 't'), ROW(1, 'f'));
SELECT * FROM composite_trigger_noop_test;
-- nested composite types
CREATE TYPE comp3 AS (c1 comp1, c2 comp2, m integer);
CREATE TABLE composite_trigger_nested_test(c comp3);
CREATE FUNCTION composite_trigger_nested_f() RETURNS trigger AS $$
return 'MODIFY'
$$ LANGUAGE plpythonu;
CREATE TRIGGER composite_trigger_nested BEFORE INSERT ON composite_trigger_nested_test
FOR EACH ROW EXECUTE PROCEDURE composite_trigger_nested_f();
INSERT INTO composite_trigger_nested_test VALUES (NULL);
INSERT INTO composite_trigger_nested_test VALUES (ROW(ROW(1, 'f'), NULL, 3));
INSERT INTO composite_trigger_nested_test VALUES (ROW(ROW(NULL, 't'), ROW(1, 'f'), NULL));
SELECT * FROM composite_trigger_nested_test;