Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Licensed 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 io.trino.sql.planner.plan;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.errorprone.annotations.Immutable;
import io.trino.spi.type.Type;
import io.trino.sql.planner.OrderingScheme;
import io.trino.sql.planner.Symbol;
import io.trino.sql.planner.plan.WindowNode.Frame;
import io.trino.sql.planner.rowpattern.ExpressionAndValuePointers;
import io.trino.sql.planner.rowpattern.ir.IrLabel;
import io.trino.sql.planner.rowpattern.ir.IrRowPattern;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import static com.google.common.base.MoreObjects.toStringHelper;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.collect.Iterables.concat;
import static io.trino.sql.planner.plan.FrameBoundType.CURRENT_ROW;
import static io.trino.sql.planner.plan.RowsPerMatch.ONE;
import static io.trino.sql.planner.plan.RowsPerMatch.WINDOW;
import static io.trino.sql.planner.plan.WindowFrameType.ROWS;
import static java.util.Objects.requireNonNull;
@Immutable
public class PatternRecognitionNode
extends PlanNode
{
private final PlanNode source;
private final DataOrganizationSpecification specification;
private final Optional hashSymbol;
private final Set prePartitionedInputs;
private final int preSortedOrderPrefix;
private final Map windowFunctions;
private final Map measures;
/*
There is one pattern matching per one PatternRecognitionNode. So, it is required that all window functions present
in the node have the same frame, because the frame is a base for pattern matching. Operator takes the following steps:
- determine common base frame
- match the pattern in that frame
- compute all measures on the match
- compute all window functions in the reduced frame defined by the match
Because the base frame is common to all window functions (and measures), it is a top-level property of PatternRecognitionNode,
and not a property of particular window functions like in WindowNode.
*/
private final Optional commonBaseFrame;
private final RowsPerMatch rowsPerMatch;
private final Set skipToLabels;
private final SkipToPosition skipToPosition;
private final boolean initial;
private final IrRowPattern pattern;
private final Map variableDefinitions;
@JsonCreator
public PatternRecognitionNode(
@JsonProperty("id") PlanNodeId id,
@JsonProperty("source") PlanNode source,
@JsonProperty("specification") DataOrganizationSpecification specification,
@JsonProperty("hashSymbol") Optional hashSymbol,
@JsonProperty("prePartitionedInputs") Set prePartitionedInputs,
@JsonProperty("preSortedOrderPrefix") int preSortedOrderPrefix,
@JsonProperty("windowFunctions") Map windowFunctions,
@JsonProperty("measures") Map measures,
@JsonProperty("commonBaseFrame") Optional commonBaseFrame,
@JsonProperty("rowsPerMatch") RowsPerMatch rowsPerMatch,
@JsonProperty("skipToLabels") Set skipToLabels,
@JsonProperty("skipToPosition") SkipToPosition skipToPosition,
@JsonProperty("initial") boolean initial,
@JsonProperty("pattern") IrRowPattern pattern,
@JsonProperty("variableDefinitions") Map variableDefinitions)
{
super(id);
requireNonNull(source, "source is null");
requireNonNull(specification, "specification is null");
requireNonNull(hashSymbol, "hashSymbol is null");
checkArgument(specification.partitionBy().containsAll(prePartitionedInputs), "prePartitionedInputs must be contained in partitionBy");
Optional orderingScheme = specification.orderingScheme();
checkArgument(preSortedOrderPrefix == 0 || (orderingScheme.isPresent() && preSortedOrderPrefix <= orderingScheme.get().orderBy().size()), "Cannot have sorted more symbols than those requested");
checkArgument(preSortedOrderPrefix == 0 || ImmutableSet.copyOf(prePartitionedInputs).equals(ImmutableSet.copyOf(specification.partitionBy())), "preSortedOrderPrefix can only be greater than zero if all partition symbols are pre-partitioned");
requireNonNull(windowFunctions, "windowFunctions is null");
requireNonNull(measures, "measures is null");
requireNonNull(commonBaseFrame, "commonBaseFrame is null");
requireNonNull(rowsPerMatch, "rowsPerMatch is null");
checkArgument(windowFunctions.isEmpty() || commonBaseFrame.isPresent(), "Common base frame is required for pattern recognition with window functions");
checkArgument(commonBaseFrame.isEmpty() || rowsPerMatch == WINDOW, "Invalid ROWS PER MATCH option for pattern recognition in window: %s", rowsPerMatch.name());
checkArgument(rowsPerMatch != WINDOW || commonBaseFrame.isPresent(), "Common base frame is required for pattern recognition in window");
checkArgument(initial || rowsPerMatch == WINDOW, "Pattern search mode SEEK is only supported in window");
commonBaseFrame.ifPresent(frame -> checkArgument(frame.getType() == ROWS && frame.getStartType() == CURRENT_ROW, "Invalid common base frame for pattern recognition in window"));
requireNonNull(skipToPosition, "skipToPosition is null");
requireNonNull(pattern, "pattern is null");
requireNonNull(variableDefinitions, "variableDefinitions is null");
this.source = source;
this.specification = specification;
this.hashSymbol = hashSymbol;
this.prePartitionedInputs = ImmutableSet.copyOf(prePartitionedInputs);
this.preSortedOrderPrefix = preSortedOrderPrefix;
this.windowFunctions = ImmutableMap.copyOf(windowFunctions);
this.measures = ImmutableMap.copyOf(measures);
this.commonBaseFrame = commonBaseFrame;
this.rowsPerMatch = rowsPerMatch;
this.skipToLabels = ImmutableSet.copyOf(skipToLabels);
this.skipToPosition = skipToPosition;
this.initial = initial;
this.pattern = pattern;
this.variableDefinitions = ImmutableMap.copyOf(variableDefinitions);
}
@Override
public List getSources()
{
return ImmutableList.of(source);
}
@Override
// The order of symbols in the returned list might be different than expected layout of the node
public List getOutputSymbols()
{
ImmutableList.Builder outputSymbols = ImmutableList.builder();
if (rowsPerMatch == ONE) {
outputSymbols.addAll(getPartitionBy());
}
else {
outputSymbols.addAll(source.getOutputSymbols());
}
outputSymbols.addAll(measures.keySet());
outputSymbols.addAll(windowFunctions.keySet());
return outputSymbols.build();
}
public Set getCreatedSymbols()
{
return ImmutableSet.copyOf(concat(measures.keySet(), windowFunctions.keySet()));
}
@JsonProperty
public PlanNode getSource()
{
return source;
}
@JsonProperty
public DataOrganizationSpecification getSpecification()
{
return specification;
}
public List getPartitionBy()
{
return specification.partitionBy();
}
public Optional getOrderingScheme()
{
return specification.orderingScheme();
}
@JsonProperty
public Optional getHashSymbol()
{
return hashSymbol;
}
@JsonProperty
public Set getPrePartitionedInputs()
{
return prePartitionedInputs;
}
@JsonProperty
public int getPreSortedOrderPrefix()
{
return preSortedOrderPrefix;
}
@JsonProperty
public Map getWindowFunctions()
{
return windowFunctions;
}
@JsonProperty
public Map getMeasures()
{
return measures;
}
@JsonProperty
public Optional getCommonBaseFrame()
{
return commonBaseFrame;
}
@JsonProperty
public RowsPerMatch getRowsPerMatch()
{
return rowsPerMatch;
}
@JsonProperty
public Set getSkipToLabels()
{
return skipToLabels;
}
@JsonProperty
public SkipToPosition getSkipToPosition()
{
return skipToPosition;
}
@JsonProperty
public boolean isInitial()
{
return initial;
}
@JsonProperty
public IrRowPattern getPattern()
{
return pattern;
}
@JsonProperty
public Map getVariableDefinitions()
{
return variableDefinitions;
}
@Override
public R accept(PlanVisitor visitor, C context)
{
return visitor.visitPatternRecognition(this, context);
}
@Override
public PlanNode replaceChildren(List newChildren)
{
return new PatternRecognitionNode(
getId(),
Iterables.getOnlyElement(newChildren),
specification,
hashSymbol,
prePartitionedInputs,
preSortedOrderPrefix,
windowFunctions,
measures,
commonBaseFrame,
rowsPerMatch,
skipToLabels,
skipToPosition,
initial,
pattern,
variableDefinitions);
}
public static class Measure
{
private final ExpressionAndValuePointers expressionAndValuePointers;
private final Type type;
@JsonCreator
public Measure(ExpressionAndValuePointers expressionAndValuePointers, Type type)
{
this.expressionAndValuePointers = requireNonNull(expressionAndValuePointers, "expressionAndValuePointers is null");
this.type = requireNonNull(type, "type is null");
}
@JsonProperty
public ExpressionAndValuePointers getExpressionAndValuePointers()
{
return expressionAndValuePointers;
}
@JsonProperty
public Type getType()
{
return type;
}
@Override
public boolean equals(Object o)
{
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Measure that = (Measure) o;
return Objects.equals(expressionAndValuePointers, that.expressionAndValuePointers) &&
Objects.equals(type, that.type);
}
@Override
public int hashCode()
{
return Objects.hash(expressionAndValuePointers, type);
}
@Override
public String toString()
{
return toStringHelper(this)
.add("expressionAndValuePointers", expressionAndValuePointers)
.add("type", type)
.toString();
}
}
}