-
Notifications
You must be signed in to change notification settings - Fork 3.6k
Allow to enable case insenstive predicate pushdown in JDBC connectors #7022
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| /* | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
| package io.trino.plugin.jdbc; | ||
|
|
||
| import com.google.inject.Binder; | ||
| import io.airlift.configuration.AbstractConfigurationAwareModule; | ||
|
|
||
| import static io.trino.plugin.jdbc.JdbcModule.bindSessionPropertiesProvider; | ||
|
|
||
| public class VarcharPredicatePushdownModule | ||
| extends AbstractConfigurationAwareModule | ||
| { | ||
| @Override | ||
| protected void setup(Binder binder) | ||
| { | ||
| binder.bind(VarcharPushdownConfig.class); | ||
| bindSessionPropertiesProvider(binder, VarcharPredicatePushdownSessionProperties.class); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| /* | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
| package io.trino.plugin.jdbc; | ||
|
|
||
| import com.google.common.collect.ImmutableList; | ||
| import io.trino.plugin.base.session.SessionPropertiesProvider; | ||
| import io.trino.spi.connector.ConnectorSession; | ||
| import io.trino.spi.session.PropertyMetadata; | ||
|
|
||
| import javax.inject.Inject; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| import static io.trino.spi.session.PropertyMetadata.booleanProperty; | ||
|
|
||
| public class VarcharPredicatePushdownSessionProperties | ||
| implements SessionPropertiesProvider | ||
| { | ||
| public static final String UNSAFE_VARCHAR_PUSHDOWN = "unsafe-varchar-pushdown"; | ||
|
|
||
| private final List<PropertyMetadata<?>> properties; | ||
|
|
||
| @Inject | ||
| public VarcharPredicatePushdownSessionProperties(VarcharPushdownConfig config) | ||
| { | ||
| properties = ImmutableList.<PropertyMetadata<?>>builder() | ||
| .add(booleanProperty( | ||
| UNSAFE_VARCHAR_PUSHDOWN, | ||
| "Enable potentially unsafe SQL pushdown based on char or varchar columns. " + | ||
| "Note that it may cause incorrect query results.", | ||
| config.isUnsafeVarcharPushdownEnabled(), | ||
| false)) | ||
| .build(); | ||
| } | ||
|
|
||
| @Override | ||
| public List<PropertyMetadata<?>> getSessionProperties() | ||
| { | ||
| return properties; | ||
| } | ||
|
|
||
| public static boolean isUnsafeVarcharPushdownEnabled(ConnectorSession session) | ||
| { | ||
| return session.getProperty(UNSAFE_VARCHAR_PUSHDOWN, Boolean.class); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| /* | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
| package io.trino.plugin.jdbc; | ||
|
|
||
| import io.airlift.configuration.Config; | ||
| import io.airlift.configuration.ConfigDescription; | ||
|
|
||
| public class VarcharPushdownConfig | ||
| { | ||
| private boolean unsafeVarcharPushdownEnabled; | ||
|
|
||
| public boolean isUnsafeVarcharPushdownEnabled() | ||
| { | ||
| return unsafeVarcharPushdownEnabled; | ||
| } | ||
|
|
||
| @Config("unsafe-varchar-pushdown.enabled") | ||
| @ConfigDescription( | ||
| "Enable potentially unsafe SQL pushdown based on char or varchar columns. " + | ||
| "Note that it may cause incorrect query results.") | ||
| public VarcharPushdownConfig setUnsafeVarcharPushdownEnabled(boolean unsafeVarcharPushdownEnabled) | ||
| { | ||
| this.unsafeVarcharPushdownEnabled = unsafeVarcharPushdownEnabled; | ||
| return this; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -18,6 +18,7 @@ | |
| import io.trino.spi.connector.SortOrder; | ||
| import io.trino.sql.planner.assertions.PlanMatchPattern; | ||
| import io.trino.sql.planner.plan.ExchangeNode; | ||
| import io.trino.sql.planner.plan.FilterNode; | ||
| import io.trino.sql.planner.plan.JoinNode; | ||
| import io.trino.sql.planner.plan.TableScanNode; | ||
| import io.trino.sql.planner.plan.TopNNode; | ||
|
|
@@ -27,6 +28,7 @@ | |
| import io.trino.testing.sql.TestTable; | ||
| import org.intellij.lang.annotations.Language; | ||
| import org.testng.SkipException; | ||
| import org.testng.annotations.DataProvider; | ||
| import org.testng.annotations.Test; | ||
|
|
||
| import java.util.List; | ||
|
|
@@ -35,6 +37,7 @@ | |
| import static com.google.common.base.Verify.verify; | ||
| import static com.google.common.collect.ImmutableList.toImmutableList; | ||
| import static com.google.common.collect.MoreCollectors.toOptional; | ||
| import static io.trino.plugin.jdbc.VarcharPredicatePushdownSessionProperties.UNSAFE_VARCHAR_PUSHDOWN; | ||
| import static io.trino.sql.planner.assertions.PlanMatchPattern.anyTree; | ||
| import static io.trino.sql.planner.assertions.PlanMatchPattern.exchange; | ||
| import static io.trino.sql.planner.assertions.PlanMatchPattern.node; | ||
|
|
@@ -48,6 +51,7 @@ | |
| import static io.trino.testing.TestingConnectorBehavior.SUPPORTS_PREDICATE_PUSHDOWN_WITH_VARCHAR_EQUALITY; | ||
| import static io.trino.testing.TestingConnectorBehavior.SUPPORTS_PREDICATE_PUSHDOWN_WITH_VARCHAR_INEQUALITY; | ||
| import static io.trino.testing.TestingConnectorBehavior.SUPPORTS_TOPN_PUSHDOWN; | ||
| import static io.trino.testing.sql.TestTable.randomTableSuffix; | ||
| import static java.lang.String.format; | ||
| import static org.assertj.core.api.Assertions.assertThat; | ||
|
|
||
|
|
@@ -553,4 +557,58 @@ protected Session joinPushdownEnabled(Session session) | |
| .setCatalogSessionProperty(session.getCatalog().orElseThrow(), "join_pushdown_enabled", "true") | ||
| .build(); | ||
| } | ||
|
|
||
| @Test(dataProvider = "testCaseInsensitivePredicatePushdownDataProvider") | ||
| public void testCaseInsensitivePredicatePushdown(String type) | ||
| { | ||
| Session unsafeVarcharPushdown = Session.builder(getSession()) | ||
| .setCatalogSessionProperty(getSession().getCatalog().orElseThrow(), UNSAFE_VARCHAR_PUSHDOWN, "true") | ||
| .build(); | ||
|
|
||
| if (hasBehavior(SUPPORTS_PREDICATE_PUSHDOWN_WITH_VARCHAR_INEQUALITY)) { | ||
| assertQueryFails(unsafeVarcharPushdown, "SELECT 1", "Unknown session property .*.unsafe-varchar-pushdown"); | ||
| return; | ||
| } | ||
| String tableName = "test_case_insensitive_predicate_pushdown" + randomTableSuffix(); | ||
| assertQuerySucceeds(format("CREATE TABLE %s (value %s)", tableName, type)); | ||
| assertQuerySucceeds(format("INSERT INTO %s VALUES 'a', 'A', 'b', 'B'", tableName)); | ||
|
|
||
| assertThat(query(unsafeVarcharPushdown, format("SELECT value FROM %s WHERE value = 'a'", tableName))) | ||
| // possibly incorrect results with unexpected 'A' | ||
| .isFullyPushedDown(); | ||
|
Comment on lines
577
to
578
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't understand.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That is because |
||
| assertThat(query(unsafeVarcharPushdown, format("SELECT value FROM %s WHERE value != 'a'", tableName))) | ||
| // possibly incorrect results with missing 'A' | ||
| .isFullyPushedDown(); | ||
| assertThat(query(unsafeVarcharPushdown, format("SELECT value FROM %s WHERE value > 'A'", tableName))) | ||
| // possibly incorrect results with missing 'a' | ||
| .isFullyPushedDown(); | ||
|
|
||
| // Verify that results are correct when session property is not used | ||
| assertThat(query(format("SELECT value FROM %s WHERE value = 'a'", tableName))) | ||
| .skippingTypesCheck() | ||
| .matches("VALUES 'a'"); | ||
| assertThat(query(format("SELECT value FROM %s WHERE value != 'a'", tableName))) | ||
| .isNotFullyPushedDown(FilterNode.class) | ||
| .skippingTypesCheck() | ||
| .matches("VALUES 'A', 'b', 'B'"); | ||
| assertThat(query(format("SELECT value FROM %s WHERE value != 'a'", tableName))) | ||
| .isNotFullyPushedDown(FilterNode.class) | ||
| .skippingTypesCheck() | ||
| .matches("VALUES 'A', 'b', 'B'"); | ||
| assertThat(query(format("SELECT value FROM %s WHERE value > 'A'", tableName))) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would prefer if you tested that ordering is correct too. Some databases/collations can sort Or am I broadening the scope by introducing
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
You are. However it sounds like a good idea to have a single toggle to control both pushdown at once.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. BTW same goes to aggregation push down. Notice that pushing down DISTINCT or GROUP BY on varchar column may produce different results. Is it handled today anyhow? It sounds to me that it could be also controlled with the same switch. @findepi ?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It should, but we also need a reusable test for aggregations as well.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Reusable tests for order by and aggregations are out of my scope. Will create tickets for that, possibly as bugs as I would expect now wrong results. Also I am going to rename toggle from
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. #7320, order by is handled by io.trino.plugin.jdbc.BaseJdbcConnectorTest#testCaseSensitiveTopNPushdown |
||
| .isNotFullyPushedDown(FilterNode.class) | ||
| .skippingTypesCheck() | ||
| .matches("VALUES 'a', 'B', 'b'"); | ||
|
|
||
| assertQuerySucceeds("DROP TABLE " + tableName); | ||
| } | ||
|
|
||
| @DataProvider | ||
| public Object[][] testCaseInsensitivePredicatePushdownDataProvider() | ||
| { | ||
| return new Object[][] { | ||
| {"char(1)"}, | ||
| {"varchar(1)"}, | ||
| }; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| /* | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
| package io.trino.plugin.jdbc; | ||
|
|
||
| import com.google.common.collect.ImmutableMap; | ||
| import org.testng.annotations.Test; | ||
|
|
||
| import java.util.Map; | ||
|
|
||
| import static io.airlift.configuration.testing.ConfigAssertions.assertFullMapping; | ||
| import static io.airlift.configuration.testing.ConfigAssertions.assertRecordedDefaults; | ||
| import static io.airlift.configuration.testing.ConfigAssertions.recordDefaults; | ||
|
|
||
| public class TestVarcharPushdownConfig | ||
| { | ||
| @Test | ||
| public void testDefaults() | ||
| { | ||
| assertRecordedDefaults(recordDefaults(VarcharPushdownConfig.class) | ||
| .setUnsafeVarcharPushdownEnabled(false)); | ||
| } | ||
|
|
||
| @Test | ||
| public void testExplicitPropertyMappings() | ||
| { | ||
| Map<String, String> properties = new ImmutableMap.Builder<String, String>() | ||
| .put("unsafe-varchar-pushdown.enabled", "true") | ||
| .build(); | ||
|
|
||
| VarcharPushdownConfig expected = new VarcharPushdownConfig() | ||
| .setUnsafeVarcharPushdownEnabled(true); | ||
|
|
||
| assertFullMapping(properties, expected); | ||
| } | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.