【发布时间】:2021-12-30 21:04:44
【问题描述】:
很抱歉这个问题已关闭,无法重新打开,而且我的英语很差,它确实是由网站翻译的。 :) https://stackoverflow.com/questions/70035964/how-to-skip-sql-parsing-in-antlr4
@BartKiers 感谢您对这个问题感兴趣,让我举一个详细的例子。
SQL查询有很多,比如select * from user或update user set field1 = 'value1' where condition = 'value'等,我们称之为原始SQL查询。
有一个java程序,通过ANTLR4将所有原始SQL查询截取并解析成Parse Tree节点,然后由java程序重写查询(取决于解析阶段),因此原始SQL查询可能被解析并改写为
select field1, field1_encrypted, field1_digest, field2 from user
或
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 查询应该跳过解析阶段,应该跳过的重写阶段一样,但原始的 SQL 查询应该按原样执行。
我想把那些有评论的标记为
/* PARSE_PHASE_SKIPPED=TRUE */ originalSQL
或前缀SKIP为
SKIP originalSQL
,我希望通过ANTLR4将整个标记但原始的SQL查询部分解析为Parse Tree节点,并将其作为ParsePhaseSkippedSQLStatement执行。
ANTLR4可以支持这种情况吗,语法应该怎么写?提前致谢。
=====================
感谢您@Mike Cargal 的回复,是的,差不多。
我再说一遍,再举一个更详细的例子。
有一个java系统我们称之为X,X有很多开发者编写的SQL查询,并保证这些SQL可以被Ibatis/JPA等正确执行,我们把这些SQL查询命名为原始SQL查询。
以以下原始 SQL 查询为例:
insert into user (username, id_no) values ('xyz', '123456')
select username, id_no from user u where u.id_no = '123456'
我们说表user的id_no列是敏感数据,我们应该保存密文而不是明文,所以原来的SQL会被ANTLR解析并用java代码重写如下,我们将这些SQL命名为重写SQL查询,也重写Ibatis / JPA等应该正确执行SQL查询。
insert
into user (username, id_no, id_no_cipher, id_no_digest)
values ('xyz', '', 'encrypted_123456', 'digest_123456')
select username, id_no_cipher as id_no
from user u
where u.id_no_digest = 'digest_123456'
在这种情况下:
1、我们看到rewrite阶段依赖于parse阶段,原来的SQL查询需要正确解析然后用java代码重写。
2、所有原始SQL查询都被解析,但只有少数符合敏感规则的查询被重写为重写SQL查询。
但是有很多原始的SQL查询我们清楚的知道不需要重写,也不需要解析,在解析的时候可能会在各种复杂的情况下报异常,但是应该被Ibatis正确执行/ JPA等
所以我打算使用sql注释/自定义关键字注释来“关闭”它的解析阶段。
【问题讨论】:
-
这仍然很难理解,但我不想接受我用另一种语言提出的问题,所以我很同情。我认为我看到了您正在尝试做的事情,并提供了一些答案,可能会让您朝着正确的方向前进。简而言之,这不是 ANTLR 的事情,但是您可以通过多种方式使用 ANTLR 来解决您的问题。
-
开启/关闭 SQL 语句的标准方法是使用
WHERE 1=1或WHERE True启动 WHERE 子句,然后使用AND col1= 'val1'添加其他条件 BTW :/*是 SQL 中的非标准注释。