mirror of
https://git.postgresql.org/git/postgresql.git
synced 2025-02-17 19:30:00 +08:00
Fix plpython crash when returning string representation of a RECORD result.
PLyString_ToComposite() blithely overwrote proc->result.out.d, even though for a composite result type the other union variant proc->result.out.r is the one that should be valid. This could result in a crash if out.r had in fact been filled in (proc->result.is_rowtype == 1) and then somebody later attempted to use that data; as per bug #13579 from Paweł Michalak. Just to add insult to injury, it didn't work for RECORD results anyway, because record_in() would refuse the case. Fix by doing the I/O function lookup in a local PLyTypeInfo variable, as we were doing already in PLyObject_ToComposite(). This is not a great technique because any fn_extra data allocated by the input function will be leaked permanently (thanks to using TopMemoryContext as fn_mcxt). But that's a pre-existing issue that is much less serious than a crash, so leave it to be fixed separately. This bug would be a potential security issue, except that plpython is only available to superusers and the crash requires coding the function in a way that didn't work before today's patches. Add regression test cases covering all the supported methods of converting composite results. Back-patch to 9.1 where the faulty coding was introduced.
This commit is contained in:
parent
09b3d27256
commit
f469f634ad
@ -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
|
||||
---+---------
|
||||
|
@ -912,20 +912,30 @@ PLySequence_ToArray(PLyObToDatum *arg, int32 typmod, PyObject *plrv)
|
||||
static Datum
|
||||
PLyString_ToComposite(PLyTypeInfo *info, TupleDesc desc, PyObject *string)
|
||||
{
|
||||
Datum result;
|
||||
HeapTuple typeTup;
|
||||
PLyTypeInfo locinfo;
|
||||
PLyExecutionContext *exec_ctx = PLy_current_execution_context();
|
||||
|
||||
/* 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,
|
||||
exec_ctx->curr_proc->langid,
|
||||
exec_ctx->curr_proc->trftypes);
|
||||
|
||||
ReleaseSysCache(typeTup);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user