package net.ttddyy.dsproxy.transform; import net.ttddyy.dsproxy.TestUtils; import net.ttddyy.dsproxy.listener.QueryExecutionListener; import net.ttddyy.dsproxy.proxy.InterceptorHolder; import net.ttddyy.dsproxy.proxy.jdk.JdkJdbcProxyFactory; import org.hsqldb.jdbc.JDBCDataSource; import org.junit.After; import org.junit.Before; import org.junit.Test; import javax.sql.DataSource; import java.sql.*; import java.util.ArrayList; import java.util.List; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*; import static org.mockito.Mockito.mock; /** * @author Tadaya Tsuyukubo */ public class CallableStatementQueryTransformerTest { // hsqldb stored procedure. insert to table foo. public static void insertFoo(Connection conn, int id, String name) throws SQLException { Statement stmt = conn.createStatement(); stmt.execute("INSERT INTO foo (id, name) VALUES (" + id + ", '" + name + "')"); stmt.close(); } // hsqldb stored procedure. insert to table bar. public static void insertBar(Connection conn, int id, String name) throws SQLException { Statement stmt = conn.createStatement(); stmt.execute("INSERT INTO bar (id, name) VALUES (" + id + ", '" + name + "')"); stmt.close(); } // hsqldb stored procedure public static String procFoo(String s) { return "foo=" + s; } // hsqldb stored procedure public static String procBar(String s) { return "bar=" + s; } private DataSource rawDatasource; private List<String> interceptedQueries = new ArrayList<String>(); private QueryTransformer transformer = new QueryTransformer() { public String transformQuery(TransformInfo transformInfo) { interceptedQueries.add(transformInfo.getQuery()); return "call proc_bar('BAR')"; } }; @Before public void setup() throws Exception { // real datasource JDBCDataSource rawDataSource = new JDBCDataSource(); rawDataSource.setDatabase("jdbc:hsqldb:mem:aname"); rawDataSource.setUser("sa"); this.rawDatasource = rawDataSource; // create stored procedure String procFoo = "CREATE FUNCTION proc_foo(s VARCHAR(50)) RETURNS VARCHAR(50) LANGUAGE JAVA DETERMINISTIC NO SQL EXTERNAL NAME 'CLASSPATH:net.ttddyy.dsproxy.transform.CallableStatementQueryTransformerTest.procFoo'"; String procBar = "CREATE FUNCTION proc_bar(s VARCHAR(50)) RETURNS VARCHAR(50) LANGUAGE JAVA DETERMINISTIC NO SQL EXTERNAL NAME 'CLASSPATH:net.ttddyy.dsproxy.transform.CallableStatementQueryTransformerTest.procBar'"; String tableFoo = "CREATE TABLE foo ( id INTEGER PRIMARY KEY, name VARCHAR(10) );"; String tableBar = "CREATE TABLE bar ( id INTEGER PRIMARY KEY, name VARCHAR(10) );"; String insertFoo = "CREATE PROCEDURE insert_foo(IN id INT, IN name VARCHAR(50)) LANGUAGE JAVA NOT DETERMINISTIC MODIFIES SQL DATA EXTERNAL NAME 'CLASSPATH:net.ttddyy.dsproxy.transform.CallableStatementQueryTransformerTest.insertFoo'"; String insertBar = "CREATE PROCEDURE insert_bar(IN id INT, IN name VARCHAR(50)) LANGUAGE JAVA NOT DETERMINISTIC MODIFIES SQL DATA EXTERNAL NAME 'CLASSPATH:net.ttddyy.dsproxy.transform.CallableStatementQueryTransformerTest.insertBar'"; Statement statement = rawDataSource.getConnection().createStatement(); statement.addBatch(procFoo); statement.addBatch(procBar); statement.addBatch(tableFoo); statement.addBatch(tableBar); statement.addBatch(insertFoo); statement.addBatch(insertBar); statement.executeBatch(); } @After public void teardown() throws Exception { interceptedQueries.clear(); TestUtils.shutdown(rawDatasource); } private Connection getProxyConnection(final String replacedQuery) throws Exception { QueryTransformer transformer = new QueryTransformer() { public String transformQuery(TransformInfo transformInfo) { interceptedQueries.add(transformInfo.getQuery()); return replacedQuery; } }; QueryExecutionListener queryListener = mock(QueryExecutionListener.class); InterceptorHolder interceptorHolder = new InterceptorHolder(queryListener, transformer); return new JdkJdbcProxyFactory().createConnection(rawDatasource.getConnection(), interceptorHolder); } @Test public void testExecute() throws Exception { String queryToReplace = "CALL proc_bar(?)"; CallableStatement cs = getProxyConnection(queryToReplace).prepareCall("CALL proc_foo(?)"); cs.setString(1, "FOO"); boolean result = cs.execute(); assertThat(result, is(true)); ResultSet rs = cs.getResultSet(); assertThat(rs.next(), is(true)); String output = rs.getString(1); assertThat(output, is("bar=FOO")); // verify intercepted query assertThat(interceptedQueries, hasSize(1)); assertThat(interceptedQueries, hasItem("CALL proc_foo(?)")); } @Test public void testBatch() throws Exception { String queryToReplace = "CALL insert_bar(?, ?)"; CallableStatement cs = getProxyConnection(queryToReplace).prepareCall("CALL insert_foo(?, ?)"); cs.setInt(1, 100); cs.setString(2, "FOO1"); cs.addBatch(); cs.setInt(1, 200); cs.setString(2, "FOO2"); cs.addBatch(); int[] result = cs.executeBatch(); assertThat(result.length, is(2)); // verify intercepted query. assertThat(interceptedQueries, hasSize(1)); assertThat(interceptedQueries, hasItem("CALL insert_foo(?, ?)")); Statement statement = rawDatasource.getConnection().createStatement(); ResultSet rs = statement.executeQuery("SELECT COUNT(*) FROM foo"); assertThat(rs.next(), is(true)); assertThat("table foo has no records", rs.getInt(1), is(0)); rs = statement.executeQuery("SELECT COUNT(*) FROM bar"); assertThat(rs.next(), is(true)); assertThat("table foo has 2 records", rs.getInt(1), is(2)); rs = statement.executeQuery("SELECT id, name FROM bar ORDER BY id ASC"); assertThat(rs.next(), is(true)); assertThat(rs.getInt("id"), is(100)); assertThat(rs.getString("name"), is("FOO1")); assertThat(rs.next(), is(true)); assertThat(rs.getInt("id"), is(200)); assertThat(rs.getString("name"), is("FOO2")); } }