/** * diqube: Distributed Query Base. * * Copyright (C) 2015 Bastian Gloeckle * * This file is part of diqube. * * diqube is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.diqube.plan.planner; import java.util.ArrayList; import java.util.List; import java.util.function.Function; import java.util.function.Supplier; import org.diqube.diql.request.ComparisonRequest; import org.diqube.diql.request.ComparisonRequest.And; import org.diqube.diql.request.ComparisonRequest.Leaf; import org.diqube.diql.request.ComparisonRequest.Not; import org.diqube.diql.request.ComparisonRequest.Or; import org.diqube.execution.consumers.RowIdConsumer; import org.diqube.plan.RemoteExecutionPlanFactory; import org.diqube.remote.cluster.thrift.RExecutionPlanStep; import org.diqube.remote.cluster.thrift.RExecutionPlanStepType; import org.diqube.util.ColumnOrValue; import org.diqube.util.Pair; import org.diqube.util.Triple; /** * Builder that handles {@link ComparisonRequest}s in a WHERE clause - these are fully handled by cluster nodes. * * @author Bastian Gloeckle */ public class WhereBuilder implements ComparisonRequestBuilder<RExecutionPlanStep> { private RemoteExecutionPlanFactory remoteExecutionPlanFactory; private Supplier<Integer> nextRemoteStepIdSupplier; private ColumnManager<RExecutionPlanStep> columnManager; private RemoteWireManager remoteWireManager; public WhereBuilder(RemoteExecutionPlanFactory remoteExecutionPlanFactory, Supplier<Integer> nextRemoteStepIdSupplier, ColumnManager<RExecutionPlanStep> columnManager, RemoteWireManager remoteWireManager) { this.remoteExecutionPlanFactory = remoteExecutionPlanFactory; this.nextRemoteStepIdSupplier = nextRemoteStepIdSupplier; this.columnManager = columnManager; this.remoteWireManager = remoteWireManager; } @Override public Pair<RExecutionPlanStep, List<RExecutionPlanStep>> build(ComparisonRequest comparisonRoot) { List<RExecutionPlanStep> allWhereSteps = new ArrayList<>(); RExecutionPlanStep whereRootStep = ComparisonRequestUtil.walkComparisonTreeAndCreate(comparisonRoot, new Function<Triple<ComparisonRequest, RExecutionPlanStep, RExecutionPlanStep>, RExecutionPlanStep>() { @Override public RExecutionPlanStep apply(Triple<ComparisonRequest, RExecutionPlanStep, RExecutionPlanStep> t) { RExecutionPlanStep res = null; if (t.getLeft() instanceof Leaf) { Leaf leaf = (Leaf) t.getLeft(); RExecutionPlanStepType type = null; switch (leaf.getOp()) { case EQ: type = RExecutionPlanStepType.ROW_ID_EQ; break; case GT_EQ: type = RExecutionPlanStepType.ROW_ID_GT_EQ; break; case GT: type = RExecutionPlanStepType.ROW_ID_GT; break; case LT_EQ: type = RExecutionPlanStepType.ROW_ID_LT_EQ; break; case LT: type = RExecutionPlanStepType.ROW_ID_LT; break; // TODO #21 support BETWEEN } res = remoteExecutionPlanFactory.createRowIdComparison(leaf, nextRemoteStepIdSupplier.get(), type); // if this step is based on any column that needs to be created (as we're in the where stmt which // cannot contain aggregate functions, these columns that need to be created need to be // projections!), we need to wait for their creation. Wire accordingly. columnManager.wireOutputOfColumnIfAvailable(leaf.getLeftColumnName(), res); if (leaf.getRight().getType().equals(ColumnOrValue.Type.COLUMN)) columnManager.wireOutputOfColumnIfAvailable(leaf.getRight().getColumnName(), res); allWhereSteps.add(res); return res; } else if (t.getLeft() instanceof Not) { RExecutionPlanStep childStep = t.getMiddle(); res = remoteExecutionPlanFactory.createRowIdNot(nextRemoteStepIdSupplier.get()); remoteWireManager.wire(RowIdConsumer.class, childStep, res); allWhereSteps.add(res); return res; } else if (t.getLeft() instanceof And) { res = remoteExecutionPlanFactory.createRowIdAnd(nextRemoteStepIdSupplier.get()); } else if (t.getLeft() instanceof Or) { res = remoteExecutionPlanFactory.createRowIdOr(nextRemoteStepIdSupplier.get()); } // wire row ID flow. remoteWireManager.wire(RowIdConsumer.class, t.getMiddle(), res); remoteWireManager.wire(RowIdConsumer.class, t.getRight(), res); allWhereSteps.add(res); return res; } }); return new Pair<>(whereRootStep, allWhereSteps); } }