-
Notifications
You must be signed in to change notification settings - Fork 3k
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 cast projection pushdown in oracle #22728
Support cast projection pushdown in oracle #22728
Conversation
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.
lgtm
plugin/trino-oracle/src/main/java/io/trino/plugin/oracle/RewriteCast.java
Outdated
Show resolved
Hide resolved
new CastTestCase("char(10)", "varchar(1001)"), | ||
new CastTestCase("char(10)", "varchar"), | ||
new CastTestCase("varchar(10)", "varchar(1001)"), | ||
new CastTestCase("varchar(10)", "varchar"), |
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's pity. This is very common usecase.
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.
can't we do something for varchars?
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 think we can use TO_NCLOB
to cast in varchar
or varchar(... >1000 CHAR)
. https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/TO_NCLOB.html
Trying it out.
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.
Apart from CAST
pushdown, comparison with clob
type was not supported for pushdown. So I have made the change to support clob
type comparison pushdown.
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.
magic!
plugin/trino-oracle/src/test/java/io/trino/plugin/oracle/BaseOracleConnectorTest.java
Outdated
Show resolved
Hide resolved
plugin/trino-oracle/src/test/java/io/trino/plugin/oracle/BaseOracleConnectorTest.java
Outdated
Show resolved
Hide resolved
plugin/trino-oracle/src/test/java/io/trino/plugin/oracle/BaseOracleConnectorTest.java
Outdated
Show resolved
Hide resolved
assertJoinFullyPushedDown(session, leftTable, rightTable, "LEFT JOIN", "l.varchar_50 = r.varchar_100", Arrays.asList(1, 2)); | ||
assertJoinFullyPushedDown(session, leftTable, rightTable, "RIGHT JOIN", "l.varchar_50 = r.varchar_100", Arrays.asList(1, null)); | ||
assertJoinFullyPushedDown(session, leftTable, rightTable, "INNER JOIN", "l.varchar_50 = r.varchar_100", List.of(1)); | ||
assertJoinFullyPushedDown(session, leftTable, rightTable, "INNER JOIN", "r.varchar_100 = l.varchar_50", List.of(1)); |
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.
why join criteria in this assertion differs from others?
plugin/trino-oracle/src/test/java/io/trino/plugin/oracle/BaseOracleConnectorTest.java
Outdated
Show resolved
Hide resolved
targetTypeHandle.get())); | ||
} | ||
|
||
private static Optional<JdbcTypeHandle> toJdbcTypeHandle(Type type) |
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.
This method is the meat of this PR.
And this is a main opportunity to improve for function pushdown.
plugin/trino-oracle/src/test/java/io/trino/plugin/oracle/BaseOracleConnectorTest.java
Outdated
Show resolved
Hide resolved
plugin/trino-oracle/src/test/java/io/trino/plugin/oracle/BaseOracleConnectorTest.java
Outdated
Show resolved
Hide resolved
|
||
assertJoinFullyPushedDown(session, leftTable, rightTable, "LEFT JOIN", "l.varchar_50 = r.varchar_100", Arrays.asList(1, 2)); | ||
assertJoinFullyPushedDown(session, leftTable, rightTable, "RIGHT JOIN", "l.varchar_50 = r.varchar_100", Arrays.asList(1, null)); | ||
assertJoinFullyPushedDown(session, leftTable, rightTable, "INNER JOIN", "l.varchar_50 = r.varchar_100", List.of(1)); |
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.
woah
1acef9d
to
f4204f3
Compare
new CastTestCase("integer", "decimal(15)"), | ||
new CastTestCase("integer", "decimal(10, 2)"), | ||
new CastTestCase("integer", "decimal(30, 2)"), | ||
new CastTestCase("smallint", "integer"), |
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.
Despite the complexity of the implementation
f4204f3#r1683242993
I guess these return types can be handled too. Could you please try?
plugin/trino-oracle/src/test/java/io/trino/plugin/oracle/BaseOracleConnectorTest.java
Outdated
Show resolved
Hide resolved
plugin/trino-oracle/src/main/java/io/trino/plugin/oracle/RewriteStringComparison.java
Outdated
Show resolved
Hide resolved
plugin/trino-oracle/src/main/java/io/trino/plugin/oracle/RewriteStringComparison.java
Outdated
Show resolved
Hide resolved
plugin/trino-oracle/src/main/java/io/trino/plugin/oracle/RewriteStringComparison.java
Outdated
Show resolved
Hide resolved
plugin/trino-oracle/src/test/java/io/trino/plugin/oracle/BaseOracleConnectorTest.java
Outdated
Show resolved
Hide resolved
plugin/trino-oracle/src/test/java/io/trino/plugin/oracle/BaseOracleConnectorTest.java
Outdated
Show resolved
Hide resolved
plugin/trino-oracle/src/test/java/io/trino/plugin/oracle/BaseOracleConnectorTest.java
Outdated
Show resolved
Hide resolved
|
||
private static String toNClob(String expression) | ||
{ | ||
return "TO_NCLOB(%s)".formatted(expression); |
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 if during trino reads the remote DB the unsupported by trino type (some remote-specific type) was force-mapped to text,
later here it was capturedAs CharType or VarcharType ?
Will TO_NCLOB work correctly?
Maybe it's the case here too https://github.com/trinodb/trino/pull/22203/files#diff-510ce28e8ade87630227de284298df1cb44186f73bc9f2219e1f6ad6505d410aR66
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.
removed this change. nclob
cast pushdown is out of scope of this PR.
plugin/trino-oracle/src/main/java/io/trino/plugin/oracle/RewriteCast.java
Outdated
Show resolved
Hide resolved
plugin/trino-oracle/src/main/java/io/trino/plugin/oracle/RewriteCast.java
Outdated
Show resolved
Hide resolved
plugin/trino-oracle/src/main/java/io/trino/plugin/oracle/RewriteCast.java
Outdated
Show resolved
Hide resolved
plugin/trino-oracle/src/test/java/io/trino/plugin/oracle/BaseOracleConnectorTest.java
Outdated
Show resolved
Hide resolved
if (!clobInfo[1]) { | ||
secondArgument = toNClob(secondExpression); | ||
} | ||
return "DBMS_LOB.compare(%s, %s) %s 0".formatted(firstArgument, secondArgument, operator); |
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.
Is the DBMS_LOB is something which is provided by default on Oracle or is it some sort of a package which needs to be installed ? How would it work with collation ? What if the underlying bytes in CLOB has some invalid string pattern - in this case won't Trino and Oracle differ ?
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.
removed this change. nclob comparison is out of scope of this PR.
} | ||
} | ||
|
||
private static List<CastTestCase> supportedCastTypePushdown() |
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.
This is same as parameterized tests ? Can we have an assertion which assert all types of join and we could pass the types as an argument to it ?
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.
This is same as parameterized tests ?
Yes
Can we have an assertion which assert all types of join and we could pass the types as an argument to it ?
I have a test testAllJoinPushdownWithCast
which covers all join but only with one data type. For other all data types I am verifying only with INNER JOIN
. Should we test all data types with all join? Or one should be fine?
plugin/trino-oracle/src/main/java/io/trino/plugin/oracle/OracleClient.java
Show resolved
Hide resolved
plugin/trino-oracle/src/main/java/io/trino/plugin/oracle/RewriteCast.java
Outdated
Show resolved
Hide resolved
fa267be
to
77cf16e
Compare
Thanks @ssheikin @Praveen2112 @marcinsbd @SemionPar for the review. Addressed comments. Removing pushdown support for Here is summary:
|
77cf16e
to
e341765
Compare
Added There is test case enhancement required to cover this comment #22728 (comment) . I will create table using remote database instead of trino. |
b44eb71
to
424f81d
Compare
Adding stale-ignore label since this looks like its very active but just stalled a bit. |
9fb7a98
to
26e9272
Compare
(Do not cast unnecessary with extra space padding when target char type has more length than source char type) |
26e9272
to
831320b
Compare
(rebased with master) |
831320b
to
4151d4c
Compare
(CI fix) |
4151d4c
to
93b238f
Compare
plugin/trino-base-jdbc/src/main/java/io/trino/plugin/jdbc/expression/AbstractRewriteCast.java
Outdated
Show resolved
Hide resolved
plugin/trino-base-jdbc/src/main/java/io/trino/plugin/jdbc/expression/AbstractRewriteCast.java
Outdated
Show resolved
Hide resolved
plugin/trino-oracle/src/main/java/io/trino/plugin/oracle/RewriteCast.java
Show resolved
Hide resolved
import static java.util.Arrays.asList; | ||
import static org.assertj.core.api.Assertions.assertThat; | ||
|
||
public abstract class BaseOracleCastPushdownTest |
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.
Do we need this abstraction ?
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.
Abstraction will be useful in the scenario where we might want to verify cast pushdown for different query runner.
93b238f
to
1d4bd4b
Compare
plugin/trino-base-jdbc/src/main/java/io/trino/plugin/jdbc/expression/AbstractRewriteCast.java
Outdated
Show resolved
Hide resolved
assertThatThrownBy(() -> getQueryRunner().execute("SELECT CAST(%s AS %s) FROM %s".formatted(testCase.sourceColumn(), testCase.castType(), leftTable()))) | ||
.hasMessageMatching("(.*)Cannot cast (.*) to (.*)"); |
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.
Does it thrown by Trino or by Oracle or by both ?
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.
By Trino.
1d4bd4b
to
cedf6fb
Compare
Pushdown was giving incorrect result wrt Unicode character values and |
cedf6fb
to
97daf47
Compare
(rebased with master) |
97daf47
to
9a002a4
Compare
The issue seems to be happening in this case: When casting
|
9a002a4
to
b9cf9f3
Compare
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.
Please evaluate a possibility of case-insensitive matching in Oracle when pushed down.
plugin/trino-base-jdbc/src/main/java/io/trino/plugin/jdbc/expression/AbstractRewriteCast.java
Show resolved
Hide resolved
public void testCastFails() | ||
{ | ||
for (CastTestCase testCase : failCast()) { | ||
assertThatThrownBy(() -> getQueryRunner().execute("SELECT CAST(%s AS %s) FROM %s".formatted(testCase.sourceColumn(), testCase.castType(), leftTable()))) |
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.
When this test fails, it doesn't say which condition has failed exactly. Do you think we could improve on that?
Took a quick look - as()
or withFailMessage()
does not seem to work, maybe custom satifies()
would.
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.
Thanks @SemionPar, I will take this as a follow up.
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.
@krvikash Sure thing!
One more thought that crossed my mind: if cast fails at runtime with different message when pushed down, say:
Trino: Cannot cast DECIMAL(19, 2) '99999999999999999.99' to DECIMAL(10, 2)
Teradata: [Error 2616] [SQLState 22003] Numeric overflow occurred during computation.
It would be good to be able to use testCastFails
to test such cases, don't you think? We might want to add message customization to CastTestCase
(or introduce FailCastTestCase
) - consider this another improvement idea.
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.
@SemionPar Here is the refactoring PR #23737
b9cf9f3
to
69df024
Compare
🎉 |
Description
This PR adds support for cast projection pushdown for the Oracle connector. This uses the framework introduced in #22203 for cast projection pushdown.
Currently, this PR only adds support for the
CHAR
andVARCHAR
cast pushdown, which has the following limitations:Char
having length > 500Varchar
having length > 1000Char
cast toVarchar
Release notes
(X) Release notes are required, with the following suggested text: