【问题标题】:pysqlite: Placeholder substitution for column or table names?pysqlite:列或表名的占位符替换?
【发布时间】:2012-02-09 02:53:17
【问题描述】:

使用 pysqlite 我正在制作一个程序来处理一些数据。对多表多列的相似字段做同样的操作,所以我想可以参数化sql语句如下图:

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),但我明白了:Pysqlite 不喜欢以这种方式使用占位符。

谁能指出这里发生了什么以及执行上述操作的正确方法?

【问题讨论】:

    标签: python sql sqlite pysqlite


    【解决方案1】:

    您根本不能对列名或表名使用占位符。我对此没有权威的引用——我只是从尝试过和失败中“知道”这一点。不过还是有道理的:

    • 如果可以对列和表进行参数化,则几乎没有 目的是在获取之前准备(execute-ing)SQL 语句,因为语句的所有部分都可以 替换。
    • 我不确定 pysqlite1,但是 MySQLdb 自动引用所有 字符串参数。不应引用列名和表名。所以 如果必须,会使驱动程序所需的解析复杂化 决定一个占位符是否代表一个列或表名,而不是一个 需要引用的值。

    简而言之,您找到了正确的方法——使用字符串格式化。

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

    1 并非所有驱动程序都引用参数 -- oursql 没有,因为它分别向服务器发送 SQL 和参数。

    【讨论】:

    • 这对 SQL 注入安全吗?
    • @berkelem:它容易受到 SQL 注入的攻击。不幸的是,由于列名和表名是不可参数化的,因此无法避免字符串格式化。 Using whitelists 是这里的最佳做法。
    【解决方案2】:

    正如@unutbu 回答的那样,没有办法为表/列名使用占位符。我的建议是做你现在正在做的事情,但也要引用表名以保护自己免受可能有奇怪名称的表或列的影响。

    What does the SQL Standard say about usage of backtick(`)? 已经在一定程度上解释了这一点,尽管该答案中存在意见,但我想说,在你的情况下,引用是个好主意。

    【讨论】:

      猜你喜欢
      • 2013-04-08
      • 1970-01-01
      • 2021-02-16
      • 2012-07-04
      • 2017-09-11
      • 2013-01-24
      • 1970-01-01
      • 1970-01-01
      • 2020-03-18
      相关资源
      最近更新 更多