Skip to content

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

Merged
nene merged 1 commit into
sql-formatter-org:masterfrom
MaxFreedomPollard:fix-singlestoredb-modulo-operator
Sep 16, 2026
Merged

nene merged 1 commit into
sql-formatter-org:masterfrom
MaxFreedomPollard:fix-singlestoredb-modulo-operator

Conversation

@MaxFreedomPollard

Copy link
Copy Markdown
Contributor

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 %.
@nene

nene commented Sep 16, 2026

Copy link
Copy Markdown
Collaborator

Thanks for the fix.

But please, don't write a wall of text to describe a trivial single-line fix like this one. Or don't use AI to to generate such an epic poem. I really don't know what I should do with it. I suppose you didn't read it. I also didn't read it. For who was it necessary then?

Perhaps if you had not written such a long description I would have even reviewed you change earlier.

@nene
nene merged commit de7587e into sql-formatter-org:master Sep 16, 2026
1 check passed
@MaxFreedomPollard

Copy link
Copy Markdown
Contributor Author

Ok, fair

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.

2 participants