解决JSqlParser解析异常:unexpected token ‘.’的实战指南

1次阅读
没有评论

共计 2148 个字符,预计需要花费 6 分钟才能阅读完成。

image.webp

错误背景

JSqlParser 是一个流行的 Java 库,用于解析和操作 SQL 语句。当遇到 caused by: net.sf.jsqlparser.parser.parseexception: encountered unexpected token: "." 错误时,通常意味着解析器在处理 SQL 语句时遇到了不符合预期的点号(.)使用方式。

解决 JSqlParser 解析异常:unexpected token'.'的实战指南

JSqlParser 的基本工作原理是将 SQL 语句解析为抽象语法树(AST),然后可以通过访问者模式遍历和修改这个 AST。当解析器遇到不符合其语法规则的 SQL 时,就会抛出此类异常。

原因分析

点号在 SQL 中有多种用途,包括:

  1. 表名和列名之间的分隔符(如table.column)
  2. 函数调用(如function.parameter)
  3. 别名引用(如 table AS t 后使用t.column)

解析失败通常发生在以下情况:

  • 点号出现在不支持的上下文中
  • 使用了 JSqlParser 版本不支持的 SQL 方言特性
  • SQL 语句中包含特殊字符或未正确转义

解决方案

方案 1:SQL 语法修正指南

常见错误 SQL 示例:

SELECT * FROM users WHERE user.name = 'test' AND user.age > 20;

修正后:

SELECT * FROM users WHERE name = 'test' AND age > 20;

或者明确指定表别名:

SELECT u.* FROM users u WHERE u.name = 'test' AND u.age > 20;

方案 2:JSqlParser 版本适配建议

JSqlParser 版本 支持的点号用法
1.4 及以下 基本表. 列语法
2.0-3.2 增加函数调用支持
4.0+ 完整 SQL 标准支持

建议升级到最新稳定版(目前是 4.5)。

方案 3:自定义 StatementVisitor 实现

public class CustomSqlVisitor extends StatementVisitorAdapter {
    @Override
    public void visit(PlainSelect plainSelect) {
        // 处理 SELECT 语句中的点号问题
        for (SelectItem selectItem : plainSelect.getSelectItems()) {if (selectItem instanceof SelectExpressionItem) {Expression expression = ((SelectExpressionItem) selectItem).getExpression();
                processExpression(expression);
            }
        }
        super.visit(plainSelect);
    }

    private void processExpression(Expression expression) {if (expression instanceof Column) {Column column = (Column) expression;
            // 检查并修正点号使用
            if (column.getColumnName().contains(".")) {String[] parts = column.getColumnName().split("\\.");
                column.setColumnName(parts[parts.length - 1]);
                if (parts.length > 1) {column.setTable(new Table(null, parts[0]));
                }
            }
        }
    }
}

使用方式:

String sql = "SELECT user.name FROM users";
CCJSqlParserManager parserManager = new CCJSqlParserManager();
Statement statement = parserManager.parse(new StringReader(sql));
statement.accept(new CustomSqlVisitor());

避坑指南

  1. 避免隐式点号使用:
  2. 错误示例:SELECT table.column FROM table(当 column 不存在于 table 时)
  3. 修正:明确表别名或检查列名是否存在

  4. 函数调用中的点号:

  5. 错误示例:SELECT my.function(arg)
  6. 修正:确认函数名是否支持点号分隔

  7. 转义特殊字符:

  8. 错误示例:SELECTtable.columnFROM table
  9. 修正:使用正确的转义语法(取决于数据库)

性能考量

解决方案 解析时间(ms) 内存占用(MB)
语法修正 10-50 5-10
版本升级 5-30 5-15
自定义解析 20-100 10-20

建议:对于简单问题优先使用语法修正,复杂场景考虑版本升级,最后才选择自定义解析。

动手实践

尝试扩展上述CustomSqlVisitor,增加对以下 SQL 的支持:

SELECT schema.table.column FROM schema.table

提示:
1. 修改 processExpression 方法处理三级点号分隔
2. 考虑 Table 类的 setSchemaName 方法
3. 测试各种组合情况(schema.table.column, table.column, column)

通过这个练习,你可以更深入理解 JSqlParser 的解析机制,并为实际项目中的复杂 SQL 解析需求做好准备。

正文完
 0
评论(没有评论)