summaryrefslogtreecommitdiffstats
path: root/src/pl/plpython/expected/plpython_composite.out
diff options
context:
space:
mode:
Diffstat (limited to 'src/pl/plpython/expected/plpython_composite.out')
-rw-r--r--src/pl/plpython/expected/plpython_composite.out594
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"