JDBC规范是否禁止在引号外使用“?”作为运算符?

19

来自Sam Macbeth的问题:

JDBC规范中是否有任何允许对“?”进行转义并使其成为除参数占位符之外其他内容的内容?

例如,Postgres允许您将?用作运算符:

SELECT * FROM tbl WHERE tbl.data ? 'abc'

如果使用 ? 作为运算符的JDBC驱动程序,是否仍然符合JDBC标准?

3个回答

15

如果您拥有最新的PostgreSQL驱动程序,则可以使用:

??

修改原查询:

SELECT * FROM tbl WHERE tbl.data ?? 'abc'

具体细节在此拉取请求中 - https://github.com/pgjdbc/pgjdbc/pull/227 虽然这个更改是在最初的问题之后很长时间才进行的,但值得注意的是现在有一个简单的答案。


8
我认为,如果JDBC驱动程序允许“?”运算符不被转义并按原样使用,这将是完全可以接受的,但这可能会1)使解析器复杂化以实际从该运算符中识别参数,并且2)可能会让习惯于“?”仅表示参数占位符的人们(和工具)感到困惑。
因此,我的建议是提供某种转义(或替代运算符)。但是,查看JDBC规范后,驱动程序应仅使用JDBC转义语法来实现JDBC规范中定义的转义(13.4.2:“转义语法不旨在用于调用用户定义或供应商特定的标量函数。”;尽管这是特别针对{fn ...} 转义的)。
因此,您需要使用替代转义,或者“违反”规则(我认为没有人会介意)。如果您想获得更权威的答案,您可以将问题发送到jdbc-spec-discuss邮件列表。我相信Lance Andersen(JDBC规范负责人)会提供答案。 编辑: 另外有趣的一点是,JDBC规范第6.2节(指南和要求)说:

驱动程序应提供对底层数据源实现的每个功能的访问,包括扩展JDBC API的功能。其目的是使使用JDBC API的应用程序能够访问与本地应用程序相同的功能集。

因此,基于这一点,您应该(并非必须)支持?运算符,您只需要找到一种实用的方法来做到这一点。


基于jdbc-spec-discuss上的讨论的更新

根据Lance Andersen的说法,JDBC规范遵循SQL规范关于问号的使用:它们只能作为查询文本中的参数占位符使用(当然除了注释和引用文本),因此像PostgreSQL hstore运算符中使用?是不被允许的。 (请参见此消息

可选的方法是提供运算符别名或转义,前提是这不会与未来的更改冲突(这很难在没有预知能力的情况下做到)。最好的解决方案-为了防止未来JDBC更改出现问题-可能是自定义转义。

JDBC实际上并没有定义供应商转义,但Lance Andersen建议使用类似于JDBC转义的转义:{postgres <thing to be escaped>};在此转义中使用供应商名称或驱动程序名称将提供一种命名空间形式,应该可以防止与规范冲突(参见this message)。
为了符合“正常”的JDBC函数转义,我建议定义一个转义,以允许将您的问题查询表示为:
SELECT * FROM tbl WHERE {postgres containskey(tbl.data, 'abc')}

我选择使用containskey是基于hstore文档?的含义。类似的建议对于?&containsallkeys,对于?|containsanykey。为了一致性,您也可以考虑对其他hstore运算符进行此操作。
您还可以决定仅转义问号本身。例如使用{postgres '?'}{postgres qm}(qm代表问号)。我认为可读性不及我的函数转义建议:
SELECT * FROM tbl WHERE tbl.data {postgres '?'} 'abc'

基于新的JDBC v.Next (4.4?)提案进行更新

下一个JDBC规范(可能编号为4.4),将可能添加一个明确的JDBC转义来完全转义查询的片段,旨在能够转义问号,以便支持不原生使用问号作为参数标记并需要支持问号的其他用途的数据库系统。

建议的语法将是{\ <thing-to escape> \}(Oracle JDBC驱动程序已支持作为非标准转义)。使用此语法,然后可以使用{\?\}转义参数标记(在字符串文字中:{\\?\\}),或转义更大的片段以提高可读性。

另请参见SQL 2016 MATCH RECOGNIZE JDBC parameter Marker / Escape Charactersjdbc-spec-discuss邮件列表上的早期讨论


5
我在JDBC规范中没有看到任何允许转义?的内容。它关于?的描述如下:
参数标记在SQL语句中用“?”表示,用于指定可能在运行时变化的语句输入值。[1]
稍后说到...
参数序数是传递给适当setter方法的整数,从一个开始,用于引用语句中的参数标记(“?”)。[2]
它仅为一小部分特性定义了转义语法,其中没有任何看起来可以应用于?的特性:
JDBC为以下内容定义了转义语法: - 标量函数 - 日期和时间字面量 - 外连接 - 调用存储过程 - LIKE子句的转义字符 [3]
总的来说,与某些W3C规范文档中频繁使用“必须”和“应该”的语言相比,JDBC规范似乎没有非常“严格”的语言。因此,我不知道允许转义?的驱动程序是否在技术上符合规范,但它可能不太兼容。
甚至连Postgres驱动程序似乎也不会允许它,因为驱动程序中实际解析SQL语句中的?的方法不检查任何转义字符

1. JDBC 4.1规范,第13.2节 —— PreparedStatement接口
2. JDBC 4.1规范,第13.3.2节 —— 设置参数
3. JDBC 4.1规范,第13.4节 —— 转义语法


那么JDBC纯粹主义者可能不会抱怨如果Postgres JDBC为'?'实现转义 - Seamus Abshere
我不能代表别人发言,但我认为为了使用hstore运算符而实现对“?”进行转义是适得其反的。因为在我看来,“?”hstore运算符旨在简短易读,而必须转义它会使它更加臃肿和晦涩(它看起来会是什么样子?c {?} 'foo'?)。正如aymeric的答案中指出的那样,已经有一种使用JDBC的解决方法。 - matts
@matts 但正如那个答案的评论之一所指出的那样:它不起作用(exists 不使用索引) - Mark Rotteveel

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