2012-01-12 11 views
13

pysqliteを使用する私はいくつかのデータで何かをするための手続きをしています。操作の同じ種類を複数のテーブルと列に類似したフィールドで行われたので、私は、以下のように私は、SQLステートメントをパラメータ化することができると思っている:pysqlite:列またはテーブル名のプレースホルダ置換?

def foo(): 
    column = 'c' 
    table = 't' 
    row = 1 
    # preferred approach, gives syntax error 
    c.execute('SELECT ? FROM ? WHERE id=?', (column, table, row)) 
    # sanity check, works fine 
    c.execute('SELECT c FROM t WHERE id=?', (row)) 
    # workaround, also works, but is this the right way? 
    c.execute('SELECT % FROM % WHERE id=?' % (column, table), row)) 

私が手にエラーが(sqlite3.OperationalError: near "?": syntax error)非常に有用ではありませんが、Iポイントを得る:Pysqliteはこの方法でプレースホルダを使用することに感謝しない。

上記を行う適切な方法に沿って、ここで何が起こっているのか誰かが指摘できますか?

答えて

15

単に列名または表名にプレースホルダを使用することはできません。私はこれの権威ある引用を持っていない - 私はこれを試して失敗したことからだけ "知っている"。これは、しかし、いくつかの意味があります:

  • 列とテーブルをパラメータ化することができれば、(execute -ing)を調製するにはほとんど 目的が存在することになるSQL文を文のすべての部分が を交換する可能性があるので、フェッチする前に。
  • 私はpysqliteについてはわかりませんですが、MySQLdbはすべての文字列パラメータを自動的に引用します。 列名と表名は引用符で囲まないでください。そのため、 は、 のプレースホルダが引用符を必要とする の値に対して列またはテーブルの名前を表すかどうかを判断する必要がある場合、ドライバが必要とする解析を複雑にします。

要するに、適切な方法を見つけました。文字列形式を使用します。

c.execute('SELECT {} FROM {} WHERE id=?'.format(column, table), row)) 

すべてのドライバは、パラメータを引用していない - それは、別途サーバーにSQLと引数を送信するのでoursqlは、しません。

+0

これはSQLインジェクションから安全ですか? – berkelem

+1

@berkelem:SQLインジェクションに脆弱です。残念ながら、列名と表名はパラメータ化できないため、文字列の書式設定を避ける方法はありません。 [ホワイトリストを使用する](https://phpdelusions.net/sql_injection#whitelist)がベストプラクティスです。 – unutbu

2

@unutbuが答えたように、テーブル/カラム名にプレースホルダを使用する方法はありません。あなたが今やっていることをすることを提案しますが、奇妙な名前を持つ可能性のあるテーブルやカラムからあなたを守るためにテーブル名を引用することもできます。

What does the SQL Standard say about usage of backtick(`)?はすでにこれについて説明していますが、その回答の意見にもかかわらず、あなたのケースでは、引用は良い考えです。