mirror of
https://github.com/postgres/postgres.git
synced 2026-02-12 15:23:16 -05:00
Dropped columns within a composite type were not handled correctly. Also, we did not check for whether a composite result type had changed since we cached the information about it. Jan Urbański, per a bug report from Jean-Baptiste Quenot
357 lines
8.6 KiB
Text
357 lines
8.6 KiB
Text
--
|
|
-- Test returning tuples
|
|
--
|
|
CREATE TABLE table_record (
|
|
first text,
|
|
second int4
|
|
) ;
|
|
CREATE TYPE type_record AS (
|
|
first text,
|
|
second int4
|
|
) ;
|
|
CREATE FUNCTION test_table_record_as(typ text, first text, second integer, retnull boolean) RETURNS table_record AS $$
|
|
if retnull:
|
|
return None
|
|
if typ == 'dict':
|
|
return { 'first': first, 'second': second, 'additionalfield': 'must not cause trouble' }
|
|
elif typ == 'tuple':
|
|
return ( first, second )
|
|
elif typ == 'list':
|
|
return [ first, second ]
|
|
elif typ == 'obj':
|
|
class type_record: pass
|
|
type_record.first = first
|
|
type_record.second = second
|
|
return type_record
|
|
$$ LANGUAGE plpythonu;
|
|
CREATE FUNCTION test_type_record_as(typ text, first text, second integer, retnull boolean) RETURNS type_record AS $$
|
|
if retnull:
|
|
return None
|
|
if typ == 'dict':
|
|
return { 'first': first, 'second': second, 'additionalfield': 'must not cause trouble' }
|
|
elif typ == 'tuple':
|
|
return ( first, second )
|
|
elif typ == 'list':
|
|
return [ first, second ]
|
|
elif typ == 'obj':
|
|
class type_record: pass
|
|
type_record.first = first
|
|
type_record.second = second
|
|
return type_record
|
|
$$ LANGUAGE plpythonu;
|
|
CREATE FUNCTION test_in_out_params(first in text, second out text) AS $$
|
|
return first + '_in_to_out';
|
|
$$ LANGUAGE plpythonu;
|
|
CREATE FUNCTION test_in_out_params_multi(first in text,
|
|
second out text, third out text) AS $$
|
|
return (first + '_record_in_to_out_1', first + '_record_in_to_out_2');
|
|
$$ LANGUAGE plpythonu;
|
|
CREATE FUNCTION test_inout_params(first inout text) AS $$
|
|
return first + '_inout';
|
|
$$ LANGUAGE plpythonu;
|
|
-- Test tuple returning functions
|
|
SELECT * FROM test_table_record_as('dict', null, null, false);
|
|
first | second
|
|
-------+--------
|
|
|
|
|
(1 row)
|
|
|
|
SELECT * FROM test_table_record_as('dict', 'one', null, false);
|
|
first | second
|
|
-------+--------
|
|
one |
|
|
(1 row)
|
|
|
|
SELECT * FROM test_table_record_as('dict', null, 2, false);
|
|
first | second
|
|
-------+--------
|
|
| 2
|
|
(1 row)
|
|
|
|
SELECT * FROM test_table_record_as('dict', 'three', 3, false);
|
|
first | second
|
|
-------+--------
|
|
three | 3
|
|
(1 row)
|
|
|
|
SELECT * FROM test_table_record_as('dict', null, null, true);
|
|
first | second
|
|
-------+--------
|
|
|
|
|
(1 row)
|
|
|
|
SELECT * FROM test_table_record_as('tuple', null, null, false);
|
|
first | second
|
|
-------+--------
|
|
|
|
|
(1 row)
|
|
|
|
SELECT * FROM test_table_record_as('tuple', 'one', null, false);
|
|
first | second
|
|
-------+--------
|
|
one |
|
|
(1 row)
|
|
|
|
SELECT * FROM test_table_record_as('tuple', null, 2, false);
|
|
first | second
|
|
-------+--------
|
|
| 2
|
|
(1 row)
|
|
|
|
SELECT * FROM test_table_record_as('tuple', 'three', 3, false);
|
|
first | second
|
|
-------+--------
|
|
three | 3
|
|
(1 row)
|
|
|
|
SELECT * FROM test_table_record_as('tuple', null, null, true);
|
|
first | second
|
|
-------+--------
|
|
|
|
|
(1 row)
|
|
|
|
SELECT * FROM test_table_record_as('list', null, null, false);
|
|
first | second
|
|
-------+--------
|
|
|
|
|
(1 row)
|
|
|
|
SELECT * FROM test_table_record_as('list', 'one', null, false);
|
|
first | second
|
|
-------+--------
|
|
one |
|
|
(1 row)
|
|
|
|
SELECT * FROM test_table_record_as('list', null, 2, false);
|
|
first | second
|
|
-------+--------
|
|
| 2
|
|
(1 row)
|
|
|
|
SELECT * FROM test_table_record_as('list', 'three', 3, false);
|
|
first | second
|
|
-------+--------
|
|
three | 3
|
|
(1 row)
|
|
|
|
SELECT * FROM test_table_record_as('list', null, null, true);
|
|
first | second
|
|
-------+--------
|
|
|
|
|
(1 row)
|
|
|
|
SELECT * FROM test_table_record_as('obj', null, null, false);
|
|
first | second
|
|
-------+--------
|
|
|
|
|
(1 row)
|
|
|
|
SELECT * FROM test_table_record_as('obj', 'one', null, false);
|
|
first | second
|
|
-------+--------
|
|
one |
|
|
(1 row)
|
|
|
|
SELECT * FROM test_table_record_as('obj', null, 2, false);
|
|
first | second
|
|
-------+--------
|
|
| 2
|
|
(1 row)
|
|
|
|
SELECT * FROM test_table_record_as('obj', 'three', 3, false);
|
|
first | second
|
|
-------+--------
|
|
three | 3
|
|
(1 row)
|
|
|
|
SELECT * FROM test_table_record_as('obj', null, null, true);
|
|
first | second
|
|
-------+--------
|
|
|
|
|
(1 row)
|
|
|
|
SELECT * FROM test_type_record_as('dict', null, null, false);
|
|
first | second
|
|
-------+--------
|
|
|
|
|
(1 row)
|
|
|
|
SELECT * FROM test_type_record_as('dict', 'one', null, false);
|
|
first | second
|
|
-------+--------
|
|
one |
|
|
(1 row)
|
|
|
|
SELECT * FROM test_type_record_as('dict', null, 2, false);
|
|
first | second
|
|
-------+--------
|
|
| 2
|
|
(1 row)
|
|
|
|
SELECT * FROM test_type_record_as('dict', 'three', 3, false);
|
|
first | second
|
|
-------+--------
|
|
three | 3
|
|
(1 row)
|
|
|
|
SELECT * FROM test_type_record_as('dict', null, null, true);
|
|
first | second
|
|
-------+--------
|
|
|
|
|
(1 row)
|
|
|
|
SELECT * FROM test_type_record_as('tuple', null, null, false);
|
|
first | second
|
|
-------+--------
|
|
|
|
|
(1 row)
|
|
|
|
SELECT * FROM test_type_record_as('tuple', 'one', null, false);
|
|
first | second
|
|
-------+--------
|
|
one |
|
|
(1 row)
|
|
|
|
SELECT * FROM test_type_record_as('tuple', null, 2, false);
|
|
first | second
|
|
-------+--------
|
|
| 2
|
|
(1 row)
|
|
|
|
SELECT * FROM test_type_record_as('tuple', 'three', 3, false);
|
|
first | second
|
|
-------+--------
|
|
three | 3
|
|
(1 row)
|
|
|
|
SELECT * FROM test_type_record_as('tuple', null, null, true);
|
|
first | second
|
|
-------+--------
|
|
|
|
|
(1 row)
|
|
|
|
SELECT * FROM test_type_record_as('list', null, null, false);
|
|
first | second
|
|
-------+--------
|
|
|
|
|
(1 row)
|
|
|
|
SELECT * FROM test_type_record_as('list', 'one', null, false);
|
|
first | second
|
|
-------+--------
|
|
one |
|
|
(1 row)
|
|
|
|
SELECT * FROM test_type_record_as('list', null, 2, false);
|
|
first | second
|
|
-------+--------
|
|
| 2
|
|
(1 row)
|
|
|
|
SELECT * FROM test_type_record_as('list', 'three', 3, false);
|
|
first | second
|
|
-------+--------
|
|
three | 3
|
|
(1 row)
|
|
|
|
SELECT * FROM test_type_record_as('list', null, null, true);
|
|
first | second
|
|
-------+--------
|
|
|
|
|
(1 row)
|
|
|
|
SELECT * FROM test_type_record_as('obj', null, null, false);
|
|
first | second
|
|
-------+--------
|
|
|
|
|
(1 row)
|
|
|
|
SELECT * FROM test_type_record_as('obj', 'one', null, false);
|
|
first | second
|
|
-------+--------
|
|
one |
|
|
(1 row)
|
|
|
|
SELECT * FROM test_type_record_as('obj', null, 2, false);
|
|
first | second
|
|
-------+--------
|
|
| 2
|
|
(1 row)
|
|
|
|
SELECT * FROM test_type_record_as('obj', 'three', 3, false);
|
|
first | second
|
|
-------+--------
|
|
three | 3
|
|
(1 row)
|
|
|
|
SELECT * FROM test_type_record_as('obj', null, null, true);
|
|
first | second
|
|
-------+--------
|
|
|
|
|
(1 row)
|
|
|
|
SELECT * FROM test_in_out_params('test_in');
|
|
second
|
|
-------------------
|
|
test_in_in_to_out
|
|
(1 row)
|
|
|
|
SELECT * FROM test_in_out_params_multi('test_in');
|
|
second | third
|
|
----------------------------+----------------------------
|
|
test_in_record_in_to_out_1 | test_in_record_in_to_out_2
|
|
(1 row)
|
|
|
|
SELECT * FROM test_inout_params('test_in');
|
|
first
|
|
---------------
|
|
test_in_inout
|
|
(1 row)
|
|
|
|
-- try changing the return types and call functions again
|
|
ALTER TABLE table_record DROP COLUMN first;
|
|
ALTER TABLE table_record DROP COLUMN second;
|
|
ALTER TABLE table_record ADD COLUMN first text;
|
|
ALTER TABLE table_record ADD COLUMN second int4;
|
|
SELECT * FROM test_table_record_as('obj', 'one', 1, false);
|
|
first | second
|
|
-------+--------
|
|
one | 1
|
|
(1 row)
|
|
|
|
ALTER TYPE type_record DROP ATTRIBUTE first;
|
|
ALTER TYPE type_record DROP ATTRIBUTE second;
|
|
ALTER TYPE type_record ADD ATTRIBUTE first text;
|
|
ALTER TYPE type_record ADD ATTRIBUTE second int4;
|
|
SELECT * FROM test_type_record_as('obj', 'one', 1, false);
|
|
first | second
|
|
-------+--------
|
|
one | 1
|
|
(1 row)
|
|
|
|
-- errors cases
|
|
CREATE FUNCTION test_type_record_error1() RETURNS type_record AS $$
|
|
return { 'first': 'first' }
|
|
$$ LANGUAGE plpythonu;
|
|
SELECT * FROM test_type_record_error1();
|
|
ERROR: key "second" not found in mapping
|
|
HINT: To return null in a column, add the value None to the mapping with the key named after the column.
|
|
CONTEXT: while creating return value
|
|
PL/Python function "test_type_record_error1"
|
|
CREATE FUNCTION test_type_record_error2() RETURNS type_record AS $$
|
|
return [ 'first' ]
|
|
$$ LANGUAGE plpythonu;
|
|
SELECT * FROM test_type_record_error2();
|
|
ERROR: length of returned sequence did not match number of columns in row
|
|
CONTEXT: while creating return value
|
|
PL/Python function "test_type_record_error2"
|
|
CREATE FUNCTION test_type_record_error3() RETURNS type_record AS $$
|
|
class type_record: pass
|
|
type_record.first = 'first'
|
|
return type_record
|
|
$$ LANGUAGE plpythonu;
|
|
SELECT * FROM test_type_record_error3();
|
|
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"
|