Skip to content

Fix SPARSE before MASKED WITH column ordering (#216) - #221

Open
NAVEEN NAIK (ZEUSXXIV) wants to merge 1 commit into
microsoft:mainfrom
ZEUSXXIV:fix-issue-216
Open

Fix SPARSE before MASKED WITH column ordering (#216)#221
NAVEEN NAIK (ZEUSXXIV) wants to merge 1 commit into
microsoft:mainfrom
ZEUSXXIV:fix-issue-216

Conversation

@ZEUSXXIV

Copy link
Copy Markdown
Contributor

Description

Fixes #216

CREATE TABLE column definitions that combine SPARSE and MASKED WITH in the order documented by the CREATE TABLE reference (SPARSE first, then MASKED WITH) failed to parse with "Incorrect syntax near 'MASKED'", even though the reversed order (MASKED WITH … SPARSE) parsed fine and both are accepted by the SQL Server engine.

Failing before this change (documented order):

CREATE TABLE t (c VARCHAR(100) SPARSE MASKED WITH (FUNCTION = 'default()') NULL);

Worked before (reversed order):

CREATE TABLE t (c VARCHAR(100) MASKED WITH (FUNCTION = 'default()') SPARSE NULL);

Root cause

In the regularColumnBody grammar rule, the maskedClause was only accepted before the SPARSE/FILESTREAM/COLUMN_SET storage options. There was no way for MASKED WITH to follow SPARSE, so the documented ordering produced a parse error.

Fix

The regularColumnBody rule now accepts maskedClause in two positions:

  1. The pre-existing leading maskedClause (before the storage options) — handles MASKED WITH … SPARSE (reversed order).
  2. A new maskedClause after the storage-options block, before the HIDDEN clause where present — handles SPARSE … MASKED WITH (documented order).

The trailing occurrence is guarded by {NextTokenMatches(Masked) && !vParent.IsMasked}?, which reuses the existing IDataMaskingSetter.IsMasked state so that MASKED WITH cannot be specified twice on the same column (the guard makes the second position inert once the leading one has already consumed a MASKED WITH).

Applied to every grammar that supports MASKED WITH (a SQL Server 2016 feature): TSql130 through TSql180 and TSqlFabricDW.

Compatibility / non-breaking

This change is intentionally additive and does not alter the public API surface:

  • No Ast.xml changes — no AST class, enum, or property was added, renamed, or retyped. It reuses the existing IDataMaskingSetter.IsMasked / MaskingFunction and ColumnStorageOptions members.
  • No behavioral regression — the new clause only triggers on a MASKED token that previously produced a parse error, so no previously valid input changes its AST or output. All existing baselines are unchanged.
  • The script generator already emits SPARSE MASKED WITH …, so parse → generate → re-parse round-trips cleanly for both input orders.

Tests

  • Positive round-trip: Test/SqlDom/TestScripts/SparseMaskedColumnOrderTests130.sql with baseline Test/SqlDom/Baselines130/SparseMaskedColumnOrderTests130.sql, wired through Only130SyntaxTests.cs. Covers the exact statement from the issue (documented order), the reversed order, and SPARSE FILESTREAM + MASKED WITH. Verified across the TSql130TSql180 parsers.
  • Negative / version-gating: SparseMaskedColumnNegativeTest in ParserErrorsTests.cs asserts that specifying MASKED WITH twice on one column is a parse error (SQL46010).
  • Full suite passes on both target frameworks: net8.0 — 907/907, net472 — 907/907.

Code Changes

CREATE TABLE column definitions that combine SPARSE and MASKED WITH in
the order documented by the CREATE TABLE reference (SPARSE first, then
MASKED WITH) failed to parse with "Incorrect syntax near 'MASKED'",
while the reversed order parsed fine.

In regularColumnBody the grammar only accepted the leading maskedClause
before the SPARSE/FILESTREAM storage options, so MASKED could never
follow SPARSE. Add a second, guarded maskedClause after the storage
block (before the HIDDEN clause where present) so both documented and
reversed orders parse. The `!vParent.IsMasked` guard prevents MASKED
WITH from being specified twice on the same column.

Applied to all grammars that support MASKED WITH: TSql130 through
TSql180 and TSqlFabricDW.

Tests:
- Positive round-trip: TestScripts/SparseMaskedColumnOrderTests130.sql
  with baseline Baselines130/SparseMaskedColumnOrderTests130.sql, wired
  through Only130SyntaxTests.cs (verified across the TSql130-TSql180
  parsers).
- Negative: SparseMaskedColumnNegativeTest in ParserErrorsTests.cs
  asserts MASKED WITH specified twice is a parse error.
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.

CREATE TABLE: SPARSE MASKED WITH (...) column order (per MS docs) fails to parse; reversed order parses fine

1 participant