Skip to content

Python 3 unicode problem in CursorWrapper.format_sql. #47

@ghost

Description

Hello,

I have been trying to get django-pyodbc working to connect to a SQL Server 2000 MSDE instance. I am using Django 1.6.1, Python 3.3 on Ubuntu 12.04.

Trying to do a simple operation such as

from django.db import connections
cursor = connections['default'].cursor()
result = cursor.execute('select * from customer')

causes the following to happen

File "/.../python3.3/dist-packages/django_pyodbc/base.py", line 410, in execute
    return self.cursor.execute(sql, params)
TypeError: The first argument to execute must be a string or unicode query.

Someone else experienced the same problem except they were running on Windows. They asked a question on StackOverflow here:

http://stackoverflow.com/questions/21272895/cant-query-sql-server-from-django-using-django-pyodbc

I tracked the problem down to line 367 in base.py:

            sql = sql.encode('utf-8')
    def format_sql(self, sql, n_params=None):
        if not self.driver_supports_utf8 and isinstance(sql, text_type):
            # Older FreeTDS (and other ODBC drivers?) don't support Unicode yet, so
            # we need to encode the SQL clause itself in utf-8
            sql = sql.encode('utf-8')

It seems that in Python 3, str.encode returns a bytes which is not a string type causing the TypeError to occur.

See this comment on StackOverflow for information on how the string/bytes changed from Python 2 to 3.

http://stackoverflow.com/a/11596746/1040695

This only seems to occur for the first query getting the product version. I need to do more analysis to see if happens later on.

  File "/.../python3.3/dist-packages/django/db/backends/__init__.py", line 159, in cursor
    cursor = util.CursorWrapper(self._cursor(), self)
  File "/.../python3.3/dist-packages/django_pyodbc/base.py", line 290, in _cursor
    if self.ops.sql_server_ver < 2005:
  File "/.../python3.3/dist-packages/django_pyodbc/operations.py", line 31, in _get_sql_server_ver
    cur.execute("SELECT CAST(SERVERPROPERTY('ProductVersion') as varchar)")
  File "/.../python3.3/dist-packages/django/db/backends/util.py", line 51, in execute
    return self.cursor.execute(sql)
  File "/.../python3.3/dist-packages/django_pyodbc/base.py", line 410, in execute
    return self.cursor.execute(sql, params)
TypeError: The first argument to execute must be a string or unicode query.

Anyway, my quick fix was to comment out lines 364-367 in base.py.

Alternatively, the bytes could be converted back to a string by changing line 367 to

sql = sql.encode('utf-8').decode('utf-8')

I hope this helps someone workaround this bug. I don't know enough about django-pyodbc to be able to fix this properly.

Michael.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions