Cannot return results from stored procedure using Python cursor
Have you tried picking one of the resultsets?
for result in cursor.stored_results():
people = result.fetchall()
It could be that it's allocating for multiple resultsets even though you only have one SELECT
stmt. I know in PHP's MySQLi stored procedures do this to allow for INOUT and OUT variable returns (which again, you have none of, but maybe it's allocating anyways).
The complete code I'm using (which is working) is:
import mysql.connector
cnx = mysql.connector.connect(user='me',password='pw',host='localhost',database='mydb')
cnx._open_connection()
cursor = cnx.cursor()
cursor.callproc("getperson",[1])
for result in cursor.stored_results():
people=result.fetchall()
for person in people:
print person
cnx.close()
Getting the result of a stored procedure after calling cursor.callproc
depends on these factors:
- whether the result of calling the procedure is assigned to an INOUT or OUT parameter
- whether the result consists of a single row or a result set (or result sets)
- the python package used to make the call
The DBAPI spec has this to say on cursor.callproc
:
Call a stored database procedure with the given name. The sequence of parameters must contain one entry for each argument that the procedure expects. The result of the call is returned as modified copy of the input sequence. Input parameters are left untouched, output and input/output parameters replaced with possibly new values.
The procedure may also provide a result set as output. This must then be made available through the standard .fetch*() methods.
In practice, using the return value of cursor.callproc
can only work if the procedure returns a single row, with the number of columns matching the number of INOUT and OUT parameters, so there is some variation in how the results are handled.
Here is how these cases are handled by the principal MySQL Python connector packages - MySQL Connector, mysqlclient (MySQLdb) and PyMySQL.
Single row result, returned via INOUT or OUT parameters
MySQL Connector returns a modified copy of the input sequence as the return value of
cursor.callproc
; the value is a tuple.params = [in_param, out_param1, out_param2] in_, out1, out2 = cursor.callproc("test_proc", params)
mysqlclient and PyMySQL require that the database is queried for the output parameters, and the results then fetched via the cursor; the value is a tuple of tuples. The parameter names to be queried are of the form
'@_{procedure_name}_{params.index(param)}'
cursor.callproc("test_proc", params) cursor.execute("""SELECT @_test_proc_0, @_test_proc_1""") result = cursor.fetchall()
One or more rows in a single result set, no INOUT or OUT parameters defined
MySQL Connector exposes the result via the cursor's stored_results method (
cursor.stored_results
is not part of the DBAPI spec)cursor.callproc("test_proc", params) results = [r.fetchall() for r in cursor.stored_results()]
mysqlclient and PyMySQL expose the result via the cursor's fetch* methods
cursor.callproc("test_proc", params) results = cursor.fetchall()
Multiple result sets, no INOUT or OUT parameters defined
MySQL Connector exposes the result via the cursor's
stored_results
methodcursor.callproc("test_proc", params) results = [r.fetchall() for r in cursor.stored_results()]
mysqlclient and PyMySQL require that each result set be fetched via the cursor, while calling cursor.nextset to advance to the next result set. Note that an extra, empty result set may be returned, a result of calling the procedure (this would also happen in the previous examples, if the result set were retrieved via
cursor.nextset
instead of only callingcursor.fetchall
once).cursor.callproc("test_proc", params) results = [cursor.fetchall()] while cursor.nextset(): results.append(cursor.fetchall())
Version Info
$ mysql --version
mysql Ver 15.1 Distrib 10.1.41-MariaDB, for debian-linux-gnu (x86_64) using readline 5.2
$ pip list | grep -i mysql
mysql-connector-python 8.0.18
mysqlclient 1.4.6
PyMySQL 0.9.3