Skip to content

HHH-19399 introduce hibernate.jdbc.log.errors #10097

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions hibernate-core/src/main/java/org/hibernate/cfg/JdbcSettings.java
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,9 @@ public interface JdbcSettings extends C3p0Settings, AgroalSettings, HikariCPSett
/**
* When enabled, specifies that JDBC statement warnings should be logged.
* <p>
* Logging of JDBC warnings may also be controlled via the log category
* {@value org.hibernate.engine.jdbc.spi.SQLExceptionLogging#WARN_NAME}.
* <p>
* The default is determined by
* {@link org.hibernate.dialect.Dialect#isJdbcLogWarningsEnabledByDefault()}.
*
Expand All @@ -461,6 +464,19 @@ public interface JdbcSettings extends C3p0Settings, AgroalSettings, HikariCPSett
*/
String LOG_JDBC_WARNINGS = "hibernate.jdbc.log.warnings";

/**
* When enabled, specifies that JDBC errors should be logged before being rethrown.
* <p>
* Logging of JDBC errors may also be controlled via the log category
* {@value org.hibernate.engine.jdbc.spi.SQLExceptionLogging#ERROR_NAME}.
*
* @settingDefault {@code true}
*
* @since 7
*/
@Incubating // this was added for symmetry with LOG_JDBC_WARNINGS
String LOG_JDBC_ERRORS = "hibernate.jdbc.log.errors";

/**
* Specifies the {@linkplain java.util.TimeZone time zone} to use in the JDBC driver,
* which is supposed to match the database timezone.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,22 +172,27 @@ public static void cleanTemporaryTableRows(
}
}

/**
* Differs from
* {@link org.hibernate.engine.jdbc.spi.SqlExceptionHelper.StandardWarningHandler}
* because it logs only at DEBUG level.
*/
private static final SqlExceptionHelper.WarningHandler WARNING_HANDLER =
new SqlExceptionHelper.WarningHandlerLoggingSupport() {
public boolean doProcess() {
return log.isDebugEnabled();
}

private static final SqlExceptionHelper.WarningHandler WARNING_HANDLER = new SqlExceptionHelper.WarningHandlerLoggingSupport() {
public boolean doProcess() {
return log.isDebugEnabled();
}

public void prepare(SQLWarning warning) {
log.warningsCreatingTempTable( warning );
}
public void prepare(SQLWarning warning) {
log.warningsCreatingTempTable( warning );
}

@Override
protected void logWarning(String description, String message) {
log.debug( description );
log.debug( message );
}
};
@Override
protected void logWarning(String description, String message) {
log.debug( description );
log.debug( message );
}
};


private static void logStatement(String sql, JdbcServices jdbcServices) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@

import org.jboss.logging.Logger;

import static org.hibernate.cfg.MappingSettings.DEFAULT_CATALOG;
import static org.hibernate.cfg.MappingSettings.DEFAULT_SCHEMA;
import static org.hibernate.engine.config.spi.StandardConverters.STRING;
import static org.hibernate.engine.jdbc.env.internal.LobCreatorBuilderImpl.makeLobCreatorBuilder;

