blob: 0f711d2db807aa6ffcd12a1c10b7ec2b56342eec [file]
/*
* Class org.apache.derbyTesting.functionTests.tests.lang.TruncateTableAndOnlineBackupTest
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.derbyTesting.functionTests.tests.lang;
import java.io.File;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import javax.sql.DataSource;
import junit.framework.Test;
import org.apache.derbyTesting.functionTests.util.PrivilegedFileOpsForTests;
import org.apache.derbyTesting.functionTests.util.SQLStateConstants;
import org.apache.derbyTesting.junit.BaseJDBCTestCase;
import org.apache.derbyTesting.junit.BaseTestSuite;
import org.apache.derbyTesting.junit.CleanDatabaseTestSetup;
import org.apache.derbyTesting.junit.JDBC;
import org.apache.derbyTesting.junit.JDBCDataSource;
import org.apache.derbyTesting.junit.TestConfiguration;
/**
* Tests interaction of TRUNCATE TABLE and Online Backup.
* See also DERBY-5213
* The test needs to test:
* o uncommitted truncate table followed by online backup;
* then access the backup copy and access the table.
* expected behavior: should see the old data.
* o uncommitted truncate table, followed by online backup that keeps logs,
* then commit the truncate, then access the table in the backup.
* expected behavior: should see old data in backup.
*/
public class TruncateTableAndOnlineBackupTest extends BaseJDBCTestCase {
static String home = null; // derby.system.home
final static String dbName = "TTOB_db";
// final static String dbName2 = dbName + "2";
final static String backupDir = "TTOB_backup";
public TruncateTableAndOnlineBackupTest(String name) {
super(name);
}
public static Test suite() {
BaseTestSuite suite =
new BaseTestSuite("TruncateTableAndOnlineBackupTest");
suite.addTest(baseSuite("TruncateTableAndOnlineBackupTest:Embedded"));
//suite.addTest(TestConfiguration
// .clientServerDecorator(baseSuite("TruncateTableAndOnlineBackupTest:Client")));
return TestConfiguration.singleUseDatabaseDecorator(suite,
dbName);
//return suite;
}
protected static Test baseSuite(String name) {
BaseTestSuite suite = new BaseTestSuite(name);
suite.addTestSuite(TruncateTableAndOnlineBackupTest.class);
return new CleanDatabaseTestSetup(suite);
}
public void setUp() throws Exception {
getConnection();
home = getSystemProperty("derby.system.home");
Statement stmt = createStatement();
stmt.executeUpdate("create table truncable(i int)");
PreparedStatement ps = getConnection().prepareStatement(
"insert into truncable values (?)");
// insert some data
getConnection().setAutoCommit(false);
for (int i=1; i <= 1000; i++) {
ps.setInt(1,i);
ps.executeUpdate();
}
getConnection().commit();
}
/*
* Drop the table truncable that was created in setUp().
*/
public void tearDown() throws Exception
{
getConnection().createStatement().execute("drop table truncable");
super.tearDown();
}
/* uncommitted truncate table followed by online backup;
* then access the backup copy and access the table.
* expected behavior: should see the old data.
*/
public void testUncommittedTruncateBasicBackup() throws Exception {
setAutoCommit(false);
Statement s = createStatement();
// check...we should have 1000 rows
JDBC.assertFullResultSet(
s.executeQuery("select count(*) from truncable"),
new String[][]{{"1000"}});
// truncate the table, but do not commit
s.executeUpdate("truncate table truncable");
// check...we should have no rows
ResultSet rs = s.executeQuery("select * from truncable");
JDBC.assertEmpty(rs);
CallableStatement cs = prepareCall
("CALL SYSCS_UTIL.SYSCS_BACKUP_DATABASE(?)");
String fullBackupDir = home + "/" + backupDir;
cs.setString(1, fullBackupDir);
cs.execute();
// check contents of table in backup dir
final DataSource ds2 = JDBCDataSource.getDataSource(fullBackupDir+"/"+dbName);
final Connection con2 = ds2.getConnection();
Statement s2 = con2.createStatement();
// check...we should have 1000 rows because truncate table was not committed
JDBC.assertFullResultSet(
s2.executeQuery("select count(*) from truncable"),
new String[][]{{"1000"}});
con2.close();
// close down both
final DataSource[] srcs =
new DataSource[] {JDBCDataSource.getDataSource(),
JDBCDataSource.getDataSource(fullBackupDir+"/"+dbName)};
for (int i=0; i < srcs.length; i++) {
JDBCDataSource.setBeanProperty(
srcs[i], "connectionAttributes", "shutdown=true");
try {
srcs[i].getConnection();
fail("shutdown failed: expected exception");
} catch (SQLException e) {
assertSQLState(
"database shutdown",
SQLStateConstants.CONNECTION_EXCEPTION_CONNECTION_FAILURE,
e);
}
}
assertDirectoryDeleted(new File(fullBackupDir));
}
/* uncommitted truncate table, followed by online backup that keeps logs,
* then commit the truncate, then access the table in the backup.
* expected behavior: should see old data in backup.
*/
public void testUncommittedTruncateBackupEnableLog() throws Exception {
setAutoCommit(false);
Statement s = createStatement();
// check...we should have 1000 rows
JDBC.assertFullResultSet(
s.executeQuery("select count(*) from truncable"),
new String[][]{{"1000"}});
// truncate the table, but do not commit
s.executeUpdate("truncate table truncable");
// check...we should have no rows
ResultSet rs = s.executeQuery("select * from truncable");
JDBC.assertEmpty(rs);
CallableStatement cs = prepareCall
("CALL SYSCS_UTIL.SYSCS_BACKUP_DATABASE_AND_ENABLE_LOG_ARCHIVE_MODE(?,1)");
String fullBackupDir = home + "/" + backupDir;
cs.setString(1, fullBackupDir);
cs.execute();
// now commit - this will commit the truncate table
commit();
// check contents of table in backup dir
final DataSource ds2 = JDBCDataSource.getDataSource(fullBackupDir+"/"+dbName);
final Connection con2 = ds2.getConnection();
Statement s2 = con2.createStatement();
// we should have 1000 rows because truncate table was not committed
JDBC.assertFullResultSet(
s2.executeQuery("select count(*) from truncable"),
new String[][]{{"1000"}});
con2.close();
// backup again, to a different dir
String fullBackupDir2=fullBackupDir+"2";
cs.setString(1, fullBackupDir2);
cs.execute();
// connect to the second backed up database, but this time,
// we should not have any rows.
final DataSource ds3 = JDBCDataSource.getDataSource(fullBackupDir2+"/"+dbName);
final Connection con3 = ds3.getConnection();
Statement s3 = con3.createStatement();
rs = s3.executeQuery("select * from truncable");
JDBC.assertEmpty(rs);
// close down all
final DataSource[] srcs =
new DataSource[] {JDBCDataSource.getDataSource(),
JDBCDataSource.getDataSource(fullBackupDir+"/"+dbName),
JDBCDataSource.getDataSource(fullBackupDir2+"/"+dbName)};
for (int i=0; i < srcs.length; i++) {
JDBCDataSource.setBeanProperty(
srcs[i], "connectionAttributes", "shutdown=true");
try {
srcs[i].getConnection();
fail("shutdown failed: expected exception");
} catch (SQLException e) {
assertSQLState(
"database shutdown",
SQLStateConstants.CONNECTION_EXCEPTION_CONNECTION_FAILURE,
e);
}
}
assertDirectoryDeleted(new File(fullBackupDir));
assertDirectoryDeleted(new File(fullBackupDir2));
}
/* uncommitted truncate table followed by online backup;
* then access the backup copy and access the table.
* expected behavior: should see the old data.
*/
public void testTruncateFreezeUnfreeze() throws Exception {
setAutoCommit(false);
Statement s = createStatement();
// check...we should have 1000 rows
JDBC.assertFullResultSet(
s.executeQuery("select count(*) from truncable"),
new String[][]{{"1000"}});
// truncate the table, but do not commit
s.executeUpdate("truncate table truncable");
// check...we should have no rows
ResultSet rs = s.executeQuery("select * from truncable");
JDBC.assertEmpty(rs);
// freeze the database
s.execute("call syscs_util.syscs_freeze_database()");
// Now copy the database directory
String fullBackupDir = backupDir + "2";
File DbDir = new File(home, dbName);
File fullBackupDbDir = new File(home, fullBackupDir );
PrivilegedFileOpsForTests.copy(DbDir, fullBackupDbDir);
// At this point, writing to the original database is blocked.
// Try to read from the original database. Should work, we should still
// be connected, and read access is allowed during the freeze.
rs = s.executeQuery("select * from truncable");
JDBC.assertEmpty(rs);
// connect to backed-up database
final DataSource ds2 = JDBCDataSource.getDataSource(fullBackupDir);
final Connection con2 = ds2.getConnection();
Statement s2 = con2.createStatement();
// check...we should have 1000 rows because truncate table was not committed
// before the freeze and copy
JDBC.assertFullResultSet(
s2.executeQuery("select count(*) from truncable"),
new String[][]{{"1000"}});
// unfreeze our original database
s.execute("call syscs_util.syscs_unfreeze_database()");
// ensure we can read and write now.
rs = s.executeQuery("select * from truncable");
JDBC.assertEmpty(rs);
s.executeUpdate("insert into truncable values(2001)");
JDBC.assertFullResultSet(
s.executeQuery("select count(*) from truncable"),
new String[][]{{"1"}});
// rollback, should rollback the truncate - then
// select again from the org db - should have 1000 rows again instead of 1
// then select again from the backup db, should still have 1000 rows.
rollback();
JDBC.assertFullResultSet(
s.executeQuery("select count(*) from truncable"),
new String[][]{{"1000"}});
JDBC.assertFullResultSet(
s2.executeQuery("select count(*) from truncable"),
new String[][]{{"1000"}});
s2.close();
con2.close();
// close down both databases
final DataSource[] srcs =
new DataSource[] {JDBCDataSource.getDataSource(),
ds2};
for (int i=0; i < srcs.length; i++) {
JDBCDataSource.setBeanProperty(
srcs[i], "connectionAttributes", "shutdown=true");
try {
srcs[i].getConnection();
fail("shutdown failed: expected exception");
} catch (SQLException e) {
assertSQLState(
"database shutdown",
SQLStateConstants.CONNECTION_EXCEPTION_CONNECTION_FAILURE,
e);
}
}
assertDirectoryDeleted(new File(home + "/"+fullBackupDir));
}
}