/* * JBoss, Home of Professional Open Source. * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. Some portions may be licensed * to Red Hat, Inc. under one or more contributor license agreements. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA. */ package org.teiid.jdbc; import static org.junit.Assert.*; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.sql.Statement; import org.junit.After; import org.teiid.script.io.ResultSetReader; /** * This class can be used as the base class to write Query tests for * integration testing. Just like the scripted one this one should provide all * those required flexibility in testing. */ public abstract class AbstractQueryTest { //NOTE not all tests will pass with this set to true, only those with scrollable resultsets static boolean WRITE_ACTUAL = false; protected Connection internalConnection = null; protected ResultSet internalResultSet = null; protected Statement internalStatement = null; protected SQLException internalException = null; protected int updateCount = -1; protected String DELIMITER = " "; //$NON-NLS-1$ public AbstractQueryTest() { super(); } public AbstractQueryTest(Connection conn) { super(); this.internalConnection = conn; } @After public void tearDown() throws Exception { closeConnection(); } public void setConnection(Connection c) { this.internalConnection = c; } public Connection getConnection() { return this.internalConnection; } public boolean execute(String sql) throws SQLException { return execute(sql, new Object[] {}); } public boolean execute(String sql, Object... params) throws SQLException { closeResultSet(); closeStatement(); this.updateCount = -1; try { assertNotNull(this.internalConnection); assertTrue(!this.internalConnection.isClosed()); boolean result = false; if (params != null && params.length > 0) { if (sql.startsWith("exec ")) { //$NON-NLS-1$ sql = sql.substring(5); this.internalStatement = createPrepareCallStatement(sql); } else { this.internalStatement = createPrepareStatement(sql); } setParameters((PreparedStatement)this.internalStatement, params); assignExecutionProperties(this.internalStatement); result = ((PreparedStatement)this.internalStatement).execute(); } else { this.internalStatement = createStatement(); assignExecutionProperties(this.internalStatement); result = this.internalStatement.execute(sql); } if (result) { this.internalResultSet = this.internalStatement.getResultSet(); } else { this.updateCount = this.internalStatement.getUpdateCount(); } return result; } catch (SQLException e) { this.internalException = e; if (!exceptionExpected()) { throw e; } } return false; } protected Statement createPrepareCallStatement(String sql) throws SQLException{ return this.internalConnection.prepareCall("{?=call "+sql+"}"); //$NON-NLS-1$ //$NON-NLS-2$ } protected Statement createPrepareStatement(String sql) throws SQLException{ return this.internalConnection.prepareStatement(sql); } protected Statement createStatement() throws SQLException{ return this.internalConnection.createStatement(); } private void setParameters(PreparedStatement stmt, Object[] params) throws SQLException{ for (int i = 0; i < params.length; i++) { stmt.setObject(i+1, params[i]); } } public int[] executeBatch(String[] sql) { return executeBatch(sql, -1); } public int[] executeBatch(String[] sql, int timeout) { closeResultSet(); closeStatement(); try { assertNotNull(this.internalConnection); assertTrue(!this.internalConnection.isClosed()); for (int i = 0; i < sql.length; i++) { if (sql[i].indexOf("?") != -1) { //$NON-NLS-1$ throw new RuntimeException("no prepared statements allowed in the batch command"); //$NON-NLS-1$ } } this.internalStatement = createStatement(); assignExecutionProperties(this.internalStatement); if (timeout != -1) { this.internalStatement.setQueryTimeout(timeout); } for (int i = 0; i < sql.length; i++) { this.internalStatement.addBatch(sql[i]); } return this.internalStatement.executeBatch(); } catch (SQLException e) { this.internalException = e; if (!exceptionExpected()) { throw new RuntimeException(e); } } return null; } /** * Override when you need to set an execution property on the statement before execution. * * <p>Example: *<code>if (this.executionProperties.getProperty(ExecutionProperties.PROP_FETCH_SIZE) != null) { * statement.setExecutionProperty(ExecutionProperties.PROP_FETCH_SIZE, this.executionProperties.getProperty(ExecutionProperties.PROP_FETCH_SIZE)); * } *</code> *</p> * @param stmt * * @since */ protected void assignExecutionProperties(Statement stmt) { } public boolean exceptionOccurred() { return this.internalException != null; } public boolean exceptionExpected() { return false; } public SQLException getLastException() { return this.internalException; } public void assertResultsSetEquals(File expected) { assertResultsSetEquals(this.internalResultSet, expected); } public void assertResultsSetEquals(ResultSet resultSet, File expected) { assertNotNull(resultSet); try { writeResultSet(expected, new BufferedReader(new ResultSetReader(resultSet, DELIMITER))); if (resultSet.getType() != ResultSet.TYPE_FORWARD_ONLY) { resultSet.beforeFirst(); } assertReaderEquals(new ResultSetReader(resultSet, DELIMITER), new FileReader(expected)); } catch (IOException e) { throw new RuntimeException(e); } catch (SQLException e) { throw new RuntimeException(e); } } private void writeResultSet(File expected, BufferedReader resultReader) throws IOException { if (WRITE_ACTUAL) { BufferedWriter bw = new BufferedWriter(new FileWriter(expected)); String s = null; while ((s = resultReader.readLine()) != null) { bw.write(s); bw.write("\n"); //$NON-NLS-1$ } bw.close(); } } public void assertResultsSetEquals(String expected) { assertResultsSetEquals(this.internalResultSet, expected); } public void assertResultsSetEquals(ResultSet resultSet,String expected) { assertNotNull(resultSet); assertReaderEquals(new ResultSetReader(resultSet, DELIMITER), new StringReader(expected)); } public void assertResults(String[] expected) { assertResultsSetEquals(expected); } public void assertResultsSetEquals(String[] expected) { assertResultsSetEquals(this.internalResultSet, expected); } public void assertResultsSetEquals(ResultSet resultSet, String[] expected) { assertNotNull(resultSet); assertReaderEquals(new ResultSetReader(resultSet, DELIMITER), new StringArrayReader(expected)); } public void assertReaderEquals(Reader expected, Reader reader) { BufferedReader resultReader = new BufferedReader(expected); BufferedReader expectedReader = new BufferedReader(reader); try { compareResults(resultReader, expectedReader); } catch (Exception e) { throw new RuntimeException(e); } finally { try { resultReader.close(); expectedReader.close(); } catch (IOException e) { throw new RuntimeException(e); } } } public void assertResultsSetMetadataEquals(ResultSetMetaData metadata, File expected) { assertNotNull(metadata); try { writeResultSet(expected, new BufferedReader(new MetadataReader(metadata, DELIMITER))); assertReaderEquals(new MetadataReader(metadata, DELIMITER), new FileReader(expected)); } catch (IOException e) { throw new RuntimeException(e); } } public void assertResultsSetMetadataEquals(ResultSetMetaData metadata, String[] expected) { assertNotNull(metadata); assertReaderEquals(new MetadataReader(metadata, DELIMITER), new StringArrayReader(expected)); } protected static String read(BufferedReader r, boolean casesensitive) throws IOException { StringBuffer result = new StringBuffer(); String s = null; try { while ((s = r.readLine()) != null) { result.append( (casesensitive ? s.trim() : s.trim().toLowerCase()) ); result.append("\n"); //$NON-NLS-1$ } } finally { r.close(); } return result.toString(); } protected void compareResults(BufferedReader resultReader, BufferedReader expectedReader) throws IOException { assertEquals(read(expectedReader, compareCaseSensitive()) , read(resultReader, compareCaseSensitive())); } protected boolean compareCaseSensitive() { return true; } public void printResults() { printResults(this.internalResultSet); } public void printResults(ResultSet results) { printResults(results, false); } public void printResults(boolean comparePrint) { assertNotNull(this.internalResultSet); printResults(this.internalResultSet, comparePrint); } public void walkResults() { assertNotNull(this.internalResultSet); try { int columnCount = this.internalResultSet.getMetaData().getColumnCount(); while(this.internalResultSet.next()) { for (int col = 1; col <= columnCount; col++) { this.internalResultSet.getObject(col); } } closeResultSet(); } catch (SQLException e) { throw new RuntimeException(e); } } void printResults(ResultSet results, boolean comparePrint) { if(results == null) { System.out.println("ResultSet is null"); //$NON-NLS-1$ return; } int row; try { row = -1; BufferedReader in = new BufferedReader(new ResultSetReader(results, DELIMITER)); String line = in.readLine(); while(line != null) { row++; if (comparePrint) { line=line.replaceAll("\"", "\\\\\""); //$NON-NLS-1$ //$NON-NLS-2$ System.out.println("\""+line+"\","); //$NON-NLS-1$ //$NON-NLS-2$ } else { System.out.println(line); } line = in.readLine(); } System.out.println("Fetched "+row+" rows\n"); //$NON-NLS-1$ //$NON-NLS-2$ } catch (IOException e) { throw new RuntimeException(e); } } public void assertUpdateCount(int expected) { assertEquals(expected, updateCount); } public void assertRowCount(int expected) { int count = getRowCount(); assertEquals(expected, count); } public int getRowCount() { assertNotNull(this.internalResultSet); // Count all try { int count = 0; while(this.internalResultSet.next()) { count++; } return count; } catch (SQLException e) { throw new RuntimeException(e); } } public void closeStatement() { closeResultSet(); if (this.internalStatement != null){ try { this.internalStatement.close(); } catch(SQLException e) { throw new RuntimeException(e); } finally { this.internalStatement = null; } } } public void closeResultSet() { this.internalException = null; if (this.internalResultSet != null) { try { this.internalResultSet.close(); } catch(SQLException e) { // ignore } finally { this.internalResultSet = null; } } } public void closeConnection() { closeStatement(); try { if (this.internalConnection != null) { try { this.internalConnection.close(); } catch(SQLException e) { throw new RuntimeException(e); } } } finally { this.internalConnection = null; } } public void cancelQuery() throws SQLException { assertNotNull(this.internalConnection); assertTrue(!this.internalConnection.isClosed()); assertNotNull(this.internalStatement); this.internalStatement.cancel(); } public void print(String msg) { System.out.println(msg); } public void print(Throwable e) { e.printStackTrace(); } protected void executeAndAssertResults(String query, String[] expected) throws SQLException { execute(query); if (expected != null) { assertResults(expected); } else { printResults(true); } } }