com.espertech.esper.epl.core.ResultSetProcessorSimple.java Source code

Java tutorial

Introduction

Here is the source code for com.espertech.esper.epl.core.ResultSetProcessorSimple.java

Source

/**************************************************************************************
 * 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.epl.core;

import com.espertech.esper.client.EventBean;
import com.espertech.esper.client.EventType;
import com.espertech.esper.collection.*;
import com.espertech.esper.core.context.util.AgentInstanceContext;
import com.espertech.esper.epl.expression.ExprEvaluator;
import com.espertech.esper.epl.expression.ExprEvaluatorContext;
import com.espertech.esper.util.CollectionUtil;
import com.espertech.esper.view.Viewable;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.util.*;

/**
 * Result set processor for the simplest case: no aggregation functions used in the select clause, and no group-by.
 * <p>
 * The processor generates one row for each event entering (new event) and one row for each event leaving (old event).
 */
public class ResultSetProcessorSimple extends ResultSetProcessorBaseSimple {
    private static final Log log = LogFactory.getLog(ResultSetProcessorSimple.class);

    private final ResultSetProcessorSimpleFactory prototype;
    private final SelectExprProcessor selectExprProcessor;
    private final OrderByProcessor orderByProcessor;
    private ExprEvaluatorContext exprEvaluatorContext;

    public ResultSetProcessorSimple(ResultSetProcessorSimpleFactory prototype,
            SelectExprProcessor selectExprProcessor, OrderByProcessor orderByProcessor,
            ExprEvaluatorContext exprEvaluatorContext) {
        this.prototype = prototype;
        this.selectExprProcessor = selectExprProcessor;
        this.orderByProcessor = orderByProcessor;
        this.exprEvaluatorContext = exprEvaluatorContext;
    }

    public void setAgentInstanceContext(AgentInstanceContext context) {
        exprEvaluatorContext = context;
    }

    public EventType getResultEventType() {
        return prototype.getResultEventType();
    }

    public UniformPair<EventBean[]> processJoinResult(Set<MultiKey<EventBean>> newEvents,
            Set<MultiKey<EventBean>> oldEvents, boolean isSynthesize) {
        EventBean[] selectOldEvents = null;
        EventBean[] selectNewEvents;

        if (prototype.getOptionalHavingExpr() == null) {
            if (prototype.isSelectRStream()) {
                selectOldEvents = getSelectEventsNoHaving(selectExprProcessor, orderByProcessor, oldEvents, false,
                        isSynthesize, exprEvaluatorContext);
            }
            selectNewEvents = getSelectEventsNoHaving(selectExprProcessor, orderByProcessor, newEvents, true,
                    isSynthesize, exprEvaluatorContext);
        } else {
            if (prototype.isSelectRStream()) {
                selectOldEvents = getSelectEventsHaving(selectExprProcessor, orderByProcessor, oldEvents,
                        prototype.getOptionalHavingExpr(), false, isSynthesize, exprEvaluatorContext);
            }
            selectNewEvents = getSelectEventsHaving(selectExprProcessor, orderByProcessor, newEvents,
                    prototype.getOptionalHavingExpr(), true, isSynthesize, exprEvaluatorContext);
        }

        return new UniformPair<EventBean[]>(selectNewEvents, selectOldEvents);
    }

    public UniformPair<EventBean[]> processViewResult(EventBean[] newData, EventBean[] oldData,
            boolean isSynthesize) {
        EventBean[] selectOldEvents = null;
        EventBean[] selectNewEvents;
        if (prototype.getOptionalHavingExpr() == null) {
            if (prototype.isSelectRStream()) {
                selectOldEvents = getSelectEventsNoHaving(selectExprProcessor, orderByProcessor, oldData, false,
                        isSynthesize, exprEvaluatorContext);
            }
            selectNewEvents = getSelectEventsNoHaving(selectExprProcessor, orderByProcessor, newData, true,
                    isSynthesize, exprEvaluatorContext);
        } else {
            if (prototype.isSelectRStream()) {
                selectOldEvents = getSelectEventsHaving(selectExprProcessor, orderByProcessor, oldData,
                        prototype.getOptionalHavingExpr(), false, isSynthesize, exprEvaluatorContext);
            }
            selectNewEvents = getSelectEventsHaving(selectExprProcessor, orderByProcessor, newData,
                    prototype.getOptionalHavingExpr(), true, isSynthesize, exprEvaluatorContext);
        }

        return new UniformPair<EventBean[]>(selectNewEvents, selectOldEvents);
    }

    /**
     * Process view results for the iterator.
     * @param newData new events
     * @return pair of insert and remove stream
     */
    public UniformPair<EventBean[]> processViewResultIterator(EventBean[] newData) {
        EventBean[] selectOldEvents = null;
        EventBean[] selectNewEvents;
        if (prototype.getOptionalHavingExpr() == null) {
            selectNewEvents = getSelectEventsNoHaving(selectExprProcessor, null, newData, true, true,
                    exprEvaluatorContext);
        } else {
            selectNewEvents = getSelectEventsHaving(selectExprProcessor, null, newData,
                    prototype.getOptionalHavingExpr(), true, true, exprEvaluatorContext);
        }

        return new UniformPair<EventBean[]>(selectNewEvents, selectOldEvents);
    }

    /**
     * Applies the select-clause to the given events returning the selected events. The number of events stays the
     * same, i.e. this method does not filter it just transforms the result set.
     * @param exprProcessor - processes each input event and returns output event
     * @param orderByProcessor - orders the outgoing events according to the order-by clause
     * @param events - input events
     * @param isNewData - indicates whether we are dealing with new data (istream) or old data (rstream)
     * @param isSynthesize - set to true to indicate that synthetic events are required for an iterator result set
     * @param exprEvaluatorContext context for expression evalauation
     * @return output events, one for each input event
     */
    protected static EventBean[] getSelectEventsNoHaving(SelectExprProcessor exprProcessor,
            OrderByProcessor orderByProcessor, EventBean[] events, boolean isNewData, boolean isSynthesize,
            ExprEvaluatorContext exprEvaluatorContext) {
        if (events == null) {
            return null;
        }

        EventBean[] result = new EventBean[events.length];
        EventBean[][] eventGenerators = null;
        if (orderByProcessor != null) {
            eventGenerators = new EventBean[events.length][];
        }

        EventBean[] eventsPerStream = new EventBean[1];
        for (int i = 0; i < events.length; i++) {
            eventsPerStream[0] = events[i];

            // Wildcard select case
            if (exprProcessor == null) {
                result[i] = events[i];
            } else {
                result[i] = exprProcessor.process(eventsPerStream, isNewData, isSynthesize, exprEvaluatorContext);
            }

            if (orderByProcessor != null) {
                eventGenerators[i] = new EventBean[] { events[i] };
            }
        }

        if (orderByProcessor != null) {
            return orderByProcessor.sort(result, eventGenerators, isNewData, exprEvaluatorContext);
        } else {
            return result;
        }
    }

    /**
     * Applies the select-clause to the given events returning the selected events. The number of events stays the
     * same, i.e. this method does not filter it just transforms the result set.
     * @param exprProcessor - processes each input event and returns output event
     * @param orderByProcessor - for sorting output events according to the order-by clause
     * @param events - input events
     * @param isNewData - indicates whether we are dealing with new data (istream) or old data (rstream)
     * @param isSynthesize - set to true to indicate that synthetic events are required for an iterator result set
     * @param exprEvaluatorContext context for expression evalauation
     * @return output events, one for each input event
     */
    protected static EventBean[] getSelectEventsNoHaving(SelectExprProcessor exprProcessor,
            OrderByProcessor orderByProcessor, Set<MultiKey<EventBean>> events, boolean isNewData,
            boolean isSynthesize, ExprEvaluatorContext exprEvaluatorContext) {
        if ((events == null) || (events.isEmpty())) {
            return null;
        }
        int length = events.size();

        EventBean[] result = new EventBean[length];
        EventBean[][] eventGenerators = null;
        if (orderByProcessor != null) {
            eventGenerators = new EventBean[length][];
        }

        int count = 0;
        for (MultiKey<EventBean> key : events) {
            EventBean[] eventsPerStream = key.getArray();
            result[count] = exprProcessor.process(eventsPerStream, isNewData, isSynthesize, exprEvaluatorContext);
            if (orderByProcessor != null) {
                eventGenerators[count] = eventsPerStream;
            }
            count++;
        }

        if (orderByProcessor != null) {
            return orderByProcessor.sort(result, eventGenerators, isNewData, exprEvaluatorContext);
        } else {
            return result;
        }
    }

    /**
     * Applies the select-clause to the given events returning the selected events. The number of events stays the
     * same, i.e. this method does not filter it just transforms the result set.
     * <p>
     * Also applies a having clause.
     * @param exprProcessor - processes each input event and returns output event
     * @param orderByProcessor - for sorting output events according to the order-by clause
     * @param events - input events
     * @param optionalHavingNode - supplies the having-clause expression
     * @param isNewData - indicates whether we are dealing with new data (istream) or old data (rstream)
     * @param isSynthesize - set to true to indicate that synthetic events are required for an iterator result set
     * @param exprEvaluatorContext context for expression evalauation
     * @return output events, one for each input event
     */
    protected static EventBean[] getSelectEventsHaving(SelectExprProcessor exprProcessor,
            OrderByProcessor orderByProcessor, EventBean[] events, ExprEvaluator optionalHavingNode,
            boolean isNewData, boolean isSynthesize, ExprEvaluatorContext exprEvaluatorContext) {
        if (events == null) {
            return null;
        }

        LinkedList<EventBean> result = new LinkedList<EventBean>();
        List<EventBean[]> eventGenerators = null;
        if (orderByProcessor != null) {
            eventGenerators = new ArrayList<EventBean[]>();
        }

        EventBean[] eventsPerStream = new EventBean[1];
        for (EventBean theEvent : events) {
            eventsPerStream[0] = theEvent;

            Boolean passesHaving = (Boolean) optionalHavingNode.evaluate(eventsPerStream, isNewData,
                    exprEvaluatorContext);
            if ((passesHaving == null) || (!passesHaving)) {
                continue;
            }

            result.add(exprProcessor.process(eventsPerStream, isNewData, isSynthesize, exprEvaluatorContext));
            if (orderByProcessor != null) {
                eventGenerators.add(new EventBean[] { theEvent });
            }
        }

        if (!result.isEmpty()) {
            if (orderByProcessor != null) {
                return orderByProcessor.sort(result.toArray(new EventBean[result.size()]),
                        eventGenerators.toArray(new EventBean[eventGenerators.size()][]), isNewData,
                        exprEvaluatorContext);
            } else {
                return result.toArray(new EventBean[result.size()]);
            }
        } else {
            return null;
        }
    }

