Skip to content

test(spark): enhance blob/vector SQL DDL coverage of the extended parser - #19408

Draft
yihua wants to merge 2 commits into
apache:masterfrom
yihua:test-blob-vector-ddl-clause-coverage
Draft

test(spark): enhance blob/vector SQL DDL coverage of the extended parser#19408
yihua wants to merge 2 commits into
apache:masterfrom
yihua:test-blob-vector-ddl-clause-coverage

Conversation

@yihua

@yihua yihua commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Describe the issue this Pull Request addresses

The six per-version extended SQL AST builders (HoodieSpark{3.3,3.4,3.5,4.0,4.1,4.2}ExtendedSqlAstBuilder.scala) were only about a quarter line-covered. The extended parser is reached only when a statement contains a Hudi-specific blob or vector token (isHoodieCommand), and such a statement is then parsed entirely by this builder. After the recent prune of the forked parser to Hudi-only statements (#19132), the remaining CREATE TABLE clause visitors (partition transforms, literal arguments, bucket spec, file and row format, interval and other data types, table properties and options) are all reachable and required, but were largely unexercised because the existing tests used a bare blob/vector column with no other clauses.

Summary and Changelog

Enhances the existing blob/vector SQL DDL and index syntax test suites to exercise the extended AST builder's CREATE TABLE clause visitors. This is a test-only, parser-coverage change. Because the builder is not dead code (every remaining path is reachable through a blob/vector statement), no further prune is warranted.

New cases route through the extended builder by keeping a BLOB or VECTOR column in every statement, and assert the parsed logical plan (CreateTable.tableSchema and CreateTable.partitioning, both stable across Spark 3.3 through 4.2) via spark.sessionState.sqlParser.parsePlan, or assert the exact parse error for the negative cases. Parse-level assertions exercise the builder without needing table creation, so they also cover clauses Hudi does not support at execution time (transform partitioning, STORED AS / ROW FORMAT, interval columns).

Suites enhanced (no new suite added):

  • TestBlobDataType: primitive, complex and interval data-type arms; partition transforms (identity, years/months/days/hours, generic apply, and bucket with int/long/short counts); typed transform-argument literals (string, boolean, null, integer, timestamp constructor, multi-unit interval); their error twins (invalid bucket count, non-column reference, too many arguments, reversed interval endpoints, unknown type); and file-format / row-format clauses (STORED AS generic and INPUTFORMAT/OUTPUTFORMAT, ROW FORMAT SERDE / DELIMITED, plus the incompatible-combination, STORED BY, and USING-with-serde errors).
  • TestCreateTable (vector): partition transforms; typed transform-argument literals (adds long, exponent/double, and unit-to-unit interval); CLUSTERED BY bucket spec (plain, SORTED BY ASC, and the SORTED BY DESC rejection); and LOCATION / COMMENT / OPTIONS / TBLPROPERTIES with string, integer and boolean values, plus the path-collision and reserved-property (provider/location/owner) errors.
  • TestIndexSyntax: folds the uncovered index branches into the existing fixture-backed test: CREATE INDEX without USING (default empty index type), DROP INDEX without IF EXISTS, and SHOW INDEXES with the IN keyword.

Findings from writing these tests:

  • A bare TIMESTAMP-typed column, and a TIMESTAMP '...' typed literal, fail to parse in the Spark 4.x extended parser for a blob/vector CREATE TABLE ("no viable alternative at input 'TIMESTAMP'"), though the Spark 3.5 extended parser accepts both. The tests use DATE instead. This looks like a Spark 4 extended-parser gap worth a separate look.
  • A bare boolean or null in a transform-argument position is parsed as a column reference: the grammar's qualifiedName alternative takes precedence over a constant, and under the default non-ANSI config true/false/null are valid identifiers. So visitBooleanLiteral and visitNullLiteral are not reachable from a CREATE TABLE statement and are left unasserted.
  • The grammar mandates at least one transform argument, so getSingleFieldReference's empty-arguments branch ("Not enough arguments for transform") is unreachable from SQL and is not asserted.

Impact

None. Test-only change; no production code or public API is modified.

Risk Level

none

Documentation Update

none

Contributor's checklist

  • Read through contributor's guide
  • Enough context is provided in the sections above
  • Adequate tests were added if applicable

Add parser-coverage cases to the existing blob/vector SQL DDL and index syntax suites so the per-version extended AST builder's CREATE TABLE clause visitors are exercised. The extended parser is reached only when a statement contains a blob or vector column, so every new case keeps such a column and asserts the parsed CreateTable plan (schema and partitioning) or the exact parse error. Covers the data-type arms, partition transforms and their literal arguments, bucket spec, file and row format clauses, table properties and options, and the previously untested index DDL branches. Test only; no production code changes.
@github-actions github-actions Bot added the size:L PR with lines of changes in (300, 1000] label Jul 29, 2026
@codecov-commenter

codecov-commenter commented Jul 29, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 76.07%. Comparing base (a284d6e) to head (53eea34).
⚠️ Report is 5 commits behind head on master.

Additional details and impacted files
@@             Coverage Diff              @@
##             master   #19408      +/-   ##
============================================
+ Coverage     74.83%   76.07%   +1.24%     
- Complexity    32332    33319     +987     
============================================
  Files          2574     2574              
  Lines        142978   142991      +13     
  Branches      17527    17555      +28     
============================================
+ Hits         106992   108781    +1789     
+ Misses        27921    25891    -2030     
- Partials       8065     8319     +254     
Components Coverage Δ
hudi-common 82.25% <ø> (+<0.01%) ⬆️
hudi-client 81.81% <ø> (+0.01%) ⬆️
hudi-flink 81.93% <ø> (+3.28%) ⬆️
hudi-spark-datasource 72.79% <ø> (+4.45%) ⬆️
hudi-utilities 71.22% <ø> (+0.03%) ⬆️
hudi-cli 15.32% <ø> (ø)
hudi-hadoop 63.49% <ø> (ø)
hudi-sync 70.67% <ø> (ø)
hudi-io 79.57% <ø> (ø)
hudi-timeline-service 83.74% <ø> (-0.49%) ⬇️
hudi-cloud 64.00% <ø> (ø)
hudi-kafka-connect 53.20% <ø> (ø)
Flag Coverage Δ
common-and-other-modules 48.54% <ø> (+0.77%) ⬆️
flink-integration-tests 48.33% <ø> (+0.69%) ⬆️
hadoop-mr-java-client 43.39% <ø> (-0.01%) ⬇️
integration-tests 13.63% <ø> (+<0.01%) ⬆️
spark-client-hadoop-common 48.71% <ø> (+<0.01%) ⬆️
spark-java-tests 51.39% <ø> (+<0.01%) ⬆️
spark-scala-tests 47.07% <ø> (+0.98%) ⬆️
utilities 36.66% <ø> (+0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.
see 47 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

…x extended parser

The Spark 4.x extended parser rejects a bare TIMESTAMP token (column type or typed literal) in a blob/vector CREATE TABLE, while spark3.5 accepts it. Retype the transform-source columns to DATE, drop the standalone TIMESTAMP primitive column, and use a DATE typed-literal constructor so the cases parse on all six profiles.
@hudi-bot

Copy link
Copy Markdown
Collaborator

CI report:

Bot commands @hudi-bot supports the following commands:
  • @hudi-bot run azure re-run the last Azure build

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L PR with lines of changes in (300, 1000]

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants