HHH-5373 - Better account for SQLWarnings in temp table creation

git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@19931 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
Steve Ebersole 2010-07-11 22:16:38 +00:00
parent 21b68ef40f
commit e197d208b6
2 changed files with 210 additions and 71 deletions

View File

@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* 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 Middleware LLC.
* 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
@ -20,12 +20,12 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*
*/
package org.hibernate.hql.ast.exec;
import java.sql.PreparedStatement;
import java.sql.Connection;
import java.sql.SQLWarning;
import java.sql.Statement;
import java.util.List;
import java.util.Collections;
@ -43,12 +43,14 @@ import org.hibernate.persister.entity.Queryable;
import org.hibernate.sql.InsertSelect;
import org.hibernate.sql.Select;
import org.hibernate.sql.SelectFragment;
import org.hibernate.util.JDBCExceptionReporter;
import org.hibernate.util.StringHelper;
import antlr.RecognitionException;
import antlr.collections.AST;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Implementation of AbstractStatementExecutor.
@ -56,6 +58,7 @@ import org.slf4j.Logger;
* @author Steve Ebersole
*/
public abstract class AbstractStatementExecutor implements StatementExecutor {
private static final Logger LOG = LoggerFactory.getLogger( AbstractStatementExecutor.class );
private final Logger log;
private final HqlSqlWalker walker;
@ -141,24 +144,24 @@ public abstract class AbstractStatementExecutor implements StatementExecutor {
// simply allow the failure to be eaten and the subsequent insert-selects/deletes should fail
IsolatedWork work = new IsolatedWork() {
public void doWork(Connection connection) throws HibernateException {
Statement stmnt = null;
try {
stmnt = connection.createStatement();
stmnt.executeUpdate( persister.getTemporaryIdTableDDL() );
}
catch( Throwable t ) {
log.debug( "unable to create temporary id table [" + t.getMessage() + "]" );
}
finally {
if ( stmnt != null ) {
Statement statement = connection.createStatement();
try {
statement.executeUpdate( persister.getTemporaryIdTableDDL() );
JDBCExceptionReporter.handleAndClearWarnings( statement, CREATION_WARNING_HANDLER );
}
finally {
try {
stmnt.close();
statement.close();
}
catch( Throwable ignore ) {
// ignore
}
}
}
catch( Exception e ) {
log.debug( "unable to create temporary id table [" + e.getMessage() + "]" );
}
}
};
if ( shouldIsolateTemporaryTableDDL() ) {
@ -175,30 +178,46 @@ public abstract class AbstractStatementExecutor implements StatementExecutor {
}
}
private static JDBCExceptionReporter.WarningHandler CREATION_WARNING_HANDLER = new JDBCExceptionReporter.WarningHandlerLoggingSupport() {
public boolean doProcess() {
return LOG.isDebugEnabled();
}
public void prepare(SQLWarning warning) {
LOG.debug( "Warnings creating temp table", warning );
}
@Override
protected void logWarning(String description, String message) {
LOG.debug( description );
LOG.debug( message );
}
};
protected void dropTemporaryTableIfNecessary(final Queryable persister, final SessionImplementor session) {
if ( getFactory().getDialect().dropTemporaryTableAfterUse() ) {
IsolatedWork work = new IsolatedWork() {
public void doWork(Connection connection) throws HibernateException {
Statement stmnt = null;
final String command = session.getFactory().getSettings().getDialect().getDropTemporaryTableString()
+ ' ' + persister.getTemporaryIdTableName();
try {
final String command = session.getFactory().getSettings().getDialect().getDropTemporaryTableString()
+ " " + persister.getTemporaryIdTableName();
stmnt = connection.createStatement();
stmnt.executeUpdate( command );
}
catch( Throwable t ) {
log.warn( "unable to drop temporary id table after use [" + t.getMessage() + "]" );
}
finally {
if ( stmnt != null ) {
Statement statement = connection.createStatement();
try {
statement = connection.createStatement();
statement.executeUpdate( command );
}
finally {
try {
stmnt.close();
statement.close();
}
catch( Throwable ignore ) {
// ignore
}
}
}
catch( Exception e ) {
log.warn( "unable to drop temporary id table after use [" + e.getMessage() + "]" );
}
}
};
@ -249,6 +268,7 @@ public abstract class AbstractStatementExecutor implements StatementExecutor {
}
}
@SuppressWarnings({ "UnnecessaryUnboxing" })
protected boolean shouldIsolateTemporaryTableDDL() {
Boolean dialectVote = getFactory().getDialect().performTemporaryTableDDLInIsolation();
if ( dialectVote != null ) {

View File

@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* 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 Middleware LLC.
* 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
@ -20,64 +20,197 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*
*/
package org.hibernate.util;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.Statement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public final class JDBCExceptionReporter {
public static final Logger log = LoggerFactory.getLogger(JDBCExceptionReporter.class);
public static final String DEFAULT_EXCEPTION_MSG = "SQL Exception";
public static final String DEFAULT_WARNING_MSG = "SQL Warning";
private JDBCExceptionReporter() {}
/**
* 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 static void logAndClearWarnings(Connection connection) {
if ( log.isWarnEnabled() ) {
try {
logWarnings( connection.getWarnings() );
}
catch (SQLException sqle) {
//workaround for WebLogic
log.debug("could not log warnings", sqle);
}
handleAndClearWarnings( connection, STANDARD_WARNING_HANDLER );
}
/**
* 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 static 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);
catch ( SQLException sqle ) {
log.debug( "could not clear warnings", sqle );
}
}
public static void logWarnings(SQLWarning warning) {
logWarnings(warning, null);
/**
* 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 static void handleAndClearWarnings(Statement statement, WarningHandler handler) {
try {
walkWarnings( statement.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...
statement.clearWarnings();
}
catch ( SQLException sqle ) {
log.debug( "could not clear warnings", sqle );
}
}
/**
* Log the given warning and all of its nested warnings, preceded with the {@link #DEFAULT_WARNING_MSG default message}
*
* @param warning The warning to log
*
* @deprecated Use {@link #walkWarnings} instead
*/
@Deprecated()
@SuppressWarnings({ "UnusedDeclaration" })
public static void logWarnings(SQLWarning warning) {
walkWarnings( warning, STANDARD_WARNING_HANDLER );
}
/**
* Log the given warning and all of its nested warnings, preceded with the given message
*
* @param warning The warning to log
* @param message The prologue message
*
* @deprecated Use {@link #walkWarnings} instead
*/
@Deprecated()
@SuppressWarnings({ "UnusedDeclaration" })
public static void logWarnings(SQLWarning warning, String message) {
if ( log.isWarnEnabled() ) {
if ( log.isDebugEnabled() && warning != null ) {
message = StringHelper.isNotEmpty(message) ? message : DEFAULT_WARNING_MSG;
log.debug( message, warning );
}
while (warning != null) {
StringBuffer buf = new StringBuffer(30)
.append( "SQL Warning: ")
.append( warning.getErrorCode() )
.append( ", SQLState: ")
.append( warning.getSQLState() );
log.warn( buf.toString() );
log.warn( warning.getMessage() );
warning = warning.getNextWarning();
}
final WarningHandler handler = StringHelper.isNotEmpty(message)
? new StandardWarningHandler( message )
: STANDARD_WARNING_HANDLER;
walkWarnings( warning, handler );
}
/**
* Contract for handling {@link SQLWarning warnings}
*/
public static interface WarningHandler {
/**
* Should processing be done? Allows short-circuiting if not.
*
* @return True to process warnings, false otherwise.
*/
public boolean doProcess();
/**
* 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.
*
* @param warning The warning to handle.
*/
public void handleWarning(SQLWarning warning);
}
/**
* Basic support for {@link WarningHandler} implementations which log
*/
public static abstract class WarningHandlerLoggingSupport implements WarningHandler {
public final void handleWarning(SQLWarning warning) {
StringBuffer buf = new StringBuffer(30)
.append( "SQL Warning Code: ").append( warning.getErrorCode() )
.append( ", SQLState: ").append( warning.getSQLState() );
logWarning( buf.toString(), warning.getMessage() );
}
/**
* 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);
}
public static class StandardWarningHandler extends WarningHandlerLoggingSupport {
private final String introMessage;
public StandardWarningHandler(String introMessage) {
this.introMessage = introMessage;
}
public boolean doProcess() {
return log.isWarnEnabled();
}
public void prepare(SQLWarning warning) {
log.debug( introMessage, warning );
}
@Override
protected void logWarning(String description, String message) {
log.warn( description );
log.warn( message );
}
}
public static StandardWarningHandler STANDARD_WARNING_HANDLER = new StandardWarningHandler( DEFAULT_WARNING_MSG );
public static void walkWarnings(SQLWarning warning, WarningHandler handler) {
if ( warning == null || handler.doProcess() ) {
return;
}
handler.prepare( warning );
while ( warning != null ) {
handler.handleWarning( warning );
warning = warning.getNextWarning();
}
}
@ -103,20 +236,6 @@ public final class JDBCExceptionReporter {
}
}
}
// public static JDBCException newJDBCException(String string, SQLException root, String sql) {
// string = string + " [" + sql + ']';
// log.error(string, root);
// logExceptions(root);
// return new JDBCException(string, root, sql);
// }
//
// public static JDBCException newJDBCException(String string, SQLException root) {
// log.error(string, root);
// logExceptions(root);
// return new JDBCException(string, root);
// }
}