From 2080291016a6581f57a012718d7effcff2f44e18 Mon Sep 17 00:00:00 2001 From: Gavin King Date: Sun, 29 Jun 2025 15:48:37 +0200 Subject: [PATCH 1/2] Use toMetaDataObjectName() to read columns from native SQL ResultSet fixes failure affecting Informix, but it's more correct anyway --- .../results/jdbc/internal/AbstractResultSetAccess.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/jdbc/internal/AbstractResultSetAccess.java b/hibernate-core/src/main/java/org/hibernate/sql/results/jdbc/internal/AbstractResultSetAccess.java index a213ef0f9c42..99184c081997 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/jdbc/internal/AbstractResultSetAccess.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/jdbc/internal/AbstractResultSetAccess.java @@ -8,11 +8,11 @@ import java.sql.SQLException; import jakarta.persistence.EnumType; +import org.hibernate.boot.model.naming.Identifier; import org.hibernate.dialect.Dialect; import org.hibernate.engine.jdbc.spi.SqlExceptionHelper; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; -import org.hibernate.internal.util.StringHelper; import org.hibernate.type.BasicType; import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.descriptor.jdbc.JdbcType; @@ -75,8 +75,7 @@ public int getColumnCount() { @Override public int resolveColumnPosition(String columnName) { try { - return getResultSet() - .findColumn( StringHelper.unquote( columnName, getDialect() ) ); + return getResultSet().findColumn( normalizeColumnName( columnName ) ); } catch (SQLException e) { throw getSqlExceptionHelper() @@ -84,6 +83,11 @@ public int resolveColumnPosition(String columnName) { } } + private String normalizeColumnName(String columnName) { + return getFactory().getJdbcServices().getJdbcEnvironment().getIdentifierHelper() + .toMetaDataObjectName( Identifier.toIdentifier( columnName ) ); + } + @Override public String resolveColumnName(int position) { try { From 6e198d4476a49a04e9d973bb66fea881be433b1e Mon Sep 17 00:00:00 2001 From: Gavin King Date: Sun, 29 Jun 2025 16:29:20 +0200 Subject: [PATCH 2/2] Introduce Dialect.getCatalogSeparator() This is ":" on Informix. Also fix defaulted quoting strategy on Informix --- .../community/dialect/InformixDialect.java | 20 +++++++++++++++++++ .../java/org/hibernate/dialect/Dialect.java | 4 ++++ .../env/internal/JdbcEnvironmentImpl.java | 3 ++- ...lifiedObjectNameFormatterStandardImpl.java | 4 ++-- ...tionExtractorJdbcDatabaseMetaDataImpl.java | 8 ++++---- .../schema/extract/spi/ExtractionContext.java | 3 +-- .../validation/MockJdbcServicesInitiator.java | 2 +- 7 files changed, 34 insertions(+), 10 deletions(-) diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/InformixDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/InformixDialect.java index c817ad6a8590..33ba7a271fff 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/InformixDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/InformixDialect.java @@ -4,11 +4,14 @@ */ package org.hibernate.community.dialect; +import java.sql.DatabaseMetaData; +import java.sql.SQLException; import java.sql.Types; import java.time.temporal.TemporalAccessor; import java.util.Date; import java.util.TimeZone; +import org.checkerframework.checker.nullness.qual.Nullable; import org.hibernate.boot.Metadata; import org.hibernate.boot.model.FunctionContributions; import org.hibernate.boot.model.TypeContributions; @@ -24,6 +27,9 @@ import org.hibernate.dialect.NullOrdering; import org.hibernate.dialect.Replacer; import org.hibernate.dialect.SelectItemReferenceStrategy; +import org.hibernate.engine.jdbc.env.spi.IdentifierCaseStrategy; +import org.hibernate.engine.jdbc.env.spi.IdentifierHelper; +import org.hibernate.engine.jdbc.env.spi.IdentifierHelperBuilder; import org.hibernate.exception.ConstraintViolationException; import org.hibernate.exception.LockAcquisitionException; import org.hibernate.exception.spi.SQLExceptionConversionDelegate; @@ -737,6 +743,11 @@ public void appendBinaryLiteral(SqlAppender appender, byte[] bytes) { throw new UnsupportedOperationException( "Informix does not support binary literals" ); } + @Override + public String getCatalogSeparator() { + return ":"; + } + @Override public SqmMultiTableMutationStrategy getFallbackSqmMutationStrategy( EntityMappingType rootEntityDescriptor, @@ -1036,4 +1047,13 @@ public boolean supportsRowValueConstructorSyntaxInInList() { public boolean requiresColumnListInCreateView() { return true; } + + @Override + public IdentifierHelper buildIdentifierHelper(IdentifierHelperBuilder builder, @Nullable DatabaseMetaData metadata) + throws SQLException { + if ( metadata == null ) { + builder.setUnquotedCaseStrategy( IdentifierCaseStrategy.LOWER ); + } + return super.buildIdentifierHelper( builder, metadata ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java index aec8c5c1707d..de7067f3d978 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java @@ -3039,6 +3039,10 @@ public boolean supportsIfExistsAfterTypeName() { return false; } + public String getCatalogSeparator() { + return "."; + } + // callable statement support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /** diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/JdbcEnvironmentImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/JdbcEnvironmentImpl.java index 55546fa1dcc3..1a6d81dafdd0 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/JdbcEnvironmentImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/JdbcEnvironmentImpl.java @@ -101,7 +101,8 @@ public JdbcEnvironmentImpl(final ServiceRegistryImplementor serviceRegistry, fin currentCatalog = identifierHelper.toIdentifier( cfgService.getSetting( DEFAULT_CATALOG, STRING ) ); currentSchema = Identifier.toIdentifier( cfgService.getSetting( DEFAULT_SCHEMA, STRING ) ); - qualifiedObjectNameFormatter = new QualifiedObjectNameFormatterStandardImpl( nameQualifierSupport ); + qualifiedObjectNameFormatter = + new QualifiedObjectNameFormatterStandardImpl( nameQualifierSupport, dialect.getCatalogSeparator() ); lobCreatorBuilder = makeLobCreatorBuilder( dialect ); } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/QualifiedObjectNameFormatterStandardImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/QualifiedObjectNameFormatterStandardImpl.java index b83f004f0691..a4424cfdca2d 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/QualifiedObjectNameFormatterStandardImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/QualifiedObjectNameFormatterStandardImpl.java @@ -55,9 +55,9 @@ private Format buildFormat( } } - public QualifiedObjectNameFormatterStandardImpl(NameQualifierSupport nameQualifierSupport) { + public QualifiedObjectNameFormatterStandardImpl(NameQualifierSupport nameQualifierSupport, String catalogSeparator) { // most dbs simply do .. - this( nameQualifierSupport, ".", false ); + this( nameQualifierSupport, catalogSeparator, false ); } public QualifiedObjectNameFormatterStandardImpl( diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/InformationExtractorJdbcDatabaseMetaDataImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/InformationExtractorJdbcDatabaseMetaDataImpl.java index 29f96cdd7a8c..02f5cf95da33 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/InformationExtractorJdbcDatabaseMetaDataImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/InformationExtractorJdbcDatabaseMetaDataImpl.java @@ -12,6 +12,7 @@ import org.hibernate.boot.model.naming.DatabaseIdentifier; import org.hibernate.boot.model.naming.Identifier; +import org.hibernate.boot.model.relational.QualifiedTableName; import org.hibernate.dialect.Dialect; import org.hibernate.tool.schema.extract.spi.ExtractionContext; import org.hibernate.tool.schema.extract.spi.TableInformation; @@ -157,11 +158,12 @@ protected void addColumns(TableInformation tableInformation) { // We use this dummy query to retrieve the table information through the ResultSetMetaData // Significantly better than using DatabaseMetaData especially on Oracle with synonyms enabled + final QualifiedTableName qualifiedTableName = tableInformation.getName(); final String tableName = extractionContext.getSqlStringGenerationContext() // The name comes from the database, so the case is correct // But we quote here to avoid issues with reserved words - .format( tableInformation.getName().quote() ); + .format( qualifiedTableName.quote() ); try { extractionContext.getQueryResults( @@ -178,9 +180,7 @@ protected void addColumns(TableInformation tableInformation) { ); } catch (SQLException e) { - throw convertSQLException( e, - "Error accessing column metadata: " - + tableInformation.getName().toString() ); + throw convertSQLException( e, "Error accessing column metadata: " + qualifiedTableName ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/spi/ExtractionContext.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/spi/ExtractionContext.java index 8e77107f9efe..5e79c2cc7372 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/spi/ExtractionContext.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/spi/ExtractionContext.java @@ -6,7 +6,6 @@ import java.sql.Connection; import java.sql.DatabaseMetaData; -import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; @@ -38,7 +37,7 @@ default T getQueryResults( String queryString, Object[] positionalParameters, ResultSetProcessor resultSetProcessor) throws SQLException { - try (PreparedStatement statement = getJdbcConnection().prepareStatement( queryString )) { + try ( var statement = getJdbcConnection().prepareStatement( queryString ) ) { if ( positionalParameters != null ) { for ( int i = 0 ; i < positionalParameters.length ; i++ ) { statement.setObject( i + 1, positionalParameters[i] ); diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/validation/MockJdbcServicesInitiator.java b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/validation/MockJdbcServicesInitiator.java index c8f5a6cfc5a2..5c18e44056ee 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/processor/validation/MockJdbcServicesInitiator.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/processor/validation/MockJdbcServicesInitiator.java @@ -58,7 +58,7 @@ public Identifier getCurrentSchema() { @Override public QualifiedObjectNameFormatter getQualifiedObjectNameFormatter() { - return new QualifiedObjectNameFormatterStandardImpl(getNameQualifierSupport()); + return new QualifiedObjectNameFormatterStandardImpl(getNameQualifierSupport(), "."); } @Override