Add cleaners for clearing a schema the first time before running a test
This commit is contained in:
parent
d767d46d05
commit
08d9fe1a3b
|
@ -9,6 +9,8 @@ package org.hibernate.envers.test;
|
|||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.testing.cleaner.DatabaseCleaner;
|
||||
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
|
||||
|
@ -22,6 +24,10 @@ import org.jboss.logging.Logger;
|
|||
@RunWith(EnversRunner.class)
|
||||
public abstract class AbstractEnversTest {
|
||||
|
||||
static {
|
||||
DatabaseCleaner.clearSchemas();
|
||||
}
|
||||
|
||||
protected final Logger log = Logger.getLogger( getClass() );
|
||||
|
||||
private String auditStrategy;
|
||||
|
|
|
@ -0,0 +1,194 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.testing.cleaner;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public abstract class AbstractMySQLDatabaseCleaner implements DatabaseCleaner {
|
||||
private static final Logger LOG = Logger.getLogger( AbstractMySQLDatabaseCleaner.class.getName() );
|
||||
private static final String SYSTEM_SCHEMAS = "'information_schema'," +
|
||||
"'mysql'," +
|
||||
"'sys'," +
|
||||
"'performance_schema'";
|
||||
private final List<String> ignoredTables = new ArrayList<>();
|
||||
private final Map<String, List<String>> clearingSqlsPerSchema = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public void addIgnoredTable(String tableName) {
|
||||
ignoredTables.add( tableName );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearAllSchemas(Connection connection) {
|
||||
try {
|
||||
clearSchema( connection, connection.getSchema() );
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw new RuntimeException( e );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearSchema(Connection connection, String schemaName) {
|
||||
clearSchema0( connection, schemaName );
|
||||
}
|
||||
|
||||
private void clearSchema0(Connection c, String schemaName) {
|
||||
clearingSqlsPerSchema.remove( schemaName );
|
||||
try (Statement s = c.createStatement()) {
|
||||
// Collect schema names
|
||||
LOG.log( Level.FINEST, "Collect table names: START" );
|
||||
ResultSet rs = s.executeQuery(
|
||||
"SELECT TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = '" + schemaName + "'" );
|
||||
|
||||
StringBuilder sb = new StringBuilder( "DROP TABLE " );
|
||||
if ( rs.next() ) {
|
||||
do {
|
||||
String tableSchema = rs.getString( 1 );
|
||||
String tableName = rs.getString( 2 );
|
||||
sb.append( tableSchema );
|
||||
sb.append( '.' );
|
||||
sb.append( tableName );
|
||||
sb.append( ',' );
|
||||
} while ( rs.next() );
|
||||
}
|
||||
else {
|
||||
// Nothing to clear since there are no tables
|
||||
return;
|
||||
}
|
||||
sb.setCharAt( sb.length() - 1, ' ' );
|
||||
LOG.log( Level.FINEST, "Collect table names: END" );
|
||||
|
||||
// Disable foreign keys
|
||||
LOG.log( Level.FINEST, "Disable foreign keys: START" );
|
||||
s.execute( "SET FOREIGN_KEY_CHECKS = 0" );
|
||||
LOG.log( Level.FINEST, "Disable foreign keys: END" );
|
||||
|
||||
LOG.log( Level.FINEST, "Dropping tables: START" );
|
||||
String sql = sb.toString();
|
||||
s.execute( sql );
|
||||
LOG.log( Level.FINEST, "Dropping tables: END" );
|
||||
|
||||
// Enable foreign keys
|
||||
LOG.log( Level.FINEST, "Enabling foreign keys: START" );
|
||||
s.execute( "SET FOREIGN_KEY_CHECKS = 1" );
|
||||
LOG.log( Level.FINEST, "Enabling foreign keys: END" );
|
||||
|
||||
LOG.log( Level.FINEST, "Committing: START" );
|
||||
c.commit();
|
||||
LOG.log( Level.FINEST, "Committing: END" );
|
||||
}
|
||||
catch (SQLException e) {
|
||||
try {
|
||||
c.rollback();
|
||||
}
|
||||
catch (SQLException e1) {
|
||||
e.addSuppressed( e1 );
|
||||
}
|
||||
|
||||
throw new RuntimeException( e );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearAllData(Connection connection) {
|
||||
clearData0(
|
||||
connection,
|
||||
null,
|
||||
statement -> {
|
||||
try {
|
||||
return statement.executeQuery(
|
||||
"SELECT TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA NOT IN (" + SYSTEM_SCHEMAS + ")" );
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw new RuntimeException( e );
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearData(Connection connection, String schemaName) {
|
||||
clearData0(
|
||||
connection,
|
||||
schemaName,
|
||||
statement -> {
|
||||
try {
|
||||
return statement.executeQuery(
|
||||
"SELECT TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = '" + schemaName + "'" );
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw new RuntimeException( e );
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private void clearData0(Connection connection, String schemaName, Function<Statement, ResultSet> tablesProvider) {
|
||||
try (Statement s = connection.createStatement()) {
|
||||
// Disable foreign keys
|
||||
LOG.log( Level.FINEST, "Disable foreign keys: START" );
|
||||
s.execute( "SET FOREIGN_KEY_CHECKS = 0" );
|
||||
LOG.log( Level.FINEST, "Disable foreign keys: END" );
|
||||
|
||||
// Delete data
|
||||
LOG.log( Level.FINEST, "Deleting data: START" );
|
||||
List<String> clearingSqls = clearingSqlsPerSchema.get( schemaName );
|
||||
if ( clearingSqls == null ) {
|
||||
clearingSqls = new ArrayList<>();
|
||||
ResultSet rs = tablesProvider.apply( s );
|
||||
while ( rs.next() ) {
|
||||
String tableSchema = rs.getString( 1 );
|
||||
String tableName = rs.getString( 2 );
|
||||
if ( !ignoredTables.contains( tableName ) ) {
|
||||
clearingSqls.add( createClearingStatementForTable( tableSchema, tableName ) );
|
||||
}
|
||||
}
|
||||
clearingSqlsPerSchema.put( schemaName, clearingSqls );
|
||||
}
|
||||
for ( String clearingSql : clearingSqls ) {
|
||||
s.execute( clearingSql );
|
||||
}
|
||||
LOG.log( Level.FINEST, "Deleting data: END" );
|
||||
|
||||
// Enable foreign keys
|
||||
LOG.log( Level.FINEST, "Enabling foreign keys: START" );
|
||||
s.execute( "SET FOREIGN_KEY_CHECKS = 1" );
|
||||
LOG.log( Level.FINEST, "Enabling foreign keys: END" );
|
||||
|
||||
LOG.log( Level.FINEST, "Committing: START" );
|
||||
connection.commit();
|
||||
LOG.log( Level.FINEST, "Committing: END" );
|
||||
}
|
||||
catch (SQLException e) {
|
||||
try {
|
||||
connection.rollback();
|
||||
}
|
||||
catch (SQLException e1) {
|
||||
e.addSuppressed( e1 );
|
||||
}
|
||||
|
||||
throw new RuntimeException( e );
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract String createClearingStatementForTable(String tableSchema, String tableName);
|
||||
|
||||
}
|
|
@ -0,0 +1,416 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.testing.cleaner;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public class DB2DatabaseCleaner implements DatabaseCleaner {
|
||||
|
||||
private static final Logger LOG = Logger.getLogger( DB2DatabaseCleaner.class.getName() );
|
||||
private static final String SYSTEM_SCHEMAS = "'SYSCAT',"
|
||||
+ "'SYSIBM',"
|
||||
+ "'SYSIBMADM',"
|
||||
+ "'SYSPUBLIC',"
|
||||
+ "'SYSSTAT',"
|
||||
+ "'SYSTOOLS'";
|
||||
|
||||
private final List<String> ignoredTables = new ArrayList<>();
|
||||
private final Map<String, Map<String, List<String>>> cachedForeignKeysPerSchema = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public boolean isApplicable(Connection connection) {
|
||||
try {
|
||||
return connection.getMetaData().getDatabaseProductName().startsWith( "DB2" );
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw new RuntimeException( "Could not resolve the database metadata!", e );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addIgnoredTable(String tableName) {
|
||||
ignoredTables.add( tableName );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearAllSchemas(Connection c) {
|
||||
cachedForeignKeysPerSchema.clear();
|
||||
try (Statement s = c.createStatement()) {
|
||||
ResultSet rs;
|
||||
List<String> sqls = new ArrayList<>();
|
||||
|
||||
// Collect schema objects
|
||||
LOG.log( Level.FINEST, "Collect schema objects: START" );
|
||||
rs = s.executeQuery(
|
||||
"SELECT 'DROP INDEX \"' || TRIM(INDSCHEMA) || '\".\"' || TRIM(INDNAME) || '\"' " +
|
||||
"FROM SYSCAT.INDEXES " +
|
||||
"WHERE UNIQUERULE = 'D' " +
|
||||
"AND INDSCHEMA NOT IN (" + SYSTEM_SCHEMAS + ")"
|
||||
);
|
||||
while ( rs.next() ) {
|
||||
sqls.add( rs.getString( 1 ) );
|
||||
}
|
||||
|
||||
rs = s.executeQuery(
|
||||
"SELECT 'ALTER TABLE \"' || TRIM(TABSCHEMA) || '\".\"' || TRIM(TABNAME) || '\" DROP FOREIGN KEY \"' || TRIM(CONSTNAME) || '\"' " +
|
||||
"FROM SYSCAT.TABCONST " +
|
||||
"WHERE TYPE = 'F' " +
|
||||
"AND TABSCHEMA NOT IN (" + SYSTEM_SCHEMAS + ")"
|
||||
);
|
||||
while ( rs.next() ) {
|
||||
sqls.add( rs.getString( 1 ) );
|
||||
}
|
||||
|
||||
rs = s.executeQuery(
|
||||
"SELECT 'ALTER TABLE \"' || TRIM(TABSCHEMA) || '\".\"' || TRIM(TABNAME) || '\" DROP UNIQUE \"' || TRIM(INDNAME) || '\"' " +
|
||||
"FROM SYSCAT.INDEXES " +
|
||||
"WHERE UNIQUERULE = 'U' " +
|
||||
"AND INDSCHEMA NOT IN (" + SYSTEM_SCHEMAS + ")"
|
||||
);
|
||||
while ( rs.next() ) {
|
||||
sqls.add( rs.getString( 1 ) );
|
||||
}
|
||||
|
||||
rs = s.executeQuery(
|
||||
"SELECT 'ALTER TABLE \"' || TRIM(TABSCHEMA) || '\".\"' || TRIM(TABNAME) || '\" DROP PRIMARY KEY' " +
|
||||
"FROM SYSCAT.INDEXES " +
|
||||
"WHERE UNIQUERULE = 'P' " +
|
||||
"AND INDSCHEMA NOT IN (" + SYSTEM_SCHEMAS + ")"
|
||||
);
|
||||
while ( rs.next() ) {
|
||||
sqls.add( rs.getString( 1 ) );
|
||||
}
|
||||
|
||||
rs = s.executeQuery(
|
||||
"SELECT 'DROP VIEW \"' || TRIM(TABSCHEMA) || '\".\"' || TRIM(TABNAME) || '\"' " +
|
||||
"FROM SYSCAT.TABLES " +
|
||||
"WHERE TYPE = 'V' " +
|
||||
"AND TABSCHEMA NOT IN (" + SYSTEM_SCHEMAS + ")"
|
||||
);
|
||||
while ( rs.next() ) {
|
||||
sqls.add( rs.getString( 1 ) );
|
||||
}
|
||||
|
||||
rs = s.executeQuery(
|
||||
"SELECT 'DROP TABLE \"' || TRIM(TABSCHEMA) || '\".\"' || TRIM(TABNAME) || '\"' " +
|
||||
"FROM SYSCAT.TABLES " +
|
||||
"WHERE TYPE = 'T' " +
|
||||
"AND TABSCHEMA NOT IN (" + SYSTEM_SCHEMAS + ")"
|
||||
);
|
||||
while ( rs.next() ) {
|
||||
sqls.add( rs.getString( 1 ) );
|
||||
}
|
||||
|
||||
rs = s.executeQuery(
|
||||
"SELECT 'DROP SEQUENCE \"' || TRIM(SEQSCHEMA) || '\".\"' || TRIM(SEQNAME) || '\"' " +
|
||||
"FROM SYSCAT.SEQUENCES " +
|
||||
"WHERE SEQSCHEMA NOT IN (" + SYSTEM_SCHEMAS + ")"
|
||||
);
|
||||
while ( rs.next() ) {
|
||||
sqls.add( rs.getString( 1 ) );
|
||||
}
|
||||
LOG.log( Level.FINEST, "Collect schema objects: END" );
|
||||
|
||||
LOG.log( Level.FINEST, "Dropping schema objects: START" );
|
||||
for ( String sql : sqls ) {
|
||||
try {
|
||||
s.execute( sql );
|
||||
}
|
||||
catch (SQLException e) {
|
||||
if ( -204 == e.getErrorCode() ) {
|
||||
// Apparently we deleted this along with a dependent object since it doesn't exist anymore
|
||||
}
|
||||
else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
LOG.log( Level.FINEST, "Dropping schema objects: END" );
|
||||
|
||||
LOG.log( Level.FINEST, "Committing: START" );
|
||||
c.commit();
|
||||
LOG.log( Level.FINEST, "Committing: END" );
|
||||
}
|
||||
catch (SQLException e) {
|
||||
try {
|
||||
c.rollback();
|
||||
}
|
||||
catch (SQLException e1) {
|
||||
e.addSuppressed( e1 );
|
||||
}
|
||||
|
||||
throw new RuntimeException( e );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearSchema(Connection c, String schemaName) {
|
||||
cachedForeignKeysPerSchema.remove( schemaName );
|
||||
schemaName = schemaName.toUpperCase();
|
||||
try (Statement s = c.createStatement()) {
|
||||
ResultSet rs;
|
||||
List<String> sqls = new ArrayList<>();
|
||||
|
||||
// Collect schema objects
|
||||
LOG.log( Level.FINEST, "Collect schema objects: START" );
|
||||
rs = s.executeQuery(
|
||||
"SELECT 'DROP INDEX \"' || TRIM(INDSCHEMA) || '\".\"' || TRIM(INDNAME) || '\"' " +
|
||||
"FROM SYSCAT.INDEXES " +
|
||||
"WHERE UNIQUERULE = 'D' " +
|
||||
"AND INDSCHEMA = '" + schemaName + "'"
|
||||
);
|
||||
while ( rs.next() ) {
|
||||
sqls.add( rs.getString( 1 ) );
|
||||
}
|
||||
|
||||
rs = s.executeQuery(
|
||||
"SELECT 'ALTER TABLE \"' || TRIM(TABSCHEMA) || '\".\"' || TRIM(TABNAME) || '\" DROP FOREIGN KEY \"' || TRIM(CONSTNAME) || '\"' " +
|
||||
"FROM SYSCAT.TABCONST " +
|
||||
"WHERE TYPE = 'F' " +
|
||||
"AND TABSCHEMA = '" + schemaName + "'"
|
||||
);
|
||||
while ( rs.next() ) {
|
||||
sqls.add( rs.getString( 1 ) );
|
||||
}
|
||||
|
||||
rs = s.executeQuery(
|
||||
"SELECT 'ALTER TABLE \"' || TRIM(TABSCHEMA) || '\".\"' || TRIM(TABNAME) || '\" DROP UNIQUE \"' || TRIM(INDNAME) || '\"' " +
|
||||
"FROM SYSCAT.INDEXES " +
|
||||
"WHERE UNIQUERULE = 'U' " +
|
||||
"AND INDSCHEMA = '" + schemaName + "'"
|
||||
);
|
||||
while ( rs.next() ) {
|
||||
sqls.add( rs.getString( 1 ) );
|
||||
}
|
||||
|
||||
rs = s.executeQuery(
|
||||
"SELECT 'ALTER TABLE \"' || TRIM(TABSCHEMA) || '\".\"' || TRIM(TABNAME) || '\" DROP PRIMARY KEY' " +
|
||||
"FROM SYSCAT.INDEXES " +
|
||||
"WHERE UNIQUERULE = 'P' " +
|
||||
"AND INDSCHEMA = '" + schemaName + "'"
|
||||
);
|
||||
while ( rs.next() ) {
|
||||
sqls.add( rs.getString( 1 ) );
|
||||
}
|
||||
|
||||
rs = s.executeQuery(
|
||||
"SELECT 'DROP VIEW \"' || TRIM(TABSCHEMA) || '\".\"' || TRIM(TABNAME) || '\"' " +
|
||||
"FROM SYSCAT.TABLES " +
|
||||
"WHERE TYPE = 'V' " +
|
||||
"AND TABSCHEMA = '" + schemaName + "'"
|
||||
);
|
||||
while ( rs.next() ) {
|
||||
sqls.add( rs.getString( 1 ) );
|
||||
}
|
||||
|
||||
rs = s.executeQuery(
|
||||
"SELECT 'DROP TABLE \"' || TRIM(TABSCHEMA) || '\".\"' || TRIM(TABNAME) || '\"' " +
|
||||
"FROM SYSCAT.TABLES " +
|
||||
"WHERE TYPE = 'T' " +
|
||||
"AND TABSCHEMA = '" + schemaName + "'"
|
||||
);
|
||||
while ( rs.next() ) {
|
||||
sqls.add( rs.getString( 1 ) );
|
||||
}
|
||||
|
||||
rs = s.executeQuery(
|
||||
"SELECT 'DROP SEQUENCE \"' || TRIM(SEQSCHEMA) || '\".\"' || TRIM(SEQNAME) || '\"' " +
|
||||
"FROM SYSCAT.SEQUENCES " +
|
||||
"WHERE SEQSCHEMA = '" + schemaName + "'"
|
||||
);
|
||||
while ( rs.next() ) {
|
||||
sqls.add( rs.getString( 1 ) );
|
||||
}
|
||||
LOG.log( Level.FINEST, "Collect schema objects: END" );
|
||||
|
||||
LOG.log( Level.FINEST, "Dropping schema objects: START" );
|
||||
for ( String sql : sqls ) {
|
||||
try {
|
||||
s.execute( sql );
|
||||
}
|
||||
catch (SQLException e) {
|
||||
if ( -204 == e.getErrorCode() ) {
|
||||
// Apparently we deleted this along with a dependent object since it doesn't exist anymore
|
||||
}
|
||||
else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
LOG.log( Level.FINEST, "Dropping schema objects: END" );
|
||||
|
||||
LOG.log( Level.FINEST, "Committing: START" );
|
||||
c.commit();
|
||||
LOG.log( Level.FINEST, "Committing: END" );
|
||||
}
|
||||
catch (SQLException e) {
|
||||
try {
|
||||
c.rollback();
|
||||
}
|
||||
catch (SQLException e1) {
|
||||
e.addSuppressed( e1 );
|
||||
}
|
||||
|
||||
throw new RuntimeException( e );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearAllData(Connection connection) {
|
||||
Map<String, List<String>> cachedForeignKeys = cachedForeignKeysPerSchema.get( null );
|
||||
if ( cachedForeignKeys == null ) {
|
||||
cachedForeignKeys = collectAllForeignKeys( connection );
|
||||
cachedForeignKeysPerSchema.put( null, cachedForeignKeys );
|
||||
}
|
||||
deleteAllData( connection, cachedForeignKeys );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearData(Connection connection, String schemaName) {
|
||||
Map<String, List<String>> cachedForeignKeys = cachedForeignKeysPerSchema.get( schemaName );
|
||||
if ( cachedForeignKeys == null ) {
|
||||
cachedForeignKeys = collectForeignKeys( connection, schemaName.toUpperCase() );
|
||||
cachedForeignKeysPerSchema.put( schemaName, cachedForeignKeys );
|
||||
}
|
||||
deleteAllData( connection, cachedForeignKeys );
|
||||
}
|
||||
|
||||
private Map<String, List<String>> collectAllForeignKeys(Connection c) {
|
||||
try (Statement s = c.createStatement()) {
|
||||
// Collect table names for schemas
|
||||
LOG.log( Level.FINEST, "Collect table names: START" );
|
||||
ResultSet rs = s.executeQuery(
|
||||
"SELECT TABLE_SCHEMA || '.' || TABLE_NAME FROM SYSIBM.TABLES WHERE TABLE_SCHEMA NOT IN (" + SYSTEM_SCHEMAS + ")"
|
||||
);
|
||||
Map<String, List<String>> foreignKeys = new HashMap<>();
|
||||
while ( rs.next() ) {
|
||||
foreignKeys.put( rs.getString( 1 ), new ArrayList<String>() );
|
||||
}
|
||||
LOG.log( Level.FINEST, "Collect table names: END" );
|
||||
|
||||
// Collect foreign keys for tables
|
||||
LOG.log( Level.FINEST, "Collect foreign keys: START" );
|
||||
ResultSet rs2 = s.executeQuery(
|
||||
"SELECT FKTABLE_SCHEM || '.' || FKTABLE_NAME, FK_NAME FROM SYSIBM.SQLFOREIGNKEYS WHERE FKTABLE_SCHEM NOT IN (" + SYSTEM_SCHEMAS + ")"
|
||||
);
|
||||
while ( rs2.next() ) {
|
||||
foreignKeys.get( rs2.getString( 1 ) ).add( rs2.getString( 2 ) );
|
||||
}
|
||||
LOG.log( Level.FINEST, "Collect foreign keys: END" );
|
||||
|
||||
return foreignKeys;
|
||||
}
|
||||
catch (SQLException e) {
|
||||
try {
|
||||
c.rollback();
|
||||
}
|
||||
catch (SQLException e1) {
|
||||
e.addSuppressed( e1 );
|
||||
}
|
||||
|
||||
throw new RuntimeException( e );
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, List<String>> collectForeignKeys(Connection c, String schemaName) {
|
||||
try (Statement s = c.createStatement()) {
|
||||
// Collect table names for schemas
|
||||
LOG.log( Level.FINEST, "Collect table names: START" );
|
||||
ResultSet rs = s.executeQuery(
|
||||
"SELECT TRIM(TABLE_SCHEMA) || '.' || TABLE_NAME FROM SYSIBM.TABLES WHERE TABLE_SCHEMA = '" + schemaName + "'"
|
||||
);
|
||||
Map<String, List<String>> foreignKeys = new HashMap<>();
|
||||
while ( rs.next() ) {
|
||||
foreignKeys.put( rs.getString( 1 ), new ArrayList<String>() );
|
||||
}
|
||||
LOG.log( Level.FINEST, "Collect table names: END" );
|
||||
|
||||
// Collect foreign keys for tables
|
||||
LOG.log( Level.FINEST, "Collect foreign keys: START" );
|
||||
ResultSet rs2 = s.executeQuery(
|
||||
"SELECT FKTABLE_SCHEM || '.' || FKTABLE_NAME, FK_NAME FROM SYSIBM.SQLFOREIGNKEYS WHERE FKTABLE_SCHEM = '" + schemaName + "'"
|
||||
);
|
||||
while ( rs2.next() ) {
|
||||
foreignKeys.get( rs2.getString( 1 ) ).add( rs2.getString( 2 ) );
|
||||
}
|
||||
LOG.log( Level.FINEST, "Collect foreign keys: END" );
|
||||
|
||||
return foreignKeys;
|
||||
}
|
||||
catch (SQLException e) {
|
||||
try {
|
||||
c.rollback();
|
||||
}
|
||||
catch (SQLException e1) {
|
||||
e.addSuppressed( e1 );
|
||||
}
|
||||
|
||||
throw new RuntimeException( e );
|
||||
}
|
||||
}
|
||||
|
||||
private void deleteAllData(Connection c, Map<String, List<String>> foreignKeys) {
|
||||
try (Statement s = c.createStatement()) {
|
||||
// Disable foreign keys
|
||||
LOG.log( Level.FINEST, "Disable foreign keys: START" );
|
||||
for ( Map.Entry<String, List<String>> entry : foreignKeys.entrySet() ) {
|
||||
for ( String fk : entry.getValue() ) {
|
||||
s.execute( "ALTER TABLE " + entry.getKey() + " ALTER FOREIGN KEY " + fk + " NOT ENFORCED" );
|
||||
}
|
||||
}
|
||||
c.commit();
|
||||
LOG.log( Level.FINEST, "Disable foreign keys: END" );
|
||||
|
||||
// Delete data
|
||||
LOG.log( Level.FINEST, "Deleting data: START" );
|
||||
for ( String table : foreignKeys.keySet() ) {
|
||||
if ( !ignoredTables.contains( table ) ) {
|
||||
s.execute( "TRUNCATE TABLE " + table + " IMMEDIATE" );
|
||||
// DB2 needs a commit after every truncate statement
|
||||
c.commit();
|
||||
}
|
||||
}
|
||||
LOG.log( Level.FINEST, "Deleting data: END" );
|
||||
|
||||
// Enable foreign keys
|
||||
LOG.log( Level.FINEST, "Enabling foreign keys: START" );
|
||||
for ( Map.Entry<String, List<String>> entry : foreignKeys.entrySet() ) {
|
||||
for ( String fk : entry.getValue() ) {
|
||||
s.execute( "ALTER TABLE " + entry.getKey() + " ALTER FOREIGN KEY " + fk + " ENFORCED" );
|
||||
}
|
||||
}
|
||||
LOG.log( Level.FINEST, "Enabling foreign keys: END" );
|
||||
|
||||
LOG.log( Level.FINEST, "Committing: START" );
|
||||
c.commit();
|
||||
LOG.log( Level.FINEST, "Committing: END" );
|
||||
}
|
||||
catch (SQLException e) {
|
||||
try {
|
||||
c.rollback();
|
||||
}
|
||||
catch (SQLException e1) {
|
||||
e.addSuppressed( e1 );
|
||||
}
|
||||
|
||||
throw new RuntimeException( e );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.testing.cleaner;
|
||||
|
||||
import java.sql.Connection;
|
||||
|
||||
/**
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public interface DatabaseCleaner {
|
||||
|
||||
static void clearSchemas() {
|
||||
final DatabaseCleaner cleaner = DatabaseCleanerContext.CLEANER;
|
||||
if ( cleaner != null ) {
|
||||
JdbcConnectionContext.work( cleaner::clearAllSchemas );
|
||||
}
|
||||
}
|
||||
|
||||
static void clearData() {
|
||||
final DatabaseCleaner cleaner = DatabaseCleanerContext.CLEANER;
|
||||
if ( cleaner != null ) {
|
||||
JdbcConnectionContext.work( cleaner::clearAllData );
|
||||
}
|
||||
}
|
||||
|
||||
void addIgnoredTable(String tableName);
|
||||
|
||||
boolean isApplicable(Connection connection);
|
||||
|
||||
void clearAllSchemas(Connection connection);
|
||||
|
||||
void clearSchema(Connection connection, String schemaName);
|
||||
|
||||
void clearAllData(Connection connection);
|
||||
|
||||
void clearData(Connection connection, String schemaName);
|
||||
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.testing.cleaner;
|
||||
|
||||
/**
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public final class DatabaseCleanerContext {
|
||||
|
||||
public static final DatabaseCleaner CLEANER;
|
||||
|
||||
static {
|
||||
CLEANER = JdbcConnectionContext.workReturning(
|
||||
connection -> {
|
||||
final DatabaseCleaner[] cleaners = new DatabaseCleaner[] {
|
||||
new DB2DatabaseCleaner(),
|
||||
new H2DatabaseCleaner(),
|
||||
new SQLServerDatabaseCleaner(),
|
||||
new MySQL5DatabaseCleaner(),
|
||||
new MySQL8DatabaseCleaner(),
|
||||
new MariaDBDatabaseCleaner(),
|
||||
new OracleDatabaseCleaner(),
|
||||
new PostgreSQLDatabaseCleaner()
|
||||
};
|
||||
for ( DatabaseCleaner cleaner : cleaners ) {
|
||||
if ( cleaner.isApplicable( connection ) ) {
|
||||
return cleaner;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private DatabaseCleanerContext() {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,158 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.testing.cleaner;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public class H2DatabaseCleaner implements DatabaseCleaner {
|
||||
|
||||
private static final Logger LOG = Logger.getLogger( H2DatabaseCleaner.class.getName() );
|
||||
private static final String SYSTEM_SCHEMAS = "'INFORMATION_SCHEMA'";
|
||||
|
||||
private final List<String> ignoredTables = new ArrayList<>();
|
||||
private final Map<String, List<String>> cachedTableNamesPerSchema = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public boolean isApplicable(Connection connection) {
|
||||
try {
|
||||
return connection.getMetaData().getDatabaseProductName().startsWith( "H2" );
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw new RuntimeException( "Could not resolve the database metadata!", e );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addIgnoredTable(String tableName) {
|
||||
ignoredTables.add( tableName );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearAllSchemas(Connection c) {
|
||||
cachedTableNamesPerSchema.clear();
|
||||
try (Statement s = c.createStatement()) {
|
||||
LOG.log( Level.FINEST, "Dropping schema objects: START" );
|
||||
s.execute( "DROP ALL OBJECTS" );
|
||||
LOG.log( Level.FINEST, "Dropping schema objects: END" );
|
||||
|
||||
LOG.log( Level.FINEST, "Committing: START" );
|
||||
c.commit();
|
||||
LOG.log( Level.FINEST, "Committing: END" );
|
||||
}
|
||||
catch (SQLException e) {
|
||||
try {
|
||||
c.rollback();
|
||||
}
|
||||
catch (SQLException e1) {
|
||||
e.addSuppressed( e1 );
|
||||
}
|
||||
|
||||
throw new RuntimeException( e );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearSchema(Connection c, String schemaName) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearAllData(Connection connection) {
|
||||
clearData0(
|
||||
connection,
|
||||
null,
|
||||
statement -> {
|
||||
try {
|
||||
return statement.executeQuery(
|
||||
"SELECT TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA NOT IN (" + SYSTEM_SCHEMAS + ")" );
|
||||
}
|
||||
catch (SQLException sqlException) {
|
||||
throw new RuntimeException( sqlException );
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearData(Connection connection, String schemaName) {
|
||||
clearData0(
|
||||
connection,
|
||||
schemaName,
|
||||
statement -> {
|
||||
try {
|
||||
return statement.executeQuery(
|
||||
"SELECT TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = '" + schemaName + "'" );
|
||||
}
|
||||
catch (SQLException sqlException) {
|
||||
throw new RuntimeException( sqlException );
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private void clearData0(Connection connection, String schemaName, Function<Statement, ResultSet> tablesProvider) {
|
||||
try (Statement s = connection.createStatement()) {
|
||||
// Disable foreign keys
|
||||
LOG.log( Level.FINEST, "Disable foreign keys: START" );
|
||||
s.execute( "SET REFERENTIAL_INTEGRITY FALSE" );
|
||||
LOG.log( Level.FINEST, "Disable foreign keys: END" );
|
||||
|
||||
// Delete data
|
||||
LOG.log( Level.FINEST, "Deleting data: START" );
|
||||
List<String> cachedTableNames = cachedTableNamesPerSchema.get( schemaName );
|
||||
if ( cachedTableNames == null ) {
|
||||
cachedTableNames = new ArrayList<>();
|
||||
ResultSet rs = tablesProvider.apply( s );
|
||||
while ( rs.next() ) {
|
||||
String tableSchema = rs.getString( 1 );
|
||||
String tableName = rs.getString( 2 );
|
||||
if ( !ignoredTables.contains( tableName ) ) {
|
||||
cachedTableNames.add( tableSchema + "." + tableName );
|
||||
}
|
||||
}
|
||||
cachedTableNamesPerSchema.put( schemaName, cachedTableNames );
|
||||
}
|
||||
for ( String table : cachedTableNames ) {
|
||||
s.execute( "TRUNCATE TABLE " + table );
|
||||
}
|
||||
LOG.log( Level.FINEST, "Deleting data: END" );
|
||||
|
||||
// Enable foreign keys
|
||||
LOG.log( Level.FINEST, "Enabling foreign keys: START" );
|
||||
s.execute( "SET REFERENTIAL_INTEGRITY TRUE" );
|
||||
LOG.log( Level.FINEST, "Enabling foreign keys: END" );
|
||||
|
||||
LOG.log( Level.FINEST, "Committing: START" );
|
||||
connection.commit();
|
||||
LOG.log( Level.FINEST, "Committing: END" );
|
||||
}
|
||||
catch (SQLException e) {
|
||||
try {
|
||||
connection.rollback();
|
||||
}
|
||||
catch (SQLException e1) {
|
||||
e.addSuppressed( e1 );
|
||||
}
|
||||
|
||||
throw new RuntimeException( e );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.testing.cleaner;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.sql.Connection;
|
||||
import java.sql.Driver;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
|
||||
/**
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public final class JdbcConnectionContext {
|
||||
private static final Driver driver;
|
||||
private static final String url;
|
||||
private static final String user;
|
||||
private static final String password;
|
||||
private static final Properties properties;
|
||||
static {
|
||||
final Properties connectionProperties = new Properties();
|
||||
try (InputStream inputStream = Thread.currentThread()
|
||||
.getContextClassLoader()
|
||||
.getResourceAsStream( "hibernate.properties" )) {
|
||||
connectionProperties.load( inputStream );
|
||||
final String driverClassName = connectionProperties.getProperty(
|
||||
AvailableSettings.DRIVER );
|
||||
driver = (Driver) Class.forName( driverClassName ).newInstance();
|
||||
url = connectionProperties.getProperty(
|
||||
AvailableSettings.URL );
|
||||
user = connectionProperties.getProperty(
|
||||
AvailableSettings.USER );
|
||||
password = connectionProperties.getProperty(
|
||||
AvailableSettings.PASS );
|
||||
Properties p = new Properties();
|
||||
p.put( "user", user );
|
||||
p.put( "password", password );
|
||||
properties = p;
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new IllegalArgumentException( e );
|
||||
}
|
||||
}
|
||||
|
||||
public static void work(ConnectionConsumer work) {
|
||||
try (Connection connection = driver.connect( url, properties )) {
|
||||
connection.setAutoCommit( false );
|
||||
work.consume( connection );
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new IllegalArgumentException( e );
|
||||
}
|
||||
}
|
||||
|
||||
public static <R> R workReturning(ConnectionFunction<R> work) {
|
||||
try (Connection connection = driver.connect( url, properties )) {
|
||||
connection.setAutoCommit( false );
|
||||
return work.apply( connection );
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new IllegalArgumentException( e );
|
||||
}
|
||||
}
|
||||
|
||||
public static interface ConnectionConsumer {
|
||||
void consume(Connection c) throws Exception;
|
||||
}
|
||||
public static interface ConnectionFunction<R> {
|
||||
R apply(Connection c) throws Exception;
|
||||
}
|
||||
|
||||
private JdbcConnectionContext() {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.testing.cleaner;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public class MariaDBDatabaseCleaner extends AbstractMySQLDatabaseCleaner {
|
||||
|
||||
@Override
|
||||
public boolean isApplicable(Connection connection) {
|
||||
try {
|
||||
return connection.getMetaData().getDatabaseProductName().equals( "MariaDB" )
|
||||
&& connection.getMetaData().getDriverName().startsWith( "MariaDB" );
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw new RuntimeException( "Could not resolve the database metadata!", e );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String createClearingStatementForTable(String tableSchema, String tableName) {
|
||||
return "TRUNCATE " + tableSchema + "." + tableName;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.testing.cleaner;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public class MySQL5DatabaseCleaner extends AbstractMySQLDatabaseCleaner {
|
||||
|
||||
@Override
|
||||
public boolean isApplicable(Connection connection) {
|
||||
try {
|
||||
return connection.getMetaData().getDatabaseProductName().startsWith( "MySQL" ) && connection.getMetaData()
|
||||
.getDatabaseMajorVersion() < 8;
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw new RuntimeException( "Could not resolve the database metadata!", e );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String createClearingStatementForTable(String tableSchema, String tableName) {
|
||||
// We do not use TRUNCATE for MySQL 5.7 due to https://bugs.mysql.com/bug.php?id=68184
|
||||
return "DELETE FROM " + tableSchema + "." + tableName;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.testing.cleaner;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public class MySQL8DatabaseCleaner extends AbstractMySQLDatabaseCleaner {
|
||||
|
||||
@Override
|
||||
public boolean isApplicable(Connection connection) {
|
||||
try {
|
||||
return connection.getMetaData().getDatabaseProductName().startsWith( "MySQL" ) && connection.getMetaData()
|
||||
.getDatabaseMajorVersion() >= 8;
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw new RuntimeException( "Could not resolve the database metadata!", e );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String createClearingStatementForTable(String tableSchema, String tableName) {
|
||||
return "TRUNCATE " + tableSchema + "." + tableName;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,272 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.testing.cleaner;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public class OracleDatabaseCleaner implements DatabaseCleaner {
|
||||
|
||||
private static final Logger LOG = Logger.getLogger( OracleDatabaseCleaner.class.getName() );
|
||||
private static final String SYSTEM_SEQUENCE_OWNERS = "'SYS'," +
|
||||
"'CTXSYS'," +
|
||||
"'DVSYS'," +
|
||||
"'OJVMSYS'," +
|
||||
"'ORDDATA'," +
|
||||
"'MDSYS'," +
|
||||
"'OLAPSYS'," +
|
||||
"'LBACSYS'," +
|
||||
"'XDB'," +
|
||||
"'WMSYS'";
|
||||
|
||||
private final List<String> ignoredTables = new ArrayList<>();
|
||||
private final Map<String, List<String>> cachedTruncateTableSqlPerSchema = new HashMap<>();
|
||||
private final Map<String, List<String>> cachedConstraintDisableSqlPerSchema = new HashMap<>();
|
||||
private final Map<String, List<String>> cachedConstraintEnableSqlPerSchema = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public boolean isApplicable(Connection connection) {
|
||||
try {
|
||||
return connection.getMetaData().getDatabaseProductName().startsWith( "Oracle" );
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw new RuntimeException( "Could not resolve the database metadata!", e );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addIgnoredTable(String tableName) {
|
||||
ignoredTables.add( tableName );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearAllSchemas(Connection connection) {
|
||||
cachedTruncateTableSqlPerSchema.clear();
|
||||
cachedConstraintDisableSqlPerSchema.clear();
|
||||
cachedConstraintEnableSqlPerSchema.clear();
|
||||
clearSchema0(
|
||||
connection,
|
||||
statement -> {
|
||||
try {
|
||||
return statement.executeQuery(
|
||||
"SELECT 'DROP TABLE ' || owner || '.\"' || table_name || '\" CASCADE CONSTRAINTS' " +
|
||||
"FROM all_tables " +
|
||||
// Exclude the tables owner by sys
|
||||
"WHERE owner NOT IN ('SYS')" +
|
||||
// Normally, user tables aren't in sysaux
|
||||
" AND tablespace_name NOT IN ('SYSAUX')" +
|
||||
// Apparently, user tables have global stats off
|
||||
" AND global_stats = 'NO'" +
|
||||
// Exclude the tables with names starting like 'DEF$_'
|
||||
" AND table_name NOT LIKE 'DEF$\\_%' ESCAPE '\\'" +
|
||||
" UNION ALL " +
|
||||
"SELECT 'DROP SEQUENCE ' || sequence_owner || '.' || sequence_name FROM all_sequences WHERE sequence_owner NOT IN (" + SYSTEM_SEQUENCE_OWNERS + ")"
|
||||
);
|
||||
}
|
||||
catch (SQLException sqlException) {
|
||||
throw new RuntimeException( sqlException );
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearSchema(Connection connection, String schemaName) {
|
||||
cachedTruncateTableSqlPerSchema.remove( schemaName );
|
||||
cachedConstraintDisableSqlPerSchema.remove( schemaName );
|
||||
cachedConstraintEnableSqlPerSchema.remove( schemaName );
|
||||
clearSchema0(
|
||||
connection,
|
||||
statement -> {
|
||||
try {
|
||||
return statement.executeQuery(
|
||||
"SELECT 'DROP TABLE ' || owner || '.\"' || table_name || '\" CASCADE CONSTRAINTS' " +
|
||||
"FROM all_tables " +
|
||||
"WHERE owner = '" + schemaName + "'" +
|
||||
// Normally, user tables aren't in sysaux
|
||||
" AND tablespace_name NOT IN ('SYSAUX')" +
|
||||
// Apparently, user tables have global stats off
|
||||
" AND global_stats = 'NO'" +
|
||||
// Exclude the tables with names starting like 'DEF$_'
|
||||
" AND table_name NOT LIKE 'DEF$\\_%' ESCAPE '\\'" +
|
||||
" UNION ALL " +
|
||||
"SELECT 'DROP SEQUENCE ' || sequence_owner || '.' || sequence_name FROM all_sequences WHERE sequence_owner = '" + schemaName + "'"
|
||||
);
|
||||
}
|
||||
catch (SQLException sqlException) {
|
||||
throw new RuntimeException( sqlException );
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private void clearSchema0(Connection c, Function<Statement, ResultSet> sqlProvider) {
|
||||
try (Statement s = c.createStatement()) {
|
||||
ResultSet rs;
|
||||
List<String> sqls = new ArrayList<>();
|
||||
|
||||
// Collect schema objects
|
||||
LOG.log( Level.FINEST, "Collect schema objects: START" );
|
||||
rs = sqlProvider.apply( s );
|
||||
while ( rs.next() ) {
|
||||
sqls.add( rs.getString( 1 ) );
|
||||
}
|
||||
LOG.log( Level.FINEST, "Collect schema objects: END" );
|
||||
|
||||
LOG.log( Level.FINEST, "Dropping schema objects: START" );
|
||||
for ( String sql : sqls ) {
|
||||
s.execute( sql );
|
||||
}
|
||||
LOG.log( Level.FINEST, "Dropping schema objects: END" );
|
||||
|
||||
LOG.log( Level.FINEST, "Committing: START" );
|
||||
c.commit();
|
||||
LOG.log( Level.FINEST, "Committing: END" );
|
||||
}
|
||||
catch (SQLException e) {
|
||||
try {
|
||||
c.rollback();
|
||||
}
|
||||
catch (SQLException e1) {
|
||||
e.addSuppressed( e1 );
|
||||
}
|
||||
|
||||
throw new RuntimeException( e );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearAllData(Connection connection) {
|
||||
clearData0(
|
||||
connection,
|
||||
null,
|
||||
statement -> {
|
||||
try {
|
||||
return statement.executeQuery(
|
||||
"SELECT tbl.owner || '.\"' || tbl.table_name || '\"', c.constraint_name FROM (" +
|
||||
"SELECT owner, table_name " +
|
||||
"FROM all_tables " +
|
||||
// Exclude the tables owner by sys
|
||||
"WHERE owner NOT IN ('SYS')" +
|
||||
// Normally, user tables aren't in sysaux
|
||||
" AND tablespace_name NOT IN ('SYSAUX')" +
|
||||
// Apparently, user tables have global stats off
|
||||
" AND global_stats = 'NO'" +
|
||||
// Exclude the tables with names starting like 'DEF$_'
|
||||
" AND table_name NOT LIKE 'DEF$\\_%' ESCAPE '\\'" +
|
||||
") tbl LEFT JOIN all_constraints c ON tbl.owner = c.owner AND tbl.table_name = c.table_name AND constraint_type = 'R'"
|
||||
);
|
||||
}
|
||||
catch (SQLException sqlException) {
|
||||
throw new RuntimeException( sqlException );
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearData(Connection connection, String schemaName) {
|
||||
clearData0(
|
||||
connection,
|
||||
schemaName, statement -> {
|
||||
try {
|
||||
return statement.executeQuery(
|
||||
"SELECT tbl.owner || '.\"' || tbl.table_name || '\"', c.constraint_name FROM (" +
|
||||
"SELECT owner, table_name " +
|
||||
"FROM all_tables " +
|
||||
"WHERE owner = '" + schemaName + "'" +
|
||||
// Normally, user tables aren't in sysaux
|
||||
" AND tablespace_name NOT IN ('SYSAUX')" +
|
||||
// Apparently, user tables have global stats off
|
||||
" AND global_stats = 'NO'" +
|
||||
// Exclude the tables with names starting like 'DEF$_'
|
||||
" AND table_name NOT LIKE 'DEF$\\_%' ESCAPE '\\'" +
|
||||
") tbl LEFT JOIN all_constraints c ON tbl.owner = c.owner AND tbl.table_name = c.table_name AND constraint_type = 'R'"
|
||||
);
|
||||
}
|
||||
catch (SQLException sqlException) {
|
||||
throw new RuntimeException( sqlException );
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private void clearData0(Connection connection, String schemaName, Function<Statement, ResultSet> tablesProvider) {
|
||||
try (Statement s = connection.createStatement()) {
|
||||
List<String> cachedTruncateTableSql = cachedTruncateTableSqlPerSchema.get( schemaName );
|
||||
List<String> cachedConstraintDisableSql = cachedConstraintDisableSqlPerSchema.get( schemaName );
|
||||
List<String> cachedConstraintEnableSql = cachedConstraintEnableSqlPerSchema.get( schemaName );
|
||||
if ( cachedTruncateTableSql == null ) {
|
||||
cachedTruncateTableSql = new ArrayList<>();
|
||||
cachedConstraintDisableSql = new ArrayList<>();
|
||||
cachedConstraintEnableSql = new ArrayList<>();
|
||||
ResultSet rs = tablesProvider.apply( s );
|
||||
while ( rs.next() ) {
|
||||
String tableName = rs.getString( 1 );
|
||||
String constraintName = rs.getString( 2 );
|
||||
if ( !ignoredTables.contains( tableName ) ) {
|
||||
cachedTruncateTableSql.add( "TRUNCATE TABLE \"" + tableName + "\"" );
|
||||
if ( constraintName != null ) {
|
||||
cachedConstraintDisableSql.add( "ALTER TABLE \"" + tableName + "\" DISABLE CONSTRAINT " + constraintName );
|
||||
cachedConstraintEnableSql.add( "ALTER TABLE \"" + tableName + "\" ENABLE CONSTRAINT " + constraintName );
|
||||
}
|
||||
}
|
||||
}
|
||||
cachedTruncateTableSqlPerSchema.put( schemaName, cachedTruncateTableSql );
|
||||
cachedConstraintDisableSqlPerSchema.put( schemaName, cachedConstraintDisableSql );
|
||||
cachedConstraintEnableSqlPerSchema.put( schemaName, cachedConstraintEnableSql );
|
||||
}
|
||||
// Disable foreign keys
|
||||
LOG.log( Level.FINEST, "Disable foreign keys: START" );
|
||||
for ( String sql : cachedConstraintDisableSql ) {
|
||||
s.execute( sql );
|
||||
}
|
||||
LOG.log( Level.FINEST, "Disable foreign keys: END" );
|
||||
|
||||
// Delete data
|
||||
LOG.log( Level.FINEST, "Deleting data: START" );
|
||||
for ( String sql : cachedTruncateTableSql ) {
|
||||
s.execute( sql );
|
||||
}
|
||||
LOG.log( Level.FINEST, "Deleting data: END" );
|
||||
|
||||
// Enable foreign keys
|
||||
LOG.log( Level.FINEST, "Enabling foreign keys: START" );
|
||||
for ( String sql : cachedConstraintEnableSql ) {
|
||||
s.execute( sql );
|
||||
}
|
||||
LOG.log( Level.FINEST, "Enabling foreign keys: END" );
|
||||
|
||||
LOG.log( Level.FINEST, "Committing: START" );
|
||||
connection.commit();
|
||||
LOG.log( Level.FINEST, "Committing: END" );
|
||||
}
|
||||
catch (SQLException e) {
|
||||
try {
|
||||
connection.rollback();
|
||||
}
|
||||
catch (SQLException e1) {
|
||||
e.addSuppressed( e1 );
|
||||
}
|
||||
|
||||
throw new RuntimeException( e );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,200 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.testing.cleaner;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public class PostgreSQLDatabaseCleaner implements DatabaseCleaner {
|
||||
|
||||
private static final Logger LOG = Logger.getLogger( PostgreSQLDatabaseCleaner.class.getName() );
|
||||
|
||||
private final List<String> ignoredTables = new ArrayList<>();
|
||||
private final Map<String, String> truncateSqlPerSchema = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public boolean isApplicable(Connection connection) {
|
||||
try {
|
||||
return connection.getMetaData().getDatabaseProductName().startsWith( "PostgreSQL" );
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw new RuntimeException( "Could not resolve the database metadata!", e );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addIgnoredTable(String tableName) {
|
||||
ignoredTables.add( tableName.toLowerCase() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearAllSchemas(Connection connection) {
|
||||
truncateSqlPerSchema.clear();
|
||||
clearSchema0(
|
||||
connection,
|
||||
statement -> {
|
||||
try {
|
||||
return statement.executeQuery(
|
||||
"SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME <> 'information_schema' AND SCHEMA_NAME NOT LIKE 'pg_%'" );
|
||||
}
|
||||
catch (SQLException sqlException) {
|
||||
throw new RuntimeException( sqlException );
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearSchema(Connection connection, String schemaName) {
|
||||
truncateSqlPerSchema.remove( schemaName );
|
||||
clearSchema0(
|
||||
connection,
|
||||
statement -> {
|
||||
try {
|
||||
return statement.executeQuery(
|
||||
"SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = '" + schemaName + "'" );
|
||||
}
|
||||
catch (SQLException sqlException) {
|
||||
throw new RuntimeException( sqlException );
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private void clearSchema0(Connection c, Function<Statement, ResultSet> schemasProvider) {
|
||||
try (Statement s = c.createStatement()) {
|
||||
ResultSet rs;
|
||||
final List<String> sqls = new ArrayList<>();
|
||||
|
||||
// Collect schema objects
|
||||
String user = c.getMetaData().getUserName();
|
||||
LOG.log( Level.FINEST, "Collect schema objects: START" );
|
||||
rs = schemasProvider.apply( s );
|
||||
while ( rs.next() ) {
|
||||
String schema = rs.getString( 1 );
|
||||
sqls.add( "DROP SCHEMA \"" + schema + "\" CASCADE" );
|
||||
sqls.add( "CREATE SCHEMA \"" + schema + "\"" );
|
||||
sqls.add( "GRANT ALL ON SCHEMA \"" + schema + "\" TO \"" + user + "\"" );
|
||||
}
|
||||
LOG.log( Level.FINEST, "Collect schema objects: END" );
|
||||
|
||||
LOG.log( Level.FINEST, "Dropping schema objects: START" );
|
||||
for ( String sql : sqls ) {
|
||||
s.execute( sql );
|
||||
}
|
||||
LOG.log( Level.FINEST, "Dropping schema objects: END" );
|
||||
|
||||
LOG.log( Level.FINEST, "Committing: START" );
|
||||
c.commit();
|
||||
LOG.log( Level.FINEST, "Committing: END" );
|
||||
}
|
||||
catch (SQLException e) {
|
||||
try {
|
||||
c.rollback();
|
||||
}
|
||||
catch (SQLException e1) {
|
||||
e.addSuppressed( e1 );
|
||||
}
|
||||
|
||||
throw new RuntimeException( e );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearAllData(Connection connection) {
|
||||
clearData0(
|
||||
connection,
|
||||
null,
|
||||
statement -> {
|
||||
try {
|
||||
return statement.executeQuery(
|
||||
"SELECT TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA <> 'information_schema' AND SCHEMA_NAME NOT LIKE 'pg_%'" );
|
||||
}
|
||||
catch (SQLException sqlException) {
|
||||
throw new RuntimeException( sqlException );
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearData(Connection connection, String schemaName) {
|
||||
clearData0(
|
||||
connection,
|
||||
schemaName,
|
||||
statement -> {
|
||||
try {
|
||||
return statement.executeQuery(
|
||||
"SELECT TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = '" + schemaName + "'" );
|
||||
}
|
||||
catch (SQLException sqlException) {
|
||||
throw new RuntimeException( sqlException );
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private void clearData0(Connection connection, String schemaName, Function<Statement, ResultSet> tablesProvider) {
|
||||
try (Statement s = connection.createStatement()) {
|
||||
// Delete data
|
||||
LOG.log( Level.FINEST, "Deleting data: START" );
|
||||
String truncateSql = truncateSqlPerSchema.get( schemaName );
|
||||
if ( truncateSql == null ) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append( "TRUNCATE TABLE " );
|
||||
ResultSet rs = tablesProvider.apply( s );
|
||||
while ( rs.next() ) {
|
||||
String tableSchema = rs.getString( 1 );
|
||||
String tableName = rs.getString( 2 );
|
||||
if ( !ignoredTables.contains( tableName ) ) {
|
||||
sb.append( '"' );
|
||||
sb.append( tableSchema );
|
||||
sb.append( '"' );
|
||||
sb.append( '.' );
|
||||
sb.append( '"' );
|
||||
sb.append( tableName );
|
||||
sb.append( '"' );
|
||||
sb.append( ',' );
|
||||
}
|
||||
}
|
||||
sb.setCharAt( sb.length() - 1, ' ' );
|
||||
sb.append( "RESTART IDENTITY CASCADE" );
|
||||
truncateSql = sb.toString();
|
||||
truncateSqlPerSchema.put( schemaName, truncateSql );
|
||||
}
|
||||
s.execute( truncateSql );
|
||||
LOG.log( Level.FINEST, "Deleting data: END" );
|
||||
|
||||
LOG.log( Level.FINEST, "Committing: START" );
|
||||
connection.commit();
|
||||
LOG.log( Level.FINEST, "Committing: END" );
|
||||
}
|
||||
catch (SQLException e) {
|
||||
try {
|
||||
connection.rollback();
|
||||
}
|
||||
catch (SQLException e1) {
|
||||
e.addSuppressed( e1 );
|
||||
}
|
||||
|
||||
throw new RuntimeException( e );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,256 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.testing.cleaner;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public class SQLServerDatabaseCleaner implements DatabaseCleaner {
|
||||
|
||||
private static final Logger LOG = Logger.getLogger( SQLServerDatabaseCleaner.class.getName() );
|
||||
|
||||
private final List<String> ignoredTables = new ArrayList<>();
|
||||
private final Map<String, List<String>> cachedTableNamesPerSchema = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public boolean isApplicable(Connection connection) {
|
||||
try {
|
||||
return connection.getMetaData().getDatabaseProductName().startsWith( "Microsoft SQL Server" );
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw new RuntimeException( "Could not resolve the database metadata!", e );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addIgnoredTable(String tableName) {
|
||||
ignoredTables.add( tableName );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearAllSchemas(Connection c) {
|
||||
cachedTableNamesPerSchema.clear();
|
||||
try (Statement s = c.createStatement()) {
|
||||
ResultSet rs;
|
||||
List<String> sqls = new ArrayList<>();
|
||||
|
||||
// Collect schema objects
|
||||
LOG.log( Level.FINEST, "Collect schema objects: START" );
|
||||
rs = s.executeQuery(
|
||||
"SELECT 'ALTER TABLE [' + TABLE_SCHEMA + '].[' + TABLE_NAME + '] DROP CONSTRAINT [' + CONSTRAINT_NAME + ']' FROM INFORMATION_SCHEMA.CONSTRAINT_TABLE_USAGE " +
|
||||
"WHERE EXISTS (SELECT 1 FROM sys.Tables t JOIN sys.Schemas s ON t.schema_id = s.schema_id WHERE t.is_ms_shipped = 0 AND s.name = TABLE_SCHEMA AND t.name = TABLE_NAME) " +
|
||||
"AND EXISTS (SELECT 1 FROM sys.Foreign_keys WHERE name = CONSTRAINT_NAME)" );
|
||||
while ( rs.next() ) {
|
||||
sqls.add( rs.getString( 1 ) );
|
||||
}
|
||||
|
||||
rs = s.executeQuery(
|
||||
"SELECT 'DROP VIEW [' + TABLE_SCHEMA + '].[' + TABLE_NAME + ']' FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'VIEW' " +
|
||||
"AND EXISTS (SELECT 1 FROM sys.Views t JOIN sys.Schemas s ON t.schema_id = s.schema_id WHERE t.is_ms_shipped = 0 AND s.name = TABLE_SCHEMA AND t.name = TABLE_NAME)" );
|
||||
while ( rs.next() ) {
|
||||
sqls.add( rs.getString( 1 ) );
|
||||
}
|
||||
|
||||
rs = s.executeQuery(
|
||||
"SELECT 'DROP TABLE [' + TABLE_SCHEMA + '].[' + TABLE_NAME + ']' FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' " +
|
||||
"AND EXISTS (SELECT 1 FROM sys.Tables t JOIN sys.Schemas s ON t.schema_id = s.schema_id WHERE t.is_ms_shipped = 0 AND s.name = TABLE_SCHEMA AND t.name = TABLE_NAME)" );
|
||||
while ( rs.next() ) {
|
||||
sqls.add( rs.getString( 1 ) );
|
||||
}
|
||||
|
||||
rs = s.executeQuery(
|
||||
"SELECT 'DROP SEQUENCE [' + SEQUENCE_SCHEMA + '].[' + SEQUENCE_NAME + ']' FROM INFORMATION_SCHEMA.SEQUENCES" );
|
||||
while ( rs.next() ) {
|
||||
sqls.add( rs.getString( 1 ) );
|
||||
}
|
||||
LOG.log( Level.FINEST, "Collect schema objects: END" );
|
||||
|
||||
LOG.log( Level.FINEST, "Dropping schema objects: START" );
|
||||
for ( String sql : sqls ) {
|
||||
s.execute( sql );
|
||||
}
|
||||
LOG.log( Level.FINEST, "Dropping schema objects: END" );
|
||||
|
||||
LOG.log( Level.FINEST, "Committing: START" );
|
||||
c.commit();
|
||||
LOG.log( Level.FINEST, "Committing: END" );
|
||||
}
|
||||
catch (SQLException e) {
|
||||
try {
|
||||
c.rollback();
|
||||
}
|
||||
catch (SQLException e1) {
|
||||
e.addSuppressed( e1 );
|
||||
}
|
||||
|
||||
throw new RuntimeException( e );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearSchema(Connection c, String schemaName) {
|
||||
cachedTableNamesPerSchema.remove( schemaName );
|
||||
try (Statement s = c.createStatement()) {
|
||||
ResultSet rs;
|
||||
List<String> sqls = new ArrayList<>();
|
||||
|
||||
// Collect schema objects
|
||||
LOG.log( Level.FINEST, "Collect schema objects: START" );
|
||||
rs = s.executeQuery(
|
||||
"SELECT 'ALTER TABLE [' + TABLE_SCHEMA + '].[' + TABLE_NAME + '] DROP CONSTRAINT [' + CONSTRAINT_NAME + ']' FROM INFORMATION_SCHEMA.CONSTRAINT_TABLE_USAGE " +
|
||||
"WHERE EXISTS (SELECT 1 FROM sys.Tables t JOIN sys.Schemas s ON t.schema_id = s.schema_id WHERE t.is_ms_shipped = 0 AND s.name = TABLE_SCHEMA AND t.name = TABLE_NAME) " +
|
||||
"AND EXISTS (SELECT 1 FROM sys.Foreign_keys WHERE name = CONSTRAINT_NAME) " +
|
||||
"AND TABLE_SCHEMA = N'" + schemaName + "'" );
|
||||
while ( rs.next() ) {
|
||||
sqls.add( rs.getString( 1 ) );
|
||||
}
|
||||
|
||||
rs = s.executeQuery(
|
||||
"SELECT 'DROP VIEW [' + TABLE_SCHEMA + '].[' + TABLE_NAME + ']' FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'VIEW' " +
|
||||
"AND EXISTS (SELECT 1 FROM sys.Views t JOIN sys.Schemas s ON t.schema_id = s.schema_id WHERE t.is_ms_shipped = 0 AND s.name = TABLE_SCHEMA AND t.name = TABLE_NAME) " +
|
||||
"AND TABLE_SCHEMA = N'" + schemaName + "'" );
|
||||
while ( rs.next() ) {
|
||||
sqls.add( rs.getString( 1 ) );
|
||||
}
|
||||
|
||||
rs = s.executeQuery(
|
||||
"SELECT 'DROP TABLE [' + TABLE_SCHEMA + '].[' + TABLE_NAME + ']' FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' " +
|
||||
"AND EXISTS (SELECT 1 FROM sys.Tables t JOIN sys.Schemas s ON t.schema_id = s.schema_id WHERE t.is_ms_shipped = 0 AND s.name = TABLE_SCHEMA AND t.name = TABLE_NAME) " +
|
||||
"AND TABLE_SCHEMA = N'" + schemaName + "'" );
|
||||
while ( rs.next() ) {
|
||||
sqls.add( rs.getString( 1 ) );
|
||||
}
|
||||
|
||||
rs = s.executeQuery(
|
||||
"SELECT 'DROP SEQUENCE [' + SEQUENCE_SCHEMA + '].[' + SEQUENCE_NAME + ']' FROM INFORMATION_SCHEMA.SEQUENCES WHERE " +
|
||||
"SEQUENCE_SCHEMA = N'" + schemaName + "'" );
|
||||
while ( rs.next() ) {
|
||||
sqls.add( rs.getString( 1 ) );
|
||||
}
|
||||
LOG.log( Level.FINEST, "Collect schema objects: END" );
|
||||
|
||||
LOG.log( Level.FINEST, "Dropping schema objects: START" );
|
||||
for ( String sql : sqls ) {
|
||||
s.execute( sql );
|
||||
}
|
||||
LOG.log( Level.FINEST, "Dropping schema objects: END" );
|
||||
|
||||
LOG.log( Level.FINEST, "Committing: START" );
|
||||
c.commit();
|
||||
LOG.log( Level.FINEST, "Committing: END" );
|
||||
}
|
||||
catch (SQLException e) {
|
||||
try {
|
||||
c.rollback();
|
||||
}
|
||||
catch (SQLException e1) {
|
||||
e.addSuppressed( e1 );
|
||||
}
|
||||
|
||||
throw new RuntimeException( e );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearAllData(Connection connection) {
|
||||
clearData0(
|
||||
connection,
|
||||
null,
|
||||
statement -> {
|
||||
try {
|
||||
return statement.executeQuery(
|
||||
"SELECT s.name, t.name FROM sys.Tables t JOIN sys.Schemas s ON t.schema_id = s.schema_id WHERE t.is_ms_shipped = 0" );
|
||||
}
|
||||
catch (SQLException sqlException) {
|
||||
throw new RuntimeException( sqlException );
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearData(Connection connection, String schemaName) {
|
||||
clearData0(
|
||||
connection,
|
||||
schemaName,
|
||||
statement -> {
|
||||
try {
|
||||
return statement.executeQuery(
|
||||
"SELECT s.name, t.name FROM sys.Tables t JOIN sys.Schemas s ON t.schema_id = s.schema_id WHERE t.is_ms_shipped = 0 AND s.name = N'" + schemaName + "'" );
|
||||
}
|
||||
catch (SQLException sqlException) {
|
||||
throw new RuntimeException( sqlException );
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private void clearData0(Connection connection, String schemaName, Function<Statement, ResultSet> tablesProvider) {
|
||||
try (Statement s = connection.createStatement()) {
|
||||
List<String> cachedTableNames = cachedTableNamesPerSchema.get( schemaName );
|
||||
if ( cachedTableNames == null ) {
|
||||
cachedTableNames = new ArrayList<>();
|
||||
ResultSet rs = tablesProvider.apply( s );
|
||||
while ( rs.next() ) {
|
||||
String tableSchema = rs.getString( 1 );
|
||||
String tableName = rs.getString( 2 );
|
||||
if ( !ignoredTables.contains( tableName ) ) {
|
||||
cachedTableNames.add( tableSchema + "." + tableName );
|
||||
}
|
||||
}
|
||||
cachedTableNamesPerSchema.put( schemaName, cachedTableNames );
|
||||
}
|
||||
// Disable foreign keys
|
||||
LOG.log( Level.FINEST, "Disable foreign keys: START" );
|
||||
for ( String table : cachedTableNames ) {
|
||||
s.execute( "ALTER TABLE " + table + " NOCHECK CONSTRAINT ALL" );
|
||||
}
|
||||
LOG.log( Level.FINEST, "Disable foreign keys: END" );
|
||||
|
||||
// Delete data
|
||||
LOG.log( Level.FINEST, "Deleting data: START" );
|
||||
for ( String table : cachedTableNames ) {
|
||||
s.execute( "DELETE FROM " + table );
|
||||
}
|
||||
LOG.log( Level.FINEST, "Deleting data: END" );
|
||||
|
||||
// Enable foreign keys
|
||||
LOG.log( Level.FINEST, "Enabling foreign keys: START" );
|
||||
for ( String table : cachedTableNames ) {
|
||||
s.execute( "ALTER TABLE " + table + " WITH CHECK CHECK CONSTRAINT ALL" );
|
||||
}
|
||||
LOG.log( Level.FINEST, "Enabling foreign keys: END" );
|
||||
|
||||
LOG.log( Level.FINEST, "Committing: START" );
|
||||
connection.commit();
|
||||
LOG.log( Level.FINEST, "Committing: END" );
|
||||
}
|
||||
catch (SQLException e) {
|
||||
try {
|
||||
connection.rollback();
|
||||
}
|
||||
catch (SQLException e1) {
|
||||
e.addSuppressed( e1 );
|
||||
}
|
||||
|
||||
throw new RuntimeException( e );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -16,6 +16,7 @@ import javax.transaction.SystemException;
|
|||
import org.hibernate.engine.transaction.internal.jta.JtaStatusHelper;
|
||||
|
||||
import org.hibernate.testing.AfterClassOnce;
|
||||
import org.hibernate.testing.cleaner.DatabaseCleaner;
|
||||
import org.hibernate.testing.jdbc.leak.ConnectionLeakUtil;
|
||||
import org.hibernate.testing.jta.TestingJtaPlatformImpl;
|
||||
import org.junit.After;
|
||||
|
@ -34,6 +35,10 @@ import org.jboss.logging.Logger;
|
|||
@RunWith( CustomRunner.class )
|
||||
public abstract class BaseUnitTestCase {
|
||||
|
||||
static {
|
||||
DatabaseCleaner.clearSchemas();
|
||||
}
|
||||
|
||||
protected final Logger log = Logger.getLogger( getClass() );
|
||||
|
||||
private static boolean enableConnectionLeakDetection = Boolean.TRUE.toString()
|
||||
|
|
Loading…
Reference in New Issue