On 10/04/12 21:47, Jan Urbański wrote:
On 10/04/12 21:27, Tom Lane wrote:
=?UTF-8?B?SmFuIFVyYmHFhHNraQ==?= writes:
Yes, that would be ideal, even though not backwards-compatible.
Back-patching is out of the question, but do we want to change trigger
functions to receive dictionaries in NEW?
Hm, I was not thinking of this as being trigger-specific, but more a
general principle that composite columns of tuples ought to be handled
in a recursive fashion.
Sure, that would be the way.
If so, should this be 9.2 material, or just a TODO?
If it can be done quickly and with not much risk, I'd vote for
squeezing it into 9.2, because it seems to me to be a clear bug that the
two directions are not handled consistently. If you don't have time for
it now or you don't think it would be a small/safe patch, we'd better
just put it on TODO.
It turned out not to be as straightforward as I though :(
The I/O code in PL/Python is a bit of a mess and that's something that
I'd like to address somewhere in the 9.3 development cycle. Right now
making the conversion function recursive is not possible without some
deep surgery (or kludgery...) so I limited myself to producing
regression-fixing patches for 9.2 and 9.1 (attached).
Cheers,
Jan
>From 513e8c484f32599a8753035fad638c8712339480 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Urba=C5=84ski?=
Date: Mon, 23 Apr 2012 02:07:46 +0200
Subject: [PATCH] Accept strings in PL/Python 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 Postgres tuples was
being used.
The reason why it's important is that trigger functions on tables with
composite columns get the composite row passed in as a string (from
record_out). This makes it impossible to implement passthrough
behaviour 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 objecst to produce
dictionaries that would then be correctly interpreted by the
Python->Postgres counterpart code. This would be too invasive to
backpatch in 9.1 and it is too late in the 9.2 cycle to do it in
HEAD. It should get revisited in 9.3, though.
Reported as bug #6559 by Kirill Simonov.
---
src/pl/plpython/expected/plpython_record.out | 16
src/pl/plpython/expected/plpython_trigger.out | 37 +
src/pl/plpython/plpython.c| 94 ---
src/pl/plpython/regression.diffs | 99 +
src/pl/plpython/regression.out| 20 +
src/pl/plpython/sql/plpython_record.sql | 10 +++
src/pl/plpython/sql/plpython_trigger.sql | 36 +
7 files changed, 268 insertions(+), 44 deletions(-)
create mode 100644 src/pl/plpython/regression.diffs
create mode 100644 src/pl/plpython/regression.out
diff --git a/src/pl/plpython/expected/plpython_record.out b/src/pl/plpython/expected/plpython_record.out
index 0bcc46c..4583307 100644
--- a/src/pl/plpython/expected/plpython_record.out
+++ b/src/pl/plpython/expected/plpython_record.out
@@ -38,6 +38,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 $$
return first + '_in_to_out';
@@ -290,6 +292,12 @@ SELECT * FROM test_type_record_as('obj', null, null, true);
|
(1 row)
+SELECT * FROM test_type_record_as('str', 'one', 1, false);
+ first | second
+---+
+ 'one' | 1
+(1 row)
+
SELECT * FROM test_in_out_params('test_in');
second
---
@@ -355,3 +363,11 @@ ERROR: attribute "second" does not exist in Python object
HINT: To return null in a column, let the returned object have an attribute named after column with value None.
CONTEXT: while creating return value
PL/Python function "test_type_record_error3"
+CREATE FUNCTION test_type_record_error4() RETURNS type_record AS $$
+return 'foo'
+$$ LANGUAGE plpythonu;
+SELECT * FROM test_type_record_error4();
+ERROR: malformed record literal: "foo"
+DETAIL: Missing left parenthesis.
+CONTEXT: while creating return value
+PL/Python function "test_type_record_error4"
diff --git a/src/pl/plpython/expected/plpython_trigger.out b/src/pl/plpython/expected/plpython_trigger.out
index 2ef66a8..ea4d500 100644
--- a/src/pl/plpython/expected/plpython_trigger.out
+++ b/src/pl/plpython/expected/plpython_trigger.out
@@ -567,3 +567,40 @@ SELECT * FROM composite_trigger_test;
(3,f) | (7,t)
(1 row)
+-- bug