Copilot commented on code in PR #12726:
URL: https://github.com/apache/gluten/pull/12726#discussion_r4063525216


##########
gluten-iceberg/src/test/scala/org/apache/gluten/execution/IcebergSuite.scala:
##########
@@ -836,4 +895,127 @@ abstract class IcebergSuite extends 
WholeStageTransformerSuite {
       }
     }
   }
+
+  test("case-sensitive mode: data column named Input_File_Name is not confused 
with metadata") {
+    // Regression test for the IcebergScanTransformer fix.
+    // A user data column whose name equals "input_file_name" when lowercased 
must NOT be
+    // misclassified as an Iceberg metadata column under caseSensitive=true.
+    // Before the fix, readSchemaFields and inputFileRelatedMetadataColumns 
both lowercased
+    // names unconditionally, so "Input_File_Name" would hash-collide with the 
metadata
+    // constant "input_file_name" and could be injected as a metadata column, 
shadowing the
+    // user data.
+    withSQLConf("spark.sql.caseSensitive" -> "true") {
+      withTable("iceberg_col_collision") {
+        spark.sql("""
+                    |CREATE TABLE iceberg_col_collision
+                    |  (id INT, `Input_File_Name` STRING)
+                    |USING iceberg
+                    |""".stripMargin)
+        spark.sql("""
+                    |INSERT INTO iceberg_col_collision VALUES
+                    |(1, 'user-data-value'), (2, 'another-value')
+                    |""".stripMargin)
+
+        // Data column must return the user value, not a file path.  This 
exercises the
+        // readSchemaFields and inputFileRelatedMetadataColumns paths fixed in 
this patch.
+        val dfData = runAndCompare("""
+                                     |SELECT id, `Input_File_Name`
+                                     |FROM iceberg_col_collision
+                                     |ORDER BY id
+                                     |""".stripMargin)
+        checkGlutenPlan[IcebergScanTransformer](dfData)
+        val dataRows = dfData.collect()
+        assert(dataRows.length == 2, s"Expected 2 rows, got 
${dataRows.length}")
+        assert(
+          dataRows(0).getString(1) == "user-data-value",
+          s"Row 0 data column value wrong: ${dataRows(0).getString(1)}")
+        assert(
+          dataRows(1).getString(1) == "another-value",
+          s"Row 1 data column value wrong: ${dataRows(1).getString(1)}")
+      }
+    }
+  }
+
+  test("case-sensitive mode: Input_File_Name data column and input_file_name 
metadata") {
+    // Regression test for PushDownInputFileExpression.PostOffload. Under 
caseSensitive=true,
+    // the user data column `Input_File_Name` and generated metadata attribute 
`input_file_name`
+    // are distinct Spark attributes and both must remain available for 
binding.
+    withSQLConf("spark.sql.caseSensitive" -> "true") {
+      withTable("iceberg_input_file_projection") {
+        spark.sql("""
+                    |CREATE TABLE iceberg_input_file_projection
+                    |  (id INT, `Input_File_Name` STRING)
+                    |USING iceberg
+                    |""".stripMargin)
+        spark.sql("""
+                    |INSERT INTO iceberg_input_file_projection VALUES
+                    |(1, 'user-data-value'), (2, 'another-value')
+                    |""".stripMargin)
+
+        val df = runAndCompare("""
+                                 |SELECT id, `Input_File_Name`, 
input_file_name() AS fname
+                                 |FROM iceberg_input_file_projection
+                                 |ORDER BY id
+                                 |""".stripMargin)
+        checkGlutenPlan[IcebergScanTransformer](df)
+        val rows = df.collect()
+        assert(rows.length == 2, s"Expected 2 rows, got ${rows.length}")
+        assert(rows(0).getString(1) == "user-data-value")
+        assert(rows(1).getString(1) == "another-value")
+        assert(
+          rows.forall(r => !r.isNullAt(2) && r.getString(2).nonEmpty),
+          s"Expected non-empty input_file_name values, got: ${rows.mkString(", 
")}")
+      }
+    }
+  }
+
+  test("case-sensitive mode: lowercase input_file_name as data column is 
rejected by Iceberg") {
+    // Iceberg reserves the field name "input_file_name" as a Spark metadata 
expression name.
+    // While Iceberg's MetadataColumns does not list it in META_COLUMNS by 
that exact string,
+    // Spark itself may reject or mishandle a user column with this exact name 
because
+    // input_file_name() resolves to an AttributeReference with that name in 
the plan.
+    // This test documents the platform behavior: if Iceberg rejects the 
schema, that is
+    // expected and is not a Gluten defect.  If it succeeds, the data value 
must be returned.
+    withSQLConf("spark.sql.caseSensitive" -> "true") {
+      withTable("iceberg_exact_collision") {
+        val created =
+          try {
+            spark.sql("""
+                        |CREATE TABLE iceberg_exact_collision
+                        |  (id INT, input_file_name STRING)
+                        |USING iceberg
+                        |""".stripMargin)
+            true
+          } catch {
+            case _: Exception => false
+          }
+        if (created) {
+          // If Iceberg allowed the schema, insert and verify Gluten handles 
it correctly.
+          val inserted =
+            try {
+              spark.sql("""
+                          |INSERT INTO iceberg_exact_collision VALUES (1, 
'exact-value')
+                          |""".stripMargin)
+              true
+            } catch {
+              case _: Exception => false
+            }
+          if (inserted) {
+            val df = runAndCompare("""
+                                     |SELECT id, input_file_name FROM 
iceberg_exact_collision
+                                     |""".stripMargin)
+            checkGlutenPlan[IcebergScanTransformer](df)
+            val rows = df.collect()
+            assert(rows.length == 1)
+            assert(
+              rows(0).getString(1) == "exact-value",
+              s"Expected 'exact-value', got: ${rows(0).getString(1)}")
+          }
+          // If insert failed (Spark resolves input_file_name as expression), 
that is
+          // expected platform behavior, not a Gluten defect.
+        }
+        // If CREATE TABLE failed, Iceberg correctly rejects reserved names.
+      }
+    }

Review Comment:
   This test can pass without executing any assertion: both table creation and 
insertion failures are caught and treated as expected, so a regression that 
makes either operation fail will remain undetected. Either remove this test if 
the exact lowercase name is intentionally unsupported, or assert the expected 
platform behavior explicitly and fail on unexpected exceptions; if the schema 
is supported, the test should not swallow creation or insertion errors.



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