Spark Sql 简单校验的实现

        在网上参考了很多资料,都是要依赖Sparksession,这个需要spark环境,非常不友好,jdk版本也不好控制。不使用Sparksession获取上下文,利用spark和antlr的静态方法使用java 实现简单的spark sql 的语法以及内置函数的校验。

1. spark 版本 3.2.0

        <dependency><groupId>org.apache.spark</groupId><artifactId>spark-sql_2.12</artifactId><version>3.2.0</version></dependency><dependency><groupId>org.antlr</groupId><artifactId>antlr4-runtime</artifactId><version>4.8</version></dependency>

2.  完整校验代码

import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.atn.PredictionMode;
import org.antlr.v4.runtime.misc.ParseCancellationException;
import org.antlr.v4.runtime.tree.ParseTreeWalker;
import org.apache.spark.sql.Column;
import org.apache.spark.sql.catalyst.parser.SqlBaseBaseListener;
import org.apache.spark.sql.catalyst.parser.SqlBaseLexer;
import org.apache.spark.sql.catalyst.parser.SqlBaseParser;
import org.apache.spark.sql.functions;import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;public class SparkSqlChecker {public static boolean validateSyntax(String sql) {System.out.println("sql: " + sql);// 1.预处理:替换换行符为空格,并去除非必要空格sql = sql.replaceAll("\\s+", " ").trim();// 2. 关键字转大写CharStream input = new UpperCaseCharStream(sql);SqlBaseLexer lexer = new SqlBaseLexer(input);// 3.语法分析CommonTokenStream tokens = new CommonTokenStream(lexer);SqlBaseParser parser = new SqlBaseParser(tokens);parser.getInterpreter().setPredictionMode(PredictionMode.LL_EXACT_AMBIG_DETECTION);parser.setErrorHandler(new BailErrorStrategy());parser.removeErrorListeners();parser.addErrorListener(new ParseErrorListener());try {SqlBaseParser.SingleStatementContext context = parser.singleStatement();// 检查是否解析到输入末尾if (parser.getInputStream().LA(1) != Token.EOF) {throw new ParseCancellationException("未完整解析SQL语句");}//4.函数校验List<String> functions = new ArrayList<>();ParseTreeWalker walker = new ParseTreeWalker();walker.walk(new FunctionNameCollector(functions), context);System.out.println("sql 中的函数:"+functions.stream().collect(Collectors.joining(",")));for (String function : functions) {if(!getBuiltInFunctions().contains(function)) {System.err.println(String.format("%s 函数不存在", function));return false;}}return true;} catch (Exception e) {System.err.println(e.getMessage());return false;}}/*** 自定义监听器*/private static class ParseErrorListener extends BaseErrorListener {@Overridepublic void syntaxError(Recognizer<?, ?> recognizer,Object offendingSymbol,int line,int charPositionInLine,String msg,RecognitionException e) {throw new ParseCancellationException(String.format("Line %d, Column %d: %s",line, charPositionInLine + 1, msg));}}/*** 收集SQL中函数名*/private static class FunctionNameCollector extends SqlBaseBaseListener {private final List<String> functions;public FunctionNameCollector(List<String> functions) {this.functions = functions;}@Overridepublic void enterFunctionCall(SqlBaseParser.FunctionCallContext ctx) {String funcName = ctx.functionName().getText().toUpperCase();functions.add(funcName);}}/*** 获取spark sql 允许使用的内置函数* @return*/private static List<String> getBuiltInFunctions() {List<String> functionList = new ArrayList<>();try {// 反射获取 FunctionRegistry 类// Class<?> functionsClass = Class.forName("org.apache.spark.sql.functions");Method[] methods = functions.class.getMethods();// 过滤出返回类型为Column的静态方法(即内置函数)for (Method method : methods) {if (method.getReturnType().equals(Column.class) &&java.lang.reflect.Modifier.isStatic(method.getModifiers())) {functionList.add(method.getName());}}functionList = functionList.stream().distinct().map(s -> s.toUpperCase()).collect(Collectors.toList());return functionList;} catch (Exception e) {System.err.println("反射调用失败: " + e.getMessage());}return Collections.emptyList();}
}
/*** 关键字转大写,antlr 有严格的大小写区分*/
class UpperCaseCharStream extends ANTLRInputStream {public UpperCaseCharStream(String input) {super(input);}@Overridepublic int LA(int i) {int c = super.LA(i);return c == CharStream.EOF ? c : Character.toUpperCase((char) c);}
}

3. 测试

    public static void main(String[] args) {System.out.println(validateSyntax("selec "));System.out.println("-------------------------------------------------");System.out.println(validateSyntax("select m "));System.out.println("-------------------------------------------------");System.out.println(validateSyntax("SELECT m FROM"));System.out.println("-------------------------------------------------");System.out.println(validateSyntax("selec m FROM x.xx"));System.out.println("-------------------------------------------------");System.out.println(validateSyntax("SELECT * FROM x.xx"));System.out.println("-------------------------------------------------");System.out.println(validateSyntax("""select m  from xx.xxxwhere a = MAX(bi_dt) and b = DATE_ADD(DATE_FORMAT(dat_parse('20250101' ,'yyyyMMdd') ,'yyyy-MM-dd') ,2)and c = 'c'"""));System.out.println("-------------------------------------------------");System.out.println(validateSyntax(" select m  from xx.xxx where a ="));System.out.println("-------------------------------------------------");System.out.println(validateSyntax(" select m  from xx.xxx where a = a b="));System.out.println("-------------------------------------------------");}//输出:
sql: selec 
Line 1, Column 1: no viable alternative at input 'selec'
false
-------------------------------------------------
sql: select m 
true
-------------------------------------------------
sql: SELECT m FROM
true
-------------------------------------------------
sql: selec m FROM x.xx
Line 1, Column 1: no viable alternative at input 'selec'
false
-------------------------------------------------
sql: SELECT * FROM x.xx
true
-------------------------------------------------
sql: select m  from xx.xxxwhere a = MAX(bi_dt) and b = DATE_ADD(DATE_FORMAT(dat_parse('20250101' ,'yyyyMMdd') ,'yyyy-MM-dd') ,2)and c = 'c'
sql 中的函数:MAX,DATE_ADD,DATE_FORMAT,DAT_PARSE
DAT_PARSE 函数不存在
false
-------------------------------------------------
sql:  select m  from xx.xxx where a =
Line 1, Column 31: no viable alternative at input '<EOF>'
false
-------------------------------------------------
sql:  select m  from xx.xxx where a = a b=
null
false
-------------------------------------------------

4. 基本的语法校验没有问题,其中还是有一些错误校验,比如,SELECT m FROM  这个sql ,应该校验不通过,from 后面没有表或者子查询,这种是一个很明显的错误,没有校验出来,后面再优化。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/34817.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【C++】 —— 笔试刷题day_6

刷题day_6&#xff0c;继续加油哇&#xff01; 今天这三道题全是高精度算法 一、大数加法 题目链接&#xff1a;大数加法 题目解析与解题思路 OK&#xff0c;这道题题目描述很简单&#xff0c;就是给我们两个字符串形式的数字&#xff0c;让我们计算这两个数字的和 看题目我…

redis终章

1. 缓存(cache) Redis最主要的用途&#xff0c;三个方面1.存储数据&#xff08;内存数据库&#xff09;&#xff1b;2.缓存[redis最常用的场景]&#xff1b;3.消息队列。 缓存(cache)是计算机中的⼀个经典的概念.核⼼思路就是把⼀些常⽤的数据放到触⼿可及(访问速度更快)的地⽅…

Matlab 多输入系统极点配置

1、内容简介 略 Matlab 172-多输入系统极点配置 可以交流、咨询、答疑 2、内容说明 略 3、仿真分析 略 clc close all clear A [-6.5727 1.1902 0 -53.4085;1.1902 -6.5727 0 -53.4085;0.5294 0.5294 0 17.7502;0 0 1 0]; B [1.3797 -0.2498;-0.2498 1.3797;-0.1111 -0.1…

国产编辑器EverEdit - 脚本(解锁文本编辑的无限可能)

1 脚本 1.1 应用场景 脚本是一种功能扩展代码&#xff0c;用于提供一些编辑器通用功能提供不了的功能&#xff0c;帮助用户在特定工作场景下提高工作效率&#xff0c;几乎所有主流的编辑器、IDE都支持脚本。   EverEdit的脚本支持js(语法与javascript类似)、VBScript两种编程…

Flutter 小技巧之通过 MediaQuery 优化 App 性能

许久没更新小技巧系列&#xff0c;温故知新&#xff0c;在两年半前的《 MediaQuery 和 build 优化你不知道的秘密》 我们聊过了在 Flutter 内 MediaQuery 对应 rebuild 机制&#xff0c;由于 MediaQuery 在 MaterialApp 内&#xff0c;并且还是一个 InheritedWidget &#xff0…

AI-医学影像分割方法与流程

AI医学影像分割方法与流程–基于低场磁共振影像的病灶识别 – 作者:coder_fang AI框架&#xff1a;PaddleSeg 数据准备&#xff0c;使用MedicalLabelMe进行dcm文件标注&#xff0c;产生同名.json文件。 编写程序生成训练集图片&#xff0c;包括掩码图。 代码如下: def doC…

【蓝桥杯每日一题】3.16

&#x1f3dd;️专栏&#xff1a; 【蓝桥杯备篇】 &#x1f305;主页&#xff1a; f狐o狸x 目录 3.9 高精度算法 一、高精度加法 题目链接&#xff1a; 题目描述&#xff1a; 解题思路&#xff1a; 解题代码&#xff1a; 二、高精度减法 题目链接&#xff1a; 题目描述&…

人工智能组第一次培训——deepseek本地部署和知识库的建立

deepseek本地部署的用处 减少对网络依赖性&#xff1a; 在断网环境下&#xff0c;依然可以使用预先下载的AI模型进行处理&#xff0c;避免因网络不稳定而无法完成任务。 提高响应速度&#xff1a; 数据和模型已经在本地设备上准备好&#xff0c;可以直接调用&#xff0c;不…

windows协议不再续签,华为再无windows可用,将于四月发布鸿蒙PC

大家好&#xff0c;我是国货系创始人张云泽&#xff0c;最近不少小伙伴在后台问&#xff1a;“听说Windows协议要到期了&#xff1f;我的电脑会不会变砖&#xff1f;”还有人说&#xff1a;“华为笔记本以后用不了Windows了&#xff1f;鸿蒙系统能用吗&#xff1f;”今天咱们就…

数据结构-----初始数据结构、及GDB调试

一、数据结构核心概念 相互之间存在一种或多种特定关系的数据元素的集合。 1. 数据结构定义 // 嵌入式场景示例&#xff1a;传感器网络节点结构 struct SensorNode {uint16_t node_id; // 2字节float temperature; // 4字节uint32_t timestamp; // 4字节struct Se…

HOT100(1)

目前想到的办法是暴力枚举&#xff0c;有什么更好的办法请多指教。。。。代码如下&#xff1a; 让数组第一个元素和后面的元素相加判断是否相等&#xff0c;让数组第二个元素与后面的元素相加判断是否相等&#xff0c;以此类推 /** * Note: The returned array must be mallo…

QuickAPI 和 DBAPI 谁更香?SQL生成API工具的硬核对比(一)

最近低代码开发火得不行&#xff0c;尤其是能把数据库秒变API的工具&#xff0c;简直是开发者的救星。今天咱就聊聊两款国内玩家&#xff1a;QuickAPI&#xff08;麦聪软件搞出来的低代码神器&#xff09;和 DBAPI&#xff08;开源社区的硬核作品&#xff09;。这两货都能靠SQL…

MySQL单表查询大全【SELECT】

山再高&#xff0c;往上攀&#xff0c;总能登顶&#xff1b;路再长&#xff0c;走下去&#xff0c;定能到达。 Mysql中Select 的用法 ------前言------【SELECT】0.【准备工作】0.1 创建一个库0.2 库中创建表0.3 表中加入一些数据 1.【查询全部】2.【查询指定列】2.1查询指定列…

开启云服务器ubuntu22.04的远程桌面,支持Windows远程连接 - 开启XRDP支持

效果图 环境 云服务器 Ubuntu 22.04 lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 22.04.5 LTS Release: 22.04 Codename: jammy 本地windows10 步骤 前置动作 # 远程登录 ssh rootx.x.x.x# 看看硬盘够不够空间&…

虚拟化数据恢复—重装系统服务器崩了的数据恢复过程

虚拟化数据恢复环境&故障&#xff1a; VMware虚拟化平台 vmfs文件系统 工作人员误操作重装操作系统&#xff0c;服务器崩溃。 重装系统会导致文件系统元文件被覆盖。要恢复数据&#xff0c;必须找到&提取重装系统前的文件系统残留信息&#xff0c;通过提取出来的元文件…

harmonyOS NEXT开发与前端开发深度对比分析

文章目录 1. 技术体系概览1.1 技术栈对比1.2 生态对比 2. 开发范式比较2.1 鸿蒙开发范式2.2 前端开发范式 3. 框架特性对比3.1 鸿蒙 Next 框架特性3.2 前端框架特性 4. 性能优化对比4.1 鸿蒙性能优化4.2 前端性能优化 5. 开发工具对比5.1 鸿蒙开发工具5.2 前端开发工具 6. 学习…

AI智能混剪工具:AnKo打造高效创作的利器!

AI智能混剪工具&#xff1a;AnKo打造高效创作的利器&#xff01; 随着AI技术的迅速发展&#xff0c;AI智能混剪工具逐渐成为内容创作的利器&#xff0c;尤其是AnKo&#xff0c;作为一款免费的AI创作平台&#xff0c;提供了多模型AI聚合工具平台&#xff0c;能为用户带来更高效…

【Hestia Project 数据集】美国化石燃料 CO₂ 排放数据

Hestia Project™ 是一个革命性的研究项目,旨在帮助城市更精确地量化和管理与气候变化相关的碳排放问题。该项目提供了细粒度(建筑、街道、工厂级别)的化石燃料 CO₂ 排放数据,并通过直观的三维可视化系统向公众、政策制定者、科学家和工业界提供详细的时空信息,支持碳管理…

【TCP】三次挥手,四次挥手详解--UDP和TCP协议详解

活动发起人小虚竹 想对你说&#xff1a; 这是一个以写作博客为目的的创作活动&#xff0c;旨在鼓励大学生博主们挖掘自己的创作潜能&#xff0c;展现自己的写作才华。如果你是一位热爱写作的、想要展现自己创作才华的小伙伴&#xff0c;那么&#xff0c;快来参加吧&#xff01…

传感云揭秘:边缘计算的革新力量

在当今快速发展的科技时代&#xff0c;传感云和边缘计算系统正逐渐成为人们关注的焦点。传感云作为物联网与云计算的结合体&#xff0c;通过虚拟化技术将物理节点转化为多个服务节点&#xff0c;为用户提供高效、便捷的服务。而边缘计算则是一种靠近数据源头或物端的网络边缘侧…