/**
Expand Down Expand Up @@ -70,75 +73,74 @@ public static boolean isMultiTenancyEnabled(ServiceRegistry serviceRegistry) {
public JdbcEnvironmentImpl(final ServiceRegistryImplementor serviceRegistry, final Dialect dialect) {
this.dialect = dialect;

this.sqlAstTranslatorFactory = resolveSqlAstTranslatorFactory( dialect );
sqlAstTranslatorFactory = resolveSqlAstTranslatorFactory( dialect );

final ConfigurationService cfgService = serviceRegistry.requireService( ConfigurationService.class );
final ConfigurationService cfgService = configurationService( serviceRegistry );

NameQualifierSupport nameQualifierSupport = dialect.getNameQualifierSupport();
if ( nameQualifierSupport == null ) {
// assume both catalogs and schemas are supported
nameQualifierSupport = NameQualifierSupport.BOTH;
}
this.nameQualifierSupport = nameQualifierSupport;
final NameQualifierSupport dialectNameQualifierSupport = dialect.getNameQualifierSupport();
nameQualifierSupport =
dialectNameQualifierSupport == null
? NameQualifierSupport.BOTH // assume both catalogs and schemas are supported
: dialectNameQualifierSupport;

this.sqlExceptionHelper = buildSqlExceptionHelper( dialect, logWarnings( cfgService, dialect ) );
sqlExceptionHelper =
buildSqlExceptionHelper( dialect,
logWarnings( cfgService, dialect ),
logErrors( cfgService ) );

final IdentifierHelperBuilder identifierHelperBuilder =
identifierHelperBuilder( cfgService, nameQualifierSupport );

final ExtractedDatabaseMetaDataImpl.Builder metaDataBuilder =
new ExtractedDatabaseMetaDataImpl.Builder( this, false, null );

this.identifierHelper = identifierHelper( dialect, identifierHelperBuilder, metaDataBuilder );
identifierHelper = identifierHelper( dialect, identifierHelperBuilder, metaDataBuilder );

this.extractedMetaDataSupport = metaDataBuilder.build();
extractedMetaDataSupport = metaDataBuilder.build();

this.currentCatalog = identifierHelper.toIdentifier(
cfgService.getSetting( AvailableSettings.DEFAULT_CATALOG, StandardConverters.STRING )
);
this.currentSchema = Identifier.toIdentifier(
cfgService.getSetting( AvailableSettings.DEFAULT_SCHEMA, StandardConverters.STRING )
);
currentCatalog = identifierHelper.toIdentifier( cfgService.getSetting( DEFAULT_CATALOG, STRING ) );
currentSchema = Identifier.toIdentifier( cfgService.getSetting( DEFAULT_SCHEMA, STRING ) );

this.qualifiedObjectNameFormatter = new QualifiedObjectNameFormatterStandardImpl( nameQualifierSupport );
qualifiedObjectNameFormatter = new QualifiedObjectNameFormatterStandardImpl( nameQualifierSupport );

lobCreatorBuilder = makeLobCreatorBuilder( dialect );
}

this.lobCreatorBuilder = makeLobCreatorBuilder( dialect );
private static ConfigurationService configurationService(ServiceRegistryImplementor serviceRegistry) {
return serviceRegistry.requireService( ConfigurationService.class );
}

private IdentifierHelperBuilder identifierHelperBuilder(
ConfigurationService cfgService, NameQualifierSupport nameQualifierSupport) {
final IdentifierHelperBuilder identifierHelperBuilder = IdentifierHelperBuilder.from( this );
identifierHelperBuilder.setGloballyQuoteIdentifiers( globalQuoting( cfgService ) );
identifierHelperBuilder.setSkipGlobalQuotingForColumnDefinitions( globalQuotingSkippedForColumnDefinitions(
cfgService ) );
identifierHelperBuilder.setAutoQuoteKeywords( autoKeywordQuoting( cfgService ) );
identifierHelperBuilder.setNameQualifierSupport( nameQualifierSupport );
return identifierHelperBuilder;
final IdentifierHelperBuilder builder = IdentifierHelperBuilder.from( this );
builder.setGloballyQuoteIdentifiers( globalQuoting( cfgService ) );
builder.setSkipGlobalQuotingForColumnDefinitions( globalQuotingSkippedForColumnDefinitions( cfgService ) );
builder.setAutoQuoteKeywords( autoKeywordQuoting( cfgService ) );
builder.setNameQualifierSupport( nameQualifierSupport );
return builder;
}

private static IdentifierHelper identifierHelper(
Dialect dialect,
IdentifierHelperBuilder identifierHelperBuilder,
IdentifierHelperBuilder builder,
ExtractedDatabaseMetaDataImpl.Builder dbMetaDataBuilder) {
try {
final IdentifierHelper identifierHelper = dialect.buildIdentifierHelper( identifierHelperBuilder, null );
final IdentifierHelper helper = dialect.buildIdentifierHelper( builder, null );
dbMetaDataBuilder.setSupportsNamedParameters( dialect.supportsNamedParameters( null ) );
if ( identifierHelper != null ) {
return identifierHelper;
if ( helper != null ) {
return helper;
}
}
catch (SQLException sqle) {
// should never ever happen
log.debug( "There was a problem accessing DatabaseMetaData in building the JdbcEnvironment", sqle );
}
return identifierHelperBuilder.build();
return builder.build();
}

private static SqlAstTranslatorFactory resolveSqlAstTranslatorFactory(Dialect dialect) {
final SqlAstTranslatorFactory sqlAstTranslatorFactory = dialect.getSqlAstTranslatorFactory();
return sqlAstTranslatorFactory != null
? sqlAstTranslatorFactory
: new StandardSqlAstTranslatorFactory();
return sqlAstTranslatorFactory == null ? new StandardSqlAstTranslatorFactory() : sqlAstTranslatorFactory;
}

private static boolean logWarnings(ConfigurationService cfgService, Dialect dialect) {
Expand All @@ -149,6 +151,14 @@ private static boolean logWarnings(ConfigurationService cfgService, Dialect dial
);
}

private static boolean logErrors(ConfigurationService cfgService) {
return cfgService.getSetting(
AvailableSettings.LOG_JDBC_ERRORS,
StandardConverters.BOOLEAN,
true
);
}

private static boolean globalQuoting(ConfigurationService cfgService) {
return cfgService.getSetting(
AvailableSettings.GLOBALLY_QUOTED_IDENTIFIERS,
Expand Down Expand Up @@ -182,29 +192,27 @@ public JdbcEnvironmentImpl(
JdbcConnectionAccess jdbcConnectionAccess) throws SQLException {
this.dialect = dialect;

this.sqlAstTranslatorFactory = resolveSqlAstTranslatorFactory( dialect );
sqlAstTranslatorFactory = resolveSqlAstTranslatorFactory( dialect );

this.sqlExceptionHelper = buildSqlExceptionHelper( dialect, false );
sqlExceptionHelper = buildSqlExceptionHelper( dialect, false, true );

this.nameQualifierSupport = nameQualifierSupport( databaseMetaData, dialect );
nameQualifierSupport = nameQualifierSupport( databaseMetaData, dialect );

this.identifierHelper = identifierHelper( databaseMetaData, dialect );
identifierHelper = identifierHelper( databaseMetaData, dialect );

this.extractedMetaDataSupport =
extractedMetaDataSupport =
new ExtractedDatabaseMetaDataImpl.Builder( this, true, jdbcConnectionAccess )
.apply( databaseMetaData )
.setSupportsNamedParameters( databaseMetaData.supportsNamedParameters() )
.build();

this.currentCatalog = null;
this.currentSchema = null;
currentCatalog = null;
currentSchema = null;

this.qualifiedObjectNameFormatter = new QualifiedObjectNameFormatterStandardImpl(
nameQualifierSupport,
databaseMetaData
);
qualifiedObjectNameFormatter =
new QualifiedObjectNameFormatterStandardImpl( nameQualifierSupport, databaseMetaData );

this.lobCreatorBuilder = makeLobCreatorBuilder( dialect );
lobCreatorBuilder = makeLobCreatorBuilder( dialect );
}

private IdentifierHelper identifierHelper(DatabaseMetaData databaseMetaData, Dialect dialect) {
Expand Down Expand Up @@ -278,41 +286,36 @@ public JdbcEnvironmentImpl(
JdbcConnectionAccess jdbcConnectionAccess) throws SQLException {
this.dialect = dialect;

this.sqlAstTranslatorFactory = resolveSqlAstTranslatorFactory( dialect );
sqlAstTranslatorFactory = resolveSqlAstTranslatorFactory( dialect );

final ConfigurationService cfgService = serviceRegistry.requireService( ConfigurationService.class );
final ConfigurationService cfgService = configurationService( serviceRegistry );

this.sqlExceptionHelper = buildSqlExceptionHelper( dialect, logWarnings( cfgService, dialect ) );
sqlExceptionHelper =
buildSqlExceptionHelper( dialect,
logWarnings( cfgService, dialect ),
logErrors( cfgService ) );

NameQualifierSupport nameQualifierSupport = nameQualifierSupport( databaseMetaData,
dialect );
this.nameQualifierSupport = nameQualifierSupport;
nameQualifierSupport = nameQualifierSupport( databaseMetaData, dialect );

final IdentifierHelperBuilder identifierHelperBuilder =
identifierHelperBuilder( cfgService, nameQualifierSupport );
this.identifierHelper = identifierHelper( dialect, databaseMetaData, identifierHelperBuilder );
identifierHelper = identifierHelper( dialect, databaseMetaData, identifierHelperBuilder );

this.extractedMetaDataSupport =
extractedMetaDataSupport =
new ExtractedDatabaseMetaDataImpl.Builder( this, true, jdbcConnectionAccess )
.apply( databaseMetaData )
.setConnectionSchemaName( determineCurrentSchemaName( databaseMetaData, serviceRegistry, dialect ) )
.setSupportsNamedParameters( dialect.supportsNamedParameters( databaseMetaData ) )
.build();

// and that current-catalog and current-schema happen after it
this.currentCatalog = identifierHelper.toIdentifier( extractedMetaDataSupport.getConnectionCatalogName() );
this.currentSchema = identifierHelper.toIdentifier( extractedMetaDataSupport.getConnectionSchemaName() );
currentCatalog = identifierHelper.toIdentifier( extractedMetaDataSupport.getConnectionCatalogName() );
currentSchema = identifierHelper.toIdentifier( extractedMetaDataSupport.getConnectionSchemaName() );

this.qualifiedObjectNameFormatter = new QualifiedObjectNameFormatterStandardImpl(
nameQualifierSupport,
databaseMetaData
);
qualifiedObjectNameFormatter =
new QualifiedObjectNameFormatterStandardImpl( nameQualifierSupport, databaseMetaData );

this.lobCreatorBuilder = LobCreatorBuilderImpl.makeLobCreatorBuilder(
dialect,
cfgService.getSettings(),
databaseMetaData.getConnection()
);
lobCreatorBuilder = makeLobCreatorBuilder( dialect, cfgService.getSettings(), databaseMetaData.getConnection() );
}

private static IdentifierHelper identifierHelper(
Expand Down Expand Up @@ -358,12 +361,12 @@ private static SchemaNameResolver getSchemaNameResolver(ServiceRegistry serviceR
dialect.getSchemaNameResolver() );
}

private static SqlExceptionHelper buildSqlExceptionHelper(Dialect dialect, boolean logWarnings) {
private static SqlExceptionHelper buildSqlExceptionHelper(Dialect dialect, boolean logWarnings, boolean logErrors) {
final SQLExceptionConversionDelegate dialectDelegate = dialect.buildSQLExceptionConversionDelegate();
final SQLExceptionConversionDelegate[] delegates = dialectDelegate == null
? new SQLExceptionConversionDelegate[] { new SQLExceptionTypeDelegate( dialect ), new SQLStateConversionDelegate( dialect ) }
: new SQLExceptionConversionDelegate[] { dialectDelegate, new SQLExceptionTypeDelegate( dialect ), new SQLStateConversionDelegate( dialect ) };
return new SqlExceptionHelper( new StandardSQLExceptionConverter( delegates ), logWarnings );
return new SqlExceptionHelper( new StandardSQLExceptionConverter( delegates ), logWarnings, logErrors );
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* SPDX-License-Identifier: Apache-2.0
* Copyright Red Hat Inc. and Hibernate Authors
*/
package org.hibernate.engine.jdbc.spi;

