From 9ae868939a7e8b10f4a75537b79cd81e587f6840 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Wed, 22 Aug 2012 18:49:16 -0400 Subject: [PATCH] - [bug] Fixed cextension bug whereby the "ambiguous column error" would fail to function properly if the given index were a Column object and not a string. Note there are still some column-targeting issues here which are fixed in 0.8. [ticket:2553] --- CHANGES | 8 +++++++ lib/sqlalchemy/cextension/resultproxy.c | 23 +++++++++++++------- test/sql/test_query.py | 28 +++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 8 deletions(-) diff --git a/CHANGES b/CHANGES index cffdf2ac8f..87ef0446e5 100644 --- a/CHANGES +++ b/CHANGES @@ -87,6 +87,14 @@ CHANGES the absense of which was preventing the new GAE dialect from being loaded. [ticket:2529] + - [bug] Fixed cextension bug whereby the + "ambiguous column error" would fail to + function properly if the given index were + a Column object and not a string. + Note there are still some column-targeting + issues here which are fixed in 0.8. + [ticket:2553] + - [bug] Fixed the repr() of Enum to include the "name" and "native_enum" flags. Helps Alembic autogenerate. diff --git a/lib/sqlalchemy/cextension/resultproxy.c b/lib/sqlalchemy/cextension/resultproxy.c index 518209e54e..ca9d28e63a 100644 --- a/lib/sqlalchemy/cextension/resultproxy.c +++ b/lib/sqlalchemy/cextension/resultproxy.c @@ -13,8 +13,8 @@ typedef int Py_ssize_t; #define PY_SSIZE_T_MAX INT_MAX #define PY_SSIZE_T_MIN INT_MIN typedef Py_ssize_t (*lenfunc)(PyObject *); -#define PyInt_FromSsize_t(x) PyInt_FromLong(x) -typedef intargfunc ssizeargfunc; +#define PyInt_FromSsize_t(x) PyInt_FromLong(x) +typedef intargfunc ssizeargfunc; #endif @@ -243,12 +243,12 @@ BaseRowProxy_subscript(BaseRowProxy *self, PyObject *key) PyObject *processors, *values; PyObject *processor, *value, *processed_value; PyObject *row, *record, *result, *indexobject; - PyObject *exc_module, *exception; + PyObject *exc_module, *exception, *cstr_obj; char *cstr_key; long index; int key_fallback = 0; int tuple_check = 0; - + if (PyInt_CheckExact(key)) { index = PyInt_AS_LONG(key); } else if (PyLong_CheckExact(key)) { @@ -300,9 +300,16 @@ BaseRowProxy_subscript(BaseRowProxy *self, PyObject *key) if (exception == NULL) return NULL; - cstr_key = PyString_AsString(key); - if (cstr_key == NULL) + // wow. this seems quite excessive. + cstr_obj = PyObject_Str(key); + if (cstr_obj == NULL) + return NULL; + cstr_key = PyString_AsString(cstr_obj); + if (cstr_key == NULL) { + Py_DECREF(cstr_obj); return NULL; + } + Py_DECREF(cstr_obj); PyErr_Format(exception, "Ambiguous column name '%.200s' in result set! " @@ -328,7 +335,7 @@ BaseRowProxy_subscript(BaseRowProxy *self, PyObject *key) value = PySequence_GetItem(row, index); tuple_check = 0; } - + if (value == NULL) return NULL; @@ -368,7 +375,7 @@ BaseRowProxy_getattro(BaseRowProxy *self, PyObject *name) tmp = BaseRowProxy_subscript(self, name); if (tmp == NULL && PyErr_ExceptionMatches(PyExc_KeyError)) { PyErr_Format( - PyExc_AttributeError, + PyExc_AttributeError, "Could not locate column in row for column '%.200s'", PyString_AsString(name) ); diff --git a/test/sql/test_query.py b/test/sql/test_query.py index aba7288d26..f46ffd8123 100644 --- a/test/sql/test_query.py +++ b/test/sql/test_query.py @@ -954,6 +954,34 @@ class QueryTest(fixtures.TestBase): lambda: r['user_id'] ) + def test_ambiguous_column_by_col(self): + users.insert().execute(user_id=1, user_name='john') + ua = users.alias() + u2 = users.alias() + result = select([users.c.user_id, ua.c.user_id]).execute() + row = result.first() + + assert_raises_message( + exc.InvalidRequestError, + "Ambiguous column name", + lambda: row[users.c.user_id] + ) + + # this is a bug, should be ambiguous. + # Fixed in 0.8 + eq_(row[ua.c.user_id], 1) + + # this is also a less severe bug - u2.c.user_id + # is not in the row at all so is not actually + # ambiguous. Still is like this in 0.8 + # and is due to overly liberal "this is a derived column" + # rules. + assert_raises_message( + exc.InvalidRequestError, + "Ambiguous column name", + lambda: row[u2.c.user_id] + ) + @testing.requires.subqueries def test_column_label_targeting(self): users.insert().execute(user_id=7, user_name='ed') -- 2.47.2