diff -ru oursql-0.9.3.1 2/oursqlx/cursor.pyx oursql-0.9.3.1/oursqlx/cursor.pyx --- oursql-0.9.3.1 2/oursqlx/cursor.pyx 2012-06-05 12:33:34.000000000 -0400 +++ oursql-0.9.3.1/oursqlx/cursor.pyx 2012-12-24 15:39:28.000000000 -0500 @@ -22,20 +22,24 @@ string will be streamed as necessary instead of fetched all at once. Note: plain queries buffer incoming result differently, and are therefore unaffected by the string_limit. + + - prepared_statement_cache_size = True: Cursor instances yield tuples to represent rows. """ cdef readonly object _statements, _stmt_kwargs cdef Connection conn - cdef int closed, try_plain_query + cdef int closed, try_plain_query, statement_cache_size, + cdef object statement_cache cdef readonly object rowcount, lastrowid, description, messages cdef public unsigned long arraysize _statement_class = _Statement _query_class = _Query - def __cinit__(self, Connection conn not None, bint try_plain_query=True, + def __cinit__(self, Connection conn not None, bint try_plain_query=True, + bint statement_cache_size=0, **kwargs): self.conn = conn self._stmt_kwargs = kwargs @@ -45,6 +49,9 @@ self.rowcount = -1 self.arraysize = 1 self.try_plain_query = try_plain_query + self.statement_cache_size=statement_cache_size + if statement_cache_size: + self.statement_cache = collections.OrderedDict() cdef int _check_closed(self) except -1: if not self.conn.conn: @@ -106,20 +113,34 @@ "parameters and a plain query") stmt = self._new_query(query) else: - stmt = self._new_statement() - try: - stmt.prepare(query) - except Error, e: - # So, if MySQL refuses to parameterize the query, we optionally - # try it again through the stupid query API. This is optional - # because you can lose state data if this is always done - # implicitly. - if self.try_plain_query and e.errno == ER_UNSUPPORTED_PS: - return self.execute(query, params, plain_query=True) - else: - raise - else: + if self.statement_cache_size and query in self.statement_cache: + stmt = self.statement_cache[query] + self._statements = collections.deque() + stmt.reset() + # Using an Ordered Dict as an LRU cache - need to reset position in the cache + self.statement_cache[query] = stmt + if len(self.statement_cache) > self.statement_cache_size: + self.statement_cache.popitem(last=False) stmt.execute(*params) + else: + stmt = self._new_statement() + try: + stmt.prepare(query) + except Error, e: + # So, if MySQL refuses to parameterize the query, we optionally + # try it again through the stupid query API. This is optional + # because you can lose state data if this is always done + # implicitly. + if self.try_plain_query and e.errno == ER_UNSUPPORTED_PS: + return self.execute(query, params, plain_query=True) + else: + raise + else: + if self.statement_cache_size: + self.statement_cache[query] = stmt + if len(self.statement_cache) > self.statement_cache_size: + self.statement_cache.popitem(last=False) + stmt.execute(*params) self._update_fields(stmt) def executemany(self, query, parambatch): diff -ru oursql-0.9.3.1 2/oursqlx/oursql.pxi oursql-0.9.3.1/oursqlx/oursql.pxi --- oursql-0.9.3.1 2/oursqlx/oursql.pxi 2012-06-05 12:33:34.000000000 -0400 +++ oursql-0.9.3.1/oursqlx/oursql.pxi 2012-12-24 15:30:10.000000000 -0500 @@ -229,6 +229,7 @@ MYSQL_BIND *bind, unsigned int column, unsigned long offset) int _mysql_stmt_store_result "mysql_stmt_store_result" (MYSQL_STMT *) my_bool mysql_stmt_free_result(MYSQL_STMT *) + my_bool mysql_stmt_reset(MYSQL_STMT *) void mysql_stmt_close(MYSQL_STMT *) MYSQL_RES *mysql_stmt_result_metadata(MYSQL_STMT *) diff -ru oursql-0.9.3.1 2/oursqlx/statement.pyx oursql-0.9.3.1/oursqlx/statement.pyx --- oursql-0.9.3.1 2/oursqlx/statement.pyx 2012-06-05 12:33:34.000000000 -0400 +++ oursql-0.9.3.1/oursqlx/statement.pyx 2012-12-24 16:12:22.000000000 -0500 @@ -409,6 +409,14 @@ self.warnings.extend(_do_warnings_query(self.conn)) finally: PyMem_Free(buf) + + def reset(self): + """Free the result set without releasing the prepared query""" + #if mysql_stmt_reset(self.stmt): + if mysql_stmt_free_result(self.stmt): + self._raise_error() + self.buffered = self.data_waiting = False + self.exhausted = True def fetchone(self): cdef MYSQL_BIND b_tryagain