sharding sphere 4.1.1 - 使用Antlr解析sql语句

.

public class AntlrTest {
    /**
     * @param args
     * @throws Exception
     * @see org.apache.shardingsphere.sql.parser.core.parser.SQLParserFactory#createSQLParser(java.lang.String, org.apache.shardingsphere.sql.parser.spi.SQLParserConfiguration)
     */
    public static void main(String[] args) throws Exception {
        String logicSql = "insert into tb_users(id,name) values(111, \"name_1\"), (?, ?)";

        DataNodeRouter dataNodeRouter = new DataNodeRouter();
        dataNodeRouter.createRouteContext(logicSql, null, false);
    }

    static class DataNodeRouter {

        /**
         * @see org.apache.shardingsphere.underlying.route.DataNodeRouter#createRouteContext(java.lang.String, java.util.List, boolean)
         * @see org.apache.shardingsphere.sql.parser.binder.SQLStatementContextFactory#newInstance
         */
        private RouteContext createRouteContext(final String sql, final List<Object> parameters, final boolean useCache) {
            SQLParserEngine sQLParserEngine = new SQLParserEngine();
            SQLStatement sQLStatement = sQLParserEngine.parse0(sql, false);
            if (sQLStatement instanceof DMLStatement) {
                DMLStatement dMLStatement = (DMLStatement) sQLStatement;
                if (dMLStatement instanceof SelectStatement) {
                    log.info("dMLStatement instanceof SelectStatement = {}", true);
                } else if (dMLStatement instanceof UpdateStatement) {
                    log.info("dMLStatement instanceof UpdateStatement = {}", true);
                } else if (dMLStatement instanceof DeleteStatement) {
                    log.info("dMLStatement instanceof DeleteStatement = {}", true);
                } else if (dMLStatement instanceof InsertStatement) {
                    InsertStatement insertStatement = (InsertStatement) dMLStatement;

                    /**
                     * @see org.apache.shardingsphere.sql.parser.binder.statement.dml.InsertStatementContext#InsertStatementContext
                     */
                    SimpleTableSegment tableSegment = insertStatement.getTable();
                    String tableName = insertStatement.getTable().getTableName().getIdentifier().getValue();
                    List<String> columnNames = insertStatement.getColumnNames();
                    log.info("tableName = {}, columnNames = {}", tableName, columnNames);
                    log.info("dMLStatement instanceof InsertStatement = {}", true);

                    /**
                     * insert into tb_users(id,name) values(111, "name_1"), (?, ?)
                     *
                     * getAllValueExpressions() = List<List<ExpressionSegment>> [
                     *      [
                     *          LiteralExpressionSegment(startIndex=37, stopIndex=39, literals=111)
                     *          CommonExpressionSegment(startIndex=42, stopIndex=49, text="name_1")
                     *      ],
                     *      [
                     *          ParameterMarkerExpressionSegment(startIndex=54, stopIndex=54, parameterMarkerIndex=0)
                     *          ParameterMarkerExpressionSegment(startIndex=57, stopIndex=57, parameterMarkerIndex=1)
                     *      ]
                     * ]
                     */
                    for (Collection<ExpressionSegment> each : insertStatement.getAllValueExpressions()) {
                        new InsertValueContext(each, null, 0);
                    }

                    /**
                     * 插入的行数
                     */
                    int valueListCount = insertStatement.getValueListCount();
                    log.info("valueListCount = {}",valueListCount);
                }
            }
            return null;
        }
    }

    /**
     * 存放的是《每一行的值列表》
     */
    static class InsertValueContext {

        private final int parametersCount;

        private final List<ExpressionSegment> valueExpressions;

        public InsertValueContext(final Collection<ExpressionSegment> assignments, final List<Object> parameters, final int parametersOffset) {
            parametersCount = calculateParametersCount(assignments); // 有多少个占位符,数量就等于几
            valueExpressions = getValueExpressions(assignments); // 绑定参数值列表(包括:占位符、非占位符)

            log.info("parametersCount = {}, valueExpressions = {}", parametersCount, valueExpressions);
            // this.parameters = getParameters(parameters, parametersOffset);
        }

        private int calculateParametersCount(final Collection<ExpressionSegment> assignments) {
            int result = 0;
            for (ExpressionSegment each : assignments) {
                if (each instanceof ParameterMarkerExpressionSegment) {
                    result++;
                }
            }
            return result;
        }

        private List<ExpressionSegment> getValueExpressions(final Collection<ExpressionSegment> assignments) {
            List<ExpressionSegment> result = new ArrayList<>(assignments.size());
            result.addAll(assignments);
            return result;
        }
    }

