diff options
Diffstat (limited to 'src/pl/plpython/expected/plpython_composite.out')
-rw-r--r-- | src/pl/plpython/expected/plpython_composite.out | 594 |
1 files changed, 594 insertions, 0 deletions
diff --git a/src/pl/plpython/expected/plpython_composite.out b/src/pl/plpython/expected/plpython_composite.out new file mode 100644 index 0000000..bb101e0 --- /dev/null +++ b/src/pl/plpython/expected/plpython_composite.out @@ -0,0 +1,594 @@ +CREATE FUNCTION multiout_simple(OUT i integer, OUT j integer) AS $$ +return (1, 2) +$$ LANGUAGE plpython3u; +SELECT multiout_simple(); + multiout_simple +----------------- + (1,2) +(1 row) + +SELECT * FROM multiout_simple(); + i | j +---+--- + 1 | 2 +(1 row) + +SELECT i, j + 2 FROM multiout_simple(); + i | ?column? +---+---------- + 1 | 4 +(1 row) + +SELECT (multiout_simple()).j + 3; + ?column? +---------- + 5 +(1 row) + +CREATE FUNCTION multiout_simple_setof(n integer = 1, OUT integer, OUT integer) RETURNS SETOF record AS $$ +return [(1, 2)] * n +$$ LANGUAGE plpython3u; +SELECT multiout_simple_setof(); + multiout_simple_setof +----------------------- + (1,2) +(1 row) + +SELECT * FROM multiout_simple_setof(); + column1 | column2 +---------+--------- + 1 | 2 +(1 row) + +SELECT * FROM multiout_simple_setof(3); + column1 | column2 +---------+--------- + 1 | 2 + 1 | 2 + 1 | 2 +(3 rows) + +CREATE FUNCTION multiout_record_as(typ text, + first text, OUT first text, + second integer, OUT second integer, + retnull boolean) RETURNS 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 +elif typ == 'str': + return "('%s',%r)" % (first, second) +$$ LANGUAGE plpython3u; +SELECT * FROM multiout_record_as('dict', 'foo', 1, 'f'); + first | second +-------+-------- + foo | 1 +(1 row) + +SELECT multiout_record_as('dict', 'foo', 1, 'f'); + multiout_record_as +-------------------- + (foo,1) +(1 row) + +SELECT * FROM multiout_record_as('dict', null, null, false); + first | second +-------+-------- + | +(1 row) + +SELECT * FROM multiout_record_as('dict', 'one', null, false); + first | second +-------+-------- + one | +(1 row) + +SELECT * FROM multiout_record_as('dict', null, 2, false); + first | second +-------+-------- + | 2 +(1 row) + +SELECT * FROM multiout_record_as('dict', 'three', 3, false); + first | second +-------+-------- + three | 3 +(1 row) + +SELECT * FROM multiout_record_as('dict', null, null, true); + first | second +-------+-------- + | +(1 row) + +SELECT * FROM multiout_record_as('tuple', null, null, false); + first | second +-------+-------- + | +(1 row) + +SELECT * FROM multiout_record_as('tuple', 'one', null, false); + first | second +-------+-------- + one | +(1 row) + +SELECT * FROM multiout_record_as('tuple', null, 2, false); + first | second +-------+-------- + | 2 +(1 row) + +SELECT * FROM multiout_record_as('tuple', 'three', 3, false); + first | second +-------+-------- + three | 3 +(1 row) + +SELECT * FROM multiout_record_as('tuple', null, null, true); + first | second +-------+-------- + | +(1 row) + +SELECT * FROM multiout_record_as('list', null, null, false); + first | second +-------+-------- + | +(1 row) + +SELECT * FROM multiout_record_as('list', 'one', null, false); + first | second +-------+-------- + one | +(1 row) + +SELECT * FROM multiout_record_as('list', null, 2, false); + first | second +-------+-------- + | 2 +(1 row) + +SELECT * FROM multiout_record_as('list', 'three', 3, false); + first | second +-------+-------- + three | 3 +(1 row) + +SELECT * FROM multiout_record_as('list', null, null, true); + first | second +-------+-------- + | +(1 row) + +SELECT * FROM multiout_record_as('obj', null, null, false); + first | second +-------+-------- + | +(1 row) + +SELECT * FROM multiout_record_as('obj', 'one', null, false); + first | second +-------+-------- + one | +(1 row) + +SELECT * FROM multiout_record_as('obj', null, 2, false); + first | second +-------+-------- + | 2 +(1 row) + +SELECT * FROM multiout_record_as('obj', 'three', 3, false); + first | second +-------+-------- + three | 3 +(1 row) + +SELECT * FROM multiout_record_as('obj', null, null, true); + first | second +-------+-------- + | +(1 row) + +SELECT * FROM multiout_record_as('str', 'one', 1, false); + first | second +-------+-------- + 'one' | 1 +(1 row) + +SELECT * FROM multiout_record_as('str', 'one', 2, false); + first | second +-------+-------- + 'one' | 2 +(1 row) + +SELECT *, s IS NULL AS snull FROM multiout_record_as('tuple', 'xxx', NULL, 'f') AS f(f, s); + f | s | snull +-----+---+------- + xxx | | t +(1 row) + +SELECT *, f IS NULL AS fnull, s IS NULL AS snull FROM multiout_record_as('tuple', 'xxx', 1, 't') AS f(f, s); + f | s | fnull | snull +---+---+-------+------- + | | t | t +(1 row) + +SELECT * FROM multiout_record_as('obj', NULL, 10, 'f'); + first | second +-------+-------- + | 10 +(1 row) + +CREATE FUNCTION multiout_setof(n integer, + OUT power_of_2 integer, + OUT length integer) RETURNS SETOF record AS $$ +for i in range(n): + power = 2 ** i + length = plpy.execute("select length('%d')" % power)[0]['length'] + yield power, length +$$ LANGUAGE plpython3u; +SELECT * FROM multiout_setof(3); + power_of_2 | length +------------+-------- + 1 | 1 + 2 | 1 + 4 | 1 +(3 rows) + +SELECT multiout_setof(5); + multiout_setof +---------------- + (1,1) + (2,1) + (4,1) + (8,1) + (16,2) +(5 rows) + +CREATE FUNCTION multiout_return_table() RETURNS TABLE (x integer, y text) AS $$ +return [{'x': 4, 'y' :'four'}, + {'x': 7, 'y' :'seven'}, + {'x': 0, 'y' :'zero'}] +$$ LANGUAGE plpython3u; +SELECT * FROM multiout_return_table(); + x | y +---+------- + 4 | four + 7 | seven + 0 | zero +(3 rows) + +CREATE FUNCTION multiout_array(OUT integer[], OUT text) RETURNS SETOF record AS $$ +yield [[1], 'a'] +yield [[1,2], 'b'] +yield [[1,2,3], None] +$$ LANGUAGE plpython3u; +SELECT * FROM multiout_array(); + column1 | column2 +---------+--------- + {1} | a + {1,2} | b + {1,2,3} | +(3 rows) + +CREATE FUNCTION singleout_composite(OUT type_record) AS $$ +return {'first': 1, 'second': 2} +$$ LANGUAGE plpython3u; +CREATE FUNCTION multiout_composite(OUT type_record) RETURNS SETOF type_record AS $$ +return [{'first': 1, 'second': 2}, + {'first': 3, 'second': 4 }] +$$ LANGUAGE plpython3u; +SELECT * FROM singleout_composite(); + first | second +-------+-------- + 1 | 2 +(1 row) + +SELECT * FROM multiout_composite(); + first | second +-------+-------- + 1 | 2 + 3 | 4 +(2 rows) + +-- composite OUT parameters in functions returning RECORD not supported yet +CREATE FUNCTION multiout_composite(INOUT n integer, OUT type_record) AS $$ +return (n, (n * 2, n * 3)) +$$ LANGUAGE plpython3u; +CREATE FUNCTION multiout_table_type_setof(typ text, returnnull boolean, INOUT n integer, OUT table_record) RETURNS SETOF record AS $$ +if returnnull: + d = None +elif typ == 'dict': + d = {'first': n * 2, 'second': n * 3, 'extra': 'not important'} +elif typ == 'tuple': + d = (n * 2, n * 3) +elif typ == 'list': + d = [ n * 2, n * 3 ] +elif typ == 'obj': + class d: pass + d.first = n * 2 + d.second = n * 3 +elif typ == 'str': + d = "(%r,%r)" % (n * 2, n * 3) +for i in range(n): + yield (i, d) +$$ LANGUAGE plpython3u; +SELECT * FROM multiout_composite(2); + n | column2 +---+--------- + 2 | (4,6) +(1 row) + +SELECT * FROM multiout_table_type_setof('dict', 'f', 3); + n | column2 +---+--------- + 0 | (6,9) + 1 | (6,9) + 2 | (6,9) +(3 rows) + +SELECT * FROM multiout_table_type_setof('dict', 'f', 7); + n | column2 +---+--------- + 0 | (14,21) + 1 | (14,21) + 2 | (14,21) + 3 | (14,21) + 4 | (14,21) + 5 | (14,21) + 6 | (14,21) +(7 rows) + +SELECT * FROM multiout_table_type_setof('tuple', 'f', 2); + n | column2 +---+--------- + 0 | (4,6) + 1 | (4,6) +(2 rows) + +SELECT * FROM multiout_table_type_setof('tuple', 'f', 3); + n | column2 +---+--------- + 0 | (6,9) + 1 | (6,9) + 2 | (6,9) +(3 rows) + +SELECT * FROM multiout_table_type_setof('list', 'f', 2); + n | column2 +---+--------- + 0 | (4,6) + 1 | (4,6) +(2 rows) + +SELECT * FROM multiout_table_type_setof('list', 'f', 3); + n | column2 +---+--------- + 0 | (6,9) + 1 | (6,9) + 2 | (6,9) +(3 rows) + +SELECT * FROM multiout_table_type_setof('obj', 'f', 4); + n | column2 +---+--------- + 0 | (8,12) + 1 | (8,12) + 2 | (8,12) + 3 | (8,12) +(4 rows) + +SELECT * FROM multiout_table_type_setof('obj', 'f', 5); + n | column2 +---+--------- + 0 | (10,15) + 1 | (10,15) + 2 | (10,15) + 3 | (10,15) + 4 | (10,15) +(5 rows) + +SELECT * FROM multiout_table_type_setof('str', 'f', 6); + n | column2 +---+--------- + 0 | (12,18) + 1 | (12,18) + 2 | (12,18) + 3 | (12,18) + 4 | (12,18) + 5 | (12,18) +(6 rows) + +SELECT * FROM multiout_table_type_setof('str', 'f', 7); + n | column2 +---+--------- + 0 | (14,21) + 1 | (14,21) + 2 | (14,21) + 3 | (14,21) + 4 | (14,21) + 5 | (14,21) + 6 | (14,21) +(7 rows) + +SELECT * FROM multiout_table_type_setof('dict', 't', 3); + n | column2 +---+--------- + 0 | + 1 | + 2 | +(3 rows) + +-- check what happens if a type changes under us +CREATE TABLE changing ( + i integer, + j integer +); +CREATE FUNCTION changing_test(OUT n integer, OUT changing) RETURNS SETOF record AS $$ +return [(1, {'i': 1, 'j': 2}), + (1, (3, 4))] +$$ LANGUAGE plpython3u; +SELECT * FROM changing_test(); + n | column2 +---+--------- + 1 | (1,2) + 1 | (3,4) +(2 rows) + +ALTER TABLE changing DROP COLUMN j; +SELECT * FROM changing_test(); +ERROR: length of returned sequence did not match number of columns in row +CONTEXT: while creating return value +PL/Python function "changing_test" +SELECT * FROM changing_test(); +ERROR: length of returned sequence did not match number of columns in row +CONTEXT: while creating return value +PL/Python function "changing_test" +ALTER TABLE changing ADD COLUMN j integer; +SELECT * FROM changing_test(); + n | column2 +---+--------- + 1 | (1,2) + 1 | (3,4) +(2 rows) + +-- tables of composite types +CREATE FUNCTION composite_types_table(OUT tab table_record[], OUT typ type_record[] ) RETURNS SETOF record AS $$ +yield {'tab': [('first', 1), ('second', 2)], + 'typ': [{'first': 'third', 'second': 3}, + {'first': 'fourth', 'second': 4}]} +yield {'tab': [('first', 1), ('second', 2)], + 'typ': [{'first': 'third', 'second': 3}, + {'first': 'fourth', 'second': 4}]} +yield {'tab': [('first', 1), ('second', 2)], + 'typ': [{'first': 'third', 'second': 3}, + {'first': 'fourth', 'second': 4}]} +$$ LANGUAGE plpython3u; +SELECT * FROM composite_types_table(); + tab | typ +----------------------------+---------------------------- + {"(first,1)","(second,2)"} | {"(third,3)","(fourth,4)"} + {"(first,1)","(second,2)"} | {"(third,3)","(fourth,4)"} + {"(first,1)","(second,2)"} | {"(third,3)","(fourth,4)"} +(3 rows) + +-- check what happens if the output record descriptor changes +CREATE FUNCTION return_record(t text) RETURNS record AS $$ +return {'t': t, 'val': 10} +$$ LANGUAGE plpython3u; +SELECT * FROM return_record('abc') AS r(t text, val integer); + t | val +-----+----- + abc | 10 +(1 row) + +SELECT * FROM return_record('abc') AS r(t text, val bigint); + t | val +-----+----- + abc | 10 +(1 row) + +SELECT * FROM return_record('abc') AS r(t text, val integer); + t | val +-----+----- + abc | 10 +(1 row) + +SELECT * FROM return_record('abc') AS r(t varchar(30), val integer); + t | val +-----+----- + abc | 10 +(1 row) + +SELECT * FROM return_record('abc') AS r(t varchar(100), val integer); + t | val +-----+----- + abc | 10 +(1 row) + +SELECT * FROM return_record('999') AS r(val text, t integer); + val | t +-----+----- + 10 | 999 +(1 row) + +CREATE FUNCTION return_record_2(t text) RETURNS record AS $$ +return {'v1':1,'v2':2,t:3} +$$ LANGUAGE plpython3u; +SELECT * FROM return_record_2('v3') AS (v3 int, v2 int, v1 int); + v3 | v2 | v1 +----+----+---- + 3 | 2 | 1 +(1 row) + +SELECT * FROM return_record_2('v3') AS (v2 int, v3 int, v1 int); + v2 | v3 | v1 +----+----+---- + 2 | 3 | 1 +(1 row) + +SELECT * FROM return_record_2('v4') AS (v1 int, v4 int, v2 int); + v1 | v4 | v2 +----+----+---- + 1 | 3 | 2 +(1 row) + +SELECT * FROM return_record_2('v4') AS (v1 int, v4 int, v2 int); + v1 | v4 | v2 +----+----+---- + 1 | 3 | 2 +(1 row) + +-- error +SELECT * FROM return_record_2('v4') AS (v1 int, v3 int, v2 int); +ERROR: key "v3" 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 "return_record_2" +-- works +SELECT * FROM return_record_2('v3') AS (v1 int, v3 int, v2 int); + v1 | v3 | v2 +----+----+---- + 1 | 3 | 2 +(1 row) + +SELECT * FROM return_record_2('v3') AS (v1 int, v2 int, v3 int); + v1 | v2 | v3 +----+----+---- + 1 | 2 | 3 +(1 row) + +-- multi-dimensional array of composite types. +CREATE FUNCTION composite_type_as_list() RETURNS type_record[] AS $$ + return [[('first', 1), ('second', 1)], [('first', 2), ('second', 2)], [('first', 3), ('second', 3)]]; +$$ LANGUAGE plpython3u; +SELECT * FROM composite_type_as_list(); + composite_type_as_list +------------------------------------------------------------------------------------ + {{"(first,1)","(second,1)"},{"(first,2)","(second,2)"},{"(first,3)","(second,3)"}} +(1 row) + +-- Starting with PostgreSQL 10, a composite type in an array cannot be +-- represented as a Python list, because it's ambiguous with multi-dimensional +-- arrays. So this throws an error now. The error should contain a useful hint +-- on the issue. +CREATE FUNCTION composite_type_as_list_broken() RETURNS type_record[] AS $$ + return [['first', 1]]; +$$ LANGUAGE plpython3u; +SELECT * FROM composite_type_as_list_broken(); +ERROR: malformed record literal: "first" +DETAIL: Missing left parenthesis. +HINT: To return a composite type in an array, return the composite type as a Python tuple, e.g., "[('foo',)]". +CONTEXT: while creating return value +PL/Python function "composite_type_as_list_broken" |