首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在antlr4中跳过SQL(SQL的一部分)解析?

如何在antlr4中跳过SQL(SQL的一部分)解析?
EN

Stack Overflow用户
提问于 2021-11-20 12:21:00
回答 2查看 99关注 0票数 0

很抱歉,这个问题已经关闭了,不能重新打开,而且我的英语很差,确实被网站翻译了。:) https://stackoverflow.com/questions/70035964/how-to-skip-sql-parsing-in-antlr4

@BartKier感谢您对这个问题感兴趣,让我给它一个详细的例子。

有很多SQL查询,比如select * from userupdate user set field1 = 'value1' where condition = 'value'等,我们称它为原始SQL查询。

有一个java程序将所有原始的SQL查询通过ANTLR4截获并解析成解析树节点,然后由java程序重写查询(依赖于解析阶段),因此原始的SQL查询可以被解析并重写为

代码语言:javascript
复制
select field1, field1_encrypted, field1_digest, field2 from user

代码语言:javascript
复制
update user 
  set field1 = value1, 
      field1_encrypted = encrypt_algorithm(value1), 
      field1_digest = digest_algorithm(value1) 
  where condition_digest = digest_algorithm(values)

等。

当他们完成重写阶段时,他们应该以SQLStatement身份执行,SELECT以SelectSQLStatement身份执行,而UPDATE以UpdateSQLStatement身份执行。

现在,我认为一些原始的SQL查询应该跳过解析阶段,以及应该跳过的重写阶段,但是originalSQL查询应该按原样执行。

我想把那些带注释的标记为

代码语言:javascript
复制
/* PARSE_PHASE_SKIPPED=TRUE */ originalSQL

或将SKIP前缀设置为

代码语言:javascript
复制
SKIP originalSQL

,我希望通过ANTLR4将整个带标记的原始SQL查询部分解析成解析树节点,并将其作为ParsePhaseSkippedSQLStatement执行。

ANTLR4可以支持这种情况吗?语法应该如何编写?提前谢谢。

====================

谢谢你的回复:Mike Cargal,是的,差不多了。

让我再说一遍,并给出一个更详细的例子。

有一个java系统,我们叫它X,X有很多开发人员编写的SQL查询,并保证这些SQL可以被Ibatis / JPA等正确执行,让我们将这些SQL查询命名为原始SQL查询。

使用以下原始SQL查询作为示例:

代码语言:javascript
复制
insert into user (username, id_no) values ('xyz', '123456')
代码语言:javascript
复制
select username, id_no from user u where u.id_no = '123456'

我们说表user上的列id_no是敏感数据,我们应该保存密文而不是明文,这样原始的SQL将被ANTLR解析并被java代码重写,如下所示,我们将这些SQL命名为重写的SQL查询,并且重写的SQL查询应该由Ibatis / JPA等正确执行。

代码语言:javascript
复制
insert 
  into user (username, id_no, id_no_cipher, id_no_digest) 
  values ('xyz', '', 'encrypted_123456', 'digest_123456')
代码语言:javascript
复制
select username, id_no_cipher as id_no 
  from user u 
  where u.id_no_digest = 'digest_123456'

在这种情况下:

1SQL我们看到重写阶段依赖于解析阶段,原始、查询需要被正确解析,然后被java代码重写。

2、所有原始SQL查询都被解析,但只有少数匹配敏感规则的SQL查询被重写为重写的SQL查询。

但我们清楚地知道,有许多原始SQL查询不需要重写,也不需要解析,并且在解析时可能会在各种复杂情况下报告异常,但它应该由Ibatis / JPA等正确执行。

因此,我计划使用sql注释/定制关键字注释来“关闭”它的解析阶段。

EN

回答 2

Stack Overflow用户

发布于 2021-11-20 13:58:53

如果我没理解错的话,您希望使用某种注释/注释来“关闭”执行下面的SQL语句。

(注意:您不能真正跳过输入的“解析”部分。这将解决您可以跳过处理已解析输入的一部分的方法,我相信这是您最终想要完成的。)

这不是ANTLR关心的问题。ANTLR的职责是解析您的输入流,并生成正确表示输入结构的解析树(从技术上讲不是AST)。

执行SQL不是ANTLR所做的事情。但是,它确实会生成实用程序侦听器和访问者类,这些类可用于干净有效地导航生成的解析树。在实际执行解析树中的SQL时,可能涉及到大量代码。通常,第一步是从解析树生成一个AST,以使其更容易处理。

这是可以做到的,但它有点“混乱”。最有可能的情况是COMMENT令牌是-> skip编辑的(或者可能发送到-> channel(HIDDEN))。这使得编写解析器规则变得容易得多,因为您不必在注释可能出现的任何地方都包含可选的COMMENT。也就是说,如果您向HIDDEN通道发送COMMENT令牌,即使它们被解析器忽略,它们仍然在令牌流中。COMMENT令牌不会在侦听器/访问者处理的规则上下文对象中,但是您可以在令牌流中向后/向前查看COMMENT节点。

它们必须与有效的SQL区分开来,所以简单的SKIP可能无法工作。

这种方法的好处是,当您扩展语法以识别注释时,您可以非常具体地说明允许在何处使用注释。您将能够将它们包含在解析树中,从而使它们更容易定位。

使用这两种方法中的任何一种,您都可以使用访问者或侦听器遍历解析树,查找注释/注释,然后用您不想执行的指示符标记后续语句。(您可以使用这些信息简单地跳过“跳过的”节点的解析树到AST转换)。

票数 1
EN

Stack Overflow用户

发布于 2021-11-26 17:21:05

让我看看我是否正确理解了你的问题。在您的环境中,您运行SQL查询(不是“SQL”,btw),其中可能包含不能直接到达服务器的数据。无论是敏感数据还是其他数据,都无关紧要。最重要的是您想要替换查询中的文本。

为此,您需要解析查询并重写它们,然后再将它们发送到服务器。但是,您不希望对所有查询执行此操作,而是仅针对特定查询执行此操作。您想出了用特殊注释标记不能转换的查询(或查询部分)的想法。到目前为止,这是否符合您的意图?

现在,我想知道为什么要在查询(解析)级别上实现这一点。这不是您想要修改的解析,而是解析结果的语义处理(这里是解析树,正如Mike Cargal已经提到的)。因此,在我看来,您不需要为查询引入特殊标记,而是定义指示必须替换哪些数据的标准。

当您考虑这一点时,您可能会意识到需要替换特定表中特定字段(列)的数据。实际上,您可以保留一个模式/表/列的元组列表,它会告诉重写器某个值是否必须重写。其他的一切都会保持原样。

ANTLR4在这个过程中没有任何作用。这一切都是在语义阶段完成的(使用解析树侦听器处理解析树)。在此阶段,您必须收集查询中使用的所有列引用。然后将该列表与重写器的列表进行比较。如果列引用匹配,则重写器必须在查询中重写该列的文本。

然而,由于嵌套查询(子查询,其中内部查询可以引用外部查询中的表),该任务并不是微不足道的。这是顺便说一句。与代码完成的工作方式非常相似,您必须为查询中提到的所有表提供一个可能的列列表。这就是我在SQL的C++代码完成中编写( to collect such references )代码的原因。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70045858

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档