    /**
     * @see org.apache.shardingsphere.underlying.rewrite.context.SQLRewriteContext#generateSQLTokens()
     * @see cn.java.sphere.demo.debug.SQLTokenGeneratorsDebug.SQLRewriteContextDecorator_
     */
    static class SQLRewriteContext {
        public void generateSQLTokens(final SQLStatementContext sqlStatementContext) {

            // 要插入的表
            {
                TableTokenGenerator generator = new TableTokenGenerator();
                Collection<TableToken> tokens = generator.generateSQLTokens(sqlStatementContext);
            }

            // 如果配置了自动生成key,根据配置,那么会在sql插入一个字段
            {
                GeneratedKeyInsertColumnTokenGenerator generator = new GeneratedKeyInsertColumnTokenGenerator();
                GeneratedKeyInsertColumnToken token = generator.generateSQLToken((InsertStatementContext) sqlStatementContext);
            }

            // 如果配置了自动生成key,根据配置,那么会生成一个值占位符?,用于填充如uuid、雪花id
            {
                GeneratedKeyAssignmentTokenGenerator generator = new GeneratedKeyAssignmentTokenGenerator();
                GeneratedKeyAssignmentToken token = generator.generateSQLToken((InsertStatementContext) sqlStatementContext);
            }
        }
    }


    public static class SQLParserEngine {

        /**
         * @see org.apache.shardingsphere.sql.parser.SQLParserEngine#parse0(java.lang.String, boolean)
         */
        SQLStatement parse0(final String sql, final boolean useCache) {
            // 1、解析出抽象语法树
            SQLParserExecutor sQLParserExecutor = new SQLParserExecutor(sql);
            ParseASTNode parseASTNode = sQLParserExecutor.execute();
            ParseTree parseTree = parseASTNode.getRootNode();
            final VisitorRule visitorRule = VisitorRule.valueOf(parseTree.getClass());

            // 2、遍历抽象语法树
            ParseTreeVisitor parseTreeVisitor = createParseTreeVisitor(visitorRule.getType());
            SQLStatement result = (SQLStatement) parseTreeVisitor.visit(parseTree);
            return result;
        }

        /**
         * 《抽象语法树》访问器
         *
         * @param type
         * @return
         * @see org.apache.shardingsphere.sql.parser.core.visitor.ParseTreeVisitorFactory#createParseTreeVisitor
         */
        private static ParseTreeVisitor createParseTreeVisitor(final SQLStatementType type) {
            SQLVisitorFacade visitorFacade = new MySQLVisitorFacade();
            try {
                switch (type) {
                    case DML:
                        /**
                         * @see org.apache.shardingsphere.sql.parser.mysql.visitor.impl.MySQLDMLVisitor
                         */
                        return (ParseTreeVisitor) visitorFacade.getDMLVisitorClass().getConstructor().newInstance();
                    case DDL:
                        /**
                         * @see org.apache.shardingsphere.sql.parser.mysql.visitor.impl.MySQLDDLVisitor
                         */
                        return (ParseTreeVisitor) visitorFacade.getDDLVisitorClass().getConstructor().newInstance();
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            return null;
        }
    }

    /**
     * @see org.apache.shardingsphere.sql.parser.core.parser.SQLParserExecutor
     */
    @RequiredArgsConstructor
    static class SQLParserExecutor {
        private final String sql;

        public ParseASTNode execute() {
            ParseASTNode result = towPhaseParse();
            if (result.getRootNode() instanceof ErrorNode) {
                throw new SQLParsingException(String.format("Unsupported SQL of `%s`", sql));
            }

            return result;
        }

        /**
         * 解析《抽象语法树》
         *
         * @return
         * @see org.apache.shardingsphere.sql.parser.mysql.MySQLParserConfiguration
         */
        private ParseASTNode towPhaseParse() {

            MySQLLexer mySQLLexer = new MySQLLexer(CharStreams.fromString(sql));
            MySQLParser mySQLParser = new MySQLParser(new CommonTokenStream(mySQLLexer));

            {
                SQLParser sqlParser = mySQLParser;
                try {
                    ((Parser) sqlParser).setErrorHandler(new BailErrorStrategy());
                    ((Parser) sqlParser).getInterpreter().setPredictionMode(PredictionMode.SLL);
                    return (ParseASTNode) sqlParser.parse();
                } catch (final ParseCancellationException ex) {
                    ((Parser) sqlParser).reset();
                    ((Parser) sqlParser).setErrorHandler(new DefaultErrorStrategy());
                    ((Parser) sqlParser).getInterpreter().setPredictionMode(PredictionMode.LL);
                    return (ParseASTNode) sqlParser.parse();
                }
            }
        }
    }
}

.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值