/*
***************************************************************************************
* 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.view;
import com.espertech.esper.client.*;
import com.espertech.esper.metrics.instrumentation.InstrumentationHelper;
import com.espertech.esper.supportregression.bean.SupportBean;
import com.espertech.esper.supportregression.bean.SupportBean_N;
import com.espertech.esper.supportregression.client.SupportConfigFactory;
import junit.framework.TestCase;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static com.espertech.esper.supportregression.util.SupportMessageAssertUtil.assertMessage;
public class TestInvalidView extends TestCase
{
private final String EVENT_NUM = SupportBean_N.class.getName();
private final String EVENT_ALLTYPES = SupportBean.class.getName();
private EPServiceProvider epService;
public void setUp()
{
epService = EPServiceProviderManager.getDefaultProvider(SupportConfigFactory.getConfiguration());
epService.initialize();
if (InstrumentationHelper.ENABLED) { InstrumentationHelper.startTest(epService, this.getClass(), getName());}
}
public void tearDown() {
if (InstrumentationHelper.ENABLED) { InstrumentationHelper.endTest();}
}
public void testInvalidPropertyExpression()
{
epService.getEPAdministrator().getConfiguration().addEventType("SupportBean", SupportBean.class);
EPStatement stmt = epService.getEPAdministrator().createEPL("@IterableUnbound select * from SupportBean");
epService.getEPRuntime().sendEvent(new SupportBean());
EventBean theEvent = stmt.iterator().next();
String exceptionText = getSyntaxExceptionProperty("", theEvent);
assertEquals("Property named '' is not a valid property name for this type", exceptionText);
exceptionText = getSyntaxExceptionProperty("-", theEvent);
assertEquals("Property named '-' is not a valid property name for this type", exceptionText);
exceptionText = getSyntaxExceptionProperty("a[]", theEvent);
assertEquals("Property named 'a[]' is not a valid property name for this type", exceptionText);
}
public void testInvalidSyntax()
{
// keyword in select clause
EPStatementSyntaxException exception = getSyntaxExceptionView("select inner from MyStream");
assertMessage(exception, "Incorrect syntax near 'inner' (a reserved keyword) at line 1 column 7, please check the select clause [");
// keyword in from clause
exception = getSyntaxExceptionView("select something from Outer");
assertMessage(exception, "Incorrect syntax near 'Outer' (a reserved keyword) at line 1 column 22, please check the from clause [");
// keyword used in package
exception = getSyntaxExceptionView("select * from com.true.mycompany.MyEvent");
assertMessage(exception, "Incorrect syntax near 'true' (a reserved keyword) expecting an identifier but found 'true' at line 1 column 18, please check the view specifications within the from clause [");
// keyword as part of identifier
exception = getSyntaxExceptionView("select * from MyEvent, MyEvent2 where a.day=b.day");
assertMessage(exception, "Incorrect syntax near 'day' (a reserved keyword) at line 1 column 40, please check the where clause [");
exception = getSyntaxExceptionView("select * * from " + EVENT_NUM);
assertMessage(exception, "Incorrect syntax near '*' at line 1 column 9 near reserved keyword 'from' [");
// keyword in select clause
exception = getSyntaxExceptionView("select day from MyEvent, MyEvent2");
assertMessage(exception, "Incorrect syntax near 'day' (a reserved keyword) at line 1 column 7, please check the select clause [");
}
public void testStatementException() throws Exception
{
EPStatementException exception;
// property near to spelling
exception = getStatementExceptionView("select s0.intPrimitv from " + SupportBean.class.getName() + " as s0");
assertMessage(exception, "Error starting statement: Failed to validate select-clause expression 's0.intPrimitv': Property named 'intPrimitv' is not valid in stream 's0' (did you mean 'intPrimitive'?) [");
exception = getStatementExceptionView("select INTPRIMITIVE from " + SupportBean.class.getName());
assertMessage(exception, "Error starting statement: Failed to validate select-clause expression 'INTPRIMITIVE': Property named 'INTPRIMITIVE' is not valid in any stream (did you mean 'intPrimitive'?) [");
exception = getStatementExceptionView("select theStrring from " + SupportBean.class.getName());
assertMessage(exception, "Error starting statement: Failed to validate select-clause expression 'theStrring': Property named 'theStrring' is not valid in any stream (did you mean 'theString'?) [");
// aggregation in where clause known
exception = getStatementExceptionView("select * from " + SupportBean.class.getName() + " where sum(intPrimitive) > 10");
assertMessage(exception, "Aggregation functions not allowed within filters [");
// class not found
exception = getStatementExceptionView("select * from dummypkg.dummy()#length(10)");
assertMessage(exception, "Failed to resolve event type: Event type or class named 'dummypkg.dummy' was not found [select * from dummypkg.dummy()#length(10)]");
// invalid view
exception = getStatementExceptionView("select * from " + EVENT_NUM + ".dummy:dummy(10)");
assertMessage(exception, "Error starting statement: View name 'dummy:dummy' is not a known view name [");
// keyword used
exception = getSyntaxExceptionView("select order from " + SupportBean.class.getName());
assertMessage(exception, "Incorrect syntax near 'order' (a reserved keyword) at line 1 column 7, please check the select clause [");
// invalid view parameter
exception = getStatementExceptionView("select * from " + EVENT_NUM + "#length('s')");
assertMessage(exception, "Error starting statement: Error in view 'length', Length view requires a single integer-type parameter [");
// where-clause relational op has invalid type
exception = getStatementExceptionView("select * from " + EVENT_ALLTYPES + "#length(1) where theString > 5");
assertMessage(exception, "Error validating expression: Failed to validate filter expression 'theString>5': Implicit conversion from datatype 'String' to numeric is not allowed [");
// where-clause has aggregation function
exception = getStatementExceptionView("select * from " + EVENT_ALLTYPES + "#length(1) where sum(intPrimitive) > 5");
assertMessage(exception, "Error validating expression: An aggregate function may not appear in a WHERE clause (use the HAVING clause) [");
// invalid numerical expression
exception = getStatementExceptionView("select 2 * 's' from " + EVENT_ALLTYPES + "#length(1)");
assertMessage(exception, "Error starting statement: Failed to validate select-clause expression '2*\"s\"': Implicit conversion from datatype 'String' to numeric is not allowed [");
// invalid property in select
exception = getStatementExceptionView("select a[2].m('a') from " + EVENT_ALLTYPES + "#length(1)");
assertMessage(exception, "Error starting statement: Failed to validate select-clause expression 'a[2].m('a')': Failed to resolve enumeration method, date-time method or mapped property 'a[2].m('a')': Failed to resolve 'a[2].m' to a property, single-row function, aggregation function, script, stream or class name [");
// select clause uses same "as" name twice
exception = getStatementExceptionView("select 2 as m, 2 as m from " + EVENT_ALLTYPES + "#length(1)");
assertMessage(exception, "Error starting statement: Column name 'm' appears more then once in select clause [");
// class in method invocation not found
exception = getStatementExceptionView("select unknownClass.method() from " + EVENT_NUM + "#length(10)");
assertMessage(exception, "Error starting statement: Failed to validate select-clause expression 'unknownClass.method()': Failed to resolve 'unknownClass.method' to a property, single-row function, aggregation function, script, stream or class name [");
// method not found
exception = getStatementExceptionView("select Math.unknownMethod() from " + EVENT_NUM + "#length(10)");
assertMessage(exception, "Error starting statement: Failed to validate select-clause expression 'Math.unknownMethod()': Failed to resolve 'Math.unknownMethod' to a property, single-row function, aggregation function, script, stream or class name [");
// invalid property in group-by
exception = getStatementExceptionView("select intPrimitive from " + EVENT_ALLTYPES + "#length(1) group by xxx");
assertMessage(exception, "Error starting statement: Failed to validate group-by-clause expression 'xxx': Property named 'xxx' is not valid in any stream [");
// group-by not specifying a property
exception = getStatementExceptionView("select intPrimitive from " + EVENT_ALLTYPES + "#length(1) group by 5");
assertMessage(exception, "Error starting statement: Group-by expressions must refer to property names [");
// group-by specifying aggregates
exception = getStatementExceptionView("select intPrimitive from " + EVENT_ALLTYPES + "#length(1) group by sum(intPrimitive)");
assertMessage(exception, "Error starting statement: Group-by expressions cannot contain aggregate functions [");
// invalid property in having clause
exception = getStatementExceptionView("select 2 * 's' from " + EVENT_ALLTYPES + "#length(1) group by intPrimitive having xxx > 5");
assertMessage(exception, "Error starting statement: Failed to validate select-clause expression '2*\"s\"': Implicit conversion from datatype 'String' to numeric is not allowed [");
// invalid having clause - not a symbol in the group-by (non-aggregate)
exception = getStatementExceptionView("select sum(intPrimitive) from " + EVENT_ALLTYPES + "#length(1) group by intBoxed having doubleBoxed > 5");
assertMessage(exception, "Error starting statement: Non-aggregated property 'doubleBoxed' in the HAVING clause must occur in the group-by clause [");
// invalid outer join - not a symbol
exception = getStatementExceptionView("select * from " + EVENT_ALLTYPES + "#length(1) as aStr " +
"left outer join " + EVENT_ALLTYPES + "#length(1) on xxxx=yyyy");
assertMessage(exception, "Error validating expression: Failed to validate on-clause join expression 'xxxx=yyyy': Property named 'xxxx' is not valid in any stream [");
// invalid outer join for 3 streams - not a symbol
exception = getStatementExceptionView("select * from " + EVENT_ALLTYPES + "#length(1) as s0 " +
"left outer join " + EVENT_ALLTYPES + "#length(1) as s1 on s0.intPrimitive = s1.intPrimitive " +
"left outer join " + EVENT_ALLTYPES + "#length(1) as s2 on s0.intPrimitive = s2.yyyy");
assertMessage(exception, "Error validating expression: Failed to validate on-clause join expression 's0.intPrimitive=s2.yyyy': Failed to resolve property 's2.yyyy' to a stream or nested property in a stream [");
// invalid outer join for 3 streams - wrong stream, the properties in on-clause don't refer to streams
exception = getStatementExceptionView("select * from " + EVENT_ALLTYPES + "#length(1) as s0 " +
"left outer join " + EVENT_ALLTYPES + "#length(1) as s1 on s0.intPrimitive = s1.intPrimitive " +
"left outer join " + EVENT_ALLTYPES + "#length(1) as s2 on s0.intPrimitive = s1.intPrimitive");
assertMessage(exception, "Error validating expression: Outer join ON-clause must refer to at least one property of the joined stream for stream 2 [");
// invalid outer join - referencing next stream
exception = getStatementExceptionView("select * from " + EVENT_ALLTYPES + "#length(1) as s0 " +
"left outer join " + EVENT_ALLTYPES + "#length(1) as s1 on s2.intPrimitive = s1.intPrimitive " +
"left outer join " + EVENT_ALLTYPES + "#length(1) as s2 on s1.intPrimitive = s2.intPrimitive");
assertMessage(exception, "Error validating expression: Outer join ON-clause invalid scope for property 'intPrimitive', expecting the current or a prior stream scope [");
// invalid outer join - same properties
exception = getStatementExceptionView("select * from " + EVENT_NUM + "#length(1) as aStr " +
"left outer join " + EVENT_ALLTYPES + "#length(1) on theString=theString");
assertMessage(exception, "Error validating expression: Outer join ON-clause cannot refer to properties of the same stream [");
// invalid order by
exception = getStatementExceptionView("select * from " + EVENT_NUM + "#length(1) as aStr order by X");
assertMessage(exception, "Error starting statement: Failed to validate order-by-clause expression 'X': Property named 'X' is not valid in any stream [");
// insert into with wildcard - not allowed
exception = getStatementExceptionView("insert into Google (a, b) select * from " + EVENT_NUM + "#length(1) as aStr");
assertMessage(exception, "Error starting statement: Wildcard not allowed when insert-into specifies column order [");
// insert into with duplicate column names
exception = getStatementExceptionView("insert into Google (a, b, a) select boolBoxed, boolPrimitive, intBoxed from " + EVENT_NUM + "#length(1) as aStr");
assertMessage(exception, "Error starting statement: Property name 'a' appears more then once in insert-into clause [");
// insert into mismatches selected columns
exception = getStatementExceptionView("insert into Google (a, b, c) select boolBoxed, boolPrimitive from " + EVENT_NUM + "#length(1) as aStr");
assertMessage(exception, "Error starting statement: Number of supplied values in the select or values clause does not match insert-into clause [");
// mismatched type on coalesce columns
exception = getStatementExceptionView("select coalesce(boolBoxed, theString) from " + SupportBean.class.getName() + "#length(1) as aStr");
assertMessage(exception, "Error starting statement: Failed to validate select-clause expression 'coalesce(boolBoxed,theString)': Implicit conversion not allowed: Cannot coerce to Boolean type java.lang.String [");
// mismatched case compare type
exception = getStatementExceptionView("select case boolPrimitive when 1 then true end from " + SupportBean.class.getName() + "#length(1) as aStr");
assertMessage(exception, "Error starting statement: Failed to validate select-clause expression 'case boolPrimitive when 1 then true end': Implicit conversion not allowed: Cannot coerce to Boolean type java.lang.Integer [");
// mismatched case result type
exception = getStatementExceptionView("select case when 1=2 then 1 when 1=3 then true end from " + SupportBean.class.getName() + "#length(1) as aStr");
assertMessage(exception, "Error starting statement: Failed to validate select-clause expression 'case when 1=2 then 1 when 1=3 then ...(43 chars)': Implicit conversion not allowed: Cannot coerce types java.lang.Integer and java.lang.Boolean [");
// case expression not returning bool
exception = getStatementExceptionView("select case when 3 then 1 end from " + SupportBean.class.getName() + "#length(1) as aStr");
assertMessage(exception, "Error starting statement: Failed to validate select-clause expression 'case when 3 then 1 end': Case node 'when' expressions must return a boolean value [");
// function not known
exception = getStatementExceptionView("select gogglex(1) from " + EVENT_NUM + "#length(1)");
assertMessage(exception, "Error starting statement: Failed to validate select-clause expression 'gogglex(1)': Unknown single-row function, aggregation function or mapped or indexed property named 'gogglex' could not be resolved [");
// insert into column name incorrect
epService.getEPAdministrator().createEPL("insert into Xyz select 1 as dodi from java.lang.String");
exception = getStatementExceptionView("select pox from pattern[Xyz(yodo=4)]");
assertMessage(exception, "Failed to validate filter expression 'yodo=4': Property named 'yodo' is not valid in any stream (did you mean 'dodi'?) [select pox from pattern[Xyz(yodo=4)]]");
}
public void testInvalidView()
{
String eventClass = SupportBean.class.getName();
tryInvalid("select * from " + eventClass + "(dummy='a')#length(3)");
tryValid("select * from " + eventClass + "(theString='a')#length(3)");
tryInvalid("select * from " + eventClass + ".dummy:length(3)");
tryInvalid("select djdjdj from " + eventClass + "#length(3)");
tryValid("select boolBoxed as xx, intPrimitive from " + eventClass + "#length(3)");
tryInvalid("select boolBoxed as xx, intPrimitive as xx from " + eventClass + "#length(3)");
tryValid("select boolBoxed as xx, intPrimitive as yy from " + eventClass + "()#length(3)");
tryValid("select boolBoxed as xx, intPrimitive as yy from " + eventClass + "()#length(3)" +
" where boolBoxed = true");
tryInvalid("select boolBoxed as xx, intPrimitive as yy from " + eventClass + "()#length(3)" +
" where xx = true");
}
private void tryInvalid(String viewStmt)
{
try
{
epService.getEPAdministrator().createEPL(viewStmt);
fail();
}
catch (EPException ex)
{
// Expected exception
}
}
private EPStatementSyntaxException getSyntaxExceptionView(String expression)
{
try
{
epService.getEPAdministrator().createEPL(expression);
fail();
}
catch (EPStatementSyntaxException ex)
{
if (log.isDebugEnabled()) {
log.debug(".getSyntaxExceptionView expression=" + expression, ex);
}
// Expected exception
return ex;
}
throw new IllegalStateException();
}
private String getSyntaxExceptionProperty(String expression, EventBean theEvent)
{
String exceptionText = null;
try
{
theEvent.get(expression);
fail();
}
catch (PropertyAccessException ex)
{
exceptionText = ex.getMessage();
if (log.isDebugEnabled())
{
log.debug(".getSyntaxExceptionProperty expression=" + expression, ex);
}
// Expected exception
}
return exceptionText;
}
private EPStatementException getStatementExceptionView(String expression) throws Exception
{
return getStatementExceptionView(expression, false);
}
private EPStatementException getStatementExceptionView(String expression, boolean isLogException) throws Exception
{
try
{
epService.getEPAdministrator().createEPL(expression, "MyStatement");
fail();
}
catch (EPStatementSyntaxException es)
{
throw es;
}
catch (EPStatementException ex)
{
// Expected exception
if (isLogException) {
log.debug(".getStatementExceptionView expression=" + expression, ex);
}
return ex;
}
throw new IllegalStateException();
}
private void tryValid(String viewStmt)
{
epService.getEPAdministrator().createEPL(viewStmt);
}
private final static Logger log = LoggerFactory.getLogger(TestInvalidView.class);
}