-
Notifications
You must be signed in to change notification settings - Fork 29.3k
[SPARK-29644][SQL] Corrected ShortType and ByteType mapping to SmallInt and TinyInt in JDBCUtils #26301
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
[SPARK-29644][SQL] Corrected ShortType and ByteType mapping to SmallInt and TinyInt in JDBCUtils #26301
Changes from 3 commits
e13326d
395fe99
66dfd4c
9cdad2b
0600894
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 |
|---|---|---|
|
|
@@ -59,7 +59,7 @@ class MsSqlServerIntegrationSuite extends DockerJDBCIntegrationSuite { | |
| """ | ||
| |INSERT INTO numbers VALUES ( | ||
| |0, | ||
| |255, 32767, 2147483647, 9223372036854775807, | ||
| |127, 32767, 2147483647, 9223372036854775807, | ||
| |123456789012345.123456789012345, 123456789012345.123456789012345, | ||
| |123456789012345.123456789012345, | ||
| |123, 12345.12, | ||
|
|
@@ -119,7 +119,7 @@ class MsSqlServerIntegrationSuite extends DockerJDBCIntegrationSuite { | |
| val types = row.toSeq.map(x => x.getClass.toString) | ||
| assert(types.length == 12) | ||
| assert(types(0).equals("class java.lang.Boolean")) | ||
| assert(types(1).equals("class java.lang.Integer")) | ||
| assert(types(1).equals("class java.lang.Byte")) | ||
| assert(types(2).equals("class java.lang.Short")) | ||
| assert(types(3).equals("class java.lang.Integer")) | ||
| assert(types(4).equals("class java.lang.Long")) | ||
|
|
@@ -131,7 +131,7 @@ class MsSqlServerIntegrationSuite extends DockerJDBCIntegrationSuite { | |
| assert(types(10).equals("class java.math.BigDecimal")) | ||
| assert(types(11).equals("class java.math.BigDecimal")) | ||
| assert(row.getBoolean(0) == false) | ||
| assert(row.getInt(1) == 255) | ||
| assert(row.getByte(1) == 127) | ||
| assert(row.getShort(2) == 32767) | ||
| assert(row.getInt(3) == 2147483647) | ||
| assert(row.getLong(4) == 9223372036854775807L) | ||
|
|
@@ -202,4 +202,46 @@ class MsSqlServerIntegrationSuite extends DockerJDBCIntegrationSuite { | |
| df2.write.jdbc(jdbcUrl, "datescopy", new Properties) | ||
| df3.write.jdbc(jdbcUrl, "stringscopy", new Properties) | ||
| } | ||
|
|
||
| test("Write tables with ShortType") { | ||
|
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 think this is a bug, so can you append the JIRA ID in the prefix?
Contributor
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. @maropu is JIRA addition required at all places i have added a new test cases?
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. Yea, plz follow |
||
| import testImplicits._ | ||
| val df = Seq(-32768.toShort, 0.toShort, 1.toShort, 38.toShort, 32768.toShort).toDF("a") | ||
| val tablename = "shorttable" | ||
| df.write | ||
| .format("jdbc") | ||
| .mode("overwrite") | ||
| .option("url", jdbcUrl) | ||
| .option("dbtable", tablename) | ||
| .save() | ||
| val df2 = spark.read | ||
| .format("jdbc") | ||
| .option("url", jdbcUrl) | ||
| .option("dbtable", tablename) | ||
| .load() | ||
| assert(df.count == df2.count) | ||
| val rows = df2.collect() | ||
| val colType = rows(0).toSeq.map(x => x.getClass.toString) | ||
| assert(colType(0) == "class java.lang.Short") | ||
| } | ||
|
shivsood marked this conversation as resolved.
|
||
|
|
||
| test("Write tables with ByteType") { | ||
| import testImplicits._ | ||
| val df = Seq(-127.toByte, 0.toByte, 1.toByte, 38.toByte, 128.toByte).toDF("a") | ||
| val tablename = "bytetable" | ||
| df.write | ||
| .format("jdbc") | ||
| .mode("overwrite") | ||
| .option("url", jdbcUrl) | ||
| .option("dbtable", tablename) | ||
| .save() | ||
| val df2 = spark.read | ||
| .format("jdbc") | ||
| .option("url", jdbcUrl) | ||
| .option("dbtable", tablename) | ||
| .load() | ||
| assert(df.count == df2.count) | ||
| val rows = df2.collect() | ||
| val colType = rows(0).toSeq.map(x => x.getClass.toString) | ||
| assert(colType(0) == "class java.lang.Byte") | ||
| } | ||
|
dongjoon-hyun marked this conversation as 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.
Ditto - #26549 (comment). Can anyone explain why it was possible, and how do we handle unsigned cases?
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.
Continuing from #26549 (comment) : TINYINT looks like it's a single byte alright, so using ByteType is reasonable. However it looks like it's treated as signed by some but not all DBMSes. Is it unsigned in SQL Server?
Just checking: these types like TINYINT and SMALLINT are not standard types, although widely supported, right? should these types be used by default for all JDBC sources?
Yeah I have some more doubts now that the TINYINT issue was pointed out. @shivsood
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.
Got it. @gatorsmile , @HyukjinKwon , @srowen . I overlooked that mismatch between TINYINT vs Byte in this PR.
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.
SMALLINTis widely supported because it's SQL-92. For TINYINT, I agree that we need to revert partially for that type.Uh oh!
There was an error while loading. Please reload this page.
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 all for pointing out these issues. I had overlooked handling of unsigned cases and the fact that each database may define on its own. I think the problem exists for both SMALLINT and TINYINT.
My understanding is that there are no unsigned type in Spark. c.f. https://spark.apache.org/docs/latest/sql-reference.html. Is that assertion right?
Do we have a test for an integer where integer value is 4294967295? Per MySQL documentation that's possible that an unsigned integer will have that value.
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.
The behavior would be as follows.
Overwrite scenario
Read scenario
If an existing table in DBMSS has type TinyInt, a read in Spark would results in a ShortType. Because ShortType range in Spark in -32786 to +32768, DBMSS signed value -127 to +127 and unsigned range of 0 to 255 will be handled.
If an existing table in DBMSS has type SmallInt, a read would result in Spark dataframe having a column type as Integer. Because Integer range in Spark in -2147483648 to +2147483648, DBMSS signed value --32768 to +32768 as well as unsigned range of 0 to 65535 will be handled.
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 we have to use a widening conversion both ways. That's the safest thing to do, I guess, and less of a change from the current behavior, where bytes go all the way to ints.
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.
Ur, I see. right.
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.
Anyway, thanks for the explanation, @shivsood
Uh oh!
There was an error while loading. Please reload this page.
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.
Raised PR #27172 with the proposed fix. ShortType is unchanged, only ByteType fix is modified to map to ShortType on the read path so enable support for 0 to 255 range.
@maropu @srowen @HyukjinKwon as FYI. Thanks