/*
* 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.dqp.internal.process;
import static org.junit.Assert.*;
import java.sql.ResultSet;
import java.util.HashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.mockito.Mockito;
import org.teiid.adminapi.DataPolicy;
import org.teiid.adminapi.impl.DataPolicyMetadata;
import org.teiid.api.exception.query.QueryResolverException;
import org.teiid.cache.CacheConfiguration;
import org.teiid.cache.DefaultCacheFactory;
import org.teiid.client.RequestMessage;
import org.teiid.client.RequestMessage.ResultsMode;
import org.teiid.client.RequestMessage.StatementType;
import org.teiid.client.ResultsMessage;
import org.teiid.client.lob.LobChunk;
import org.teiid.client.util.ResultsFuture;
import org.teiid.common.buffer.BufferManagerFactory;
import org.teiid.common.buffer.impl.BufferManagerImpl;
import org.teiid.core.TeiidProcessingException;
import org.teiid.core.types.BlobType;
import org.teiid.dqp.internal.datamgr.ConnectorManagerRepository;
import org.teiid.dqp.internal.datamgr.FakeTransactionService;
import org.teiid.dqp.internal.process.AbstractWorkItem.ThreadState;
import org.teiid.dqp.service.AutoGenDataService;
import org.teiid.dqp.service.FakeBufferService;
import org.teiid.query.optimizer.TestOptimizer;
import org.teiid.query.optimizer.capabilities.BasicSourceCapabilities;
import org.teiid.query.optimizer.capabilities.SourceCapabilities.Capability;
import org.teiid.query.unittest.RealMetadataFactory;
import org.teiid.translator.SourceSystemFunctions;
@SuppressWarnings("nls")
public class TestDQPCore {
private final class LobThread extends Thread {
BlobType bt;
private final RequestMessage reqMsg;
volatile ResultsFuture<LobChunk> chunkFuture;
protected DQPWorkContext workContext;
private LobThread(RequestMessage reqMsg) {
this.reqMsg = reqMsg;
}
@Override
public void run() {
synchronized (this) {
while (workContext == null) {
try {
this.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
workContext.runInContext(new Runnable() {
@Override
public void run() {
try {
chunkFuture = core.requestNextLobChunk(1, reqMsg.getExecutionId(), bt.getReferenceStreamId());
} catch (TeiidProcessingException e) {
e.printStackTrace();
}
}
});
}
}
private DQPCore core;
private DQPConfiguration config;
private AutoGenDataService agds;
@Before public void setUp() throws Exception {
agds = new AutoGenDataService();
DQPWorkContext context = RealMetadataFactory.buildWorkContext(RealMetadataFactory.createTransformationMetadata(RealMetadataFactory.exampleBQTCached().getMetadataStore(), "bqt"));
context.getVDB().getModel("BQT3").setVisible(false); //$NON-NLS-1$
context.getVDB().getModel("VQT").setVisible(false); //$NON-NLS-1$
HashMap<String, DataPolicy> policies = new HashMap<String, DataPolicy>();
policies.put("foo", new DataPolicyMetadata());
context.setPolicies(policies);
ConnectorManagerRepository repo = Mockito.mock(ConnectorManagerRepository.class);
context.getVDB().addAttchment(ConnectorManagerRepository.class, repo);
Mockito.stub(repo.getConnectorManager(Mockito.anyString())).toReturn(agds);
BufferManagerImpl bm = BufferManagerFactory.createBufferManager();
bm.setInlineLobs(false);
FakeBufferService bs = new FakeBufferService(bm, bm);
core = new DQPCore();
core.setBufferManager(bs.getBufferManager());
core.setResultsetCache(new SessionAwareCache<CachedResults>("resultset", new DefaultCacheFactory(new CacheConfiguration()), SessionAwareCache.Type.RESULTSET, 0));
core.setPreparedPlanCache(new SessionAwareCache<PreparedPlan>("preparedplan", new DefaultCacheFactory(new CacheConfiguration()), SessionAwareCache.Type.PREPAREDPLAN, 0));
core.setTransactionService(new FakeTransactionService());
config = new DQPConfiguration();
config.setMaxActivePlans(1);
config.setUserRequestSourceConcurrency(2);
DefaultAuthorizationValidator daa = new DefaultAuthorizationValidator();
daa.setPolicyDecider(new DataRolePolicyDecider());
config.setAuthorizationValidator(daa);
core.start(config);
core.getPrepPlanCache().setModTime(1);
core.getRsCache().setTupleBufferCache(bs.getBufferManager());
}
@After public void tearDown() throws Exception {
DQPWorkContext.setWorkContext(new DQPWorkContext());
core.stop();
}
int id = 0;
public RequestMessage exampleRequestMessage(String sql) {
RequestMessage msg = new RequestMessage(sql);
msg.setCursorType(ResultSet.TYPE_SCROLL_INSENSITIVE);
msg.setFetchSize(10);
msg.setPartialResults(false);
msg.setExecutionId(100);
msg.setExecutionId(id++);
return msg;
}
@Test public void testConfigurationSets() {
assertEquals(1, core.getMaxActivePlans());
assertEquals(2, core.getUserRequestSourceConcurrency());
}
@Test public void testRequest1() throws Exception {
helpExecute("SELECT IntKey FROM BQT1.SmallA", "a"); //$NON-NLS-1$ //$NON-NLS-2$
}
@Test public void testHasRole() throws Exception {
String sql = "SELECT hasRole('foo')"; //$NON-NLS-1$
String userName = "logon"; //$NON-NLS-1$
ResultsMessage rm = helpExecute(sql, userName);
assertTrue((Boolean)rm.getResultsList().get(0).get(0));
}
@Test public void testNotHasRole() throws Exception {
String sql = "SELECT hasRole('bar')"; //$NON-NLS-1$
String userName = "logon"; //$NON-NLS-1$
ResultsMessage rm = helpExecute(sql, userName);
assertFalse((Boolean)rm.getResultsList().get(0).get(0));
}
@Test public void testUser1() throws Exception {
String sql = "SELECT IntKey FROM BQT1.SmallA WHERE user() = 'logon'"; //$NON-NLS-1$
String userName = "logon"; //$NON-NLS-1$
helpExecute(sql, userName);
}
@Test public void testUser2() throws Exception {
String sql = "SELECT IntKey FROM BQT1.SmallA WHERE user() LIKE 'logon'"; //$NON-NLS-1$
String userName = "logon"; //$NON-NLS-1$
helpExecute(sql, userName);
}
@Test public void testUser3() throws Exception {
String sql = "SELECT IntKey FROM BQT1.SmallA WHERE user() IN ('logon3') AND StringKey LIKE '1'"; //$NON-NLS-1$
String userName = "logon3"; //$NON-NLS-1$
helpExecute(sql, userName);
}
@Test public void testUser4() throws Exception {
String sql = "SELECT IntKey FROM BQT1.SmallA WHERE 'logon4' = user() AND StringKey = '1'"; //$NON-NLS-1$
String userName = "logon4"; //$NON-NLS-1$
helpExecute(sql, userName);
}
@Test public void testUser5() throws Exception {
String sql = "SELECT IntKey FROM BQT1.SmallA WHERE user() IS NULL "; //$NON-NLS-1$
String userName = "logon"; //$NON-NLS-1$
helpExecute(sql, userName);
}
@Test public void testUser6() throws Exception {
String sql = "SELECT IntKey FROM BQT1.SmallA WHERE user() = 'logon33' "; //$NON-NLS-1$
String userName = "logon"; //$NON-NLS-1$
helpExecute(sql, userName);
}
@Test public void testUser7() throws Exception {
String sql = "UPDATE BQT1.SmallA SET IntKey = 2 WHERE user() = 'logon' AND StringKey = '1' "; //$NON-NLS-1$
String userName = "logon"; //$NON-NLS-1$
helpExecute(sql, userName);
}
@Test public void testUser8() throws Exception {
String sql = "SELECT user(), StringKey FROM BQT1.SmallA WHERE IntKey = 1 "; //$NON-NLS-1$
String userName = "logon"; //$NON-NLS-1$
helpExecute(sql, userName);
}
@Test public void testUser9() throws Exception {
String sql = "SELECT IntKey FROM BQT1.SmallA WHERE user() = StringKey AND StringKey = '1' "; //$NON-NLS-1$
String userName = "1"; //$NON-NLS-1$
helpExecute(sql, userName);
}
@Test public void testTxnAutoWrap() throws Exception {
String sql = "SELECT * FROM BQT1.SmallA"; //$NON-NLS-1$
helpExecute(sql, "a", 1, true); //$NON-NLS-1$
}
/**
* Ensures that VQT visibility does not affect the view query
*/
@Test public void testViewVisibility() throws Exception {
String sql = "SELECT * FROM VQT.SmallA_2589g"; //$NON-NLS-1$
helpExecute(sql, "a"); //$NON-NLS-1$
}
@Test public void testLimitCompensation() throws Exception {
String sql = "SELECT * FROM VQT.SmallA_2589g LIMIT 1, 1"; //$NON-NLS-1$
BasicSourceCapabilities caps = TestOptimizer.getTypicalCapabilities();
caps.setCapabilitySupport(Capability.ROW_LIMIT, true);
agds.setCaps(caps);
ResultsMessage rm = helpExecute(sql, "a"); //$NON-NLS-1$
//we test for > 0 here because the autogen service doesn't obey the limit
assertTrue(rm.getResultsList().size() > 0);
}
@Test public void testLimitCompensation1() throws Exception {
String sql = "SELECT * FROM VQT.SmallA_2589g LIMIT 1, 1"; //$NON-NLS-1$
ResultsMessage rm = helpExecute(sql, "a"); //$NON-NLS-1$
assertEquals(1, rm.getResultsList().size());
}
/**
* Tests whether an exception result is sent when an exception occurs
* @since 4.3
*/
@Test public void testPlanningException() throws Exception {
String sql = "SELECT IntKey FROM BQT1.BadIdea "; //$NON-NLS-1$
RequestMessage reqMsg = exampleRequestMessage(sql);
Future<ResultsMessage> message = core.executeRequest(reqMsg.getExecutionId(), reqMsg);
try {
message.get(5000, TimeUnit.MILLISECONDS);
} catch (ExecutionException e) {
assertTrue(e.getCause() instanceof QueryResolverException);
}
}
@Ignore("visibility no longer ristricts access")
@Test public void testLookupVisibility() throws Exception {
helpTestVisibilityFails("select lookup('bqt3.smalla', 'intkey', 'stringkey', '?')"); //$NON-NLS-1$
}
@Test public void testCancel() throws Exception {
assertFalse(this.core.cancelRequest(1L));
}
@Test public void testBufferLimit() throws Exception {
//the sql should return 400 rows
String sql = "SELECT A.IntKey FROM BQT1.SmallA as A, BQT1.SmallA as B, (select intkey from BQT1.SmallA limit 4) as C"; //$NON-NLS-1$
String userName = "1"; //$NON-NLS-1$
String sessionid = "1"; //$NON-NLS-1$
RequestMessage reqMsg = exampleRequestMessage(sql);
reqMsg.setCursorType(ResultSet.TYPE_FORWARD_ONLY);
DQPWorkContext.getWorkContext().getSession().setSessionId(sessionid);
DQPWorkContext.getWorkContext().getSession().setUserName(userName);
((BufferManagerImpl)core.getBufferManager()).setProcessorBatchSize(1);
Future<ResultsMessage> message = core.executeRequest(reqMsg.getExecutionId(), reqMsg);
ResultsMessage rm = message.get(500000, TimeUnit.MILLISECONDS);
assertNull(rm.getException());
int rowsPerBatch = 8;
assertEquals(rowsPerBatch, rm.getResultsList().size());
RequestWorkItem item = core.getRequestWorkItem(DQPWorkContext.getWorkContext().getRequestID(reqMsg.getExecutionId()));
message = core.processCursorRequest(reqMsg.getExecutionId(), 9, rowsPerBatch);
rm = message.get(500000, TimeUnit.MILLISECONDS);
assertNull(rm.getException());
assertEquals(rowsPerBatch, rm.getResultsList().size());
//ensure that we are idle
for (int i = 0; i < 10 && item.getThreadState() != ThreadState.IDLE; i++) {
Thread.sleep(100);
}
assertEquals(ThreadState.IDLE, item.getThreadState());
assertTrue(item.resultsBuffer.getManagedRowCount() <= rowsPerBatch*23);
//pull the rest of the results
int start = 17;
while (true) {
item = core.getRequestWorkItem(DQPWorkContext.getWorkContext().getRequestID(reqMsg.getExecutionId()));
message = core.processCursorRequest(reqMsg.getExecutionId(), start, rowsPerBatch);
rm = message.get(5000, TimeUnit.MILLISECONDS);
assertNull(rm.getException());
assertTrue(rowsPerBatch >= rm.getResultsList().size());
start += rm.getResultsList().size();
if (rm.getFinalRow() == rm.getLastRow()) {
break;
}
}
//insensitive should not block
reqMsg.setCursorType(ResultSet.TYPE_SCROLL_INSENSITIVE);
reqMsg.setExecutionId(id++);
message = core.executeRequest(reqMsg.getExecutionId(), reqMsg);
rm = message.get(500000, TimeUnit.MILLISECONDS);
assertNull(rm.getException());
assertEquals(rowsPerBatch, rm.getResultsList().size());
item = core.getRequestWorkItem(DQPWorkContext.getWorkContext().getRequestID(reqMsg.getExecutionId()));
message = core.processCursorRequest(reqMsg.getExecutionId(), 9, rowsPerBatch);
rm = message.get(500000, TimeUnit.MILLISECONDS);
assertNull(rm.getException());
assertEquals(rowsPerBatch, rm.getResultsList().size());
//ensure that we are idle
for (int i = 0; i < 10 && item.getThreadState() != ThreadState.IDLE; i++) {
Thread.sleep(100);
}
assertEquals(ThreadState.IDLE, item.getThreadState());
//should buffer the same as forward only until a further batch is requested
assertTrue(item.resultsBuffer.getManagedRowCount() <= rowsPerBatch*23);
//local should not buffer
reqMsg = exampleRequestMessage(sql);
reqMsg.setCursorType(ResultSet.TYPE_FORWARD_ONLY);
reqMsg.setSync(true);
message = core.executeRequest(reqMsg.getExecutionId(), reqMsg);
rm = message.get(0, TimeUnit.MILLISECONDS);
assertNull(rm.getException());
assertEquals(rowsPerBatch, rm.getResultsList().size());
item = core.getRequestWorkItem(DQPWorkContext.getWorkContext().getRequestID(reqMsg.getExecutionId()));
assertEquals(0, item.resultsBuffer.getManagedRowCount());
assertEquals(8, item.resultsBuffer.getRowCount());
}
@Test public void testBufferReuse() throws Exception {
//the sql should return 100 rows
String sql = "SELECT A.IntKey FROM BQT1.SmallA as A, BQT1.SmallA as B ORDER BY A.IntKey"; //$NON-NLS-1$
String userName = "1"; //$NON-NLS-1$
String sessionid = "1"; //$NON-NLS-1$
RequestMessage reqMsg = exampleRequestMessage(sql);
reqMsg.setCursorType(ResultSet.TYPE_FORWARD_ONLY);
DQPWorkContext.getWorkContext().getSession().setSessionId(sessionid);
DQPWorkContext.getWorkContext().getSession().setUserName(userName);
((BufferManagerImpl)core.getBufferManager()).setProcessorBatchSize(1);
Future<ResultsMessage> message = core.executeRequest(reqMsg.getExecutionId(), reqMsg);
ResultsMessage rm = message.get(500000, TimeUnit.MILLISECONDS);
assertNull(rm.getException());
assertEquals(8, rm.getResultsList().size());
RequestWorkItem item = core.getRequestWorkItem(DQPWorkContext.getWorkContext().getRequestID(reqMsg.getExecutionId()));
assertEquals(100, item.resultsBuffer.getRowCount());
}
@Test public void testFinalRow() throws Exception {
String sql = "SELECT A.IntKey FROM BQT1.SmallA as A"; //$NON-NLS-1$
String userName = "1"; //$NON-NLS-1$
String sessionid = "1"; //$NON-NLS-1$
RequestMessage reqMsg = exampleRequestMessage(sql);
reqMsg.setCursorType(ResultSet.TYPE_FORWARD_ONLY);
DQPWorkContext.getWorkContext().getSession().setSessionId(sessionid);
DQPWorkContext.getWorkContext().getSession().setUserName(userName);
((BufferManagerImpl)core.getBufferManager()).setProcessorBatchSize(10);
Future<ResultsMessage> message = core.executeRequest(reqMsg.getExecutionId(), reqMsg);
ResultsMessage rm = message.get(500000, TimeUnit.MILLISECONDS);
assertNull(rm.getException());
assertEquals(10, rm.getResultsList().size());
RequestWorkItem item = core.getRequestWorkItem(DQPWorkContext.getWorkContext().getRequestID(reqMsg.getExecutionId()));
while(item.isProcessing());
synchronized (item) {
for (int i = 0; i < 100; i++) {
Thread.sleep(10);
}
}
assertEquals(10, item.resultsBuffer.getRowCount());
}
@Test public void testBufferReuse1() throws Exception {
//the sql should return 100 rows
String sql = "SELECT IntKey FROM texttable('1112131415' columns intkey integer width 2 no row delimiter) t " +
"union " +
"SELECT IntKey FROM bqt1.smalla order by intkey"; //$NON-NLS-1$
String userName = "1"; //$NON-NLS-1$
String sessionid = "1"; //$NON-NLS-1$
agds.sleep = 50;
agds.setUseIntCounter(true);
RequestMessage reqMsg = exampleRequestMessage(sql);
reqMsg.setRowLimit(11);
reqMsg.setCursorType(ResultSet.TYPE_FORWARD_ONLY);
DQPWorkContext.getWorkContext().getSession().setSessionId(sessionid);
DQPWorkContext.getWorkContext().getSession().setUserName(userName);
BufferManagerImpl bufferManager = (BufferManagerImpl)core.getBufferManager();
bufferManager.setProcessorBatchSize(20);
Future<ResultsMessage> message = core.executeRequest(reqMsg.getExecutionId(), reqMsg);
ResultsMessage rm = message.get(500000, TimeUnit.MILLISECONDS);
assertNull(rm.getException());
assertEquals(10, rm.getResultsList().size());
message = core.processCursorRequest(reqMsg.getExecutionId(), 6, 5);
rm = message.get(500000, TimeUnit.MILLISECONDS);
assertNull(rm.getException());
assertEquals(5, rm.getResultsList().size());
message = core.processCursorRequest(reqMsg.getExecutionId(), 11, 5);
rm = message.get(500000, TimeUnit.MILLISECONDS);
assertNull(rm.getException());
assertEquals(1, rm.getResultsList().size());
assertEquals(11, rm.getFirstRow());
assertEquals(11, rm.getFinalRow());
}
@Test public void testSourceConcurrency() throws Exception {
//setup default of 2
agds.setSleep(100);
BasicSourceCapabilities bsc = TestOptimizer.getTypicalCapabilities();
bsc.setFunctionSupport(SourceSystemFunctions.CONCAT, true);
agds.setCaps(bsc);
StringBuffer sql = new StringBuffer();
int branches = 20;
for (int i = 0; i < branches; i++) {
if (i > 0) {
sql.append(" union all ");
}
sql.append("select stringkey || " + i + " from bqt1.smalla");
}
//sql.append(" limit 2");
helpExecute(sql.toString(), "a", 1, false);
//there's isn't a hard guarantee that only two requests will get started
assertTrue(agds.getExecuteCount().get() <= 6);
//20 concurrent
core.setUserRequestSourceConcurrency(20);
agds.getExecuteCount().set(0);
helpExecute(sql.toString(), "a", 2, false);
assertTrue(agds.getExecuteCount().get() > 10 && agds.getExecuteCount().get() <= 20);
//serial
core.setUserRequestSourceConcurrency(1);
agds.getExecuteCount().set(0);
helpExecute(sql.toString(), "a", 3, false);
//there's two since 1 is smaller than the expected batch
assertTrue(agds.getExecuteCount().get() <= 2);
}
@Test public void testSourceConcurrencyWithLimitedUnion() throws Exception {
agds.setSleep(100);
helpTestSourceConcurrencyWithLimitedUnion();
}
@Test public void testSourceConcurrencyWithLimitedUnionThreadBound() throws Exception {
agds.setSleep(100);
agds.threadBound = true;
helpTestSourceConcurrencyWithLimitedUnion();
}
@Test public void testSerialThreadBoundClose() throws Exception {
agds.setSleep(100);
agds.threadBound = true;
core.setUserRequestSourceConcurrency(1);
String sql = "SELECT IntKey FROM BQT1.SmallA"; //$NON-NLS-1$
String userName = "logon"; //$NON-NLS-1$
((BufferManagerImpl)core.getBufferManager()).setProcessorBatchSize(1);
RequestMessage reqMsg = exampleRequestMessage(sql);
//execute by don't finish the work
execute(userName, 1, reqMsg);
//make sure the source request is still closed
assertEquals(1, agds.getCloseCount().get());
}
@Test(expected=TeiidProcessingException.class) public void testThreadBoundException() throws Exception {
agds.threadBound = true;
agds.throwExceptionOnExecute = true;
String sql = "SELECT IntKey FROM BQT1.SmallA"; //$NON-NLS-1$
String userName = "logon"; //$NON-NLS-1$
helpExecute(sql, userName);
}
private void helpTestSourceConcurrencyWithLimitedUnion() throws Exception {
BasicSourceCapabilities bsc = TestOptimizer.getTypicalCapabilities();
bsc.setFunctionSupport(SourceSystemFunctions.CONCAT, true);
agds.setCaps(bsc);
StringBuffer sql = new StringBuffer();
int branches = 20;
for (int i = 0; i < branches; i++) {
if (i > 0) {
sql.append(" union all ");
}
sql.append("select stringkey || " + i + " from bqt1.smalla");
}
sql.append(" limit 11");
helpExecute(sql.toString(), "a", 1, false);
assertTrue(String.valueOf(agds.getExecuteCount()), agds.getExecuteCount().get() <= 2);
//20 concurrent max, but we'll use 6
core.setUserRequestSourceConcurrency(20);
agds.getExecuteCount().set(0);
helpExecute(sql.toString(), "a", 2, false);
assertTrue(String.valueOf(agds.getExecuteCount()), agds.getExecuteCount().get() <= 6);
//serial
core.setUserRequestSourceConcurrency(1);
agds.getExecuteCount().set(0);
helpExecute(sql.toString(), "a", 3, false);
assertTrue(agds.getExecuteCount().get() <= 2);
//ensure that we'll still consult all sources even if the limit is not met
core.setUserRequestSourceConcurrency(4);
agds.getExecuteCount().set(0);
agds.setRows(0);
helpExecute(sql.toString(), "a", 4, false);
assertEquals(20, agds.getExecuteCount().get());
}
@Test public void testUsingFinalBuffer() throws Exception {
String sql = "select intkey from bqt1.smalla order by intkey";
((BufferManagerImpl)core.getBufferManager()).setProcessorBatchSize(2);
agds.sleep = 50;
RequestMessage reqMsg = exampleRequestMessage(sql);
Future<ResultsMessage> message = core.executeRequest(reqMsg.getExecutionId(), reqMsg);
ResultsMessage rm = message.get(500000, TimeUnit.MILLISECONDS);
assertNull(rm.getException());
assertEquals(10, rm.getResultsList().size());
message = core.processCursorRequest(reqMsg.getExecutionId(), 3, 2);
rm = message.get(500000, TimeUnit.MILLISECONDS);
assertNull(rm.getException());
assertEquals(2, rm.getResultsList().size());
}
@Test public void testPreparedPlanInvalidation() throws Exception {
helpTestPlanInvalidation("select * from #temp a, #temp b limit 10");
assertEquals(2, this.core.getPrepPlanCache().getCacheHitCount());
}
@Test public void testPreparedPlanSimpleNoInvalidation() throws Exception {
helpTestPlanInvalidation("select * from #temp");
assertEquals(3, this.core.getPrepPlanCache().getCacheHitCount());
}
private void helpTestPlanInvalidation(String query) throws InterruptedException,
ExecutionException, TimeoutException, TeiidProcessingException {
String sql = "insert into #temp select * FROM vqt.SmallB"; //$NON-NLS-1$
String userName = "1"; //$NON-NLS-1$
int sessionid = 1; //$NON-NLS-1$
RequestMessage reqMsg = exampleRequestMessage(sql);
ResultsMessage rm = execute(userName, sessionid, reqMsg);
assertEquals(1, rm.getResultsList().size()); //$NON-NLS-1$
sql = query;
reqMsg = exampleRequestMessage(sql);
reqMsg.setStatementType(StatementType.PREPARED);
rm = execute(userName, sessionid, reqMsg);
assertEquals(10, rm.getResultsList().size()); //$NON-NLS-1$
sql = query;
reqMsg = exampleRequestMessage(sql);
reqMsg.setStatementType(StatementType.PREPARED);
rm = execute(userName, sessionid, reqMsg);
assertEquals(10, rm.getResultsList().size()); //$NON-NLS-1$
assertEquals(1, this.core.getPrepPlanCache().getCacheHitCount());
Thread.sleep(100);
//perform a minor update, we should still use the cache
sql = "delete from #temp where a12345 = '11'"; //$NON-NLS-1$
reqMsg = exampleRequestMessage(sql);
rm = execute(userName, sessionid, reqMsg);
assertEquals(1, rm.getResultsList().size()); //$NON-NLS-1$
sql = query;
reqMsg = exampleRequestMessage(sql);
reqMsg.setStatementType(StatementType.PREPARED);
rm = execute(userName, sessionid, reqMsg);
assertEquals(10, rm.getResultsList().size()); //$NON-NLS-1$
assertEquals(2, this.core.getPrepPlanCache().getCacheHitCount());
//perform a major update, it might purge the plan
sql = "delete from #temp"; //$NON-NLS-1$
reqMsg = exampleRequestMessage(sql);
rm = execute(userName, sessionid, reqMsg);
assertEquals(1, rm.getResultsList().size()); //$NON-NLS-1$
sql = query;
reqMsg = exampleRequestMessage(sql);
reqMsg.setStatementType(StatementType.PREPARED);
rm = execute(userName, sessionid, reqMsg);
assertEquals(0, rm.getResultsList().size()); //$NON-NLS-1$
}
@Test public void testRsCacheInvalidation() throws Exception {
String sql = "select * FROM vqt.SmallB"; //$NON-NLS-1$
String userName = "1"; //$NON-NLS-1$
int sessionid = 1; //$NON-NLS-1$
RequestMessage reqMsg = exampleRequestMessage(sql);
reqMsg.setUseResultSetCache(true);
ResultsMessage rm = execute(userName, sessionid, reqMsg);
assertEquals(10, rm.getResultsList().size()); //$NON-NLS-1$
assertEquals(0, this.core.getRsCache().getCacheHitCount());
sql = "select * FROM vqt.SmallB"; //$NON-NLS-1$
reqMsg = exampleRequestMessage(sql);
reqMsg.setUseResultSetCache(true);
rm = execute(userName, sessionid, reqMsg);
assertEquals(10, rm.getResultsList().size()); //$NON-NLS-1$
assertEquals(1, this.core.getRsCache().getCacheHitCount());
Thread.sleep(100);
sql = "delete from bqt1.smalla"; //$NON-NLS-1$
reqMsg = exampleRequestMessage(sql);
rm = execute(userName, sessionid, reqMsg);
assertEquals(1, rm.getResultsList().size()); //$NON-NLS-1$
sql = "select * FROM vqt.SmallB"; //$NON-NLS-1$
reqMsg = exampleRequestMessage(sql);
reqMsg.setUseResultSetCache(true);
rm = execute(userName, sessionid, reqMsg);
assertEquals(10, rm.getResultsList().size()); //$NON-NLS-1$
assertEquals(1, this.core.getRsCache().getCacheHitCount());
}
@Test public void testLobConcurrency() throws Exception {
RequestMessage reqMsg = exampleRequestMessage("select to_bytes(stringkey, 'utf-8') FROM BQT1.SmallA");
reqMsg.setTxnAutoWrapMode(RequestMessage.TXN_WRAP_OFF);
agds.setSleep(100);
ResultsFuture<ResultsMessage> message = core.executeRequest(reqMsg.getExecutionId(), reqMsg);
final LobThread t = new LobThread(reqMsg);
t.start();
message.addCompletionListener(new ResultsFuture.CompletionListener<ResultsMessage>() {
@Override
public void onCompletion(ResultsFuture<ResultsMessage> future) {
try {
final BlobType bt = (BlobType)future.get().getResultsList().get(0).get(0);
synchronized (t) {
t.bt = bt;
t.workContext = DQPWorkContext.getWorkContext();
t.notify();
}
Thread.sleep(100); //give the Thread a chance to run
} catch (Exception e) {
t.interrupt();
throw new RuntimeException(e);
}
}
});
message.get();
t.join();
assertNotNull(t.chunkFuture.get().getBytes());
}
@Test public void testServerTimeout() throws Exception {
RequestMessage reqMsg = exampleRequestMessage("select to_bytes(stringkey, 'utf-8') FROM BQT1.SmallA");
reqMsg.setTxnAutoWrapMode(RequestMessage.TXN_WRAP_OFF);
agds.setSleep(100);
this.config.setQueryTimeout(1);
ResultsMessage rm = execute("A", 1, reqMsg);
assertNotNull(rm.getException());
}
@Test public void testLongRunningQuery() throws Exception {
RequestMessage reqMsg = exampleRequestMessage("select * FROM BQT1.SmallA");
execute("A", 1, reqMsg);
this.config.setQueryThresholdInMilli(5000);
assertEquals(1, this.core.getRequests().size());
assertEquals(0, this.core.getLongRunningRequests().size());
this.config.setQueryThresholdInMilli(10);
Thread.sleep(20);
assertEquals(1, this.core.getLongRunningRequests().size());
}
@Test public void testDataAvailable() throws Exception {
agds.dataNotAvailable = -1;
agds.dataAvailable = true;
RequestMessage reqMsg = exampleRequestMessage("select * FROM BQT1.SmallA");
ResultsMessage results = execute("A", 1, reqMsg);
if (results.getException() != null) {
throw results.getException();
}
}
@Test public void testXmlTableStreamingWithLimit() throws Exception {
String sql = "select * from xmltable('/a/b' passing xmlparse(document '<a x=''1''><b>foo</b><b>bar</b><b>zed</b></a>') columns y string path '.') as x limit 2"; //$NON-NLS-1$
ResultsMessage rm = execute("A", 1, exampleRequestMessage(sql));
assertNull(rm.getException());
assertEquals(2, rm.getResultsList().size());
}
/**
* Ensure that the row limit is not misapplied.
* Note that it still could be applied in this example, but the
* resultset only returns a single row
*/
@Test public void testProcedureMaxRows() throws Exception {
String sql = "{? = call TEIIDSP9(1, ?)}"; //$NON-NLS-1$
RequestMessage request = exampleRequestMessage(sql);
request.setRowLimit(1);
request.setStatementType(StatementType.CALLABLE);
ResultsMessage rm = execute("A", 1, request);
assertNull(rm.getException());
assertEquals(2, rm.getResultsList().size());
}
@Test public void testProcedureUpdateCount() throws Exception {
String sql = "{? = call TEIIDSP8(1)}"; //$NON-NLS-1$
RequestMessage request = exampleRequestMessage(sql);
request.setResultsMode(ResultsMode.UPDATECOUNT);
request.setStatementType(StatementType.CALLABLE);
ResultsMessage rm = execute("A", 1, request);
assertNull(rm.getException());
assertEquals(1, rm.getResultsList().size());
}
public void helpTestVisibilityFails(String sql) throws Exception {
RequestMessage reqMsg = exampleRequestMessage(sql);
reqMsg.setTxnAutoWrapMode(RequestMessage.TXN_WRAP_OFF);
Future<ResultsMessage> message = core.executeRequest(reqMsg.getExecutionId(), reqMsg);
ResultsMessage results = message.get(5000, TimeUnit.MILLISECONDS);
assertEquals("[QueryValidatorException]Group does not exist: BQT3.SmallA", results.getException().toString()); //$NON-NLS-1$
}
///////////////////////////Helper method///////////////////////////////////
private ResultsMessage helpExecute(String sql, String userName) throws Exception {
return helpExecute(sql, userName, 1, false);
}
private ResultsMessage helpExecute(String sql, String userName, int sessionid, boolean txnAutoWrap) throws Exception {
RequestMessage reqMsg = exampleRequestMessage(sql);
if (txnAutoWrap) {
reqMsg.setTxnAutoWrapMode(RequestMessage.TXN_WRAP_ON);
}
ResultsMessage results = execute(userName, sessionid, reqMsg);
core.terminateSession(String.valueOf(sessionid));
assertNull(core.getClientState(String.valueOf(sessionid), false));
if (results.getException() != null) {
throw results.getException();
}
return results;
}
private ResultsMessage execute(String userName, int sessionid, RequestMessage reqMsg)
throws InterruptedException, ExecutionException, TimeoutException, TeiidProcessingException {
DQPWorkContext.getWorkContext().getSession().setSessionId(String.valueOf(sessionid));
DQPWorkContext.getWorkContext().getSession().setUserName(userName);
Future<ResultsMessage> message = core.executeRequest(reqMsg.getExecutionId(), reqMsg);
assertNotNull(core.getClientState(String.valueOf(sessionid), false));
ResultsMessage results = message.get(500000, TimeUnit.MILLISECONDS);
return results;
}
}