import org.hibernate.internal.log.SubSystemLogging;
import org.jboss.logging.BasicLogger;
import org.jboss.logging.Logger;
import org.jboss.logging.annotations.LogMessage;
import org.jboss.logging.annotations.Message;
import org.jboss.logging.annotations.MessageLogger;

import java.lang.invoke.MethodHandles;

import static org.jboss.logging.Logger.Level.WARN;

/**
* Responsible for logging SQL {@linkplain java.sql.SQLException errors}
* and {@linkplain java.sql.SQLWarning warnings}.
*
* @author Gavin King
* @since 7
*/
@MessageLogger(projectCode = "HHH")
public interface SQLExceptionLogging extends BasicLogger {
String ERROR_NAME = SubSystemLogging.BASE + ".jdbc.error";
String WARN_NAME = SubSystemLogging.BASE + ".jdbc.warn";

SQLExceptionLogging ERROR_LOG = Logger.getMessageLogger( MethodHandles.lookup(), SQLExceptionLogging.class, ERROR_NAME );
SQLExceptionLogging WARNING_LOG = Logger.getMessageLogger( MethodHandles.lookup(), SQLExceptionLogging.class, WARN_NAME );

@LogMessage(level = WARN)
@Message(value = "ErrorCode: %s, SQLState: %s", id = 247)
void logErrorCodes(int errorCode, String sqlState);
}
Loading