@Override
public PhysicalOperation visitUnion(UnionNode node, LocalExecutionPlanContext context)
{
List<TupleInfo> tupleInfos = getSourceOperatorTupleInfos(node, context.getTypes());
InMemoryExchange inMemoryExchange = new InMemoryExchange(tupleInfos);
for (int i = 0; i < node.getSources().size(); i++) {
PlanNode subplan = node.getSources().get(i);
List<Symbol> expectedLayout = node.sourceOutputLayout(i);
LocalExecutionPlanContext subContext = context.createSubContext();
PhysicalOperation source = subplan.accept(this, subContext);
List<OperatorFactory> operatorFactories = new ArrayList<>(source.getOperatorFactories());
boolean projectionMatchesOutput = IterableTransformer.on(source.getLayout().entries())
.orderBy(inputOrdering().onResultOf(MoreFunctions.<Symbol, Input>valueGetter()))
.transform(MoreFunctions.<Symbol, Input>keyGetter())
.list()
.equals(expectedLayout);
if (!projectionMatchesOutput) {
IdentityProjectionInfo mappings = computeIdentityMapping(expectedLayout, source.getLayout(), context.getTypes());
operatorFactories.add(new FilterAndProjectOperatorFactory(subContext.getNextOperatorId(), FilterFunctions.TRUE_FUNCTION, mappings.getProjections()));
}
operatorFactories.add(inMemoryExchange.createSinkFactory(subContext.getNextOperatorId()));
DriverFactory driverFactory = new DriverFactory(subContext.isInputDriver(), false, operatorFactories);
context.addDriverFactory(driverFactory);
}
inMemoryExchange.noMoreSinkFactories();
// the main driver is not an input... the union sources are the input for the plan
context.setInputDriver(false);
// Fow now, we assume that subplans always produce one symbol per channel. TODO: remove this assumption