我可以使用参数作为sqlite3中的表名吗?

23

我对 sqlite3 的 参数 有些奇怪的感觉,我想向您请教。

以下是我的查询和失败信息:

#query
'SELECT id FROM ? WHERE key = ? AND (userid = '0' OR userid = ?) ORDER BY userid DESC LIMIT 1;'
#error message, fails when calling sqlite3_prepare()
error: 'near "?": syntax error'

在我的代码中看起来像是:

// Query is a helper class, at creation it does an sqlite3_preprare()
Query q("SELECT id FROM ? WHERE key = ? AND (userid = 0 OR userid = ?) ORDER BY userid DESC LIMIT 1;");
// bind arguments
q.bindString(1, _db_name.c_str() ); // class member, the table name
q.bindString(2, key.c_str()); // function argument (std::string)
q.bindInt   (3, currentID); // function argument (int)
q.execute();

我有这样的感觉,好像无法在sqlite参数中使用表名,但我在Sqlite3 C API中找不到确认。

你知道我的查询有什么问题吗?
我是否需要预处理SQL语句以在准备查询之前包含表名?


2
不,你不能用SQLite或大多数其他SQL产品来做到这一点。参数绑定是用于绑定参数的,而不是替换你喜欢的任何旧查询部分。 - user2100815
那正是我猜测的,但SQLite API并没有提到这一点,您知道我在哪里可以得到确认吗?同时,我不同意参数不能是SQL语句的变量之一。 INSERTUPDATE WHERE是SQL语言的静态固定词法分析器,但表名不是,依我看。 - Gui13
1
例如在这里http://www.sqlite.org/c3ref/bind_blob.htm中说“字面量可以被参数替换”。在SQL语法中,字面量是指字符串和数字等内容,而表名不是字面量。 - user2100815
1
表名影响语句中列名的含义,因此解析器需要知道它们。在这方面,它们就像其他语言中的类一样,大多数语言也不能使用变量来表示类。 - Jan Hudec
@JanHudec 您是指大多数静态类型语言。 - JAB
@JAB:是的。实际上我指的是静态类型,而不是类。因为并非所有类型都是类,而在某些动态语言中,类并不真正代表类型。 - Jan Hudec
2个回答

19

3
SQLite文档可以在此找到:https://www.sqlite.org/cintro.html,在第6章“绑定参数和重复使用已准备好的语句”中说到:“参数不能用于列名或表名。” - Bruno Bieri

5

我知道这已经很老了,但是由于您的查询只是一个字符串,因此您可以在C ++中像这样附加表名:

std::string queryString = "SELECT id FROM " + std::string(_db_name);

或者用Objective-C:

[@"SELECT id FROM " stringByAppendingString:_db_name];

1
没错,但那是为了一个嵌入式系统,我必须限制内存碎片化。这样做会在一行中分配4个字符串,效率不高。当时我通过将数据库布局更改为更合适的方式来解决了这个问题。 - Gui13
@Gui13 实际上,这行代码最多会分配2个块:一个用于存储 _db_name,另一个用于存储整个查询和 "SELECT ..." 前缀,如果编译器没有优化 operator+(const char*, std::string&&),或者临时空间不足的话。在将 char* 字面量附加到另一个字符串之前,没有必要将其转换为字符串,并且在复制初始化中,复制是省略的。此外,大多数编译器使用(或具有使用)小字符串优化,这意味着在大多数情况下根本不需要分配。 - bcrist
7
更重要的是,字符串拼接容易导致 SQL 注入攻击。比如 _db_name 的值是 "table; delete from table;",那就麻烦了。虽然我们无法将表名作为参数传递,但至少可以对值进行净化处理,或者先验证该表是否存在。 - ateijelo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接