    /**
     * Applies the select-clause to the given events returning the selected events. The number of events stays the
     * same, i.e. this method does not filter it just transforms the result set.
     * <p>
     * Also applies a having clause.
     * @param exprProcessor - processes each input event and returns output event
     * @param orderByProcessor - for sorting output events according to the order-by clause
     * @param events - input events
     * @param optionalHavingNode - supplies the having-clause expression
     * @param isNewData - indicates whether we are dealing with new data (istream) or old data (rstream)
     * @param isSynthesize - set to true to indicate that synthetic events are required for an iterator result set
     * @param exprEvaluatorContext context for expression evalauation
     * @return output events, one for each input event
     */
    protected static EventBean[] getSelectEventsHaving(SelectExprProcessor exprProcessor,
            OrderByProcessor orderByProcessor, Set<MultiKey<EventBean>> events, ExprEvaluator optionalHavingNode,
            boolean isNewData, boolean isSynthesize, ExprEvaluatorContext exprEvaluatorContext) {
        if ((events == null) || (events.isEmpty())) {
            return null;
        }

        LinkedList<EventBean> result = new LinkedList<EventBean>();
        List<EventBean[]> eventGenerators = null;
        if (orderByProcessor != null) {
            eventGenerators = new ArrayList<EventBean[]>();
        }

        for (MultiKey<EventBean> key : events) {
            EventBean[] eventsPerStream = key.getArray();

            Boolean passesHaving = (Boolean) optionalHavingNode.evaluate(eventsPerStream, isNewData,
                    exprEvaluatorContext);
            if ((passesHaving == null) || (!passesHaving)) {
                continue;
            }

            EventBean resultEvent = exprProcessor.process(eventsPerStream, isNewData, isSynthesize,
                    exprEvaluatorContext);
            result.add(resultEvent);
            if (orderByProcessor != null) {
                eventGenerators.add(eventsPerStream);
            }
        }

        if (!result.isEmpty()) {
            if (orderByProcessor != null) {
                return orderByProcessor.sort(result.toArray(new EventBean[result.size()]),
                        eventGenerators.toArray(new EventBean[eventGenerators.size()][]), isNewData,
                        exprEvaluatorContext);
            } else {
                return result.toArray(new EventBean[result.size()]);
            }
        } else {
            return null;
        }
    }

    public Iterator<EventBean> getIterator(Viewable parent) {
        if (orderByProcessor != null) {
            // Pull all events, generate order keys
            EventBean[] eventsPerStream = new EventBean[1];
            List<EventBean> events = new ArrayList<EventBean>();
            List<Object> orderKeys = new ArrayList<Object>();
            Iterator parentIterator = parent.iterator();
            if (parentIterator == null) {
                return CollectionUtil.NULL_EVENT_ITERATOR;
            }
            for (EventBean aParent : parent) {
                eventsPerStream[0] = aParent;
                Object orderKey = orderByProcessor.getSortKey(eventsPerStream, true, exprEvaluatorContext);
                UniformPair<EventBean[]> pair = processViewResultIterator(eventsPerStream);
                EventBean[] result = pair.getFirst();
                if (result.length != 0) {
                    events.add(result[0]);
                }
                orderKeys.add(orderKey);
            }

            // sort
            EventBean[] outgoingEvents = events.toArray(new EventBean[events.size()]);
            Object[] orderKeysArr = orderKeys.toArray(new Object[orderKeys.size()]);
            EventBean[] orderedEvents = orderByProcessor.sort(outgoingEvents, orderKeysArr, exprEvaluatorContext);

            return new ArrayEventIterator(orderedEvents);
        }
        // Return an iterator that gives row-by-row a result
        return new TransformEventIterator(parent.iterator(), new ResultSetProcessorSimpleTransform(this));
    }

    public Iterator<EventBean> getIterator(Set<MultiKey<EventBean>> joinSet) {
        // Process join results set as a regular join, includes sorting and having-clause filter
        UniformPair<EventBean[]> result = processJoinResult(joinSet, CollectionUtil.EMPTY_ROW_SET, true);
        return new ArrayEventIterator(result.getFirst());
    }

    public void clear() {
        // No need to clear state, there is no state held
    }

