-
Notifications
You must be signed in to change notification settings - Fork 2.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
[CALCITE-6265] Type coercion is failing for numeric values in prepared statements #3687
Changes from all commits
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 |
---|---|---|
|
@@ -622,9 +622,49 @@ public static UnaryExpression convert_(Expression expression, Type type, | |
* operation that throws an exception if the target type is | ||
* overflowed. | ||
*/ | ||
public static UnaryExpression convertChecked(Expression expression, | ||
public static Expression convertChecked(Expression expression, | ||
Type type) { | ||
throw Extensions.todo(); | ||
if (type == Byte.class | ||
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. It's funny, I implemented this myself in a separate PR: #3589 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. Nice. Your approach seems to cover more scenarios. I will keep |
||
|| type == Short.class | ||
|| type == Integer.class | ||
|| type == Long.class) { | ||
Class<?> typeClass = (Class<?>) type; | ||
|
||
Object minValue; | ||
Object maxValue; | ||
|
||
try { | ||
minValue = typeClass.getField("MIN_VALUE").get(null); | ||
maxValue = typeClass.getField("MAX_VALUE").get(null); | ||
} catch (IllegalAccessException | NoSuchFieldException e) { | ||
throw new RuntimeException(e); | ||
} | ||
|
||
ThrowStatement throwStmt = | ||
Expressions.throw_( | ||
Expressions.new_( | ||
IllegalArgumentException.class, | ||
Expressions.constant("value is outside the range of " + typeClass.getName()))); | ||
|
||
// Covers all lower precision types | ||
Expression longValue = Expressions.call(expression, "longValue"); | ||
|
||
Expression minCheck = Expressions.lessThan(longValue, Expressions.constant(minValue)); | ||
Expression maxCheck = Expressions.greaterThan(longValue, Expressions.constant(maxValue)); | ||
|
||
Primitive primitive = requireNonNull(Primitive.ofBox(type)); | ||
String primitiveName = requireNonNull(primitive.primitiveName); | ||
Expression convertExpr = Expressions.call(expression, primitiveName + "Value"); | ||
|
||
return Expressions.convert_( | ||
Expressions.makeTernary( | ||
ExpressionType.Conditional, | ||
Expressions.or(minCheck, maxCheck), | ||
Expressions.fromStatement(throwStmt), | ||
convertExpr), type); | ||
} | ||
|
||
throw new IllegalArgumentException("Type " + type.getTypeName() + " is not supported yet"); | ||
} | ||
|
||
/** | ||
|
@@ -2822,6 +2862,18 @@ public static SymbolDocumentInfo symbolDocument(String filename, | |
throw Extensions.todo(); | ||
} | ||
|
||
/** | ||
* Create an expression from a statement. | ||
*/ | ||
public static Expression fromStatement(Statement statement) { | ||
FunctionExpression<Function<?>> lambda = | ||
Expressions.lambda( | ||
Blocks.toFunctionBlock(statement), | ||
Collections.emptyList()); | ||
|
||
return Expressions.call(lambda, "apply"); | ||
} | ||
|
||
/** | ||
* Creates a statement that represents the throwing of an exception. | ||
*/ | ||
|
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 you also add a test where the value overflows the type, e.g., TINYINT with a value of 300?
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.
TINYINT(300)
is not valid SQL, but while working on a test for it, I noticed thatNUMERIC(<digits>)
conversions are currently not supported either. An exception is thrown becausePrimitive.ofBox(returnType))
returnsnull
forBigDecimal
. This is fixed in the last commit.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.
CAST(300 as TINYINT)
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 for clarifying.
CAST(300 as TINYINT)
is correctly fine, butCAST(? as TINYINT)
does not trigger an error when the value is out of bounds. I added a test and fixed it.