1 CREATE FUNCTION multiout_simple(OUT i integer, OUT j integer) AS $$
4 SELECT multiout_simple();
10 SELECT * FROM multiout_simple();
16 SELECT i, j + 2 FROM multiout_simple();
22 SELECT (multiout_simple()).j + 3;
28 CREATE FUNCTION multiout_simple_setof(n integer = 1, OUT integer, OUT integer) RETURNS SETOF record AS $$
30 $$ LANGUAGE plpythonu;
31 SELECT multiout_simple_setof();
33 -----------------------
37 SELECT * FROM multiout_simple_setof();
43 SELECT * FROM multiout_simple_setof(3);
51 CREATE FUNCTION multiout_record_as(typ text,
52 first text, OUT first text,
53 second integer, OUT second integer,
54 retnull boolean) RETURNS record AS $$
58 return { 'first': first, 'second': second, 'additionalfield': 'must not cause trouble' }
60 return ( first, second )
62 return [ first, second ]
64 class type_record: pass
65 type_record.first = first
66 type_record.second = second
69 return "('%s',%r)" % (first, second)
70 $$ LANGUAGE plpythonu;
71 SELECT * FROM multiout_record_as('dict', 'foo', 1, 'f');
77 SELECT multiout_record_as('dict', 'foo', 1, 'f');
83 SELECT * FROM multiout_record_as('dict', null, null, false);
89 SELECT * FROM multiout_record_as('dict', 'one', null, false);
95 SELECT * FROM multiout_record_as('dict', null, 2, false);
101 SELECT * FROM multiout_record_as('dict', 'three', 3, false);
107 SELECT * FROM multiout_record_as('dict', null, null, true);
113 SELECT * FROM multiout_record_as('tuple', null, null, false);
119 SELECT * FROM multiout_record_as('tuple', 'one', null, false);
125 SELECT * FROM multiout_record_as('tuple', null, 2, false);
131 SELECT * FROM multiout_record_as('tuple', 'three', 3, false);
137 SELECT * FROM multiout_record_as('tuple', null, null, true);
143 SELECT * FROM multiout_record_as('list', null, null, false);
149 SELECT * FROM multiout_record_as('list', 'one', null, false);
155 SELECT * FROM multiout_record_as('list', null, 2, false);
161 SELECT * FROM multiout_record_as('list', 'three', 3, false);
167 SELECT * FROM multiout_record_as('list', null, null, true);
173 SELECT * FROM multiout_record_as('obj', null, null, false);
179 SELECT * FROM multiout_record_as('obj', 'one', null, false);
185 SELECT * FROM multiout_record_as('obj', null, 2, false);
191 SELECT * FROM multiout_record_as('obj', 'three', 3, false);
197 SELECT * FROM multiout_record_as('obj', null, null, true);
203 SELECT * FROM multiout_record_as('str', 'one', 1, false);
209 SELECT * FROM multiout_record_as('str', 'one', 2, false);
215 SELECT *, s IS NULL AS snull FROM multiout_record_as('tuple', 'xxx', NULL, 'f') AS f(f, s);
221 SELECT *, f IS NULL AS fnull, s IS NULL AS snull FROM multiout_record_as('tuple', 'xxx', 1, 't') AS f(f, s);
222 f | s | fnull | snull
223 ---+---+-------+-------
227 SELECT * FROM multiout_record_as('obj', NULL, 10, 'f');
233 CREATE FUNCTION multiout_setof(n integer,
234 OUT power_of_2 integer,
235 OUT length integer) RETURNS SETOF record AS $$
238 length = plpy.execute("select length('%d')" % power)[0]['length']
240 $$ LANGUAGE plpythonu;
241 SELECT * FROM multiout_setof(3);
243 ------------+--------
249 SELECT multiout_setof(5);
259 CREATE FUNCTION multiout_return_table() RETURNS TABLE (x integer, y text) AS $$
260 return [{'x': 4, 'y' :'four'},
261 {'x': 7, 'y' :'seven'},
262 {'x': 0, 'y' :'zero'}]
263 $$ LANGUAGE plpythonu;
264 SELECT * FROM multiout_return_table();
272 CREATE FUNCTION multiout_array(OUT integer[], OUT text) RETURNS SETOF record AS $$
275 yield [[1,2,3], None]
276 $$ LANGUAGE plpythonu;
277 SELECT * FROM multiout_array();
285 CREATE FUNCTION singleout_composite(OUT type_record) AS $$
286 return {'first': 1, 'second': 2}
287 $$ LANGUAGE plpythonu;
288 CREATE FUNCTION multiout_composite(OUT type_record) RETURNS SETOF type_record AS $$
289 return [{'first': 1, 'second': 2},
290 {'first': 3, 'second': 4 }]
291 $$ LANGUAGE plpythonu;
292 SELECT * FROM singleout_composite();
298 SELECT * FROM multiout_composite();
305 -- composite OUT parameters in functions returning RECORD not supported yet
306 CREATE FUNCTION multiout_composite(INOUT n integer, OUT type_record) AS $$
307 return (n, (n * 2, n * 3))
308 $$ LANGUAGE plpythonu;
309 CREATE FUNCTION multiout_table_type_setof(typ text, returnnull boolean, INOUT n integer, OUT table_record) RETURNS SETOF record AS $$
313 d = {'first': n * 2, 'second': n * 3, 'extra': 'not important'}
323 d = "(%r,%r)" % (n * 2, n * 3)
326 $$ LANGUAGE plpythonu;
327 SELECT * FROM multiout_composite(2);
333 SELECT * FROM multiout_table_type_setof('dict', 'f', 3);
341 SELECT * FROM multiout_table_type_setof('dict', 'f', 7);
353 SELECT * FROM multiout_table_type_setof('tuple', 'f', 2);
360 SELECT * FROM multiout_table_type_setof('tuple', 'f', 3);
368 SELECT * FROM multiout_table_type_setof('list', 'f', 2);
375 SELECT * FROM multiout_table_type_setof('list', 'f', 3);
383 SELECT * FROM multiout_table_type_setof('obj', 'f', 4);
392 SELECT * FROM multiout_table_type_setof('obj', 'f', 5);
402 SELECT * FROM multiout_table_type_setof('str', 'f', 6);
413 SELECT * FROM multiout_table_type_setof('str', 'f', 7);
425 SELECT * FROM multiout_table_type_setof('dict', 't', 3);
433 -- check what happens if a type changes under us
434 CREATE TABLE changing (
438 CREATE FUNCTION changing_test(OUT n integer, OUT changing) RETURNS SETOF record AS $$
439 return [(1, {'i': 1, 'j': 2}),
441 $$ LANGUAGE plpythonu;
442 SELECT * FROM changing_test();
449 ALTER TABLE changing DROP COLUMN j;
450 SELECT * FROM changing_test();
451 ERROR: length of returned sequence did not match number of columns in row
452 CONTEXT: while creating return value
453 PL/Python function "changing_test"
454 SELECT * FROM changing_test();
455 ERROR: length of returned sequence did not match number of columns in row
456 CONTEXT: while creating return value
457 PL/Python function "changing_test"
458 ALTER TABLE changing ADD COLUMN j integer;
459 SELECT * FROM changing_test();
466 -- tables of composite types
467 CREATE FUNCTION composite_types_table(OUT tab table_record[], OUT typ type_record[] ) RETURNS SETOF record AS $$
468 yield {'tab': [('first', 1), ('second', 2)],
469 'typ': [{'first': 'third', 'second': 3},
470 {'first': 'fourth', 'second': 4}]}
471 yield {'tab': [('first', 1), ('second', 2)],
472 'typ': [{'first': 'third', 'second': 3},
473 {'first': 'fourth', 'second': 4}]}
474 yield {'tab': [('first', 1), ('second', 2)],
475 'typ': [{'first': 'third', 'second': 3},
476 {'first': 'fourth', 'second': 4}]}
477 $$ LANGUAGE plpythonu;
478 SELECT * FROM composite_types_table();
480 ----------------------------+----------------------------
481 {"(first,1)","(second,2)"} | {"(third,3)","(fourth,4)"}
482 {"(first,1)","(second,2)"} | {"(third,3)","(fourth,4)"}
483 {"(first,1)","(second,2)"} | {"(third,3)","(fourth,4)"}
486 -- check what happens if the output record descriptor changes
487 CREATE FUNCTION return_record(t text) RETURNS record AS $$
488 return {'t': t, 'val': 10}
489 $$ LANGUAGE plpythonu;
490 SELECT * FROM return_record('abc') AS r(t text, val integer);
496 SELECT * FROM return_record('abc') AS r(t text, val bigint);
502 SELECT * FROM return_record('abc') AS r(t text, val integer);
508 SELECT * FROM return_record('abc') AS r(t varchar(30), val integer);
514 SELECT * FROM return_record('abc') AS r(t varchar(100), val integer);
520 SELECT * FROM return_record('999') AS r(val text, t integer);
526 CREATE FUNCTION return_record_2(t text) RETURNS record AS $$
527 return {'v1':1,'v2':2,t:3}
528 $$ LANGUAGE plpythonu;
529 SELECT * FROM return_record_2('v3') AS (v3 int, v2 int, v1 int);
535 SELECT * FROM return_record_2('v3') AS (v2 int, v3 int, v1 int);
541 SELECT * FROM return_record_2('v4') AS (v1 int, v4 int, v2 int);
547 SELECT * FROM return_record_2('v4') AS (v1 int, v4 int, v2 int);
554 SELECT * FROM return_record_2('v4') AS (v1 int, v3 int, v2 int);
555 ERROR: key "v3" not found in mapping
556 HINT: To return null in a column, add the value None to the mapping with the key named after the column.
557 CONTEXT: while creating return value
558 PL/Python function "return_record_2"
560 SELECT * FROM return_record_2('v3') AS (v1 int, v3 int, v2 int);
566 SELECT * FROM return_record_2('v3') AS (v1 int, v2 int, v3 int);
572 -- multi-dimensional array of composite types.
573 CREATE FUNCTION composite_type_as_list() RETURNS type_record[] AS $$
574 return [[('first', 1), ('second', 1)], [('first', 2), ('second', 2)], [('first', 3), ('second', 3)]];
575 $$ LANGUAGE plpythonu;
576 SELECT * FROM composite_type_as_list();
577 composite_type_as_list
578 ------------------------------------------------------------------------------------
579 {{"(first,1)","(second,1)"},{"(first,2)","(second,2)"},{"(first,3)","(second,3)"}}
582 -- Starting with PostgreSQL 10, a composite type in an array cannot be
583 -- represented as a Python list, because it's ambiguous with multi-dimensional
584 -- arrays. So this throws an error now. The error should contain a useful hint
586 CREATE FUNCTION composite_type_as_list_broken() RETURNS type_record[] AS $$
587 return [['first', 1]];
588 $$ LANGUAGE plpythonu;
589 SELECT * FROM composite_type_as_list_broken();
590 ERROR: malformed record literal: "first"
591 DETAIL: Missing left parenthesis.
592 HINT: To return a composite type in an array, return the composite type as a Python tuple, e.g., "[('foo',)]".
593 CONTEXT: while creating return value
594 PL/Python function "composite_type_as_list_broken"