Question

I am looking for a nice "pythonic" and "SQL-Injection-free" solution for a problem with reserved words in MySQL.

I have the following code:

alter_sql = 'ALTER TABLE %s ADD COLUMN %s TEXT'      
cursor.execute(alter_sql, sql_params)

The problem occurs when column name is something like 'index', 'int', 'limit' ....

In MySQL shell I can do:

ALTER TABLE test ADD COLUMN test.limit;

or

ALTER TABLE test ADD COLUMN `limit`;

but not

ALTER TABLE test ADD COLUMN 'test.limit';

How can I achieve that with Python and MySQLdb?

Was it helpful?

Solution

Maybe this will work:

alter_sql = 'ALTER TABLE `%s` ADD COLUMN `%s` TEXT'

UPDATE: This seems not to work, because binding parameters this way will add single quotes, as MySQLdb supposes this is a string literal.

Alternatively, you can append the table name before the column name?

table_name = MySQLdb.escape_string(table_name)
escaped_column_name = MySQLdb.escape_string(column_name)
column_name = '`%s`.`%s`' % (table_name, escaped_column_name)

alter_sql = 'ALTER TABLE %s ADD COLUMN %s TEXT' % (table_name, column_name)

This way, you must escape them manually, to avoid binding them and adding single quotes around it.

OTHER TIPS

From here:

You can issue the same statement by using %s placeholder markers and binding the appropriate values to them:

cursor.execute("""UPDATE animal SET name = %s
                  WHERE name = %s
               """, ("snake", "turtle"))
print "Number of rows updated: %d" % cursor.rowcount

Note the following points about the form of the preceding execute() call:

  • The %s placeholder marker should occur once for each value that is to be inserted into the statement string.
  • No quotes should be placed around the %s markers; MySQLdb supplies quotes for you as necessary.
  • Following the statement string argument to execute(), provide a tuple containing the values to be bound to the placeholders, in the order they should appear within the string. If you have only a single value x, specify it as (x,) to indicate a single-element tuple.
  • Bind the Python None value to a placeholder to insert an SQL NULL value into the statement.

So, based on that, you should just pre-process your arguments to see if they're in a list of reserved keywords, and if so, prefix the table name to the column name, for eg.

RESERVED_KEYWORDS = ['LIMIT', 'INT', 'INDEX']
table_name = 'TESTING'
column_name = 'LIMIT'
if column_name in RESERVED_KEYWORDS:
    column_name = '%s.%s' % (table_name, column_name)
sql_params = [table_name, column_name]
alter_sql = 'ALTER TABLE %s ADD COLUMN %s TEXT'      
cursor.execute(alter_sql, sql_params)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top