- changed status to resolved
UnicodeDecodeError is thrown instead of StatementError if the statement with non-ASCII symbols lacks parameter bind value
Environment: Ubuntu 12.04, python 2.7.3, SA 0.8.2, sys.getdefaultencoding() => 'ascii'
What we do:
run Session.execute
against SQL statement with a non-ASCII symbols that declares a bind parameter but has it not fullfilled.
What do we expect:
A StatementError
with text A value is required for bind parameter 'x'
is thrown
What do we observe:
A UnicodeDecodeError
is thrown instead.
Sample script:
# encoding: utf-8
from sqlalchemy.engine import create_engine
from sqlalchemy.orm.session import sessionmaker
def test_foo():
engine = create_engine('sqlite://')
engine.execute('create table test (value varchar(100))')
session = sessionmaker(bind=engine)()
session.execute(u"""
--- КИРИЛЛИЦА
insert into test values (:x)
""")
if __name__ == '__main__':
test_foo()
In the absence of --- КИРИЛЛИЦА
line this throws a proper StatementError
:
Traceback (most recent call last):
File "test_a.py", line 15, in <module>
test_foo()
File "test_a.py", line 12, in test_foo
""")
File "/usr/lib/python2.7/dist-packages/sqlalchemy/orm/session.py", line 934, in execute
clause, params or {})
File "/usr/lib/python2.7/dist-packages/sqlalchemy/engine/base.py", line 662, in execute
params)
File "/usr/lib/python2.7/dist-packages/sqlalchemy/engine/base.py", line 761, in _execute_clauseelement
compiled_sql, distilled_params
File "/usr/lib/python2.7/dist-packages/sqlalchemy/engine/base.py", line 828, in _execute_context
None, None)
File "/usr/lib/python2.7/dist-packages/sqlalchemy/engine/base.py", line 1024, in _handle_dbapi_exception
exc_info
File "/usr/lib/python2.7/dist-packages/sqlalchemy/util/compat.py", line 195, in raise_from_cause
reraise(type(exception), exception, tb=exc_tb)
File "/usr/lib/python2.7/dist-packages/sqlalchemy/engine/base.py", line 824, in _execute_context
context = constructor(dialect, self, conn, *args)
File "/usr/lib/python2.7/dist-packages/sqlalchemy/engine/default.py", line 438, in _init_compiled
grp, m in enumerate(parameters)]
File "/usr/lib/python2.7/dist-packages/sqlalchemy/sql/compiler.py", line 367, in construct_params
% bindparam.key)
sqlalchemy.exc.StatementError: A value is required for bind parameter u'x' (original cause: InvalidRequestError: A value is required for bind parameter u'x') '\n insert into test values (?)\n ' [{}]({})
But the actual error is:
Traceback (most recent call last):
File "test_a.py", line 16, in <module>
test_foo()
File "test_a.py", line 13, in test_foo
""")
File "/usr/lib/python2.7/dist-packages/sqlalchemy/orm/session.py", line 934, in execute
clause, params or {})
File "/usr/lib/python2.7/dist-packages/sqlalchemy/engine/base.py", line 662, in execute
params)
File "/usr/lib/python2.7/dist-packages/sqlalchemy/engine/base.py", line 761, in _execute_clauseelement
compiled_sql, distilled_params
File "/usr/lib/python2.7/dist-packages/sqlalchemy/engine/base.py", line 827, in _execute_context
str(statement), parameters,
UnicodeEncodeError: 'ascii' codec can't encode characters in position 9-17: ordinal not in range(128)
This is causes here: https://github.com/zzzeek/sqlalchemy/blob/master/lib/sqlalchemy/engine/base.py#L827
Strangely, but it is the only place where str(statement)
is called in preparation for self._handle_dbapi_exception
call. Looks like the str
part is superfluous.
Comments (2)
-
repo owner -
repo owner - removed milestone
Removing milestone: 0.8.xx (automated comment)
- Log in to comment
the code is unclear in this regard in that the variable name
statement
withinbase.py
is used to represent SQL statements in at least three forms; as a string, as aCompiled
object, and as aClauseElement
. In this case, the statement enters the method as aCompiled
construct, so in order for it to be part of theStatementException
object's message, we need to call its__str__()
or__unicode__()
method. After we get anExecutionContext
, the same namestatement
is re-assigned to the stringified SQL statement, so is then handled as a string. So the namestatement
throughoutengine/base.py
might be better if it were renamed to clarify its type.thanks for the test!
ad85ab12d62e65b0310c778057551bcdd460f0d9 0.8
f112dc1d533033f19186eb65227aba1660d03102 0.9