/*
* Copyright 2004-2011 H2 Group. Multiple-Licensed under the H2 License,
* Version 1.0, and under the Eclipse Public License, Version 1.0
* (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.test.jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
import org.h2.Driver;
import org.h2.api.DatabaseEventListener;
import org.h2.constant.ErrorCode;
import org.h2.test.TestBase;
/**
* Tests the DatabaseEventListener interface.
*/
public class TestDatabaseEventListener extends TestBase implements DatabaseEventListener {
private static boolean calledOpened, calledClosingDatabase, calledScan, calledCreateIndex;
private static boolean calledStatementStart, calledStatementEnd, calledStatementProgress;
/**
* Run just this test.
*
* @param a ignored
*/
public static void main(String... a) throws Exception {
TestBase.createCaller().init().test();
}
public void test() throws SQLException {
testInit();
testIndexRebuiltOnce();
testIndexNotRebuilt();
testCalled();
testCloseLog0(false);
testCloseLog0(true);
testCalledForStatement();
deleteDb("databaseEventListener");
}
/**
* Initialize the database after opening.
*/
public static class Init implements DatabaseEventListener {
private String databaseUrl;
public void init(String url) {
databaseUrl = url;
}
public void opened() {
try {
// using DriverManager.getConnection could result in a deadlock
// when using the server mode, but within the same process
Properties prop = new Properties();
prop.setProperty("user", "sa");
prop.setProperty("password", "sa");
Connection conn = Driver.load().connect(databaseUrl, prop);
Statement stat = conn.createStatement();
stat.execute("create table if not exists test(id int)");
conn.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
public void closingDatabase() {
// nothing to do
}
public void exceptionThrown(SQLException e, String sql) {
// nothing to do
}
public void setProgress(int state, String name, int x, int max) {
// nothing to do
}
}
private void testInit() throws SQLException {
if (config.cipher != null || config.memory) {
return;
}
deleteDb("databaseEventListener");
String url = getURL("databaseEventListener", true);
url += ";DATABASE_EVENT_LISTENER='" + Init.class.getName() + "'";
Connection conn = DriverManager.getConnection(url, "sa", "sa");
Statement stat = conn.createStatement();
stat.execute("select * from test");
conn.close();
}
private void testIndexRebuiltOnce() throws SQLException {
if (config.memory) {
return;
}
deleteDb("databaseEventListener");
String url = getURL("databaseEventListener", true);
String user = getUser(), password = getPassword();
Properties p = new Properties();
p.setProperty("user", user);
p.setProperty("password", password);
Connection conn;
Statement stat;
conn = DriverManager.getConnection(url, p);
stat = conn.createStatement();
// the old.id index head is at position 0
stat.execute("create table old(id identity) as select 1");
// the test.id index head is at position 1
stat.execute("create table test(id identity) as select 1");
conn.close();
conn = DriverManager.getConnection(url, p);
stat = conn.createStatement();
// free up space at position 0
stat.execute("drop table old");
stat.execute("insert into test values(2)");
stat.execute("checkpoint sync");
stat.execute("shutdown immediately");
assertThrows(ErrorCode.DATABASE_IS_CLOSED, conn).close();
// now the index should be re-built
conn = DriverManager.getConnection(url, p);
conn.close();
calledCreateIndex = false;
p.put("DATABASE_EVENT_LISTENER", getClass().getName());
conn = org.h2.Driver.load().connect(url, p);
conn.close();
assertTrue(!calledCreateIndex);
}
private void testIndexNotRebuilt() throws SQLException {
if (config.memory) {
return;
}
deleteDb("databaseEventListener");
String url = getURL("databaseEventListener", true);
String user = getUser(), password = getPassword();
Properties p = new Properties();
p.setProperty("user", user);
p.setProperty("password", password);
Connection conn = DriverManager.getConnection(url, p);
Statement stat = conn.createStatement();
// the old.id index head is at position 0
stat.execute("create table old(id identity) as select 1");
// the test.id index head is at position 1
stat.execute("create table test(id identity) as select 1");
conn.close();
conn = DriverManager.getConnection(url, p);
stat = conn.createStatement();
// free up space at position 0
stat.execute("drop table old");
// truncate, relocating to position 0
stat.execute("truncate table test");
stat.execute("insert into test select 1");
conn.close();
calledCreateIndex = false;
p.put("DATABASE_EVENT_LISTENER", getClass().getName());
conn = org.h2.Driver.load().connect(url, p);
conn.close();
assertTrue(!calledCreateIndex);
}
private void testCloseLog0(boolean shutdown) throws SQLException {
if (config.memory) {
return;
}
deleteDb("databaseEventListener");
String url = getURL("databaseEventListener", true);
String user = getUser(), password = getPassword();
Properties p = new Properties();
p.setProperty("user", user);
p.setProperty("password", password);
Connection conn = DriverManager.getConnection(url, p);
Statement stat = conn.createStatement();
stat.execute("create table test(id int primary key, name varchar)");
stat.execute("insert into test select x, space(1000) from system_range(1,1000)");
if (shutdown) {
stat.execute("shutdown");
}
conn.close();
calledOpened = false;
calledScan = false;
p.put("DATABASE_EVENT_LISTENER", getClass().getName());
conn = org.h2.Driver.load().connect(url, p);
conn.close();
if (calledOpened) {
assertTrue(!calledScan);
}
}
private void testCalled() throws SQLException {
Properties p = new Properties();
p.setProperty("user", "sa");
p.setProperty("password", "sa");
calledOpened = false;
calledClosingDatabase = false;
p.put("DATABASE_EVENT_LISTENER", getClass().getName());
org.h2.Driver.load();
String url = "jdbc:h2:mem:databaseEventListener";
Connection conn = org.h2.Driver.load().connect(url, p);
conn.close();
assertTrue(calledOpened);
assertTrue(calledClosingDatabase);
}
private void testCalledForStatement() throws SQLException {
Properties p = new Properties();
p.setProperty("user", "sa");
p.setProperty("password", "sa");
calledStatementStart = false;
calledStatementEnd = false;
calledStatementProgress = false;
p.put("DATABASE_EVENT_LISTENER", getClass().getName());
org.h2.Driver.load();
String url = "jdbc:h2:mem:databaseEventListener";
Connection conn = org.h2.Driver.load().connect(url, p);
Statement stat = conn.createStatement();
stat.execute("create table test(id int primary key, name varchar)");
stat.execute("select * from test");
conn.close();
assertTrue(calledStatementStart);
assertTrue(calledStatementEnd);
assertTrue(calledStatementProgress);
}
public void closingDatabase() {
calledClosingDatabase = true;
}
public void exceptionThrown(SQLException e, String sql) {
// nothing to do
}
public void init(String url) {
// nothing to do
}
public void opened() {
calledOpened = true;
}
public void setProgress(int state, String name, int x, int max) {
if (state == DatabaseEventListener.STATE_SCAN_FILE) {
calledScan = true;
}
if (state == DatabaseEventListener.STATE_CREATE_INDEX) {
if (!name.startsWith("SYS:")) {
calledCreateIndex = true;
}
}
if (state == STATE_STATEMENT_START) {
if (name.equals("select * from test")) {
calledStatementStart = true;
}
}
if (state == STATE_STATEMENT_END) {
if (name.equals("select * from test")) {
calledStatementEnd = true;
}
}
if (state == STATE_STATEMENT_PROGRESS) {
if (name.equals("select * from test")) {
calledStatementProgress = true;
}
}
}
}