use of io.trino.spi.connector.JoinCondition in project trino by trinodb.
the class PushJoinIntoTableScan method getPushableJoinCondition.
private Optional<JoinCondition> getPushableJoinCondition(Expression conjunct, Set<Symbol> leftSymbols, Set<Symbol> rightSymbols, Context context) {
if (!(conjunct instanceof ComparisonExpression)) {
return Optional.empty();
}
ComparisonExpression comparison = (ComparisonExpression) conjunct;
if (!(comparison.getLeft() instanceof SymbolReference) || !(comparison.getRight() instanceof SymbolReference)) {
return Optional.empty();
}
Symbol left = Symbol.from(comparison.getLeft());
Symbol right = Symbol.from(comparison.getRight());
ComparisonExpression.Operator operator = comparison.getOperator();
if (!leftSymbols.contains(left)) {
// lets try with flipped expression
Symbol tmp = left;
left = right;
right = tmp;
operator = operator.flip();
}
if (leftSymbols.contains(left) && rightSymbols.contains(right)) {
return Optional.of(new JoinCondition(joinConditionOperator(operator), new Variable(left.getName(), context.getSymbolAllocator().getTypes().get(left)), new Variable(right.getName(), context.getSymbolAllocator().getTypes().get(right))));
}
return Optional.empty();
}
use of io.trino.spi.connector.JoinCondition in project trino by trinodb.
the class DefaultJdbcMetadata method applyJoin.
@Override
public Optional<JoinApplicationResult<ConnectorTableHandle>> applyJoin(ConnectorSession session, JoinType joinType, ConnectorTableHandle left, ConnectorTableHandle right, List<JoinCondition> joinConditions, Map<String, ColumnHandle> leftAssignments, Map<String, ColumnHandle> rightAssignments, JoinStatistics statistics) {
if (!isJoinPushdownEnabled(session)) {
return Optional.empty();
}
JdbcTableHandle leftHandle = flushAttributesAsQuery(session, (JdbcTableHandle) left);
JdbcTableHandle rightHandle = flushAttributesAsQuery(session, (JdbcTableHandle) right);
int nextSyntheticColumnId = max(leftHandle.getNextSyntheticColumnId(), rightHandle.getNextSyntheticColumnId());
ImmutableMap.Builder<JdbcColumnHandle, JdbcColumnHandle> newLeftColumnsBuilder = ImmutableMap.builder();
for (JdbcColumnHandle column : jdbcClient.getColumns(session, leftHandle)) {
newLeftColumnsBuilder.put(column, JdbcColumnHandle.builderFrom(column).setColumnName(column.getColumnName() + "_" + nextSyntheticColumnId).build());
nextSyntheticColumnId++;
}
Map<JdbcColumnHandle, JdbcColumnHandle> newLeftColumns = newLeftColumnsBuilder.buildOrThrow();
ImmutableMap.Builder<JdbcColumnHandle, JdbcColumnHandle> newRightColumnsBuilder = ImmutableMap.builder();
for (JdbcColumnHandle column : jdbcClient.getColumns(session, rightHandle)) {
newRightColumnsBuilder.put(column, JdbcColumnHandle.builderFrom(column).setColumnName(column.getColumnName() + "_" + nextSyntheticColumnId).build());
nextSyntheticColumnId++;
}
Map<JdbcColumnHandle, JdbcColumnHandle> newRightColumns = newRightColumnsBuilder.buildOrThrow();
ImmutableList.Builder<JdbcJoinCondition> jdbcJoinConditions = ImmutableList.builder();
for (JoinCondition joinCondition : joinConditions) {
Optional<JdbcColumnHandle> leftColumn = getVariableColumnHandle(leftAssignments, joinCondition.getLeftExpression());
Optional<JdbcColumnHandle> rightColumn = getVariableColumnHandle(rightAssignments, joinCondition.getRightExpression());
if (leftColumn.isEmpty() || rightColumn.isEmpty()) {
return Optional.empty();
}
jdbcJoinConditions.add(new JdbcJoinCondition(leftColumn.get(), joinCondition.getOperator(), rightColumn.get()));
}
Optional<PreparedQuery> joinQuery = jdbcClient.implementJoin(session, joinType, asPreparedQuery(leftHandle), asPreparedQuery(rightHandle), jdbcJoinConditions.build(), newRightColumns.entrySet().stream().collect(toImmutableMap(Map.Entry::getKey, entry -> entry.getValue().getColumnName())), newLeftColumns.entrySet().stream().collect(toImmutableMap(Map.Entry::getKey, entry -> entry.getValue().getColumnName())), statistics);
if (joinQuery.isEmpty()) {
return Optional.empty();
}
return Optional.of(new JoinApplicationResult<>(new JdbcTableHandle(new JdbcQueryRelationHandle(joinQuery.get()), TupleDomain.all(), ImmutableList.of(), Optional.empty(), OptionalLong.empty(), Optional.of(ImmutableList.<JdbcColumnHandle>builder().addAll(newLeftColumns.values()).addAll(newRightColumns.values()).build()), ImmutableSet.<SchemaTableName>builder().addAll(leftHandle.getAllReferencedTables()).addAll(rightHandle.getAllReferencedTables()).build(), nextSyntheticColumnId), ImmutableMap.copyOf(newLeftColumns), ImmutableMap.copyOf(newRightColumns), false));
}
use of io.trino.spi.connector.JoinCondition in project trino by trinodb.
the class PushJoinIntoTableScan method splitFilter.
private FilterSplitResult splitFilter(Expression filter, List<Symbol> leftSymbolsList, List<Symbol> rightSymbolsList, Context context) {
Set<Symbol> leftSymbols = ImmutableSet.copyOf(leftSymbolsList);
Set<Symbol> rightSymbols = ImmutableSet.copyOf(rightSymbolsList);
ImmutableList.Builder<JoinCondition> comparisonConditions = ImmutableList.builder();
ImmutableList.Builder<Expression> remainingConjuncts = ImmutableList.builder();
for (Expression conjunct : extractConjuncts(filter)) {
getPushableJoinCondition(conjunct, leftSymbols, rightSymbols, context).ifPresentOrElse(comparisonConditions::add, () -> remainingConjuncts.add(conjunct));
}
return new FilterSplitResult(comparisonConditions.build(), ExpressionUtils.and(remainingConjuncts.build()));
}
use of io.trino.spi.connector.JoinCondition in project trino by trinodb.
the class TestPushJoinIntoTableScan method testPushJoinIntoTableScan.
@Test(dataProvider = "testPushJoinIntoTableScanParams")
public void testPushJoinIntoTableScan(JoinNode.Type joinType, Optional<ComparisonExpression.Operator> filterComparisonOperator) {
try (RuleTester ruleTester = defaultRuleTester()) {
MockConnectorFactory connectorFactory = createMockConnectorFactory((session, applyJoinType, left, right, joinConditions, leftAssignments, rightAssignments) -> {
assertThat(((MockConnectorTableHandle) left).getTableName()).isEqualTo(TABLE_A_SCHEMA_TABLE_NAME);
assertThat(((MockConnectorTableHandle) right).getTableName()).isEqualTo(TABLE_B_SCHEMA_TABLE_NAME);
Assertions.assertThat(applyJoinType).isEqualTo(toSpiJoinType(joinType));
JoinCondition.Operator expectedOperator = filterComparisonOperator.map(this::getConditionOperator).orElse(JoinCondition.Operator.EQUAL);
Assertions.assertThat(joinConditions).containsExactly(new JoinCondition(expectedOperator, COLUMN_A1_VARIABLE, COLUMN_B1_VARIABLE));
return Optional.of(new JoinApplicationResult<>(JOIN_CONNECTOR_TABLE_HANDLE, JOIN_TABLE_A_COLUMN_MAPPING, JOIN_TABLE_B_COLUMN_MAPPING, false));
});
ruleTester.getQueryRunner().createCatalog(MOCK_CATALOG, connectorFactory, ImmutableMap.of());
ruleTester.assertThat(new PushJoinIntoTableScan(ruleTester.getMetadata())).on(p -> {
Symbol columnA1Symbol = p.symbol(COLUMN_A1);
Symbol columnA2Symbol = p.symbol(COLUMN_A2);
Symbol columnB1Symbol = p.symbol(COLUMN_B1);
TableScanNode left = p.tableScan(TABLE_A_HANDLE, ImmutableList.of(columnA1Symbol, columnA2Symbol), ImmutableMap.of(columnA1Symbol, COLUMN_A1_HANDLE, columnA2Symbol, COLUMN_A2_HANDLE));
TableScanNode right = p.tableScan(TABLE_B_HANDLE, ImmutableList.of(columnB1Symbol), ImmutableMap.of(columnB1Symbol, COLUMN_B1_HANDLE));
if (filterComparisonOperator.isEmpty()) {
return p.join(joinType, left, right, new JoinNode.EquiJoinClause(columnA1Symbol, columnB1Symbol));
}
return p.join(joinType, left, right, new ComparisonExpression(filterComparisonOperator.get(), columnA1Symbol.toSymbolReference(), columnB1Symbol.toSymbolReference()));
}).withSession(MOCK_SESSION).matches(project(tableScan(JOIN_PUSHDOWN_SCHEMA_TABLE_NAME.getTableName())));
}
}
Aggregations