/* *************************************************************************************** * 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.epl; import com.espertech.esper.client.Configuration; import com.espertech.esper.client.EPServiceProvider; import com.espertech.esper.client.EPServiceProviderManager; import com.espertech.esper.client.EPStatementException; import com.espertech.esper.epl.join.plan.*; import com.espertech.esper.epl.join.util.QueryPlanIndexDescOnExpr; import com.espertech.esper.epl.join.util.QueryPlanIndexDescSubquery; import com.espertech.esper.epl.lookup.SubordFullTableScanLookupStrategyFactory; import com.espertech.esper.epl.lookup.SubordWMatchExprLookupStrategyFactoryAllFiltered; import com.espertech.esper.supportregression.bean.SupportBean_S0; import com.espertech.esper.supportregression.bean.SupportBean_S1; import com.espertech.esper.supportregression.client.SupportConfigFactory; import com.espertech.esper.supportregression.epl.SupportExprNodeFactory; import com.espertech.esper.supportregression.epl.SupportQueryPlanBuilder; import com.espertech.esper.supportregression.epl.SupportQueryPlanIndexHelper; import com.espertech.esper.supportregression.epl.SupportQueryPlanIndexHook; import com.espertech.esper.supportregression.util.IndexBackingTableInfo; import junit.framework.TestCase; public class TestExcludePlanHint extends TestCase implements IndexBackingTableInfo { private EPServiceProvider epService; public void setUp() { Configuration configuration = SupportConfigFactory.getConfiguration(); configuration.getEngineDefaults().getLogging().setEnableQueryPlan(true); epService = EPServiceProviderManager.getDefaultProvider(configuration); epService.initialize(); epService.getEPAdministrator().getConfiguration().addEventType("S0", SupportBean_S0.class); epService.getEPAdministrator().getConfiguration().addEventType("S1", SupportBean_S1.class); } public void testDocSample() { epService.getEPAdministrator().getConfiguration().addEventType(AEvent.class); epService.getEPAdministrator().getConfiguration().addEventType(BEvent.class); String[] hints = new String[] { "@hint('exclude_plan(true)')", "@hint('exclude_plan(opname=\"equals\")')", "@hint('exclude_plan(opname=\"equals\" and from_streamname=\"a\")')", "@hint('exclude_plan(opname=\"equals\" and from_streamname=\"b\")')", "@hint('exclude_plan(exprs[0]=\"aprop\")')"}; for (String hint : hints) { epService.getEPAdministrator().createEPL("@Audit " + hint + "select * from AEvent#keepall as a, BEvent#keepall as b where aprop = bprop"); } // test subquery SupportQueryPlanIndexHook.reset(); epService.getEPAdministrator().createEPL(INDEX_CALLBACK_HOOK + "@hint('exclude_plan(true)') select (select * from S0#unique(p00) as s0 where s1.p10 = p00) from S1 as s1"); QueryPlanIndexDescSubquery subq = SupportQueryPlanIndexHook.getAndResetSubqueries().get(0); assertEquals(SubordFullTableScanLookupStrategyFactory.class.getSimpleName(), subq.getTableLookupStrategy()); // test named window epService.getEPAdministrator().createEPL("create window S0Window#keepall as S0"); epService.getEPAdministrator().createEPL(INDEX_CALLBACK_HOOK + "@hint('exclude_plan(true)') on S1 as s1 select * from S0Window as s0 where s1.p10 = s0.p00"); QueryPlanIndexDescOnExpr onExpr = SupportQueryPlanIndexHook.getAndResetOnExpr(); assertEquals(SubordWMatchExprLookupStrategyFactoryAllFiltered.class.getSimpleName(), onExpr.getStrategyName()); } public void testJoin() { String epl = "select * from S0#keepall as s0, S1#keepall as s1 "; QueryPlan planFullTableScan = SupportQueryPlanBuilder.start(2) .setIndexFullTableScan(0, "i0") .setIndexFullTableScan(1, "i1") .setLookupPlanInner(0, new FullTableScanLookupPlan(0, 1, getIndexKey("i1"))) .setLookupPlanInner(1, new FullTableScanLookupPlan(1, 0, getIndexKey("i0"))).get(); // test "any" String excludeAny = "@hint('exclude_plan(true)')"; runAssertionJoin(epl, planFullTableScan); runAssertionJoin(excludeAny + epl + " where p00 = p10", planFullTableScan); runAssertionJoin(excludeAny + epl + " where p00 = 'abc'", planFullTableScan); runAssertionJoin(excludeAny + epl + " where p00 = (p10 || 'A')", planFullTableScan); runAssertionJoin(excludeAny + epl + " where p10 = 'abc'", planFullTableScan); runAssertionJoin(excludeAny + epl + " where p00 > p10", planFullTableScan); runAssertionJoin(excludeAny + epl + " where p00 > 'A'", planFullTableScan); runAssertionJoin(excludeAny + epl + " where p10 > 'A'", planFullTableScan); runAssertionJoin(excludeAny + epl + " where p10 > 'A'", planFullTableScan); runAssertionJoin(excludeAny + epl + " where p00 > (p10 || 'A')", planFullTableScan); runAssertionJoin(excludeAny + epl + " where p00 between p10 and p11", planFullTableScan); runAssertionJoin(excludeAny + epl + " where p00 between 'a' and p11", planFullTableScan); runAssertionJoin(excludeAny + epl + " where p00 between 'a' and 'c'", planFullTableScan); runAssertionJoin(excludeAny + epl + " where p00 between p10 and 'c'", planFullTableScan); runAssertionJoin(excludeAny + epl + " where p00 in (p10, p11)", planFullTableScan); runAssertionJoin(excludeAny + epl + " where p00 in ('a', p11)", planFullTableScan); runAssertionJoin(excludeAny + epl + " where p00 in ('a', 'b')", planFullTableScan); runAssertionJoin(excludeAny + epl + " where p10 in (p00, p01)", planFullTableScan); // test EQUALS QueryPlan planEquals = SupportQueryPlanBuilder.start(2) .addIndexHashSingleNonUnique(0, "i1", "p00") .setIndexFullTableScan(1, "i2") .setLookupPlanInner(0, new FullTableScanLookupPlan(0, 1, getIndexKey("i2"))) .setLookupPlanInner(1, new IndexedTableLookupPlanSingle(1, 0, getIndexKey("i1"), SupportExprNodeFactory.makeKeyed("p10"))).get(); String eplWithWhereEquals = epl + " where p00 = p10"; runAssertionJoin("@hint('exclude_plan(from_streamnum=0)')" + eplWithWhereEquals, planEquals); runAssertionJoin("@hint('exclude_plan(from_streamname=\"s0\")')" + eplWithWhereEquals, planEquals); runAssertionJoin("@hint('exclude_plan(from_streamname=\"s0\")') @hint('exclude_plan(from_streamname=\"s1\")')" + eplWithWhereEquals, planFullTableScan); runAssertionJoin("@hint('exclude_plan(from_streamname=\"s0\")') @hint('exclude_plan(from_streamname=\"s1\")')" + eplWithWhereEquals, planFullTableScan); runAssertionJoin("@hint('exclude_plan(to_streamname=\"s1\")')" + eplWithWhereEquals, planEquals); runAssertionJoin("@hint('exclude_plan(to_streamname=\"s0\")') @hint('exclude_plan(to_streamname=\"s1\")')" + eplWithWhereEquals, planFullTableScan); runAssertionJoin("@hint('exclude_plan(from_streamnum=0 and to_streamnum = 1)')" + eplWithWhereEquals, planEquals); runAssertionJoin("@hint('exclude_plan(to_streamnum=1)')" + eplWithWhereEquals, planEquals); runAssertionJoin("@hint('exclude_plan(to_streamnum = 1, from_streamnum = 0)')" + eplWithWhereEquals, planEquals); runAssertionJoin("@hint('exclude_plan(opname=\"equals\")')" + eplWithWhereEquals, planFullTableScan); runAssertionJoin("@hint('exclude_plan(exprs.anyOf(v=> v=\"p00\"))')" + eplWithWhereEquals, planFullTableScan); runAssertionJoin("@hint('exclude_plan(\"p10\" in (exprs))')" + eplWithWhereEquals, planFullTableScan); // test greater (relop) QueryPlan planGreater = SupportQueryPlanBuilder.start(2) .addIndexBtreeSingle(0, "i1", "p00") .setIndexFullTableScan(1, "i2") .setLookupPlanInner(0, new FullTableScanLookupPlan(0, 1, getIndexKey("i2"))) .setLookupPlanInner(1, new SortedTableLookupPlan(1, 0, getIndexKey("i1"), SupportExprNodeFactory.makeRangeLess("p10"))).get(); String eplWithWhereGreater = epl + " where p00 > p10"; runAssertionJoin("@hint('exclude_plan(from_streamnum=0)')" + eplWithWhereGreater, planGreater); runAssertionJoin("@hint('exclude_plan(opname=\"relop\")')" + eplWithWhereGreater, planFullTableScan); // test range (relop) QueryPlan planRange = SupportQueryPlanBuilder.start(2) .addIndexBtreeSingle(0, "i1", "p00") .setIndexFullTableScan(1, "i2") .setLookupPlanInner(0, new FullTableScanLookupPlan(0, 1, getIndexKey("i2"))) .setLookupPlanInner(1, new SortedTableLookupPlan(1, 0, getIndexKey("i1"), SupportExprNodeFactory.makeRangeIn("p10", "p11"))).get(); String eplWithWhereRange = epl + " where p00 between p10 and p11"; runAssertionJoin("@hint('exclude_plan(from_streamnum=0)')" + eplWithWhereRange, planRange); runAssertionJoin("@hint('exclude_plan(opname=\"relop\")')" + eplWithWhereRange, planFullTableScan); // test in (relop) QueryPlan planIn = SupportQueryPlanBuilder.start(2) .addIndexHashSingleNonUnique(0, "i1", "p00") .setIndexFullTableScan(1, "i2") .setLookupPlanInner(0, new FullTableScanLookupPlan(0, 1, getIndexKey("i2"))) .setLookupPlanInner(1, new InKeywordTableLookupPlanSingleIdx(1, 0, getIndexKey("i1"), SupportExprNodeFactory.makeIdentExprNodes("p10", "p11"))).get(); String eplWithIn = epl + " where p00 in (p10, p11)"; runAssertionJoin("@hint('exclude_plan(from_streamnum=0)')" + eplWithIn, planIn); runAssertionJoin("@hint('exclude_plan(opname=\"inkw\")')" + eplWithIn, planFullTableScan); } public void testInvalid() { String epl = "select * from S0 unidirectional, S1#keepall"; // no params tryInvalid("@hint('exclude_plan') " + epl, "Failed to process statement annotations: Hint 'EXCLUDE_PLAN' requires additional parameters in parentheses [@hint('exclude_plan') select * from S0 unidirectional, S1#keepall]"); // empty parameter allowed, to be filled in epService.getEPAdministrator().createEPL("@hint('exclude_plan()') " + epl); epService.getEPRuntime().sendEvent(new SupportBean_S0(1)); // invalid return type tryInvalid("@hint('exclude_plan(1)') " + epl, "Error starting statement: Expression provided for hint EXCLUDE_PLAN must return a boolean value [@hint('exclude_plan(1)') select * from S0 unidirectional, S1#keepall]"); // invalid expression tryInvalid("@hint('exclude_plan(dummy = 1)') " + epl, "Error starting statement: Failed to validate hint expression 'dummy=1': Property named 'dummy' is not valid in any stream [@hint('exclude_plan(dummy = 1)') select * from S0 unidirectional, S1#keepall]"); } private void tryInvalid(String epl, String expected) { try { epService.getEPAdministrator().createEPL(epl); fail(); } catch (EPStatementException ex) { assertEquals(expected, ex.getMessage()); } } private void runAssertionJoin(String epl, QueryPlan expectedPlan) { SupportQueryPlanIndexHook.reset(); epl = INDEX_CALLBACK_HOOK + epl; epService.getEPAdministrator().createEPL(epl); QueryPlan actualPlan = SupportQueryPlanIndexHook.assertJoinAndReset(); SupportQueryPlanIndexHelper.compareQueryPlans(expectedPlan, actualPlan); epService.getEPAdministrator().destroyAllStatements(); } private static class AEvent { private final String aprop; private AEvent(String aprop) { this.aprop = aprop; } public String getAprop() { return aprop; } } private static class BEvent { private final String bprop; private BEvent(String bprop) { this.bprop = bprop; } public String getBprop() { return bprop; } } private static TableLookupIndexReqKey getIndexKey(String name) { return new TableLookupIndexReqKey(name); } }