文档章节

解决Hibernate不支持PostgreSQL中双冒号(::)的问题

李玉珏
 李玉珏
发布于 2015/03/05 13:53
字数 620
阅读 2375
收藏 2

        在PostgreSQL中,双冒号(::)的作用是类型转换,而在Hibernate中,SQL中冒号的作用是命名参数,用于SQL中命名参数的匹配,这时,当在PostgreSQL数据库环境中,正常的SQL本身包括双冒号时,通过Hibernate进行查询就会报错,这个应该是Hibernate的一个Bug,怎么解决呢,本文将给出方案。

        通过研究Hibernate的源代码,发现了问题所在,问题出在org.hibernate.engine.query.spi.ParameterParser,这个类构造方法为私有,包括若干个静态方法,无法通过扩展二次开发的方式解决,遇到这个问题的,只能自行修改Hibernate的源代码,然后编译。

        经过分析,只需要修改其中的parse方法即可,下面的代码即为修改后的代码,测试了一下,大体应该是没问题的,该问题的发现、开发、测试是在Hibernate4.2.15版本下进行的,其他版本如有问题,请开发者自行处理。

public static void parse(String sqlString, Recognizer recognizer) throws QueryException {
        boolean hasMainOutputParameter = startsWithEscapeCallTemplate( sqlString );
        boolean foundMainOutputParam = false;

        int stringLength = sqlString.length();
        boolean inQuote = false;
        for ( int indx = 0; indx < stringLength; indx++ ) {
            char c = sqlString.charAt( indx );
            if ( inQuote ) {
                if ( '\'' == c ) {
                    inQuote = false;
                }
                recognizer.other( c );
            }
            else if ( '\'' == c ) {
                inQuote = true;
                recognizer.other( c );
            }
            else if ( '\\' == c ) {
                // skip sending the backslash and instead send then next character, treating is as a literal
                recognizer.other( sqlString.charAt( ++indx ) );
            }
            else {
                if ( c == ':' ) {
                    // named parameter
                    int right = StringHelper.firstIndexOfChar( sqlString, ParserHelper.HQL_SEPARATORS_BITSET, indx + 1 );
                    int chopLocation = right < 0 ? sqlString.length() : right;
                    //增加了双冒号的处理
                    if (sqlString.charAt( indx+1 ) != ':'){
                        String param = sqlString.substring( indx + 1, chopLocation );
                        if ( StringHelper.isEmpty( param ) ) {
                            throw new QueryException(
                                    "Space is not allowed after parameter prefix ':' [" + sqlString + "]"
                            );
                        }
                        recognizer.namedParameter( param, indx );
                        indx = chopLocation - 1;
                    }else{
                        recognizer.other(c);
                        recognizer.other(c);
                        indx++;
                    }
                }
                else if ( c == '?' ) {
                    // could be either an ordinal or JPA-positional parameter
                    if ( indx < stringLength - 1 && Character.isDigit( sqlString.charAt( indx + 1 ) ) ) {
                        // a peek ahead showed this as an JPA-positional parameter
                        int right = StringHelper.firstIndexOfChar( sqlString, ParserHelper.HQL_SEPARATORS, indx + 1 );
                        int chopLocation = right < 0 ? sqlString.length() : right;
                        String param = sqlString.substring( indx + 1, chopLocation );
                        // make sure this "name" is an integral
                        try {
                            Integer.valueOf( param );
                        }
                        catch( NumberFormatException e ) {
                            throw new QueryException( "JPA-style positional param was not an integral ordinal" );
                        }
                        recognizer.jpaPositionalParameter( param, indx );
                        indx = chopLocation - 1;
                    }
                    else {
                        if ( hasMainOutputParameter && !foundMainOutputParam ) {
                            foundMainOutputParam = true;
                            recognizer.outParameter( indx );
                        }
                        else {
                            recognizer.ordinalParameter( indx );
                        }
                    }
                }
                else {
                    recognizer.other( c );
                }
            }
        }
    }

 

 

© 著作权归作者所有

共有 人打赏支持
李玉珏

李玉珏

粉丝 298
博文 63
码字总数 106838
作品 0
沈阳
技术主管
私信 提问
加载中

评论(6)

a
ayashaki

引用来自“liyuj”的评论

引用来自“ayashaki”的评论

引用来自“Tengern”的评论

