Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] 对二进制字段(blob)进行update时会丢失转义字符 #6227

Open
YapAmbition opened this issue Nov 13, 2024 · 1 comment
Open

Comments

@YapAmbition
Copy link

Database Type

MySQL

Database Version

5.7+, 8.0+

Druid Version

1.1.6, 1.1.14

JDK Version

jdk8, jdk11

Error SQL

  1. sql:update tb_blob set description = _binary'你好\"世界';
  2. 经过MySqlStatementParser解析出List,对里边的SQLStatement调用accept(SQLASTOutputVisitor),最终返回的sql中,description会被修改为【你好"世界】,👈没有中括号,丢失了一个转义字符
  3. 作为对比,把此update语句直接原样发到MySql服务,最终的description会被修改为【你好"世界】

Testcase Code

No response

Stacktrace Info

No response

Error Info

No response

@YapAmbition
Copy link
Author

在idea做了debug之后,目前发现影响面只有二进制字段的更新操作。
转义字符丢掉的原因:

  1. 用MySqlOutputVisitor对AST进行遍历,对待更新的二进制字段,druid会将其解析为MySqlCharExpr,而非二进制字段会被解析为SQLCharExpr
  2. MySqlOutputVisitor对于MySqlCharExpr的处理方式和SQLCharExpr不同。MySqlCharExpr会直接输出原样文本,这里会首先会在解析时消耗掉第一个,然后在Java的字符串转换时消耗掉第二个\;而SQLCharExpr会显示地补充\
  3. 最终MySqlOutputVisitor输出的sql就会丢掉两个\

这里还发现个现象,对insert语句能正确处理,debug发现MySqlOutputVisitor重写了针对update语句的visit(MySqlUpdateStatement x),却没有重写针对insert语句的visit(ValuesClause x),重写后的visit方法对于字段输出在选择使用哪个visit()重载方法时是用getClass() == XXX.class来做比较,相比之下没有重写的visit方法在选择使用哪个visit重载方法时使用x instanceof XXX.class。这就使得同样是MySqlCharExpr类型,insert语句会进入到visit(SQLCharExpr),而update则会进入到visit(MySqlCharExpr)。

👆请问一下以上的两个现象分别会导致二进制字段和非二进制字段行为不一致、insert和update行为不一致,这里面是一个潜在的问题还是有意为之呢。我们的使用场景是作为一个数据库中间键使用,进入我们的服务时会解析语法树,有时会改写语法树并使用MySqlOutputVisitor将修改后的结果输出,现在发现对二进制字段的update相比非二进制和insert时会丢失转义字符,请问是否有规避方法呢?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant