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