I'm still in the process of reducing my problem down to a minimal test case, but it's sufficiently annoying and difficult to track down that I thought I'd throw up a first posting to see if anyone else in the Hibernate community had encountered it yet, and if so, if they'd found a workaround.
Something in Mac OS X 10.4.1's JDKs breaks HQL. A chunk of code like
Code:
return getHibernateTemplate().find(
"from Category c where (c.deal = ? or c.type != ?) and c.name = ? and c.parent is null and c.id != ?",
new Object[] { deal, CategoryType.CUSTOM.toInteger(), name, id });
where
c.deal is a mapped entity,
c.type is an Integer,
c.name is a String, and
c.id is a Long, causes PostgreSQL to produce the following output in its log:
Code:
ERROR: operator does not exist: integer = bytea
HINT: No operator matches the given name and argument type(s). You may need to add explicit type casts.
It looks like either Hibernate or JDBC are trying to put in a serialized representation of the class rather than the properly cast parameter value, but that's just a guess based on the fact that
bytea is a blob type in PostgreSQL. Mapped entities aren't the only culprits, either – dates and other composite types are getting similarly munged.
The affected code worked flawlessly under Mac OS X 10.3.9's JDK (also a build of JDK 1.4.2) two weeks ago, but a crashed hard drive and a broken backup forced me to move to 10.4.1. I assumed it was a database bug at first, but three different versions of PostgreSQL (7.3.3, 7.4.8, 8.0.3) all exhibited the same problem. I also tried switching between J2SE 1.4.2 (both the build distributed with Mac OS X 10.4 and the new J2SE 1.4.2R2DP1 released by Apple Developer Connection on July 6) and the Apple Developer Preview of J2SE 1.5.0, which also didn't fix it. However, tarring up the compiled code and moving it to a Debian GNU/Linux box running the Blackdown JDK (and using the database on my laptop) worked just fine. All of the libraries and drivers (including the PostgreSQL JDBC driver) are contained in the WAR I was moving around.
Does this ring any bells for anyone? I've already filed a bug report with Apple, and spent a good few hours inside the debugger trying to figure out where things are getting messed up, but it's still eluding me. I don't think this is actually a Hibernate bug, but since I can't use my primary development machine until I figure out what's going on here, I'm casting a wide net. Any help would be gratefully appreciated.
Hibernate version: Hibernate 2.1.8
Mapping documents:For the
Category class:
Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<hibernate-mapping>
<class name="com.foo.model.process.Category" table="category" dynamic-update="false"
dynamic-insert="true">
<id name="id" column="_id" type="long" unsaved-value="null">
<generator class="sequence">
<param name="sequence">seq_category</param>
</generator>
</id>
<version name="version" column="_version" type="long"/>
<property name="dateCreated" type="com.foo.util.Timestamp" update="true"
insert="true" column="_date_created"/>
<property name="dateModified" type="com.foo.util.Timestamp" update="true"
insert="true" column="_date_modified"/>
<many-to-one name="deal" column="_id_deal" class="com.foo.model.domain.Deal"
cascade="none" not-null="false"/>
<property name="name" type="string" update="true" insert="true" column="title"/>
<property name="type" type="com.foo.dao.hibernate.type.CategoryTypeUserType" update="true"
insert="true" column="type"/>
<many-to-one name="parent" column="parent_id"
class="com.foo.model.process.Category" cascade="none" not-null="false"/>
</class>
</hibernate-mapping>
For the
Deal class:
Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<hibernate-mapping>
<class name="com.foo.model.domain.Deal" table="deal" dynamic-update="false"
dynamic-insert="true">
<id name="id" column="_id" type="long" unsaved-value="null">
<generator class="sequence">
<param name="sequence">seq_deal</param>
</generator>
</id>
<version name="version" column="_version" type="long"/>
<property name="dateCreated" type="com.foo.util.Timestamp" update="true"
not-null="true" insert="true" column="_date_created"/>
<property name="dateModified" type="com.foo.util.Timestamp" update="true"
not-null="true" insert="true" column="_date_modified"/>
<many-to-one name="creatorUser" column="_id_user_creator" not-null="false"
class="com.foo.model.user.User" cascade="none"/>
<many-to-one name="creatorRole" column="_id_role_creator" not-null="false"
class="com.foo.model.auth.TitleRoleImpl" cascade="none"/>
<many-to-one name="modifierUser" column="_id_user_modifier" not-null="false"
class="com.foo.model.user.User" cascade="none"/>
<many-to-one name="modifierRole" column="_id_role_modifier" not-null="false"
class="com.foo.model.auth.TitleRoleImpl" cascade="none"/>
<property name="state" type="com.foo.dao.hibernate.type.StateUserType"
update="true" insert="true" column="_state"/>
<property name="name" type="string" unique="true" update="true" insert="true"
column="name"/>
<many-to-one name="address" column="address" not-null="false"
class="com.foo.model.address.Address" cascade="all"/>
<many-to-one name="client" column="client" not-null="true"
class="com.foo.model.client.Client" cascade="none"/>
<set name="sharedRoles" lazy="true" inverse="true" cascade="all">
<key column="_id_deal"/>
<one-to-many class="com.foo.model.auth.SharedRoleImpl"/>
</set>
</class>
</hibernate-mapping>
Code between sessionFactory.openSession() and session.close():If I can come up with a short enough reduction, I'll post it here.
Full stack trace of any exception that occurs:Code:
org.springframework.jdbc.BadSqlGrammarException: Hibernate operation: Could not execute query; bad SQL grammar []; nested exception is java.sql.SQLException: ERROR: operator does not exist: integer = bytea
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:1471)
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1256)
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:175)
at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:388)
at org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:329)
at org.postgresql.jdbc2.AbstractJdbc2Statement.executeQuery(AbstractJdbc2Statement.java:239)
at org.apache.commons.dbcp.DelegatingPreparedStatement.executeQuery(DelegatingPreparedStatement.java:92)
at net.sf.hibernate.impl.BatcherImpl.getResultSet(BatcherImpl.java:89)
at net.sf.hibernate.loader.Loader.getResultSet(Loader.java:880)
at net.sf.hibernate.loader.Loader.doQuery(Loader.java:273)
at net.sf.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:138)
at net.sf.hibernate.loader.Loader.doList(Loader.java:1063)
at net.sf.hibernate.loader.Loader.list(Loader.java:1054)
at net.sf.hibernate.hql.QueryTranslator.list(QueryTranslator.java:854)
at net.sf.hibernate.impl.SessionImpl.find(SessionImpl.java:1554)
at net.sf.hibernate.impl.QueryImpl.list(QueryImpl.java:49)
at org.springframework.orm.hibernate.HibernateTemplate$19.doInHibernate(HibernateTemplate.java:647)
at org.springframework.orm.hibernate.HibernateTemplate.execute(HibernateTemplate.java:314)
at org.springframework.orm.hibernate.HibernateTemplate.find(HibernateTemplate.java:633)
at org.springframework.orm.hibernate.HibernateTemplate.find(HibernateTemplate.java:625)
at com.foo.dao.hibernate.process.CategoryDaoImpl.findDups(CategoryDaoImpl.java:149)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:324)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:288)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:155)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:122)
at com.foo.service.profiler.ProfilerAdvice.invoke(ProfilerAdvice.java:50)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:144)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:174)
at $Proxy17.findDups(Unknown Source)
at com.foo.service.process.CategoryServiceImpl.countDuplicates(CategoryServiceImpl.java:163)
at com.foo.service.process.CategoryServiceImpl.save(CategoryServiceImpl.java:113)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:324)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:288)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:155)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:122)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:57)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:144)
at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:53)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:144)
at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:53)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:144)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:174)
at $Proxy18.save(Unknown Source)
at com.foo.service.process.CategoryBootstrapper.updateEntity(CategoryBootstrapper.java:99)
at com.foo.service.StandardDBBootstrapper.doBootstrap(StandardDBBootstrapper.java:79)
at com.foo.service.BootstrapperBase.bootstrap(BootstrapperBase.java:35)
at com.foo.service.BootstrapRunner.run(BootstrapRunner.java:49)
at com.foo.util.StartupListener.onApplicationEvent(StartupListener.java:33)
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:68)
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:218)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:315)
at org.springframework.context.support.FileSystemXmlApplicationContext.<init>(FileSystemXmlApplicationContext.java:82)
at org.springframework.context.support.FileSystemXmlApplicationContext.<init>(FileSystemXmlApplicationContext.java:67)
at org.springframework.context.support.FileSystemXmlApplicationContext.<init>(FileSystemXmlApplicationContext.java:58)
at com.foo.test.AppContextTestSetup.setUp(AppContextTestSetup.java:46)
at com.foo.test.DatabaseTestSetup.setUp(DatabaseTestSetup.java:26)
at junit.extensions.TestSetup$1.protect(TestSetup.java:18)
at junit.framework.TestResult.runProtected(TestResult.java:124)
at junit.extensions.TestSetup.run(TestSetup.java:23)
at junit.framework.TestSuite.runTest(TestSuite.java:208)
at junit.framework.TestSuite.run(TestSuite.java:203)
at junit.textui.TestRunner.doRun(TestRunner.java:116)
at junit.textui.TestRunner.doRun(TestRunner.java:109)
at junit.textui.TestRunner.run(TestRunner.java:72)
at com.foo.test.TextTestRunner.run(TextTestRunner.java:17)
at com.foo.test.ManualTests.main(ManualTests.java:35)
Name and version of the database you are using:PostgreSQL 7.3.3 (pg73jdbc3.jar)
PostgreSQL 7.4.8 (pg74.216.jdbc3.jar)
PostgreSQL 8.0.2 (pg80.310.jdbc3.jar)
The generated SQL (show_sql=true):Code:
select category0_._id as _id, category0_._version as _version, category0_._date_created as _date_cr3_, category0_._date_modified as _date_mo4_, category0_._id_deal as _id_deal, category0_.title as title, category0_.type as type, category0_.parent_id as parent_id from category category0_ where ((category0_._id_deal=? )or(category0_.type!=? ))and(category0_.title=? )and(category0_.parent_id is null )and(category0_._id!=? )
Debug level Hibernate log excerpt:Code:
2005-07-07 02:09:55,014 DEBUG [main] hibernate.impl.BatcherImpl - preparing statement
2005-07-07 02:09:55,014 DEBUG [main] hibernate.type.SerializableType - binding null to parameter: 1
2005-07-07 02:09:55,015 DEBUG [main] hibernate.type.IntegerType - binding '0' to parameter: 2
2005-07-07 02:09:55,015 DEBUG [main] hibernate.type.StringType - binding 'Physical' to parameter: 3
2005-07-07 02:09:55,015 DEBUG [main] hibernate.type.LongType - binding '1' to parameter: 4
2005-07-07 02:09:55,032 ERROR [main] hibernate.util.JDBCExceptionReporter - ERROR: operator does not exist: integer = bytea
2005-07-07 02:09:55,038 DEBUG [main] hibernate.impl.BatcherImpl - done closing: 0 open PreparedStatements, 0 open ResultSets
2005-07-07 02:09:55,038 DEBUG [main] hibernate.impl.BatcherImpl - closing statement
2005-07-07 02:09:55,040 ERROR [main] hibernate.util.JDBCExceptionReporter - ERROR: operator does not exist: integer = bytea
2005-07-07 02:09:55,203 DEBUG [main] hibernate.transaction.JDBCTransaction - rollback
2005-07-07 02:09:55,206 DEBUG [main] hibernate.impl.SessionImpl - transaction completion
2005-07-07 02:09:55,206 DEBUG [main] hibernate.transaction.JDBCTransaction - re-enabling autocommit
2005-07-07 02:09:55,210 FATAL [main] foo.test.AppContextTestSetup - app context initialization failed