HHH-2859 : work api

git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@14029 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
Steve Ebersole 2007-09-27 16:37:27 +00:00
parent ccdfd6c4a3
commit 9d406f51d2
26 changed files with 1327 additions and 646 deletions

View File

@ -4,6 +4,7 @@ package org.hibernate;
import java.io.Serializable;
import java.sql.Connection;
import org.hibernate.jdbc.Work;
import org.hibernate.stat.SessionStatistics;
/**
@ -158,7 +159,8 @@ public interface Session extends Serializable {
*
* @return the JDBC connection in use by the <tt>Session</tt>
* @throws HibernateException if the <tt>Session</tt> is disconnected
* @deprecated To be replaced with a SPI for performing work against the connection; scheduled for removal in 4.x
* @deprecated (scheduled for removal in 4.x). Replacement depends on need; for doing direct JDBC stuff use
* {@link #doWork}; for opening a 'temporary Session' use (TBD).
*/
public Connection connection() throws HibernateException;
@ -739,6 +741,14 @@ public interface Session extends Serializable {
*/
public void setReadOnly(Object entity, boolean readOnly);
/**
* Controller for allowing users to perform JDBC related work using the Connection
* managed by this Session.
*
* @param work The work to be performed.
* @throws HibernateException Generally indicates wrapped {@link java.sql.SQLException}
*/
public void doWork(Work work) throws HibernateException;
/**

View File

@ -3,17 +3,18 @@ package org.hibernate.cfg;
import java.util.Map;
import org.hibernate.ConnectionReleaseMode;
import org.hibernate.EntityMode;
import org.hibernate.cache.QueryCacheFactory;
import org.hibernate.cache.RegionFactory;
import org.hibernate.connection.ConnectionProvider;
import org.hibernate.dialect.Dialect;
import org.hibernate.exception.SQLExceptionConverter;
import org.hibernate.hql.QueryTranslatorFactory;
import org.hibernate.jdbc.BatcherFactory;
import org.hibernate.jdbc.util.SQLStatementLogger;
import org.hibernate.transaction.TransactionFactory;
import org.hibernate.transaction.TransactionManagerLookup;
import org.hibernate.exception.SQLExceptionConverter;
import org.hibernate.EntityMode;
import org.hibernate.ConnectionReleaseMode;
/**
* Settings that affect the behaviour of Hibernate at runtime.
@ -22,8 +23,9 @@ import org.hibernate.ConnectionReleaseMode;
*/
public final class Settings {
private boolean showSql;
private boolean formatSql;
// private boolean showSql;
// private boolean formatSql;
private SQLStatementLogger sqlStatementLogger;
private Integer maximumFetchDepth;
private Map querySubstitutions;
private Dialect dialect;
@ -77,6 +79,18 @@ public final class Settings {
// public getters ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// public boolean isShowSqlEnabled() {
// return showSql;
// }
//
// public boolean isFormatSqlEnabled() {
// return formatSql;
// }
public SQLStatementLogger getSqlStatementLogger() {
return sqlStatementLogger;
}
public String getDefaultSchemaName() {
return defaultSchemaName;
}
@ -101,14 +115,6 @@ public final class Settings {
return querySubstitutions;
}
public boolean isShowSqlEnabled() {
return showSql;
}
public boolean isFormatSqlEnabled() {
return formatSql;
}
public boolean isIdentifierRollbackEnabled() {
return identifierRollbackEnabled;
}
@ -260,6 +266,18 @@ public final class Settings {
// package protected setters ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// void setShowSqlEnabled(boolean b) {
// showSql = b;
// }
//
// void setFormatSqlEnabled(boolean b) {
// formatSql = b;
// }
void setSqlStatementLogger(SQLStatementLogger sqlStatementLogger) {
this.sqlStatementLogger = sqlStatementLogger;
}
void setDefaultSchemaName(String string) {
defaultSchemaName = string;
}
@ -284,14 +302,6 @@ public final class Settings {
querySubstitutions = map;
}
void setShowSqlEnabled(boolean b) {
showSql = b;
}
void setFormatSqlEnabled(boolean b) {
formatSql = b;
}
void setIdentifierRollbackEnabled(boolean b) {
identifierRollbackEnabled = b;
}

View File

@ -12,6 +12,7 @@ import java.util.Properties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.hibernate.ConnectionReleaseMode;
import org.hibernate.EntityMode;
import org.hibernate.HibernateException;
@ -30,6 +31,7 @@ import org.hibernate.hql.QueryTranslatorFactory;
import org.hibernate.jdbc.BatcherFactory;
import org.hibernate.jdbc.BatchingBatcherFactory;
import org.hibernate.jdbc.NonBatchingBatcherFactory;
import org.hibernate.jdbc.util.SQLStatementLogger;
import org.hibernate.transaction.TransactionFactory;
import org.hibernate.transaction.TransactionFactoryFactory;
import org.hibernate.transaction.TransactionManagerLookup;
@ -278,11 +280,13 @@ public class SettingsFactory implements Serializable {
boolean showSql = PropertiesHelper.getBoolean(Environment.SHOW_SQL, properties);
if (showSql) log.info("Echoing all SQL to stdout");
settings.setShowSqlEnabled(showSql);
// settings.setShowSqlEnabled(showSql);
boolean formatSql = PropertiesHelper.getBoolean(Environment.FORMAT_SQL, properties);
settings.setFormatSqlEnabled(formatSql);
// settings.setFormatSqlEnabled(formatSql);
settings.setSqlStatementLogger( new SQLStatementLogger( showSql, formatSql ) );
boolean useStatistics = PropertiesHelper.getBoolean(Environment.GENERATE_STATISTICS, properties);
log.info( "Statistics: " + enabledDisabled(useStatistics) );
settings.setStatisticsEnabled(useStatistics);

View File

@ -14,6 +14,7 @@ import org.slf4j.LoggerFactory;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.MappingException;
import org.hibernate.jdbc.util.FormatStyle;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.engine.TransactionHelper;
@ -129,7 +130,7 @@ public class MultipleHiLoPerTableGenerator
// or read committed isolation level
//sql = query;
SQL.debug(query);
SQL_STATEMENT_LOGGER.logStatement( sql, FormatStyle.BASIC );
PreparedStatement qps = conn.prepareStatement(query);
PreparedStatement ips = null;
try {

View File

@ -1,10 +1,9 @@
//$Id: PersistentIdentifierGenerator.java 6514 2005-04-26 06:37:54Z oneovthafew $
package org.hibernate.id;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.hibernate.HibernateException;
import org.hibernate.dialect.Dialect;
import org.hibernate.jdbc.util.SQLStatementLogger;
/**
* An <tt>IdentifierGenerator</tt> that requires creation of database objects.
@ -48,28 +47,31 @@ public interface PersistentIdentifierGenerator extends IdentifierGenerator {
/**
* The SQL required to create the underlying database objects.
* @param dialect
* @return String[]
* @throws HibernateException
*
* @param dialect The dialect against which to generate the create command(s)
* @return The create command(s)
* @throws HibernateException problem creating the create command(s)
*/
public String[] sqlCreateStrings(Dialect dialect) throws HibernateException;
/**
* The SQL required to remove the underlying database objects.
* @param dialect
* @return String
* @throws HibernateException
*
* @param dialect The dialect against which to generate the drop command(s)
* @return The drop command(s)
* @throws HibernateException problem creating the drop command(s)
*/
public String[] sqlDropStrings(Dialect dialect) throws HibernateException;
/**
* Return a key unique to the underlying database objects. Prevents us from
* trying to create/remove them multiple times.
*
* @return Object an identifying key for this generator
*/
public Object generatorKey();
static final Logger SQL = LoggerFactory.getLogger( "org.hibernate.SQL" );
static final SQLStatementLogger SQL_STATEMENT_LOGGER = new SQLStatementLogger( false, false );
}

View File

@ -13,6 +13,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.jdbc.util.FormatStyle;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.engine.TransactionHelper;
@ -128,7 +129,7 @@ public class TableGenerator extends TransactionHelper
// or read committed isolation level
sql = query;
SQL.debug(query);
SQL_STATEMENT_LOGGER.logStatement( sql, FormatStyle.BASIC );
PreparedStatement qps = conn.prepareStatement(query);
try {
ResultSet rs = qps.executeQuery();
@ -149,7 +150,7 @@ public class TableGenerator extends TransactionHelper
}
sql = update;
SQL.debug(update);
SQL_STATEMENT_LOGGER.logStatement( sql, FormatStyle.BASIC );
PreparedStatement ups = conn.prepareStatement(update);
try {
ups.setInt( 1, result + 1 );

View File

@ -21,6 +21,7 @@ import org.hibernate.dialect.Dialect;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.LockMode;
import org.hibernate.jdbc.util.FormatStyle;
import org.hibernate.mapping.Table;
import org.hibernate.util.PropertiesHelper;
import org.hibernate.util.StringHelper;
@ -223,7 +224,7 @@ public class TableGenerator extends TransactionHelper implements PersistentIdent
int rows;
do {
sql = query;
SQL.debug( sql );
SQL_STATEMENT_LOGGER.logStatement( sql, FormatStyle.BASIC );
PreparedStatement queryPS = conn.prepareStatement( query );
try {
queryPS.setString( 1, segmentValue );
@ -233,7 +234,7 @@ public class TableGenerator extends TransactionHelper implements PersistentIdent
try {
result = initialValue;
sql = insert;
SQL.debug( sql );
SQL_STATEMENT_LOGGER.logStatement( sql, FormatStyle.BASIC );
insertPS = conn.prepareStatement( insert );
insertPS.setString( 1, segmentValue );
insertPS.setLong( 2, result );
@ -259,7 +260,7 @@ public class TableGenerator extends TransactionHelper implements PersistentIdent
}
sql = update;
SQL.debug( sql );
SQL_STATEMENT_LOGGER.logStatement( sql, FormatStyle.BASIC );
PreparedStatement updatePS = conn.prepareStatement( update );
try {
long newValue = optimizer.applyIncrementSizeToSourceValues()

View File

@ -1,21 +1,23 @@
package org.hibernate.id.enhanced;
import java.sql.Types;
import java.io.Serializable;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.io.Serializable;
import java.sql.SQLException;
import java.sql.Types;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.hibernate.dialect.Dialect;
import org.hibernate.LockMode;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.engine.TransactionHelper;
import org.hibernate.id.IdentifierGenerationException;
import org.hibernate.jdbc.util.FormatStyle;
import org.hibernate.jdbc.util.SQLStatementLogger;
/**
* Describes a table used to mimic sequence behavior
@ -24,7 +26,7 @@ import org.hibernate.id.IdentifierGenerationException;
*/
public class TableStructure extends TransactionHelper implements DatabaseStructure {
private static final Logger log = LoggerFactory.getLogger( TableStructure.class );
private static final Logger SQL_LOG = LoggerFactory.getLogger( "org.hibernate.SQL" );
private static final SQLStatementLogger SQL_STATEMENT_LOGGER = new SQLStatementLogger( false, false );
private final String tableName;
private final String valueColumnName;
@ -98,7 +100,7 @@ public class TableStructure extends TransactionHelper implements DatabaseStructu
int rows;
do {
sql = select;
SQL_LOG.debug( sql );
SQL_STATEMENT_LOGGER.logStatement( sql, FormatStyle.BASIC );
PreparedStatement qps = conn.prepareStatement( select );
try {
ResultSet rs = qps.executeQuery();
@ -119,7 +121,7 @@ public class TableStructure extends TransactionHelper implements DatabaseStructu
}
sql = update;
SQL_LOG.debug( sql );
SQL_STATEMENT_LOGGER.logStatement( sql, FormatStyle.BASIC );
PreparedStatement ups = conn.prepareStatement( update );
try {
int increment = applyIncrementSizeToSourceValues ? incrementSize : 1;

View File

@ -6,6 +6,7 @@ import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
@ -15,9 +16,10 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.dom4j.Element;
import org.hibernate.CacheMode;
import org.hibernate.ConnectionReleaseMode;
import org.hibernate.Criteria;
@ -41,7 +43,6 @@ import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.TransientObjectException;
import org.hibernate.UnresolvableObjectException;
import org.hibernate.engine.query.sql.NativeSQLQuerySpecification;
import org.hibernate.collection.PersistentCollection;
import org.hibernate.engine.ActionQueue;
import org.hibernate.engine.CollectionEntry;
@ -55,6 +56,7 @@ import org.hibernate.engine.Status;
import org.hibernate.engine.query.FilterQueryPlan;
import org.hibernate.engine.query.HQLQueryPlan;
import org.hibernate.engine.query.NativeSQLQueryPlan;
import org.hibernate.engine.query.sql.NativeSQLQuerySpecification;
import org.hibernate.event.AutoFlushEvent;
import org.hibernate.event.AutoFlushEventListener;
import org.hibernate.event.DeleteEvent;
@ -71,6 +73,7 @@ import org.hibernate.event.InitializeCollectionEvent;
import org.hibernate.event.InitializeCollectionEventListener;
import org.hibernate.event.LoadEvent;
import org.hibernate.event.LoadEventListener;
import org.hibernate.event.LoadEventListener.LoadType;
import org.hibernate.event.LockEvent;
import org.hibernate.event.LockEventListener;
import org.hibernate.event.MergeEvent;
@ -83,9 +86,10 @@ import org.hibernate.event.ReplicateEvent;
import org.hibernate.event.ReplicateEventListener;
import org.hibernate.event.SaveOrUpdateEvent;
import org.hibernate.event.SaveOrUpdateEventListener;
import org.hibernate.event.LoadEventListener.LoadType;
import org.hibernate.exception.JDBCExceptionHelper;
import org.hibernate.jdbc.Batcher;
import org.hibernate.jdbc.JDBCContext;
import org.hibernate.jdbc.Work;
import org.hibernate.loader.criteria.CriteriaLoader;
import org.hibernate.loader.custom.CustomLoader;
import org.hibernate.loader.custom.CustomQuery;
@ -1841,6 +1845,16 @@ public final class SessionImpl extends AbstractSessionImpl
persistenceContext.setReadOnly(entity, readOnly);
}
public void doWork(Work work) throws HibernateException {
try {
work.execute( jdbcContext.getConnectionManager().getConnection() );
jdbcContext.getConnectionManager().afterStatement();
}
catch ( SQLException e ) {
throw JDBCExceptionHelper.convert( factory.getSettings().getSQLExceptionConverter(), e, "error executing work" );
}
}
public void afterScrollOperation() {
// nothing to do in a stateful session
}

View File

@ -11,6 +11,7 @@ import java.util.Iterator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.hibernate.AssertionFailure;
import org.hibernate.HibernateException;
import org.hibernate.Interceptor;
@ -19,7 +20,7 @@ import org.hibernate.TransactionException;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.exception.JDBCExceptionHelper;
import org.hibernate.pretty.Formatter;
import org.hibernate.jdbc.util.FormatStyle;
import org.hibernate.util.JDBCExceptionReporter;
/**
@ -36,7 +37,6 @@ public abstract class AbstractBatcher implements Batcher {
private int openResultSetCount;
protected static final Logger log = LoggerFactory.getLogger( AbstractBatcher.class );
protected static final Logger SQL_LOG = LoggerFactory.getLogger( "org.hibernate.SQL" );
private final ConnectionManager connectionManager;
private final SessionFactoryImplementor factory;
@ -395,29 +395,14 @@ public abstract class AbstractBatcher implements Batcher {
}
private void log(String sql) {
if ( SQL_LOG.isDebugEnabled() ) {
SQL_LOG.debug( format(sql) );
}
if ( factory.getSettings().isShowSqlEnabled() ) {
System.out.println( "Hibernate: " + format(sql) );
}
}
private String format(String sql) {
if ( factory.getSettings().isFormatSqlEnabled() ) {
return new Formatter(sql).format();
}
else {
return sql;
}
factory.getSettings().getSqlStatementLogger().logStatement( sql, FormatStyle.BASIC );
}
private PreparedStatement getPreparedStatement(
final Connection conn,
final String sql,
final boolean scrollable,
final ScrollMode scrollMode)
throws SQLException {
final ScrollMode scrollMode) throws SQLException {
return getPreparedStatement(
conn,
sql,

View File

@ -0,0 +1,37 @@
/*
* Copyright (c) 2007, Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1. This program is distributed in the
* hope that it will be useful, but WITHOUT A 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, v.2.1 along with this
* distribution; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Red Hat Author(s): Steve Ebersole
*/
package org.hibernate.jdbc;
import java.sql.Connection;
import java.sql.SQLException;
import org.hibernate.HibernateException;
/**
* Contract for performing a discrete piece of JDBC work.
*
* @author Steve Ebersole
*/
public interface Work {
/**
* Execute the discrete work encapsulated by this work instance using the supplied connection.
*
* @param connection The connection on which to perform the work.
* @throws SQLException Thrown during execution of the underlying JDBC interaction.
* @throws HibernateException Generally indicates a wrapped SQLException.
*/
public void execute(Connection connection) throws SQLException;
}

View File

@ -0,0 +1,388 @@
/*
* Copyright (c) 2007, Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1. This program is distributed in the
* hope that it will be useful, but WITHOUT A 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, v.2.1 along with this
* distribution; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Red Hat Author(s): Gavin King, Steve Ebersole
*/
package org.hibernate.jdbc.util;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Set;
import java.util.StringTokenizer;
import org.hibernate.util.StringHelper;
/**
* Performs formatting of basic SQL statements (DML + query).
*
* @author Gavin King
* @author Steve Ebersole
*/
public class BasicFormatterImpl implements Formatter {
private static final Set BEGIN_CLAUSES = new HashSet();
private static final Set END_CLAUSES = new HashSet();
private static final Set LOGICAL = new HashSet();
private static final Set QUANTIFIERS = new HashSet();
private static final Set DML = new HashSet();
private static final Set MISC = new HashSet();
static {
BEGIN_CLAUSES.add( "left" );
BEGIN_CLAUSES.add( "right" );
BEGIN_CLAUSES.add( "inner" );
BEGIN_CLAUSES.add( "outer" );
BEGIN_CLAUSES.add( "group" );
BEGIN_CLAUSES.add( "order" );
END_CLAUSES.add( "where" );
END_CLAUSES.add( "set" );
END_CLAUSES.add( "having" );
END_CLAUSES.add( "join" );
END_CLAUSES.add( "from" );
END_CLAUSES.add( "by" );
END_CLAUSES.add( "join" );
END_CLAUSES.add( "into" );
END_CLAUSES.add( "union" );
LOGICAL.add( "and" );
LOGICAL.add( "or" );
LOGICAL.add( "when" );
LOGICAL.add( "else" );
LOGICAL.add( "end" );
QUANTIFIERS.add( "in" );
QUANTIFIERS.add( "all" );
QUANTIFIERS.add( "exists" );
QUANTIFIERS.add( "some" );
QUANTIFIERS.add( "any" );
DML.add( "insert" );
DML.add( "update" );
DML.add( "delete" );
MISC.add( "select" );
MISC.add( "on" );
}
static final String indentString = " ";
static final String initial = "\n ";
public String format(String source) {
return new FormatProcess( source ).perform();
}
private static class FormatProcess {
boolean beginLine = true;
boolean afterBeginBeforeEnd = false;
boolean afterByOrSetOrFromOrSelect = false;
boolean afterValues = false;
boolean afterOn = false;
boolean afterBetween = false;
boolean afterInsert = false;
int inFunction = 0;
int parensSinceSelect = 0;
private LinkedList parenCounts = new LinkedList();
private LinkedList afterByOrFromOrSelects = new LinkedList();
int indent = 1;
StringBuffer result = new StringBuffer();
StringTokenizer tokens;
String lastToken;
String token;
String lcToken;
public FormatProcess(String sql) {
tokens = new StringTokenizer(
sql,
"()+*/-=<>'`\"[]," + StringHelper.WHITESPACE,
true
);
}
public String perform() {
result.append( initial );
while ( tokens.hasMoreTokens() ) {
token = tokens.nextToken();
lcToken = token.toLowerCase();
if ( "'".equals( token ) ) {
String t;
do {
t = tokens.nextToken();
token += t;
}
while ( !"'".equals( t ) && tokens.hasMoreTokens() ); // cannot handle single quotes
}
else if ( "\"".equals( token ) ) {
String t;
do {
t = tokens.nextToken();
token += t;
}
while ( !"\"".equals( t ) );
}
if ( afterByOrSetOrFromOrSelect && ",".equals( token ) ) {
commaAfterByOrFromOrSelect();
}
else if ( afterOn && ",".equals( token ) ) {
commaAfterOn();
}
else if ( "(".equals( token ) ) {
openParen();
}
else if ( ")".equals( token ) ) {
closeParen();
}
else if ( BEGIN_CLAUSES.contains( lcToken ) ) {
beginNewClause();
}
else if ( END_CLAUSES.contains( lcToken ) ) {
endNewClause();
}
else if ( "select".equals( lcToken ) ) {
select();
}
else if ( DML.contains( lcToken ) ) {
updateOrInsertOrDelete();
}
else if ( "values".equals( lcToken ) ) {
values();
}
else if ( "on".equals( lcToken ) ) {
on();
}
else if ( afterBetween && lcToken.equals( "and" ) ) {
misc();
afterBetween = false;
}
else if ( LOGICAL.contains( lcToken ) ) {
logical();
}
else if ( isWhitespace( token ) ) {
white();
}
else {
misc();
}
if ( !isWhitespace( token ) ) {
lastToken = lcToken;
}
}
return result.toString();
}
private void commaAfterOn() {
out();
indent--;
newline();
afterOn = false;
afterByOrSetOrFromOrSelect = true;
}
private void commaAfterByOrFromOrSelect() {
out();
newline();
}
private void logical() {
if ( "end".equals( lcToken ) ) {
indent--;
}
newline();
out();
beginLine = false;
}
private void on() {
indent++;
afterOn = true;
newline();
out();
beginLine = false;
}
private void misc() {
out();
if ( "between".equals( lcToken ) ) {
afterBetween = true;
}
if ( afterInsert ) {
newline();
afterInsert = false;
}
else {
beginLine = false;
if ( "case".equals( lcToken ) ) {
indent++;
}
}
}
private void white() {
if ( !beginLine ) {
result.append( " " );
}
}
private void updateOrInsertOrDelete() {
out();
indent++;
beginLine = false;
if ( "update".equals( lcToken ) ) {
newline();
}
if ( "insert".equals( lcToken ) ) {
afterInsert = true;
}
}
private void select() {
out();
indent++;
newline();
parenCounts.addLast( Integer.valueOf( parensSinceSelect ) );
afterByOrFromOrSelects.addLast( Boolean.valueOf( afterByOrSetOrFromOrSelect ) );
parensSinceSelect = 0;
afterByOrSetOrFromOrSelect = true;
}
private void out() {
result.append( token );
}
private void endNewClause() {
if ( !afterBeginBeforeEnd ) {
indent--;
if ( afterOn ) {
indent--;
afterOn = false;
}
newline();
}
out();
if ( !"union".equals( lcToken ) ) {
indent++;
}
newline();
afterBeginBeforeEnd = false;
afterByOrSetOrFromOrSelect = "by".equals( lcToken )
|| "set".equals( lcToken )
|| "from".equals( lcToken );
}
private void beginNewClause() {
if ( !afterBeginBeforeEnd ) {
if ( afterOn ) {
indent--;
afterOn = false;
}
indent--;
newline();
}
out();
beginLine = false;
afterBeginBeforeEnd = true;
}
private void values() {
indent--;
newline();
out();
indent++;
newline();
afterValues = true;
}
private void closeParen() {
parensSinceSelect--;
if ( parensSinceSelect < 0 ) {
indent--;
parensSinceSelect = ( ( Integer ) parenCounts.removeLast() ).intValue();
afterByOrSetOrFromOrSelect = ( ( Boolean ) afterByOrFromOrSelects.removeLast() ).booleanValue();
}
if ( inFunction > 0 ) {
inFunction--;
out();
}
else {
if ( !afterByOrSetOrFromOrSelect ) {
indent--;
newline();
}
out();
}
beginLine = false;
}
private void openParen() {
if ( isFunctionName( lastToken ) || inFunction > 0 ) {
inFunction++;
}
beginLine = false;
if ( inFunction > 0 ) {
out();
}
else {
out();
if ( !afterByOrSetOrFromOrSelect ) {
indent++;
newline();
beginLine = true;
}
}
parensSinceSelect++;
}
private static boolean isFunctionName(String tok) {
final char begin = tok.charAt( 0 );
final boolean isIdentifier = Character.isJavaIdentifierStart( begin ) || '"' == begin;
return isIdentifier &&
!LOGICAL.contains( tok ) &&
!END_CLAUSES.contains( tok ) &&
!QUANTIFIERS.contains( tok ) &&
!DML.contains( tok ) &&
!MISC.contains( tok );
}
private static boolean isWhitespace(String token) {
return StringHelper.WHITESPACE.indexOf( token ) >= 0;
}
private void newline() {
result.append( "\n" );
for ( int i = 0; i < indent; i++ ) {
result.append( indentString );
}
beginLine = true;
}
}
}

View File

@ -0,0 +1,148 @@
/*
* Copyright (c) 2007, Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1. This program is distributed in the
* hope that it will be useful, but WITHOUT A 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, v.2.1 along with this
* distribution; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Red Hat Author(s): Gavin King, Steve Ebersole
*/
package org.hibernate.jdbc.util;
import java.util.StringTokenizer;
/**
* Performs formatting of DDL SQL statements.
*
* @author Gavin King
* @author Steve Ebersole
*/
public class DDLFormatterImpl implements Formatter {
/**
* Format an SQL statement using simple rules<ul>
* <li>Insert newline after each comma</li>
* <li>Indent three spaces after each inserted newline</li>
* </ul>
* If the statement contains single/double quotes return unchanged,
* it is too complex and could be broken by simple formatting.
*
* @param sql The statement to be fornmatted.
*/
public String format(String sql) {
if ( sql.toLowerCase().startsWith( "create table" ) ) {
return formatCreateTable( sql );
}
else if ( sql.toLowerCase().startsWith( "alter table" ) ) {
return formatAlterTable( sql );
}
else if ( sql.toLowerCase().startsWith( "comment on" ) ) {
return formatCommentOn( sql );
}
else {
return "\n " + sql;
}
}
private String formatCommentOn(String sql) {
StringBuffer result = new StringBuffer( 60 ).append( "\n " );
StringTokenizer tokens = new StringTokenizer( sql, " '[]\"", true );
boolean quoted = false;
while ( tokens.hasMoreTokens() ) {
String token = tokens.nextToken();
result.append( token );
if ( isQuote( token ) ) {
quoted = !quoted;
}
else if ( !quoted ) {
if ( "is".equals( token ) ) {
result.append( "\n " );
}
}
}
return result.toString();
}
private String formatAlterTable(String sql) {
StringBuffer result = new StringBuffer( 60 ).append( "\n " );
StringTokenizer tokens = new StringTokenizer( sql, " (,)'[]\"", true );
boolean quoted = false;
while ( tokens.hasMoreTokens() ) {
String token = tokens.nextToken();
if ( isQuote( token ) ) {
quoted = !quoted;
}
else if ( !quoted ) {
if ( isBreak( token ) ) {
result.append( "\n " );
}
}
result.append( token );
}
return result.toString();
}
private String formatCreateTable(String sql) {
StringBuffer result = new StringBuffer( 60 ).append( "\n " );
StringTokenizer tokens = new StringTokenizer( sql, "(,)'[]\"", true );
int depth = 0;
boolean quoted = false;
while ( tokens.hasMoreTokens() ) {
String token = tokens.nextToken();
if ( isQuote( token ) ) {
quoted = !quoted;
result.append( token );
}
else if ( quoted ) {
result.append( token );
}
else {
if ( ")".equals( token ) ) {
depth--;
if ( depth == 0 ) {
result.append( "\n " );
}
}
result.append( token );
if ( ",".equals( token ) && depth == 1 ) {
result.append( "\n " );
}
if ( "(".equals( token ) ) {
depth++;
if ( depth == 1 ) {
result.append( "\n " );
}
}
}
}
return result.toString();
}
private static boolean isBreak(String token) {
return "drop".equals( token ) ||
"add".equals( token ) ||
"references".equals( token ) ||
"foreign".equals( token ) ||
"on".equals( token );
}
private static boolean isQuote(String tok) {
return "\"".equals( tok ) ||
"`".equals( tok ) ||
"]".equals( tok ) ||
"[".equals( tok ) ||
"'".equals( tok );
}
}

View File

@ -0,0 +1,67 @@
/*
* Copyright (c) 2007, Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1. This program is distributed in the
* hope that it will be useful, but WITHOUT A 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, v.2.1 along with this
* distribution; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Red Hat Author(s): Steve Ebersole
*/
package org.hibernate.jdbc.util;
/**
* Represents the the understood types or styles of formatting.
*
* @author Steve Ebersole
*/
public class FormatStyle {
public static final FormatStyle BASIC = new FormatStyle( "basic", new BasicFormatterImpl() );
public static final FormatStyle DDL = new FormatStyle( "ddl", new DDLFormatterImpl() );
public static final FormatStyle NONE = new FormatStyle( "none", new NoFormatImpl() );
private final String name;
private final Formatter formatter;
private FormatStyle(String name, Formatter formatter) {
this.name = name;
this.formatter = formatter;
}
public String getName() {
return name;
}
public Formatter getFormatter() {
return formatter;
}
public boolean equals(Object o) {
if ( this == o ) {
return true;
}
if ( o == null || getClass() != o.getClass() ) {
return false;
}
FormatStyle that = ( FormatStyle ) o;
return name.equals( that.name );
}
public int hashCode() {
return name.hashCode();
}
private static class NoFormatImpl implements Formatter {
public String format(String source) {
return source;
}
}
}

View File

@ -0,0 +1,25 @@
/*
* Copyright (c) 2007, Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1. This program is distributed in the
* hope that it will be useful, but WITHOUT A 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, v.2.1 along with this
* distribution; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Red Hat Author(s): Steve Ebersole
*/
package org.hibernate.jdbc.util;
/**
* Formatter contract
*
* @author Steve Ebersole
*/
public interface Formatter {
public String format(String source);
}

View File

@ -0,0 +1,111 @@
/*
* Copyright (c) 2007, Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1. This program is distributed in the
* hope that it will be useful, but WITHOUT A 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, v.2.1 along with this
* distribution; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Red Hat Author(s): Steve Ebersole
*/
package org.hibernate.jdbc.util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Centralize logging handling for SQL statements.
*
* @author Steve Ebersole
*/
public class SQLStatementLogger {
// todo : for 4.0
// private static final Logger log = LoggerFactory.getLogger( SQLStatementLogger.class );
// this is the legacy logging 'category'...
private static final Logger log = LoggerFactory.getLogger( "org.hibernate.SQL" );
private boolean logToStdout;
private boolean formatSql;
/**
* Constructs a new SQLStatementLogger instance.
*/
public SQLStatementLogger() {
this( false, false );
}
/**
* Constructs a new SQLStatementLogger instance.
*
* @param logToStdout Should we log to STDOUT in addition to our internal logger.
* @param formatSql Should we format SQL ('prettify') prior to logging.
*/
public SQLStatementLogger(boolean logToStdout, boolean formatSql) {
this.logToStdout = logToStdout;
this.formatSql = formatSql;
}
/**
* Getter for property 'logToStdout'.
* @see #setLogToStdout
*
* @return Value for property 'logToStdout'.
*/
public boolean isLogToStdout() {
return logToStdout;
}
/**
* Setter for property 'logToStdout'.
*
* @param logToStdout Value to set for property 'logToStdout'.
*/
public void setLogToStdout(boolean logToStdout) {
this.logToStdout = logToStdout;
}
/**
* Getter for property 'formatSql'.
* @see #setFormatSql
*
* @return Value for property 'formatSql'.
*/
public boolean isFormatSql() {
return formatSql;
}
/**
* Setter for property 'formatSql'.
*
* @param formatSql Value to set for property 'formatSql'.
*/
public void setFormatSql(boolean formatSql) {
this.formatSql = formatSql;
}
/**
* Log a SQL statement string.
*
* @param statement The SQL statement.
* @param style The requested formatting style.
*/
public void logStatement(String statement, FormatStyle style) {
if ( log.isDebugEnabled() || logToStdout ) {
style = determineActualStyle( style );
statement = style.getFormatter().format( statement );
}
log.debug( statement );
if ( logToStdout ) {
System.out.println( "Hibernate: " + statement );
}
}
private FormatStyle determineActualStyle(FormatStyle style) {
return formatSql ? style : FormatStyle.NONE;
}
}

View File

@ -1,126 +0,0 @@
//$Id: DDLFormatter.java 7664 2005-07-27 23:29:37Z oneovthafew $
package org.hibernate.pretty;
import java.util.StringTokenizer;
public class DDLFormatter {
private String sql;
public DDLFormatter(String sql) {
this.sql = sql;
}
/**
* Format an SQL statement using simple rules:
* a) Insert newline after each comma;
* b) Indent three spaces after each inserted newline;
* If the statement contains single/double quotes return unchanged,
* it is too complex and could be broken by simple formatting.
*/
public String format() {
if ( sql.toLowerCase().startsWith("create table") ) {
return formatCreateTable();
}
else if ( sql.toLowerCase().startsWith("alter table") ) {
return formatAlterTable();
}
else if ( sql.toLowerCase().startsWith("comment on") ) {
return formatCommentOn();
}
else {
return "\n " + sql;
}
}
private String formatCommentOn() {
StringBuffer result = new StringBuffer(60).append("\n ");
StringTokenizer tokens = new StringTokenizer( sql, " '[]\"", true );
boolean quoted = false;
while ( tokens.hasMoreTokens() ) {
String token = tokens.nextToken();
result.append(token);
if ( isQuote(token) ) {
quoted = !quoted;
}
else if (!quoted) {
if ( "is".equals(token) ) {
result.append("\n ");
}
}
}
return result.toString();
}
private String formatAlterTable() {
StringBuffer result = new StringBuffer(60).append("\n ");
StringTokenizer tokens = new StringTokenizer( sql, " (,)'[]\"", true );
boolean quoted = false;
while ( tokens.hasMoreTokens() ) {
String token = tokens.nextToken();
if ( isQuote(token) ) {
quoted = !quoted;
}
else if (!quoted) {
if ( isBreak(token) ) {
result.append("\n ");
}
}
result.append(token);
}
return result.toString();
}
private String formatCreateTable() {
StringBuffer result = new StringBuffer(60).append("\n ");
StringTokenizer tokens = new StringTokenizer( sql, "(,)'[]\"", true );
int depth = 0;
boolean quoted = false;
while ( tokens.hasMoreTokens() ) {
String token = tokens.nextToken();
if ( isQuote(token) ) {
quoted = !quoted;
result.append(token);
}
else if (quoted) {
result.append(token);
}
else {
if ( ")".equals(token) ) {
depth--;
if (depth==0) result.append("\n ");
}
result.append(token);
if ( ",".equals(token) && depth==1 ) result.append("\n ");
if ( "(".equals(token) ) {
depth++;
if (depth==1) result.append("\n ");
}
}
}
return result.toString();
}
private static boolean isBreak(String token) {
return "drop".equals(token) ||
"add".equals(token) ||
"references".equals(token) ||
"foreign".equals(token) ||
"on".equals(token);
}
private static boolean isQuote(String tok) {
return "\"".equals(tok) ||
"`".equals(tok) ||
"]".equals(tok) ||
"[".equals(tok) ||
"'".equals(tok);
}
}

View File

@ -1,370 +0,0 @@
//$Id: Formatter.java 9961 2006-05-30 13:17:45Z max.andersen@jboss.com $
package org.hibernate.pretty;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Set;
import java.util.StringTokenizer;
import org.hibernate.util.StringHelper;
public class Formatter {
private static final Set BEGIN_CLAUSES = new HashSet();
private static final Set END_CLAUSES = new HashSet();
private static final Set LOGICAL = new HashSet();
private static final Set QUANTIFIERS = new HashSet();
private static final Set DML = new HashSet();
private static final Set MISC = new HashSet();
static {
BEGIN_CLAUSES.add("left");
BEGIN_CLAUSES.add("right");
BEGIN_CLAUSES.add("inner");
BEGIN_CLAUSES.add("outer");
BEGIN_CLAUSES.add("group");
BEGIN_CLAUSES.add("order");
END_CLAUSES.add("where");
END_CLAUSES.add("set");
END_CLAUSES.add("having");
END_CLAUSES.add("join");
END_CLAUSES.add("from");
END_CLAUSES.add("by");
END_CLAUSES.add("join");
END_CLAUSES.add("into");
END_CLAUSES.add("union");
LOGICAL.add("and");
LOGICAL.add("or");
LOGICAL.add("when");
LOGICAL.add("else");
LOGICAL.add("end");
QUANTIFIERS.add("in");
QUANTIFIERS.add("all");
QUANTIFIERS.add("exists");
QUANTIFIERS.add("some");
QUANTIFIERS.add("any");
DML.add("insert");
DML.add("update");
DML.add("delete");
MISC.add("select");
MISC.add("on");
//MISC.add("values");
}
String indentString = " ";
String initial = "\n ";
boolean beginLine = true;
boolean afterBeginBeforeEnd = false;
boolean afterByOrSetOrFromOrSelect = false;
boolean afterValues = false;
boolean afterOn = false;
boolean afterBetween = false;
boolean afterInsert = false;
int inFunction = 0;
int parensSinceSelect = 0;
private LinkedList parenCounts = new LinkedList();
private LinkedList afterByOrFromOrSelects = new LinkedList();
int indent = 1;
StringBuffer result = new StringBuffer();
StringTokenizer tokens;
String lastToken;
String token;
String lcToken;
public Formatter(String sql) {
tokens = new StringTokenizer(
sql,
"()+*/-=<>'`\"[]," + StringHelper.WHITESPACE,
true
);
}
public Formatter setInitialString(String initial) {
this.initial = initial;
return this;
}
public Formatter setIndentString(String indent) {
this.indentString = indent;
return this;
}
public String format() {
result.append(initial);
while ( tokens.hasMoreTokens() ) {
token = tokens.nextToken();
lcToken = token.toLowerCase();
if ( "'".equals(token) ) {
String t;
do {
t = tokens.nextToken();
token += t;
}
while ( !"'".equals(t) && tokens.hasMoreTokens() ); // cannot handle single quotes
}
else if ( "\"".equals(token) ) {
String t;
do {
t = tokens.nextToken();
token += t;
}
while ( !"\"".equals(t) );
}
if ( afterByOrSetOrFromOrSelect && ",".equals(token) ) {
commaAfterByOrFromOrSelect();
}
else if ( afterOn && ",".equals(token) ) {
commaAfterOn();
}
else if ( "(".equals(token) ) {
openParen();
}
else if ( ")".equals(token) ) {
closeParen();
}
else if ( BEGIN_CLAUSES.contains(lcToken) ) {
beginNewClause();
}
else if ( END_CLAUSES.contains(lcToken) ) {
endNewClause();
}
else if ( "select".equals(lcToken) ) {
select();
}
else if ( DML.contains(lcToken) ) {
updateOrInsertOrDelete();
}
else if ( "values".equals(lcToken) ) {
values();
}
else if ( "on".equals(lcToken) ) {
on();
}
else if ( afterBetween && lcToken.equals("and") ) {
misc();
afterBetween = false;
}
else if ( LOGICAL.contains(lcToken) ) {
logical();
}
else if ( isWhitespace(token) ) {
white();
}
else {
misc();
}
if ( !isWhitespace( token ) ) lastToken = lcToken;
}
return result.toString();
}
private void commaAfterOn() {
out();
indent--;
newline();
afterOn = false;
afterByOrSetOrFromOrSelect = true;
}
private void commaAfterByOrFromOrSelect() {
out();
newline();
}
private void logical() {
if ( "end".equals(lcToken) ) indent--;
newline();
out();
beginLine = false;
}
private void on() {
indent++;
afterOn = true;
newline();
out();
beginLine = false;
}
private void misc() {
out();
if ( "between".equals(lcToken) ) {
afterBetween = true;
}
if (afterInsert) {
newline();
afterInsert = false;
}
else {
beginLine = false;
if ( "case".equals(lcToken) ) {
indent++;
}
}
}
private void white() {
if ( !beginLine ) {
result.append(" ");
}
}
private void updateOrInsertOrDelete() {
out();
indent++;
beginLine = false;
if ( "update".equals(lcToken) ) newline();
if ( "insert".equals(lcToken) ) afterInsert = true;
}
private void select() {
out();
indent++;
newline();
parenCounts.addLast( new Integer(parensSinceSelect) );
afterByOrFromOrSelects.addLast( new Boolean(afterByOrSetOrFromOrSelect) );
parensSinceSelect = 0;
afterByOrSetOrFromOrSelect = true;
}
private void out() {
result.append(token);
}
private void endNewClause() {
if (!afterBeginBeforeEnd) {
indent--;
if (afterOn) {
indent--;
afterOn=false;
}
newline();
}
out();
if ( !"union".equals(lcToken) ) indent++;
newline();
afterBeginBeforeEnd = false;
afterByOrSetOrFromOrSelect = "by".equals(lcToken)
|| "set".equals(lcToken)
|| "from".equals(lcToken);
}
private void beginNewClause() {
if (!afterBeginBeforeEnd) {
if (afterOn) {
indent--;
afterOn=false;
}
indent--;
newline();
}
out();
beginLine = false;
afterBeginBeforeEnd = true;
}
private void values() {
indent--;
newline();
out();
indent++;
newline();
afterValues = true;
}
private void closeParen() {
parensSinceSelect--;
if (parensSinceSelect<0) {
indent--;
parensSinceSelect = ( (Integer) parenCounts.removeLast() ).intValue();
afterByOrSetOrFromOrSelect = ( (Boolean) afterByOrFromOrSelects.removeLast() ).booleanValue();
}
if ( inFunction>0 ) {
inFunction--;
out();
}
else {
if (!afterByOrSetOrFromOrSelect) {
indent--;
newline();
}
out();
}
beginLine = false;
}
private void openParen() {
if ( isFunctionName( lastToken ) || inFunction>0 ) {
inFunction++;
}
beginLine = false;
if ( inFunction>0 ) {
out();
}
else {
out();
if (!afterByOrSetOrFromOrSelect) {
indent++;
newline();
beginLine = true;
}
}
parensSinceSelect++;
}
private static boolean isFunctionName(String tok) {
final char begin = tok.charAt(0);
final boolean isIdentifier = Character.isJavaIdentifierStart( begin ) || '"'==begin;
return isIdentifier &&
!LOGICAL.contains(tok) &&
!END_CLAUSES.contains(tok) &&
!QUANTIFIERS.contains(tok) &&
!DML.contains(tok) &&
!MISC.contains(tok);
}
private static boolean isWhitespace(String token) {
return StringHelper.WHITESPACE.indexOf(token)>=0;
}
private void newline() {
result.append("\n");
for ( int i=0; i<indent; i++ ) {
result.append(indentString);
}
beginLine = true;
}
public static void main(String[] args) {
if ( args.length>0 ) System.out.println(
new Formatter( StringHelper.join(" ", args) ).format()
);
}
}

View File

@ -12,14 +12,15 @@ import java.io.Reader;
import java.io.Writer;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.SQLWarning;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.hibernate.HibernateException;
import org.hibernate.JDBCException;
import org.hibernate.cfg.Configuration;
@ -27,17 +28,19 @@ import org.hibernate.cfg.Environment;
import org.hibernate.cfg.NamingStrategy;
import org.hibernate.cfg.Settings;
import org.hibernate.dialect.Dialect;
import org.hibernate.pretty.DDLFormatter;
import org.hibernate.jdbc.util.FormatStyle;
import org.hibernate.jdbc.util.Formatter;
import org.hibernate.jdbc.util.SQLStatementLogger;
import org.hibernate.util.ConfigHelper;
import org.hibernate.util.JDBCExceptionReporter;
import org.hibernate.util.PropertiesHelper;
import org.hibernate.util.ReflectHelper;
import org.hibernate.util.JDBCExceptionReporter;
/**
* Commandline tool to export table schema to the database. This
* class may also be called from inside an application.
* Commandline tool to export table schema to the database. This class may also be called from inside an application.
*
* @author Daniel Bradby, Gavin King
* @author Daniel Bradby
* @author Gavin King
*/
public class SchemaExport {
@ -52,37 +55,46 @@ public class SchemaExport {
private String delimiter;
private final List exceptions = new ArrayList();
private boolean haltOnError = false;
private boolean format = true;
private Formatter formatter;
private SQLStatementLogger sqlStatementLogger;
/**
* Create a schema exporter for the given Configuration
*
* @param cfg The configuration from which to build a schema export.
* @throws HibernateException Indicates problem preparing for schema export.
*/
public SchemaExport(Configuration cfg) throws HibernateException {
this( cfg, cfg.getProperties() );
}
/**
* Create a schema exporter for the given Configuration
* and given settings
* Create a schema exporter for the given Configuration and given settings
*
* @param cfg The configuration from which to build a schema export.
* @param settings The 'parsed' settings.
* @throws HibernateException Indicates problem preparing for schema export.
*/
public SchemaExport(Configuration cfg, Settings settings) throws HibernateException {
dialect = settings.getDialect();
connectionHelper = new SuppliedConnectionProviderConnectionHelper(
settings.getConnectionProvider()
);
connectionHelper = new SuppliedConnectionProviderConnectionHelper( settings.getConnectionProvider() );
dropSQL = cfg.generateDropSchemaScript( dialect );
createSQL = cfg.generateSchemaCreationScript( dialect );
format = settings.isFormatSqlEnabled();
sqlStatementLogger = settings.getSqlStatementLogger();
formatter = ( sqlStatementLogger.isFormatSql() ? FormatStyle.DDL : FormatStyle.NONE ).getFormatter();
}
/**
* Create a schema exporter for the given Configuration, with the given
* database connection properties.
*
* @param cfg The configuration from which to build a schema export.
* @param properties The properties from which to configure connectivity etc.
* @throws HibernateException Indicates problem preparing for schema export.
*
* @deprecated properties may be specified via the Configuration object
*/
public SchemaExport(Configuration cfg, Properties properties)
throws HibernateException {
public SchemaExport(Configuration cfg, Properties properties) throws HibernateException {
dialect = Dialect.getDialect( properties );
Properties props = new Properties();
@ -92,24 +104,42 @@ public class SchemaExport {
connectionHelper = new ManagedProviderConnectionHelper( props );
dropSQL = cfg.generateDropSchemaScript( dialect );
createSQL = cfg.generateSchemaCreationScript( dialect );
format = PropertiesHelper.getBoolean( Environment.FORMAT_SQL, props );
formatter = ( PropertiesHelper.getBoolean( Environment.FORMAT_SQL, props ) ? FormatStyle.DDL : FormatStyle.NONE ).getFormatter();
}
public SchemaExport(Configuration cfg, Connection connection) {
/**
* Create a schema exporter for the given Configuration, using the supplied connection for connectivity.
*
* @param cfg The configuration to use.
* @param connection The JDBC connection to use.
* @throws HibernateException Indicates problem preparing for schema export.
*/
public SchemaExport(Configuration cfg, Connection connection) throws HibernateException {
this.connectionHelper = new SuppliedConnectionHelper( connection );
dialect = Dialect.getDialect( cfg.getProperties() );
dropSQL = cfg.generateDropSchemaScript( dialect );
createSQL = cfg.generateSchemaCreationScript( dialect );
formatter = ( PropertiesHelper.getBoolean( Environment.FORMAT_SQL, cfg.getProperties() ) ? FormatStyle.DDL : FormatStyle.NONE ).getFormatter();
}
/**
* Set an output filename. The generated script will be written to this file.
* For generating a export script file, this is the file which will be written.
*
* @param filename The name of the file to which to write the export script.
* @return this
*/
public SchemaExport setOutputFile(String filename) {
outputFile = filename;
return this;
}
/**
* An import file, containing raw SQL statements to be executed.
*
* @param filename The import file name.
* @return this
*/
public SchemaExport setImportFile(String filename) {
importFile = filename;
return this;
@ -117,12 +147,37 @@ public class SchemaExport {
/**
* Set the end of statement delimiter
*
* @param delimiter The delimiter
* @return this
*/
public SchemaExport setDelimiter(String delimiter) {
this.delimiter = delimiter;
return this;
}
/**
* Should we format the sql strings?
*
* @param format Should we format SQL strings
* @return this
*/
public SchemaExport setFormat(boolean format) {
this.formatter = ( format ? FormatStyle.DDL : FormatStyle.NONE ).getFormatter();
return this;
}
/**
* Should we stop once an error occurs?
*
* @param haltOnError True if export should stop after error.
* @return this
*/
public SchemaExport setHaltOnError(boolean haltOnError) {
this.haltOnError = haltOnError;
return this;
}
/**
* Run the schema creation script.
*
@ -143,12 +198,6 @@ public class SchemaExport {
execute( script, export, true, false );
}
private String format(String sql) {
return format ?
new DDLFormatter( sql ).format() :
sql;
}
public void execute(boolean script, boolean export, boolean justDrop, boolean justCreate) {
log.info( "Running hbm2ddl schema export" );
@ -295,7 +344,7 @@ public class SchemaExport {
private void execute(boolean script, boolean export, Writer fileOutput, Statement statement, final String sql)
throws IOException, SQLException {
String formatted = format( sql );
String formatted = formatter.format( sql );
if ( delimiter != null ) {
formatted += delimiter;
}
@ -307,6 +356,7 @@ public class SchemaExport {
fileOutput.write( formatted + "\n" );
}
if ( export ) {
statement.executeUpdate( sql );
try {
SQLWarning warnings = statement.getWarnings();
@ -423,14 +473,4 @@ public class SchemaExport {
public List getExceptions() {
return exceptions;
}
public SchemaExport setFormat(boolean format) {
this.format = format;
return this;
}
public SchemaExport setHaltOnError(boolean haltOnError) {
this.haltOnError = haltOnError;
return this;
}
}

View File

@ -0,0 +1,69 @@
/*
* Copyright (c) 2007, Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1. This program is distributed in the
* hope that it will be useful, but WITHOUT A 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, v.2.1 along with this
* distribution; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Red Hat Author(s): Steve Ebersole
*/
package org.hibernate.jdbc.util;
import java.util.StringTokenizer;
import junit.framework.TestCase;
/**
* BasicFormatterTest implementation
*
* @author Steve Ebersole
*/
public class BasicFormatterTest extends TestCase {
public BasicFormatterTest(String name) {
super( name );
}
public void testNoLoss() {
assertNoLoss( "insert into Address (city, state, zip, \"from\") values (?, ?, ?, 'insert value')" );
assertNoLoss( "delete from Address where id = ? and version = ?" );
assertNoLoss( "update Address set city = ?, state=?, zip=?, version = ? where id = ? and version = ?" );
assertNoLoss( "update Address set city = ?, state=?, zip=?, version = ? where id in (select aid from Person)" );
assertNoLoss(
"select p.name, a.zipCode, count(*) from Person p left outer join Employee e on e.id = p.id and p.type = 'E' and (e.effective>? or e.effective<?) join Address a on a.pid = p.id where upper(p.name) like 'G%' and p.age > 100 and (p.sex = 'M' or p.sex = 'F') and coalesce( trim(a.street), a.city, (a.zip) ) is not null order by p.name asc, a.zipCode asc"
);
assertNoLoss(
"select ( (m.age - p.age) * 12 ), trim(upper(p.name)) from Person p, Person m where p.mother = m.id and ( p.age = (select max(p0.age) from Person p0 where (p0.mother=m.id)) and p.name like ? )"
);
assertNoLoss(
"select * from Address a join Person p on a.pid = p.id, Person m join Address b on b.pid = m.id where p.mother = m.id and p.name like ?"
);
assertNoLoss(
"select case when p.age > 50 then 'old' when p.age > 18 then 'adult' else 'child' end from Person p where ( case when p.age > 50 then 'old' when p.age > 18 then 'adult' else 'child' end ) like ?"
);
assertNoLoss(
"/* Here we' go! */ select case when p.age > 50 then 'old' when p.age > 18 then 'adult' else 'child' end from Person p where ( case when p.age > 50 then 'old' when p.age > 18 then 'adult' else 'child' end ) like ?"
);
}
private void assertNoLoss(String query) {
String formattedQuery = FormatStyle.BASIC.getFormatter().format( query );
StringTokenizer formatted = new StringTokenizer( formattedQuery, " \t\n\r\f()" );
StringTokenizer plain = new StringTokenizer( query, " \t\n\r\f()" );
System.out.println( "Original: " + query );
System.out.println( "Formatted: " + formattedQuery );
while ( formatted.hasMoreTokens() && plain.hasMoreTokens() ) {
String plainToken = plain.nextToken();
String formattedToken = formatted.nextToken();
assertEquals( "formatter did not return the same token", plainToken, formattedToken );
}
assertFalse( formatted.hasMoreTokens() );
assertFalse( plain.hasMoreTokens() );
}
}

View File

@ -0,0 +1,69 @@
/*
* Copyright (c) 2007, Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1. This program is distributed in the
* hope that it will be useful, but WITHOUT A 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, v.2.1 along with this
* distribution; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Red Hat Author(s): Steve Ebersole
*/
package org.hibernate.jdbc;
/**
* Boat implementation
*
* @author Steve Ebersole
*/
public class Boat {
private Long id;
private String tag;
private Person driver;
private Person boarder;
public Boat() {
}
public Boat(String tag, Person driver, Person boarder) {
this.tag = tag;
this.driver = driver;
this.boarder = boarder;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getTag() {
return tag;
}
public void setTag(String tag) {
this.tag = tag;
}
public Person getDriver() {
return driver;
}
public void setDriver(Person driver) {
this.driver = driver;
}
public Person getBoarder() {
return boarder;
}
public void setBoarder(Person boarder) {
this.boarder = boarder;
}
}

View File

@ -0,0 +1,136 @@
/*
* Copyright (c) 2007, Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1. This program is distributed in the
* hope that it will be useful, but WITHOUT A 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, v.2.1 along with this
* distribution; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Red Hat Author(s): Steve Ebersole
*/
package org.hibernate.jdbc;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import junit.framework.Test;
import org.hibernate.JDBCException;
import org.hibernate.Session;
import org.hibernate.junit.functional.FunctionalTestCase;
import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
/**
* GeneralWorkTest implementation
*
* @author Steve Ebersole
*/
public class GeneralWorkTest extends FunctionalTestCase {
public GeneralWorkTest(String string) {
super( string );
}
public String getBaseForMappings() {
return "org/hibernate/";
}
public String[] getMappings() {
return new String[] { "jdbc/Mappings.hbm.xml" };
}
public static Test suite() {
return new FunctionalTestClassTestSuite( GeneralWorkTest.class );
}
public void testGeneralUsage() throws Throwable {
Session session = openSession();
session.beginTransaction();
session.doWork(
new Work() {
public void execute(Connection connection) throws SQLException {
// in this current form, users must handle try/catches themselves for proper resource release
Statement statement = null;
try {
statement = connection.createStatement();
ResultSet resultSet = null;
try {
resultSet = statement.executeQuery( "select * from T_JDBC_PERSON" );
}
finally {
releaseQuietly( resultSet );
}
try {
resultSet = statement.executeQuery( "select * from T_JDBC_BOAT" );
}
finally {
releaseQuietly( resultSet );
}
}
finally {
releaseQuietly( statement );
}
}
}
);
session.getTransaction().commit();
session.close();
}
public void testSQLExceptionThrowing() {
Session session = openSession();
session.beginTransaction();
try {
session.doWork(
new Work() {
public void execute(Connection connection) throws SQLException {
Statement statement = null;
try {
statement = connection.createStatement();
statement.executeQuery( "select * from non_existent" );
}
finally {
releaseQuietly( statement );
}
}
}
);
fail( "expecting exception" );
}
catch ( JDBCException expected ) {
// expected outcome
}
session.getTransaction().commit();
session.close();
}
private void releaseQuietly(Statement statement) {
if ( statement == null ) {
return;
}
try {
statement.close();
}
catch ( SQLException e ) {
// ignore
}
}
private void releaseQuietly(ResultSet resultSet) {
if ( resultSet == null ) {
return;
}
try {
resultSet.close();
}
catch ( SQLException e ) {
// ignore
}
}
}

View File

@ -0,0 +1,41 @@
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!--
~ Copyright (c) 2007, Red Hat Middleware, LLC. All rights reserved.
~
~ 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, v. 2.1. This program is distributed in the
~ hope that it will be useful, but WITHOUT A 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, v.2.1 along with this
~ distribution; if not, write to the Free Software Foundation, Inc.,
~ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
~
~ Red Hat Author(s): Steve Ebersole
-->
<hibernate-mapping package="org.hibernate.jdbc">
<class name="Person" table="T_JDBC_PERSON">
<id name="id" column="ID">
<generator class="increment" />
</id>
<property name="firstName" />
<property name="lastName" />
</class>
<class name="Boat" table="T_JDBC_BOAT">
<id name="id" column="ID">
<generator class="increment" />
</id>
<property name="tag" />
<many-to-one name="driver"/>
<many-to-one name="boarder"/>
</class>
</hibernate-mapping>

View File

@ -0,0 +1,59 @@
/*
* Copyright (c) 2007, Red Hat Middleware, LLC. All rights reserved.
*
* 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, v. 2.1. This program is distributed in the
* hope that it will be useful, but WITHOUT A 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, v.2.1 along with this
* distribution; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Red Hat Author(s): Steve Ebersole
*/
package org.hibernate.jdbc;
/**
* Person implementation
*
* @author Steve Ebersole
*/
public class Person {
private Long id;
private String firstName;
private String lastName;
public Person() {
}
public Person(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}

View File

@ -22,7 +22,7 @@ import java.io.Serializable;
*
* @author Steve Ebersole
*/
public class AbstractJPATest extends FunctionalTestCase {
public abstract class AbstractJPATest extends FunctionalTestCase {
public AbstractJPATest(String name) {
super( name );
}

View File

@ -1,43 +0,0 @@
package org.hibernate.test.pretty;
import java.util.StringTokenizer;
import org.hibernate.pretty.Formatter;
import org.hibernate.junit.UnitTestCase;
public class SQLFormatterTest extends UnitTestCase {
public SQLFormatterTest(String string) {
super( string );
}
public void testNoLoss() {
assertNoLoss("insert into Address (city, state, zip, \"from\") values (?, ?, ?, 'insert value')");
assertNoLoss("delete from Address where id = ? and version = ?");
assertNoLoss("update Address set city = ?, state=?, zip=?, version = ? where id = ? and version = ?");
assertNoLoss("update Address set city = ?, state=?, zip=?, version = ? where id in (select aid from Person)");
assertNoLoss("select p.name, a.zipCode, count(*) from Person p left outer join Employee e on e.id = p.id and p.type = 'E' and (e.effective>? or e.effective<?) join Address a on a.pid = p.id where upper(p.name) like 'G%' and p.age > 100 and (p.sex = 'M' or p.sex = 'F') and coalesce( trim(a.street), a.city, (a.zip) ) is not null order by p.name asc, a.zipCode asc");
assertNoLoss("select ( (m.age - p.age) * 12 ), trim(upper(p.name)) from Person p, Person m where p.mother = m.id and ( p.age = (select max(p0.age) from Person p0 where (p0.mother=m.id)) and p.name like ? )");
assertNoLoss("select * from Address a join Person p on a.pid = p.id, Person m join Address b on b.pid = m.id where p.mother = m.id and p.name like ?");
assertNoLoss("select case when p.age > 50 then 'old' when p.age > 18 then 'adult' else 'child' end from Person p where ( case when p.age > 50 then 'old' when p.age > 18 then 'adult' else 'child' end ) like ?");
assertNoLoss("/* Here we' go! */ select case when p.age > 50 then 'old' when p.age > 18 then 'adult' else 'child' end from Person p where ( case when p.age > 50 then 'old' when p.age > 18 then 'adult' else 'child' end ) like ?");
}
private void assertNoLoss(String query) {
String formattedQuery = new Formatter(query).format();
StringTokenizer formatted = new StringTokenizer(formattedQuery," \t\n\r\f()");
StringTokenizer plain = new StringTokenizer(query," \t\n\r\f()");
System.out.println("Original: " + query);
System.out.println("Formatted: " + formattedQuery);
while(formatted.hasMoreTokens() && plain.hasMoreTokens()) {
String plainToken = plain.nextToken();
String formattedToken = formatted.nextToken();
assertEquals("formatter did not return the same token",plainToken, formattedToken);
}
assertFalse(formatted.hasMoreTokens());
assertFalse(plain.hasMoreTokens());
}
}