Problem with MySQL cursor

F

Florian Lindner

Hello,
I have a function that executes a SQL statement with MySQLdb:

def executeSQL(sql, *args):
print sql % args
cursor = conn.cursor()
cursor.execute(sql, args)
cursor.close()

it's called like that:

sql = "INSERT INTO %s (%s) VALUES (%s)"
executeSQL(sql, DOMAIN_TABLE, DOMAIN_FIELD, domainname)

The statement that is printed looks ok (missing quotes, but AFAIK
cursor.execute does that):

INSERT INTO domains (domain) VALUES (xgm.de)

but MySQL prints an error:

Traceback (most recent call last):
File "manage.py", line 90, in ?
addDomain(domainName)
File "manage.py", line 27, in addDomain
executeSQL(sql, DOMAIN_TABLE, DOMAIN_FIELD, domainname)
File "manage.py", line 22, in executeSQL
cursor.execute(sql, args)
File "/usr/lib/python2.4/site-packages/MySQLdb/cursors.py", line 163, in
execute
self.errorhandler(self, exc, value)
File "/usr/lib/python2.4/site-packages/MySQLdb/connections.py", line 35,
in defaulterrorhandler
raise errorclass, errorvalue
_mysql_exceptions.ProgrammingError: (1064, "You have an error in your SQL
syntax; check the manual that corresponds to your MySQL server version for
the right syntax to use near ''domains' ('domain') VALUES ('xgm.de')' at
line 1")

I see the error: 2 opening quotes but only 1 closing around domains. But
where do they come from?

Note that there are no quotes at print sql % args.

Thanks,

Florian
 
J

J. Clifford Dyer

Traceback (most recent call last):
File "manage.py", line 90, in ?
addDomain(domainName)
File "manage.py", line 27, in addDomain
executeSQL(sql, DOMAIN_TABLE, DOMAIN_FIELD, domainname)
File "manage.py", line 22, in executeSQL
cursor.execute(sql, args)
File "/usr/lib/python2.4/site-packages/MySQLdb/cursors.py", line 163, in
execute
self.errorhandler(self, exc, value)
File "/usr/lib/python2.4/site-packages/MySQLdb/connections.py", line 35,
in defaulterrorhandler
raise errorclass, errorvalue
_mysql_exceptions.ProgrammingError: (1064, "You have an error in your SQL
syntax; check the manual that corresponds to your MySQL server version for
the right syntax to use near ''domains' ('domain') VALUES ('xgm.de')' at
line 1")

I see the error: 2 opening quotes but only 1 closing around domains. But
where do they come from?

Note that there are no quotes at print sql % args.

No, there are no double quote issues. The first quote is provided by the error message, and is paired with the quote after the closed parenthesis in ('xgm.de')'. It is not part of your SQL.

Cheers,
Cliff
 
C

Carsten Haese

Hello,
I have a function that executes a SQL statement with MySQLdb:

def executeSQL(sql, *args):
print sql % args
cursor = conn.cursor()
cursor.execute(sql, args)
cursor.close()

it's called like that:

sql = "INSERT INTO %s (%s) VALUES (%s)"
executeSQL(sql, DOMAIN_TABLE, DOMAIN_FIELD, domainname)

You can't use parameter binding to substitute table names and column
names, or any other syntax element, into a query. You can only bind
parameters in places where a literal value would be allowed (more or
less, the real rules are more complicated, but this rule of thumb gets
you close enough). You have to construct the query string like this, for
example:

sql = "INSERT INTO "+DOMAIN_TABLE+"("+DOMAIN_FIELD+") VALUES (%s)"
executeSQL(sql, domainname)

HTH,
 
F

Florian Lindner

Carsten said:
You can't use parameter binding to substitute table names and column
names, or any other syntax element, into a query. You can only bind
parameters in places where a literal value would be allowed (more or
less, the real rules are more complicated, but this rule of thumb gets
you close enough). You have to construct the query string like this, for
example:

sql = "INSERT INTO "+DOMAIN_TABLE+"("+DOMAIN_FIELD+") VALUES (%s)"
executeSQL(sql, domainname)

Ok, I understand it and now it works, but why is limitation? Why can't I
just the string interpolation in any playes and the cursor function escapes
any strings so that they can't do harm to my query?

Regards,

Florian
 
D

Diez B. Roggisch

Florian said:
Ok, I understand it and now it works, but why is limitation? Why can't I
just the string interpolation in any playes and the cursor function
escapes any strings so that they can't do harm to my query?

Because the function doesn't know that you wanted

select * from user where email = 'foo@bar'

instead of

select * from user where email = 'foo'; drop table user where '' = ''

And of course you don't gain anything from using USER INPUT in the
string-interpolation for creating the sql statement!!!

Diez
 
C

Carsten Haese

Ok, I understand it and now it works, but why is limitation? Why can't I
just the string interpolation in any playes and the cursor function escapes
any strings so that they can't do harm to my query?

What's happening here is not string interpolation. It's called parameter
binding, and the SQL standard defines exactly what parameter binding can
and can not do. (The SQL standard also defines that parameter markers
are question marks, and the fact that DB-API v2 modules are allowed to
blur the distinction between string interpolation and parameter binding
by choosing to use %s markers is very unfortunate.)

A primary purpose of parameter binding is the ability to prepare a query
once and then execute it many times over with different values. This
saves time because the query only needs to be parsed and planned once.
For this to be useful, parameters can't be bound to anything that would
alter the query plan. Consequently, parameter binding can't "substitute"
any of the following:

* The type of statement (SELECT/UPDATE/etc.)
* The tables involved
* The columns involved
* The structure of the join and where clauses
* The group by, order by, and having clauses
* The names of called functions and procedures
* Probably a whole lot of other things I'm not thinking of right now

Once you exclude all the things that parameter binding can't substitute,
you're left with only a very small segment of the SQL language that
parameter binding *can* substitute, which basically boils down to
"anything that could be a literal value".

HTH,
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,821
Messages
2,569,748
Members
45,726
Latest member
RaleighAll

Latest Threads

Top