Skip to content

test: move explode/posexplode coverage from CometGenerateExecSuite to Comet SQL tests #6630

Description

@andygrove

Part of #6615.

What / Why

This issue moves the generator coverage in exec/CometGenerateExecSuite to Comet SQL tests: explode, explode_outer, posexplode, posexplode_outer, over arrays and struct arrays, across batch boundaries, and under LIMIT ... OFFSET. Fixtures go under sql-tests/expressions/array/, next to explode.sql and posexplode.sql. Static analysis on main at 3bc2faa found the following:

Suite Covered Convert Blocked Split Keep Total
CometGenerateExecSuite 1 40 0 0 2 43

Nearly everything converts. The plan-shape test and the ScalaUDF test stay.

Work

Line numbers refer to CometGenerateExecSuite.

  • explode_local_table_scan.sql (new), covering the 24 Seq.toDF tests from L114 to L436 except L214, L227 and L393
    • Use -- Config: spark.comet.exec.localTableScan.enabled=true with inline VALUES.
    • The behavior is already in explode.sql / posexplode.sql over Parquet. What this file adds is the source: Parquet always reads arrays back with containsNull=true, while Seq.toDF gives non-null elements, which is the bug: array/map kernels crash on non-null child field via CometLocalTableScanExec #4789 hazard.
    • ConvertToLocalRelation folds only Project, Filter and Limit, so a Generate over VALUES still reaches the native explode.
    • Write NULL arrays as bare NULL, because CAST(NULL AS ARRAY<INT>) makes the elements nullable again.
    • Seven of these behaviors are in no fixture today: L180, L191, L202, L240, L297, L381 and L436.
  • explode_disabled.sql (new, L214): set spark.comet.exec.explode.enabled=false and assert the fallback reason.
  • explode.sql (L227): add the explode(m) fallback.
    • Also move the rand() query out into its own file. The whole file is gated MinSparkVersion: 3.5 for that one query, so today it is skipped entirely on Spark 3.4.
  • posexplode.sql (L100): add posexplode(split(s, 'x')).
  • explode_small_batches.sql (new): L447, L465, L488, L613, L629, L646, using -- ConfigMatrix: spark.comet.batchSize=4,8 and single-file tables.
  • explode_limit_offset.sql (new): L523, L539, L561, L580, using single-file tables with LIMIT 4 OFFSET 1 (ListPositionsExpr panics on sliced list input, breaking native posexplode over LIMIT with OFFSET #5224).
  • explode_boolean_struct.sql (new): L691 (four instances) and L710, using a 3000-row table generated with hash() (Native explode returns wrong booleans for arrays of structs after the first batch of output #6464).
  • explode_boolean_struct_batch_100.sql (new): L700, with spark.comet.batchSize=100.

Use INSERT INTO t SELECT /*+ COALESCE(1) */ ... or range(0, n, 1, 1) for every batch-boundary fixture. INSERT ... VALUES writes one file per row and would never put two rows in one batch.

Stays in Scala

Notes on the Scala tests

  • The non-outer NULL/empty tests never reach the native operator with those rows (L125, L136, L263, L323, L334, L406). Spark's InferFiltersFromGenerate adds a non-NULL, non-empty filter, and ConvertToLocalRelation applies it to the Seq data at plan time. The fixtures keep the queries, but the coverage that matters is in the _outer variants.
  • L447 never has two input batches in one partition.
  • Bare -0.0. explode.sql:142,156 and posexplode.sql:131 write cast(-0.0 as float/double), which is +0.0. Use float('-0.0') / double('-0.0').

Done when

  • Every test in the table below is accounted for. Either a fixture covers it (the same inputs, configs and assertion strength, or stronger), the fixture that already covers it is cited, or it stays in Scala for the reason given above.
  • Each converted Scala test is deleted in the PR that adds its coverage. A suite left empty is deleted and removed from the suite lists in .github/workflows/pr_build_linux.yml and pr_build_macos.yml.
  • The new and changed fixtures pass on every Spark profile. Apply run-all-spark-profiles, because pull requests run only the default profile.
Every Scala test in scope, with its verdict and target fixture
Suite Line Test Verdict Target
CometGenerateExecSuite 38 generator identity preserves exchange reuse: $generator($input), AQE=$adaptive [8 instances: explode/posexplode x s.arr/slice(s.arr, 1, 10) x AQE false/true] keep
CometGenerateExecSuite 100 posexplode with a computed array from Parquet convert array/posexplode.sql
CometGenerateExecSuite 114 explode with simple array convert array/explode_local_table_scan.sql (new)
CometGenerateExecSuite 125 explode with empty array convert array/explode_local_table_scan.sql (new)
CometGenerateExecSuite 136 explode with null array convert array/explode_local_table_scan.sql (new)
CometGenerateExecSuite 147 explode_outer with simple array convert array/explode_local_table_scan.sql (new)
CometGenerateExecSuite 158 explode_outer with empty array convert array/explode_local_table_scan.sql (new)
CometGenerateExecSuite 169 explode_outer with null array convert array/explode_local_table_scan.sql (new)
CometGenerateExecSuite 180 explode with multiple columns convert array/explode_local_table_scan.sql (new)
CometGenerateExecSuite 191 explode with array of strings convert array/explode_local_table_scan.sql (new)
CometGenerateExecSuite 202 explode with filter convert array/explode_local_table_scan.sql (new)
CometGenerateExecSuite 214 explode fallback when disabled convert array/explode_disabled.sql (new)
CometGenerateExecSuite 227 explode with map input falls back convert array/explode.sql
CometGenerateExecSuite 240 explode with nullable projected column convert array/explode_local_table_scan.sql (new)
CometGenerateExecSuite 251 explode_outer with nullable projected column convert array/explode_local_table_scan.sql (new)
CometGenerateExecSuite 263 explode with mixed null, empty, and non-empty arrays convert array/explode_local_table_scan.sql (new)
CometGenerateExecSuite 280 explode_outer with mixed null, empty, and non-empty arrays convert array/explode_local_table_scan.sql (new)
CometGenerateExecSuite 297 explode with multiple nullable columns convert array/explode_local_table_scan.sql (new)
CometGenerateExecSuite 312 posexplode with simple array convert array/explode_local_table_scan.sql (new)
CometGenerateExecSuite 323 posexplode with empty array convert array/explode_local_table_scan.sql (new)
CometGenerateExecSuite 334 posexplode with null array convert array/explode_local_table_scan.sql (new)
CometGenerateExecSuite 345 posexplode_outer with simple array convert array/explode_local_table_scan.sql (new)
CometGenerateExecSuite 356 posexplode with array of strings convert array/explode_local_table_scan.sql (new)
CometGenerateExecSuite 367 posexplode with nullable elements convert array/explode_local_table_scan.sql (new)
CometGenerateExecSuite 381 posexplode with multiple projected columns convert array/explode_local_table_scan.sql (new)
CometGenerateExecSuite 393 posexplode with map input falls back covered array/posexplode.sql
CometGenerateExecSuite 406 posexplode with array of structs convert array/explode_local_table_scan.sql (new)
CometGenerateExecSuite 421 posexplode in lateral view convert array/explode_local_table_scan.sql (new)
CometGenerateExecSuite 436 posexplode of literal array convert array/explode_local_table_scan.sql (new)
CometGenerateExecSuite 447 posexplode across batch boundary with small batch size convert array/explode_small_batches.sql (new)
CometGenerateExecSuite 465 explode_outer across batch boundary with mixed empty/null rows convert array/explode_small_batches.sql (new)
CometGenerateExecSuite 488 posexplode_outer across batch boundary with mixed empty/null rows convert array/explode_small_batches.sql (new)
CometGenerateExecSuite 523 posexplode over limit with offset convert array/explode_limit_offset.sql (new)
CometGenerateExecSuite 539 posexplode_outer over limit with offset convert array/explode_limit_offset.sql (new)
CometGenerateExecSuite 561 explode over limit with offset convert array/explode_limit_offset.sql (new)
CometGenerateExecSuite 580 explode_outer over limit with offset convert array/explode_limit_offset.sql (new)
CometGenerateExecSuite 613 posexplode single row exceeds batch size convert array/explode_small_batches.sql (new)
CometGenerateExecSuite 629 posexplode_outer single row exceeds batch size convert array/explode_small_batches.sql (new)
CometGenerateExecSuite 646 explode single row exceeds batch size convert array/explode_small_batches.sql (new)
CometGenerateExecSuite 691 $generator of structs keeps boolean fields past the first output batch [instances: explode, explode_outer, posexplode, posexplode_outer] convert array/explode_boolean_struct.sql (new)
CometGenerateExecSuite 700 explode of structs keeps boolean fields when one row exceeds the batch size convert array/explode_boolean_struct_batch_100.sql (new)
CometGenerateExecSuite 710 named_struct over an exploded boolean keeps its values convert array/explode_boolean_struct.sql (new)
CometGenerateExecSuite 717 boolean ScalaUDF over an exploded boolean keeps its values keep
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions