Skip to content

Commit d91f36e

Browse files
authored
Merge PR #387: SingleStoreDB support
2 parents 873a482 + 2a951a5 commit d91f36e

12 files changed

+1582
-49
lines changed

CONTRIBUTING.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ For those who have admin access on the repo, the new release publish flow is as
4141
- Martin Nowak <[email protected]>
4242
- Matheus Salmi <[email protected]>
4343
- Matheus Teixeira <[email protected]>
44+
- Michael Giannakopoulos <[email protected]>
4445
- Nicolas Dermine <[email protected]>
4546
- Offir Baron <[email protected]>
4647
- Olexandr Sydorchuk <[email protected]>

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
It started as a port of a [PHP Library][], but has since considerably diverged.
88

99
It supports various SQL dialects:
10-
GCP BigQuery, IBM DB2, Apache Hive, MariaDB, MySQL, Couchbase N1QL, Oracle PL/SQL, PostgreSQL, Amazon Redshift, Spark, SQL Server Transact-SQL, Trino/Presto.
10+
GCP BigQuery, IBM DB2, Apache Hive, MariaDB, MySQL, Couchbase N1QL, Oracle PL/SQL, PostgreSQL, Amazon Redshift, SingleStoreDB, Spark, SQL Server Transact-SQL, Trino/Presto.
1111
See [language option docs](docs/language.md) for more details.
1212

1313
It does not support:

