GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — feat: support SQL Server OPTION query hints (#161) by fudianchn · Pull Request #2472 · JSQLParser/JSqlParser

Conversation

@fudianchn

@fudianchn fudianchn commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

What

Adds support for the SQL Server (T-SQL) OPTION (...) query hint clause at the end of SELECT (including after set operations and FOR XML), UPDATE and DELETE statements, modelled as a new OptionClause holding a list of OptionHints.

Why

The grammar has no production for query hints (#161), so statements like SELECT CustomerID, PersonID, StoreID FROM cte OPTION (MAXRECURSION 2) fail to parse, although this is everyday T-SQL for query tuning.

How

  • New OptionClause() production attached in four places (after ForClause in PlainSelect, before LIMIT in the Select wrapper, after LIMIT in Update/Delete), following the Hints (Transact-SQL) - Query Hints documentation.
  • OptionHintName() collects (possibly multi-word) keyword names (RECOMPILE, HASH JOIN, OPTIMIZE FOR UNKNOWN, ...) from identifiers, the non-reserved word range and an explicit list of reserved words usable inside hint keywords (JOIN, FOR, ORDER, UNION, EXCEPT, INTERSECT, USE, OPTIMIZE, FORCE, UNKNOWN).
  • A hint takes no argument, a single value (FAST 100, MAXDOP 4, MAX_GRANT_PERCENT = 25) or a parenthesized argument list (USE HINT ('...'), OPTIMIZE FOR (@p = 1), TABLE HINT (t, INDEX (i))), kept generically as name + value/parameters because SQL Server keeps adding new hints with every release.
  • K_OPTION is a non-reserved keyword; isAliasAhead() treats K_OPTION followed by ( as a clause start rather than a table alias, so option remains usable as a column and table name.
  • Like ORDER BY/LIMIT, the clause is hoisted from the last PlainSelect onto the SetOperationList, so SELECT ... UNION SELECT ... ORDER BY ... OPTION (...) deparse in the right order.
  • AST classes OptionClause/OptionHint plus wiring in Select, Update, Delete, the three deparsers and the three validators.

Root cause

Missing feature: the grammar has no production for the T-SQL query hint clause, so such statements always threw a ParseException.

Testing

  • New OptionClauseTest (13 cases): the issue's SQL plus AST assertions, all hint shapes (keyword / value / equals / parameter list), UNION, FOR XML, UPDATE, DELETE, and option as column/table name; ./gradlew test --tests ...OptionClauseTest passes.
  • Full local gate ./gradlew spotlessApply check on the branch: 4816 tests, 0 failures.

Verification of the original issue

Before (master 406a4d4): CCJSqlParserUtil.parse("SELECT CustomerID, PersonID, StoreID FROM cte OPTION (MAXRECURSION 2)") throws a ParseException.
After: parses into PlainSelect with getOption().getOptionHints().get(0) = name MAXRECURSION, value 2, and the deparse round-trips unchanged. All other query hint forms currently documented by Microsoft parse and round-trip as well.

Grammar change, paired gradle jmh runs (JSQLParserBenchmark.parseSQLStatements on performance.sql, version=latest, 10 forks x 10 iterations = 100 samples each, 32-core host), two interleaved pairs:

build ms/op (run 1) ms/op (run 2)
master 406a4d4 3.724 ± 0.028 3.740 ± 0.030
this PR 3.747 ± 0.025 3.761 ± 0.030

In both pairs the delta (+0.6%) is smaller than the combined confidence interval -> not statistically significant, no regression.

Limitation: T-SQL also allows OPTION (...) after INSERT and MERGE statements, and the OPTIMIZE FOR (@var UNKNOWN) parameter form; these are not covered yet (the latter needs an AST representation for a variable followed by the bare UNKNOWN keyword, e.g. a dedicated expression type or a nullable-value VariableAssignment; both can be added in follow-ups without changing the modeling introduced here).

Fixes #161

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@fudianchn
feat: support SQL Server OPTION query hints (JSQLParser#161)
3bca3dc
Parse the T-SQL OPTION (...) clause at the end of SELECT (including after
set operations and FOR XML), UPDATE and DELETE statements, following the
Query Hints documentation: multi-word keyword hints (RECOMPILE, HASH
JOIN, FORCE ORDER, OPTIMIZE FOR UNKNOWN, ...), single value arguments
(FAST 100, MAXDOP 4, MAX_GRANT_PERCENT = 25) and parenthesized argument
lists (USE HINT ('...'), OPTIMIZE FOR (@p = 1), TABLE HINT (t, INDEX
(i))).

Hints are kept in a generic OptionHint (keyword name + optional value or
ExpressionList parameters) attached via a new OptionClause, mirroring
how SQL Server keeps adding new hints without enum churn. OPTION is a
non-reserved keyword and K_OPTION followed by ( is excluded from alias
positions, so option remains usable as a column and table name. The
union hoisting lifts the clause from the last PlainSelect onto the
SetOperationList like ORDER BY and LIMIT.

Signed-off-by: 付典 <[email protected]>
@fudianchn fudianchn mentioned this pull request Aug 15, 2026
add support for SQL Server Query Hints #161
Closed
@manticore-projects

manticore-projects commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

Strong and solid! Thank you for providing this!

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@manticore-projects
manticore-projects merged commit 138947d into JSQLParser:master Aug 16, 2026
7 checks passed

Uh oh!

There was an error while loading. Please reload this page.

@fudianchn fudianchn mentioned this pull request Aug 18, 2026
feat: complete SQL Server OPTION query hint support #2486
Merged
@fudianchn
fudianchn deleted the feat/sqlserver-query-hints-161 branch August 21, 2026 00:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

No reviews

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

add support for SQL Server Query Hints

Uh oh!

There was an error while loading. Please reload this page.

2 participants

@fudianchn @manticore-projects
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.