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:
parent
ccdfd6c4a3
commit
9d406f51d2
|
@ -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;
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 );
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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 );
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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()
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() );
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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>
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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 );
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
||||
}
|
Loading…
Reference in New Issue