/*
* Licensed to Crate under one or more contributor license agreements.
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership. Crate 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.
*
* However, if you have executed another commercial license agreement
* with Crate these terms will supersede the license and you may use the
* software solely pursuant to the terms of the relevant commercial
* agreement.
*/
package io.crate.planner.fetch;
import io.crate.analyze.MultiSourceSelect;
import io.crate.analyze.relations.QueriedRelation;
import io.crate.analyze.symbol.Symbol;
import io.crate.metadata.Reference;
import io.crate.metadata.TableIdent;
import io.crate.planner.Planner;
import io.crate.planner.ReaderAllocations;
import io.crate.planner.node.fetch.FetchPhase;
import io.crate.planner.node.fetch.FetchSource;
import io.crate.planner.projection.FetchProjection;
import io.crate.planner.projection.builder.InputColumns;
import javax.annotation.Nullable;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
public final class FetchPushDown {
private FetchPushDown() {
}
@Nullable
public static Builder<MultiSourceSelect> pushDown(MultiSourceSelect mss) {
if (mss.canBeFetched().isEmpty()) {
return null;
}
MultiSourceFetchPushDown pd = new MultiSourceFetchPushDown(mss);
pd.process();
LinkedHashSet<Reference> fetchRefs = new LinkedHashSet<>();
for (FetchSource fetchSource : pd.fetchSources().values()) {
fetchRefs.addAll(fetchSource.references());
}
return new Builder<>(
fetchRefs,
pd.fetchSources(),
InputColumns.create(pd.remainingOutputs(), new InputColumns.Context(mss.querySpec().outputs())),
mss
);
}
public static class PhaseAndProjection {
public final FetchPhase phase;
public final FetchProjection projection;
private PhaseAndProjection(FetchPhase phase, FetchProjection projection) {
this.phase = phase;
this.projection = projection;
}
}
public static class Builder<T extends QueriedRelation> {
private final Collection<Reference> fetchRefs;
private final Map<TableIdent, FetchSource> fetchSourceByTable;
private final List<Symbol> outputs;
private final T replacedRelation;
public Builder(Collection<Reference> fetchRefs,
Map<TableIdent, FetchSource> fetchSourceByTable,
List<Symbol> outputs,
T replacedRelation) {
this.fetchRefs = fetchRefs;
this.fetchSourceByTable = fetchSourceByTable;
this.outputs = outputs;
this.replacedRelation = replacedRelation;
}
/**
* Builds the {@link FetchPhase} and {@link FetchProjection}.
* They can only be build after the plans are processed and all shards and readers are allocated.
*/
public PhaseAndProjection build(Planner.Context plannerContext) {
ReaderAllocations readerAllocations = plannerContext.buildReaderAllocations();
FetchPhase fetchPhase = new FetchPhase(
plannerContext.nextExecutionPhaseId(),
readerAllocations.nodeReaders().keySet(),
readerAllocations.bases(),
readerAllocations.tableIndices(),
fetchRefs
);
FetchProjection fetchProjection = new FetchProjection(
fetchPhase.phaseId(),
plannerContext.fetchSize(),
fetchSourceByTable,
outputs,
readerAllocations.nodeReaders(),
readerAllocations.indices(),
readerAllocations.indicesToIdents());
return new PhaseAndProjection(fetchPhase, fetchProjection);
}
public T replacedRelation() {
return replacedRelation;
}
}
}