/* *************************************************************************************** * 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.join.exec.base; import com.espertech.esper.client.EventBean; import com.espertech.esper.epl.expression.core.ExprEvaluatorContext; import com.espertech.esper.util.IndentWriter; import java.util.Collection; import java.util.LinkedList; import java.util.List; /** * Execution node that performs a nested iteration over all child nodes. * <p> * Each child node under this node typically represents a table lookup. The implementation * 'hops' from the first child to the next recursively for each row returned by a child. * <p> * It passes a 'prototype' row (prefillPath) to each new child which contains the current partial event set. */ public class NestedIterationExecNode extends ExecNode { private final LinkedList<ExecNode> childNodes; private final int[] nestedStreams; private int nestingOrderLength; /** * Ctor. * * @param nestedStreams - array of integers defining order of streams in nested join. */ public NestedIterationExecNode(int[] nestedStreams) { this.nestedStreams = nestedStreams; this.childNodes = new LinkedList<ExecNode>(); } /** * Add a child node. * * @param childNode to add */ public void addChildNode(ExecNode childNode) { childNodes.add(childNode); } public void process(EventBean lookupEvent, EventBean[] prefillPath, Collection<EventBean[]> result, ExprEvaluatorContext exprEvaluatorContext) { nestingOrderLength = childNodes.size(); recursiveNestedJoin(lookupEvent, 0, prefillPath, result, exprEvaluatorContext); } /** * Recursive method to run through all child nodes and, for each result set tuple returned * by a child node, execute the inner child of the child node until there are no inner child nodes. * * @param lookupEvent - current event to use for lookup by child node * @param nestingOrderIndex - index within the child nodes indicating what nesting level we are at * @param currentPath - prototype result row to use by child nodes for generating result rows * @param result - result tuple rows to be populated * @param exprEvaluatorContext context for expression evalauation */ protected void recursiveNestedJoin(EventBean lookupEvent, int nestingOrderIndex, EventBean[] currentPath, Collection<EventBean[]> result, ExprEvaluatorContext exprEvaluatorContext) { List<EventBean[]> nestedResult = new LinkedList<EventBean[]>(); ExecNode nestedExecNode = childNodes.get(nestingOrderIndex); nestedExecNode.process(lookupEvent, currentPath, nestedResult, exprEvaluatorContext); boolean isLastStream = nestingOrderIndex == nestingOrderLength - 1; // This is not the last nesting level so no result rows are added. Invoke next nesting level for // each event found. if (!isLastStream) { for (EventBean[] row : nestedResult) { EventBean lookup = row[nestedStreams[nestingOrderIndex]]; recursiveNestedJoin(lookup, nestingOrderIndex + 1, row, result, exprEvaluatorContext); } return; } // Loop to add result rows for (EventBean[] row : nestedResult) { result.add(row); } } public void print(IndentWriter writer) { writer.println("NestedIterationExecNode"); writer.incrIndent(); for (ExecNode child : childNodes) { child.print(writer); } writer.decrIndent(); } }