From 3ee30ecc710057f7eb939431bc2ee0322e902025 Mon Sep 17 00:00:00 2001 From: Vilnis Termanis Date: Tue, 25 Jul 2017 11:36:11 +0100 Subject: [PATCH] Make MySQLCursor.callproc & stored_results more consistent - Choose matching (buffered) cursor for populating stored_results (e.g. so get dict result if using dict cursor) - Always return simple sequence of arguments from callproc, even if cursor if of type dict or namedtuple --- lib/mysql/connector/cursor.py | 31 ++++++++++++++++++++++++------- lib/mysql/connector/cursor_cext.py | 35 +++++++++++++++++++++++++++-------- 2 files changed, 51 insertions(+), 15 deletions(-) diff --git a/lib/mysql/connector/cursor.py b/lib/mysql/connector/cursor.py index 3002192..80a8b60 100644 --- a/lib/mysql/connector/cursor.py +++ b/lib/mysql/connector/cursor.py @@ -754,14 +754,10 @@ def callproc(self, procname, args=()): # We disable consuming results temporary to make sure we # getting all results can_consume_results = self._connection._consume_results + tmp_cursor_type = self.__get_buffered_cursor_type() for result in self._connection.cmd_query_iter(call): self._connection._consume_results = False - # pylint: disable=R0204 - if self._raw: - tmp = MySQLCursorBufferedRaw(self._connection._get_self()) - else: - tmp = MySQLCursorBuffered(self._connection._get_self()) - # pylint: enable=R0204 + tmp = tmp_cursor_type(self._connection._get_self()) tmp._executed = "(a result of {0})".format(call) tmp._handle_result(result) if tmp._warnings is not None: @@ -775,7 +771,12 @@ def callproc(self, procname, args=()): select = "SELECT {0}".format(','.join(argtypes)) self.execute(select) self._stored_results = results - return self.fetchone() + retargs = self.fetchone() + # Always return arguments as simple sequence + if isinstance(retargs, dict): + retargs = tuple(retargs[argname] for argname in argnames) + # Also catches namedtuple instances (otherwise will be noop) + return tuple(retargs) else: self._stored_results = results return () @@ -786,6 +787,22 @@ def callproc(self, procname, args=()): raise errors.InterfaceError( "Failed calling stored routine; {0}".format(err)) + def __get_buffered_cursor_type(self): + """Returns cursor type for this cursor or buffered equivalent if unbuffered. + """ + # pylint: disable=R0204 + if isinstance(self, MySQLCursorBuffered): + cursor = type(self) + elif isinstance(self, MySQLCursorRaw): + cursor = MySQLCursorBufferedRaw + elif isinstance(self, MySQLCursorDict): + cursor = MySQLCursorBufferedDict + elif isinstance(self, MySQLCursorNamedTuple): + cursor = MySQLCursorBufferedNamedTuple + else: + cursor = MySQLCursorBuffered + return cursor + def getlastrowid(self): """Returns the value generated for an AUTO_INCREMENT column diff --git a/lib/mysql/connector/cursor_cext.py b/lib/mysql/connector/cursor_cext.py index df5fed3..1522d97 100644 --- a/lib/mysql/connector/cursor_cext.py +++ b/lib/mysql/connector/cursor_cext.py @@ -431,16 +431,14 @@ def callproc(self, procname, args=()): raw_as_string=self._raw_as_string) results = [] + tmp_cursor_type = self.__get_buffered_cursor_type() while self._cnx.result_set_available: result = self._cnx.fetch_eof_columns() - # pylint: disable=W0212,R0204 - if self._raw: - cur = CMySQLCursorBufferedRaw(self._cnx._get_self()) - else: - cur = CMySQLCursorBuffered(self._cnx._get_self()) + # pylint: disable=W0212 + cur = tmp_cursor_type(self._cnx._get_self()) cur._executed = "(a result of {0})".format(call) cur._handle_result(result) - # pylint: enable=W0212,R0204 + # pylint: enable=W0212 results.append(cur) self._cnx.next_result() self._stored_results = results @@ -450,8 +448,13 @@ def callproc(self, procname, args=()): self.reset() select = "SELECT {0}".format(','.join(argtypes)) self.execute(select) - - return self.fetchone() + retargs = self.fetchone() + # Always return arguments as simple sequence + if isinstance(retargs, dict): + # Returned dictinary keys bytes, not str + retargs = tuple(retargs[argname.encode('utf-8')] for argname in argnames) + # Also catches namedtuple instances (otherwise will be noop) + return tuple(retargs) else: return tuple() @@ -461,6 +464,22 @@ def callproc(self, procname, args=()): raise errors.InterfaceError( "Failed calling stored routine; {0}".format(err)) + def __get_buffered_cursor_type(self): + """Returns cursor type for this cursor or buffered equivalent if unbuffered. + """ + # pylint: disable=R0204 + if isinstance(self, CMySQLCursorBuffered): + cursor = type(self) + elif isinstance(self, CMySQLCursorRaw): + cursor = CMySQLCursorBufferedRaw + elif isinstance(self, CMySQLCursorDict): + cursor = CMySQLCursorBufferedDict + elif isinstance(self, CMySQLCursorNamedTuple): + cursor = CMySQLCursorBufferedNamedTuple + else: + cursor = CMySQLCursorBuffered + return cursor + def nextset(self): """Skip to the next available result set""" if not self._cnx.next_result():