use of io.trino.sql.planner.rowpattern.ir.IrLabel in project trino by trinodb.
the class MergePatternRecognitionNodes method equivalent.
private static boolean equivalent(Map<IrLabel, ExpressionAndValuePointers> parentVariableDefinitions, Map<IrLabel, ExpressionAndValuePointers> childVariableDefinitions) {
if (!parentVariableDefinitions.keySet().equals(childVariableDefinitions.keySet())) {
return false;
}
for (Map.Entry<IrLabel, ExpressionAndValuePointers> parentDefinition : parentVariableDefinitions.entrySet()) {
IrLabel label = parentDefinition.getKey();
ExpressionAndValuePointers parentExpression = parentDefinition.getValue();
ExpressionAndValuePointers childExpression = childVariableDefinitions.get(label);
if (!ExpressionAndValuePointersEquivalence.equivalent(parentExpression, childExpression)) {
return false;
}
}
return true;
}
use of io.trino.sql.planner.rowpattern.ir.IrLabel in project trino by trinodb.
the class PushDownProjectionsFromPatternRecognition method apply.
@Override
public Result apply(PatternRecognitionNode node, Captures captures, Context context) {
Assignments.Builder assignments = Assignments.builder();
Map<IrLabel, ExpressionAndValuePointers> rewrittenVariableDefinitions = rewriteVariableDefinitions(node.getVariableDefinitions(), assignments, context);
Map<Symbol, Measure> rewrittenMeasureDefinitions = rewriteMeasureDefinitions(node.getMeasures(), assignments, context);
if (assignments.build().isEmpty()) {
return Result.empty();
}
assignments.putIdentities(node.getSource().getOutputSymbols());
ProjectNode projectNode = new ProjectNode(context.getIdAllocator().getNextId(), node.getSource(), assignments.build());
PatternRecognitionNode patternRecognitionNode = new PatternRecognitionNode(node.getId(), projectNode, node.getSpecification(), node.getHashSymbol(), node.getPrePartitionedInputs(), node.getPreSortedOrderPrefix(), node.getWindowFunctions(), rewrittenMeasureDefinitions, node.getCommonBaseFrame(), node.getRowsPerMatch(), node.getSkipToLabel(), node.getSkipToPosition(), node.isInitial(), node.getPattern(), node.getSubsets(), rewrittenVariableDefinitions);
return Result.ofPlanNode(restrictOutputs(context.getIdAllocator(), patternRecognitionNode, ImmutableSet.copyOf(node.getOutputSymbols())).orElse(patternRecognitionNode));
}
use of io.trino.sql.planner.rowpattern.ir.IrLabel in project trino by trinodb.
the class SymbolMapper method map.
public PatternRecognitionNode map(PatternRecognitionNode node, PlanNode source) {
ImmutableMap.Builder<Symbol, WindowNode.Function> newFunctions = ImmutableMap.builder();
node.getWindowFunctions().forEach((symbol, function) -> {
List<Expression> newArguments = function.getArguments().stream().map(this::map).collect(toImmutableList());
WindowNode.Frame newFrame = map(function.getFrame());
newFunctions.put(map(symbol), new WindowNode.Function(function.getResolvedFunction(), newArguments, newFrame, function.isIgnoreNulls()));
});
ImmutableMap.Builder<Symbol, Measure> newMeasures = ImmutableMap.builder();
node.getMeasures().forEach((symbol, measure) -> {
ExpressionAndValuePointers newExpression = map(measure.getExpressionAndValuePointers());
newMeasures.put(map(symbol), new Measure(newExpression, measure.getType()));
});
ImmutableMap.Builder<IrLabel, ExpressionAndValuePointers> newVariableDefinitions = ImmutableMap.builder();
node.getVariableDefinitions().forEach((label, expression) -> newVariableDefinitions.put(label, map(expression)));
return new PatternRecognitionNode(node.getId(), source, mapAndDistinct(node.getSpecification()), node.getHashSymbol().map(this::map), node.getPrePartitionedInputs().stream().map(this::map).collect(toImmutableSet()), node.getPreSortedOrderPrefix(), newFunctions.buildOrThrow(), newMeasures.buildOrThrow(), node.getCommonBaseFrame().map(this::map), node.getRowsPerMatch(), node.getSkipToLabel(), node.getSkipToPosition(), node.isInitial(), node.getPattern(), node.getSubsets(), newVariableDefinitions.buildOrThrow());
}
use of io.trino.sql.planner.rowpattern.ir.IrLabel in project trino by trinodb.
the class TestLogicalPlanner method testDoNotPlanUnreferencedRowPatternMeasures.
@Test
public void testDoNotPlanUnreferencedRowPatternMeasures() {
// row pattern measure `label` is not referenced
assertPlan("SELECT val OVER w " + " FROM (VALUES (1, 90)) t(id, value) " + " WINDOW w AS ( " + " ORDER BY id " + " MEASURES " + " RUNNING LAST(value) AS val, " + " CLASSIFIER() AS label " + " ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING " + " PATTERN (A+) " + " DEFINE A AS true " + " )", output(project(patternRecognition(builder -> builder.specification(specification(ImmutableList.of(), ImmutableList.of("id"), ImmutableMap.of("id", ASC_NULLS_LAST))).addMeasure("val", "LAST(value)", INTEGER).rowsPerMatch(WINDOW).frame(windowFrame(ROWS, CURRENT_ROW, Optional.empty(), UNBOUNDED_FOLLOWING, Optional.empty(), Optional.empty())).pattern(new IrQuantified(new IrLabel("A"), oneOrMore(true))).addVariableDefinition(new IrLabel("A"), "true"), values(ImmutableList.of("id", "value"), ImmutableList.of(ImmutableList.of(new LongLiteral("1"), new LongLiteral("90"))))))));
// row pattern measure `label` is not referenced
assertPlan("SELECT min(value) OVER w " + " FROM (VALUES (1, 90)) t(id, value) " + " WINDOW w AS ( " + " ORDER BY id " + " MEASURES CLASSIFIER() AS label " + " ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING " + " PATTERN (A+) " + " DEFINE A AS true " + " )", output(project(patternRecognition(builder -> builder.specification(specification(ImmutableList.of(), ImmutableList.of("id"), ImmutableMap.of("id", ASC_NULLS_LAST))).addFunction("min", functionCall("min", ImmutableList.of("value"))).rowsPerMatch(WINDOW).frame(windowFrame(ROWS, CURRENT_ROW, Optional.empty(), UNBOUNDED_FOLLOWING, Optional.empty(), Optional.empty())).pattern(new IrQuantified(new IrLabel("A"), oneOrMore(true))).addVariableDefinition(new IrLabel("A"), "true"), values(ImmutableList.of("id", "value"), ImmutableList.of(ImmutableList.of(new LongLiteral("1"), new LongLiteral("90"))))))));
}
use of io.trino.sql.planner.rowpattern.ir.IrLabel in project trino by trinodb.
the class RelationPlanner method planPatternRecognitionComponents.
public PatternRecognitionComponents planPatternRecognitionComponents(Function<Expression, Expression> expressionRewrite, List<SubsetDefinition> subsets, List<MeasureDefinition> measures, Optional<SkipTo> skipTo, Optional<PatternSearchMode> searchMode, RowPattern pattern, List<VariableDefinition> variableDefinitions) {
// rewrite subsets
ImmutableMap.Builder<IrLabel, Set<IrLabel>> rewrittenSubsets = ImmutableMap.builder();
for (SubsetDefinition subsetDefinition : subsets) {
IrLabel label = irLabel(subsetDefinition.getName());
Set<IrLabel> elements = subsetDefinition.getIdentifiers().stream().map(RelationPlanner::irLabel).collect(toImmutableSet());
rewrittenSubsets.put(label, elements);
}
// NOTE: There might be aggregate functions in measure definitions and variable definitions.
// They are handled different than top level aggregations in a query:
// 1. Their arguments are not pre-projected and replaced with single symbols. This is because the arguments might
// not be eligible for pre-projection, when they contain references to CLASSIFIER() or MATCH_NUMBER() functions
// which are evaluated at runtime. If some aggregation arguments can be pre-projected, it will be done in the
// Optimizer.
// 2. Their arguments do not need to be coerced by hand. Since the pattern aggregation arguments are rewritten as
// parts of enclosing expressions, and not as standalone expressions, all necessary coercions will be applied by the
// TranslationMap.
// rewrite measures
ImmutableMap.Builder<Symbol, Measure> rewrittenMeasures = ImmutableMap.builder();
ImmutableList.Builder<Symbol> measureOutputs = ImmutableList.builder();
for (MeasureDefinition measureDefinition : measures) {
Type type = analysis.getType(measureDefinition.getExpression());
Symbol symbol = symbolAllocator.newSymbol(measureDefinition.getName().getValue().toLowerCase(ENGLISH), type);
Expression expression = expressionRewrite.apply(measureDefinition.getExpression());
ExpressionAndValuePointers measure = LogicalIndexExtractor.rewrite(expression, rewrittenSubsets.buildOrThrow(), symbolAllocator, plannerContext.getMetadata());
rewrittenMeasures.put(symbol, new Measure(measure, type));
measureOutputs.add(symbol);
}
// rewrite pattern to IR
IrRowPattern rewrittenPattern = RowPatternToIrRewriter.rewrite(pattern, analysis);
// rewrite variable definitions
ImmutableMap.Builder<IrLabel, ExpressionAndValuePointers> rewrittenVariableDefinitions = ImmutableMap.builder();
for (VariableDefinition variableDefinition : variableDefinitions) {
IrLabel label = irLabel(variableDefinition.getName());
Expression expression = expressionRewrite.apply(variableDefinition.getExpression());
ExpressionAndValuePointers definition = LogicalIndexExtractor.rewrite(expression, rewrittenSubsets.buildOrThrow(), symbolAllocator, plannerContext.getMetadata());
rewrittenVariableDefinitions.put(label, definition);
}
// add `true` definition for undefined labels
for (String label : analysis.getUndefinedLabels(pattern)) {
rewrittenVariableDefinitions.put(irLabel(label), ExpressionAndValuePointers.TRUE);
}
return new PatternRecognitionComponents(rewrittenSubsets.buildOrThrow(), rewrittenMeasures.buildOrThrow(), measureOutputs.build(), skipTo.flatMap(SkipTo::getIdentifier).map(RelationPlanner::irLabel), skipTo.map(SkipTo::getPosition).orElse(PAST_LAST), searchMode.map(mode -> mode.getMode() == INITIAL).orElse(TRUE), rewrittenPattern, rewrittenVariableDefinitions.buildOrThrow());
}
Aggregations