文档章节

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

李玉珏
 李玉珏
发布于 2015/03/05 13:53
字数 620
阅读 2300
收藏 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 );
                }
            }
        }
    }

 

 

© 著作权归作者所有

共有 人打赏支持
李玉珏

李玉珏

粉丝 279
博文 60
码字总数 102475
作品 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 ) 这段代码会进行转义处理
[笔记]将系统的数据库从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数据类型-数据类型简介和布尔类型

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

白豆腐徐长卿
2017/11/06
0
0
PostgreSQL和MySQL

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

悟道之客
05/04
0
0
PostgreSQL 数据库初体验

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

高强
2015/10/15
0
0
PostgreSQL--数据类型格式化函数

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

莫显辉
01/11
0
0

没有更多内容

加载失败,请刷新页面

加载更多

play framework 如何支持多数据源

有段时间没有写博客了,但今天又写一篇了,主要是因为这事有一丝自己的思考和动手实践,所以就记录下来了。 现有的问题: play 1.2.4 两台数据库服务器,但是play1.2.4 并不支持同时连接两台...

tuerqidi
17分钟前
0
0
Mysql only_full_group_by解析

查看当前数据库模式: select @@sql_mode; 原因: mysql 5.7中的sql_mode的值中包含'ONLY_FULL_GROUP_BY'; 处理:执行以下SQL set GLOBAL sql_mode ='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,N......

年轻的中年大叔
18分钟前
0
0
防止表单重复提交

1:前端方式(治标不治本) $("#admin-role-save").click(function(){//admin-role-save为submit的idvar ts=$(this);var ts_old_val=ts.val();ts.val("提交中....");ts.att...

uug
18分钟前
0
0
保持屏幕常亮

getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); 在act的created方法中调用即可,一般是播放视频的时候......

Carbenson
18分钟前
0
0
智能合约实施指南

与区块链技术一样,智能合约在商业领域也非常有价值。 为了让我们的读者彻底了解智能合约是什么以及它们如何影响现代商业的交易方式,我们准备了本指南。 集中商业模式正在给去中心化的模式让...

geek12345
21分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部