PL/Python: Fix crash when colnames() etc. called without result set
The result object methods colnames() etc. would crash when called after a command that did not produce a result set. Now they throw an exception. discovery and initial patch by Jean-Baptiste Quenot
This commit is contained in:
parent
4efbb7d04f
commit
c03523ed3f
@ -935,6 +935,14 @@ foo = rv[i]["my_column"]
|
|||||||
Return a list of column names, list of column type OIDs, and list of
|
Return a list of column names, list of column type OIDs, and list of
|
||||||
type-specific type modifiers for the columns, respectively.
|
type-specific type modifiers for the columns, respectively.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
These methods raise an exception when called on a result object from
|
||||||
|
a command that did not produce a result set, e.g.,
|
||||||
|
<command>UPDATE</command> without <literal>RETURNING</literal>, or
|
||||||
|
<command>DROP TABLE</command>. But it is OK to use these methods on
|
||||||
|
a result set containing zero rows.
|
||||||
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
</variablelist>
|
</variablelist>
|
||||||
|
@ -115,9 +115,9 @@ SELECT join_sequences(sequences) FROM sequences
|
|||||||
--
|
--
|
||||||
-- plan and result objects
|
-- plan and result objects
|
||||||
--
|
--
|
||||||
CREATE FUNCTION result_nrows_test() RETURNS int
|
CREATE FUNCTION result_metadata_test(cmd text) RETURNS int
|
||||||
AS $$
|
AS $$
|
||||||
plan = plpy.prepare("SELECT 1 AS foo, '11'::text AS bar UNION SELECT 2, '22'")
|
plan = plpy.prepare(cmd)
|
||||||
plpy.info(plan.status()) # not really documented or useful
|
plpy.info(plan.status()) # not really documented or useful
|
||||||
result = plpy.execute(plan)
|
result = plpy.execute(plan)
|
||||||
if result.status() > 0:
|
if result.status() > 0:
|
||||||
@ -128,20 +128,28 @@ if result.status() > 0:
|
|||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
$$ LANGUAGE plpythonu;
|
$$ LANGUAGE plpythonu;
|
||||||
SELECT result_nrows_test();
|
SELECT result_metadata_test($$SELECT 1 AS foo, '11'::text AS bar UNION SELECT 2, '22'$$);
|
||||||
INFO: True
|
INFO: True
|
||||||
CONTEXT: PL/Python function "result_nrows_test"
|
CONTEXT: PL/Python function "result_metadata_test"
|
||||||
INFO: ['foo', 'bar']
|
INFO: ['foo', 'bar']
|
||||||
CONTEXT: PL/Python function "result_nrows_test"
|
CONTEXT: PL/Python function "result_metadata_test"
|
||||||
INFO: [23, 25]
|
INFO: [23, 25]
|
||||||
CONTEXT: PL/Python function "result_nrows_test"
|
CONTEXT: PL/Python function "result_metadata_test"
|
||||||
INFO: [-1, -1]
|
INFO: [-1, -1]
|
||||||
CONTEXT: PL/Python function "result_nrows_test"
|
CONTEXT: PL/Python function "result_metadata_test"
|
||||||
result_nrows_test
|
result_metadata_test
|
||||||
-------------------
|
----------------------
|
||||||
2
|
2
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
|
SELECT result_metadata_test($$CREATE TEMPORARY TABLE foo1 (a int, b text)$$);
|
||||||
|
INFO: True
|
||||||
|
CONTEXT: PL/Python function "result_metadata_test"
|
||||||
|
ERROR: plpy.Error: command did not produce a result set
|
||||||
|
CONTEXT: Traceback (most recent call last):
|
||||||
|
PL/Python function "result_metadata_test", line 6, in <module>
|
||||||
|
plpy.info(result.colnames())
|
||||||
|
PL/Python function "result_metadata_test"
|
||||||
-- cursor objects
|
-- cursor objects
|
||||||
CREATE FUNCTION simple_cursor_test() RETURNS int AS $$
|
CREATE FUNCTION simple_cursor_test() RETURNS int AS $$
|
||||||
res = plpy.cursor("select fname, lname from users")
|
res = plpy.cursor("select fname, lname from users")
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include "plpython.h"
|
#include "plpython.h"
|
||||||
|
|
||||||
#include "plpy_resultobject.h"
|
#include "plpy_resultobject.h"
|
||||||
|
#include "plpy_elog.h"
|
||||||
|
|
||||||
|
|
||||||
static void PLy_result_dealloc(PyObject *arg);
|
static void PLy_result_dealloc(PyObject *arg);
|
||||||
@ -131,6 +132,12 @@ PLy_result_colnames(PyObject *self, PyObject *unused)
|
|||||||
PyObject *list;
|
PyObject *list;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
if (!ob->tupdesc)
|
||||||
|
{
|
||||||
|
PLy_exception_set(PLy_exc_error, "command did not produce a result set");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
list = PyList_New(ob->tupdesc->natts);
|
list = PyList_New(ob->tupdesc->natts);
|
||||||
for (i = 0; i < ob->tupdesc->natts; i++)
|
for (i = 0; i < ob->tupdesc->natts; i++)
|
||||||
PyList_SET_ITEM(list, i, PyString_FromString(NameStr(ob->tupdesc->attrs[i]->attname)));
|
PyList_SET_ITEM(list, i, PyString_FromString(NameStr(ob->tupdesc->attrs[i]->attname)));
|
||||||
@ -145,6 +152,12 @@ PLy_result_coltypes(PyObject *self, PyObject *unused)
|
|||||||
PyObject *list;
|
PyObject *list;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
if (!ob->tupdesc)
|
||||||
|
{
|
||||||
|
PLy_exception_set(PLy_exc_error, "command did not produce a result set");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
list = PyList_New(ob->tupdesc->natts);
|
list = PyList_New(ob->tupdesc->natts);
|
||||||
for (i = 0; i < ob->tupdesc->natts; i++)
|
for (i = 0; i < ob->tupdesc->natts; i++)
|
||||||
PyList_SET_ITEM(list, i, PyInt_FromLong(ob->tupdesc->attrs[i]->atttypid));
|
PyList_SET_ITEM(list, i, PyInt_FromLong(ob->tupdesc->attrs[i]->atttypid));
|
||||||
@ -159,6 +172,12 @@ PLy_result_coltypmods(PyObject *self, PyObject *unused)
|
|||||||
PyObject *list;
|
PyObject *list;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
if (!ob->tupdesc)
|
||||||
|
{
|
||||||
|
PLy_exception_set(PLy_exc_error, "command did not produce a result set");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
list = PyList_New(ob->tupdesc->natts);
|
list = PyList_New(ob->tupdesc->natts);
|
||||||
for (i = 0; i < ob->tupdesc->natts; i++)
|
for (i = 0; i < ob->tupdesc->natts; i++)
|
||||||
PyList_SET_ITEM(list, i, PyInt_FromLong(ob->tupdesc->attrs[i]->atttypmod));
|
PyList_SET_ITEM(list, i, PyInt_FromLong(ob->tupdesc->attrs[i]->atttypmod));
|
||||||
|
@ -93,9 +93,9 @@ SELECT join_sequences(sequences) FROM sequences
|
|||||||
-- plan and result objects
|
-- plan and result objects
|
||||||
--
|
--
|
||||||
|
|
||||||
CREATE FUNCTION result_nrows_test() RETURNS int
|
CREATE FUNCTION result_metadata_test(cmd text) RETURNS int
|
||||||
AS $$
|
AS $$
|
||||||
plan = plpy.prepare("SELECT 1 AS foo, '11'::text AS bar UNION SELECT 2, '22'")
|
plan = plpy.prepare(cmd)
|
||||||
plpy.info(plan.status()) # not really documented or useful
|
plpy.info(plan.status()) # not really documented or useful
|
||||||
result = plpy.execute(plan)
|
result = plpy.execute(plan)
|
||||||
if result.status() > 0:
|
if result.status() > 0:
|
||||||
@ -107,7 +107,8 @@ else:
|
|||||||
return None
|
return None
|
||||||
$$ LANGUAGE plpythonu;
|
$$ LANGUAGE plpythonu;
|
||||||
|
|
||||||
SELECT result_nrows_test();
|
SELECT result_metadata_test($$SELECT 1 AS foo, '11'::text AS bar UNION SELECT 2, '22'$$);
|
||||||
|
SELECT result_metadata_test($$CREATE TEMPORARY TABLE foo1 (a int, b text)$$);
|
||||||
|
|
||||||
|
|
||||||
-- cursor objects
|
-- cursor objects
|
||||||
|
Loading…
x
Reference in New Issue
Block a user