/*
***************************************************************************************
* 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.epl.expression.subquery;
import com.espertech.esper.epl.expression.core.ExprEvaluator;
import com.espertech.esper.epl.expression.core.ExprNode;
import com.espertech.esper.epl.expression.core.ExprValidationException;
import com.espertech.esper.epl.spec.GroupByClauseExpressions;
import com.espertech.esper.type.RelationalOpEnum;
import com.espertech.esper.util.CoercionException;
import com.espertech.esper.util.JavaClassHelper;
import com.espertech.esper.util.SimpleNumberCoercer;
import com.espertech.esper.util.SimpleNumberCoercerFactory;
import java.util.Collection;
import java.util.Map;
/**
* Factory for subselect evaluation strategies.
*/
public class SubselectEvalStrategyNRFactory {
public static SubselectEvalStrategyNR createStrategyExists(ExprSubselectExistsNode subselectExpression) {
boolean aggregated = aggregated(subselectExpression.getSubselectAggregationType());
boolean grouped = grouped(subselectExpression.getStatementSpecCompiled().getGroupByExpressions());
if (grouped) {
if (subselectExpression.havingExpr != null) {
return new SubselectEvalStrategyNRExistsWGroupByWHaving(subselectExpression.havingExpr);
}
return SubselectEvalStrategyNRExistsWGroupBy.INSTANCE;
}
if (aggregated) {
if (subselectExpression.havingExpr != null) {
return new SubselectEvalStrategyNRExistsAggregated(subselectExpression.havingExpr);
}
return SubselectEvalStrategyNRExistsAlwaysTrue.INSTANCE;
}
return new SubselectEvalStrategyNRExistsDefault(subselectExpression.filterExpr, subselectExpression.havingExpr);
}
public static SubselectEvalStrategyNR createStrategyAnyAllIn(ExprSubselectNode subselectExpression,
boolean isNot,
boolean isAll,
boolean isAny,
RelationalOpEnum relationalOp) throws ExprValidationException {
if (subselectExpression.getChildNodes().length != 1) {
throw new ExprValidationException("The Subselect-IN requires 1 child expression");
}
ExprNode valueExpr = subselectExpression.getChildNodes()[0];
// Must be the same boxed type returned by expressions under this
Class typeOne = JavaClassHelper.getBoxedType(subselectExpression.getChildNodes()[0].getExprEvaluator().getType());
// collections, array or map not supported
if ((typeOne.isArray()) || (JavaClassHelper.isImplementsInterface(typeOne, Collection.class)) || (JavaClassHelper.isImplementsInterface(typeOne, Map.class))) {
throw new ExprValidationException("Collection or array comparison is not allowed for the IN, ANY, SOME or ALL keywords");
}
Class typeTwo;
if (subselectExpression.getSelectClause() != null) {
typeTwo = subselectExpression.getSelectClause()[0].getExprEvaluator().getType();
} else {
typeTwo = subselectExpression.getRawEventType().getUnderlyingType();
}
boolean aggregated = aggregated(subselectExpression.getSubselectAggregationType());
boolean grouped = grouped(subselectExpression.getStatementSpecCompiled().getGroupByExpressions());
ExprEvaluator selectEval = subselectExpression.getSelectClause() == null ? null : subselectExpression.getSelectClause()[0].getExprEvaluator();
ExprEvaluator valueEval = valueExpr.getExprEvaluator();
ExprEvaluator filterEval = subselectExpression.getFilterExpr();
ExprEvaluator havingEval = subselectExpression.getHavingExpr();
if (relationalOp != null) {
if ((typeOne != String.class) || (typeTwo != String.class)) {
if (!JavaClassHelper.isNumeric(typeOne)) {
throw new ExprValidationException("Implicit conversion from datatype '" +
typeOne.getSimpleName() +
"' to numeric is not allowed");
}
if (!JavaClassHelper.isNumeric(typeTwo)) {
throw new ExprValidationException("Implicit conversion from datatype '" +
typeTwo.getSimpleName() +
"' to numeric is not allowed");
}
}
Class compareType = JavaClassHelper.getCompareToCoercionType(typeOne, typeTwo);
RelationalOpEnum.Computer computer = relationalOp.getComputer(compareType, typeOne, typeTwo);
if (isAny) {
if (grouped) {
return new SubselectEvalStrategyNRRelOpAnyWGroupBy(valueEval, selectEval, false, computer, havingEval);
}
if (aggregated) {
return new SubselectEvalStrategyNRRelOpAllAnyAggregated(valueEval, selectEval, false, computer, havingEval);
}
return new SubselectEvalStrategyNRRelOpAnyDefault(valueEval, selectEval, false, computer, filterEval);
}
// handle ALL
if (grouped) {
return new SubselectEvalStrategyNRRelOpAllWGroupBy(valueEval, selectEval, true, computer, havingEval);
}
if (aggregated) {
return new SubselectEvalStrategyNRRelOpAllAnyAggregated(valueEval, selectEval, true, computer, havingEval);
}
return new SubselectEvalStrategyNRRelOpAllDefault(valueEval, selectEval, true, computer, filterEval);
}
SimpleNumberCoercer coercer = getCoercer(typeOne, typeTwo);
if (isAll) {
if (grouped) {
return new SubselectEvalStrategyNREqualsAllWGroupBy(valueEval, selectEval, true, isNot, coercer, havingEval);
}
if (aggregated) {
return new SubselectEvalStrategyNREqualsAllAnyAggregated(valueEval, selectEval, true, isNot, coercer, havingEval);
}
return new SubselectEvalStrategyNREqualsAllDefault(valueEval, selectEval, true, isNot, coercer, filterEval);
} else if (isAny) {
if (grouped) {
return new SubselectEvalStrategyNREqualsAnyWGroupBy(valueEval, selectEval, false, isNot, coercer, havingEval);
}
if (aggregated) {
return new SubselectEvalStrategyNREqualsAllAnyAggregated(valueEval, selectEval, true, isNot, coercer, havingEval);
}
return new SubselectEvalStrategyNREqualsAnyDefault(valueEval, selectEval, false, isNot, coercer, filterEval);
} else {
if (grouped) {
return new SubselectEvalStrategyNREqualsInWGroupBy(valueEval, selectEval, isNot, coercer, havingEval);
}
if (aggregated) {
return new SubselectEvalStrategyNREqualsInAggregated(valueEval, selectEval, isNot, coercer, havingEval);
}
if (filterEval == null) {
return new SubselectEvalStrategyNREqualsInUnfiltered(valueEval, selectEval, isNot, coercer);
}
return new SubselectEvalStrategyNREqualsInFiltered(valueEval, selectEval, isNot, coercer, filterEval);
}
}
private static SimpleNumberCoercer getCoercer(Class typeOne, Class typeTwo) throws ExprValidationException {
// Get the common type such as Bool, String or Double and Long
Class coercionType;
boolean mustCoerce;
try {
coercionType = JavaClassHelper.getCompareToCoercionType(typeOne, typeTwo);
} catch (CoercionException ex) {
throw new ExprValidationException("Implicit conversion from datatype '" +
typeTwo.getSimpleName() +
"' to '" +
typeOne.getSimpleName() +
"' is not allowed");
}
// Check if we need to coerce
mustCoerce = false;
if ((coercionType != JavaClassHelper.getBoxedType(typeOne)) ||
(coercionType != JavaClassHelper.getBoxedType(typeTwo))) {
if (JavaClassHelper.isNumeric(coercionType)) {
mustCoerce = true;
}
}
return !mustCoerce ? null : SimpleNumberCoercerFactory.getCoercer(null, coercionType);
}
private static boolean grouped(GroupByClauseExpressions groupByExpressions) {
return groupByExpressions != null && groupByExpressions.getGroupByNodes() != null && groupByExpressions.getGroupByNodes().length != 0;
}
private static boolean aggregated(ExprSubselectNode.SubqueryAggregationType subqueryAggregationType) {
return subqueryAggregationType != null && subqueryAggregationType != ExprSubselectNode.SubqueryAggregationType.NONE;
}
}