diff --git a/src/pl/plpython/expected/plpython_composite.out b/src/pl/plpython/expected/plpython_composite.out index 61b3046790f268409d8f4eed76657406c56f0cbf..d2384eb9865c461bef87a6ef9faf6495b878fc58 100644 --- a/src/pl/plpython/expected/plpython_composite.out +++ b/src/pl/plpython/expected/plpython_composite.out @@ -65,6 +65,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; SELECT * FROM multiout_record_as('dict', 'foo', 1, 'f'); first | second @@ -78,6 +80,138 @@ SELECT multiout_record_as('dict', 'foo', 1, 'f'); (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 -----+---+------- @@ -179,10 +313,14 @@ 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 plpythonu; @@ -200,6 +338,18 @@ SELECT * FROM multiout_table_type_setof('dict', 'f', 3); 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 ---+--------- @@ -207,6 +357,29 @@ SELECT * FROM multiout_table_type_setof('tuple', 'f', 2); 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 ---+--------- @@ -216,6 +389,39 @@ SELECT * FROM multiout_table_type_setof('obj', 'f', 4); 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 ---+--------- diff --git a/src/pl/plpython/plpy_typeio.c b/src/pl/plpython/plpy_typeio.c index 566cf6c0fec2d248e0687f8efaf7cba599981b60..bba5d82054b1200ec902b141753bdcc0f2b09106 100644 --- a/src/pl/plpython/plpy_typeio.c +++ b/src/pl/plpython/plpy_typeio.c @@ -863,18 +863,28 @@ PLySequence_ToArray(PLyObToDatum *arg, int32 typmod, PyObject *plrv) static Datum PLyString_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *string) { + Datum result; HeapTuple typeTup; + PLyTypeInfo locinfo; + + /* Create a dummy PLyTypeInfo */ + MemSet(&locinfo, 0, sizeof(PLyTypeInfo)); + PLy_typeinfo_init(&locinfo); typeTup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(desc->tdtypeid)); if (!HeapTupleIsValid(typeTup)) elog(ERROR, "cache lookup failed for type %u", desc->tdtypeid); - PLy_output_datum_func2(&info->out.d, typeTup); + PLy_output_datum_func2(&locinfo.out.d, typeTup); ReleaseSysCache(typeTup); ReleaseTupleDesc(desc); - return PLyObject_ToDatum(&info->out.d, info->out.d.typmod, string); + result = PLyObject_ToDatum(&locinfo.out.d, desc->tdtypmod, string); + + PLy_typeinfo_dealloc(&locinfo); + + return result; } diff --git a/src/pl/plpython/sql/plpython_composite.sql b/src/pl/plpython/sql/plpython_composite.sql index cee98f288d4cf3cc33f77241905b9fae3ab40e4b..8bdb5c115ab0e42f55c15b20d3003b4dcee7c920 100644 --- a/src/pl/plpython/sql/plpython_composite.sql +++ b/src/pl/plpython/sql/plpython_composite.sql @@ -32,10 +32,40 @@ elif typ == 'obj': type_record.first = first type_record.second = second return type_record +elif typ == 'str': + return "('%s',%r)" % (first, second) $$ LANGUAGE plpythonu; SELECT * FROM multiout_record_as('dict', 'foo', 1, 'f'); SELECT multiout_record_as('dict', 'foo', 1, 'f'); + +SELECT * FROM multiout_record_as('dict', null, null, false); +SELECT * FROM multiout_record_as('dict', 'one', null, false); +SELECT * FROM multiout_record_as('dict', null, 2, false); +SELECT * FROM multiout_record_as('dict', 'three', 3, false); +SELECT * FROM multiout_record_as('dict', null, null, true); + +SELECT * FROM multiout_record_as('tuple', null, null, false); +SELECT * FROM multiout_record_as('tuple', 'one', null, false); +SELECT * FROM multiout_record_as('tuple', null, 2, false); +SELECT * FROM multiout_record_as('tuple', 'three', 3, false); +SELECT * FROM multiout_record_as('tuple', null, null, true); + +SELECT * FROM multiout_record_as('list', null, null, false); +SELECT * FROM multiout_record_as('list', 'one', null, false); +SELECT * FROM multiout_record_as('list', null, 2, false); +SELECT * FROM multiout_record_as('list', 'three', 3, false); +SELECT * FROM multiout_record_as('list', null, null, true); + +SELECT * FROM multiout_record_as('obj', null, null, false); +SELECT * FROM multiout_record_as('obj', 'one', null, false); +SELECT * FROM multiout_record_as('obj', null, 2, false); +SELECT * FROM multiout_record_as('obj', 'three', 3, false); +SELECT * FROM multiout_record_as('obj', null, null, true); + +SELECT * FROM multiout_record_as('str', 'one', 1, false); +SELECT * FROM multiout_record_as('str', 'one', 2, false); + SELECT *, s IS NULL AS snull FROM multiout_record_as('tuple', 'xxx', NULL, 'f') AS f(f, s); SELECT *, f IS NULL AS fnull, s IS NULL AS snull FROM multiout_record_as('tuple', 'xxx', 1, 't') AS f(f, s); SELECT * FROM multiout_record_as('obj', NULL, 10, 'f'); @@ -92,18 +122,29 @@ 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 plpythonu; SELECT * FROM multiout_composite(2); SELECT * FROM multiout_table_type_setof('dict', 'f', 3); +SELECT * FROM multiout_table_type_setof('dict', 'f', 7); SELECT * FROM multiout_table_type_setof('tuple', 'f', 2); +SELECT * FROM multiout_table_type_setof('tuple', 'f', 3); +SELECT * FROM multiout_table_type_setof('list', 'f', 2); +SELECT * FROM multiout_table_type_setof('list', 'f', 3); SELECT * FROM multiout_table_type_setof('obj', 'f', 4); +SELECT * FROM multiout_table_type_setof('obj', 'f', 5); +SELECT * FROM multiout_table_type_setof('str', 'f', 6); +SELECT * FROM multiout_table_type_setof('str', 'f', 7); SELECT * FROM multiout_table_type_setof('dict', 't', 3); -- check what happens if a type changes under us