/*
* 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.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.teiid.adminapi.impl.ModelMetaData;
import org.teiid.core.util.UnitTestUtil;
import org.teiid.language.Call;
import org.teiid.language.QueryExpression;
import org.teiid.metadata.RuntimeMetadata;
import org.teiid.translator.CacheDirective.Scope;
import org.teiid.translator.DataNotAvailableException;
import org.teiid.translator.ExecutionContext;
import org.teiid.translator.ExecutionFactory;
import org.teiid.translator.ProcedureExecution;
import org.teiid.translator.ResultSetExecution;
import org.teiid.translator.TranslatorException;
@SuppressWarnings("nls")
public class TestResultsCache {
private Connection conn;
private static FakeServer server;
@BeforeClass public static void oneTimeSetup() throws Exception {
server = new FakeServer(true);
server.deployVDB("test", UnitTestUtil.getTestDataPath() + "/TestCase3473/test.vdb");
}
@AfterClass public static void oneTimeTeardown() {
server.stop();
}
@Before public void setUp() throws Exception {
conn = server.createConnection("jdbc:teiid:test"); //$NON-NLS-1$ //$NON-NLS-2$
}
@After public void teardown() throws SQLException {
conn.close();
}
@Test public void testCacheHint() throws Exception {
Statement s = conn.createStatement();
s.execute("set showplan on");
ResultSet rs = s.executeQuery("/* cache */ select 1");
assertTrue(rs.next());
s.execute("set noexec on");
rs = s.executeQuery("/* cache */ select 1");
assertTrue(rs.next());
rs = s.executeQuery("select 1");
assertFalse(rs.next());
}
@Test public void testCacheHintWithMaxRows() throws Exception {
Statement s = conn.createStatement();
s.setMaxRows(1);
ResultSet rs = s.executeQuery("/* cache */ select 1 union all select 2");
assertTrue(rs.next());
assertFalse(rs.next());
s.setMaxRows(2);
rs = s.executeQuery("/* cache */ select 1 union all select 2");
assertTrue(rs.next());
assertTrue(rs.next());
}
@Test public void testCacheHintTtl() throws Exception {
Statement s = conn.createStatement();
s.execute("set showplan on");
ResultSet rs = s.executeQuery("/*+ cache(ttl:50) */ select 1");
assertTrue(rs.next());
s.execute("set noexec on");
Thread.sleep(60);
rs = s.executeQuery("/*+ cache(ttl:50) */ select 1");
assertFalse(rs.next());
}
@Test public void testExecutionProperty() throws Exception {
Statement s = conn.createStatement();
s.execute("set showplan on");
s.execute("set resultSetCacheMode true");
ResultSet rs = s.executeQuery("select 1");
assertTrue(rs.next());
s.execute("set noexec on");
rs = s.executeQuery("select 1");
assertTrue(rs.next());
s.execute("set resultSetCacheMode false");
rs = s.executeQuery("select 1");
assertFalse(rs.next());
}
@Test public void testCacheHintWithLargeSQLXML() throws Exception {
Statement s = conn.createStatement();
ResultSet rs = s.executeQuery("/* cache */ WITH t(n) AS ( VALUES (1) UNION ALL SELECT n+1 FROM t WHERE n < 10000 ) SELECT xmlelement(root, xmlagg(xmlelement(val, n))) FROM t");
assertTrue(rs.next());
assertEquals(148907, rs.getString(1).length());
assertFalse(rs.next());
rs.close();
rs = s.executeQuery("/* cache */ WITH t(n) AS ( VALUES (1) UNION ALL SELECT n+1 FROM t WHERE n < 10000 ) SELECT xmlelement(root, xmlagg(xmlelement(val, n))) FROM t");
assertTrue(rs.next());
assertEquals(148907, rs.getString(1).length());
assertFalse(rs.next());
}
@Test public void testScope() throws Exception {
ModelMetaData mmd = new ModelMetaData();
mmd.setName("x");
mmd.addProperty("teiid_rel:determinism", "USER_DETERMINISTIC");
mmd.addSourceMapping("x", "x", null);
mmd.addSourceMetadata("ddl", "create foreign table t (c string); create foreign procedure p () returns table (c string);");
final AtomicBoolean setScope = new AtomicBoolean();
server.addTranslator("x", new ExecutionFactory() {
@Override
public boolean isSourceRequired() {
return false;
}
@Override
public ResultSetExecution createResultSetExecution(
QueryExpression command, final ExecutionContext executionContext,
RuntimeMetadata metadata, Object connection)
throws TranslatorException {
return createProcedureExecution(null, executionContext, metadata, connection);
}
@Override
public ProcedureExecution createProcedureExecution(Call command,
final ExecutionContext executionContext,
RuntimeMetadata metadata, Object connection)
throws TranslatorException {
return new ProcedureExecution() {
boolean returned = false;
@Override
public void execute() throws TranslatorException {
}
@Override
public void close() {
}
@Override
public void cancel() throws TranslatorException {
}
@Override
public List<?> next() throws TranslatorException, DataNotAvailableException {
if (setScope.get()) {
executionContext.setScope(Scope.SESSION); //prevent caching altogether
}
if (returned) {
return null;
}
returned = true;
return Arrays.asList(executionContext.getSession().getSessionId());
}
@Override
public List<?> getOutputParameterValues()
throws TranslatorException {
return null;
}
};
}
});
server.deployVDB("x", mmd);
Connection c = server.getDriver().connect("jdbc:teiid:x;user=alice", null);
Statement s = c.createStatement();
ResultSet rs = s.executeQuery("/* cache */ select * from t");
assertTrue(rs.next());
String sessionid = rs.getString(1);
//should be the same with same user/session
rs = s.executeQuery("/* cache */ select * from t");
assertTrue(rs.next());
assertEquals(sessionid, rs.getString(1));
c.close();
c = server.getDriver().connect("jdbc:teiid:x;user=alice", null);
s = c.createStatement();
rs = s.executeQuery("/* cache */ select * from t");
assertTrue(rs.next());
assertEquals(sessionid, rs.getString(1));
c.close();
//for the final test
setScope.set(true);
//should be different with another user
c = server.getDriver().connect("jdbc:teiid:x;user=bill", null);
s = c.createStatement();
rs = s.executeQuery("/* cache */ select * from t");
assertTrue(rs.next());
String sessionid1 = rs.getString(1);
c.close();
assertNotEquals(sessionid, sessionid1);
c = server.getDriver().connect("jdbc:teiid:x;user=bill", null);
s = c.createStatement();
rs = s.executeQuery("/* cache */ select * from t");
assertTrue(rs.next());
//scope session should prevent reuse
assertNotEquals(sessionid1, rs.getString(1));
setScope.set(false);
rs = s.executeQuery("/* cache */ call p()");
assertTrue(rs.next());
sessionid = rs.getString(1);
c.close();
c = server.getDriver().connect("jdbc:teiid:x;user=alice", null);
s = c.createStatement();
rs = s.executeQuery("/* cache */ call p()");
assertTrue(rs.next());
assertNotEquals(sessionid, rs.getString(1));
c.close();
}
}