lar*_*nna 4 sqlite parameters bind identifier special-characters
我正在尝试构建一个系统,其中 SQL 参数会自动绑定到新查询。根据这个线程:
@、_ 和 # 字符应该允许在标识符中。所以我尝试将参数构建为:
:表名#字段名
但是当我做我得到错误:
PBdatabase.select_query: [1] DB[2] prepare() SELECT * FROM entity WHERE pk = :creature#pk [near "#pk": 语法错误]
似乎它不喜欢 # 字符,我尝试使用下划线,它似乎有效,但我已经在字段名称中使用了下划线。这就是为什么我想使用不同的字符。
由于上面的线程讨论了 SQL Server,SQLITE 中的受限字符可能会有所不同。我找到了 SQLITE 限制关键字列表,但没有找到字符。
有人知道我可以使用哪些其他特殊字符吗?
更新
有人想知道我这有什么用。这是一个示例,假设您有 2 个具有 1 到 N 关系的表:Fleet 包含船只。
您想显示一个由 2 个块组成的表格,其中顶部显示 1 个当时选定的舰队。底部区块列出了舰队中的所有船只。
第一个块查询将类似于:
SELECT pk, number, location FROM fleet;
Run Code Online (Sandbox Code Playgroud)
然后所选条目的字段将被放入具有以下名称的字段注册表中(假设 # 符号有效):
:fleet#pk
:fleet#number
:fleet#location
Run Code Online (Sandbox Code Playgroud)
然后将运行第二个块的第二个查询,包括上面的注册字段。所以查询看起来像:
SELECT pk, fk_fleet, name FROM ship WHERE fk_fleet = :fleet#pk
Run Code Online (Sandbox Code Playgroud)
此查询使用上述查询中的参数。标识符将被上一个查询中的值替换。这允许仅显示与上面选定的舰队相关联的船只,而不是所有可用的船只。
现在你们中的一些人可能会说我可以简单地保存我想要的变量并将它们作为参数传递给下一个查询。问题是所有查询都是从数据库加载的。我实际上不知道我要运行哪个查询以及我需要为另一个查询保存哪个值。相反,我将它们全部保存在注册表中,如果另一个 SQL 语句要求提供参数,则该值将可用。
SQLite 和 SQL server 相似,但它们的语法略有不同,就像 SQL 的所有实现通常具有不同的规则一样。
SQLite的允许字母,A- ,Z- a,z- 0,9,_,$对冒号的"::"第一个字符后,和Unicode字符比u007f大。
此外,在参数的末尾,可以添加括号:(and ),它们之间可以是除 ASCII 空白字符和)char之外的任何字符。0x00也永远不允许(因为这表示 C 字符串的结尾)。
所以以下参数是有效的:
:a, :_, :$, :a::, :A, :9, :, :?(U+2000, the Unicode en quad space character), :a(:/$asd().
虽然这些是无效的:
:#, :::, ::, :;, :(, :( )(普通的 ASCII 空间)
我在 SQLite 网站上找到了一篇文章(参见https://www.sqlite.org/draft/tokenreq.html),其中指定命名参数(也称为变量)可以包括:
“参数名称”被定义为一个或多个字符的序列,由 ALPHANUMERIC 字符和/或美元符号 (u0025) 与冒号对 (u003a) 混合组成,并且可选地后跟任何非零、非-WHITESPACE 括在括号中的字符(u0028 和 u0029)。
其中 ALPHANUMERIC 字符定义为:
ALPHABETIC u0041 到 u005a(字母“A”到“Z”)或 u0061 到 u007a(字母“a”到“z”)范围内的任何字符或字符 u005f(“_”)或任何其他字符字符大于 u007f。
和
NUMERIC u0030 到 u0039 范围内的任何字符(数字“0”到“9”)
我还编写了一个简短的 Python 脚本来确认上述值。在Unicode字符0xd800来0xdfff也没有工作,由于Python3拒绝作出这些值的字符串(见https://en.wikipedia.org/wiki/UTF-16#U+D800_to_U+DFFF为什么),所以这可以在 SQLite C 代码中工作。
import sqlite3
import tqdm
import itertools
with sqlite3.connect(":memory:") as conn:
with conn as cur:
cur.execute("create table test(x);")
strings_to_test = ["{}", "a{}", "{0}{0}", "a{0}{0}", "a({})"]
# make a list to hold the invalid chars for each test item
strings_to_test = {x: list() for x in strings_to_test}
def attempt_insert(string, i, invalid_list):
try:
cur.execute("insert into test values ( :{} );".format(string)
.format(chr(i)),{"{}".format(string).format(chr(i)): 42})
except Exception as e:
invalid_list.append(i)
# 0x10FFFF is the max value for UTF chars
for char_num in tqdm.trange(0, 0x10FFFF):
for string, invalid_char_list in strings_to_test.items():
attempt_insert(string, char_num, invalid_char_list)
def gen_ranges(i):
# from https://stackoverflow.com/a/4629241 with changes for Python3
for a, b in itertools.groupby(enumerate(i), lambda x: x[1] - x[0]):
b = list(b)
yield b[0][1], b[-1][1]
def ranges(invalid_chars):
return "{}".format(["0x{:06x} to 0x{:06x}".format(*range) \
for range in gen_ranges(invalid_chars)])
print("Invalid Single Chars: ie :x were: {}".format(
ranges(strings_to_test["{}"])))
print("Invalid Single Second Chars: ie :ax were: {}".format(
ranges(strings_to_test["a{}"])))
print("Invalid Double Chars: ie :xx were: {}".format(
ranges(strings_to_test["{0}{0}"])))
print("Invalid Double Chars in second pos: ie :axx were: {}".format(
ranges(strings_to_test["a{0}{0}"])))
print("Invalid Parenthesised Chars: ie :abc(x) were: {}".format(
ranges(strings_to_test["a({})"])))
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1720 次 |
| 最近记录: |