diff --git a/plugin/trino-base-jdbc/src/main/java/io/trino/plugin/jdbc/BaseJdbcClient.java b/plugin/trino-base-jdbc/src/main/java/io/trino/plugin/jdbc/BaseJdbcClient.java index 989317dae45d..42d6731d52cc 100644 --- a/plugin/trino-base-jdbc/src/main/java/io/trino/plugin/jdbc/BaseJdbcClient.java +++ b/plugin/trino-base-jdbc/src/main/java/io/trino/plugin/jdbc/BaseJdbcClient.java @@ -550,6 +550,41 @@ public Optional implementJoin( } } + @Deprecated + @Override + public Optional legacyImplementJoin( + ConnectorSession session, + JoinType joinType, + PreparedQuery leftSource, + PreparedQuery rightSource, + List joinConditions, + Map rightAssignments, + Map leftAssignments, + JoinStatistics statistics) + { + for (JdbcJoinCondition joinCondition : joinConditions) { + if (!isSupportedJoinCondition(session, joinCondition)) { + return Optional.empty(); + } + } + + try (Connection connection = this.connectionFactory.openConnection(session)) { + return Optional.of(queryBuilder.legacyPrepareJoinQuery( + this, + session, + connection, + joinType, + leftSource, + rightSource, + joinConditions, + leftAssignments, + rightAssignments)); + } + catch (SQLException e) { + throw new TrinoException(JDBC_ERROR, e); + } + } + protected boolean isSupportedJoinCondition(ConnectorSession session, JdbcJoinCondition joinCondition) { return false; diff --git a/plugin/trino-base-jdbc/src/main/java/io/trino/plugin/jdbc/CachingJdbcClient.java b/plugin/trino-base-jdbc/src/main/java/io/trino/plugin/jdbc/CachingJdbcClient.java index f473c94d96b9..ecea7b964a4e 100644 --- a/plugin/trino-base-jdbc/src/main/java/io/trino/plugin/jdbc/CachingJdbcClient.java +++ b/plugin/trino-base-jdbc/src/main/java/io/trino/plugin/jdbc/CachingJdbcClient.java @@ -293,6 +293,20 @@ public Optional implementJoin( return delegate.implementJoin(session, joinType, leftSource, leftProjections, rightSource, rightProjections, joinConditions, statistics); } + @Override + public Optional legacyImplementJoin( + ConnectorSession session, + JoinType joinType, + PreparedQuery leftSource, + PreparedQuery rightSource, + List joinConditions, + Map rightAssignments, + Map leftAssignments, + JoinStatistics statistics) + { + return delegate.legacyImplementJoin(session, joinType, leftSource, rightSource, joinConditions, rightAssignments, leftAssignments, statistics); + } + @Override public boolean supportsTopN(ConnectorSession session, JdbcTableHandle handle, List sortOrder) { diff --git a/plugin/trino-base-jdbc/src/main/java/io/trino/plugin/jdbc/DefaultJdbcMetadata.java b/plugin/trino-base-jdbc/src/main/java/io/trino/plugin/jdbc/DefaultJdbcMetadata.java index 607d813b49ef..7d0d7f6d6b08 100644 --- a/plugin/trino-base-jdbc/src/main/java/io/trino/plugin/jdbc/DefaultJdbcMetadata.java +++ b/plugin/trino-base-jdbc/src/main/java/io/trino/plugin/jdbc/DefaultJdbcMetadata.java @@ -40,6 +40,7 @@ import io.trino.spi.connector.Constraint; import io.trino.spi.connector.ConstraintApplicationResult; import io.trino.spi.connector.JoinApplicationResult; +import io.trino.spi.connector.JoinCondition; import io.trino.spi.connector.JoinStatistics; import io.trino.spi.connector.JoinType; import io.trino.spi.connector.LimitApplicationResult; @@ -94,6 +95,7 @@ import static io.trino.plugin.jdbc.JdbcErrorCode.JDBC_NON_TRANSIENT_ERROR; import static io.trino.plugin.jdbc.JdbcMetadataSessionProperties.isAggregationPushdownEnabled; import static io.trino.plugin.jdbc.JdbcMetadataSessionProperties.isComplexExpressionPushdown; +import static io.trino.plugin.jdbc.JdbcMetadataSessionProperties.isComplexJoinPushdownEnabled; import static io.trino.plugin.jdbc.JdbcMetadataSessionProperties.isJoinPushdownEnabled; import static io.trino.plugin.jdbc.JdbcMetadataSessionProperties.isTopNPushdownEnabled; import static io.trino.plugin.jdbc.JdbcWriteSessionProperties.isNonTransactionalInsert; @@ -447,6 +449,19 @@ public Optional> applyJoin( Map rightAssignments, JoinStatistics statistics) { + if (!isComplexJoinPushdownEnabled(session)) { + // Fallback to the old join pushdown code + return JdbcMetadata.super.applyJoin( + session, + joinType, + left, + right, + joinCondition, + leftAssignments, + rightAssignments, + statistics); + } + if (isTableHandleForProcedure(left) || isTableHandleForProcedure(right)) { return Optional.empty(); } @@ -536,6 +551,101 @@ public Optional> applyJoin( precalculateStatisticsForPushdown)); } + @Deprecated + @Override + public Optional> applyJoin( + ConnectorSession session, + JoinType joinType, + ConnectorTableHandle left, + ConnectorTableHandle right, + List joinConditions, + Map leftAssignments, + Map rightAssignments, + JoinStatistics statistics) + { + if (isTableHandleForProcedure(left) || isTableHandleForProcedure(right)) { + return Optional.empty(); + } + + if (!isJoinPushdownEnabled(session)) { + return Optional.empty(); + } + + JdbcTableHandle leftHandle = flushAttributesAsQuery(session, (JdbcTableHandle) left); + JdbcTableHandle rightHandle = flushAttributesAsQuery(session, (JdbcTableHandle) right); + + if (!leftHandle.getAuthorization().equals(rightHandle.getAuthorization())) { + return Optional.empty(); + } + int nextSyntheticColumnId = max(leftHandle.getNextSyntheticColumnId(), rightHandle.getNextSyntheticColumnId()); + + ImmutableMap.Builder newLeftColumnsBuilder = ImmutableMap.builder(); + OptionalInt maxColumnNameLength = jdbcClient.getMaxColumnNameLength(session); + for (JdbcColumnHandle column : jdbcClient.getColumns(session, leftHandle)) { + newLeftColumnsBuilder.put(column, createSyntheticJoinProjectionColumn(column, nextSyntheticColumnId, maxColumnNameLength)); + nextSyntheticColumnId++; + } + Map newLeftColumns = newLeftColumnsBuilder.buildOrThrow(); + + ImmutableMap.Builder newRightColumnsBuilder = ImmutableMap.builder(); + for (JdbcColumnHandle column : jdbcClient.getColumns(session, rightHandle)) { + newRightColumnsBuilder.put(column, createSyntheticJoinProjectionColumn(column, nextSyntheticColumnId, maxColumnNameLength)); + nextSyntheticColumnId++; + } + Map newRightColumns = newRightColumnsBuilder.buildOrThrow(); + + ImmutableList.Builder jdbcJoinConditions = ImmutableList.builder(); + for (JoinCondition joinCondition : joinConditions) { + Optional leftColumn = getVariableColumnHandle(leftAssignments, joinCondition.getLeftExpression()); + Optional rightColumn = getVariableColumnHandle(rightAssignments, joinCondition.getRightExpression()); + if (leftColumn.isEmpty() || rightColumn.isEmpty()) { + return Optional.empty(); + } + jdbcJoinConditions.add(new JdbcJoinCondition(leftColumn.get(), joinCondition.getOperator(), rightColumn.get())); + } + + Optional joinQuery = jdbcClient.legacyImplementJoin( + session, + joinType, + asPreparedQuery(leftHandle), + asPreparedQuery(rightHandle), + jdbcJoinConditions.build(), + newRightColumns.entrySet().stream() + .collect(toImmutableMap(Entry::getKey, entry -> entry.getValue().getColumnName())), + newLeftColumns.entrySet().stream() + .collect(toImmutableMap(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.builder() + .addAll(newLeftColumns.values()) + .addAll(newRightColumns.values()) + .build()), + leftHandle.getAllReferencedTables().flatMap(leftReferencedTables -> + rightHandle.getAllReferencedTables().map(rightReferencedTables -> + ImmutableSet.builder() + .addAll(leftReferencedTables) + .addAll(rightReferencedTables) + .build())), + nextSyntheticColumnId, + leftHandle.getAuthorization(), + leftHandle.getUpdateAssignments()), + ImmutableMap.copyOf(newLeftColumns), + ImmutableMap.copyOf(newRightColumns), + precalculateStatisticsForPushdown)); + } + @VisibleForTesting static JdbcColumnHandle createSyntheticJoinProjectionColumn(JdbcColumnHandle column, int nextSyntheticColumnId, OptionalInt optionalMaxColumnNameLength) { diff --git a/plugin/trino-base-jdbc/src/main/java/io/trino/plugin/jdbc/DefaultQueryBuilder.java b/plugin/trino-base-jdbc/src/main/java/io/trino/plugin/jdbc/DefaultQueryBuilder.java index 7d3a4f5f0524..bd06719f9ce1 100644 --- a/plugin/trino-base-jdbc/src/main/java/io/trino/plugin/jdbc/DefaultQueryBuilder.java +++ b/plugin/trino-base-jdbc/src/main/java/io/trino/plugin/jdbc/DefaultQueryBuilder.java @@ -147,6 +147,46 @@ public PreparedQuery prepareJoinQuery( return new PreparedQuery(query, parameters); } + @Override + public PreparedQuery legacyPrepareJoinQuery( + JdbcClient client, + ConnectorSession session, + Connection connection, + JoinType joinType, + PreparedQuery leftSource, + PreparedQuery rightSource, + List joinConditions, + Map leftAssignments, + Map rightAssignments) + { + // Verify assignments are present. This is safe assumption as join conditions are not pruned, and simplifies the code here. + verify(!leftAssignments.isEmpty(), "leftAssignments is empty"); + verify(!rightAssignments.isEmpty(), "rightAssignments is empty"); + // Joins wih no conditions are not pushed down, so it is a same assumption and simplifies the code here + verify(!joinConditions.isEmpty(), "joinConditions is empty"); + + String leftRelationAlias = "l"; + String rightRelationAlias = "r"; + + String query = format( + "SELECT %s, %s FROM (%s) %s %s (%s) %s ON %s", + formatAssignments(client, leftRelationAlias, leftAssignments), + formatAssignments(client, rightRelationAlias, rightAssignments), + leftSource.getQuery(), + leftRelationAlias, + formatJoinType(joinType), + rightSource.getQuery(), + rightRelationAlias, + joinConditions.stream() + .map(condition -> formatJoinCondition(client, leftRelationAlias, rightRelationAlias, condition)) + .collect(joining(" AND "))); + List parameters = ImmutableList.builder() + .addAll(leftSource.getParameters()) + .addAll(rightSource.getParameters()) + .build(); + return new PreparedQuery(query, parameters); + } + @Override public PreparedQuery prepareDeleteQuery( JdbcClient client, diff --git a/plugin/trino-base-jdbc/src/main/java/io/trino/plugin/jdbc/ForwardingJdbcClient.java b/plugin/trino-base-jdbc/src/main/java/io/trino/plugin/jdbc/ForwardingJdbcClient.java index f2ac9981f9ef..3f672896d56c 100644 --- a/plugin/trino-base-jdbc/src/main/java/io/trino/plugin/jdbc/ForwardingJdbcClient.java +++ b/plugin/trino-base-jdbc/src/main/java/io/trino/plugin/jdbc/ForwardingJdbcClient.java @@ -220,6 +220,20 @@ public Optional implementJoin( return delegate().implementJoin(session, joinType, leftSource, leftProjections, rightSource, rightProjections, joinConditions, statistics); } + @Override + public Optional legacyImplementJoin( + ConnectorSession session, + JoinType joinType, + PreparedQuery leftSource, + PreparedQuery rightSource, + List joinConditions, + Map rightAssignments, + Map leftAssignments, + JoinStatistics statistics) + { + return delegate().legacyImplementJoin(session, joinType, leftSource, rightSource, joinConditions, rightAssignments, leftAssignments, statistics); + } + @Override public JdbcOutputTableHandle beginCreateTable(ConnectorSession session, ConnectorTableMetadata tableMetadata) { diff --git a/plugin/trino-base-jdbc/src/main/java/io/trino/plugin/jdbc/JdbcClient.java b/plugin/trino-base-jdbc/src/main/java/io/trino/plugin/jdbc/JdbcClient.java index a52f100c78b1..cb2ff550a8e8 100644 --- a/plugin/trino-base-jdbc/src/main/java/io/trino/plugin/jdbc/JdbcClient.java +++ b/plugin/trino-base-jdbc/src/main/java/io/trino/plugin/jdbc/JdbcClient.java @@ -133,6 +133,17 @@ Optional implementJoin( List joinConditions, JoinStatistics statistics); + @Deprecated + Optional legacyImplementJoin( + ConnectorSession session, + JoinType joinType, + PreparedQuery leftSource, + PreparedQuery rightSource, + List joinConditions, + Map rightAssignments, + Map leftAssignments, + JoinStatistics statistics); + boolean supportsTopN(ConnectorSession session, JdbcTableHandle handle, List sortOrder); /** diff --git a/plugin/trino-base-jdbc/src/main/java/io/trino/plugin/jdbc/JdbcMetadataConfig.java b/plugin/trino-base-jdbc/src/main/java/io/trino/plugin/jdbc/JdbcMetadataConfig.java index 039195481a86..d6896c157a1a 100644 --- a/plugin/trino-base-jdbc/src/main/java/io/trino/plugin/jdbc/JdbcMetadataConfig.java +++ b/plugin/trino-base-jdbc/src/main/java/io/trino/plugin/jdbc/JdbcMetadataConfig.java @@ -30,6 +30,7 @@ public class JdbcMetadataConfig * in terms of performance and money due to an increased network traffic. */ private boolean joinPushdownEnabled; + private boolean complexJoinPushdownEnabled = true; private boolean aggregationPushdownEnabled = true; private boolean topNPushdownEnabled = true; @@ -67,6 +68,19 @@ public JdbcMetadataConfig setJoinPushdownEnabled(boolean joinPushdownEnabled) return this; } + public boolean isComplexJoinPushdownEnabled() + { + return complexJoinPushdownEnabled; + } + + @Config("join-pushdown.with-expressions") + @ConfigDescription("Enable join pushdown with complex expressions") + public JdbcMetadataConfig setComplexJoinPushdownEnabled(boolean complexJoinPushdownEnabled) + { + this.complexJoinPushdownEnabled = complexJoinPushdownEnabled; + return this; + } + public boolean isAggregationPushdownEnabled() { return aggregationPushdownEnabled; diff --git a/plugin/trino-base-jdbc/src/main/java/io/trino/plugin/jdbc/JdbcMetadataSessionProperties.java b/plugin/trino-base-jdbc/src/main/java/io/trino/plugin/jdbc/JdbcMetadataSessionProperties.java index d4ae2a0b5b12..96476cce488e 100644 --- a/plugin/trino-base-jdbc/src/main/java/io/trino/plugin/jdbc/JdbcMetadataSessionProperties.java +++ b/plugin/trino-base-jdbc/src/main/java/io/trino/plugin/jdbc/JdbcMetadataSessionProperties.java @@ -33,6 +33,7 @@ public class JdbcMetadataSessionProperties { public static final String COMPLEX_EXPRESSION_PUSHDOWN = "complex_expression_pushdown"; public static final String JOIN_PUSHDOWN_ENABLED = "join_pushdown_enabled"; + public static final String COMPLEX_JOIN_PUSHDOWN_ENABLED = "complex_join_pushdown_enabled"; public static final String AGGREGATION_PUSHDOWN_ENABLED = "aggregation_pushdown_enabled"; public static final String TOPN_PUSHDOWN_ENABLED = "topn_pushdown_enabled"; public static final String DOMAIN_COMPACTION_THRESHOLD = "domain_compaction_threshold"; @@ -54,6 +55,11 @@ public JdbcMetadataSessionProperties(JdbcMetadataConfig jdbcMetadataConfig, @Max "Enable join pushdown", jdbcMetadataConfig.isJoinPushdownEnabled(), false)) + .add(booleanProperty( + COMPLEX_JOIN_PUSHDOWN_ENABLED, + "Enable join pushdown with non-comparison expressions", + jdbcMetadataConfig.isComplexJoinPushdownEnabled(), + false)) .add(booleanProperty( AGGREGATION_PUSHDOWN_ENABLED, "Enable aggregation pushdown", @@ -89,6 +95,11 @@ public static boolean isJoinPushdownEnabled(ConnectorSession session) return session.getProperty(JOIN_PUSHDOWN_ENABLED, Boolean.class); } + public static boolean isComplexJoinPushdownEnabled(ConnectorSession session) + { + return session.getProperty(COMPLEX_JOIN_PUSHDOWN_ENABLED, Boolean.class); + } + public static boolean isAggregationPushdownEnabled(ConnectorSession session) { return session.getProperty(AGGREGATION_PUSHDOWN_ENABLED, Boolean.class); diff --git a/plugin/trino-base-jdbc/src/main/java/io/trino/plugin/jdbc/QueryBuilder.java b/plugin/trino-base-jdbc/src/main/java/io/trino/plugin/jdbc/QueryBuilder.java index a6dc6f53d985..9c6fbf7c4ca9 100644 --- a/plugin/trino-base-jdbc/src/main/java/io/trino/plugin/jdbc/QueryBuilder.java +++ b/plugin/trino-base-jdbc/src/main/java/io/trino/plugin/jdbc/QueryBuilder.java @@ -52,6 +52,17 @@ PreparedQuery prepareJoinQuery( Map rightProjections, List joinConditions); + PreparedQuery legacyPrepareJoinQuery( + JdbcClient client, + ConnectorSession session, + Connection connection, + JoinType joinType, + PreparedQuery leftSource, + PreparedQuery rightSource, + List joinConditions, + Map leftAssignments, + Map rightAssignments); + PreparedQuery prepareDeleteQuery( JdbcClient client, ConnectorSession session, diff --git a/plugin/trino-base-jdbc/src/main/java/io/trino/plugin/jdbc/jmx/StatisticsAwareJdbcClient.java b/plugin/trino-base-jdbc/src/main/java/io/trino/plugin/jdbc/jmx/StatisticsAwareJdbcClient.java index a19087465750..339cf17df0f5 100644 --- a/plugin/trino-base-jdbc/src/main/java/io/trino/plugin/jdbc/jmx/StatisticsAwareJdbcClient.java +++ b/plugin/trino-base-jdbc/src/main/java/io/trino/plugin/jdbc/jmx/StatisticsAwareJdbcClient.java @@ -17,6 +17,7 @@ import io.trino.plugin.jdbc.JdbcClient; import io.trino.plugin.jdbc.JdbcColumnHandle; import io.trino.plugin.jdbc.JdbcExpression; +import io.trino.plugin.jdbc.JdbcJoinCondition; import io.trino.plugin.jdbc.JdbcOutputTableHandle; import io.trino.plugin.jdbc.JdbcProcedureHandle; import io.trino.plugin.jdbc.JdbcProcedureHandle.ProcedureQuery; @@ -239,6 +240,19 @@ public Optional implementJoin(ConnectorSession session, return stats.getImplementJoin().wrap(() -> delegate().implementJoin(session, joinType, leftSource, leftProjections, rightSource, rightProjections, joinConditions, statistics)); } + @Override + public Optional legacyImplementJoin(ConnectorSession session, + JoinType joinType, + PreparedQuery leftSource, + PreparedQuery rightSource, + List joinConditions, + Map rightAssignments, + Map leftAssignments, + JoinStatistics statistics) + { + return stats.getImplementJoin().wrap(() -> delegate().legacyImplementJoin(session, joinType, leftSource, rightSource, joinConditions, rightAssignments, leftAssignments, statistics)); + } + @Override public Optional getTableComment(ResultSet resultSet) throws SQLException diff --git a/plugin/trino-base-jdbc/src/test/java/io/trino/plugin/jdbc/BaseJdbcConnectorTest.java b/plugin/trino-base-jdbc/src/test/java/io/trino/plugin/jdbc/BaseJdbcConnectorTest.java index 1cf08c54b3fd..63ab5bebabdf 100644 --- a/plugin/trino-base-jdbc/src/test/java/io/trino/plugin/jdbc/BaseJdbcConnectorTest.java +++ b/plugin/trino-base-jdbc/src/test/java/io/trino/plugin/jdbc/BaseJdbcConnectorTest.java @@ -64,6 +64,7 @@ import static io.trino.SystemSessionProperties.MARK_DISTINCT_STRATEGY; import static io.trino.plugin.jdbc.JdbcDynamicFilteringSessionProperties.DYNAMIC_FILTERING_ENABLED; import static io.trino.plugin.jdbc.JdbcDynamicFilteringSessionProperties.DYNAMIC_FILTERING_WAIT_TIMEOUT; +import static io.trino.plugin.jdbc.JdbcMetadataSessionProperties.COMPLEX_JOIN_PUSHDOWN_ENABLED; import static io.trino.plugin.jdbc.JdbcMetadataSessionProperties.DOMAIN_COMPACTION_THRESHOLD; import static io.trino.plugin.jdbc.JdbcMetadataSessionProperties.JOIN_PUSHDOWN_ENABLED; import static io.trino.plugin.jdbc.JoinOperator.FULL_JOIN; @@ -1332,6 +1333,14 @@ public void testComplexJoinPushdown() Session session = joinPushdownEnabled(getSession()); String query = "SELECT n.name, o.orderstatus FROM nation n JOIN orders o ON n.regionkey = o.orderkey AND n.nationkey + o.custkey - 3 = 0"; + // The join cannot be pushed down without "complex join pushdown" + assertThat(query( + Session.builder(session) + .setCatalogSessionProperty(catalog, COMPLEX_JOIN_PUSHDOWN_ENABLED, "false") + .build(), + query)) + .joinIsNotFullyPushedDown(); + // The join can be pushed down assertJoinConditionallyPushedDown( session, diff --git a/plugin/trino-base-jdbc/src/test/java/io/trino/plugin/jdbc/TestDefaultJdbcQueryBuilder.java b/plugin/trino-base-jdbc/src/test/java/io/trino/plugin/jdbc/TestDefaultJdbcQueryBuilder.java index a407d624d5d8..170df828714b 100644 --- a/plugin/trino-base-jdbc/src/test/java/io/trino/plugin/jdbc/TestDefaultJdbcQueryBuilder.java +++ b/plugin/trino-base-jdbc/src/test/java/io/trino/plugin/jdbc/TestDefaultJdbcQueryBuilder.java @@ -22,6 +22,7 @@ import io.trino.plugin.jdbc.logging.RemoteQueryModifier; import io.trino.spi.connector.ColumnHandle; import io.trino.spi.connector.ConnectorSession; +import io.trino.spi.connector.JoinCondition; import io.trino.spi.connector.JoinType; import io.trino.spi.connector.SchemaTableName; import io.trino.spi.predicate.Domain; @@ -537,6 +538,39 @@ public void testBuildJoinSql() } } + @Test + public void testBuildJoinSqlLegacy() + throws SQLException + { + Connection connection = database.getConnection(); + + PreparedQuery preparedQuery = queryBuilder.legacyPrepareJoinQuery( + jdbcClient, + SESSION, + connection, + JoinType.INNER, + new PreparedQuery("SELECT * FROM \"test_table\"", List.of()), + new PreparedQuery("SELECT * FROM \"test_table\"", List.of()), + List.of(new JdbcJoinCondition(columns.get(7), JoinCondition.Operator.EQUAL, columns.get(8))), + Map.of(columns.get(2), "name1"), + Map.of(columns.get(3), "name2")); + try (PreparedStatement preparedStatement = queryBuilder.prepareStatement(jdbcClient, SESSION, connection, preparedQuery, Optional.empty())) { + assertThat(preparedQuery.getQuery()).isEqualTo("" + + "SELECT l.\"col_2\" AS \"name1\", r.\"col_3\" AS \"name2\" FROM " + + "(SELECT * FROM \"test_table\") l " + + "INNER JOIN " + + "(SELECT * FROM \"test_table\") r " + + "ON l.\"col_7\" = r.\"col_8\""); + long count = 0; + try (ResultSet resultSet = preparedStatement.executeQuery()) { + while (resultSet.next()) { + count++; + } + } + assertThat(count).isEqualTo(8); + } + } + @Test public void testBuildSqlWithLimit() throws SQLException diff --git a/plugin/trino-base-jdbc/src/test/java/io/trino/plugin/jdbc/TestJdbcMetadataConfig.java b/plugin/trino-base-jdbc/src/test/java/io/trino/plugin/jdbc/TestJdbcMetadataConfig.java index ed09ca49e4ba..e86c88d7a3fc 100644 --- a/plugin/trino-base-jdbc/src/test/java/io/trino/plugin/jdbc/TestJdbcMetadataConfig.java +++ b/plugin/trino-base-jdbc/src/test/java/io/trino/plugin/jdbc/TestJdbcMetadataConfig.java @@ -30,6 +30,7 @@ public void testDefaults() assertRecordedDefaults(recordDefaults(JdbcMetadataConfig.class) .setComplexExpressionPushdownEnabled(true) .setJoinPushdownEnabled(false) + .setComplexJoinPushdownEnabled(true) .setAggregationPushdownEnabled(true) .setTopNPushdownEnabled(true) .setDomainCompactionThreshold(32)); @@ -41,6 +42,7 @@ public void testExplicitPropertyMappings() Map properties = ImmutableMap.builder() .put("complex-expression-pushdown.enabled", "false") .put("join-pushdown.enabled", "true") + .put("join-pushdown.with-expressions", "false") .put("aggregation-pushdown.enabled", "false") .put("domain-compaction-threshold", "42") .put("topn-pushdown.enabled", "false") @@ -49,6 +51,7 @@ public void testExplicitPropertyMappings() JdbcMetadataConfig expected = new JdbcMetadataConfig() .setComplexExpressionPushdownEnabled(false) .setJoinPushdownEnabled(true) + .setComplexJoinPushdownEnabled(false) .setAggregationPushdownEnabled(false) .setTopNPushdownEnabled(false) .setDomainCompactionThreshold(42); diff --git a/plugin/trino-ignite/src/main/java/io/trino/plugin/ignite/IgniteClient.java b/plugin/trino-ignite/src/main/java/io/trino/plugin/ignite/IgniteClient.java index 7af9b61915fc..9fa2f946b2ad 100644 --- a/plugin/trino-ignite/src/main/java/io/trino/plugin/ignite/IgniteClient.java +++ b/plugin/trino-ignite/src/main/java/io/trino/plugin/ignite/IgniteClient.java @@ -595,6 +595,25 @@ public Optional implementJoin( return super.implementJoin(session, joinType, leftSource, leftProjections, rightSource, rightProjections, joinConditions, statistics); } + @Override + public Optional legacyImplementJoin( + ConnectorSession session, + JoinType joinType, + PreparedQuery leftSource, + PreparedQuery rightSource, + List joinConditions, + Map rightAssignments, + Map leftAssignments, + JoinStatistics statistics) + { + // Ignite does not support FULL JOIN + if (joinType == JoinType.FULL_OUTER) { + return Optional.empty(); + } + + return super.legacyImplementJoin(session, joinType, leftSource, rightSource, joinConditions, rightAssignments, leftAssignments, statistics); + } + @Override protected boolean isSupportedJoinCondition(ConnectorSession session, JdbcJoinCondition joinCondition) { diff --git a/plugin/trino-mariadb/src/main/java/io/trino/plugin/mariadb/MariaDbClient.java b/plugin/trino-mariadb/src/main/java/io/trino/plugin/mariadb/MariaDbClient.java index 2f8d2ff527de..18b6e2ec02b5 100644 --- a/plugin/trino-mariadb/src/main/java/io/trino/plugin/mariadb/MariaDbClient.java +++ b/plugin/trino-mariadb/src/main/java/io/trino/plugin/mariadb/MariaDbClient.java @@ -652,6 +652,24 @@ public Optional implementJoin( return super.implementJoin(session, joinType, leftSource, leftProjections, rightSource, rightProjections, joinConditions, statistics); } + @Override + public Optional legacyImplementJoin( + ConnectorSession session, + JoinType joinType, + PreparedQuery leftSource, + PreparedQuery rightSource, + List joinConditions, + Map rightAssignments, + Map leftAssignments, + JoinStatistics statistics) + { + if (joinType == JoinType.FULL_OUTER) { + // Not supported in MariaDB + return Optional.empty(); + } + return super.legacyImplementJoin(session, joinType, leftSource, rightSource, joinConditions, rightAssignments, leftAssignments, statistics); + } + @Override protected boolean isSupportedJoinCondition(ConnectorSession session, JdbcJoinCondition joinCondition) { diff --git a/plugin/trino-mysql/src/main/java/io/trino/plugin/mysql/MySqlClient.java b/plugin/trino-mysql/src/main/java/io/trino/plugin/mysql/MySqlClient.java index cece995ce02b..241ffd0cf051 100644 --- a/plugin/trino-mysql/src/main/java/io/trino/plugin/mysql/MySqlClient.java +++ b/plugin/trino-mysql/src/main/java/io/trino/plugin/mysql/MySqlClient.java @@ -1033,6 +1033,30 @@ public Optional implementJoin( () -> super.implementJoin(session, joinType, leftSource, leftProjections, rightSource, rightProjections, joinConditions, statistics)); } + @Override + public Optional legacyImplementJoin( + ConnectorSession session, + JoinType joinType, + PreparedQuery leftSource, + PreparedQuery rightSource, + List joinConditions, + Map rightAssignments, + Map leftAssignments, + JoinStatistics statistics) + { + if (joinType == JoinType.FULL_OUTER) { + // Not supported in MySQL + return Optional.empty(); + } + return implementJoinCostAware( + session, + joinType, + leftSource, + rightSource, + statistics, + () -> super.legacyImplementJoin(session, joinType, leftSource, rightSource, joinConditions, rightAssignments, leftAssignments, statistics)); + } + @Override protected boolean isSupportedJoinCondition(ConnectorSession session, JdbcJoinCondition joinCondition) { diff --git a/plugin/trino-postgresql/src/main/java/io/trino/plugin/postgresql/PostgreSqlClient.java b/plugin/trino-postgresql/src/main/java/io/trino/plugin/postgresql/PostgreSqlClient.java index 976f09c08285..ace69134eb2d 100644 --- a/plugin/trino-postgresql/src/main/java/io/trino/plugin/postgresql/PostgreSqlClient.java +++ b/plugin/trino-postgresql/src/main/java/io/trino/plugin/postgresql/PostgreSqlClient.java @@ -1074,6 +1074,30 @@ public Optional implementJoin( () -> super.implementJoin(session, joinType, leftSource, leftProjections, rightSource, rightProjections, joinConditions, statistics)); } + @Override + public Optional legacyImplementJoin( + ConnectorSession session, + JoinType joinType, + PreparedQuery leftSource, + PreparedQuery rightSource, + List joinConditions, + Map rightAssignments, + Map leftAssignments, + JoinStatistics statistics) + { + if (joinType == JoinType.FULL_OUTER) { + // FULL JOIN is only supported with merge-joinable or hash-joinable join conditions + return Optional.empty(); + } + return implementJoinCostAware( + session, + joinType, + leftSource, + rightSource, + statistics, + () -> super.legacyImplementJoin(session, joinType, leftSource, rightSource, joinConditions, rightAssignments, leftAssignments, statistics)); + } + @Override protected boolean isSupportedJoinCondition(ConnectorSession session, JdbcJoinCondition joinCondition) { diff --git a/plugin/trino-redshift/src/main/java/io/trino/plugin/redshift/RedshiftClient.java b/plugin/trino-redshift/src/main/java/io/trino/plugin/redshift/RedshiftClient.java index d39389fc0a7c..c1cc81b72033 100644 --- a/plugin/trino-redshift/src/main/java/io/trino/plugin/redshift/RedshiftClient.java +++ b/plugin/trino-redshift/src/main/java/io/trino/plugin/redshift/RedshiftClient.java @@ -426,6 +426,29 @@ public Optional implementJoin(ConnectorSession session, () -> super.implementJoin(session, joinType, leftSource, leftProjections, rightSource, rightProjections, joinConditions, statistics)); } + @Override + public Optional legacyImplementJoin(ConnectorSession session, + JoinType joinType, + PreparedQuery leftSource, + PreparedQuery rightSource, + List joinConditions, + Map rightAssignments, + Map leftAssignments, + JoinStatistics statistics) + { + if (joinType == JoinType.FULL_OUTER) { + // FULL JOIN is only supported with merge-joinable or hash-joinable join conditions + return Optional.empty(); + } + return implementJoinCostAware( + session, + joinType, + leftSource, + rightSource, + statistics, + () -> super.legacyImplementJoin(session, joinType, leftSource, rightSource, joinConditions, rightAssignments, leftAssignments, statistics)); + } + @Override protected void renameTable(ConnectorSession session, Connection connection, String catalogName, String remoteSchemaName, String remoteTableName, String newRemoteSchemaName, String newRemoteTableName) throws SQLException diff --git a/plugin/trino-singlestore/src/main/java/io/trino/plugin/singlestore/SingleStoreClient.java b/plugin/trino-singlestore/src/main/java/io/trino/plugin/singlestore/SingleStoreClient.java index a080363ff4b7..2f2afd7884cb 100644 --- a/plugin/trino-singlestore/src/main/java/io/trino/plugin/singlestore/SingleStoreClient.java +++ b/plugin/trino-singlestore/src/main/java/io/trino/plugin/singlestore/SingleStoreClient.java @@ -595,6 +595,24 @@ public Optional implementJoin( return super.implementJoin(session, joinType, leftSource, leftProjections, rightSource, rightProjections, joinConditions, statistics); } + @Override + public Optional legacyImplementJoin( + ConnectorSession session, + JoinType joinType, + PreparedQuery leftSource, + PreparedQuery rightSource, + List joinConditions, + Map rightAssignments, + Map leftAssignments, + JoinStatistics statistics) + { + if (joinType == JoinType.FULL_OUTER) { + // Not supported in SingleStore + return Optional.empty(); + } + return super.legacyImplementJoin(session, joinType, leftSource, rightSource, joinConditions, rightAssignments, leftAssignments, statistics); + } + @Override protected boolean isSupportedJoinCondition(ConnectorSession session, JdbcJoinCondition joinCondition) { diff --git a/plugin/trino-sqlserver/src/main/java/io/trino/plugin/sqlserver/SqlServerClient.java b/plugin/trino-sqlserver/src/main/java/io/trino/plugin/sqlserver/SqlServerClient.java index 2f1fac35ff77..a148e184ce72 100644 --- a/plugin/trino-sqlserver/src/main/java/io/trino/plugin/sqlserver/SqlServerClient.java +++ b/plugin/trino-sqlserver/src/main/java/io/trino/plugin/sqlserver/SqlServerClient.java @@ -904,6 +904,26 @@ public Optional implementJoin( () -> super.implementJoin(session, joinType, leftSource, leftProjections, rightSource, rightProjections, joinConditions, statistics)); } + @Override + public Optional legacyImplementJoin( + ConnectorSession session, + JoinType joinType, + PreparedQuery leftSource, + PreparedQuery rightSource, + List joinConditions, + Map rightAssignments, + Map leftAssignments, + JoinStatistics statistics) + { + return implementJoinCostAware( + session, + joinType, + leftSource, + rightSource, + statistics, + () -> super.legacyImplementJoin(session, joinType, leftSource, rightSource, joinConditions, rightAssignments, leftAssignments, statistics)); + } + private LongWriteFunction sqlServerTimeWriteFunction(int precision) { return new LongWriteFunction()