/*
***************************************************************************************
* Copyright (C) 2006 EsperTech, Inc. All rights reserved. *
* http://www.espertech.com/esper *
* http://www.espertech.com *
* ---------------------------------------------------------------------------------- *
* The software in this package is published under the terms of the GPL license *
* a copy of which has been included with this distribution in the license.txt file. *
***************************************************************************************
*/
package com.espertech.esper.regression.nwtable;
import com.espertech.esper.client.*;
import com.espertech.esper.client.scopetest.EPAssertionUtil;
import com.espertech.esper.client.scopetest.SupportUpdateListener;
import com.espertech.esper.epl.join.util.QueryPlanIndexDescSubquery;
import com.espertech.esper.metrics.instrumentation.InstrumentationHelper;
import com.espertech.esper.supportregression.bean.*;
import com.espertech.esper.supportregression.client.SupportConfigFactory;
import com.espertech.esper.supportregression.epl.SupportQueryPlanIndexHook;
import com.espertech.esper.supportregression.util.IndexAssertion;
import com.espertech.esper.supportregression.util.IndexAssertionEventSend;
import com.espertech.esper.supportregression.util.IndexBackingTableInfo;
import junit.framework.TestCase;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class TestInfraSubqCorrelIndex extends TestCase implements IndexBackingTableInfo
{
private final static Logger log = LoggerFactory.getLogger(TestInfraSubqCorrelIndex.class);
private EPServiceProvider epService;
private EPRuntime epRuntime;
private SupportUpdateListener listenerStmtOne;
public void setUp()
{
Configuration config = SupportConfigFactory.getConfiguration();
config.getEngineDefaults().getLogging().setEnableQueryPlan(true);
epService = EPServiceProviderManager.getDefaultProvider(config);
epService.initialize();
if (InstrumentationHelper.ENABLED) { InstrumentationHelper.startTest(epService, this.getClass(), getName());}
epRuntime = epService.getEPRuntime();
epService.getEPAdministrator().getConfiguration().addEventType("SupportBean", SupportBean.class);
epService.getEPAdministrator().getConfiguration().addEventType("ABean", SupportBean_S0.class);
epService.getEPAdministrator().getConfiguration().addEventType("SB2", SupportBeanTwo.class);
listenerStmtOne = new SupportUpdateListener();
SupportQueryPlanIndexHook.reset();
}
protected void tearDown() throws Exception {
if (InstrumentationHelper.ENABLED) { InstrumentationHelper.endTest();}
listenerStmtOne = null;
epRuntime = null;
}
public void testNoShare() {
// named window tests
runAssertion(true, false, false, false, false); // testNoShare
runAssertion(true, false, false, false, true); // testNoShareSetnoindex
runAssertion(true, false, false, true, false); // testNoShareCreate
runAssertion(true, true, false, false, false); // testShare
runAssertion(true, true, false, true, false); // testShareCreate
runAssertion(true, true, false, true, true); // testShareCreateSetnoindex
runAssertion(true, true, true, false, false); // testDisableShare
runAssertion(true, true, true, true, false); // testDisableShareCreate
// table tests
runAssertion(false, false, false, false, false); // table no-index
runAssertion(false, false, false, true, false); // table yes-index
}
public void testMultipleIndexHints() {
epService.getEPAdministrator().getConfiguration().addEventType("SSB1", SupportSimpleBeanOne.class);
epService.getEPAdministrator().getConfiguration().addEventType("SSB2", SupportSimpleBeanTwo.class);
runAssertionMultipleIndexHints(true);
runAssertionMultipleIndexHints(false);
}
public void testIndexShareIndexChoice() {
epService.getEPAdministrator().getConfiguration().addEventType("SSB1", SupportSimpleBeanOne.class);
epService.getEPAdministrator().getConfiguration().addEventType("SSB2", SupportSimpleBeanTwo.class);
runAssertionIndexShareIndexChoice(true);
runAssertionIndexShareIndexChoice(false);
}
public void testNoIndexShareIndexChoice() {
epService.getEPAdministrator().getConfiguration().addEventType("SSB1", SupportSimpleBeanOne.class);
epService.getEPAdministrator().getConfiguration().addEventType("SSB2", SupportSimpleBeanTwo.class);
runAssertionNoIndexShareIndexChoice(true);
runAssertionNoIndexShareIndexChoice(false);
}
public void runAssertionNoIndexShareIndexChoice(boolean namedWindow) {
String backingUniqueS1 = "unique hash={s1(string)} btree={} advanced={}";
Object[] preloadedEventsOne = new Object[] {new SupportSimpleBeanOne("E1", 10, 11, 12), new SupportSimpleBeanOne("E2", 20, 21, 22)};
IndexAssertionEventSend eventSendAssertion = new IndexAssertionEventSend() {
public void run() {
String[] fields = "s2,ssb1[0].s1,ssb1[0].i1".split(",");
epRuntime.sendEvent(new SupportSimpleBeanTwo("E2", 50, 21, 22));
EPAssertionUtil.assertProps(listenerStmtOne.assertOneGetNewAndReset(), fields, new Object[]{"E2", "E2", 20});
epRuntime.sendEvent(new SupportSimpleBeanTwo("E1", 60, 11, 12));
EPAssertionUtil.assertProps(listenerStmtOne.assertOneGetNewAndReset(), fields, new Object[] {"E1", "E1", 10});
}
};
IndexAssertionEventSend noAssertion = new IndexAssertionEventSend() {
public void run() {
}
};
// unique-s1
assertIndexChoice(namedWindow, false, new String[0], preloadedEventsOne, "std:unique(s1)",
new IndexAssertion[] {
new IndexAssertion(null, "s1 = ssb2.s2", namedWindow ? null : "MyInfra", namedWindow ? BACKING_SINGLE_UNIQUE : backingUniqueS1, eventSendAssertion),
new IndexAssertion(null, "s1 = ssb2.s2 and l1 = ssb2.l2", namedWindow ? null : "MyInfra", namedWindow ? BACKING_SINGLE_UNIQUE : backingUniqueS1, eventSendAssertion),
new IndexAssertion(null, "i1 between 1 and 10", null, namedWindow ? BACKING_SORTED : null, noAssertion),
new IndexAssertion(null, "l1 = ssb2.l2", null, namedWindow ? BACKING_SINGLE_DUPS : null, eventSendAssertion),
});
// unique-s1+i1
if (namedWindow) {
assertIndexChoice(namedWindow, false, new String[0], preloadedEventsOne, "std:unique(s1, d1)",
new IndexAssertion[] {
new IndexAssertion(null, "s1 = ssb2.s2", null, BACKING_SINGLE_DUPS, eventSendAssertion),
new IndexAssertion(null, "s1 = ssb2.s2 and l1 = ssb2.l2", null, BACKING_MULTI_DUPS, eventSendAssertion),
new IndexAssertion(null, "s1 = ssb2.s2 and d1 = ssb2.d2", null, BACKING_MULTI_UNIQUE, eventSendAssertion),
new IndexAssertion(null, "s1 = ssb2.s2 and l1 = ssb2.l2 and d1 = ssb2.d2", null, BACKING_MULTI_UNIQUE, eventSendAssertion),
new IndexAssertion(null, "d1 = ssb2.d2 and s1 = ssb2.s2 and l1 = ssb2.l2", null, BACKING_MULTI_UNIQUE, eventSendAssertion),
new IndexAssertion(null, "l1 = ssb2.l2 and s1 = ssb2.s2 and d1 = ssb2.d2", null, BACKING_MULTI_UNIQUE, eventSendAssertion),
});
}
}
private void runAssertionIndexShareIndexChoice(boolean namedWindow) {
String backingUniqueS1 = "unique hash={s1(string)} btree={} advanced={}";
String backingUniqueS1L1 = "unique hash={s1(string),l1(long)} btree={} advanced={}";
String backingUniqueS1D1 = "unique hash={s1(string),d1(double)} btree={} advanced={}";
String backingNonUniqueS1 = "non-unique hash={s1(string)} btree={} advanced={}";
String backingNonUniqueD1 = "non-unique hash={d1(double)} btree={} advanced={}";
String backingBtreeI1 = "non-unique hash={} btree={i1(int)} advanced={}";
String backingBtreeD1 = "non-unique hash={} btree={d1(double)} advanced={}";
String primaryIndexTable = namedWindow ? null : "MyInfra";
Object[] preloadedEventsOne = new Object[] {new SupportSimpleBeanOne("E1", 10, 11, 12), new SupportSimpleBeanOne("E2", 20, 21, 22)};
IndexAssertionEventSend eventSendAssertion = new IndexAssertionEventSend() {
public void run() {
String[] fields = "s2,ssb1[0].s1,ssb1[0].i1".split(",");
epRuntime.sendEvent(new SupportSimpleBeanTwo("E2", 50, 21, 22));
EPAssertionUtil.assertProps(listenerStmtOne.assertOneGetNewAndReset(), fields, new Object[]{"E2", "E2", 20});
epRuntime.sendEvent(new SupportSimpleBeanTwo("E1", 60, 11, 12));
EPAssertionUtil.assertProps(listenerStmtOne.assertOneGetNewAndReset(), fields, new Object[] {"E1", "E1", 10});
}
};
// no index one field (essentially duplicated since declared std:unique)
String[] noindexes = new String[] {};
assertIndexChoice(namedWindow, true, noindexes, preloadedEventsOne, "std:unique(s1)",
new IndexAssertion[] {
new IndexAssertion(null, "s1 = ssb2.s2", primaryIndexTable, backingUniqueS1, eventSendAssertion),
new IndexAssertion(null, "s1 = ssb2.s2 and l1 = ssb2.l2", primaryIndexTable, backingUniqueS1, eventSendAssertion),
new IndexAssertion("@Hint('index(One)')", "s1 = ssb2.s2 and l1 = ssb2.l2", primaryIndexTable, backingUniqueS1, eventSendAssertion),
});
// single index one field (essentially duplicated since declared std:unique)
if (namedWindow) {
String[] indexOneField = new String[] {"create unique index One on MyInfra (s1)"};
assertIndexChoice(namedWindow, true, indexOneField, preloadedEventsOne, "std:unique(s1)",
new IndexAssertion[] {
new IndexAssertion(null, "s1 = ssb2.s2", "One", backingUniqueS1, eventSendAssertion),
new IndexAssertion(null, "s1 = ssb2.s2 and l1 = ssb2.l2", "One", backingUniqueS1, eventSendAssertion),
new IndexAssertion("@Hint('index(One)')", "s1 = ssb2.s2 and l1 = ssb2.l2", "One", backingUniqueS1, eventSendAssertion),
});
}
// single index two field
String[] indexTwoField = new String[] {"create unique index One on MyInfra (s1, l1)"};
assertIndexChoice(namedWindow, true, indexTwoField, preloadedEventsOne, "std:unique(s1)",
new IndexAssertion[] {
new IndexAssertion(null, "s1 = ssb2.s2", primaryIndexTable, backingUniqueS1, eventSendAssertion),
new IndexAssertion(null, "s1 = ssb2.s2 and l1 = ssb2.l2", "One", backingUniqueS1L1, eventSendAssertion),
});
// two index one unique with std:unique(s1)
String[] indexSetTwo = new String[] {
"create index One on MyInfra (s1)",
"create unique index Two on MyInfra (s1, d1)"};
assertIndexChoice(namedWindow, true, indexSetTwo, preloadedEventsOne, "std:unique(s1)",
new IndexAssertion[] {
new IndexAssertion(null, "d1 = ssb2.d2", null, namedWindow ? backingNonUniqueD1 : null, eventSendAssertion),
new IndexAssertion(null, "s1 = ssb2.s2", namedWindow ? "One" : "MyInfra", namedWindow ? backingNonUniqueS1 : backingUniqueS1, eventSendAssertion),
new IndexAssertion(null, "s1 = ssb2.s2 and l1 = ssb2.l2", namedWindow ? "One" : "MyInfra", namedWindow ? backingNonUniqueS1 : backingUniqueS1, eventSendAssertion),
new IndexAssertion("@Hint('index(One)')", "s1 = ssb2.s2 and l1 = ssb2.l2", "One", backingNonUniqueS1, eventSendAssertion),
new IndexAssertion("@Hint('index(Two,One)')", "s1 = ssb2.s2 and l1 = ssb2.l2", "One", backingNonUniqueS1, eventSendAssertion),
new IndexAssertion("@Hint('index(Two,bust)')", "s1 = ssb2.s2 and l1 = ssb2.l2"), // busted
new IndexAssertion("@Hint('index(explicit,bust)')", "s1 = ssb2.s2 and l1 = ssb2.l2", namedWindow ? "One" : "MyInfra", namedWindow ? backingNonUniqueS1 : backingUniqueS1, eventSendAssertion),
new IndexAssertion(null, "s1 = ssb2.s2 and d1 = ssb2.d2 and l1 = ssb2.l2", namedWindow ? "Two" : "MyInfra", namedWindow ? backingUniqueS1D1 : backingUniqueS1, eventSendAssertion),
new IndexAssertion("@Hint('index(explicit,bust)')", "d1 = ssb2.d2 and l1 = ssb2.l2") // busted
});
// two index one unique with keep-all
assertIndexChoice(namedWindow, true, indexSetTwo, preloadedEventsOne, "win:keepall()",
new IndexAssertion[] {
new IndexAssertion(null, "d1 = ssb2.d2", null, namedWindow ? backingNonUniqueD1 : null, eventSendAssertion),
new IndexAssertion(null, "s1 = ssb2.s2", namedWindow ? "One" : "MyInfra", namedWindow ? backingNonUniqueS1 : backingUniqueS1, eventSendAssertion),
new IndexAssertion(null, "s1 = ssb2.s2 and l1 = ssb2.l2", namedWindow ? "One" : "MyInfra", namedWindow ? backingNonUniqueS1 : backingUniqueS1, eventSendAssertion),
new IndexAssertion("@Hint('index(One)')", "s1 = ssb2.s2 and l1 = ssb2.l2", "One", backingNonUniqueS1, eventSendAssertion),
new IndexAssertion("@Hint('index(Two,One)')", "s1 = ssb2.s2 and l1 = ssb2.l2", "One", backingNonUniqueS1, eventSendAssertion),
new IndexAssertion("@Hint('index(Two,bust)')", "s1 = ssb2.s2 and l1 = ssb2.l2"), // busted
new IndexAssertion("@Hint('index(explicit,bust)')", "s1 = ssb2.s2 and l1 = ssb2.l2", namedWindow ? "One" : "MyInfra", namedWindow ? backingNonUniqueS1 : backingUniqueS1, eventSendAssertion),
new IndexAssertion(null, "s1 = ssb2.s2 and d1 = ssb2.d2 and l1 = ssb2.l2", namedWindow ? "Two" : "MyInfra", namedWindow ? backingUniqueS1D1 : backingUniqueS1, eventSendAssertion),
new IndexAssertion("@Hint('index(explicit,bust)')", "d1 = ssb2.d2 and l1 = ssb2.l2") // busted
});
// range
IndexAssertionEventSend noAssertion = new IndexAssertionEventSend() {
public void run() {
}
};
String[] indexSetThree = new String[] {
"create index One on MyInfra (i1 btree)",
"create index Two on MyInfra (d1 btree)"};
assertIndexChoice(namedWindow, true, indexSetThree, preloadedEventsOne, "std:unique(s1)",
new IndexAssertion[] {
new IndexAssertion(null, "i1 between 1 and 10", "One", backingBtreeI1, noAssertion),
new IndexAssertion(null, "d1 between 1 and 10", "Two", backingBtreeD1, noAssertion),
new IndexAssertion("@Hint('index(One, bust)')", "d1 between 1 and 10"), // busted
});
epService.getEPAdministrator().destroyAllStatements();
epService.getEPAdministrator().getConfiguration().removeEventType("MyInfra", false);
}
private void runAssertionMultipleIndexHints(boolean namedWindow) {
String eplCreate = namedWindow ?
"@Hint('enable_window_subquery_indexshare') create window MyInfra#keepall as select * from SSB1" :
"create table MyInfra(s1 String primary key, i1 int primary key, d1 double primary key, l1 long primary key)";
epService.getEPAdministrator().createEPL(eplCreate);
epService.getEPAdministrator().createEPL("create unique index I1 on MyInfra (s1)");
epService.getEPAdministrator().createEPL("create unique index I2 on MyInfra (i1)");
epService.getEPAdministrator().createEPL(INDEX_CALLBACK_HOOK +
"@Hint('index(subquery(1), I1, bust)')\n" +
"@Hint('index(subquery(0), I2, bust)')\n" +
"select " +
"(select * from MyInfra where s1 = ssb2.s2 and i1 = ssb2.i2) as sub1," +
"(select * from MyInfra where i1 = ssb2.i2 and s1 = ssb2.s2) as sub2 " +
"from SSB2 ssb2");
List<QueryPlanIndexDescSubquery> subqueries = SupportQueryPlanIndexHook.getAndResetSubqueries();
Collections.sort(subqueries, new Comparator<QueryPlanIndexDescSubquery>() {
public int compare(QueryPlanIndexDescSubquery o1, QueryPlanIndexDescSubquery o2) {
return o1.getTables()[0].getIndexName().compareTo(o2.getTables()[0].getIndexName());
}
});
SupportQueryPlanIndexHook.assertSubquery(subqueries.get(0), 1, "I1", "unique hash={s1(string)} btree={} advanced={}");
SupportQueryPlanIndexHook.assertSubquery(subqueries.get(1), 0, "I2", "unique hash={i1(int)} btree={} advanced={}");
epService.getEPAdministrator().destroyAllStatements();
epService.getEPAdministrator().getConfiguration().removeEventType("MyInfra", false);
}
private void assertIndexChoice(boolean namedWindow, boolean indexShare, String[] indexes, Object[] preloadedEvents, String datawindow,
IndexAssertion[] assertions) {
String epl = namedWindow ?
"create window MyInfra." + datawindow + " as select * from SSB1" :
"create table MyInfra(s1 string primary key, i1 int, d1 double, l1 long)";
if (indexShare) {
epl = "@Hint('enable_window_subquery_indexshare') " + epl;
}
epService.getEPAdministrator().createEPL(epl);
epService.getEPAdministrator().createEPL("insert into MyInfra select * from SSB1");
for (String index : indexes) {
epService.getEPAdministrator().createEPL(index);
}
for (Object event : preloadedEvents) {
epService.getEPRuntime().sendEvent(event);
}
int count = 0;
for (IndexAssertion assertion : assertions) {
log.info("======= Testing #" + count++);
String consumeEpl = INDEX_CALLBACK_HOOK +
(assertion.getHint() == null ? "" : assertion.getHint()) + "select *, " +
"(select * from MyInfra where " + assertion.getWhereClause() + ") @eventbean as ssb1 from SSB2 as ssb2";
EPStatement consumeStmt = null;
try {
consumeStmt = epService.getEPAdministrator().createEPL(consumeEpl);
}
catch (EPStatementException ex) {
if (assertion.getEventSendAssertion() == null) {
// no assertion, expected
assertTrue(ex.getMessage().contains("index hint busted"));
continue;
}
throw new RuntimeException("Unexpected statement exception: " + ex.getMessage(), ex);
}
// assert index and access
SupportQueryPlanIndexHook.assertSubqueryBackingAndReset(0, assertion.getExpectedIndexName(), assertion.getIndexBackingClass());
consumeStmt.addListener(listenerStmtOne);
assertion.getEventSendAssertion().run();
consumeStmt.destroy();
}
epService.getEPAdministrator().destroyAllStatements();
epService.getEPAdministrator().getConfiguration().removeEventType("MyInfra", false);
}
private void runAssertion(boolean namedWindow, boolean enableIndexShareCreate, boolean disableIndexShareConsumer, boolean createExplicitIndex, boolean setNoindex) {
String createEpl = namedWindow ?
"create window MyInfra#unique(theString) as (theString string, intPrimitive int)" :
"create table MyInfra(theString string primary key, intPrimitive int)";
if (enableIndexShareCreate) {
createEpl = "@Hint('enable_window_subquery_indexshare') " + createEpl;
}
epService.getEPAdministrator().createEPL(createEpl);
epService.getEPAdministrator().createEPL("insert into MyInfra select theString, intPrimitive from SupportBean");
EPStatement stmtIndex = null;
if (createExplicitIndex) {
stmtIndex = epService.getEPAdministrator().createEPL("create index MyIndex on MyInfra (theString)");
}
String consumeEpl = "select status.*, (select * from MyInfra where theString = ABean.p00) @eventbean as details from ABean as status";
if (disableIndexShareConsumer) {
consumeEpl = "@Hint('disable_window_subquery_indexshare') " + consumeEpl;
}
if (setNoindex) {
consumeEpl = "@Hint('set_noindex') " + consumeEpl;
}
EPStatement consumeStmt = epService.getEPAdministrator().createEPL(consumeEpl);
consumeStmt.addListener(listenerStmtOne);
String[] fields = "id,details[0].theString,details[0].intPrimitive".split(",");
epRuntime.sendEvent(new SupportBean("E1", 10));
epRuntime.sendEvent(new SupportBean("E2", 20));
epRuntime.sendEvent(new SupportBean("E3", 30));
epRuntime.sendEvent(new SupportBean_S0(1, "E1"));
EPAssertionUtil.assertProps(listenerStmtOne.assertOneGetNewAndReset(), fields, new Object[]{1, "E1", 10});
epRuntime.sendEvent(new SupportBean_S0(2, "E2"));
EPAssertionUtil.assertProps(listenerStmtOne.assertOneGetNewAndReset(), fields, new Object[]{2, "E2", 20});
// test late start
consumeStmt.destroy();
consumeStmt = epService.getEPAdministrator().createEPL(consumeEpl);
consumeStmt.addListener(listenerStmtOne);
epRuntime.sendEvent(new SupportBean_S0(1, "E1"));
EPAssertionUtil.assertProps(listenerStmtOne.assertOneGetNewAndReset(), fields, new Object[]{1, "E1", 10});
epRuntime.sendEvent(new SupportBean_S0(2, "E2"));
EPAssertionUtil.assertProps(listenerStmtOne.assertOneGetNewAndReset(), fields, new Object[]{2, "E2", 20});
if (stmtIndex != null) {
stmtIndex.destroy();
}
consumeStmt.destroy();
epService.getEPAdministrator().destroyAllStatements();
epService.getEPAdministrator().getConfiguration().removeEventType("MyInfra", false);
}
}