/*
* 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.systemmodel;
import static org.junit.Assert.*;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.teiid.adminapi.Model.Type;
import org.teiid.adminapi.impl.ModelMetaData;
import org.teiid.client.util.ResultsFuture;
import org.teiid.jdbc.AsynchPositioningException;
import org.teiid.jdbc.ConnectionImpl;
import org.teiid.jdbc.ContinuousStatementCallback;
import org.teiid.jdbc.FakeServer;
import org.teiid.jdbc.RequestOptions;
import org.teiid.jdbc.StatementCallback;
import org.teiid.jdbc.TeiidResultSet;
import org.teiid.jdbc.TeiidStatement;
import org.teiid.language.QueryExpression;
import org.teiid.metadata.RuntimeMetadata;
import org.teiid.runtime.HardCodedExecutionFactory;
import org.teiid.translator.ExecutionContext;
import org.teiid.translator.ResultSetExecution;
import org.teiid.translator.TranslatorException;
@SuppressWarnings("nls")
public class TestAsynch {
private static FakeServer server;
private ConnectionImpl internalConnection;
private static HardCodedExecutionFactory ef;
private static List<String> partIds = Collections.synchronizedList(new ArrayList<String>());
@BeforeClass public static void oneTimeSetup() throws Exception {
server = new FakeServer(true);
ModelMetaData mmd = new ModelMetaData();
mmd.setName("v");
mmd.setModelType(Type.PHYSICAL);
mmd.setSchemaSourceType("ddl");
mmd.addSourceMapping("z", "z", null);
mmd.setSchemaText("create view test (col integer) as select 1; create foreign table someTable (col integer);");
ef = new HardCodedExecutionFactory() {
@Override
public ResultSetExecution createResultSetExecution(
QueryExpression command, ExecutionContext executionContext,
RuntimeMetadata metadata, Object connection)
throws TranslatorException {
partIds.add(executionContext.getPartIdentifier());
return super.createResultSetExecution(command, executionContext, metadata,
connection);
}
};
server.addTranslator("z", ef);
server.deployVDB("x", mmd);
}
@After public void teardown() {
partIds.clear();
}
@AfterClass public static void oneTimeTeardown() throws Exception {
server.stop();
}
@Before public void setUp() throws Exception {
this.internalConnection = server.createConnection("jdbc:teiid:x"); //$NON-NLS-1$ //$NON-NLS-2$
}
@Test public void testAsynch() throws Exception {
Statement stmt = this.internalConnection.createStatement();
TeiidStatement ts = stmt.unwrap(TeiidStatement.class);
final ResultsFuture<Integer> result = new ResultsFuture<Integer>();
ts.submitExecute("select * from sys.tables a, sys.tables b, sys.tables c", new StatementCallback() {
int rowCount;
@Override
public void onRow(Statement s, ResultSet rs) {
rowCount++;
try {
if (!rs.isLast()) {
assertTrue(rs.unwrap(TeiidResultSet.class).available() > 0);
}
if (rowCount == 10000) {
s.close();
}
} catch (AsynchPositioningException e) {
try {
assertEquals(0, rs.unwrap(TeiidResultSet.class).available());
} catch (SQLException e1) {
result.getResultsReceiver().exceptionOccurred(e1);
}
} catch (SQLException e) {
result.getResultsReceiver().exceptionOccurred(e);
}
}
@Override
public void onException(Statement s, Exception e) {
result.getResultsReceiver().exceptionOccurred(e);
}
@Override
public void onComplete(Statement s) {
result.getResultsReceiver().receiveResults(rowCount);
}
}, new RequestOptions());
assertEquals(10000, result.get().intValue());
}
@Test public void testAsynchContinuousEmpty() throws Exception {
Statement stmt = this.internalConnection.createStatement();
TeiidStatement ts = stmt.unwrap(TeiidStatement.class);
final ResultsFuture<Integer> result = new ResultsFuture<Integer>();
ts.submitExecute("select * from SYS.Schemas where 1 = 0", new ContinuousStatementCallback() {
int execCount;
@Override
public void onRow(Statement s, ResultSet rs) throws SQLException {
fail();
}
@Override
public void onException(Statement s, Exception e) {
result.getResultsReceiver().exceptionOccurred(e);
}
@Override
public void onComplete(Statement s) {
result.getResultsReceiver().receiveResults(execCount);
}
@Override
public void beforeNextExecution(Statement s) throws SQLException {
execCount++;
assertEquals(-1, s.getResultSet().unwrap(TeiidResultSet.class).available());
if (execCount == 1024) {
s.close();
}
}
}, new RequestOptions().continuous(true));
assertEquals(1024, result.get().intValue());
}
@Test public void testAsynchContinuousNonEmpty() throws Exception {
Statement stmt = this.internalConnection.createStatement();
TeiidStatement ts = stmt.unwrap(TeiidStatement.class);
final ResultsFuture<Integer> result = new ResultsFuture<Integer>();
ts.submitExecute("select 1", new ContinuousStatementCallback() {
int execCount;
@Override
public void onRow(Statement s, ResultSet rs) throws SQLException {
assertEquals(0, rs.unwrap(TeiidResultSet.class).available());
s.close();
}
@Override
public void onException(Statement s, Exception e) {
result.getResultsReceiver().exceptionOccurred(e);
}
@Override
public void onComplete(Statement s) {
result.getResultsReceiver().receiveResults(execCount);
}
@Override
public void beforeNextExecution(Statement s) throws SQLException {
execCount++;
}
}, new RequestOptions().continuous(true));
assertEquals(0, result.get().intValue());
}
@Test public void testAsynchContinuous() throws Exception {
Statement stmt = this.internalConnection.createStatement();
TeiidStatement ts = stmt.unwrap(TeiidStatement.class);
final ResultsFuture<Integer> result = new ResultsFuture<Integer>();
ts.submitExecute("select xmlelement(name x) from SYS.Schemas", new StatementCallback() {
int rowCount;
@Override
public void onRow(Statement s, ResultSet rs) throws SQLException {
rowCount++;
if (rowCount == 1024) {
s.close();
}
}
@Override
public void onException(Statement s, Exception e) {
result.getResultsReceiver().exceptionOccurred(e);
}
@Override
public void onComplete(Statement s) {
result.getResultsReceiver().receiveResults(rowCount);
}
}, new RequestOptions().continuous(true));
assertEquals(1024, result.get().intValue());
}
@Test public void testAsynchContinuousMergeBlock() throws Exception {
Statement stmt = this.internalConnection.createStatement();
stmt.execute("create temporary table t (c string, primary key (c))");
stmt.execute("set autoCommitTxn off");
TeiidStatement ts = stmt.unwrap(TeiidStatement.class);
final ResultsFuture<Integer> result = new ResultsFuture<Integer>();
ts.submitExecute("begin merge into t select name from schemas limit 2; select rowcount; end", new StatementCallback() {
int rowCount;
@Override
public void onRow(Statement s, ResultSet rs) throws SQLException {
rowCount++;
if (rowCount == 10) {
s.close();
}
}
@Override
public void onException(Statement s, Exception e) {
result.getResultsReceiver().exceptionOccurred(e);
}
@Override
public void onComplete(Statement s) {
result.getResultsReceiver().receiveResults(rowCount);
}
}, new RequestOptions().continuous(true));
assertEquals(10, result.get().intValue());
stmt = this.internalConnection.createStatement();
ResultSet rs = stmt.executeQuery("select count(*) from t");
rs.next();
assertEquals(2, rs.getInt(1));
}
@Test public void testAsynchContinuousWithAlter() throws Exception {
Statement stmt = this.internalConnection.createStatement();
TeiidStatement ts = stmt.unwrap(TeiidStatement.class);
final ResultsFuture<Integer> result = new ResultsFuture<Integer>();
ts.submitExecute("select * from test", new StatementCallback() {
int rowCount;
@Override
public void onRow(Statement s, ResultSet rs) {
try {
rowCount++;
if (rowCount < 3) {
assertEquals(1, rs.getInt(1));
if (rowCount == 2) {
Statement st = internalConnection.createStatement();
st.execute("alter view v.test as select 2");
st.close();
try {
Thread.sleep(100); //we only track down to millisecond resolution
} catch (InterruptedException e) {
result.getResultsReceiver().exceptionOccurred(e);
}
}
} else {
assertEquals(2, rs.getInt(1)); //new value
s.close();
}
} catch (SQLException e) {
result.getResultsReceiver().exceptionOccurred(e);
throw new RuntimeException(e);
}
}
@Override
public void onException(Statement s, Exception e) {
result.getResultsReceiver().exceptionOccurred(e);
}
@Override
public void onComplete(Statement s) {
result.getResultsReceiver().receiveResults(rowCount);
}
}, new RequestOptions().continuous(true));
assertEquals(3, result.get().intValue());
}
@Test public void testAsynchPlaning() throws Exception {
Statement stmt = this.internalConnection.createStatement();
TeiidStatement ts = stmt.unwrap(TeiidStatement.class);
ef.addData("SELECT someTable.col FROM someTable", Arrays.asList(Arrays.asList(1)));
final ResultsFuture<Integer> result = new ResultsFuture<Integer>();
ts.submitExecute("select * from someTable", new StatementCallback() {
int rowCount;
@Override
public void onRow(Statement s, ResultSet rs) {
try {
rowCount++;
if (rowCount == 3) {
s.close();
}
} catch (SQLException e) {
result.getResultsReceiver().exceptionOccurred(e);
throw new RuntimeException(e);
}
}
@Override
public void onException(Statement s, Exception e) {
result.getResultsReceiver().exceptionOccurred(e);
}
@Override
public void onComplete(Statement s) {
result.getResultsReceiver().receiveResults(rowCount);
}
}, new RequestOptions().continuous(true));
assertEquals(3, result.get().intValue());
assertEquals(3, partIds.size());
assertEquals(partIds.get(0), partIds.get(1));
assertEquals(partIds.get(1), partIds.get(2));
}
/**
* Runs sufficient iterations to ensure the temptablestore state is correct
* @throws Exception
*/
@Test public void testAsynchAnon() throws Exception {
String query = "begin\n" +
"insert into #mom_collectors select 'a' as hostname, 123 as port, 1 as id from sometable;\n" +
"insert into #apm_collectors select 'a' as hostname, 124 as port, 12 as id from sometable;\n"+
"select 'add', hostname, port, id from #mom_collectors\n"+
"where (hostname, port) not in (select (hostname, port) from #apm_collectors)\n"+
"union select 'delete', hostname, port, id from #apm_collectors\n"+
"where (hostname, port) not in (select (hostname, port) from #mom_collectors) with return; end";
Statement stmt = this.internalConnection.createStatement();
TeiidStatement ts = stmt.unwrap(TeiidStatement.class);
ef.addData("SELECT someTable.col FROM someTable", Collections.nCopies(1, Arrays.asList(1)));
ts.setExecutionProperty("autoCommitTxn", "off");
final ResultsFuture<Integer> result = new ResultsFuture<Integer>();
ts.submitExecute(query, new StatementCallback() {
int rowCount;
@Override
public void onRow(Statement s, ResultSet rs) {
try {
rowCount++;
if (rowCount == 100000) {
s.close();
}
} catch (SQLException e) {
result.getResultsReceiver().exceptionOccurred(e);
throw new RuntimeException(e);
}
}
@Override
public void onException(Statement s, Exception e) {
result.getResultsReceiver().exceptionOccurred(e);
}
@Override
public void onComplete(Statement s) {
result.getResultsReceiver().receiveResults(rowCount);
}
}, new RequestOptions().continuous(true));
assertEquals(100000, result.get().intValue());
}
@Test public void testTransactionCycle() throws Exception {
Statement stmt = this.internalConnection.createStatement();
TeiidStatement ts = stmt.unwrap(TeiidStatement.class);
final ResultsFuture<Void> result = new ResultsFuture<Void>();
ts.submitExecute("start transaction", new StatementCallback() {
@Override
public void onRow(Statement s, ResultSet rs) {
}
@Override
public void onException(Statement s, Exception e) {
result.getResultsReceiver().exceptionOccurred(e);
}
@Override
public void onComplete(Statement s) {
result.getResultsReceiver().receiveResults(null);
}
}, new RequestOptions());
result.get();
final ResultsFuture<Void> rollBackResult = new ResultsFuture<Void>();
ts.submitExecute("rollback", new StatementCallback() {
@Override
public void onRow(Statement s, ResultSet rs) {
}
@Override
public void onException(Statement s, Exception e) {
rollBackResult.getResultsReceiver().exceptionOccurred(e);
}
@Override
public void onComplete(Statement s) {
rollBackResult.getResultsReceiver().receiveResults(null);
}
}, new RequestOptions());
rollBackResult.get();
}
}