-
Notifications
You must be signed in to change notification settings - Fork 57
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
SNOW-1507007 Support schema for new table format #814
Changes from all commits
eab2ab2
ff8f766
21afa2b
b55dce8
183c307
f1ce017
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 |
---|---|---|
@@ -1,5 +1,5 @@ | ||
/* | ||
* Copyright (c) 2021 Snowflake Computing Inc. All rights reserved. | ||
* Copyright (c) 2021-2024 Snowflake Computing Inc. All rights reserved. | ||
*/ | ||
|
||
package net.snowflake.ingest.streaming.internal; | ||
|
@@ -19,6 +19,7 @@ | |
import java.io.IOException; | ||
import java.math.BigDecimal; | ||
import java.math.BigInteger; | ||
import java.math.RoundingMode; | ||
import java.nio.charset.StandardCharsets; | ||
import java.time.Instant; | ||
import java.time.LocalDate; | ||
|
@@ -718,7 +719,13 @@ static BigDecimal validateAndParseBigDecimal( | |
|| input instanceof Long) { | ||
return BigDecimal.valueOf(((Number) input).longValue()); | ||
} else if (input instanceof Float || input instanceof Double) { | ||
return BigDecimal.valueOf(((Number) input).doubleValue()); | ||
try { | ||
return BigDecimal.valueOf(((Number) input).doubleValue()); | ||
} catch (NumberFormatException e) { | ||
/* NaN and infinity are not allowed */ | ||
throw valueFormatNotAllowedException( | ||
columnName, "NUMBER", "Not a valid number", insertRowIndex); | ||
} | ||
} else if (input instanceof String) { | ||
try { | ||
final String stringInput = ((String) input).trim(); | ||
|
@@ -957,6 +964,66 @@ static double validateAndParseReal(String columnName, Object input, long insertR | |
columnName, input.getClass(), "REAL", new String[] {"Number", "String"}, insertRowIndex); | ||
} | ||
|
||
/** | ||
* Validates and parses input Iceberg INT column. Allowed Java types: | ||
* | ||
* <ul> | ||
* <li>Number | ||
* <li>String | ||
* </ul> | ||
* | ||
* @param columnName Column name, used in validation error messages | ||
* @param input Object to validate and parse | ||
* @param insertRowIndex Row index for error reporting | ||
* @return Parsed integer | ||
*/ | ||
static int validateAndParseIcebergInt(String columnName, Object input, long insertRowIndex) { | ||
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. Should we add unit tests for these functions, which focus on corner cases? Min and max values, Double/Float NaN+positive/negative infinity, big integers and big decimals outside of the allowed range, etc.? 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. Added tests here. |
||
BigDecimal roundedValue = | ||
validateAndParseBigDecimal(columnName, input, insertRowIndex) | ||
.setScale(0, RoundingMode.HALF_UP); | ||
try { | ||
return roundedValue.intValueExact(); | ||
} catch (ArithmeticException e) { | ||
/* overflow */ | ||
throw new SFException( | ||
ErrorCode.INVALID_VALUE_ROW, | ||
String.format( | ||
"Number out of representable inclusive range of integers between %d and %d," | ||
+ " rowIndex:%d", | ||
Integer.MIN_VALUE, Integer.MAX_VALUE, insertRowIndex)); | ||
} | ||
} | ||
|
||
/** | ||
* Validates and parses input Iceberg LONG column. Allowed Java types: | ||
* | ||
* <ul> | ||
* <li>Number | ||
* <li>String | ||
* </ul> | ||
* | ||
* @param columnName Column name, used in validation error messages | ||
* @param input Object to validate and parse | ||
* @param insertRowIndex Row index for error reporting | ||
* @return Parsed long | ||
*/ | ||
static long validateAndParseIcebergLong(String columnName, Object input, long insertRowIndex) { | ||
BigDecimal roundedValue = | ||
validateAndParseBigDecimal(columnName, input, insertRowIndex) | ||
.setScale(0, RoundingMode.HALF_UP); | ||
try { | ||
return roundedValue.longValueExact(); | ||
} catch (ArithmeticException e) { | ||
/* overflow */ | ||
throw new SFException( | ||
ErrorCode.INVALID_VALUE_ROW, | ||
String.format( | ||
"Number out of representable inclusive range of integers between %d and %d," | ||
+ " rowIndex:%d", | ||
Long.MIN_VALUE, Long.MAX_VALUE, insertRowIndex)); | ||
} | ||
} | ||
|
||
/** | ||
* Validate and parse input to integer output, 1=true, 0=false. String values converted to boolean | ||
* according to https://docs.snowflake.com/en/sql-reference/functions/to_boolean.html#usage-notes | ||
|
@@ -1003,6 +1070,16 @@ static void checkValueInRange( | |
} | ||
} | ||
|
||
static void checkFixedLengthByteArray(byte[] bytes, int length, final long insertRowIndex) { | ||
if (bytes.length != length) { | ||
throw new SFException( | ||
ErrorCode.INVALID_FORMAT_ROW, | ||
String.format( | ||
"Binary length mismatch: expected=%d, actual=%d, rowIndex:%d", | ||
length, bytes.length, insertRowIndex)); | ||
} | ||
} | ||
|
||
static Set<String> allowedBooleanStringsLowerCased = | ||
Sets.newHashSet("1", "0", "yes", "no", "y", "n", "t", "f", "true", "false", "on", "off"); | ||
|
||
|
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 find this library being used anywhere, why is this change needed?
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 a transitive dependency from
org.apache.iceberg:iceberg-core
.