Edgewall Software
Modify

Opened 15 years ago

Closed 15 years ago

Last modified 9 years ago

#8740 closed defect (fixed)

Encode strings into database encoding before cursor.execute()

Reported by: xiled@… Owned by: Christian Boos
Priority: high Milestone: 0.12
Component: database backend Version: 0.12dev
Severity: major Keywords: psycopg2, mysqldb, unicode, postgresql
Cc: Branch:
Release Notes:
API Changes:
Internal Changes:

Description (last modified by Christian Boos)

In trac/db/utils.py in def execute(self, sql, args=None):

it should be something like:

if args:
  encoded_args = []
  for a in args:
    try:
        encoded_args.append( a.encode("db_coding") ) # utf8 in my case
    except:
         encoded_args.append( a )
     return cursor.execute(..., encoded_args)

Note: I know that try/except is ugly here but type checking type(a) == types.UnicdeType did not worked for me. Somehow u"" passed through.

Otherwise if strings is not encoded.. i get error from psycopg2 .. when ticket resolution is in russian.

2009-10-14 17:36:17,215 pid: 31501, ERROR sql_escape_percent(sql) : INSERT INTO ticket_change (ticket,time,author,field,oldvalue,newvalue) VALUES (%s, %s, %s, %s, %s, %s) => [3, 1255520177, u'admin', 'resolution', u'', u'\u043d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0440\u0435\u0448\u0438\u0442\u044c']
2009-10-14 17:36:17,218 pid: 31501, ERROR Internal Server Error:
Traceback (most recent call last):
  File "/usr/lib/python2.5/site-packages/Trac-0.12dev_r8661-py2.5.egg/trac/web/main.py", line 467, in _dispatch_request
    dispatcher.dispatch(req)
  File "/usr/lib/python2.5/site-packages/Trac-0.12dev_r8661-py2.5.egg/trac/web/main.py", line 212, in dispatch
    resp = chosen_handler.process_request(req)
  File "/usr/lib/python2.5/site-packages/Trac-0.12dev_r8661-py2.5.egg/trac/ticket/web_ui.py", line 188, in process_request
    return self._process_ticket_request(req)
  File "/usr/lib/python2.5/site-packages/Trac-0.12dev_r8661-py2.5.egg/trac/ticket/web_ui.py", line 541, in _process_ticket_request
    self._do_save(req, ticket, action)
  File "/usr/lib/python2.5/site-packages/Trac-0.12dev_r8661-py2.5.egg/trac/ticket/web_ui.py", line 1196, in _do_save
    cnum=internal_cnum):
  File "/usr/lib/python2.5/site-packages/Trac-0.12dev_r8661-py2.5.egg/trac/ticket/model.py", line 301, in save_changes
    self[name]))
  File "/usr/lib/python2.5/site-packages/Trac-0.12dev_r8661-py2.5.egg/trac/db/util.py", line 75, in execute
    return self.cursor.execute(sql_escape_percent(sql), new_args)
  File "/usr/lib/python2.5/site-packages/Trac-0.12dev_r8661-py2.5.egg/trac/db/util.py", line 75, in execute
    return self.cursor.execute(sql_escape_percent(sql), new_args)
ProgrammingError: can't adapt

I dont know if it is psycopg2 bug.. but i think encoding strings before execute is good.

Attachments (1)

t8740-psycopg2-adapters (1.6 KB ) - added by Christian Boos 15 years ago.
In postgres_backend, register_adapter for Markup and Empty unicode subclasses (follows-up and applies on r8661)

Download all attachments as: .zip

Change History (11)

comment:1 by Christian Boos, 15 years ago

Description: modified (diff)
Keywords: unicode added; encoding removed
Priority: lownormal

comment:2 by Remy Blank, 15 years ago

Isn't that done automatically by psycopg2 when a unicode string is passed?

comment:3 by Christian Boos, 15 years ago

Milestone: 0.12
Priority: normalhigh
Severity: normalmajor

You were trying to change the resolution to "невозможно решить", this should just work.

It works for me when using SQLite database, and I also just tested with a PostgreSQL backend and I could indeed reproduce the issue.

System used for the test:

Trac:	0.12dev-r8656
Python:	2.6.1 (r261:67517, Dec 4 2008, 16:51:00) [MSC v.1500 32 bit (Intel)]
setuptools:	0.7a1
psycopg2:	2.0.8
Genshi:	0.6dev-r1071
Babel:	0.9.4
Pygments:	1.0dev-20090211
Subversion:	1.6.2 (r37639)
jQuery:	1.3.2

comment:4 by Christian Boos, 15 years ago

Keywords: postgres psycopg2 added; database removed

Weird. Same system but different version (latest 0.11-stable), it worked. Switched back to 0.12dev again: now it works!

Need to find more details about this "can't adapt" error.

comment:5 by Christian Boos, 15 years ago

Interesting, there's a duplicate here with this comment: ticket:3501#comment:4

comment:6 by Christian Boos, 15 years ago

When it works, I'm able to see such output in the log with [trac] debug_sql = true:

3:23:16 PM Trac[util] DEBUG: SQL: 'UPDATE ticket SET resolution=%s WHERE id=%s'
3:23:16 PM Trac[util] DEBUG: args: (u'\u043d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0440\u0435\u0448\u0438\u0442\u044c', 1)

But if I force unicode instances to actually be Markup instances, I systematically get the "can't adapt" error. Note that I get the same result if I force the empty sentinel value in.

So I guess we need extra adapters for those types, as the comment linked above suggested.

I'm not yet sure about the specific circumstances that make us get a Markup instance there in some cases and not in other, and in particular if this sequence is 0.12 specific, need further investigations for that.

comment:7 by Christian Boos, 15 years ago

Owner: set to Christian Boos
Status: newassigned

Well, of course it's obviously 0.12 specific, as we're running 0.11-stable on psycopg2 here on t.e.o ;-)

And we actually don't try to store a Markup string but the shiny new empty value (r8661). This happens after the first "close", for the oldvalue field of the resolution value in the ticket_change table.

Patch follows.

by Christian Boos, 15 years ago

Attachment: t8740-psycopg2-adapters added

In postgres_backend, register_adapter for Markup and Empty unicode subclasses (follows-up and applies on r8661)

comment:8 by Christian Boos, 15 years ago

The MySQL binding, like the SQLite one, is also immune to the problem.

comment:9 by Christian Boos, 15 years ago

Keywords: mysqldb added
Resolution: fixed
Status: assignedclosed
Summary: Encode strings into database encoding before corsor.execute()Encode strings into database encoding before cursor.execute()

Patch applied, and unit tests added, in r8669.

Interestingly the unit tests helped to discover a similar issue with the MySQL bindings. There, unicode subclasses were treated as str, so it worked for the empty value (as str(u'') is fine) and also worked for Markup instances which contained only 'ascii' characters (that's why I thought it was OK in comment:8), but not on the more general case with non-ASCII characters.

comment:10 by Ryan J Ollos, 9 years ago

Keywords: postgresql added; postgres removed

Modify Ticket

Change Properties
Set your email in Preferences
Action
as closed The owner will remain Christian Boos.
The resolution will be deleted. Next status will be 'reopened'.
to The owner will be changed from Christian Boos to the specified user.

Add Comment


E-mail address and name can be saved in the Preferences .
 
Note: See TracTickets for help on using tickets.