sqlite / python - 没有引号的命名参数?

5 投票
2 回答
2052 浏览
提问于 2025-04-16 07:08

在使用SQLite的准备语句和命名参数时(特别是用Python的sqlite3模块 http://docs.python.org/library/sqlite3.html),有没有办法在不让字符串值被加上引号的情况下使用它们?

我现在有这个:

columnName = '''C1'''
cur = cur.execute('''SELECT DISTINCT(:colName) FROM T1''', {'colName': columnName})

结果生成的SQL看起来是这样的:

SELECT DISTINCT('C1') FROM T1

当然,这样并没有什么用,我真正想要的是:

SELECT DISTINCT(C1) FROM T1 .

有没有办法让执行方法处理提供的参数时,不在它们周围加上引号呢?

我写了一个小测试程序来深入探讨这个问题,所以这里分享一下:

import sys
import sqlite3
def getDatabaseConnection():
    DEFAULTDBPATH = ':memory:'

    conn = sqlite3.connect(DEFAULTDBPATH, detect_types=sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES)
    conn.text_factory = str

    return conn

def initializeDBTables(conn):
    conn.execute('''
    CREATE TABLE T1(
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      C1 STRING);''')   
    cur = conn.cursor()
    cur.row_factory = sqlite3.Row  # fields by name 

    for v in ['A','A','A','B','B','C']:
        cur.execute('''INSERT INTO T1 values (NULL, ?)''', v)

    columnName = '''C1'''
    cur = cur.execute('''SELECT DISTINCT(:colName) FROM T1''', {'colName': columnName})

    #Should end up with three output rows, in
    #fact we end up with one
    for row in cur:
        print row


def main():
    conn = getDatabaseConnection()
    initializeDBTables(conn)

if __name__ == '__main__':
    main()

我很想知道有没有办法调整执行方法,让它可以正常工作。

2 个回答

0

你正在使用绑定,而绑定只能用于值,不能用于表名或列名。你需要使用字符串插值或格式化来达到你想要的效果,但这样做会让你面临SQL注入攻击的风险,特别是当列名来自不可信的来源时。在这种情况下,你可以对字符串进行清理(比如只允许字母和数字),并使用授权接口来检查是否会发生意外的操作。

4

SELECT DISTINCT(C1) FROM T1 这条语句中,C1 不是一个字符串值,而是一段SQL代码。这里的参数(在 execute 中被转义)是用来插入值的,而不是用来插入代码的部分。

撰写回答