为什么不进行转义呐,使用“\\:\\:”。 else if ( '\\' == c ) 这段代码会进行转义处理
为什么我转义了还是报错。。 Space is not allowed after parameter prefix ':' [select @rownum\:=@rownum+1 AS rownum 用的hibernate3.3.2

我这个是在hibernate4上代码,3上是怎么实现的,我不知道,你可以下个代码跟踪下
3估计没有,最后还是选择换sql语句了。。。
李玉珏
李玉珏

引用来自“ayashaki”的评论

引用来自“Tengern”的评论

为什么不进行转义呐,使用“\\:\\:”。 else if ( '\\' == c ) 这段代码会进行转义处理
为什么我转义了还是报错。。 Space is not allowed after parameter prefix ':' [select @rownum\:=@rownum+1 AS rownum 用的hibernate3.3.2

我这个是在hibernate4上代码,3上是怎么实现的,我不知道,你可以下个代码跟踪下
a
ayashaki

引用来自“Tengern”的评论

为什么不进行转义呐,使用“\\:\\:”。 else if ( '\\' == c ) 这段代码会进行转义处理
为什么我转义了还是报错。。 Space is not allowed after parameter prefix ':' [select @rownum\:=@rownum+1 AS rownum 用的hibernate3.3.2
李玉珏
李玉珏

引用来自“Tengern”的评论

为什么不进行转义呐,使用“\\:\\:”。 else if ( '\\' == c ) 这段代码会进行转义处理

其实在sql里,还可以用cast函数,但是都不太好,增加了开发人员的工作量,当时用双冒号,主要是用了pg的动态类型特性,到处转义的话,代码看上去不太干净
李玉珏
李玉珏

引用来自“Tengern”的评论

为什么不进行转义呐,使用“\\:\\:”。 else if ( '\\' == c ) 这段代码会进行转义处理

嗯?让开发人员写两个反斜杠?这不好吧?
好像就pg有这个双冒号的写法吧?
Tengern
Tengern
为什么不进行转义呐,使用“\\:\\:”。 else if ( '\\' == c ) 这段代码会进行转义处理
PostgreSQL数据类型-数据类型简介和布尔类型

PostgreSQL相对于其他数据库,支持数据类型很多。 PostgreSQL数据类型有布尔类型、整数类型、字符串类型、二进制字符串类型、位串类型、时间与日期类型、枚举类型、几何类型、网络地址类型、...

白豆腐徐长卿
2017/11/06
0
0
[笔记]将系统的数据库从MySQL 5.5迁移到PostgreSQL 9.1

环境 Windows Server 2003 x64 简体中文, MySQL 5.5 (UTF8编码), PostgreSQL 9.1.4-1 (UTF8编码) Spring 3.0.7, Struts 2.3.4, Hibernate 3.5.5 从MySQL迁移到PostgreSQL ------------------......

leeoo
2012/07/22
0
3
PostgreSQL和MySQL

翻译来源:https://www.2ndquadrant.com/en/postgresql/postgresql-vs-mysql/ PostgreSQL和MySQL 之间有着根本的区别。在评估两个系统之间的差异和折衷之后,必须做出明智的决定。 我们已经提...

悟道之客
05/04
0
0
PostgreSQL--数据类型格式化函数

数据类型格式化函数 主要转换方式为: 在转换过程中可以使用对结果进行限制,具体使用可见PostgreSQL 9.3.1 中文手册的章 10. 类型转换 新发现 有双冒号()这种操作,可以直接进行格式化,比如...

莫显辉
01/11
0
0
PostgreSQL 数据库初体验

高强,“DBA+济南群”联合发起人。现就职于山东华鲁科技发展股份有限公司。擅长Oracle、AIX、Linux、PostgreSQL和DB2等产品的实施、运维和故障处理。曾是一名存储工程师,负责实施存储、双机...

高强
2015/10/15
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Git —— 创建版本库和提交回退版本

二、 创建版本库 版本库又叫做仓库,简单理解就是一个目录,这个目录里面所有的文件都可以被Git管理起来,每个文件的修改、删除,Git都可以跟踪,便于追踪历史与还原。找到一个合适的位置,创...

lwenhao
29分钟前
3
0
guava cache使用介绍

今天在项目中发现大量使用guava cache提供缓存,觉得不错。 jvm堆大小为5G /** * * 占用JVM内存,内部数据结构类似于ConcurrentHashMap。因为JVM堆大小的限制,guava cac...

jack_peng
34分钟前
3
0
崛起于Springboot2.X之投票活动排行榜项目

简介:投票活动,用户只能一天投票一次,然后对参与投票的项目进行实时的排行功能。 架构:redis+mysql+springboot2.0.3+mybatis 不懂可以私信我哦 1、数据库建表 CREATE TABLE `t_dtb_prod...

木九天
42分钟前
2
0
logback源码分析-2、appender解析

源码基于logback 1.1.2 logback.xml文件内容如下 <?xml version="1.0"?><configuration scan="true" scanPeriod="30 seconds"> <property name="fileDir" value="/export/log/ingore......

924411018
48分钟前
2
0
【HAVENT原创】NodeJS 两个模块进行 RSA 加密解密(匹配Java RSA)

业务逻辑需要使用 NodeJS 进行公钥加密传输给 Java 后端进行私钥解密,但是默认 NodeJS 使用的 RSA padding 模式与 Java 的不一致,所以需要配置。 不啰嗦,上代码,分别用 crypto 和 node-r...

HAVENT
55分钟前
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部