property names beginning with underscores cause Hibernate to generate invalid aliases

Description

Hibernate is generating invalid SQL (for Oracle) for collections that are stored in fields with names that start with underscores.

In this SQL:
Hibernate: select tags0.SIMPLE_OBJECT_ID as SIMPLE1_0_, tags0.TAG as TAG0_ from SIMPLE_OBJECT_TAG tags0 where tags0.SIMPLE_OBJECT_ID=?

an alias called "tags0" is created for the collection table. Unfortunately, Oracle does not allow non-alphabetic characters for the first character in an alias.

Here's the stacktrace:
Hibernate: select tags0.SIMPLE_OBJECT_ID as SIMPLE1_0_, tags0.TAG as TAG0_ from SIMPLE_OBJECT_TAG tags0 where tags0.SIMPLE_OBJECT_ID=?
WARN JDBCExceptionReporter 20060822-011120.817 - SQL Error: 911, SQLState: 42000
ERROR JDBCExceptionReporter 20060822-011120.818 - ORA-00911: invalid character

INFO DefaultLoadEventListener 20060822-011120.820 - Error performing load command
org.hibernate.exception.SQLGrammarException: could not initialize a collection: [SimpleObject._tags#1]
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:67)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
at org.hibernate.loader.Loader.loadCollection(Loader.java:1926)
at org.hibernate.loader.collection.CollectionLoader.initialize(CollectionLoader.java:36)
at org.hibernate.persister.collection.AbstractCollectionPersister.initialize(AbstractCollectionPersister.java:520)
at org.hibernate.event.def.DefaultInitializeCollectionEventListener.onInitializeCollection(DefaultInitializeCollectionEventListener.java:60)
at org.hibernate.impl.SessionImpl.initializeCollection(SessionImpl.java:1676)
at org.hibernate.collection.AbstractPersistentCollection.forceInitialization(AbstractPersistentCollection.java:454)
at org.hibernate.engine.StatefulPersistenceContext.initializeNonLazyCollections(StatefulPersistenceContext.java:755)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:229)
at org.hibernate.loader.Loader.loadEntity(Loader.java:1785)
at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:47)
at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:41)
at org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:2730)
at org.hibernate.event.def.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:365)
at org.hibernate.event.def.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:346)
at org.hibernate.event.def.DefaultLoadEventListener.load(DefaultLoadEventListener.java:123)
at org.hibernate.event.def.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:161)
at org.hibernate.event.def.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:87)
at org.hibernate.impl.SessionImpl.fireLoad(SessionImpl.java:862)
at org.hibernate.impl.SessionImpl.get(SessionImpl.java:799)
at org.hibernate.impl.SessionImpl.get(SessionImpl.java:792)
at InvalidCharacterErrorCase.runTest(InvalidCharacterErrorCase.java:28)
at InvalidCharacterErrorCase.main(InvalidCharacterErrorCase.java:11)
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:585)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:90)
Caused by: java.sql.SQLException: ORA-00911: invalid character

at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:112)
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:331)
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:288)
at oracle.jdbc.driver.T4C8Oall.receive(T4C8Oall.java:743)
at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:216)
at oracle.jdbc.driver.T4CPreparedStatement.executeForDescribe(T4CPreparedStatement.java:799)
at oracle.jdbc.driver.OracleStatement.executeMaybeDescribe(OracleStatement.java:1039)
at oracle.jdbc.driver.T4CPreparedStatement.executeMaybeDescribe(T4CPreparedStatement.java:839)
at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1132)
at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3285)
at oracle.jdbc.driver.OraclePreparedStatement.executeQuery(OraclePreparedStatement.java:3329)
at org.hibernate.jdbc.AbstractBatcher.getResultSet(AbstractBatcher.java:139)
at org.hibernate.loader.Loader.getResultSet(Loader.java:1669)
at org.hibernate.loader.Loader.doQuery(Loader.java:662)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:224)
at org.hibernate.loader.Loader.loadCollection(Loader.java:1919)
... 26 more

I have attached a test case that causes this error.

After a little bit of research, it appears that a change to StringHelper.generateAlias(String description, int unique) (or StringHelper.generateAliasRoot(String description)) to remove all characters up to the first alphabetic character would solve this problem.

Environment

Hibernate 3.1.3
Oracle 10.2.0.1

Activity

Show:
Jerry Cattell
August 22, 2006, 8:56 AM

I am attaching a possible patch to org.hibernate.util.StringHelper that solves the problem.

Jerry Cattell
August 22, 2006, 8:59 AM

I should probably mention that the patch was generated against version 3.1.3.

Steve Ebersole
August 23, 2006, 3:39 PM

trunk/3.2

Matej Sekoranja
September 5, 2007, 12:49 PM

I am using Hibernate 3.2.5 and Oracle 10g Express Edition.
I got the same error as reported and "fixed" in this report.
This fix works (and implementation) only if a alias contains at least one alphabetic character. If not, the same alias is returned as given (and not the cleaned one), e.g. "0.

My fix of StringHelper.java#cleanAlias method:

/**

  • Clean the generated alias by removing any non-alpha characters from the
    * beginning.
    *
    * @param alias The generated alias to be cleaned.
    * @return The cleaned alias, stripped of any leading non-alpha characters.
    */
    private static String cleanAlias(String alias) {
    char[] chars = alias.toCharArray();
    // short cut check...
    if ( !Character.isLetter( chars[0] ) ) {
    for ( int i = 1; i < chars.length; i++ ) {
    // as soon as we encounter our first letter, return the substring
    // from that position
    if ( Character.isLetter( chars[i] ) ) {
    return alias.substring( i );
    }
    }
    +
    + // no alphabetic characters in alias, prefix with some
    + return "fix" + alias;
    }
    return alias;
    }

Matej Sekoranja
April 9, 2013, 9:32 PM

This is still an issue.

Assignee

Steve Ebersole

Reporter

Jerry Cattell

Fix versions

Labels

None

backPortable

None

Suitable for new contributors

None

Requires Release Note

None

Pull Request

None

backportDecision

None

Components

Affects versions

Priority

Minor
Configure