/*
* *************************************************************************************
* Copyright (C) 2008 EsperTech, Inc. All rights reserved. *
* http://esper.codehaus.org *
* 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.epl;
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.support.bean.*;
import com.espertech.esper.support.client.SupportConfigFactory;
import com.espertech.esper.support.epl.SupportQueryPlanIndexHook;
import com.espertech.esper.support.util.IndexAssertion;
import com.espertech.esper.support.util.IndexAssertionEventSend;
import com.espertech.esper.support.util.IndexBackingTableInfo;
import junit.framework.TestCase;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.util.List;
public class TestNamedWindowSubqCorrelIndex extends TestCase implements IndexBackingTableInfo
{
private static Log log = LogFactory.getLog(TestNamedWindowSubqCorrelIndex.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();
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();
}
protected void tearDown() throws Exception {
listenerStmtOne = null;
epRuntime = null;
}
public void testNoShare() {
runAssertion(false, false, false, false);
}
public void testNoShareSetnoindex() {
runAssertion(false, false, false, true);
}
public void testNoShareCreate() {
runAssertion(false, false, true, false);
}
public void testShare() {
runAssertion(true, false, false, false);
}
public void testShareCreate() {
runAssertion(true, false, true, false);
}
public void testShareCreateSetnoindex() {
runAssertion(true, false, true, true);
}
public void testDisableShare() {
runAssertion(true, true, false, false);
}
public void testDisableShareCreate() {
runAssertion(true, true, true, false);
}
public void testMultipleIndexHints() {
epService.getEPAdministrator().getConfiguration().addEventType("SSB1", SupportSimpleBeanOne.class);
epService.getEPAdministrator().getConfiguration().addEventType("SSB2", SupportSimpleBeanTwo.class);
epService.getEPAdministrator().createEPL("@Hint('enable_window_subquery_indexshare') create window MyWindow.win:keepall() as select * from SSB1");
epService.getEPAdministrator().createEPL("create unique index I1 on MyWindow (s1)");
epService.getEPAdministrator().createEPL("create unique index I2 on MyWindow (i1)");
epService.getEPAdministrator().createEPL(INDEX_CALLBACK_HOOK +
"@Hint('index(subquery(1), I1, bust)')\n" +
"@Hint('index(subquery(0), I2, bust)')\n" +
"select " +
"(select * from MyWindow where s1 = ssb2.s2 and i1 = ssb2.i2) as sub1," +
"(select * from MyWindow where i1 = ssb2.i2 and s1 = ssb2.s2) as sub2 " +
"from SSB2 ssb2");
List<QueryPlanIndexDescSubquery> subqueries = SupportQueryPlanIndexHook.getAndResetSubqueries();
SupportQueryPlanIndexHook.assertSubquery(subqueries.get(0), 0, "I2", BACKING_SINGLE_UNIQUE);
SupportQueryPlanIndexHook.assertSubquery(subqueries.get(1), 1, "I1", BACKING_SINGLE_UNIQUE);
}
public void testIndexShareIndexChoice() {
epService.getEPAdministrator().getConfiguration().addEventType("SSB1", SupportSimpleBeanOne.class);
epService.getEPAdministrator().getConfiguration().addEventType("SSB2", SupportSimpleBeanTwo.class);
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.s1,ssb1.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(true, noindexes, preloadedEventsOne, "std:unique(s1)",
new IndexAssertion[] {
new IndexAssertion(null, "s1 = ssb2.s2", null, BACKING_SINGLE_UNIQUE, eventSendAssertion),
new IndexAssertion(null, "s1 = ssb2.s2 and l1 = ssb2.l2", null, BACKING_SINGLE_UNIQUE, eventSendAssertion),
new IndexAssertion("@Hint('index(One)')", "s1 = ssb2.s2 and l1 = ssb2.l2", null, BACKING_SINGLE_UNIQUE, eventSendAssertion),
});
// single index one field (essentially duplicated since declared std:unique)
String[] indexOneField = new String[] {"create unique index One on MyWindow (s1)"};
assertIndexChoice(true, indexOneField, preloadedEventsOne, "std:unique(s1)",
new IndexAssertion[] {
new IndexAssertion(null, "s1 = ssb2.s2", "One", BACKING_SINGLE_UNIQUE, eventSendAssertion),
new IndexAssertion(null, "s1 = ssb2.s2 and l1 = ssb2.l2", "One", BACKING_SINGLE_UNIQUE, eventSendAssertion),
new IndexAssertion("@Hint('index(One)')", "s1 = ssb2.s2 and l1 = ssb2.l2", "One", BACKING_SINGLE_UNIQUE, eventSendAssertion),
});
// single index two field
String[] indexTwoField = new String[] {"create unique index One on MyWindow (s1, l1)"};
assertIndexChoice(true, indexTwoField, preloadedEventsOne, "std:unique(s1)",
new IndexAssertion[] {
new IndexAssertion(null, "s1 = ssb2.s2", null, BACKING_SINGLE_UNIQUE, eventSendAssertion),
new IndexAssertion(null, "s1 = ssb2.s2 and l1 = ssb2.l2", "One", BACKING_MULTI_UNIQUE, eventSendAssertion),
});
// two index one unique with std:unique(s1)
String[] indexSetTwo = new String[] {
"create index One on MyWindow (s1)",
"create unique index Two on MyWindow (s1, d1)"};
assertIndexChoice(true, indexSetTwo, preloadedEventsOne, "std:unique(s1)",
new IndexAssertion[] {
new IndexAssertion(null, "d1 = ssb2.d2", null, BACKING_SINGLE_DUPS, eventSendAssertion),
new IndexAssertion(null, "s1 = ssb2.s2", "One", BACKING_SINGLE_DUPS, eventSendAssertion),
new IndexAssertion(null, "s1 = ssb2.s2 and l1 = ssb2.l2", null, BACKING_SINGLE_UNIQUE, eventSendAssertion),
new IndexAssertion("@Hint('index(One)')", "s1 = ssb2.s2 and l1 = ssb2.l2", "One", BACKING_SINGLE_DUPS, eventSendAssertion),
new IndexAssertion("@Hint('index(Two,One)')", "s1 = ssb2.s2 and l1 = ssb2.l2", "One", BACKING_SINGLE_DUPS, 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", "One", BACKING_SINGLE_DUPS, eventSendAssertion),
new IndexAssertion(null, "s1 = ssb2.s2 and d1 = ssb2.d2 and l1 = ssb2.l2", "Two", BACKING_MULTI_UNIQUE, eventSendAssertion),
new IndexAssertion("@Hint('index(explicit,bust)')", "d1 = ssb2.d2 and l1 = ssb2.l2") // busted
});
// two index one unique with keep-all
assertIndexChoice(true, indexSetTwo, preloadedEventsOne, "win:keepall()",
new IndexAssertion[] {
new IndexAssertion(null, "d1 = ssb2.d2", null, BACKING_SINGLE_DUPS, eventSendAssertion),
new IndexAssertion(null, "s1 = ssb2.s2", "One", BACKING_SINGLE_DUPS, eventSendAssertion),
new IndexAssertion(null, "s1 = ssb2.s2 and l1 = ssb2.l2", null, BACKING_MULTI_DUPS, eventSendAssertion),
new IndexAssertion("@Hint('index(One)')", "s1 = ssb2.s2 and l1 = ssb2.l2", "One", BACKING_SINGLE_DUPS, eventSendAssertion),
new IndexAssertion("@Hint('index(Two,One)')", "s1 = ssb2.s2 and l1 = ssb2.l2", "One", BACKING_SINGLE_DUPS, 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", "One", BACKING_SINGLE_DUPS, eventSendAssertion),
new IndexAssertion(null, "s1 = ssb2.s2 and d1 = ssb2.d2 and l1 = ssb2.l2", "Two", BACKING_MULTI_UNIQUE, 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 MyWindow (i1 btree)",
"create index Two on MyWindow (d1 btree)"};
assertIndexChoice(true, indexSetThree, preloadedEventsOne, "std:unique(s1)",
new IndexAssertion[] {
new IndexAssertion(null, "i1 between 1 and 10", "One", BACKING_SORTED_COERCED, noAssertion),
new IndexAssertion(null, "d1 between 1 and 10", "Two", BACKING_SORTED_COERCED, noAssertion),
new IndexAssertion("@Hint('index(One, bust)')", "d1 between 1 and 10"), // busted
});
}
public void testNoIndexShareIndexChoice() {
epService.getEPAdministrator().getConfiguration().addEventType("SSB1", SupportSimpleBeanOne.class);
epService.getEPAdministrator().getConfiguration().addEventType("SSB2", SupportSimpleBeanTwo.class);
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.s1,ssb1.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(false, new String[0], preloadedEventsOne, "std:unique(s1)",
new IndexAssertion[] {
new IndexAssertion(null, "s1 = ssb2.s2", null, BACKING_SINGLE_UNIQUE, eventSendAssertion),
new IndexAssertion(null, "s1 = ssb2.s2 and l1 = ssb2.l2", null, BACKING_SINGLE_UNIQUE, eventSendAssertion),
new IndexAssertion(null, "i1 between 1 and 10", null, BACKING_SORTED, noAssertion),
new IndexAssertion(null, "l1 = ssb2.l2", null, BACKING_SINGLE_DUPS, eventSendAssertion),
});
// unique-s1+i1
assertIndexChoice(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 assertIndexChoice(boolean indexShare, String[] indexes, Object[] preloadedEvents, String datawindow,
IndexAssertion ... assertions) {
String epl = "create window MyWindow." + datawindow + " as select * from SSB1";
if (indexShare) {
epl = "@Hint('enable_window_subquery_indexshare') " + epl;
}
epService.getEPAdministrator().createEPL(epl);
epService.getEPAdministrator().createEPL("insert into MyWindow 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 MyWindow where " + assertion.getWhereClause() + ") 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.assertSubqueryAndReset(0, assertion.getExpectedIndexName(), assertion.getIndexBackingClass());
consumeStmt.addListener(listenerStmtOne);
assertion.getEventSendAssertion().run();
consumeStmt.destroy();
}
epService.getEPAdministrator().destroyAllStatements();
}
private void runAssertion(boolean enableIndexShareCreate, boolean disableIndexShareConsumer, boolean createExplicitIndex, boolean setNoindex) {
String createEpl = "create window MyWindow.std:unique(theString) as select * from SupportBean";
if (enableIndexShareCreate) {
createEpl = "@Hint('enable_window_subquery_indexshare') " + createEpl;
}
epService.getEPAdministrator().createEPL(createEpl);
epService.getEPAdministrator().createEPL("insert into MyWindow select * from SupportBean");
EPStatement stmtIndex = null;
if (createExplicitIndex) {
stmtIndex = epService.getEPAdministrator().createEPL("create index MyIndex on MyWindow (theString)");
}
String consumeEpl = "select status.*, (select * from MyWindow where theString = ABean.p00) 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.theString,details.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();
}
}