From 5448f6129cd0487c3d06324385cc2ef0701b5815 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Sat, 10 Mar 2012 16:18:52 -0800 Subject: [PATCH] - [bug] Fixed memory leak in core which would occur when C extensions were used with particular types of result fetches, in particular when orm query.count() were called. [ticket:2427] --- CHANGES | 6 ++++++ lib/sqlalchemy/cextension/resultproxy.c | 6 ++++++ test/aaa_profiling/test_memusage.py | 16 ++++++++++++++++ 3 files changed, 28 insertions(+) diff --git a/CHANGES b/CHANGES index c98b80f569..cc5f663484 100644 --- a/CHANGES +++ b/CHANGES @@ -69,6 +69,12 @@ CHANGES on the method object. [ticket:2352] - sql + - [bug] Fixed memory leak in core which would + occur when C extensions were used with + particular types of result fetches, + in particular when orm query.count() + were called. [ticket:2427] + - [feature] Added support for SQL standard common table expressions (CTE), allowing SELECT objects as the CTE source (DML diff --git a/lib/sqlalchemy/cextension/resultproxy.c b/lib/sqlalchemy/cextension/resultproxy.c index 64b6855faa..325007c117 100644 --- a/lib/sqlalchemy/cextension/resultproxy.c +++ b/lib/sqlalchemy/cextension/resultproxy.c @@ -246,6 +246,7 @@ BaseRowProxy_subscript(BaseRowProxy *self, PyObject *key) PyObject *exc_module, *exception; char *cstr_key; long index; + int key_fallback = 0; if (PyInt_CheckExact(key)) { index = PyInt_AS_LONG(key); @@ -276,12 +277,17 @@ BaseRowProxy_subscript(BaseRowProxy *self, PyObject *key) "O", key); if (record == NULL) return NULL; + key_fallback = 1; } indexobject = PyTuple_GetItem(record, 2); if (indexobject == NULL) return NULL; + if (key_fallback) { + Py_DECREF(record); + } + if (indexobject == Py_None) { exc_module = PyImport_ImportModule("sqlalchemy.exc"); if (exc_module == NULL) diff --git a/test/aaa_profiling/test_memusage.py b/test/aaa_profiling/test_memusage.py index 579555c3f6..cffe8b71f7 100644 --- a/test/aaa_profiling/test_memusage.py +++ b/test/aaa_profiling/test_memusage.py @@ -496,6 +496,22 @@ class MemUsageTest(EnsureZeroed): metadata.drop_all() assert_no_mappers() + @testing.fails_if(lambda : testing.db.dialect.name == 'sqlite' \ + and testing.db.dialect.dbapi.version > '2.5') + @testing.provide_metadata + def test_key_fallback_result(self): + e = testing.db + m = self.metadata + t = Table('t', m, Column('x', Integer), Column('y', Integer)) + m.create_all(e) + e.execute(t.insert(), {"x":1, "y":1}) + @profile_memory + def go(): + r = e.execute(t.alias().select()) + for row in r: + row[t.c.x] + go() + # fails on newer versions of pysqlite due to unusual memory behvior # in pysqlite itself. background at: # http://thread.gmane.org/gmane.comp.python.db.pysqlite.user/2290 -- 2.47.2