[CALCITE-7801] JSON_VALUE(..., RETURNING DOUBLE) throws ClassCastException when the JSON number is an integer - #5276
Open
wasabii wants to merge 1 commit into
Conversation
…ption when the JSON number is an integer
wasabii
force-pushed
the
calcite-7801-json-value-returning-conversion
branch
from
September 20, 2026 22:05
95af1ba to
9e44450
Compare
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



JSON_VALUEnever converted the value it pulled out of the document to the type in theRETURNINGclause. Its return type is always nullable, so code generation asksEnumUtils.convertforObjectto a boxed primitive, and that case falls through to a plain(Double) x. The cast only worked when the JSON value already happened to be that class:INTEGER,VARCHARandDECIMALhappened to work; everything else threw. And because the exception escaped the runtime function,ON ERRORnever saw it.JSON_QUERYhas the same problem withRETURNING ... ARRAY, where the elements are never converted at all, so I fixed both.The conversion has to happen inside the runtime function, since that is where the
ON EMPTY/ON ERRORlogic lives. It can't simply callCAST: that is generated code, chosen from the statically known source and target types, and here the source is only known at run time — the scalar may arrive as anInteger,Double,BigInteger,StringorBoolean. None of that is specific to JSON, so I put it inSqlFunctions, next to thetoInt(Object)family it delegates to:These dispatch on the target type and call the same methods cast's generated code would have:
Primitive.integerCastfor the exact numerics,Primitive.charToDecimalCastand friends forDECIMAL,truncate/truncateOrPadfor character types, theDateTimeUtilsparsers for datetimes. The type, its precision and scale, and the type system's rounding mode come down from the two implementors as constants.castArrayconverts a nested array at every level, soRETURNING DOUBLE ARRAY ARRAYworks where it used to throw, and it checks the value against the declared type rather than following whatever shape the value happens to have.Precision and scale were being dropped entirely, and now aren't:
Datetimes parse from the JSON string, including both
WITH LOCAL TIME ZONEtypes — no time zone needs supplying, because cast passes one only when converting aTIMEorTIMESTAMP, which is a local reading of a clock, and a JSON datetime is always a string. A JSON number is not a datetime, so converting one is an error; Oracle and MySQL agree, PostgreSQL doesn't.castraises for any target type it doesn't handle, so a conversion failure can no longer escapeON ERROR. Cases that used to throw an uncatchableClassCastExceptionnow go through it:RETURNING VARBINARY(n);RETURNING <type> ARRAYonJSON_VALUE, which cannot match anything as Calcite implements it, sinceJSON_VALUEreturns a scalar; and a value whose shape does not fit an arrayRETURNINGtype, such as a JSON object, or an array nested more or less deeply than the type says.RETURNING DECIMALthat yields NULL still doesn't work, here and on main alike, because linq4j's constant-hoisting lifts the conversion out of its null guard. That can be fixed separately.