    /**
     * Applies the select-clause to the given events returning the selected events. The number of events stays the
     * same, i.e. this method does not filter it just transforms the result set.
     * @param exprProcessor - processes each input event and returns output event
     * @param events - input events
     * @param isNewData - indicates whether we are dealing with new data (istream) or old data (rstream)
     * @param isSynthesize - set to true to indicate that synthetic events are required for an iterator result set
     * @return output events, one for each input event
     */
    protected static EventBean[] getSelectEventsNoHaving(SelectExprProcessor exprProcessor, EventBean[] events,
            boolean isNewData, boolean isSynthesize, ExprEvaluatorContext exprEvaluatorContext) {
        if (events == null) {
            return null;
        }

        EventBean[] result = new EventBean[events.length];
        EventBean[] eventsPerStream = new EventBean[1];
        for (int i = 0; i < events.length; i++) {
            eventsPerStream[0] = events[i];
            result[i] = exprProcessor.process(eventsPerStream, isNewData, isSynthesize, exprEvaluatorContext);
        }

        return result;
    }

    /**
     * Applies the select-clause to the given events returning the selected events. The number of events stays the
     * same, i.e. this method does not filter it just transforms the result set.
     * @param exprProcessor - processes each input event and returns output event
     * @param events - input events
     * @param isNewData - indicates whether we are dealing with new data (istream) or old data (rstream)
     * @param isSynthesize - set to true to indicate that synthetic events are required for an iterator result set
     * @return output events, one for each input event
     */
    protected static EventBean[] getSelectEventsNoHaving(SelectExprProcessor exprProcessor,
            Set<MultiKey<EventBean>> events, boolean isNewData, boolean isSynthesize,
            ExprEvaluatorContext exprEvaluatorContext) {
        if ((events == null) || (events.isEmpty())) {
            return null;
        }
        int length = events.size();

        EventBean[] result = new EventBean[length];

        int count = 0;
        for (MultiKey<EventBean> key : events) {
            EventBean[] eventsPerStream = key.getArray();
            result[count] = exprProcessor.process(eventsPerStream, isNewData, isSynthesize, exprEvaluatorContext);
            count++;
        }

        return result;
    }

    /**
     * Applies the select-clause to the given events returning the selected events. The number of events stays the
     * same, i.e. this method does not filter it just transforms the result set.
     * <p>
     * Also applies a having clause.
     * @param exprProcessor - processes each input event and returns output event
     * @param events - input events
     * @param optionalHavingNode - supplies the having-clause expression
     * @param isNewData - indicates whether we are dealing with new data (istream) or old data (rstream)
     * @param isSynthesize - set to true to indicate that synthetic events are required for an iterator result set
     * @param exprEvaluatorContext context for expression evalauation
     * @return output events, one for each input event
     */
    protected static EventBean[] getSelectEventsHaving(SelectExprProcessor exprProcessor, EventBean[] events,
            ExprEvaluator optionalHavingNode, boolean isNewData, boolean isSynthesize,
            ExprEvaluatorContext exprEvaluatorContext) {
        if (events == null) {
            return null;
        }

        LinkedList<EventBean> result = new LinkedList<EventBean>();

        EventBean[] eventsPerStream = new EventBean[1];
        for (EventBean theEvent : events) {
            eventsPerStream[0] = theEvent;

            Boolean passesHaving = (Boolean) optionalHavingNode.evaluate(eventsPerStream, isNewData,
                    exprEvaluatorContext);
            if ((passesHaving == null) || (!passesHaving)) {
                continue;
            }

            result.add(exprProcessor.process(eventsPerStream, isNewData, isSynthesize, exprEvaluatorContext));
        }

        if (!result.isEmpty()) {
            return result.toArray(new EventBean[result.size()]);
        } else {
            return null;
        }
    }

