/*
***************************************************************************************
* 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.client.EventBean;
import com.espertech.esper.client.EventType;
import com.espertech.esper.epl.agg.service.AggregationService;
import com.espertech.esper.epl.core.StreamTypeService;
import com.espertech.esper.epl.expression.core.*;
import com.espertech.esper.epl.spec.StatementSpecCompiled;
import com.espertech.esper.epl.spec.StatementSpecRaw;
import com.espertech.esper.metrics.instrumentation.InstrumentationHelper;
import java.io.StringWriter;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
/**
* Represents a subselect in an expression tree.
*/
public abstract class ExprSubselectNode extends ExprNodeBase implements ExprEvaluator, ExprEvaluatorEnumeration, ExprEvaluatorTypableReturn {
public static final ExprSubselectNode[] EMPTY_SUBSELECT_ARRAY = new ExprSubselectNode[0];
private static final long serialVersionUID = -2469169635913155764L;
/**
* The validated select clause.
*/
protected ExprNode[] selectClause;
protected transient ExprEvaluator[] selectClauseEvaluator;
protected String[] selectAsNames;
/**
* The validate filter expression.
*/
protected transient ExprEvaluator filterExpr;
/**
* The validated having expression.
*/
protected transient ExprEvaluator havingExpr;
/**
* The event type generated for wildcard selects.
*/
protected transient EventType rawEventType;
protected String statementName;
private transient StreamTypeService filterSubqueryStreamTypes;
private StatementSpecRaw statementSpecRaw;
private transient StatementSpecCompiled statementSpecCompiled;
private transient ExprSubselectStrategy strategy;
private transient SubqueryAggregationType subselectAggregationType;
protected int subselectNumber;
private boolean filterStreamSubselect;
protected transient AggregationService subselectAggregationService;
/**
* Evaluate the lookup expression returning an evaluation result object.
*
* @param eventsPerStream is the events for each stream in a join
* @param isNewData is true for new data, or false for old data
* @param matchingEvents is filtered results from the table of stored lookup events
* @param exprEvaluatorContext context for expression evalauation
* @return evaluation result
*/
public abstract Object evaluate(EventBean[] eventsPerStream, boolean isNewData, Collection<EventBean> matchingEvents, ExprEvaluatorContext exprEvaluatorContext);
public abstract Collection<EventBean> evaluateGetCollEvents(EventBean[] eventsPerStream, boolean isNewData, Collection<EventBean> matchingEvents, ExprEvaluatorContext exprEvaluatorContext);
public abstract Collection evaluateGetCollScalar(EventBean[] eventsPerStream, boolean isNewData, Collection<EventBean> matchingEvents, ExprEvaluatorContext exprEvaluatorContext);
public abstract EventBean evaluateGetEventBean(EventBean[] eventsPerStream, boolean isNewData, Collection<EventBean> matchingEvents, ExprEvaluatorContext exprEvaluatorContext);
public abstract boolean isAllowMultiColumnSelect();
public abstract void validateSubquery(ExprValidationContext validationContext) throws ExprValidationException;
public abstract LinkedHashMap<String, Object> typableGetRowProperties() throws ExprValidationException;
public abstract Object[] evaluateTypableSingle(EventBean[] eventsPerStream, boolean isNewData, Collection<EventBean> matchingEvents, ExprEvaluatorContext exprEvaluatorContext);
public abstract Object[][] evaluateTypableMulti(EventBean[] eventsPerStream, boolean isNewData, Collection<EventBean> matchingEvents, ExprEvaluatorContext exprEvaluatorContext);
/**
* Ctor.
*
* @param statementSpec is the lookup statement spec from the parser, unvalidated
*/
public ExprSubselectNode(StatementSpecRaw statementSpec) {
this.statementSpecRaw = statementSpec;
}
public ExprEvaluator getExprEvaluator() {
return this;
}
public boolean isConstantResult() {
return false;
}
public ExprNode validate(ExprValidationContext validationContext) throws ExprValidationException {
this.statementName = validationContext.getStatementName();
validateSubquery(validationContext);
return null;
}
/**
* Supplies a compiled statement spec.
*
* @param statementSpecCompiled compiled validated filters
* @param subselectNumber subselect assigned number
*/
public void setStatementSpecCompiled(StatementSpecCompiled statementSpecCompiled, int subselectNumber) {
this.statementSpecCompiled = statementSpecCompiled;
this.subselectNumber = subselectNumber;
}
/**
* Returns the compiled statement spec.
*
* @return compiled statement
*/
public StatementSpecCompiled getStatementSpecCompiled() {
return statementSpecCompiled;
}
/**
* Sets the validate select clause
*
* @param selectClause is the expression representing the select clause
*/
public void setSelectClause(ExprNode[] selectClause) {
this.selectClause = selectClause;
this.selectClauseEvaluator = ExprNodeUtility.getEvaluators(selectClause);
}
public Object evaluate(EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext) {
if (InstrumentationHelper.ENABLED) {
InstrumentationHelper.get().qExprSubselect(this);
Collection<EventBean> matchingEvents = evaluateMatching(eventsPerStream, exprEvaluatorContext);
Object result = evaluate(eventsPerStream, isNewData, matchingEvents, exprEvaluatorContext);
InstrumentationHelper.get().aExprSubselect(result);
return result;
}
Collection<EventBean> matchingEvents = evaluateMatching(eventsPerStream, exprEvaluatorContext);
return evaluate(eventsPerStream, isNewData, matchingEvents, exprEvaluatorContext);
}
public Collection<EventBean> evaluateGetROCollectionEvents(EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext) {
Collection<EventBean> matchingEvents = evaluateMatching(eventsPerStream, exprEvaluatorContext);
return evaluateGetCollEvents(eventsPerStream, isNewData, matchingEvents, exprEvaluatorContext);
}
public Collection evaluateGetROCollectionScalar(EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext) {
Collection<EventBean> matchingEvents = evaluateMatching(eventsPerStream, exprEvaluatorContext);
return evaluateGetCollScalar(eventsPerStream, isNewData, matchingEvents, exprEvaluatorContext);
}
public EventBean evaluateGetEventBean(EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext context) {
Collection<EventBean> matchingEvents = evaluateMatching(eventsPerStream, context);
return evaluateGetEventBean(eventsPerStream, isNewData, matchingEvents, context);
}
private Collection<EventBean> evaluateMatching(EventBean[] eventsPerStream, ExprEvaluatorContext exprEvaluatorContext) {
return strategy.evaluateMatching(eventsPerStream, exprEvaluatorContext);
}
public LinkedHashMap<String, Object> getRowProperties() throws ExprValidationException {
return typableGetRowProperties();
}
public Boolean isMultirow() {
return true; // subselect can always return multiple rows
}
public Object[] evaluateTypableSingle(EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext context) {
Collection<EventBean> matching = strategy.evaluateMatching(eventsPerStream, context);
return evaluateTypableSingle(eventsPerStream, isNewData, matching, context);
}
public Object[][] evaluateTypableMulti(EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext context) {
Collection<EventBean> matching = strategy.evaluateMatching(eventsPerStream, context);
return evaluateTypableMulti(eventsPerStream, isNewData, matching, context);
}
/**
* Returns the uncompiled statement spec.
*
* @return statement spec uncompiled
*/
public StatementSpecRaw getStatementSpecRaw() {
return statementSpecRaw;
}
/**
* Supplies the name of the select expression as-tag
*
* @param selectAsNames is the as-name(s)
*/
public void setSelectAsNames(String[] selectAsNames) {
this.selectAsNames = selectAsNames;
}
/**
* Sets the validated filter expression, or null if there is none.
*
* @param filterExpr is the filter
*/
public void setFilterExpr(ExprEvaluator filterExpr) {
this.filterExpr = filterExpr;
}
public void setHavingExpr(ExprEvaluator havingExpr) {
this.havingExpr = havingExpr;
}
public void toPrecedenceFreeEPL(StringWriter writer) {
if ((selectAsNames != null) && (selectAsNames[0] != null)) {
writer.append(selectAsNames[0]);
return;
}
writer.append("subselect_");
writer.append(Integer.toString(subselectNumber));
}
public ExprPrecedenceEnum getPrecedence() {
return ExprPrecedenceEnum.UNARY;
}
public boolean equalsNode(ExprNode node, boolean ignoreStreamPrefix) {
return false; // 2 subselects are never equivalent
}
/**
* Sets the strategy for boiling down the table of lookup events into a subset against which to run the filter.
*
* @param strategy is the looking strategy (full table scan or indexed)
*/
public void setStrategy(ExprSubselectStrategy strategy) {
this.strategy = strategy;
}
/**
* Sets the event type generated for wildcard selects.
*
* @param rawEventType is the wildcard type (parent view)
*/
public void setRawEventType(EventType rawEventType) {
this.rawEventType = rawEventType;
}
/**
* Returns the select clause or null if none.
*
* @return clause
*/
public ExprNode[] getSelectClause() {
return selectClause;
}
/**
* Returns filter expr or null if none.
*
* @return filter
*/
public ExprEvaluator getFilterExpr() {
return filterExpr;
}
public ExprEvaluator getHavingExpr() {
return havingExpr;
}
/**
* Returns the event type.
*
* @return type
*/
public EventType getRawEventType() {
return rawEventType;
}
/**
* Return stream types.
*
* @return types
*/
public StreamTypeService getFilterSubqueryStreamTypes() {
return filterSubqueryStreamTypes;
}
/**
* Set stream types.
*
* @param filterSubqueryStreamTypes types
*/
public void setFilterSubqueryStreamTypes(StreamTypeService filterSubqueryStreamTypes) {
this.filterSubqueryStreamTypes = filterSubqueryStreamTypes;
}
public SubqueryAggregationType getSubselectAggregationType() {
return subselectAggregationType;
}
public void setSubselectAggregationType(SubqueryAggregationType subselectAggregationType) {
this.subselectAggregationType = subselectAggregationType;
}
public int getSubselectNumber() {
return subselectNumber;
}
public void setFilterStreamSubselect(boolean filterStreamSubselect) {
this.filterStreamSubselect = filterStreamSubselect;
}
public boolean isFilterStreamSubselect() {
return filterStreamSubselect;
}
public static ExprSubselectNode[] toArray(List<ExprSubselectNode> subselectNodes) {
if (subselectNodes.isEmpty()) {
return EMPTY_SUBSELECT_ARRAY;
}
return subselectNodes.toArray(new ExprSubselectNode[subselectNodes.size()]);
}
public void setSubselectAggregationService(AggregationService subselectAggregationService) {
this.subselectAggregationService = subselectAggregationService;
}
public AggregationService getSubselectAggregationService() {
return subselectAggregationService;
}
public static enum SubqueryAggregationType {
NONE,
FULLY_AGGREGATED_NOPROPS,
FULLY_AGGREGATED_WPROPS
}
}