最近在用jsqlparser4.5解析SQL时遇到了一个问题,

如下是apache phoenix的UPSERT语句

UPSERT INTO TEST (ID, COUNTER) VALUES (123, 0) ON DUPLICATE KEY IGNORE

ON DUPLICATE KEY IGNORE即为当主键重复时忽略,这与MySQL的IGNORE语法不同:

INSERT IGNORE INTO TEST (ID, COUNTER) VALUES (123, 0)

jsqlparser目前的最新版本支持UPSERT语法,也支持ON DUPLICATE KEY UPDATE,但不支持ON DUPLICATE KEY IGNORE

所以jsqlparser解析SQL遇到ON DUPLICATE KEY IGNORE语法时解析器会报错 expect "UPDATE"

JSqlParserCC.jjt

为了解决这个问题我翻了jsqlparser的源码,找到了jsqlparser的语法定义文件(JSqlParserCC.jjt),是基于JavaCC实现的。

JSqlParserCC.jjt文件的位置在:jsqlparser/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt

打开它在1635行就能找到UPSERT语句分析ON DUPLICATE KEY UPDATE语法的位置,
为了看懂语法定义文件(JSqlParserCC.jjt),我又恶补了一下JavaCC的语法,基本上能看懂了。
原来的代码是

    [ <K_ON> <K_DUPLICATE> <K_KEY> <K_UPDATE>{ useDuplicate = true; }tableColumn=Column() "=" exp=SimpleExpression(){duplicateUpdateColumns = new ArrayList<Column>();duplicateUpdateExpressionList = new ArrayList<Expression>();duplicateUpdateColumns.add(tableColumn);duplicateUpdateExpressionList.add(exp);}("," tableColumn=Column() "=" exp=SimpleExpression(){ duplicateUpdateColumns.add(tableColumn);duplicateUpdateExpressionList.add(exp); } )*]

修改为如下:

    [<K_ON> <K_DUPLICATE> <K_KEY> (<K_IGNORE>{ modifierIgnore = true; }|<K_UPDATE>{ useDuplicate = true; }tableColumn=Column() "=" exp=SimpleExpression(){duplicateUpdateColumns = new ArrayList<Column>();duplicateUpdateExpressionList = new ArrayList<Expression>();duplicateUpdateColumns.add(tableColumn);duplicateUpdateExpressionList.add(exp);}("," tableColumn=Column() "=" exp=SimpleExpression(){ duplicateUpdateColumns.add(tableColumn);duplicateUpdateExpressionList.add(exp); } )*)]

即允许 ON DUPLICATE后为IGNOREUPDATE,为IGNORE时将modifierIgnore 设置为true

modifierIgnore为新增加的变量定义,后续会用到。

如下图为主要修改的前后对比

Upsert.java

不仅要修改语法定义文件,同时还要修改src/main/java/net/sf/jsqlparser/statement/upsert/Upsert.java,相应增加modifierIgnore字段,
完整代码参见我的码云仓库:
https://gitee.com/l0km/JSqlParser.git

【不是master分支,是gyd分支,gyd分支,gyd分支,重要的事情说三遍】

下载代码

git clone -b gyd https://gitee.com/l0km/JSqlParser.git

maven编译

cd JSqlParser
$ mvn clean install -DskipTests=true

单元测试

jsqlparser项目有比较完备的单元测试,上述修改完毕执行UPSERT语句的单元测试UpsertTest.java验证修改是否有效。
先执行原有的ON DUPLICATE KEY UPDATE语法测试,看看是否有影响

$ mvn -Dtest=UpsertTest#testUpsertDuplicate test

我在src/test/java/net/sf/jsqlparser/statement/upsert/UpsertTest.java增加了新的单元测试方法testUpsertIgnore 以验证ON DUPLICATE KEY IGNORE语法有效性。

    @Testpublic void testUpsertIgnore() throws JSQLParserException {String statement = "UPSERT INTO TEST (ID, COUNTER) VALUES (123, 0) ON DUPLICATE KEY IGNORE";Upsert upsert = (Upsert) parserManager.parse(new StringReader(statement));assertEquals("TEST", upsert.getTable().getName());assertEquals(2, upsert.getColumns().size());assertTrue(upsert.isUseValues());assertEquals("ID", upsert.getColumns().get(0).getColumnName());assertEquals("COUNTER", upsert.getColumns().get(1).getColumnName());assertEquals(2, ((ExpressionList) upsert.getItemsList()).getExpressions().size());assertEquals(123, ((LongValue) upsert.getItemsList(ExpressionList.class).getExpressions().get(0)).getValue());assertEquals(0, ((LongValue) upsert.getItemsList(ExpressionList.class).getExpressions().get(1)).getValue());assertTrue(upsert.isModifierIgnore());assertEquals(statement, "" + upsert);}

执行新增的ON DUPLICATE KEY IGNORE语法测试

$ mvn -Dtest=UpsertTest#testUpsertIgnore test

Pull Request

此问题修复已经向jsqlparser提交了Pull Request
参见 https://github.com/JSQLParser/JSqlParser/pull/1689

如果批准,就可以在下一个官方版本中更新了。

参考资料

《UPSERT》
《JavaCC》

jsqlparser:修改语法定义(JSqlParserCC.jjt)实现UPSERT支持Phoenix语法ON DUPLICATE KEY IGNORE相关推荐

  1. insert...on duplicate key update语法详解

    一.作用和使用场景 在mysql入库时,不能出现两条数据主键一致的情况,因为在两条数据的主键一致的情况下,mysql就会判定为待插入数据在数据库中存在重复数据,也就是说判断数据是否重复是根据主键来区别 ...

  2. thymeleaf模板的使用——1,thymeleaf概述|| thymeleaf 的使用方法|| 如何修改Thymeleaf的默认存放地址||Thymeleaf的相关语法

    thymeleaf模板的使用 1,thymeleaf概述 简单说, Thymeleaf 是一个跟 Velocity.FreeMarker 类似的模板引擎,它可以完全替代 JSP .相较与其他的模板引擎 ...

  3. vue-cli项目布署问题解决:空白页、静态资源文件404错误、refrenceError:promise未定义(部分浏览器不支持ES6语法)

    (前言:文章记录vue-cli项目打包使用IIS布署遇到的几个错误及解决方式) 首先简单理解webpack打包: 个人理解:项目开发中我们构建 "低耦合高内聚" 的组件/模块来代码 ...

  4. join为什么每个字符都分割了 js_为什么 webpack4 默认支持 ES6 语法的压缩?

    在专栏课程里,有位同学提到过一个很有意思的问题:"我没装 babel,js 入口里写了个箭头函数,运行 webpack 构建命令后,也成功编译了.这是为什么?".今天就带领大家一起 ...

  5. python导入模块的语法结构_python学习第五讲,python基础语法之函数语法,与Import导入模块....

    python学习第五讲,python基础语法之函数语法,与Import导入模块. 一丶函数简介 函数,就是一个代码块,这个代码块是别人写好的.我们调用就可以. 函数也可以称为方法. 1.函数语法定义 ...

  6. python运行不了control+shift+i_Python不支持 i ++ 语法的原因解析

    简要讨论为什么它不提供++作为运算符 正常情况下,当有人问起++原因而不是Python中的运算符时,这一行引起了我的注意. 如果您想知道最初的原因,则必须翻阅旧的Python邮件列表,或询问那里的某个 ...

  7. mysql批量insert bug_MySQL Bug insert into on duplicate key update 语法更新 text blob 大字段导致 MySQL crash...

    1. 背景 业务执行 SQL 导致 MySQL 进程 Crash,做故障切换后,新的主库又 Crash 了.查看 MySQL 错误日志,发现多次 Crash 时的堆栈相同,如下: Thread poi ...

  8. python显示无效语法怎么处理-Python不支持 i ++ 语法的原因解析

    简要讨论为什么它不提供++作为运算符 正常情况下,当有人问起++原因而不是Python中的运算符时,这一行引起了我的注意. 如果您想知道最初的原因,则必须翻阅旧的Python邮件列表,或询问那里的某个 ...

  9. 深入mysql ON DUPLICATE KEY UPDATE 语法的分析

    mysql "ON DUPLICATE KEY UPDATE" 语法 如果在INSERT语句末尾指定了ON DUPLICATE KEY UPDATE,并且插入行后会导致在一个UNI ...

最新文章

  1. 一个传值的问题”*”与”*”
  2. 某人想在h小时内钓到_为某人命名以重新连接到您的服务器
  3. dj鲜生-30-退出用户的登陆
  4. 十大经典排序算法详细总结 图形展示 代码示例
  5. 尝试使用Microsoft IE 7.0 Beta 1
  6. 8首次登陆与线上求助
  7. JS 字符串截取切割操作汇总
  8. compute shader
  9. android 空调遥控,安卓版万能空调遥控器
  10. aspcms标签大全
  11. iOS 手机号码验证
  12. 红米note5解锁教程_红米note手机密码忘了怎么解锁
  13. iOS中scheme详解
  14. slack 使用说明_使用Reacji自动将Slack消息移至其他渠道
  15. 咸鱼Micropython— machine库
  16. 团队作业之一:团队介绍及选题背景与意义
  17. 基于SPI的OLED显示
  18. 计算机快捷键打开程序格式,win电脑任务管理器怎么打开?6种方法助你迅速优雅的打开(含快捷键方法)...
  19. Unity3d中异形屏的适配
  20. Java依赖于抽象不依赖于具体,依赖倒置原则(Dependecy-Inversion Principle)

热门文章

  1. 【贪心】数列极差问题
  2. 混合线性模型学习笔记1
  3. php漏洞 乌云,灵活布置、可二次开发的乌云公开漏洞及知识库搜索
  4. c语言程序设计第四版乌云高娃,C语言程序设计教学课件作者第2版乌云高娃课件源程序及习题答案第4章课件.ppt...
  5. Python批量给文件改名的两种方法
  6. iOS获取设备信息和获取当前屏幕状态
  7. 【数据工具】高德地图POI数据下载工具(支持选择省市以及POI类型)
  8. 万亿规模的二手交易市场,真的是门好生意吗?
  9. B - Balala Power!
  10. dnf强化卷代码_DNF4.9日魔盒更新内容详解_全强化卷概率一览_52pk