voonhous commented on code in PR #19583:
URL: https://github.com/apache/hudi/pull/19583#discussion_r3772837826


##########
hudi-spark-datasource/hudi-spark-common/src/main/scala/org/apache/hudi/MergeOnReadSnapshotRelation.scala:
##########
@@ -132,7 +133,15 @@ abstract class BaseMergeOnReadSnapshotRelation(sqlContext: 
SQLContext,
           getPartitionColumnsAsInternalRow(file.getPathInfo), 
file.getPathInfo.getPath, 0, file.getFileSize)
       }
 
-      HoodieMergeOnReadFileSplit(partitionedBaseFile, logFiles)
+      // These values are empty unless the partition columns are omitted from 
the data files, which is

Review Comment:
   Right, the extract-from-path read option applies to tables that do persist 
their partition columns, so "empty unless the columns are omitted" was wrong. 
Reworded to name `shouldExtractPartitionValuesFromPartitionPath`'s three 
triggers instead: dropped partition columns, the extract-from-path read option, 
or a bootstrap data-queries-only read. Fixed in b78ba3df.
   



##########
hudi-spark-datasource/hudi-spark-common/src/main/scala/org/apache/hudi/cdc/InternalRowToJsonStringConverter.scala:
##########
@@ -90,10 +91,40 @@ class InternalRowToJsonStringConverter(schema: StructType) {
               structMap.toMap
             case _ => value // fallback
           }
+        case dt if dt.typeName == 
InternalRowToJsonStringConverter.VARIANT_TYPE_NAME =>
+          // VariantVal.toString renders the variant as JSON; embed it as a 
real JSON node so
+          // the image carries the variant's structure. Falling through to the 
default would
+          // serialize the VariantVal bean, i.e. its raw value/metadata bytes 
as base64.
+          // Matched on the type name rather than SparkAdapter.isVariantType: 
this guard is
+          // evaluated for every non-string/array/map/struct field, and 
resolving the adapter
+          // needs a version module that is not on hudi-spark-common's own 
test classpath.
+          val variantJson = value.toString
+          try {
+            mapper.readTree(variantJson)
+          } catch {
+            // A variant can hold a field name, string or nesting depth past 
Jackson's default
+            // StreamReadConstraints (50k chars, 20M chars, 1000 levels) while 
staying well inside
+            // the variant size limit, and all three arrive here as 
StreamConstraintsException. A
+            // CDC image is diagnostic data rather than the table's data, so 
keep the rendering as
+            // a plain string instead of failing the query over it.
+            // NOTE: value.toString is deliberately outside this block. It 
throws MALFORMED_VARIANT
+            // on corrupt bytes, which is a data-integrity problem an operator 
has to see, not a
+            // rendering quirk to paper over -- and there would be no 
rendering left to fall back to.
+            case _: JsonProcessingException => variantJson

Review Comment:
   Confirmed and taken, not deferred -- it is a couple of lines and the case is 
real. `RawValue` it is, in b78ba3df.
   
   While confirming it I measured the window, and it is a little different from 
999-1000: jackson-core's `WriterBasedJsonGenerator.writeStartObject(Object)` 
validates the *parent* context's depth rather than the child's, so the object 
path tolerates one extra level. That works out to a window of one level per 
enclosing object for an object-rendered variant, and one more for an 
array-rendered one. A variant at the top of the image rendering as an array 
fails at exactly depth 1000, which is what the new test pins -- verified red 
before the change with `StreamWriteConstraints.getMaxNestingDepth()` exceeded, 
green after. Same behaviour on jackson 2.18.2, 2.20.0 and 2.21.2.
   
   Two things the verbatim embed needed that the parsed-node path did not, 
since `readTree` is a weaker gate than it looks: `FAIL_ON_TRAILING_TOKENS` on 
the mapper, because it otherwise parses a valid prefix and leaves the rest 
unconsumed, and an explicit `MissingNode` check, because blank input comes back 
as `MissingNode` rather than throwing and `RawValue` would emit nothing at all. 
Both would have spliced corrupt text into the image. Neither is producible by 
`Variant.toJson`, which always emits exactly one complete value, so they are 
defence in depth.
   
   For the common case it is a byte-identical swap -- I checked the parsed-node 
and raw paths against the real renderer across decimals, doubles, escaping, key 
ordering and every scalar shape -- and it drops a parse-then-rebuild round 
trip. One consequence worth naming: the image can now be written at a depth 
above the default *read* limit, so a consumer re-parsing it with stock 
constraints could reject it. That band exists today too (the node path can emit 
1001); this widens it slightly, and for diagnostic data a deep-but-valid image 
still beats failing the query.
   



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to