/** * Copyright (C) 2009-2013 FoundationDB, LLC * * This program 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 com.foundationdb.sql.optimizer.plan; import com.foundationdb.ais.model.IndexColumn; import com.foundationdb.ais.model.Table; import com.foundationdb.util.Strings; import com.foundationdb.sql.optimizer.plan.Sort.OrderByExpression; import java.util.List; public final class MultiIndexIntersectScan extends IndexScan { private IndexScan outputScan; private IndexScan selectorScan; private int comparisonColumns; private List<ConditionExpression> conditions; public MultiIndexIntersectScan(IndexScan outerScan, IndexScan selectorScan, int comparisonColumns) { this(outerScan.getRootMostTable(), outerScan.getLeafMostTable()); assert outerScan.getRootMostTable() == outerScan.getRootMostInnerTable() : outerScan; assert outerScan.getLeafMostTable() == outerScan.getLeafMostInnerTable() : outerScan; this.outputScan = outerScan; this.selectorScan = selectorScan; this.comparisonColumns = comparisonColumns; } private MultiIndexIntersectScan(TableSource rootMost, TableSource leafMost) { super(rootMost, rootMost, leafMost, leafMost); } public IndexScan getOutputIndexScan() { return outputScan; } public IndexScan getSelectorIndexScan() { return selectorScan; } public int getComparisonFields() { return comparisonColumns; } public boolean[] getComparisonFieldDirections() { boolean[] ascending = new boolean[comparisonColumns]; for (int i = 0; i < comparisonColumns; i++) { ascending[i] = getOrdering().get(getPeggedCount() + i).isAscending(); } return ascending; } public int getOutputOrderingFields() { return getOrderingFields(outputScan); } public int getSelectorOrderingFields() { return getOrderingFields(selectorScan); } private int getOrderingFields(IndexScan scan) { return scan.getAllColumns().size() - scan.getPeggedCount(); } @Override public List<OrderByExpression> getOrdering() { return outputScan.getOrdering(); } @Override public OrderEffectiveness getOrderEffectiveness() { return outputScan.getOrderEffectiveness(); } @Override public List<ExpressionNode> getEqualityComparands() { return outputScan.getEqualityComparands(); } @Override public ExpressionNode getLowComparand() { return outputScan.getLowComparand(); } @Override public boolean isLowInclusive() { return outputScan.isLowInclusive(); } @Override public ExpressionNode getHighComparand() { return outputScan.getHighComparand(); } @Override public boolean isHighInclusive() { return outputScan.isHighInclusive(); } @Override public boolean isSpatial() { return outputScan.isSpatial(); } @Override public List<ConditionExpression> getConditions() { return conditions; } @Override public boolean hasConditions() { return !conditions.isEmpty(); } public void setConditions(List<ConditionExpression> conditions) { this.conditions = conditions; } @Override public List<ExpressionNode> getColumns() { return outputScan.getColumns(); } @Override public Table getLeafMostAisTable() { return outputScan.getLeafMostTable().getTable().getTable(); } @Override public List<IndexColumn> getAllColumns() { return outputScan.getAllColumns(); } @Override public int getNEquality() { return outputScan.getNEquality(); } @Override public int getNUnions() { return outputScan.getNUnions(); } @Override public void setIncludeUnionAsEquality(boolean sortColumn) { outputScan.setIncludeUnionAsEquality(sortColumn); } @Override public void incrementConditionsCounter(ConditionsCounter<? super ConditionExpression> counter) { outputScan.incrementConditionsCounter(counter); selectorScan.incrementConditionsCounter(counter); } @Override public boolean isUseful(ConditionsCount<? super ConditionExpression> count) { return outputScan.isUseful(count) && selectorScan.isUseful(count); } @Override public List<IndexColumn> getIndexColumns() { return outputScan.getIndexColumns(); } @Override public int getNKeyColumns() { return outputScan.getNKeyColumns(); } @Override public boolean usesAllColumns() { return outputScan.usesAllColumns(); } @Override public void setUsesAllColumns(boolean usesAllColumns) { outputScan.setUsesAllColumns(usesAllColumns); } @Override protected String summarizeIndex(int indentation, SummaryConfiguration configuration) { boolean pretty = indentation >= 0; int nextIndentation = pretty ? indentation + 1 : -1; StringBuilder sb = new StringBuilder(); if (pretty) { sb.append("compare ").append(getComparisonFields()).append(Strings.NL); indent(sb, nextIndentation); } else { sb.append("INTERSECT(compare ").append(getComparisonFields()).append(", "); } summarizeChildIndex(outputScan, nextIndentation, sb, configuration); if (pretty) { sb.append(Strings.NL); indent(sb, nextIndentation); } else { sb.append(" AND "); } summarizeChildIndex(selectorScan, nextIndentation, sb, configuration); if (!pretty) sb.append(')'); return sb.toString(); } private void summarizeChildIndex(IndexScan child, int indentation, StringBuilder sb, SummaryConfiguration configuration) { int skips = child.getAllColumns().size() - getOrderingFields(child); sb.append("skip ").append(skips).append(": "); child.buildSummaryString(sb, indentation, false, configuration); } @Override public boolean isAscendingAt(int i) { return outputScan.isAscendingAt(i); } @Override public boolean isRecoverableAt(int i) { return outputScan.isRecoverableAt(i); } @Override public Table findCommonAncestor(IndexScan other) { return outputScan.findCommonAncestor(other); } @Override public void visitComparands(ExpressionRewriteVisitor v) { outputScan.visitComparands(v); selectorScan.visitComparands(v); } @Override public void visitComparands(ExpressionVisitor v) { outputScan.visitComparands(v); selectorScan.visitComparands(v); } }