andygrove commented on code in PR #5729:
URL: https://github.com/apache/datafusion-comet/pull/5729#discussion_r3944411574


##########
spark/src/test/scala/org/apache/comet/CometIcebergWriteActionSuite.scala:
##########
@@ -1033,6 +1033,124 @@ class CometIcebergWriteActionSuite
     }
   }
 
+  // iceberg-java renders a `timestamptz` partition value with
+  // `DateTimeUtil.microsToIsoTimestamptz` and a `binary` one with base64; 
iceberg-rust's
+  // `partition_to_path` renders the first as a `chrono` `DateTime<Utc>` 
(space separator, " UTC"
+  // suffix) -- and outright panics on a pre-1970 value with a sub-second 
part, since
+  // `microseconds_to_datetimetz` casts a negative remainder to `u32`
+  // (apache/datafusion-comet#5694) -- and the second as uppercase hex. Comet 
renders the path
+  // itself; this pins the result against the layout iceberg-java's own writer 
produces.
+  test("native acceleration: timestamptz and binary partition paths match 
iceberg-java") {
+    assumeNativeAcceleration()
+    withIcebergCatalog { warehouseDir =>
+      // A UTC session zone makes the stored micros of each literal exact, so 
the expected
+      // directory names below are not a function of the machine's zone.
+      withSQLConf("spark.sql.session.timeZone" -> "UTC") {
+        Seq("ts_path_native", "ts_path_jvm").foreach { table =>
+          spark.sql(s"""
+            CREATE TABLE $catalog.$ns.$table (id INT, ts TIMESTAMP, bin BINARY)
+            USING iceberg PARTITIONED BY (ts, bin)
+          """)
+        }
+        // Pre-epoch with a sub-second part (the panic case), pre-epoch on a 
whole second, the
+        // epoch itself, and a post-epoch microsecond value.
+        val values =
+          "(1, TIMESTAMP '1969-12-31 23:59:58.5', X'0001FF'), " +
+            "(2, TIMESTAMP '1969-12-31 23:59:58', X'00'), " +
+            "(3, TIMESTAMP '1970-01-01 00:00:00', X''), " +
+            "(4, TIMESTAMP '2024-04-01 19:25:00.123456', X'FF')"
+
+        assertNativeWriteEngages("ts_path_native", Seq(1, 2, 3, 4)) {
+          spark.sql(s"INSERT INTO $catalog.$ns.ts_path_native VALUES $values")
+        }
+        spark.sql(s"INSERT INTO $catalog.$ns.ts_path_jvm VALUES $values")
+
+        val nativeDirs = partitionDirs(warehouseDir, "ts_path_native")
+        assert(nativeDirs == partitionDirs(warehouseDir, "ts_path_jvm"), 
s"native: $nativeDirs")
+        assert(
+          
nativeDirs.contains("ts=1969-12-31T23%3A59%3A58.5%2B00%3A00/bin=AAH%2F"),
+          s"native: $nativeDirs")
+        assert(
+          nativeDirs.contains("ts=1970-01-01T00%3A00%3A00%2B00%3A00/bin="),
+          s"native: $nativeDirs")
+        assert(
+          
nativeDirs.contains("ts=2024-04-01T19%3A25%3A00.123456%2B00%3A00/bin=%2Fw%3D%3D"),
+          s"native: $nativeDirs")
+
+        // Values round-trip through both readers regardless of how the path 
was spelled.
+        Seq("true", "false").foreach { cometEnabled =>
+          withSQLConf(CometConf.COMET_ENABLED.key -> cometEnabled) {
+            val rows =
+              spark.sql(s"SELECT id, ts FROM $catalog.$ns.ts_path_native ORDER 
BY id").collect()
+            assert(
+              rows.toSeq ==
+                spark
+                  .sql(s"SELECT id, ts FROM $catalog.$ns.ts_path_jvm ORDER BY 
id")
+                  .collect()
+                  .toSeq,
+              s"comet=$cometEnabled: $rows")
+          }
+        }
+      }
+    }
+  }
+
+  // iceberg-java's `UpdatePartitionSpec` keeps a dropped partition field in a 
format-version-1
+  // spec as a `void` transform so its field id survives, and 
`PartitionSpec#isUnpartitioned` is
+  // "every field is void", not "no fields". The next write therefore runs 
through the
+  // unpartitioned writer -- which stamps an empty partition struct -- against 
a spec whose fields
+  // are non-empty, and iceberg-rust's `ManifestWriter` used to `zip_eq` the 
two and panic across
+  // the JNI boundary (apache/datafusion-comet#5691). Dropping the source 
column afterwards then
+  // broke the manifest's `partition_type` resolution as well 
(apache/datafusion-comet#5693).
+  test("native acceleration: writes after a V1 partition field is dropped 
match iceberg-java") {
+    assumeNativeAcceleration()
+    withIcebergCatalog { _ =>
+      Seq("evolved_native", "evolved_jvm").foreach { table =>
+        spark.sql(s"""
+          CREATE TABLE $catalog.$ns.$table (id INT, region STRING)
+          USING iceberg TBLPROPERTIES ('format-version'='1')
+        """)
+      }
+
+      def evolve(table: String, write: (String, Seq[Int]) => Unit): Unit = {
+        write("(1, 'us')", Seq(1))
+        spark.sql(s"ALTER TABLE $catalog.$ns.$table ADD PARTITION FIELD region 
AS region_part")
+        write("(2, 'eu')", Seq(1, 2))
+        spark.sql(s"ALTER TABLE $catalog.$ns.$table DROP PARTITION FIELD 
region_part")
+        // The spec is now void-only: the #5691 shape.
+        write("(3, 'ap')", Seq(1, 2, 3))
+        spark.sql(s"ALTER TABLE $catalog.$ns.$table DROP COLUMN region")
+        // The void field's source column is gone: the #5693 shape.
+        write("(4)", Seq(1, 2, 3, 4))

Review Comment:
   Agreed, and thanks for separating 1.10 out. I'd assumed the `UnknownType` 
fallback added to `partitionType` covered it, but `javaClasses` only got the 
same fallback in 1.11, so 1.10 gets further and still fails. Since that failure 
is in the driver-side commit the native path shares with the stock one, gating 
is the only honest option: normalising the transport manifest can't rescue it.
   
   Split the source-column drop into its own test behind 
`assume(icebergVersionAtLeast(1, 11))` and left the void-only stages 
unconditional, so #5691 itself stays covered on 3.4/3.5/4.0. Verified 
`CometIcebergWriteActionSuite` locally on spark-3.4 (Iceberg 1.5.2), spark-3.5 
(1.8.1), spark-4.0 (1.10.0) and spark-4.1 (1.11.0), plus the other Iceberg 
suites in the `scans` group on 3.4 and 4.0.



-- 
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]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to