【问题标题】:SQLITE what are the restricted characters for identifiersSQLITE 标识符的限制字符是什么
【发布时间】:2015-10-25 15:50:57
【问题描述】:

我正在尝试构建一个 SQL 参数自动绑定到新查询的系统。根据这个线程:

SQL Server - Invalid characters in parameter names

应允许在标识符中使用@、_ 和# 字符。所以我尝试将参数构建为:

:表名#字段名

但是当我这样做时会出错:

PBdatabase.select_query: [1] DB[2] prepare() SELECT * FROM creative WHERE pk = :creature#pk [near "#pk": 语法错误]

它似乎不喜欢 # 字符,我尝试使用下划线,它似乎可以工作,但我已经在字段名称中使用了下划线。这就是我想使用不同字符的原因。

由于上面的线程谈到了 SQL 服务器,SQLITE 中的受限字符可能会有所不同。我找到了 SQLITE 受限关键字列表,但没有找到字符。

有人知道我还可以使用哪个特殊字符吗?


更新

有人想知道我有什么用处。这是一个示例,假设您有 2 个具有 1 对 N 关系的表:Fleet 包含船只。

您想要显示一个由 2 个块组成的表格,其中顶部显示 1 个当时选择的舰队。底部区块列出了舰队中的所有船只。

第一个块查询将类似于:

SELECT pk, number, location  FROM fleet;

然后所选条目的字段将被放入具有以下名称的字段注册表中(假设 # 符号有效):

:fleet#pk
:fleet#number
:fleet#location

然后将运行第二个块的第二个查询,包括上面的注册字段。所以查询看起来像:

SELECT pk, fk_fleet, name  FROM ship WHERE fk_fleet = :fleet#pk

此查询使用上述查询中的参数。标识符将替换为上一个查询中的值。这允许仅显示与上面所选舰队链接的船只,而不是所有可用的船只。

现在你们中的一些人可能会说我可以简单地保存我想要的变量并将它们作为参数传递给下一个查询。问题是所有查询都是从数据库加载的。我实际上不知道要运行哪个查询以及需要为另一个查询保存哪个值。相反,我将它们全部保存在注册表中,如果另一个 SQL 语句要求提供参数,则该值将可用。

【问题讨论】:

  • 顺便说一句,我不明白你在做什么。您的绑定系统应该在实际评估查询之前发生,因此表达式的有效性应该无关紧要
  • lang_keyword 页面列表关键字,而不是字符。至于我想要做什么,它是允许查询之间的通信。我将使用示例更新帖子。
  • 越来越好奇。什么是字段注册表?

标签: sqlite parameters special-characters bind identifier


【解决方案1】:

SQLite 和 SQL Server 相似,但它们的语法略有不同,就像 SQL 的所有实现通常有不同的规则一样。

SQLite 允许在第一个字符后使用字母 A-Za-z0-9_$、冒号对 "::" , 和大于 u007f 的 Unicode 字符。

另外,在参数末尾,可以加括号:(),括号之间可以是除ASCII空白字符和)字符之外的任何字符。 0x00 也是不允许的(因为它表示 C 字符串的结束)。

示例

所以下面的参数是有效的:

:a, :_, :$, :a::, :A, :9, :?, :  (U+2000, Unicode en 四空格字符), :a(:/$asd() .

虽然这些是无效的:

:#::::::;:(:( )(普通的 ASCII 空格)

来源

我在 SQLite 网站上找到一篇文章(见https://www.sqlite.org/draft/tokenreq.html),其中指定命名参数(也称为变量)可以包含:

“参数名称”被定义为一个或多个的序列 由 ALPHANUMERIC 字符和/或 美元符号 (u0025) 与冒号对 (u003a) 和 可选地后跟任何非零、非WHITESPACE的序列 括在括号中的字符(u0028 和 u0029)。

其中字母字符定义为:

字母 u0041 到 u005a 范围内的任何字符(字母“A”到“Z”) 或在 u0061 到 u007a 范围内(字母“a”到“z”)或字符 u005f ("_") 或任何其他大于 u007f 的字符。

数字 u0030 到 u0039 范围内的任何字符(数字“0”到“9”)

我还编写了一个简短的 Python 脚本来确认上述值。 Unicode 字符 0xd8000xdfff 也不起作用,因为 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({})"])))

【讨论】:

    【解决方案2】:

    在 SQLite 中,查询参数名称只能包含字母数字字符(?NNN 除外,它必须是整数);请参阅sqlite3_bind_* 函数参考的第二段。

    【讨论】:

    • 如果只接受字母数字,那么下划线将是无效字符,但事实并非如此。除了下划线,还有其他可接受的非字母数字字符吗?
    • 似乎在某些情况下下划线可以是可接受的字母数字字符。也许这就是 SQLITE 的情况。如果是这样的话,我会坚持使用下划线,丑陋但有效。
    猜你喜欢
    • 2017-05-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-17
    • 2018-09-22
    • 1970-01-01
    • 2012-09-26
    相关资源
    最近更新 更多