use of io.trino.sql.planner.plan.ProjectNode in project trino by trinodb.
the class RelationPlanner method planJoinUsing.
private RelationPlan planJoinUsing(Join node, RelationPlan left, RelationPlan right) {
/* Given: l JOIN r USING (k1, ..., kn)
produces:
- project
coalesce(l.k1, r.k1)
...,
coalesce(l.kn, r.kn)
l.v1,
...,
l.vn,
r.v1,
...,
r.vn
- join (l.k1 = r.k1 and ... l.kn = r.kn)
- project
cast(l.k1 as commonType(l.k1, r.k1))
...
- project
cast(rl.k1 as commonType(l.k1, r.k1))
If casts are redundant (due to column type and common type being equal),
they will be removed by optimization passes.
*/
List<Identifier> joinColumns = ((JoinUsing) node.getCriteria().orElseThrow()).getColumns();
Analysis.JoinUsingAnalysis joinAnalysis = analysis.getJoinUsing(node);
ImmutableList.Builder<JoinNode.EquiJoinClause> clauses = ImmutableList.builder();
Map<Identifier, Symbol> leftJoinColumns = new HashMap<>();
Map<Identifier, Symbol> rightJoinColumns = new HashMap<>();
Assignments.Builder leftCoercions = Assignments.builder();
Assignments.Builder rightCoercions = Assignments.builder();
leftCoercions.putIdentities(left.getRoot().getOutputSymbols());
rightCoercions.putIdentities(right.getRoot().getOutputSymbols());
for (int i = 0; i < joinColumns.size(); i++) {
Identifier identifier = joinColumns.get(i);
Type type = analysis.getType(identifier);
// compute the coercion for the field on the left to the common supertype of left & right
Symbol leftOutput = symbolAllocator.newSymbol(identifier, type);
int leftField = joinAnalysis.getLeftJoinFields().get(i);
leftCoercions.put(leftOutput, new Cast(left.getSymbol(leftField).toSymbolReference(), toSqlType(type), false, typeCoercion.isTypeOnlyCoercion(left.getDescriptor().getFieldByIndex(leftField).getType(), type)));
leftJoinColumns.put(identifier, leftOutput);
// compute the coercion for the field on the right to the common supertype of left & right
Symbol rightOutput = symbolAllocator.newSymbol(identifier, type);
int rightField = joinAnalysis.getRightJoinFields().get(i);
rightCoercions.put(rightOutput, new Cast(right.getSymbol(rightField).toSymbolReference(), toSqlType(type), false, typeCoercion.isTypeOnlyCoercion(right.getDescriptor().getFieldByIndex(rightField).getType(), type)));
rightJoinColumns.put(identifier, rightOutput);
clauses.add(new JoinNode.EquiJoinClause(leftOutput, rightOutput));
}
ProjectNode leftCoercion = new ProjectNode(idAllocator.getNextId(), left.getRoot(), leftCoercions.build());
ProjectNode rightCoercion = new ProjectNode(idAllocator.getNextId(), right.getRoot(), rightCoercions.build());
JoinNode join = new JoinNode(idAllocator.getNextId(), JoinNode.Type.typeConvert(node.getType()), leftCoercion, rightCoercion, clauses.build(), leftCoercion.getOutputSymbols(), rightCoercion.getOutputSymbols(), false, Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty(), ImmutableMap.of(), Optional.empty());
// Add a projection to produce the outputs of the columns in the USING clause,
// which are defined as coalesce(l.k, r.k)
Assignments.Builder assignments = Assignments.builder();
ImmutableList.Builder<Symbol> outputs = ImmutableList.builder();
for (Identifier column : joinColumns) {
Symbol output = symbolAllocator.newSymbol(column, analysis.getType(column));
outputs.add(output);
assignments.put(output, new CoalesceExpression(leftJoinColumns.get(column).toSymbolReference(), rightJoinColumns.get(column).toSymbolReference()));
}
for (int field : joinAnalysis.getOtherLeftFields()) {
Symbol symbol = left.getFieldMappings().get(field);
outputs.add(symbol);
assignments.put(symbol, symbol.toSymbolReference());
}
for (int field : joinAnalysis.getOtherRightFields()) {
Symbol symbol = right.getFieldMappings().get(field);
outputs.add(symbol);
assignments.put(symbol, symbol.toSymbolReference());
}
return new RelationPlan(new ProjectNode(idAllocator.getNextId(), join, assignments.build()), analysis.getScope(node), outputs.build(), outerContext);
}
use of io.trino.sql.planner.plan.ProjectNode in project trino by trinodb.
the class QueryPlanner method pruneInvisibleFields.
public static NodeAndMappings pruneInvisibleFields(RelationPlan plan, PlanNodeIdAllocator idAllocator) {
List<Symbol> visibleFields = visibleFields(plan);
ProjectNode pruned = new ProjectNode(idAllocator.getNextId(), plan.getRoot(), Assignments.identity(visibleFields));
return new NodeAndMappings(pruned, visibleFields);
}
use of io.trino.sql.planner.plan.ProjectNode in project trino by trinodb.
the class QueryPlanner method coerce.
public static NodeAndMappings coerce(RelationPlan plan, List<Type> types, SymbolAllocator symbolAllocator, PlanNodeIdAllocator idAllocator) {
List<Symbol> visibleFields = visibleFields(plan);
checkArgument(visibleFields.size() == types.size());
Assignments.Builder assignments = Assignments.builder();
ImmutableList.Builder<Symbol> mappings = ImmutableList.builder();
for (int i = 0; i < types.size(); i++) {
Symbol input = visibleFields.get(i);
Type type = types.get(i);
if (!symbolAllocator.getTypes().get(input).equals(type)) {
Symbol coerced = symbolAllocator.newSymbol(input.getName(), type);
assignments.put(coerced, new Cast(input.toSymbolReference(), toSqlType(type)));
mappings.add(coerced);
} else {
assignments.putIdentity(input);
mappings.add(input);
}
}
ProjectNode coerced = new ProjectNode(idAllocator.getNextId(), plan.getRoot(), assignments.build());
return new NodeAndMappings(coerced, mappings.build());
}
use of io.trino.sql.planner.plan.ProjectNode in project trino by trinodb.
the class TestPushProjectionThroughJoin method testDoesNotPushStraddlingProjection.
@Test
public void testDoesNotPushStraddlingProjection() {
PlanBuilder p = new PlanBuilder(new PlanNodeIdAllocator(), dummyMetadata(), TEST_SESSION);
Symbol a = p.symbol("a");
Symbol b = p.symbol("b");
Symbol c = p.symbol("c");
ProjectNode planNode = p.project(Assignments.of(c, new ArithmeticBinaryExpression(ADD, a.toSymbolReference(), b.toSymbolReference())), p.join(INNER, p.values(a), p.values(b)));
Optional<PlanNode> rewritten = pushProjectionThroughJoin(PLANNER_CONTEXT, planNode, noLookup(), new PlanNodeIdAllocator(), testSessionBuilder().build(), createTestingTypeAnalyzer(PLANNER_CONTEXT), p.getTypes());
assertThat(rewritten).isEmpty();
}
use of io.trino.sql.planner.plan.ProjectNode in project trino by trinodb.
the class TestPushProjectionThroughJoin method testDoesNotPushProjectionThroughOuterJoin.
@Test
public void testDoesNotPushProjectionThroughOuterJoin() {
PlanBuilder p = new PlanBuilder(new PlanNodeIdAllocator(), dummyMetadata(), TEST_SESSION);
Symbol a = p.symbol("a");
Symbol b = p.symbol("b");
Symbol c = p.symbol("c");
ProjectNode planNode = p.project(Assignments.of(c, new ArithmeticUnaryExpression(MINUS, a.toSymbolReference())), p.join(LEFT, p.values(a), p.values(b)));
Optional<PlanNode> rewritten = pushProjectionThroughJoin(PLANNER_CONTEXT, planNode, noLookup(), new PlanNodeIdAllocator(), testSessionBuilder().build(), createTestingTypeAnalyzer(PLANNER_CONTEXT), p.getTypes());
assertThat(rewritten).isEmpty();
}
Aggregations