views:

38

answers:

4

I'm having a hard time getting some sql in python to correctly go through MySQLdb. It's pythons string formatting that is killing me.

My sql statement is using the LIKE keyword with wildcards. I've tried a number of different things in Python. The problem is once I get one of them working, there's a line of code in MySQLdb that burps on string format.

Attempt 1: "SELECT tag.userId, count(user.id) as totalRows FROM user INNER JOIN tag ON user.id = tag.userId WHERE user.username LIKE '%%s%'" % (query)

This is a no go. I get value error: ValueError: unsupported format character ''' (0x27) at index 128

Attempt 2: "SELECT tag.userId, count(user.id) as totalRows FROM user INNER JOIN tag ON user.id = tag.userId WHERE user.username LIKE '\%%s\%'" % (query)

I get the same result from attempt 1.

Attempt 3: like = "LIKE '%" + str(query) + "%'" totalq = "SELECT tag.userId, count(user.id) as totalRows FROM user INNER JOIN tag ON user.id = tag.userId WHERE user.username " + like

This correctly creates the totalq variable, but now when I go to run the query I get errors from MySQLdb:

File "build/bdist.macosx-10.6-universal/egg/MySQLdb/cursors.py", line 158, in execute query = query % db.literal(args) TypeError: not enough arguments for format string

Attempt 4: like = "LIKE '\%" + str(query) + "\%'" totalq = "SELECT tag.userId, count(user.id) as totalRows FROM user INNER JOIN tag ON user.id = tag.userId WHERE user.username " + like

This is the same output as attempt 3.

This all seems really strange. How can I use wildcards in sql statements with python?

+1  A: 

Which library are you using to manage your database connection? You don't want to be trying to construct Queries as Strings - this leaves your application susceptible to SQL Injection. Instead, there should be a method that will allow you to prepare / execute statements with variables. In kinterbasdb (the library for Firebird) that's the execute method. Something like this:

qry = "Select Field1, Field2, Field3 From Table1 Where Field1 like ?"

searchParm = '%' + variable + '%'

# con is a connection object.

cursor = con.cursor()

cursor.execute(qry, (searchParm,))
g.d.d.c
Good answer. Minor point: OP does mention using MySQLdb in the question. In which case the parameter placeholder would be `%s` instead of `?`.
Adam Bernier
I'm using Tornado's database wrapper class which wraps MySQLdb with some convenience methods. With your suggestion, I've tried this:totalq = "SELECT tag.userId, count(user.id) as totalRows FROM user INNER JOIN tag ON user.id = tag.userId WHERE user.username LIKE ?"; row = self.db.get(totalq,(like,));I end up getting another error: TypeError: not all arguments converted during string formatting
bl4th3rsk1t3
ignore the above comment. posted before I saw the others..
bl4th3rsk1t3
A: 

To escape ampersands in Python string formatting expressions, double the ampersand:

'%%%s%%' % search_string

Edit: But I definitely agree with another answer. Direct string substitution in SQL queries is almost always a bad idea.

jrdioko
+3  A: 

Those queries all appear to be vulnerable to SQL injection attacks.

Try something like this instead:

curs.execute("""SELECT tag.userId, count(user.id) as totalRows 
                  FROM user 
            INNER JOIN tag ON user.id = tag.userId 
                 WHERE user.username LIKE %s""", ('%' + query + '%',))

Where there are two arguments being passed to execute().

Adam Bernier
That also looks vulnerable to SQL injection. Using parameterized queries through whatever library is used to connect to the database is the way to go.
jrdioko
@jrdioko: thanks for your comment. Note that there is no actual string interpolation, and that the query *is* prepared by the `execute()` method.
Adam Bernier
I take that back, it appears that syntax is how the library in question does parameterized queries.
jrdioko
+3  A: 

It's not about string formatting but the problem is how queries should be executed according to db operations requirements in Python (PEP 249)

try something like this:

sql = "SELECT column FROM table WHERE col1=%s AND col2=%s" 
params = (col1_value, col2_value)
cursor.execute(sql, params)

here are some examples for psycog2 where you have some explanations that should also be valid for mysql (mysqldb also follows PEP249 dba api guidance 2.0: here are examples for mysqldb)

Lukasz Dziedzia
Thanks. that did it. For some reason I thought MySQL db would figure out how to escape parameters even inside of the sql statement. But now it makes sense to throw parameters in like this.
bl4th3rsk1t3
Glad it helped you! I spent a lot of time until I figured that some time ago:)
Lukasz Dziedzia