blob: 2e418b5de4bc5ccd69535b8448c4e66bf449097e [file] [log] [blame]
/*
* Copyright (c) 1998, 2020 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
// Contributors:
// 21/08/2013-2.6 Chris Delahunt
package org.eclipse.persistence.testing.tests;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.Vector;
import org.eclipse.persistence.exceptions.DatabaseException;
import org.eclipse.persistence.internal.databaseaccess.Platform;
import org.eclipse.persistence.internal.sessions.AbstractSession;
import org.eclipse.persistence.internal.sessions.ArrayRecord;
import org.eclipse.persistence.logging.AbstractSessionLog;
import org.eclipse.persistence.sessions.DatabaseLogin;
import org.eclipse.persistence.testing.framework.TestCase;
/**
* This test is used to allow clearing the schema before running automated tests.
* It is not intended to test behavior, but might be included in test runs where problems can be recorded.
*
*/
public class ClearDatabaseSchemaTest extends TestCase {
public ClearDatabaseSchemaTest() {
setDescription("Clears the database for MYSQL, Oracle DB, Derby, MSSQL, HSQL, Postgres.");
}
@Override
public void test() {
//TODO: add missing platforms, currently supported are:
//MySQL, Oracle DB, Derby, HSQLDB, PostgreSQL, MSSQL
AbstractSession session = (AbstractSession) getSession();
Platform platform = session.getDatasourcePlatform();
if (platform.isMySQL()) {
resetMySQL(session);
} else if (platform.isOracle()) {
resetOracle(session);
} else if (platform.isDerby()) {
resetDerby(session);
} else if (platform.isSQLServer()) {
resetMSSQL(session);
} else if (platform.isHSQL()) {
resetHsql(session);
} else if (platform.isPostgreSQL()) {
resetPostgres(session);
} else {
fail("Clear DB test run on unsupported DB");
}
getDatabaseSession().logout();
getDatabaseSession().login();
}
private void resetMySQL(AbstractSession session) {
ArrayRecord record = null;
try {
record = (ArrayRecord) session.executeSQL("select DATABASE()").get(0);
session.executeNonSelectingSQL("drop database " + record.get("DATABASE()"));
} catch (DatabaseException x) {
AbstractSessionLog.getLog().warning("Failed to drop database");
// Using System.err since session log may not print out the stack trace
x.printStackTrace(System.err);
} finally {
if (record != null) {
session.executeNonSelectingSQL("create database " + record.get("DATABASE()"));
} else {
DatabaseLogin databaseLogin = (DatabaseLogin) session.getDatasourceLogin();
String url = databaseLogin.getDatabaseURL();
Properties properties = new Properties();
properties.put("user", databaseLogin.getUserName());
properties.put("password", databaseLogin.getPassword());
int databaseNameSeparatorIndex = url.lastIndexOf('/');
String databaseName = url.substring(databaseNameSeparatorIndex + 1);
int propertiesIndex = databaseName.indexOf('?');
if (propertiesIndex > 0) {
for (String propertyString : databaseName.substring(propertiesIndex + 1).split("&")) {
String[] propertyDetails = propertyString.split("=");
properties.put(propertyDetails[0].trim(), propertyDetails[1].trim());
}
databaseName = databaseName.substring(0, propertiesIndex);
}
url = url.substring(0, databaseNameSeparatorIndex);
try (Connection connection = DriverManager.getConnection(url, properties)) {
connection.prepareStatement("create database " + databaseName).execute();
} catch (SQLException e) {
// Using System.err since session log may not print out the stack trace
e.printStackTrace(System.err);
}
}
}
//unused for now but kept here for alternate option
// Vector<ArrayRecord> result = session.executeSQL("SELECT concat('ALTER TABLE ', C.TABLE_SCHEMA, '.', C.TABLE_NAME, ' DROP FOREIGN KEY ', C.CONSTRAINT_NAME) "
// + "FROM information_schema.TABLE_CONSTRAINTS C "
// + "WHERE C.TABLE_SCHEMA = (SELECT SCHEMA()) and C.CONSTRAINT_TYPE = 'FOREIGN KEY'");
// List<String> toRetry = execStatements(session, result);
// result = session.executeSQL("SELECT concat('DROP TABLE IF EXISTS ', T.TABLE_SCHEMA, '.', T.TABLE_NAME) "
// + "FROM information_schema.TABLES T WHERE T.TABLE_SCHEMA = (SELECT SCHEMA())");
// toRetry.addAll(execStatements(session, result));
// assertTrue(toRetry + " statements failed", toRetry.isEmpty());
}
private void resetOracle(AbstractSession session) {
session.executeNonSelectingSQL("BEGIN FOR cur_rec IN (\n" + "SELECT object_name, object_type FROM user_objects WHERE object_type IN "
+ "('TABLE', 'VIEW', 'PACKAGE', 'PROCEDURE', 'FUNCTION', 'SEQUENCE', 'TYPE'))\n"
+ "LOOP BEGIN IF cur_rec.object_type = 'TABLE' "
+ "THEN EXECUTE IMMEDIATE 'DROP ' || cur_rec.object_type || ' \"' || cur_rec.object_name || '\" CASCADE CONSTRAINTS'; "
+ "ELSIF cur_rec.object_type = 'TYPE' THEN EXECUTE IMMEDIATE 'DROP ' || cur_rec.object_type || ' \"' || cur_rec.object_name || '\" FORCE'; "
+ "ELSE EXECUTE IMMEDIATE 'DROP ' || cur_rec.object_type || ' \"' || cur_rec.object_name || '\"'; "
+ "END IF;\nEXCEPTION WHEN OTHERS "
+ "THEN DBMS_OUTPUT.put_line ('FAILED: DROP ' || cur_rec.object_type || ' \"' || cur_rec.object_name || '\"');"
+ "END;\nEND LOOP; END;");
session.executeNonSelectingSQL("PURGE user_recyclebin");
session.executeNonSelectingSQL("PURGE recyclebin");
}
private void resetDerby(AbstractSession session) {
Vector<ArrayRecord> result = session.executeSQL("SELECT 'ALTER TABLE '||S.SCHEMANAME||'.'||T.TABLENAME||' DROP CONSTRAINT '||C.CONSTRAINTNAME\n"
+ "FROM SYS.SYSCONSTRAINTS C, SYS.SYSSCHEMAS S, SYS.SYSTABLES T\n"
+ "WHERE C.SCHEMAID = S.SCHEMAID AND C.TABLEID = T.TABLEID AND S.SCHEMANAME = CURRENT SCHEMA ORDER BY C.REFERENCECOUNT DESC");
List<String> toRetry = execStatements(session, result);
final int MAX_ROUNDS = 3;
int round = 0;
while (!toRetry.isEmpty() && round < MAX_ROUNDS ) {
for (Iterator<String> i = toRetry.iterator(); i.hasNext();) {
String stmt = i.next();
try {
session.executeNonSelectingSQL(stmt);
i.remove();
} catch (DatabaseException de) {
//ignore, next round may be successful
}
}
round++;
}
result = session.executeSQL("SELECT 'DROP TABLE ' || schemaname ||'.' || tablename FROM SYS.SYSTABLES\n"
+ "INNER JOIN SYS.SYSSCHEMAS ON SYS.SYSTABLES.SCHEMAID = SYS.SYSSCHEMAS.SCHEMAID\n"
+ "WHERE schemaname = CURRENT SCHEMA");
toRetry.addAll(execStatements(session, result));
assertTrue(toRetry + " statements failed", toRetry.isEmpty());
}
private void resetMSSQL(AbstractSession session) {
session.executeNonSelectingSQL(
"DECLARE @name VARCHAR(256)\n" +
"DECLARE @subName VARCHAR(256)\n" +
"DECLARE @statement VARCHAR(256)\n" +
"WHILE((SELECT COUNT(1) FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME()) > 0)\n" +
"BEGIN\n" +
"\tSELECT TOP 1 @name=TABLE_NAME, @subName=CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() ORDER BY CONSTRAINT_TYPE\n" +
" SELECT @statement = 'ALTER TABLE [dbo].[' + RTRIM(@name) +'] DROP CONSTRAINT [' + RTRIM(@subName) +']'\n" +
" EXEC (@statement)\n" +
"END\n" +
"WHILE((SELECT COUNT(1) FROM sysobjects WHERE [type] IN ('P', 'V', N'FN', N'IF', N'TF', N'FS', N'FT', 'U') AND category = 0) > 0)\n" +
"BEGIN\n" +
"\tSELECT TOP 1 @name=[name], @subName=[type] FROM sysobjects WHERE [type] IN ('P', 'V', N'FN', N'IF', N'TF', N'FS', N'FT', 'U') AND category = 0\n" +
" SELECT @statement = 'DROP ' + CASE @subName WHEN 'P' THEN 'PROCEDURE' WHEN 'V' THEN 'VIEW' WHEN 'U' THEN 'TABLE' ELSE 'FUNCTION' END + ' [dbo].[' + RTRIM(@name) +']'\n" +
" EXEC (@statement)\n" +
"END");
}
private void resetHsql(AbstractSession session) {
Vector<ArrayRecord> result = session.executeSQL("select 'DROP TABLE \"' || table_name || '\" CASCADE' FROM INFORMATION_SCHEMA.system_tables "
+ "WHERE table_type = 'TABLE' and table_schem = CURRENT_SCHEMA");
List<String> toRetry = execStatements(session, result);
assertTrue(toRetry + " statements failed", toRetry.isEmpty());
}
private void resetPostgres(AbstractSession session) {
Vector<ArrayRecord> result = getSession().executeSQL("SELECT 'DROP TABLE \"' || tablename || '\" CASCADE;' "
+ "FROM pg_tables WHERE schemaname = current_schema();");
List<String> toRetry = execStatements(session, result);
assertTrue(toRetry + " statements failed", toRetry.isEmpty());
}
private List<String> execStatements(AbstractSession session, Vector<ArrayRecord> records) {
List<String> failures = new ArrayList<String>();
for (ArrayRecord ar : records) {
for (Object o : ar.values()) {
String stmt = (String) o;
try {
session.executeNonSelectingSQL(stmt);
} catch (DatabaseException t) {
failures.add(stmt);
}
}
}
return failures;
}
}