    /**
     * Applies the select-clause to the given events returning the selected events. The number of events stays the
     * same, i.e. this method does not filter it just transforms the result set.
     * <p>
     * Also applies a having clause.
     * @param exprProcessor - processes each input event and returns output event
     * @param events - input events
     * @param optionalHavingNode - supplies the having-clause expression
     * @param isNewData - indicates whether we are dealing with new data (istream) or old data (rstream)
     * @param isSynthesize - set to true to indicate that synthetic events are required for an iterator result set
     * @param exprEvaluatorContext context for expression evalauation
     * @return output events, one for each input event
     */
    protected static EventBean[] getSelectEventsHaving(SelectExprProcessor exprProcessor,
            Set<MultiKey<EventBean>> events, ExprEvaluator optionalHavingNode, boolean isNewData,
            boolean isSynthesize, ExprEvaluatorContext exprEvaluatorContext) {
        LinkedList<EventBean> result = new LinkedList<EventBean>();

        for (MultiKey<EventBean> key : events) {
            EventBean[] eventsPerStream = key.getArray();

            Boolean passesHaving = (Boolean) optionalHavingNode.evaluate(eventsPerStream, isNewData,
                    exprEvaluatorContext);
            if ((passesHaving == null) || (!passesHaving)) {
                continue;
            }

            EventBean resultEvent = exprProcessor.process(eventsPerStream, isNewData, isSynthesize,
                    exprEvaluatorContext);
            result.add(resultEvent);
        }

        if (!result.isEmpty()) {
            return result.toArray(new EventBean[result.size()]);
        } else {
            return null;
        }
    }

    /**
     * Applies the select-clause to the given events returning the selected events. The number of events stays the
     * same, i.e. this method does not filter it just transforms the result set.
     * @param exprProcessor - processes each input event and returns output event
     * @param orderByProcessor - orders the outgoing events according to the order-by clause
     * @param events - input events
     * @param isNewData - indicates whether we are dealing with new data (istream) or old data (rstream)
     * @param isSynthesize - set to true to indicate that synthetic events are required for an iterator result set
     * @param result is the result event list to populate
     * @param exprEvaluatorContext context for expression evalauation
     * @param optSortKeys is the result sort key list to populate, for sorting
     */
    protected static void getSelectEventsNoHaving(SelectExprProcessor exprProcessor,
            OrderByProcessor orderByProcessor, EventBean[] events, boolean isNewData, boolean isSynthesize,
            List<EventBean> result, List<Object> optSortKeys, ExprEvaluatorContext exprEvaluatorContext) {
        if (events == null) {
            return;
        }

        EventBean[] eventsPerStream = new EventBean[1];
        for (EventBean theEvent : events) {
            eventsPerStream[0] = theEvent;

            result.add(exprProcessor.process(eventsPerStream, isNewData, isSynthesize, exprEvaluatorContext));
            if (orderByProcessor != null) {
                optSortKeys.add(orderByProcessor.getSortKey(eventsPerStream, isNewData, exprEvaluatorContext));
            }
        }
    }

    /**
     * Applies the select-clause to the given events returning the selected events. The number of events stays the
     * same, i.e. this method does not filter it just transforms the result set.
     * @param exprProcessor - processes each input event and returns output event
     * @param orderByProcessor - for sorting output events according to the order-by clause
     * @param events - input events
     * @param isNewData - indicates whether we are dealing with new data (istream) or old data (rstream)
     * @param isSynthesize - set to true to indicate that synthetic events are required for an iterator result set
     * @param result is the result event list to populate
     * @param optSortKeys is the result sort key list to populate, for sorting
     * @param exprEvaluatorContext context for expression evalauation
     */
    protected static void getSelectEventsNoHaving(SelectExprProcessor exprProcessor,
            OrderByProcessor orderByProcessor, Set<MultiKey<EventBean>> events, boolean isNewData,
            boolean isSynthesize, List<EventBean> result, List<Object> optSortKeys,
            ExprEvaluatorContext exprEvaluatorContext) {
        int length = (events != null) ? events.size() : 0;
        if (length == 0) {
            return;
        }

        for (MultiKey<EventBean> key : events) {
            EventBean[] eventsPerStream = key.getArray();
            result.add(exprProcessor.process(eventsPerStream, isNewData, isSynthesize, exprEvaluatorContext));
            if (orderByProcessor != null) {
                optSortKeys.add(orderByProcessor.getSortKey(eventsPerStream, isNewData, exprEvaluatorContext));
            }
        }
    }