docs/language.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ Specifies the SQL dialect to use.
1414
- `"plsql"` - [Oracle PL/SQL][]
1515
- `"postgresql"` - [PostgreSQL][]
1616
- `"redshift"` - [Amazon Redshift][]
17+
- `"singlestoredb"` - [SingleStoreDB][]
1718
- `"spark"` - [Spark][]
1819
- `"sqlite"` - [SQLite][sqlite]
1920
- `"trino"` - [Trino][] / [Presto][]
@@ -35,6 +36,7 @@ Better to always pick something more specific if possible.
3536
[postgresql]: https://www.postgresql.org/
3637
[presto]: https://prestodb.io/docs/current/
3738
[amazon redshift]: https://docs.aws.amazon.com/redshift/latest/dg/cm_chap_SQLCommandRef.html
39+
[singlestoredb]: https://docs.singlestore.com/managed-service/en/reference.html
3840
[spark]: https://spark.apache.org/docs/latest/api/sql/index.html
3941
[sqlite]: https://sqlite.org/index.html
4042
[trino]: https://trino.io/docs/current/

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
"format",
1515
"n1ql",
1616
"redshift",
17+
"singlestoredb",
1718
"spark",
1819
"whitespace",
1920
"mysql",
@@ -48,6 +49,7 @@
4849
"Martin Nowak <[email protected]>",
4950
"Matheus Salmi <[email protected]>",
5051
"Matheus Teixeira <[email protected]>",
52+
"Michael Giannakopoulos <[email protected]>",
5153
"Nicolas Dermine <[email protected]>",
5254
"Offir Baron <[email protected]>",
5355
"Olexandr Sydorchuk <[email protected]>",
Lines changed: 266 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,266 @@
1+
import { expandPhrases } from 'src/expandPhrases';
2+
import Formatter from 'src/formatter/Formatter';
3+
import Tokenizer from 'src/lexer/Tokenizer';
4+
import { EOF_TOKEN, isToken, type Token, TokenType } from 'src/lexer/token';
5+
import { keywords } from './singlestoredb.keywords';
6+
import { functions } from './singlestoredb.functions';
7+
8+
const reservedCommands = expandPhrases([
9+
// queries
10+
'WITH',
11+
'SELECT [ALL | DISTINCT | DISTINCTROW]',
12+
'FROM',
13+
'WHERE',
14+
'GROUP BY',
15+
'HAVING',
16+
'ORDER BY',
17+
'LIMIT',
18+
'OFFSET',
19+
// Data manipulation
20+
// - insert:
21+
'INSERT [IGNORE] [INTO]',
22+
'VALUES',
23+
'REPLACE [INTO]',
24+
// - update:
25+
'UPDATE',
26+
'SET',
27+
// - delete:
28+
'DELETE [FROM]',
29+
// - truncate:
30+
'TRUNCATE [TABLE]',
31+
// Data definition
32+
'CREATE VIEW',
33+
'CREATE [ROWSTORE] [REFERENCE | TEMPORARY | GLOBAL TEMPORARY] TABLE [IF NOT EXISTS]',
34+
'CREATE [OR REPLACE] [TEMPORARY] PROCEDURE [IF NOT EXISTS]',
35+
'CREATE [OR REPLACE] [EXTERNAL] FUNCTION',
36+
'DROP [TEMPORARY] TABLE [IF EXISTS]',
37+
// - alter table:
38+
'ALTER [ONLINE] TABLE',
39+
'ADD [COLUMN]',
40+
'ADD [UNIQUE] {INDEX | KEY}',
41+
'DROP [COLUMN]',
42+
'MODIFY [COLUMN]',
43+
'CHANGE',
44+
'RENAME [TO | AS]',
45+
46+
// https://docs.singlestore.com/managed-service/en/reference/sql-reference.html
47+
'ADD AGGREGATOR',
48+
'ADD LEAF',
49+
'AGGREGATOR SET AS MASTER',
50+
'ALTER DATABASE',
51+
'ALTER PIPELINE',
52+
'ALTER RESOURCE POOL',
53+
'ALTER USER',
54+
'ALTER VIEW',
55+
'ANALYZE TABLE',
56+
'ATTACH DATABASE',
57+
'ATTACH LEAF',
58+
'ATTACH LEAF ALL',
59+
'BACKUP DATABASE',
60+
'BINLOG',
61+
'BOOTSTRAP AGGREGATOR',
62+
'CACHE INDEX',
63+
'CALL',
64+
'CHANGE',
65+
'CHANGE MASTER TO',
66+
'CHANGE REPLICATION FILTER',
67+
'CHANGE REPLICATION SOURCE TO',
68+
'CHECK BLOB CHECKSUM',
69+
'CHECK TABLE',
70+
'CHECKSUM TABLE',
71+
'CLEAR ORPHAN DATABASES',
72+
'CLONE',
73+
'COMMIT',
74+
'CREATE DATABASE',
75+
'CREATE GROUP',
76+
'CREATE INDEX',
77+
'CREATE LINK',
78+
'CREATE MILESTONE',
79+
'CREATE PIPELINE',
80+
'CREATE RESOURCE POOL',
81+
'CREATE ROLE',
82+
'CREATE USER',
83+
'DEALLOCATE PREPARE',
84+
'DESCRIBE',
85+
'DETACH DATABASE',
86+
'DETACH PIPELINE',
87+
'DO',
88+
'DROP DATABASE',
89+
'DROP FUNCTION',
90+
'DROP INDEX',
91+
'DROP LINK',
92+
'DROP PIPELINE',
93+
'DROP PROCEDURE',
94+
'DROP RESOURCE POOL',
95+
'DROP ROLE',
96+
'DROP USER',
97+
'DROP VIEW',
98+
'EXECUTE',
99+
'EXPLAIN',
100+
'FLUSH',
101+
'FORCE',
102+
'GRANT',
103+
'HANDLER',
104+
'HELP',
105+
'KILL CONNECTION',
106+
'KILLALL QUERIES',
107+
'LOAD DATA',
108+
'LOAD INDEX INTO CACHE',
109+
'LOAD XML',
110+
'LOCK INSTANCE FOR BACKUP',
111+
'LOCK TABLES',
112+
'MASTER_POS_WAIT',
113+
'OPTIMIZE TABLE',
114+
'PREPARE',
115+
'PURGE BINARY LOGS',
116+
'REBALANCE PARTITIONS',
117+
'RELEASE SAVEPOINT',
118+
'REMOVE AGGREGATOR',
119+
'REMOVE LEAF',
120+
'REPAIR TABLE',
121+
'REPLACE',
122+
'REPLICATE DATABASE',
123+
'RESET',
124+
'RESET MASTER',
125+
'RESET PERSIST',
126+
'RESET REPLICA',
127+
'RESET SLAVE',
128+
'RESTART',
129+
'RESTORE DATABASE',
130+
'RESTORE REDUNDANCY',
131+
'REVOKE',
132+
'ROLLBACK',
133+
'ROLLBACK TO SAVEPOINT',
134+
'SAVEPOINT',
135+
'SET CHARACTER SET',
136+
'SET DEFAULT ROLE',
137+
'SET NAMES',
138+
'SET PASSWORD',
139+
'SET RESOURCE GROUP',
140+
'SET ROLE',
141+
'SET TRANSACTION',
142+
'SHOW',
143+
'SHOW CHARACTER SET',
144+
'SHOW COLLATION',
145+
'SHOW COLUMNS',
146+
'SHOW CREATE DATABASE',
147+
'SHOW CREATE FUNCTION',
148+
'SHOW CREATE PIPELINE',
149+
'SHOW CREATE PROCEDURE',
150+
'SHOW CREATE TABLE',
151+
'SHOW CREATE USER',
152+
'SHOW CREATE VIEW',
153+
'SHOW DATABASES',
154+
'SHOW ENGINE',
155+
'SHOW ENGINES',
156+
'SHOW ERRORS',
157+
'SHOW FUNCTION CODE',
158+
'SHOW FUNCTION STATUS',
159+
'SHOW GRANTS',
160+
'SHOW INDEX',
161+
'SHOW MASTER STATUS',
162+
'SHOW OPEN TABLES',
163+
'SHOW PLUGINS',
164+
'SHOW PRIVILEGES',
165+
'SHOW PROCEDURE CODE',
166+
'SHOW PROCEDURE STATUS',
167+
'SHOW PROCESSLIST',
168+
'SHOW PROFILE',
169+
'SHOW PROFILES',
170+
'SHOW RELAYLOG EVENTS',
171+
'SHOW REPLICA STATUS',
172+
'SHOW REPLICAS',
173+
'SHOW SLAVE',
174+
'SHOW SLAVE HOSTS',
175+
'SHOW STATUS',
176+
'SHOW TABLE STATUS',
177+
'SHOW TABLES',
178+
'SHOW VARIABLES',
179+
'SHOW WARNINGS',
180+
'SHUTDOWN',
181+
'SNAPSHOT DATABASE',
182+
'SOURCE_POS_WAIT',
183+
'START GROUP_REPLICATION',
184+
'START PIPELINE',
185+
'START REPLICA',
186+
'START SLAVE',
187+
'START TRANSACTION',
188+
'STOP GROUP_REPLICATION',
189+
'STOP PIPELINE',
190+
'STOP REPLICA',
191+
'STOP REPLICATING',
192+
'STOP SLAVE',
193+
'TEST PIPELINE',
194+
'TRUNCATE TABLE',
195+
'UNLOCK INSTANCE',
196+
'UNLOCK TABLES',
197+
'USE',
198+
'XA',
199+
// flow control
200+
'ITERATE',
201+
'LEAVE',
202+
'LOOP',
203+
'REPEAT',
204+
'RETURN',
205+
'WHILE',
206+
]);
207+
208+
const reservedSetOperations = expandPhrases([
209+
'UNION [ALL | DISTINCT]',
210+
'EXCEPT',
211+
'INTERSECT',
212+
'MINUS',
213+
]);
214+
215+
const reservedJoins = expandPhrases([
216+
'JOIN',
217+
'{LEFT | RIGHT | FULL} [OUTER] JOIN',
218+
'{INNER | CROSS} JOIN',
219+
'NATURAL {LEFT | RIGHT} [OUTER] JOIN',
220+
// non-standard joins
221+
'STRAIGHT_JOIN',
222+
]);
223+
224+
const reservedPhrases = ['ON DELETE', 'ON UPDATE', 'CHARACTER SET'];
225+
226+
export default class SingleStoreDbFormatter extends Formatter {
227+
static operators = ['~', ':=', '<=>', '<<', '>>', '&&', '||'];
228+
229+
tokenizer() {
230+
return new Tokenizer({
231+
reservedCommands,
232+
reservedSetOperations,
233+
reservedJoins,
234+
reservedDependentClauses: ['WHEN', 'ELSE', 'ELSEIF'],
235+
reservedPhrases,
236+
reservedLogicalOperators: ['AND', 'OR'],
237+
reservedKeywords: keywords,
238+
reservedFunctionNames: functions,
239+
// TODO: support _binary"some string" prefix
240+
stringTypes: [
241+
{ quote: "''", prefixes: ['B', 'X'] },
242+
{ quote: '""', prefixes: ['B', 'X'] },
243+
],
244+
identTypes: ['``'],
245+
identChars: { first: '$', rest: '$', allowFirstCharNumber: true },
246+
variableTypes: [
247+
{ regex: '@[A-Za-z0-9_$]+' },
248+
{ quote: '``', prefixes: ['@'], requirePrefix: true },
249+
],
250+
lineCommentTypes: ['--', '#'],
251+
operators: SingleStoreDbFormatter.operators,
252+
postProcess,
253+
});
254+
}
255+
}
256+
257+
function postProcess(tokens: Token[]) {
258+
return tokens.map((token, i) => {
259+
const nextToken = tokens[i + 1] || EOF_TOKEN;
260+
if (isToken.SET(token) && nextToken.text === '(') {
261+
// This is SET datatype, not SET statement
262+
return { ...token, type: TokenType.RESERVED_FUNCTION_NAME };
263+
}
264+
return token;
265+
});
266+
}

0 commit comments

Comments
 (0)