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:
parent
21b68ef40f
commit
e197d208b6
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* 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
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* 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,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -20,12 +20,12 @@
|
||||||
* Free Software Foundation, Inc.
|
* Free Software Foundation, Inc.
|
||||||
* 51 Franklin Street, Fifth Floor
|
* 51 Franklin Street, Fifth Floor
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
package org.hibernate.hql.ast.exec;
|
package org.hibernate.hql.ast.exec;
|
||||||
|
|
||||||
import java.sql.PreparedStatement;
|
import java.sql.PreparedStatement;
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
|
import java.sql.SQLWarning;
|
||||||
import java.sql.Statement;
|
import java.sql.Statement;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
@ -43,12 +43,14 @@ import org.hibernate.persister.entity.Queryable;
|
||||||
import org.hibernate.sql.InsertSelect;
|
import org.hibernate.sql.InsertSelect;
|
||||||
import org.hibernate.sql.Select;
|
import org.hibernate.sql.Select;
|
||||||
import org.hibernate.sql.SelectFragment;
|
import org.hibernate.sql.SelectFragment;
|
||||||
|
import org.hibernate.util.JDBCExceptionReporter;
|
||||||
import org.hibernate.util.StringHelper;
|
import org.hibernate.util.StringHelper;
|
||||||
|
|
||||||
import antlr.RecognitionException;
|
import antlr.RecognitionException;
|
||||||
import antlr.collections.AST;
|
import antlr.collections.AST;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of AbstractStatementExecutor.
|
* Implementation of AbstractStatementExecutor.
|
||||||
|
@ -56,6 +58,7 @@ import org.slf4j.Logger;
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractStatementExecutor implements StatementExecutor {
|
public abstract class AbstractStatementExecutor implements StatementExecutor {
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger( AbstractStatementExecutor.class );
|
||||||
|
|
||||||
private final Logger log;
|
private final Logger log;
|
||||||
private final HqlSqlWalker walker;
|
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
|
// simply allow the failure to be eaten and the subsequent insert-selects/deletes should fail
|
||||||
IsolatedWork work = new IsolatedWork() {
|
IsolatedWork work = new IsolatedWork() {
|
||||||
public void doWork(Connection connection) throws HibernateException {
|
public void doWork(Connection connection) throws HibernateException {
|
||||||
Statement stmnt = null;
|
|
||||||
try {
|
try {
|
||||||
stmnt = connection.createStatement();
|
Statement statement = connection.createStatement();
|
||||||
stmnt.executeUpdate( persister.getTemporaryIdTableDDL() );
|
try {
|
||||||
}
|
statement.executeUpdate( persister.getTemporaryIdTableDDL() );
|
||||||
catch( Throwable t ) {
|
JDBCExceptionReporter.handleAndClearWarnings( statement, CREATION_WARNING_HANDLER );
|
||||||
log.debug( "unable to create temporary id table [" + t.getMessage() + "]" );
|
}
|
||||||
}
|
finally {
|
||||||
finally {
|
|
||||||
if ( stmnt != null ) {
|
|
||||||
try {
|
try {
|
||||||
stmnt.close();
|
statement.close();
|
||||||
}
|
}
|
||||||
catch( Throwable ignore ) {
|
catch( Throwable ignore ) {
|
||||||
// ignore
|
// ignore
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch( Exception e ) {
|
||||||
|
log.debug( "unable to create temporary id table [" + e.getMessage() + "]" );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if ( shouldIsolateTemporaryTableDDL() ) {
|
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) {
|
protected void dropTemporaryTableIfNecessary(final Queryable persister, final SessionImplementor session) {
|
||||||
if ( getFactory().getDialect().dropTemporaryTableAfterUse() ) {
|
if ( getFactory().getDialect().dropTemporaryTableAfterUse() ) {
|
||||||
IsolatedWork work = new IsolatedWork() {
|
IsolatedWork work = new IsolatedWork() {
|
||||||
public void doWork(Connection connection) throws HibernateException {
|
public void doWork(Connection connection) throws HibernateException {
|
||||||
Statement stmnt = null;
|
final String command = session.getFactory().getSettings().getDialect().getDropTemporaryTableString()
|
||||||
|
+ ' ' + persister.getTemporaryIdTableName();
|
||||||
try {
|
try {
|
||||||
final String command = session.getFactory().getSettings().getDialect().getDropTemporaryTableString()
|
Statement statement = connection.createStatement();
|
||||||
+ " " + persister.getTemporaryIdTableName();
|
try {
|
||||||
stmnt = connection.createStatement();
|
statement = connection.createStatement();
|
||||||
stmnt.executeUpdate( command );
|
statement.executeUpdate( command );
|
||||||
}
|
}
|
||||||
catch( Throwable t ) {
|
finally {
|
||||||
log.warn( "unable to drop temporary id table after use [" + t.getMessage() + "]" );
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
if ( stmnt != null ) {
|
|
||||||
try {
|
try {
|
||||||
stmnt.close();
|
statement.close();
|
||||||
}
|
}
|
||||||
catch( Throwable ignore ) {
|
catch( Throwable ignore ) {
|
||||||
// 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() {
|
protected boolean shouldIsolateTemporaryTableDDL() {
|
||||||
Boolean dialectVote = getFactory().getDialect().performTemporaryTableDDLInIsolation();
|
Boolean dialectVote = getFactory().getDialect().performTemporaryTableDDLInIsolation();
|
||||||
if ( dialectVote != null ) {
|
if ( dialectVote != null ) {
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* 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
|
* indicated by the @author tags or express copyright attribution
|
||||||
* statements applied by the authors. All third-party contributions are
|
* 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,
|
* 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
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
@ -20,64 +20,197 @@
|
||||||
* Free Software Foundation, Inc.
|
* Free Software Foundation, Inc.
|
||||||
* 51 Franklin Street, Fifth Floor
|
* 51 Franklin Street, Fifth Floor
|
||||||
* Boston, MA 02110-1301 USA
|
* Boston, MA 02110-1301 USA
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
package org.hibernate.util;
|
package org.hibernate.util;
|
||||||
|
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.sql.SQLWarning;
|
import java.sql.SQLWarning;
|
||||||
|
import java.sql.Statement;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
public final class JDBCExceptionReporter {
|
public final class JDBCExceptionReporter {
|
||||||
|
|
||||||
public static final Logger log = LoggerFactory.getLogger(JDBCExceptionReporter.class);
|
public static final Logger log = LoggerFactory.getLogger(JDBCExceptionReporter.class);
|
||||||
public static final String DEFAULT_EXCEPTION_MSG = "SQL Exception";
|
public static final String DEFAULT_EXCEPTION_MSG = "SQL Exception";
|
||||||
public static final String DEFAULT_WARNING_MSG = "SQL Warning";
|
public static final String DEFAULT_WARNING_MSG = "SQL Warning";
|
||||||
|
|
||||||
private JDBCExceptionReporter() {}
|
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) {
|
public static void logAndClearWarnings(Connection connection) {
|
||||||
if ( log.isWarnEnabled() ) {
|
handleAndClearWarnings( connection, STANDARD_WARNING_HANDLER );
|
||||||
try {
|
}
|
||||||
logWarnings( connection.getWarnings() );
|
|
||||||
}
|
/**
|
||||||
catch (SQLException sqle) {
|
* General purpose handling of warnings associated with a JDBC {@link Connection}.
|
||||||
//workaround for WebLogic
|
*
|
||||||
log.debug("could not log warnings", sqle);
|
* @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 {
|
try {
|
||||||
//Sybase fail if we don't do that, sigh...
|
//Sybase fail if we don't do that, sigh...
|
||||||
connection.clearWarnings();
|
connection.clearWarnings();
|
||||||
}
|
}
|
||||||
catch (SQLException sqle) {
|
catch ( SQLException sqle ) {
|
||||||
log.debug("could not clear warnings", 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) {
|
public static void logWarnings(SQLWarning warning, String message) {
|
||||||
if ( log.isWarnEnabled() ) {
|
final WarningHandler handler = StringHelper.isNotEmpty(message)
|
||||||
if ( log.isDebugEnabled() && warning != null ) {
|
? new StandardWarningHandler( message )
|
||||||
message = StringHelper.isNotEmpty(message) ? message : DEFAULT_WARNING_MSG;
|
: STANDARD_WARNING_HANDLER;
|
||||||
log.debug( message, warning );
|
walkWarnings( warning, handler );
|
||||||
}
|
}
|
||||||
while (warning != null) {
|
|
||||||
StringBuffer buf = new StringBuffer(30)
|
/**
|
||||||
.append( "SQL Warning: ")
|
* Contract for handling {@link SQLWarning warnings}
|
||||||
.append( warning.getErrorCode() )
|
*/
|
||||||
.append( ", SQLState: ")
|
public static interface WarningHandler {
|
||||||
.append( warning.getSQLState() );
|
/**
|
||||||
log.warn( buf.toString() );
|
* Should processing be done? Allows short-circuiting if not.
|
||||||
log.warn( warning.getMessage() );
|
*
|
||||||
warning = warning.getNextWarning();
|
* @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);
|
|
||||||
// }
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue