Skip to content

fix(singlestoredb): support % as the modulo operator - #971

Open
MaxFreedomPollard wants to merge 1 commit into
sql-formatter-org:masterfrom
MaxFreedomPollard:fix-singlestoredb-modulo-operator
Open

fix(singlestoredb): support % as the modulo operator#971
MaxFreedomPollard wants to merge 1 commit into
sql-formatter-org:masterfrom
MaxFreedomPollard:fix-singlestoredb-modulo-operator

Conversation

@MaxFreedomPollard

Copy link
Copy Markdown

Formatting a SingleStoreDB query that uses % throws a parse error instead of returning SQL. MOD(a, b) and a MOD b format fine, but a % b does not, even though SingleStore documents all three as equivalent (MOD gives expression1 % expression2 and the example SELECT 25 % 0;).

format('SELECT 25 % 7', { language: 'singlestoredb' });
// Parse error: Unexpected "% 7" at line 1 column 11.
// SQL dialect used: "singlestoredb".

This is the same symptom #578 reported against MySQL, where (released_year % 2) != 0 failed to format. MySQL was fixed; SingleStoreDB still fails on the identical query.

Root cause

src/lexer/Tokenizer.ts builds the OPERATOR rule from a fixed standard set (+ - / > < = <> <= >= !=) plus whatever the dialect puts in cfg.operators. % is not in the standard set, and the operators array at src/languages/singlestoredb/singlestoredb.formatter.ts:267 omits it, so nothing matches the character and TokenizerEngine raises the parse error.

Every MySQL-family sibling lists '%' first in that same array: src/languages/mysql/mysql.formatter.ts, src/languages/mariadb/mariadb.formatter.ts and src/languages/tidb/tidb.formatter.ts. The SingleStoreDB list, which otherwise tracks them, just dropped it.

Fix

Add '%' to singlestoredb.formatter.ts, in the same leading position the siblings use.

regexFactory.operator sorts the alternatives by length descending, so SingleStore's three-character ::% conversion path-operator still matches before the bare one-character %. The existing formats '::%' conversion path-operator without spaces test in test/singlestoredb.test.ts pins that and still passes.

I checked the other 19 dialect files under src/languages/ for the same omission and found none: every dialect whose documentation gives a % operator already lists it. Standard sql and bigquery are correct to leave it out, since GoogleSQL has MOD(X, Y) and no % operator. db2i also leaves it out, and I left that as it is.

Tests

'%' added to the supportsOperators(...) list in test/singlestoredb.test.ts, which covers both default spacing (foo % bar % zap) and denseOperators: true (foo%bar). Prettier reflowed the array onto one entry per line, matching how test/mysql.test.ts already writes it.

Both new cases fail on master with Parse error: Unexpected "% bar %zap" and pass with the fix. pnpm run pretty:check, pnpm run lint, pnpm run ts:check, pnpm run test and pnpm run build are all green.

Formatting a SingleStoreDB query that uses % throws instead of
returning SQL:

  format('SELECT 25 % 7', { language: 'singlestoredb' })
  Parse error: Unexpected "% 7" at line 1 column 11.

SingleStore documents three equivalent modulo forms, MOD(a, b),
a MOD b and a % b. The first two format fine, the third does not.

The tokenizer builds its OPERATOR rule from a fixed standard set
(+ - / > < = <> <= >= !=) plus the dialect's own cfg.operators list,
in src/lexer/Tokenizer.ts. % is not in the standard set, and the
operators array in src/languages/singlestoredb/singlestoredb.formatter.ts
omits it, so no rule matches the character and TokenizerEngine raises a
parse error. Every MySQL-family sibling (mysql, mariadb, tidb) lists '%'
first in the same array; the SingleStoreDB copy dropped it.

Add '%' to that array, in the same leading position the siblings use.
regexFactory.operator sorts the alternatives by length descending, so
SingleStore's ::% conversion path-operator still matches before the
bare %.
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