Skip to content

fix: allow sample and extend as unquoted identifiers - #2774

Open
fudianchn wants to merge 1 commit into
JSQLParser:masterfrom
fudianchn:fix/sample-extend-as-identifier
Open

fudianchn wants to merge 1 commit into
JSQLParser:masterfrom
fudianchn:fix/sample-extend-as-identifier

Conversation

@fudianchn

@fudianchn fudianchn commented Oct 11, 2026 •

Copy link
Copy Markdown
Contributor

AI disclosure: this change was prepared with AI coding agents, reviewed and revised line by line by me.

What

SAMPLE and EXTEND can be used as unquoted table and column names, explicit or implicit aliases, and CTE names, including directly after UPDATE. Sampling clauses and the |> EXTEND pipe operator retain their tested meanings.

Why

Both are non-reserved in the common dialects and reach the parser as ordinary names when downstream tools rewrite application SQL: FROM sample / UPDATE sample SET ... (baomidou/mybatis-plus#6504, baomidou/mybatis-plus#6871) and UPDATE t SET extend = ? (baomidou/mybatis-plus#7029, failing for users since 5.2). The identifier failures are reproduced on the tested upstream baseline 8d12a5d7a.

How

Move <K_SAMPLE> and <K_EXTEND> into NonReservedWord() so the existing name, alias, CTE, expression and statement-dispatch helpers recognize them consistently. Add a guard to isAliasAhead(): SAMPLE followed by (, BLOCK, an integer or a decimal starts sampling rather than an implicit alias. The existing AS alias handling and |> EXTEND pipe dispatch remain in place.

Root cause

Both tokens were classified as reserved for their operator uses. A RelObjectName()-only whitelist does not update the other keyword classifiers, leaving implicit aliases, CTEs, UPDATE table names and expression contexts inconsistent. Moving the tokens to NonReservedWord() fixes that classification; the sampling guard is needed because the newly accepted implicit alias could otherwise consume the start of a SAMPLE clause.

Testing

  • Final KeywordsTest: 858 cases, 0 failures. Running the final test source on upstream 8d12a5d7a produces 21 failures among 854 cases (the parameterized keyword enumeration changes with the classification).
  • Regression coverage includes the original identifier statements, mixed-case names, implicit aliases, normal/recursive CTEs, UPDATE table names, CASE, ternaries, and pipe expressions/functions. Assertions check AST node types and their positions as well as parse/deparse output. SELECT ALL cases assert the AST because existing serialization omits ALL.
  • testSampleClauseStaysClause checks the sampling AST and absence of an alias for SAMPLE (10), SAMPLE BLOCK (10) SEED (1), SAMPLE 0.1 OFFSET 1000, USING SAMPLE 10 PERCENT (BERNOULLI) and TABLESAMPLE SYSTEM (10). Removing the alias guard makes the three SAMPLE cases fail; the other two remain passing.
  • On JDK 17.0.20, ./gradlew spotlessApply check jmhJar --no-daemon passes with 9,980 tests; mvn -B -ntp clean verify passes with 9,962 tests. Each suite has 0 failures, 0 errors and 25 existing skips. The initial KeywordsTest.java Spotless formatting failures are corrected.
  • CI for this commit: Gradle and Maven on Linux, Windows and macOS, the grammar-conflict gate, and Codacy all pass. The PR-only run skips publishing and documentation deployment.
  • JSQLParserBenchmark.parseSQLStatements, version=latest, performance.sql checked to produce 54 non-null statements: same Linux host (Intel i9-13900KS), JDK 17.0.20, 512 MiB heap, 3 forks, 2 x 1 s warmup and 5 x 1 s measurement iterations per fork (15 samples per run). Final baseline (8d12a5d7a) -> change -> baseline sequence for this PR: 26.942 [20.933, 32.951] -> 27.454 [20.596, 34.313] -> 26.908 [21.204, 32.612] ms/op; brackets are 99.9% confidence intervals. These short runs did not detect a performance regression; the wide confidence intervals do not rule out smaller differences or effects on other workloads.

Behavior notes

  • t SAMPLE n, USING SAMPLE, TABLESAMPLE and |> EXTEND ... are unchanged.
  • UPDATE sample SET a = 1 and UPDATE extend SET a = 1 now parse and round-trip, including the mixed-case variants in the tests. Implicit aliases use the new non-reserved classification; the SAMPLE guard preserves the tested sampling forms.
  • No AST, deparser or public API changes.

Verification of the original issue

KeywordsTest.testSampleExtendAsIdentifier covers the reported unquoted-name cases, including SELECT * FROM sample and assignments to extend. This test fails on upstream 8d12a5d7a and passes on the final version; additional coverage verifies table names directly after UPDATE. Final single commit 8c023a204ad105606fddd66bba45824d67412518 on fix/sample-extend-as-identifier.

Partially addresses #2772.

Signed-off-by: 付典 <fudianchn@gmail.com>
@fudianchn
fudianchn force-pushed the fix/sample-extend-as-identifier branch from 3289526 to 8c023a2 Compare October 11, 2026 12:51

This branch has not been deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant