jsqlparser无法解析 "if" "IF" "="等MySQL语法

背景:Mybatis plus 提供 了一个sql 解析器抽象类AbstractJsqlParser

    /**
     * 解析 SQL 方法
     *
     * @param metaObject 元对象
     * @param sql        SQL 语句
     * @return SQL 信息
     */

    @Override
    public SqlInfo parser(MetaObject metaObject, String sql) {
        if (this.allowProcess(metaObject)) {
            try {
                logger.debug("Original SQL: " + sql);
                // fixed github pull/295
                StringBuilder sqlStringBuilder = new StringBuilder();
                Statements statements = CCJSqlParserUtil.parseStatements(sql);
                int i = 0;
                for (Statement statement : statements.getStatements()) {
                    if (null != statement) {
                        if (i++ > 0) {
                            sqlStringBuilder.append(';');
                        }
                        sqlStringBuilder.append(this.processParser(statement).getSql());
                    }
                }
                if (sqlStringBuilder.length() > 0) {
                    return SqlInfo.newInstance().setSql(sqlStringBuilder.toString());
                }
            } catch (JSQLParserException e) {
                throw ExceptionUtils.mpe("Failed to process, please exclude the tableName or statementId.\n Error SQL: %s", e, sql);
            }
        }
        return null;
    }

方法里面 Statements statements = CCJSqlParserUtil.parseStatements(sql); 使用了JSQLParser对原始sql 进行解析,本以为一切都很完美的进行,结果调试的时候发现发生几个解析异常
异常一:

Original SQL: 
SELECT
        1 as query_type,
        a.id as bill_id,
        a.bill_code,
        td.trade_money as bill_money,
        td.trade_money,
        a.inputer_name,
        t.trade_type,
        t.status AS trade_status,
        if(a.status=2||a.status=4,1,0) as expired,
        a.status AS asset_status,
        a.output_time,
        t.create_time AS trade_date,
        a.expire_date,
        ABS(TIMESTAMPDIFF(DAY, a.output_time, a.expire_date)) AS days,
        t.trade_no,
        t.creator_id
        FROM asset AS a
        JOIN trade_detail AS td
        ON a.id = td.pre_bill_id
        JOIN trade AS t
        ON td.trade_no = t.trade_no
         WHERE t.trade_type = 1
            AND t.status IN (2, 3, 4, 5)
            AND a.outputer_id = ?
                and a.bill_code = ?
        and a.output_time >= ?
        and a.output_time <=?
        and a.expire_date >=?
        and a.expire_date <=?
        and t.create_time >=?
        and t.create_time <=?
        and t.trade_no = ?
        and a.status in (0,1,3,5) 
        order by output_time asc
when useing jsqlparser parser this sql then throw a exception:Encountered unexpected token: "if" "IF"

Caused by: net.sf.jsqlparser.JSQLParserException
    at net.sf.jsqlparser.parser.CCJSqlParserUtil.parseStatements(CCJSqlParserUtil.java:137)
    at com.baomidou.mybatisplus.core.parser.AbstractJsqlParser.parser(AbstractJsqlParser.java:60)
    ... 47 more
Caused by: net.sf.jsqlparser.parser.ParseException: Encountered unexpected token: "if" "IF"
    at line 10, column 9.

Was expecting one of:

    "!"
    "("
    "*"
    "+"
    "-"
    "?"
    "@"
    "@@"
    "ACTION"
    "ANY"
    "BYTE"
    "CASCADE"
    "CASE"
    "CAST"
    "CHANGE"
    "CHAR"
    "CHARACTER"
    "COLUMN"
    "COLUMNS"
    "COMMENT"
    "COMMIT"
    "DESCRIBE"
    "DO"
    "DUPLICATE"
    "ENABLE"
    "END"
    "EXTRACT"
    "FALSE"
    "FIRST"
    "FN"
    "FOLLOWING"
    "GROUP_CONCAT"
    "INDEX"
    "INSERT"
    "INTERVAL"
    "ISNULL"
    "KEY"
    "LAST"
    "MATERIALIZED"
    "NEXTVAL"
    "NO"
    "NOT"
    "NULL"
    "NULLS"
    "OPEN"
    "OVER"
    "PARTITION"
    "PATH"
    "PERCENT"
    "PRECISION"
    "PRIMARY"
    "PRIOR"
    "RANGE"
    "READ"
    "REPLACE"
    "ROW"
    "ROWS"
    "SEPARATOR"
    "SESSION"
    "SIBLINGS"
    "SIZE"
    "START"
    "TABLE"
    "TEMP"
    "TEMPORARY"
    "TOP"
    "TRUE"
    "TRUNCATE"
    "TYPE"
    "UNSIGNED"
    "VALUE"
    "VALUES"
    "XML"
    "ZONE"
    "{d"
    "{t"
    "{ts"
    "~"
    <K_DATETIMELITERAL>
    <K_DATE_LITERAL>
    <K_TIME_KEY_EXPR>
    <S_CHAR_LITERAL>
    <S_DOUBLE>
    <S_HEX>
    <S_IDENTIFIER>
    <S_LONG>
    <S_QUOTED_IDENTIFIER>

if.png

异常二:

Original SQL:
SELECT
        b2.id AS node_id,
        a.outputer_id,
        a.outputer_name,
        a.output_time as output_date,
        a.factor_id,
        b2.owner_id,
        b2.owner_name,
        t.inputer_id AS pledge_ent_id,
        t.inputer_name AS pledge_ent_name,
        b2.bill_code,
        b2.bill_money,
        b.root_id,
        td2.bill_id AS parent,
        b2.create_time AS owner_date,
        td2.trade_no,
        b2.bill_level,
        t.trade_type,
        t.status AS trade_status,
        (select pledge_type from bill_pledge_operation s where s.trade_no =  t.trade_no AND s.STATUS = 1 ORDER BY create_time desc limit 1) AS pledge_type,
        (select date_format(create_time,'%Y-%m-%d') from bill_pledge_operation s where s.trade_no =  t.trade_no AND s.STATUS = 1 ORDER BY create_time desc limit 1) AS unbind_pledge_date,
        tpe.pledge_date,
        (t.outputer_id  =  b2.owner_id) AS is_remain
        FROM
        trade_detail AS td
        JOIN bill AS b
        ON b.id = td.bill_id
        JOIN bill AS b2
        ON b2.root_id = b.root_id
        JOIN trade_detail AS td2
        ON td2.pre_bill_id = b2.id
        JOIN trade AS t
        ON t.trade_no = td2.trade_no
        JOIN asset AS a
        ON a.id = b.root_id
        LEFT JOIN trade_pledge_ext AS tpe
        ON tpe.trade_no = td2.trade_no
         WHERE  td.bill_code = ?
                AND td.trade_no = ?
            AND t.status in (4,5) 
        ORDER BY b2.bill_level
        
when useing jsqlparser parser this sql then throw a exception:Encountered unexpected token: "=" "="

Caused by: net.sf.jsqlparser.JSQLParserException
    at net.sf.jsqlparser.parser.CCJSqlParserUtil.parseStatements(CCJSqlParserUtil.java:137)
    at com.baomidou.mybatisplus.core.parser.AbstractJsqlParser.parser(AbstractJsqlParser.java:60)
    ... 61 more
Caused by: net.sf.jsqlparser.parser.ParseException: Encountered unexpected token: "=" "="
    at line 23, column 25.

Was expecting one of:

    "&"
    ")"
    "::"
    "<<"
    ">>"
    "COLLATE"
    "["
    "^"
    "|"
==.png

由上面异常信息可知 JSQLParser 不支持上面两个语法;

解决方法:
1、针对 if("","","")函数 可以使用case when 代替 ;
2、针对与 = 判断两个数值是否相等其实个人不太愿意使用 case when 来实现,代码太多,然后想到了使用 ^ 异或运算如果两个整型值相等返回0 ,跟= 返回值正好相反,这个使用方式根据自己业务确定;
对于JSQLParser 不支持"if" "IF" "=" 也在GitHub 留了issues 期待各位大佬提出更好的解决方案;
作者建议 if(a.status=2||a.status=4,1,0) as expired, 修改为if(a.status=2 or a.status=4,1,0) as expired,
高版本已经兼容;
Encountered unexpected token: "if" "IF" "=" · Issue #1648 · JSQLParser/JSqlParser (github.com)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,744评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,505评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,105评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,242评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,269评论 6 389
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,215评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,096评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,939评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,354评论 1 311
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,573评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,745评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,448评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,048评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,683评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,838评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,776评论 2 369
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,652评论 2 354

推荐阅读更多精彩内容