-
Notifications
You must be signed in to change notification settings - Fork 3.1k
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
Support table handles with columns in JDBC applyProjection #14770
Conversation
Set<JdbcColumnHandle> newColumnSet = newColumns.stream() | ||
// It may happen fresh table handle comes with a columns prepared already. | ||
// In such case it may happen that applyProjection may want to add UPDATE_ROW_ID id, which is created later during the planning. | ||
.filter(column -> !column.getColumnName().equals(UPDATE_ROW_ID)) | ||
.collect(toImmutableSet()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move your changes just before verify
.
Why?
2022-10-26T13:13:38.567-0500 ERROR pool-3-thread-1 io.trino.testng.services.ProgressLoggingListener [TEST FAILURE] io.trino.faulttolerant.postgresql.TestPostgresTaskFailureRecoveryTest.testDelete; (took: 3 minutes and 1 seconds)
io.trino.testing.QueryFailedException: The optimizer exhausted the time limit of 180000 ms: Top rules: {
io.trino.sql.planner.iterative.rule.PushProjectionIntoTableScan@3ed486ed: 51209 ms, 2133950 invocations, 2133950 applications,
io.trino.sql.planner.iterative.rule.PruneTableScanColumns@54c3ba96: 5112 ms, 2133950 invocations, 0 applications,
io.trino.sql.planner.iterative.rule.PushProjectionThroughUnion@16d94047: 2772 ms, 2133950 invocations, 0 applications,
io.trino.sql.planner.iterative.rule.PruneAggregationColumns@53236a7d: 2770 ms, 2133950 invocations, 0 applications,
io.trino.sql.planner.iterative.rule.PushDownDereferenceThroughJoin@c0241fd: 2327 ms, 2133950 invocations, 0 applications }
at io.trino.testing.AbstractTestingTrinoClient.execute(AbstractTestingTrinoClient.java:122)
at io.trino.testing.DistributedQueryRunner.executeWithQueryId(DistributedQueryRunner.java:496)
at io.trino.faulttolerant.BaseFailureRecoveryTest$FailureRecoveryAssert.execute(BaseFailureRecoveryTest.java:599)
at io.trino.faulttolerant.BaseFailureRecoveryTest$FailureRecoveryAssert.executeExpected(BaseFailureRecoveryTest.java:560)
at io.trino.faulttolerant.BaseFailureRecoveryTest$FailureRecoveryAssert.isCoordinatorOnly(BaseFailureRecoveryTest.java:638)
at io.trino.faulttolerant.jdbc.BaseJdbcFailureRecoveryTest.testDelete(BaseJdbcFailureRecoveryTest.java:73)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:104)
at org.testng.internal.Invoker.invokeMethod(Invoker.java:645)
at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:851)
at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1177)
at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:129)
at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:112)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: io.trino.spi.TrinoException: The optimizer exhausted the time limit of 180000 ms: Top rules: {
io.trino.sql.planner.iterative.rule.PushProjectionIntoTableScan@3ed486ed: 51209 ms, 2133950 invocations, 2133950 applications,
io.trino.sql.planner.iterative.rule.PruneTableScanColumns@54c3ba96: 5112 ms, 2133950 invocations, 0 applications,
io.trino.sql.planner.iterative.rule.PushProjectionThroughUnion@16d94047: 2772 ms, 2133950 invocations, 0 applications,
io.trino.sql.planner.iterative.rule.PruneAggregationColumns@53236a7d: 2770 ms, 2133950 invocations, 0 applications,
io.trino.sql.planner.iterative.rule.PushDownDereferenceThroughJoin@c0241fd: 2327 ms, 2133950 invocations, 0 applications }
at io.trino.sql.planner.iterative.IterativeOptimizer$Context.checkTimeoutNotExhausted(IterativeOptimizer.java:380)
at io.trino.sql.planner.iterative.IterativeOptimizer.exploreNode(IterativeOptimizer.java:157)
at io.trino.sql.planner.iterative.IterativeOptimizer.exploreGroup(IterativeOptimizer.java:133)
at io.trino.sql.planner.iterative.IterativeOptimizer.exploreChildren(IterativeOptimizer.java:252)
at io.trino.sql.planner.iterative.IterativeOptimizer.exploreGroup(IterativeOptimizer.java:135)
at io.trino.sql.planner.iterative.IterativeOptimizer.exploreChildren(IterativeOptimizer.java:252)
at io.trino.sql.planner.iterative.IterativeOptimizer.exploreGroup(IterativeOptimizer.java:135)
at io.trino.sql.planner.iterative.IterativeOptimizer.exploreChildren(IterativeOptimizer.java:252)
at io.trino.sql.planner.iterative.IterativeOptimizer.exploreGroup(IterativeOptimizer.java:135)
at io.trino.sql.planner.iterative.IterativeOptimizer.optimize(IterativeOptimizer.java:118)
at io.trino.sql.planner.LogicalPlanner.plan(LogicalPlanner.java:247)
at io.trino.sql.planner.LogicalPlanner.plan(LogicalPlanner.java:222)
at io.trino.sql.planner.LogicalPlanner.plan(LogicalPlanner.java:217)
at io.trino.execution.SqlQueryExecution.doPlanQuery(SqlQueryExecution.java:475)
at io.trino.execution.SqlQueryExecution.planQuery(SqlQueryExecution.java:456)
at io.trino.execution.SqlQueryExecution.start(SqlQueryExecution.java:397)
at io.trino.execution.SqlQueryManager.createQuery(SqlQueryManager.java:249)
at io.trino.dispatcher.LocalDispatchQuery.lambda$startExecution$7(LocalDispatchQuery.java:143)
at io.trino.$gen.Trino_testversion____20221026_180846_142.run(Unknown Source)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
at java.base/java.lang.Thread.run(Thread.java:833)
@@ -100,6 +101,7 @@ | |||
implements JdbcMetadata | |||
{ | |||
private static final String SYNTHETIC_COLUMN_NAME_PREFIX = "_pfgnrtd_"; | |||
private static final String UPDATE_ROW_ID = "_trino_artificial_column_handle_for_update_row_id_"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't it too long?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think so. It is that long to make sure that we don't hit a conflict.
plugin/trino-base-jdbc/src/main/java/io/trino/plugin/jdbc/DefaultJdbcMetadata.java
Outdated
Show resolved
Hide resolved
// In such case it may happen that applyProjection may want to add UPDATE_ROW_ID id, which is created later during the planning. | ||
.filter(column -> !column.getColumnName().equals(UPDATE_ROW_ID)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about other synthetic handles like DELETE_ROW_ID, MERGE_ROW_ID? We don't care yet since DefaultJdbcMetadata doesn't provide them (via getDeleteRowIdColumnHandle
)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no constant name for them, because they don't have implementation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is not yet implemented yet.
Set<JdbcColumnHandle> newColumnSet = newColumns.stream() | ||
// It may happen fresh table handle comes with a columns prepared already. | ||
// In such case it may happen that applyProjection may want to add UPDATE_ROW_ID id, which is created later during the planning. | ||
.filter(column -> !column.getColumnName().equals(UPDATE_ROW_ID)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
UPDATE_ROW_ID could be different for different connectors. So this will not work for some, which have getDeleteRowIdColumnHandle
overriden.
Please consider
Set<JdbcColumnHandle> tableSyntheticColumnSet = ImmutableSet.<JdbcColumnHandle>builder()
.addAll(tableColumnSet)
.add((JdbcColumnHandle) getDeleteRowIdColumnHandle(session, table))
.add((JdbcColumnHandle) getMergeRowIdColumnHandle(session, table))
.add((JdbcColumnHandle) getUpdateRowIdColumnHandle(session, table, ImmutableList.of())) // not sure about ImmutableList.of()
.build();
verify(tableSyntheticColumnSet.containsAll(newColumnSet), "applyProjection called with columns %s and some are not available in existing query: %s", newColumnSet, tableSyntheticColumnSet);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and actually these will fail:
.add((JdbcColumnHandle) getMergeRowIdColumnHandle(session, table))
.add((JdbcColumnHandle) getUpdateRowIdColumnHandle(session, table, ImmutableList.of())) // not sure about ImmutableList.of()
because they throw new TrinoException(NOT_SUPPORTED
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So may be add a new public
method List<String> getSyntacticColumnNames()
and .filter(column -> !getSyntacticColumnNames().contains(column.getColumnName())
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's not overcomplicate things
It may happen fresh table handle comes with a columns prepared already. The BaseJdbcClient#getTableHandle may return table handle with columns included. That way it is possible to skip another remote metadata call in BaseJdbcClient#getColumns. However, now typically JDBC connectors do not provide table columns in table handle by default so the verify in applyProjection was very strict and assumed that applyProjection is not going to add any new column to table handle. However it may happen that applyProjection may want to add UPDATE_ROW_ID id, which is created later during the planning for UPDATE and DELETE statements. This column is artificial, and it is used only in planning. Co-authored-by: Sasha Sheikin <myminitrue@gmail.com>
2eea471
to
814d8cf
Compare
Does this require a release note? |
No release notes. |
Support table handles with columns in JDBC applyProjection
It may happen fresh table handle comes with a columns prepared
already. The BaseJdbcClient#getTableHandle may return table handle with
columns included. That way it is possible to skip another remote metadata call
in BaseJdbcClient#getColumns.
However, now typically JDBC connectors do not provide table columns in
table handle by default so the verify in applyProjection was very
strict and assumed that applyProjection is not going to add any new
column to table handle. However it may happen that applyProjection
may want to add UPDATE_ROW_ID id, which is created later during the
planning for UPDATE and DELETE statements. This column is artificial,
and it is used only in planning.