blob: 548fa31cd6916e9a70d9c1173d9ea430a523a8cc [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.drill.exec.planner.index.generators;
import org.apache.drill.shaded.guava.com.google.common.collect.Lists;
import org.apache.drill.shaded.guava.com.google.common.base.Preconditions;
import org.apache.calcite.plan.RelTraitSet;
import org.apache.calcite.rel.InvalidRelException;
import org.apache.calcite.rel.RelCollation;
import org.apache.calcite.rel.RelNode;
import org.apache.calcite.rex.RexNode;
import org.apache.drill.exec.physical.base.IndexGroupScan;
import org.apache.drill.exec.planner.index.IndexCallContext;
import org.apache.drill.exec.planner.index.IndexDescriptor;
import org.apache.drill.exec.planner.index.FunctionalIndexInfo;
import org.apache.drill.exec.planner.index.IndexPlanUtils;
import org.apache.drill.exec.planner.logical.DrillParseContext;
import org.apache.drill.exec.planner.physical.PlannerSettings;
import org.apache.drill.exec.planner.physical.ProjectPrel;
import org.apache.drill.exec.planner.physical.PrelUtil;
import org.apache.drill.exec.planner.physical.ScanPrel;
import org.apache.drill.exec.planner.physical.Prule;
import org.apache.drill.exec.planner.physical.Prel;
import org.apache.drill.exec.physical.base.DbGroupScan;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
public class CoveringPlanNoFilterGenerator extends AbstractIndexPlanGenerator {
private static final Logger logger = LoggerFactory.getLogger(CoveringPlanNoFilterGenerator.class);
final protected IndexGroupScan indexGroupScan;
final protected IndexDescriptor indexDesc;
final boolean isSingletonSortedStream;
// Ideally This functionInfo should be cached along with indexDesc.
final protected FunctionalIndexInfo functionInfo;
public CoveringPlanNoFilterGenerator(IndexCallContext indexContext,
FunctionalIndexInfo functionInfo,
boolean isSingleton,
PlannerSettings settings) {
super(indexContext, null, null, null, settings);
this.functionInfo = functionInfo;
this.indexDesc = functionInfo == null ? null : functionInfo.getIndexDesc();
this.indexGroupScan = functionInfo == null ? null : functionInfo.getIndexDesc().getIndexGroupScan();
this.isSingletonSortedStream = isSingleton;
}
public RelNode convertChild(final RelNode filter, final RelNode input) throws InvalidRelException {
return this.convertChild();
}
public RelNode convertChild() throws InvalidRelException {
Preconditions.checkNotNull(indexContext.getSort());
if (indexGroupScan == null) {
logger.error("Null indexgroupScan in CoveringIndexPlanGenerator.convertChild");
return null;
}
//update sort expressions in context
IndexPlanUtils.updateSortExpression(indexContext, indexContext.getSort() != null ?
indexContext.getCollation().getFieldCollations() : null);
ScanPrel indexScanPrel =
IndexPlanUtils.buildCoveringIndexScan(origScan, indexGroupScan, indexContext, indexDesc);
((IndexGroupScan)indexScanPrel.getGroupScan()).setStatistics(((DbGroupScan)IndexPlanUtils.getGroupScan(origScan)).getStatistics());
RelTraitSet indexScanTraitSet = indexScanPrel.getTraitSet();
RelNode finalRel = indexScanPrel;
if (indexContext.getLowerProject() != null) {
RelCollation collation = IndexPlanUtils.buildCollationProject(indexContext.getLowerProject().getProjects(), null,
indexContext.getScan(), functionInfo, indexContext);
finalRel = new ProjectPrel(indexContext.getScan().getCluster(), indexScanTraitSet.plus(collation),
indexScanPrel, indexContext.getLowerProject().getProjects(), indexContext.getLowerProject().getRowType());
if (functionInfo.hasFunctional()) {
//if there is functional index field, then a rewrite may be needed in upperProject/indexProject
//merge upperProject with indexProjectPrel(from origProject) if both exist,
ProjectPrel newProject = (ProjectPrel)finalRel;
// then rewrite functional expressions in new project.
List<RexNode> newProjects = Lists.newArrayList();
DrillParseContext parseContxt = new DrillParseContext(PrelUtil.getPlannerSettings(newProject.getCluster()));
for(RexNode projectRex: newProject.getProjects()) {
RexNode newRex = IndexPlanUtils.rewriteFunctionalRex(indexContext, parseContxt, null, origScan, projectRex,
indexScanPrel.getRowType(), functionInfo);
newProjects.add(newRex);
}
ProjectPrel rewrittenProject = new ProjectPrel(newProject.getCluster(),
collation==null? newProject.getTraitSet() : newProject.getTraitSet().plus(collation),
indexScanPrel, newProjects, newProject.getRowType());
finalRel = rewrittenProject;
}
}
finalRel = getSortNode(indexContext, finalRel, true, isSingletonSortedStream, indexContext.getExchange() != null);
if (finalRel == null) {
return null;
}
finalRel = Prule.convert(finalRel, finalRel.getTraitSet().plus(Prel.DRILL_PHYSICAL));
logger.debug("CoveringPlanNoFilterGenerator got finalRel {} from origScan {}, original digest {}, new digest {}.",
finalRel.toString(), indexContext.getScan().toString(),
indexContext.getLowerProject()!=null?indexContext.getLowerProject().getDigest(): indexContext.getScan().getDigest(),
finalRel.getDigest());
return finalRel;
}
}