/*
 * Hibernate, Relational Persistence for Idiomatic Java
 *
 * Copyright (c) 2010, Red Hat Inc. or third-party contributors as
 * indicated by the @author tags or express copyright attribution
 * statements applied by the authors.  All third-party contributions are
 * distributed under license by Red Hat Inc.
 *
 * This copyrighted material is made available to anyone wishing to use, modify,
 * copy, or redistribute it subject to the terms and conditions of the GNU
 * Lesser General Public License, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
 * for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this distribution; if not, write to:
 * Free Software Foundation, Inc.
 * 51 Franklin Street, Fifth Floor
 * Boston, MA  02110-1301  USA
 */
package org.hibernate.engine.jdbc.spi;

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.Statement;

import org.hibernate.JDBCException;
import org.hibernate.exception.internal.SQLStateConverter;
import org.hibernate.exception.spi.SQLExceptionConverter;
import org.hibernate.exception.spi.ViolatedConstraintNameExtracter;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.StringHelper;

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

Helper for handling SQLExceptions in various manners.
Author:Steve Ebersole
/** * Helper for handling SQLExceptions in various manners. * * @author Steve Ebersole */
public class SqlExceptionHelper { private static final CoreMessageLogger LOG = Logger.getMessageLogger( CoreMessageLogger.class, SqlExceptionHelper.class.getName() ); private static final String DEFAULT_EXCEPTION_MSG = "SQL Exception"; private static final String DEFAULT_WARNING_MSG = "SQL Warning"; private static final SQLExceptionConverter DEFAULT_CONVERTER = new SQLStateConverter( new ViolatedConstraintNameExtracter() { public String extractConstraintName(SQLException e) { return null; } } ); private SQLExceptionConverter sqlExceptionConverter;
Create an exception helper with a default exception converter.
/** * Create an exception helper with a default exception converter. */
public SqlExceptionHelper() { sqlExceptionConverter = DEFAULT_CONVERTER; }
Create an exception helper with a specific exception converter.
Params:
  • sqlExceptionConverter – The exception converter to use.
/** * Create an exception helper with a specific exception converter. * * @param sqlExceptionConverter The exception converter to use. */
public SqlExceptionHelper(SQLExceptionConverter sqlExceptionConverter) { this.sqlExceptionConverter = sqlExceptionConverter; }
Access the current exception converter being used internally.
Returns:The current exception converter.
/** * Access the current exception converter being used internally. * * @return The current exception converter. */
public SQLExceptionConverter getSqlExceptionConverter() { return sqlExceptionConverter; }
Inject the exception converter to use.

NOTE : null is allowed and signifies to use the default.
Params:
  • sqlExceptionConverter – The converter to use.
/** * Inject the exception converter to use. * <p/> * NOTE : <tt>null</tt> is allowed and signifies to use the default. * * @param sqlExceptionConverter The converter to use. */
public void setSqlExceptionConverter(SQLExceptionConverter sqlExceptionConverter) { this.sqlExceptionConverter = (sqlExceptionConverter == null ? DEFAULT_CONVERTER : sqlExceptionConverter); } // SQLException ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Convert an SQLException using the current converter, doing some logging first.
Params:
  • sqlException – The exception to convert
  • message – An error message.
Returns:The converted exception
/** * Convert an SQLException using the current converter, doing some logging first. * * @param sqlException The exception to convert * @param message An error message. * * @return The converted exception */
public JDBCException convert(SQLException sqlException, String message) { return convert( sqlException, message, "n/a" ); }
Convert an SQLException using the current converter, doing some logging first.
Params:
  • sqlException – The exception to convert
  • message – An error message.
  • sql – The SQL being executed when the exception occurred
Returns:The converted exception
/** * Convert an SQLException using the current converter, doing some logging first. * * @param sqlException The exception to convert * @param message An error message. * @param sql The SQL being executed when the exception occurred * * @return The converted exception */
public JDBCException convert(SQLException sqlException, String message, String sql) { logExceptions( sqlException, message + " [" + sql + "]" ); return sqlExceptionConverter.convert( sqlException, message, sql ); }
Log the given (and any nested) exception.
Params:
  • sqlException – The exception to log
  • message – The message text to use as a preamble.
/** * Log the given (and any nested) exception. * * @param sqlException The exception to log * @param message The message text to use as a preamble. */
public void logExceptions(SQLException sqlException, String message) { if ( LOG.isEnabled( Level.ERROR ) ) { if ( LOG.isDebugEnabled() ) { message = StringHelper.isNotEmpty( message ) ? message : DEFAULT_EXCEPTION_MSG; LOG.debug( message, sqlException ); } final boolean warnEnabled = LOG.isEnabled( Level.WARN ); while ( sqlException != null ) { if ( warnEnabled ) { LOG.warn( "SQL Error: " + sqlException.getErrorCode() + ", SQLState: " + sqlException.getSQLState() ); } LOG.error( sqlException.getMessage() ); sqlException = sqlException.getNextException(); } } } // SQLWarning ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Contract for handling warnings
/** * Contract for handling {@link SQLWarning warnings} */
public static interface WarningHandler {
Should processing be done? Allows short-circuiting if not.
Returns:True to process warnings, false otherwise.
/** * Should processing be done? Allows short-circuiting if not. * * @return True to process warnings, false otherwise. */
public boolean doProcess();
Prepare for processing of a warning stack.

Note that the warning here is also the first passed to handleWarning
Params:
  • warning – The first warning in the stack.
/** * Prepare for processing of a {@link SQLWarning warning} stack. * <p/> * Note that the warning here is also the first passed to {@link #handleWarning} * * @param warning The first warning in the stack. */
public void prepare(SQLWarning warning);
Handle an individual warning in the stack.
Params:
  • warning – The warning to handle.
/** * Handle an individual warning in the stack. * * @param warning The warning to handle. */
public void handleWarning(SQLWarning warning); }
Basic support for WarningHandler implementations which handle warnings
/** * Basic support for {@link WarningHandler} implementations which handle {@link SQLWarning warnings} */
public abstract static class WarningHandlerLoggingSupport implements WarningHandler { @Override public final void handleWarning(SQLWarning warning) { logWarning( "SQL Warning Code: " + warning.getErrorCode() + ", SQLState: " + warning.getSQLState(), warning.getMessage() ); }
Delegate to log common details of a warning
Params:
  • description – A description of the warning
  • message – The warning message
/** * Delegate to log common details of a {@link SQLWarning warning} * * @param description A description of the warning * @param message The warning message */
protected abstract void logWarning(String description, String message); }
Standard SQLWarning handler for logging warnings
/** * Standard SQLWarning handler for logging warnings */
public static class StandardWarningHandler extends WarningHandlerLoggingSupport { private final String introMessage;
Creates a StandardWarningHandler
Params:
  • introMessage – The introduction message for the hierarchy
/** * Creates a StandardWarningHandler * * @param introMessage The introduction message for the hierarchy */
public StandardWarningHandler(String introMessage) { this.introMessage = introMessage; } @Override public boolean doProcess() { return LOG.isEnabled( Level.WARN ); } @Override public void prepare(SQLWarning warning) { LOG.debug( introMessage, warning ); } @Override protected void logWarning( String description, String message) { LOG.warn( description ); LOG.warn( message ); } }
Static access to the standard handler for logging warnings
/** * Static access to the standard handler for logging warnings */
public static final StandardWarningHandler STANDARD_WARNING_HANDLER = new StandardWarningHandler( DEFAULT_WARNING_MSG );
Generic algorithm to walk the hierarchy of SQLWarnings
Params:
  • warning – The warning to walk
  • handler – The handler
/** * Generic algorithm to walk the hierarchy of SQLWarnings * * @param warning The warning to walk * @param handler The handler */
public void walkWarnings( SQLWarning warning, WarningHandler handler) { if ( warning == null || !handler.doProcess() ) { return; } handler.prepare( warning ); while ( warning != null ) { handler.handleWarning( warning ); warning = warning.getNextWarning(); } }
Standard (legacy) behavior for logging warnings associated with a JDBC Connection and clearing them.

Calls handleAndClearWarnings(Connection, WarningHandler) using STANDARD_WARNING_HANDLER
Params:
  • connection – The JDBC connection potentially containing warnings
/** * Standard (legacy) behavior for logging warnings associated with a JDBC {@link Connection} and clearing them. * <p/> * Calls {@link #handleAndClearWarnings(Connection, WarningHandler)} using {@link #STANDARD_WARNING_HANDLER} * * @param connection The JDBC connection potentially containing warnings */
public void logAndClearWarnings(Connection connection) { handleAndClearWarnings( connection, STANDARD_WARNING_HANDLER ); } public void logAndClearWarnings(Statement statement) { handleAndClearWarnings( statement, STANDARD_WARNING_HANDLER ); }
General purpose handling of warnings associated with a JDBC Connection.
Params:
  • connection – The JDBC connection potentially containing warnings
  • handler – The handler for each individual warning in the stack.
See Also:
/** * General purpose handling of warnings associated with a JDBC {@link Connection}. * * @param connection The JDBC connection potentially containing warnings * @param handler The handler for each individual warning in the stack. * * @see #walkWarnings */
@SuppressWarnings({"ThrowableResultOfMethodCallIgnored"}) public void handleAndClearWarnings( Connection connection, WarningHandler handler) { try { walkWarnings( connection.getWarnings(), handler ); } catch (SQLException sqle) { // workaround for WebLogic LOG.debug( "could not log warnings", sqle ); } try { // Sybase fail if we don't do that, sigh... connection.clearWarnings(); } catch (SQLException sqle) { LOG.debug( "could not clear warnings", sqle ); } }
General purpose handling of warnings associated with a JDBC Statement.
Params:
  • statement – The JDBC statement potentially containing warnings
  • handler – The handler for each individual warning in the stack.
See Also:
/** * General purpose handling of warnings associated with a JDBC {@link Statement}. * * @param statement The JDBC statement potentially containing warnings * @param handler The handler for each individual warning in the stack. * * @see #walkWarnings */
@SuppressWarnings({"ThrowableResultOfMethodCallIgnored"}) public void handleAndClearWarnings( Statement statement, WarningHandler handler) { // See HHH-9174. Statement#getWarnings can be an expensive call for many JDBC libs. Don't do it unless // the log level would actually allow a warning to be logged. if (LOG.isEnabled(Level.WARN)) { try { walkWarnings( statement.getWarnings(), handler ); } catch (SQLException sqlException) { // workaround for WebLogic LOG.debug( "could not log warnings", sqlException ); } } try { // Sybase fail if we don't do that, sigh... statement.clearWarnings(); } catch (SQLException sqle) { LOG.debug( "could not clear warnings", sqle ); } } }