Apache Calcite解析含@@变量的MySQL SQL语句失败求助
解决Apache Calcite解析MySQL @@变量的方案
1. 扩展Calcite的MySQL方言,添加@@变量语法支持
Calcite的MySqlDialect默认对@@开头的系统变量支持不全,你可以自定义方言类继承它,重写相关解析逻辑:
- 找到Calcite中处理标识符或变量的解析规则,在
SqlParserImpl生成代码里添加对@@前缀的识别,把@@session.xxx这类结构解析成SqlIdentifier或自定义的SqlNode子类(比如MySqlSystemVariable)。 - 注册自定义方言替换默认MySQL方言,示例代码片段:
public class CustomMySqlDialect extends MySqlDialect { public CustomMySqlDialect(Context context) { super(context); } @Override public SqlNode parseSql(String sql) throws SqlParseException { // 可在此添加预处理或自定义解析逻辑识别@@变量 return super.parseSql(sql); } }
2. 预处理SQL语句,转换@@变量为Calcite可识别形式
在交给Calcite解析前,先对SQL做字符串替换,把@@session.xxx替换为自定义函数形式,后续遍历节点树时再还原:
- 用正则匹配
@@([a-zA-Z0-9_.]+),替换为自定义函数调用,示例:
String processedSql = sql.replaceAll("@@([a-zA-Z0-9_.]+)", "MYSQL_VAR('$1')");
- 解析完成后,遍历
SqlNode树,找到对应SqlCall节点,再转换回系统变量的原始表示形式。
3. 自定义Calcite解析器规则
修改Calcite的ANTLR语法文件(如SqlParser.g4或MySQL专用语法文件),添加@@变量的语法定义:
- 在语法规则中新增:
systemVariable : '@@' (SESSION | GLOBAL)? '.' identifier | '@@' identifier ;
- 重新生成解析器代码,替换Calcite默认实现,即可直接将
@@变量解析为对应SqlNode节点,避免抛出异常。
4. 捕获解析异常后手动修复节点树
如果不想修改底层规则,可以捕获SqlParseException,手动解析出错位置的@@变量并构造SqlNode插入树中:
- 捕获异常后,分析错误位置上下文,提取
@@变量内容,构造SqlIdentifier或自定义SqlSystemVariable节点。 - 手动修复解析树,跳过错误位置继续解析剩余内容,这种方式适合快速兼容,但需要熟悉Calcite解析树结构。
内容的提问来源于stack exchange,提问作者Spanners
相关产品推荐
相关产品推荐

