-
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 automatic type coercion in Iceberg table creation #13981
Support automatic type coercion in Iceberg table creation #13981
Conversation
6f29241
to
4993fb1
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.
This change has broader ranging implications around the semantics of CREATE TABLE
and CREATE TABLE ... AS
, and it's not as simple as adding support for precision <= 6 to the connector.
We had a discussion about this exact topic a couple of years ago, but I can't find it right now. @findepi, do you remember?
Agreed, I'm not saying this PR is fully done or right at this moment. The current behaviour in a CREATE TABLE is different from the CTAS. For example: the user created a table with TIMESTAMP(6), so we might say that the user opted for this precision and is OK with rounding (note that I have not checked the SQL spec on this but this is what is happening now).
Now in the case of a CTAS statement this PR changes the behaviour to distinguish between the target table type and the query type. The table type can be specified/overridden by the connector. For Iceberg we define the table type as TIMESTAMP(6) and the query type might be either lower, same or higher precision. I think what is missing is that we should throw an exception in case of loss of precision. I thought this was the goal of the As far as I can see that is the impact, actually if a connector doesn't implement |
@martint Yeah, don't know where it was (slack, PRs or issues). AFAIR we discussed being able to CTAS into a JDBC connector and we decided we will allow users to export data, even if we cannot create columns of requested types (eg more or less precision than requested). This was the driving use-case (obviously at odds with our desire to create table schema exactly as requested) and this is how it got implemented in JDBC connectors. For reference, this is probably the first commit implementing this logic: 425c3b0 (part of #5342).
This is a good improvement, as it allows us to differentiate between CTAS's implicit schema and CT explicit schema and handle them differently, addressing the above mentioned desire to create table schema with types exactly as requested by the user, or fail if it's not possible. Involving engine in the conversion is a good change too. In 425c3b0 (and other such implementations), the connector needs to take care of CAST's rounding logic upon CTAS and doesn't have to do this upon iNSERT. This is unnecessary complexity. This is also much harder for connectors like Iceberg and Hive, where the conversion would be implemented in the file writers layer, or come at a performance cost. Letting the connector tell the engine "hey, this is the effective table schema" during CTAS frees the connector from that logic.
Just like in INSERT, we should round. cc @losipiuk |
@mdesmet I'd suggest to separate |
Created #13994 |
@mdesmet |
4993fb1
to
9ccbae3
Compare
Build is 🔴
|
return Types.TimeType.get(); | ||
} | ||
if (type.equals(TIMESTAMP_MICROS)) { | ||
if (type instanceof TimestampType timestampType) { | ||
if (timestampType.getPrecision() > 6) { |
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.
Considering that the table foo
has a column col
of type timestamp(6)
, why would we allow statements like the following:
ALTER TABLE foo ALTER COLUMN col SET DATA TYPE timestamp(3)
?
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.
My understanding is that even when internally iceberg stores time values using microseconds precision. We could still allow any precision in Trino.
However I agree this goes beyond the scope of this PR, I will restore the existing behaviour.
Build is still 🔴 Still the same method is failing: |
9ccbae3
to
6bdafb9
Compare
plugin/trino-iceberg/src/main/java/io/trino/plugin/iceberg/IcebergMetadata.java
Outdated
Show resolved
Hide resolved
plugin/trino-iceberg/src/main/java/io/trino/plugin/iceberg/IcebergMetadata.java
Outdated
Show resolved
Hide resolved
plugin/trino-iceberg/src/main/java/io/trino/plugin/iceberg/IcebergMetadata.java
Outdated
Show resolved
Hide resolved
plugin/trino-iceberg/src/test/java/io/trino/plugin/iceberg/BaseIcebergConnectorTest.java
Show resolved
Hide resolved
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.
Tested successfully with manually on my local machine.
There is still a bit of testing to be added.
Looks good overall.
6bdafb9
to
b0efb73
Compare
46e23d0
to
3fa3f1f
Compare
Build is 🔴
|
3fa3f1f
to
25b05fb
Compare
{ | ||
if (setup.sourceValueLiteral().equals("TIMESTAMP '1969-12-31 23:59:59.999999499999'")) { | ||
return Optional.of(setup.withNewValueLiteral("TIMESTAMP '1970-01-01 00:00:00.999999'")); | ||
} | ||
if (setup.sourceValueLiteral().equals("TIMESTAMP '1969-12-31 23:59:59.9999994'")) { | ||
return Optional.of(setup.withNewValueLiteral("TIMESTAMP '1970-01-01 00:00:00.999999'")); | ||
} | ||
return Optional.of(setup); |
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.
@findepi : Do you know if this is something ORC related?
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.
not sure i have context. this being what exactly?
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.
Providing a timestamp like TIMESTAMP '1969-12-31 23:59:59.9999994
and TIMESTAMP '1969-12-31 23:59:59.999999499999'
as an input value for a CTAS statement results in a Iceberg table with value TIMESTAMP '1970-01-01 00:00:00.999999
.
Is this expected for ORC files?
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 looks like a bug. i remember there were some +/-1s for at-the-epoch values in ORC, but @dain will know more
are you able to reproduce this without coercions, i.e. with direct insert of a timestamp(6) value into Iceberg?
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 seems also prevalent in Hive:
trino:default> CREATE table r AS SELECT TIMESTAMP '1969-12-31 23:59:59.999' a;
CREATE TABLE: 1 row
Query 20230920_082205_00009_62iqv, FINISHED, 1 node
Splits: 18 total, 18 done (100,00%)
0,42 [0 rows, 0B] [0 rows/s, 0B/s]
trino:default> select * from r;
a
-------------------------
1970-01-01 00:00:00.999
(1 row)
Query 20230920_082212_00010_62iqv, FINISHED, 1 node
Splits: 1 total, 1 done (100,00%)
0,31 [1 rows, 259B] [3 rows/s, 849B/s]
return Optional.of(setup.withNewValueLiteral("TIMESTAMP '1970-01-01 00:00:00.999999'")); | ||
} | ||
if (setup.sourceValueLiteral().equals("TIMESTAMP '1969-12-31 23:59:59.9999994'")) { | ||
return Optional.of(setup.withNewValueLiteral("TIMESTAMP '1970-01-01 00:00:00.999999'")); |
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 add a comment why this happens
Required engine changes were implemented elsewhere
@findepi : PTAL |
public Optional<io.trino.spi.type.Type> getSupportedType(ConnectorSession session, io.trino.spi.type.Type type) | ||
{ | ||
if (type instanceof TimestampWithTimeZoneType) { | ||
return Optional.of(TIMESTAMP_TZ_MICROS); |
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.
Support time types with precison <= 6 in Iceberg CT and CTAS
Change title
- replace
time types
withdate/time types
- replace
with precison <= 6
withwith precison != 6
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 changed the PR title to much commit title.
Similar to trinodb#13981, extend type coercion support to char type.
Similar to #13981, extend type coercion support to char type.
Description
The connector can specify the actual Trino types that will be used to store the table for CTAS statements. This permits the core engine to perform the necessary coercions and casts.
Enhancement
Change to Iceberg connector
Related issues, pull requests, and links
Documentation
( ) No documentation is needed.
( ) Sufficient documentation is included in this PR.
( ) Documentation PR is available with #prnumber.
( ) Documentation issue #issuenumber is filed, and can be handled later.
Release notes
( ) No release notes entries required.
( ) Release notes entries required with the following suggested text: