Parameter binding not working for SQLite PRAGMA table_info

Question:

I am working with sqlite3 for Python. Why doesn’t work the parameter binding for the expression:

self.cursor.execute("PRAGMA table_info(?)", table_name)

as expected? For any other SELECT query it replaces my parameters as expected. I now used

self.cursor.execute("PRAGMA table_info('%s')" % table_name)

but this is not safe against SQL injections. How can I solve this issue?

Asked By: Patrick

||

Answers:

EDIT: As of SQLite version 3.16.0 (2017-01-02), all PRAGMAS can now be used as PRAGMA functions, which should allow for parameterization.

In Python:

self.cursor.execute("SELECT * FROM pragma_table_info(?)", table_name)

(Thanks to Rubinium’s answer for pointing this out). But if you are using an earlier version of SQLite, then my original answer might be your only choice.


I wanted to do the same thing, but it looks like it’s not possible to bind parameters to Sqlite PRAGMAs.

What you could do to stay secure (and what I might end up doing myself) is to query all the table names in the current Sqlite database in SQL like so:

SELECT * FROM sqlite_master

or, to just get tables and ignore views, do:

SELECT * FROM sqlite_master where type="table"

Then store those table names in an array/list/set. Now that you have a list of all possible tables in the db, you can simply check the user input to see if it matches one of the tables in the array. If it does, then it will be safe to insert into the string directly, and there will be no chance for SQL injection. Essentially, it is being sanitized against a whitelist.

In Python, it will look something like this:

if table_name in tables:
    self.cursor.execute("PRAGMA table_info('%s')" % table_name)
else:
    print("Bad table name: %s" % table_name)
Answered By: Hintron

For anyone happening on this question, the optimal method is to use the pragma functions like so:

self.cursor.execute("SELECT * FROM pragma_table_info(?)", table_name)

or

sqlite3_prepare_v2( db, "SELECT * FROM pragma_table_info(?)", -1, &stmt, &tail );
sqlite3_bind_text( stmt, 1, table_name, -1, nullptr );
Answered By: Rubinium