    /**
     * Applies the select-clause to the given events returning the selected events. The number of events stays the
     * same, i.e. this method does not filter it just transforms the result set.
     * <p>
     * Also applies a having clause.
     * @param exprProcessor - processes each input event and returns output event
     * @param orderByProcessor - for sorting output events according to the order-by clause
     * @param events - input events
     * @param optionalHavingNode - supplies the having-clause expression
     * @param isNewData - indicates whether we are dealing with new data (istream) or old data (rstream)
     * @param isSynthesize - set to true to indicate that synthetic events are required for an iterator result set
     * @param result is the result event list to populate
     * @param exprEvaluatorContext context for expression evalauation
     * @param optSortKeys is the result sort key list to populate, for sorting
     */
    protected static void getSelectEventsHaving(SelectExprProcessor exprProcessor,
            OrderByProcessor orderByProcessor, EventBean[] events, ExprEvaluator optionalHavingNode,
            boolean isNewData, boolean isSynthesize, List<EventBean> result, List<Object> optSortKeys,
            ExprEvaluatorContext exprEvaluatorContext) {
        if (events == null) {
            return;
        }

        EventBean[] eventsPerStream = new EventBean[1];
        for (EventBean theEvent : events) {
            eventsPerStream[0] = theEvent;

            Boolean passesHaving = (Boolean) optionalHavingNode.evaluate(eventsPerStream, isNewData,
                    exprEvaluatorContext);
            if ((passesHaving == null) || (!passesHaving)) {
                continue;
            }

            result.add(exprProcessor.process(eventsPerStream, isNewData, isSynthesize, exprEvaluatorContext));
            if (orderByProcessor != null) {
                optSortKeys.add(orderByProcessor.getSortKey(eventsPerStream, isNewData, exprEvaluatorContext));
            }
        }
    }

    /**
     * Applies the select-clause to the given events returning the selected events. The number of events stays the
     * same, i.e. this method does not filter it just transforms the result set.
     * <p>
     * Also applies a having clause.
     * @param exprProcessor - processes each input event and returns output event
     * @param orderByProcessor - for sorting output events according to the order-by clause
     * @param events - input events
     * @param optionalHavingNode - supplies the having-clause expression
     * @param isNewData - indicates whether we are dealing with new data (istream) or old data (rstream)
     * @param isSynthesize - set to true to indicate that synthetic events are required for an iterator result set
     * @param result is the result event list to populate
     * @param optSortKeys is the result sort key list to populate, for sorting
     * @param exprEvaluatorContext context for expression evalauation
     */
    protected static void getSelectEventsHaving(SelectExprProcessor exprProcessor,
            OrderByProcessor orderByProcessor, Set<MultiKey<EventBean>> events, ExprEvaluator optionalHavingNode,
            boolean isNewData, boolean isSynthesize, List<EventBean> result, List<Object> optSortKeys,
            ExprEvaluatorContext exprEvaluatorContext) {
        if (events == null) {
            return;
        }
        for (MultiKey<EventBean> key : events) {
            EventBean[] eventsPerStream = key.getArray();

            Boolean passesHaving = (Boolean) optionalHavingNode.evaluate(eventsPerStream, isNewData,
                    exprEvaluatorContext);
            if ((passesHaving == null) || (!passesHaving)) {
                continue;
            }

            EventBean resultEvent = exprProcessor.process(eventsPerStream, isNewData, isSynthesize,
                    exprEvaluatorContext);
            result.add(resultEvent);
            if (orderByProcessor != null) {
                optSortKeys.add(orderByProcessor.getSortKey(eventsPerStream, isNewData, exprEvaluatorContext));
            }
        }
    }

    public boolean hasAggregation() {
        return false;
    }
}