use of io.trino.sql.tree.IsNullPredicate in project trino by trinodb.
the class DomainTranslator method toPredicate.
private Expression toPredicate(Session session, Domain domain, SymbolReference reference) {
if (domain.getValues().isNone()) {
return domain.isNullAllowed() ? new IsNullPredicate(reference) : FALSE_LITERAL;
}
if (domain.getValues().isAll()) {
return domain.isNullAllowed() ? TRUE_LITERAL : new NotExpression(new IsNullPredicate(reference));
}
List<Expression> disjuncts = new ArrayList<>();
disjuncts.addAll(domain.getValues().getValuesProcessor().transform(ranges -> extractDisjuncts(session, domain.getType(), ranges, reference), discreteValues -> extractDisjuncts(session, domain.getType(), discreteValues, reference), allOrNone -> {
throw new IllegalStateException("Case should not be reachable");
}));
// Add nullability disjuncts
if (domain.isNullAllowed()) {
disjuncts.add(new IsNullPredicate(reference));
}
return combineDisjunctsWithDefault(plannerContext.getMetadata(), disjuncts, TRUE_LITERAL);
}
use of io.trino.sql.tree.IsNullPredicate in project trino by trinodb.
the class TestMergeProjectWithValues method testMergeProjectWithValues.
@Test
public void testMergeProjectWithValues() {
tester().assertThat(new MergeProjectWithValues(tester().getMetadata())).on(p -> {
Symbol a = p.symbol("a");
Symbol b = p.symbol("b");
Symbol c = p.symbol("c");
Symbol d = p.symbol("d");
Symbol e = p.symbol("e");
Symbol f = p.symbol("f");
Assignments.Builder assignments = Assignments.builder();
// identity assignment
assignments.putIdentity(a);
// renaming assignment
assignments.put(d, b.toSymbolReference());
// expression involving input symbol
assignments.put(e, new IsNullPredicate(a.toSymbolReference()));
// constant expression
assignments.put(f, new LongLiteral("1"));
return p.project(assignments.build(), p.valuesOfExpressions(ImmutableList.of(a, b, c), ImmutableList.of(new Row(ImmutableList.of(new CharLiteral("x"), new BooleanLiteral("true"), new LongLiteral("1"))), new Row(ImmutableList.of(new CharLiteral("y"), new BooleanLiteral("false"), new LongLiteral("2"))), new Row(ImmutableList.of(new CharLiteral("z"), new BooleanLiteral("true"), new LongLiteral("3"))))));
}).matches(values(ImmutableList.of("a", "d", "e", "f"), ImmutableList.of(ImmutableList.of(new CharLiteral("x"), new BooleanLiteral("true"), new IsNullPredicate(new CharLiteral("x")), new LongLiteral("1")), ImmutableList.of(new CharLiteral("y"), new BooleanLiteral("false"), new IsNullPredicate(new CharLiteral("y")), new LongLiteral("1")), ImmutableList.of(new CharLiteral("z"), new BooleanLiteral("true"), new IsNullPredicate(new CharLiteral("z")), new LongLiteral("1")))));
// ValuesNode has no rows
tester().assertThat(new MergeProjectWithValues(tester().getMetadata())).on(p -> {
Symbol a = p.symbol("a");
Symbol b = p.symbol("b");
Symbol c = p.symbol("c");
Symbol d = p.symbol("d");
Symbol e = p.symbol("e");
Symbol f = p.symbol("f");
Assignments.Builder assignments = Assignments.builder();
// identity assignment
assignments.putIdentity(a);
// renaming assignment
assignments.put(d, b.toSymbolReference());
// expression involving input symbol
assignments.put(e, new IsNullPredicate(a.toSymbolReference()));
// constant expression
assignments.put(f, new LongLiteral("1"));
return p.project(assignments.build(), p.values(ImmutableList.of(a, b, c), ImmutableList.of()));
}).matches(values(ImmutableList.of("a", "d", "e", "f"), ImmutableList.of()));
}
use of io.trino.sql.tree.IsNullPredicate in project trino by trinodb.
the class DecorrelateUnnest method apply.
@Override
public Result apply(CorrelatedJoinNode correlatedJoinNode, Captures captures, Context context) {
// determine shape of the subquery
PlanNode searchRoot = correlatedJoinNode.getSubquery();
// 1. find EnforceSingleRowNode in the subquery
Optional<EnforceSingleRowNode> enforceSingleRow = PlanNodeSearcher.searchFrom(searchRoot, context.getLookup()).where(EnforceSingleRowNode.class::isInstance).recurseOnlyWhen(planNode -> false).findFirst();
if (enforceSingleRow.isPresent()) {
searchRoot = enforceSingleRow.get().getSource();
}
// 2. find correlated UnnestNode in the subquery
Optional<UnnestNode> subqueryUnnest = PlanNodeSearcher.searchFrom(searchRoot, context.getLookup()).where(node -> isSupportedUnnest(node, correlatedJoinNode.getCorrelation(), context.getLookup())).recurseOnlyWhen(node -> node instanceof ProjectNode || (node instanceof LimitNode && ((LimitNode) node).getCount() > 0) || (node instanceof TopNNode && ((TopNNode) node).getCount() > 0)).findFirst();
if (subqueryUnnest.isEmpty()) {
return Result.empty();
}
UnnestNode unnestNode = subqueryUnnest.get();
// assign unique id to input rows
Symbol uniqueSymbol = context.getSymbolAllocator().newSymbol("unique", BIGINT);
PlanNode input = new AssignUniqueId(context.getIdAllocator().getNextId(), correlatedJoinNode.getInput(), uniqueSymbol);
// pre-project unnest symbols if they were pre-projected in subquery
// The correlated UnnestNode either unnests correlation symbols directly, or unnests symbols produced by a projection that uses only correlation symbols.
// Here, any underlying projection that was a source of the correlated UnnestNode, is appended as a source of the rewritten UnnestNode.
// If the projection is not necessary for UnnestNode (i.e. it does not produce any unnest symbols), it should be pruned afterwards.
PlanNode unnestSource = context.getLookup().resolve(unnestNode.getSource());
if (unnestSource instanceof ProjectNode) {
ProjectNode sourceProjection = (ProjectNode) unnestSource;
input = new ProjectNode(sourceProjection.getId(), input, Assignments.builder().putIdentities(input.getOutputSymbols()).putAll(sourceProjection.getAssignments()).build());
}
// determine join type for rewritten UnnestNode
Type unnestJoinType = LEFT;
if (enforceSingleRow.isEmpty() && correlatedJoinNode.getType() == CorrelatedJoinNode.Type.INNER && unnestNode.getJoinType() == INNER) {
unnestJoinType = INNER;
}
// make sure that the rewritten node is with ordinality, which might be necessary to restore inner unnest semantics after rewrite.
Symbol ordinalitySymbol = unnestNode.getOrdinalitySymbol().orElseGet(() -> context.getSymbolAllocator().newSymbol("ordinality", BIGINT));
// rewrite correlated join to UnnestNode.
UnnestNode rewrittenUnnest = new UnnestNode(context.getIdAllocator().getNextId(), input, input.getOutputSymbols(), unnestNode.getMappings(), Optional.of(ordinalitySymbol), unnestJoinType, Optional.empty());
// restore all nodes from the subquery
PlanNode rewrittenPlan = Rewriter.rewriteNodeSequence(correlatedJoinNode.getSubquery(), input.getOutputSymbols(), ordinalitySymbol, uniqueSymbol, rewrittenUnnest, context.getSession(), metadata, context.getLookup(), context.getIdAllocator(), context.getSymbolAllocator());
// between unnested rows and synthetic rows added by left unnest.
if (unnestNode.getJoinType() == INNER && rewrittenUnnest.getJoinType() == LEFT) {
Assignments.Builder assignments = Assignments.builder().putIdentities(correlatedJoinNode.getInput().getOutputSymbols());
for (Symbol subquerySymbol : correlatedJoinNode.getSubquery().getOutputSymbols()) {
assignments.put(subquerySymbol, new IfExpression(new IsNullPredicate(ordinalitySymbol.toSymbolReference()), new Cast(new NullLiteral(), toSqlType(context.getSymbolAllocator().getTypes().get(subquerySymbol))), subquerySymbol.toSymbolReference()));
}
rewrittenPlan = new ProjectNode(context.getIdAllocator().getNextId(), rewrittenPlan, assignments.build());
}
// restrict outputs
return Result.ofPlanNode(restrictOutputs(context.getIdAllocator(), rewrittenPlan, ImmutableSet.copyOf(correlatedJoinNode.getOutputSymbols())).orElse(rewrittenPlan));
}
use of io.trino.sql.tree.IsNullPredicate in project trino by trinodb.
the class TransformCorrelatedInPredicateToJoin method buildInPredicateEquivalent.
private PlanNode buildInPredicateEquivalent(ApplyNode apply, InPredicate inPredicate, Symbol inPredicateOutputSymbol, Decorrelated decorrelated, PlanNodeIdAllocator idAllocator, SymbolAllocator symbolAllocator, Session session) {
Expression correlationCondition = and(decorrelated.getCorrelatedPredicates());
PlanNode decorrelatedBuildSource = decorrelated.getDecorrelatedNode();
AssignUniqueId probeSide = new AssignUniqueId(idAllocator.getNextId(), apply.getInput(), symbolAllocator.newSymbol("unique", BIGINT));
Symbol buildSideKnownNonNull = symbolAllocator.newSymbol("buildSideKnownNonNull", BIGINT);
ProjectNode buildSide = new ProjectNode(idAllocator.getNextId(), decorrelatedBuildSource, Assignments.builder().putIdentities(decorrelatedBuildSource.getOutputSymbols()).put(buildSideKnownNonNull, bigint(0)).build());
Symbol probeSideSymbol = Symbol.from(inPredicate.getValue());
Symbol buildSideSymbol = Symbol.from(inPredicate.getValueList());
Expression joinExpression = and(or(new IsNullPredicate(probeSideSymbol.toSymbolReference()), new ComparisonExpression(ComparisonExpression.Operator.EQUAL, probeSideSymbol.toSymbolReference(), buildSideSymbol.toSymbolReference()), new IsNullPredicate(buildSideSymbol.toSymbolReference())), correlationCondition);
JoinNode leftOuterJoin = leftOuterJoin(idAllocator, probeSide, buildSide, joinExpression);
Symbol matchConditionSymbol = symbolAllocator.newSymbol("matchConditionSymbol", BOOLEAN);
Expression matchCondition = and(isNotNull(probeSideSymbol), isNotNull(buildSideSymbol));
Symbol nullMatchConditionSymbol = symbolAllocator.newSymbol("nullMatchConditionSymbol", BOOLEAN);
Expression nullMatchCondition = and(isNotNull(buildSideKnownNonNull), not(matchCondition));
ProjectNode preProjection = new ProjectNode(idAllocator.getNextId(), leftOuterJoin, Assignments.builder().putIdentities(leftOuterJoin.getOutputSymbols()).put(matchConditionSymbol, matchCondition).put(nullMatchConditionSymbol, nullMatchCondition).build());
Symbol countMatchesSymbol = symbolAllocator.newSymbol("countMatches", BIGINT);
Symbol countNullMatchesSymbol = symbolAllocator.newSymbol("countNullMatches", BIGINT);
AggregationNode aggregation = new AggregationNode(idAllocator.getNextId(), preProjection, ImmutableMap.<Symbol, AggregationNode.Aggregation>builder().put(countMatchesSymbol, countWithFilter(session, matchConditionSymbol)).put(countNullMatchesSymbol, countWithFilter(session, nullMatchConditionSymbol)).buildOrThrow(), singleGroupingSet(probeSide.getOutputSymbols()), ImmutableList.of(), AggregationNode.Step.SINGLE, Optional.empty(), Optional.empty());
// TODO since we care only about "some count > 0", we could have specialized node instead of leftOuterJoin that does the job without materializing join results
SearchedCaseExpression inPredicateEquivalent = new SearchedCaseExpression(ImmutableList.of(new WhenClause(isGreaterThan(countMatchesSymbol, 0), booleanConstant(true)), new WhenClause(isGreaterThan(countNullMatchesSymbol, 0), booleanConstant(null))), Optional.of(booleanConstant(false)));
return new ProjectNode(idAllocator.getNextId(), aggregation, Assignments.builder().putIdentities(apply.getInput().getOutputSymbols()).put(inPredicateOutputSymbol, inPredicateEquivalent).build());
}
use of io.trino.sql.tree.IsNullPredicate in project trino by trinodb.
the class TestCostCalculator method testFilter.
@Test
public void testFilter() {
TableScanNode tableScan = tableScan("ts", "string");
IsNullPredicate expression = new IsNullPredicate(new SymbolReference("string"));
FilterNode filter = new FilterNode(new PlanNodeId("filter"), tableScan, expression);
Map<String, PlanCostEstimate> costs = ImmutableMap.of("ts", cpuCost(1000));
Map<String, PlanNodeStatsEstimate> stats = ImmutableMap.of("filter", statsEstimate(filter, 4000), "ts", statsEstimate(tableScan, 1000));
Map<String, Type> types = ImmutableMap.of("string", VARCHAR);
assertCost(filter, costs, stats, types).cpu(1000 + 1000 * OFFSET_AND_IS_NULL_OVERHEAD).memory(0).network(0);
assertCostEstimatedExchanges(filter, costs, stats, types).cpu(1000 + 1000 * OFFSET_AND_IS_NULL_OVERHEAD).memory(0).network(0);
assertCostFragmentedPlan(filter, costs, stats, types).cpu(1000 + 1000 * OFFSET_AND_IS_NULL_OVERHEAD).memory(0).network(0);
assertCostHasUnknownComponentsForUnknownStats(filter, types);
}
Aggregations