Repository: sql-formatter-org/sql-formatter
Pull request #369 (2022-08-03 09:40:46)

Data manipulation clauses overhaul
Based on our wiki docs.

- Organized the list of these clauses in consistent way for all dialects
- Added bunch of tests

There are more data-manipulation statements, but at least the main ones should now be better covered.


Patch:
diff --git a/src/languages/bigquery/bigquery.formatter.ts b/src/languages/bigquery/bigquery.formatter.ts
index 5c86f196..6ab665d3 100644
--- a/src/languages/bigquery/bigquery.formatter.ts
+++ b/src/languages/bigquery/bigquery.formatter.ts
@@ -20,13 +20,21 @@ const reservedCommands = expandPhrases([
   'LIMIT',
   'OFFSET',
   'OMIT RECORD IF', // legacy
-  // DML, https://cloud.google.com/bigquery/docs/reference/standard-sql/dml-syntax
+  // Data modification: https://cloud.google.com/bigquery/docs/reference/standard-sql/dml-syntax
+  // - insert:
   'INSERT [INTO]',
   'VALUES',
+  // - update:
+  'UPDATE',
+  'SET',
+  // - delete:
   'DELETE [FROM]',
+  // - truncate:
   'TRUNCATE TABLE',
-  'UPDATE',
+  // - merge:
   'MERGE [INTO]',
+  'WHEN [NOT] MATCHED [BY SOURCE | BY TARGET] [THEN]',
+  'UPDATE SET',
   // DDL, https://cloud.google.com/bigquery/docs/reference/standard-sql/data-definition-language
   'CREATE SCHEMA [IF NOT EXISTS]',
   'DEFAULT COLLATE',
@@ -77,7 +85,6 @@ const reservedCommands = expandPhrases([
   'REVOKE',
   // Script, https://cloud.google.com/bigquery/docs/reference/standard-sql/scripting
   'DECLARE',
-  'SET',
   'EXECUTE IMMEDIATE',
   'LOOP',
   'END LOOP',
diff --git a/src/languages/db2/db2.formatter.ts b/src/languages/db2/db2.formatter.ts
index 620660f3..1b54ddc6 100644
--- a/src/languages/db2/db2.formatter.ts
+++ b/src/languages/db2/db2.formatter.ts
@@ -14,6 +14,24 @@ const reservedCommands = expandPhrases([
   'HAVING',
   'ORDER BY [INPUT SEQUENCE]',
   'FETCH FIRST',
+  // Data modification
+  // - insert:
+  'INSERT INTO',
+  'VALUES',
+  // - update:
+  'UPDATE',
+  'SET',
+  'WHERE CURRENT OF',
+  'WITH {RR | RS | CS | UR}',
+  // - delete:
+  'DELETE FROM',
+  // - truncate:
+  'TRUNCATE [TABLE]',
+  // - merge:
+  'MERGE INTO',
+  'WHEN [NOT] MATCHED [THEN]',
+  'UPDATE SET',
+  'INSERT',
   // https://www.ibm.com/docs/en/db2-for-zos/11?topic=statements-list-supported
   'ALLOCATE CURSOR',
   'ALTER DATABASE',
@@ -62,8 +80,6 @@ const reservedCommands = expandPhrases([
   'DECLARE STATEMENT',
   'DECLARE TABLE',
   'DECLARE VARIABLE',
-  'DELETE',
-  'DELETE FROM',
   'DESCRIBE CURSOR',
   'DESCRIBE INPUT',
   'DESCRIBE OUTPUT',
@@ -81,10 +97,8 @@ const reservedCommands = expandPhrases([
   'GRANT',
   'HOLD LOCATOR',
   'INCLUDE',
-  'INSERT',
   'LABEL',
   'LOCK TABLE',
-  'MERGE',
   'OPEN',
   'PREPARE',
   'REFRESH',
@@ -96,7 +110,6 @@ const reservedCommands = expandPhrases([
   'SAVEPOINT',
   'SELECT INTO',
   'SET CONNECTION',
-  'SET',
   'SET CURRENT ACCELERATOR',
   'SET CURRENT APPLICATION COMPATIBILITY',
   'SET CURRENT APPLICATION ENCODING SCHEME',
@@ -124,9 +137,6 @@ const reservedCommands = expandPhrases([
   'SET SCHEMA',
   'SET SESSION TIME ZONE',
   'SIGNAL',
-  'TRUNCATE',
-  'UPDATE',
-  'VALUES',
   'VALUES INTO',
   'WHENEVER',
   // other
@@ -135,7 +145,6 @@ const reservedCommands = expandPhrases([
   'AFTER',
   'DROP TABLE',
   'GO',
-  'INSERT INTO',
   'SET CURRENT SCHEMA',
 ]);
 
diff --git a/src/languages/hive/hive.formatter.ts b/src/languages/hive/hive.formatter.ts
index ec4c6507..77b81019 100644
--- a/src/languages/hive/hive.formatter.ts
+++ b/src/languages/hive/hive.formatter.ts
@@ -19,6 +19,31 @@ const reservedCommands = expandPhrases([
   'CLUSTER BY',
   'DISTRIBUTE BY',
   'LIMIT',
+  // Data manipulation
+  // - insert:
+  //   Hive does not actually support plain INSERT INTO, only INSERT INTO TABLE
+  //   but it's a nuisance to not support it, as all other dialects do.
+  'INSERT INTO [TABLE]',
+  'VALUES',
+  // - update:
+  'UPDATE',
+  'SET',
+  // - delete:
+  'DELETE FROM',
+  // - truncate:
+  'TRUNCATE [TABLE]',
+  // - merge:
+  'MERGE INTO',
+  'WHEN [NOT] MATCHED [THEN]',
+  'UPDATE SET',
+  'INSERT [VALUES]',
+  // - insert overwrite directory:
+  //   https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DML#LanguageManualDML-Writingdataintothefilesystemfromqueries
+  'INSERT OVERWRITE [LOCAL] DIRECTORY',
+  // - load:
+  //   https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DML#LanguageManualDML-Loadingfilesintotables
+  'LOAD DATA [LOCAL] INPATH',
+  '[OVERWRITE] INTO TABLE',
   // other
   'ALTER',
   'ALTER COLUMN', // added
@@ -30,14 +55,8 @@ const reservedCommands = expandPhrases([
   'DROP',
   'DROP TABLE', // added
   'FETCH',
-  'INSERT',
-  'INSERT INTO', // added
-  'SET',
   'SET SCHEMA', // added
   'SHOW',
-  'TRUNCATE',
-  'UPDATE',
-  'VALUES',
   // newline keywords
   'STORED AS',
   'STORED BY',
diff --git a/src/languages/mariadb/mariadb.formatter.ts b/src/languages/mariadb/mariadb.formatter.ts
index eff6c8d5..9f4d7797 100644
--- a/src/languages/mariadb/mariadb.formatter.ts
+++ b/src/languages/mariadb/mariadb.formatter.ts
@@ -17,6 +17,18 @@ const reservedCommands = expandPhrases([
   'LIMIT',
   'OFFSET',
   'FETCH {FIRST | NEXT}',
+  // Data manipulation
+  // - insert:
+  'INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE] [INTO]',
+  'REPLACE [LOW_PRIORITY | DELAYED] [INTO]',
+  'VALUES',
+  // - update:
+  'UPDATE [LOW_PRIORITY] [IGNORE]',
+  'SET',
+  // - delete:
+  'DELETE [LOW_PRIORITY] [QUICK] [IGNORE] FROM',
+  // - truncate:
+  'TRUNCATE [TABLE]',
   // https://mariadb.com/docs/reference/mdb/sql-statements/
   'ALTER DATABASE',
   'ALTER DATABASE COMMENT',
@@ -60,8 +72,6 @@ const reservedCommands = expandPhrases([
   'CREATE USER',
   'CREATE VIEW',
   'DEALLOCATE PREPARE',
-  'DELETE',
-  'DELETE FROM',
   'DESCRIBE',
   'DO',
   'DROP DATABASE',
@@ -85,7 +95,6 @@ const reservedCommands = expandPhrases([
   'GRANT',
   'HANDLER',
   'HELP',
-  'INSERT',
   'INSTALL PLUGIN',
   'INSTALL SONAME',
   'KILL',
@@ -102,7 +111,6 @@ const reservedCommands = expandPhrases([
   'RENAME USER',
   'REPAIR TABLE',
   'REPAIR VIEW',
-  'REPLACE',
   'RESET MASTER',
   'RESET QUERY CACHE',
   'RESET REPLICA',
@@ -113,7 +121,6 @@ const reservedCommands = expandPhrases([
   'ROLLBACK',
   'SAVEPOINT',
   'SELECT',
-  'SET',
   'SET CHARACTER SET',
   'SET DEFAULT ROLE',
   'SET GLOBAL TRANSACTION',
@@ -204,12 +211,9 @@ const reservedCommands = expandPhrases([
   'STOP ALL SLAVES',
   'STOP REPLICA',
   'STOP SLAVE',
-  'TRUNCATE',
-  'TRUNCATE TABLE',
   'UNINSTALL PLUGIN',
   'UNINSTALL SONAME',
   'UNLOCK TABLE',
-  'UPDATE',
   'USE',
   'XA BEGIN',
   'XA COMMIT',
@@ -221,9 +225,6 @@ const reservedCommands = expandPhrases([
   // other
   'ADD',
   'ALTER COLUMN',
-  'INSERT INTO',
-  'INSERT',
-  'VALUES',
 ]);
 
 const reservedSetOperations = expandPhrases([
diff --git a/src/languages/mysql/mysql.formatter.ts b/src/languages/mysql/mysql.formatter.ts
index 32a42dbf..cbef23d4 100644
--- a/src/languages/mysql/mysql.formatter.ts
+++ b/src/languages/mysql/mysql.formatter.ts
@@ -18,6 +18,18 @@ const reservedCommands = expandPhrases([
   'ORDER BY',
   'LIMIT',
   'OFFSET',
+  // Data manipulation
+  // - insert:
+  'INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE] [INTO]',
+  'REPLACE [LOW_PRIORITY | DELAYED] [INTO]',
+  'VALUES',
+  // - update:
+  'UPDATE [LOW_PRIORITY] [IGNORE]',
+  'SET',
+  // - delete:
+  'DELETE [LOW_PRIORITY] [QUICK] [IGNORE] FROM',
+  // - truncate:
+  'TRUNCATE [TABLE]',
   // https://dev.mysql.com/doc/refman/8.0/en/sql-statements.html
   'ALTER DATABASE',
   'ALTER EVENT',
@@ -59,8 +71,6 @@ const reservedCommands = expandPhrases([
   'CREATE USER',
   'CREATE VIEW',
   'DEALLOCATE PREPARE',
-  'DELETE',
-  'DELETE FROM',
   'DESCRIBE',
   'DO',
   'DROP DATABASE',
@@ -86,7 +96,6 @@ const reservedCommands = expandPhrases([
   'HANDLER',
   'HELP',
   'IMPORT TABLE',
-  'INSERT',
   'INSTALL COMPONENT',
   'INSTALL PLUGIN',
   'KILL',
@@ -103,7 +112,6 @@ const reservedCommands = expandPhrases([
   'RENAME TABLE',
   'RENAME USER',
   'REPAIR TABLE',
-  'REPLACE',
   'RESET',
   'RESET MASTER',
   'RESET PERSIST',
@@ -114,7 +122,6 @@ const reservedCommands = expandPhrases([
   'ROLLBACK',
   'ROLLBACK TO SAVEPOINT',
   'SAVEPOINT',
-  'SET',
   'SET CHARACTER SET',
   'SET DEFAULT ROLE',
   'SET NAMES',
@@ -175,14 +182,11 @@ const reservedCommands = expandPhrases([
   'STOP REPLICA',
   'STOP SLAVE',
   'TABLE',
-  'TRUNCATE TABLE',
   'UNINSTALL COMPONENT',
   'UNINSTALL PLUGIN',
   'UNLOCK INSTANCE',
   'UNLOCK TABLES',
-  'UPDATE',
   'USE',
-  'VALUES',
   'XA',
   // flow control
   // 'IF',
@@ -195,7 +199,6 @@ const reservedCommands = expandPhrases([
   // other
   'ADD',
   'ALTER COLUMN',
-  'INSERT INTO',
 ]);
 
 const reservedSetOperations = expandPhrases(['UNION [ALL | DISTINCT]']);
diff --git a/src/languages/n1ql/n1ql.formatter.ts b/src/languages/n1ql/n1ql.formatter.ts
index d60c846d..96335234 100644
--- a/src/languages/n1ql/n1ql.formatter.ts
+++ b/src/languages/n1ql/n1ql.formatter.ts
@@ -17,6 +17,20 @@ const reservedCommands = expandPhrases([
   'ORDER BY',
   'LIMIT',
   'OFFSET',
+  // Data manipulation
+  // - insert:
+  'INSERT INTO',
+  'VALUES',
+  // - update:
+  'UPDATE',
+  'SET',
+  // - delete:
+  'DELETE FROM',
+  // - merge:
+  'MERGE INTO',
+  'WHEN [NOT] MATCHED THEN',
+  'UPDATE SET',
+  'INSERT',
   // https://docs.couchbase.com/server/current/n1ql/n1ql-language-reference/reservedwords.html
   'ADVISE',
   'ALTER INDEX',
@@ -28,8 +42,6 @@ const reservedCommands = expandPhrases([
   'CREATE INDEX',
   'CREATE PRIMARY INDEX',
   'CREATE SCOPE',
-  'DELETE',
-  'DELETE FROM',
   'DROP COLLECTION',
   'DROP FUNCTION',
   'DROP INDEX',
@@ -40,28 +52,22 @@ const reservedCommands = expandPhrases([
   'EXPLAIN',
   'GRANT',
   'INFER',
-  'INSERT',
-  'MERGE',
   'PREPARE',
   'RETURNING',
   'REVOKE',
   'ROLLBACK TRANSACTION',
   'SAVEPOINT',
   'SET TRANSACTION',
-  'UPDATE',
   'UPDATE STATISTICS',
   'UPSERT',
   // other
-  'INSERT INTO',
   'LET',
   'NEST',
   'SET CURRENT SCHEMA',
   'SET SCHEMA',
-  'SET',
   'SHOW',
   'UNNEST',
   'USE KEYS',
-  'VALUES',
 ]);
 
 const reservedSetOperations = expandPhrases(['UNION [ALL]', 'EXCEPT [ALL]', 'INTERSECT [ALL]']);
diff --git a/src/languages/plsql/plsql.formatter.ts b/src/languages/plsql/plsql.formatter.ts
index 0b4fadc7..19c18324 100644
--- a/src/languages/plsql/plsql.formatter.ts
+++ b/src/languages/plsql/plsql.formatter.ts
@@ -16,6 +16,21 @@ const reservedCommands = expandPhrases([
   'ORDER [SIBLINGS] BY',
   'OFFSET',
   'FETCH {FIRST | NEXT}',
+  // Data manipulation
+  // - insert:
+  'INSERT [INTO | ALL INTO]',
+  'VALUES',
+  // - update:
+  'UPDATE [ONLY]',
+  'SET',
+  // - delete:
+  'DELETE FROM [ONLY]',
+  // - truncate:
+  'TRUNCATE TABLE',
+  // - merge:
+  'MERGE [INTO]',
+  'WHEN [NOT] MATCHED [THEN]',
+  'UPDATE SET',
   // other
   'ADD',
   'ALTER COLUMN',
@@ -25,21 +40,14 @@ const reservedCommands = expandPhrases([
   'CREATE TABLE',
   'DROP TABLE',
   'DECLARE',
-  'DELETE',
-  'DELETE FROM',
   'EXCEPT',
   'EXCEPTION',
-  'INSERT INTO',
-  'INSERT',
   'LOOP',
   'MODIFY',
   'RETURNING',
   'SET CURRENT SCHEMA',
   'SET SCHEMA',
-  'SET',
   'START WITH',
-  'UPDATE',
-  'VALUES',
 ]);
 
 const reservedSetOperations = expandPhrases(['UNION [ALL]', 'EXCEPT', 'INTERSECT']);
diff --git a/src/languages/postgresql/postgresql.formatter.ts b/src/languages/postgresql/postgresql.formatter.ts
index 65a7cab0..73397d71 100644
--- a/src/languages/postgresql/postgresql.formatter.ts
+++ b/src/languages/postgresql/postgresql.formatter.ts
@@ -18,6 +18,18 @@ const reservedCommands = expandPhrases([
   'LIMIT',
   'OFFSET',
   'FETCH {FIRST | NEXT}',
+  // Data manipulation
+  // - insert:
+  'INSERT INTO',
+  'VALUES',
+  // - update:
+  'UPDATE [ONLY]',
+  'SET',
+  'WHERE CURRENT OF',
+  // - delete:
+  'DELETE FROM [ONLY]',
+  // - truncate:
+  'TRUNCATE [TABLE] [ONLY]',
   // https://www.postgresql.org/docs/14/sql-commands.html
   'ABORT',
   'ALTER AGGREGATE',
@@ -116,8 +128,6 @@ const reservedCommands = expandPhrases([
   'CREATE VIEW',
   'DEALLOCATE',
   'DECLARE',
-  'DELETE',
-  'DELETE FROM',
   'DISCARD',
   'DO',
   'DROP ACCESS METHOD',
@@ -168,7 +178,6 @@ const reservedCommands = expandPhrases([
   'FETCH',
   'GRANT',
   'IMPORT FOREIGN SCHEMA',
-  'INSERT',
   'LISTEN',
   'LOAD',
   'LOCK',
@@ -189,23 +198,18 @@ const reservedCommands = expandPhrases([
   'SAVEPOINT',
   'SECURITY LABEL',
   'SELECT INTO',
-  'SET',
   'SET CONSTRAINTS',
   'SET ROLE',
   'SET SESSION AUTHORIZATION',
   'SET TRANSACTION',
   'SHOW',
   'START TRANSACTION',
-  'TRUNCATE',
   'UNLISTEN',
-  'UPDATE',
   'VACUUM',
-  'VALUES',
   // other
   'ADD',
   'AFTER',
   'ALTER COLUMN',
-  'INSERT INTO',
   'SET SCHEMA',
 ]);
 
diff --git a/src/languages/redshift/redshift.formatter.ts b/src/languages/redshift/redshift.formatter.ts
index 0245f8b1..396b082c 100644
--- a/src/languages/redshift/redshift.formatter.ts
+++ b/src/languages/redshift/redshift.formatter.ts
@@ -15,6 +15,17 @@ const reservedCommands = expandPhrases([
   'ORDER BY',
   'LIMIT',
   'OFFSET',
+  // Data manipulation
+  // - insert:
+  'INSERT INTO',
+  'VALUES',
+  // - update:
+  'UPDATE',
+  'SET',
+  // - delete:
+  'DELETE [FROM]',
+  // - truncate:
+  'TRUNCATE [TABLE]',
   // https://docs.aws.amazon.com/redshift/latest/dg/c_SQL_commands.html
   'ABORT',
   'ALTER DATABASE',
@@ -56,8 +67,6 @@ const reservedCommands = expandPhrases([
   'CREATE VIEW',
   'DEALLOCATE',
   'DECLARE',
-  'DELETE',
-  'DELETE FROM',
   'DESC DATASHARE',
   'DROP DATABASE',
   'DROP DATASHARE',
@@ -76,7 +85,6 @@ const reservedCommands = expandPhrases([
   'EXPLAIN',
   'FETCH',
   'GRANT',
-  'INSERT',
   'LOCK',
   'PREPARE',
   'REFRESH MATERIALIZED VIEW',
@@ -84,7 +92,6 @@ const reservedCommands = expandPhrases([
   'REVOKE',
   'ROLLBACK',
   'SELECT INTO',
-  'SET',
   'SET SESSION AUTHORIZATION',
   'SET SESSION CHARACTERISTICS',
   'SHOW',
@@ -95,13 +102,9 @@ const reservedCommands = expandPhrases([
   'SHOW TABLE',
   'SHOW VIEW',
   'START TRANSACTION',
-  'TRUNCATE',
   'UNLOAD',
-  'UPDATE',
   'VACUUM',
-  'VALUES',
   // other
-  'INSERT INTO',
   'ALTER COLUMN',
 ]);
 
diff --git a/src/languages/spark/spark.formatter.ts b/src/languages/spark/spark.formatter.ts
index ae78b8af..19e2b31e 100644
--- a/src/languages/spark/spark.formatter.ts
+++ b/src/languages/spark/spark.formatter.ts
@@ -20,6 +20,19 @@ const reservedCommands = expandPhrases([
   'CLUSTER BY',
   'DISTRIBUTE BY',
   'LIMIT',
+  // Data manipulation
+  // - insert:
+  'INSERT [INTO | OVERWRITE] [TABLE]',
+  'VALUES',
+  // - truncate:
+  'TRUNCATE TABLE',
+  // - insert overwrite directory:
+  //   https://spark.apache.org/docs/latest/sql-ref-syntax-dml-insert-overwrite-directory.html
+  'INSERT OVERWRITE [LOCAL] DIRECTORY',
+  // - load:
+  //   https://spark.apache.org/docs/latest/sql-ref-syntax-dml-load.html
+  'LOAD DATA [LOCAL] INPATH',
+  '[OVERWRITE] INTO TABLE',
   // DDL
   'ALTER COLUMN',
   'ALTER DATABASE',
@@ -34,15 +47,8 @@ const reservedCommands = expandPhrases([
   'DROP TABLE',
   'DROP VIEW',
   'REPAIR TABLE',
-  'TRUNCATE TABLE',
   'USE DATABASE',
-  // DML
-  'INSERT INTO',
-  'INSERT OVERWRITE',
-  'INSERT OVERWRITE DIRECTORY',
-  'LOAD',
   // Data Retrieval
-  'VALUES',
   'TABLESAMPLE',
   'PIVOT',
   'TRANSFORM',
@@ -63,7 +69,6 @@ const reservedCommands = expandPhrases([
   'REFRESH TABLE',
   'REFRESH FUNCTION',
   'RESET',
-  'SET',
   'SHOW COLUMNS',
   'SHOW CREATE TABLE',
   'SHOW DATABASES',
@@ -75,9 +80,7 @@ const reservedCommands = expandPhrases([
   'SHOW VIEWS',
   'UNCACHE TABLE',
   // other
-  'INSERT',
   'LATERAL VIEW',
-  'UPDATE',
 ]);
 
 const reservedSetOperations = expandPhrases([
diff --git a/src/languages/sql/sql.formatter.ts b/src/languages/sql/sql.formatter.ts
index 3a680fcc..b7efdbed 100644
--- a/src/languages/sql/sql.formatter.ts
+++ b/src/languages/sql/sql.formatter.ts
@@ -18,18 +18,25 @@ const reservedCommands = expandPhrases([
   'LIMIT',
   'OFFSET',
   'FETCH {FIRST | NEXT}',
+  // Data manipulation
+  // - insert:
+  'INSERT INTO',
+  'VALUES',
+  // - update:
+  'UPDATE',
+  'SET',
+  'WHERE CURRENT OF',
+  // - delete:
+  'DELETE FROM',
+  // - truncate:
+  'TRUNCATE TABLE',
   // other
   'ADD',
   'ALTER COLUMN',
   'ALTER TABLE',
   'CREATE TABLE',
   'DROP TABLE',
-  'DELETE FROM',
-  'INSERT INTO',
   'SET SCHEMA',
-  'SET',
-  'UPDATE',
-  'VALUES',
 ]);
 
 const reservedSetOperations = expandPhrases([
diff --git a/src/languages/sqlite/sqlite.formatter.ts b/src/languages/sqlite/sqlite.formatter.ts
index aa72b751..b9716d23 100644
--- a/src/languages/sqlite/sqlite.formatter.ts
+++ b/src/languages/sqlite/sqlite.formatter.ts
@@ -17,19 +17,23 @@ const reservedCommands = expandPhrases([
   'ORDER BY',
   'LIMIT',
   'OFFSET',
+  // Data manipulation
+  // - insert:
+  'INSERT [OR ABORT | OR FAIL | OR IGNORE | OR REPLACE | OR ROLLBACK] INTO',
+  'REPLACE INTO',
+  'VALUES',
+  // - update:
+  'UPDATE [OR ABORT | OR FAIL | OR IGNORE | OR REPLACE | OR ROLLBACK]',
+  'SET',
+  // - delete:
+  'DELETE FROM',
   // other
   'ADD',
   'ALTER COLUMN',
   'ALTER TABLE',
   'CREATE TABLE',
   'DROP TABLE',
-  'DELETE',
-  'DELETE FROM',
-  'INSERT INTO',
   'SET SCHEMA',
-  'SET',
-  'UPDATE',
-  'VALUES',
 ]);
 
 const reservedSetOperations = expandPhrases(['UNION [ALL]', 'EXCEPT', 'INTERSECT']);
diff --git a/src/languages/trino/trino.formatter.ts b/src/languages/trino/trino.formatter.ts
index 8a3d0380..5a6c1f3b 100644
--- a/src/languages/trino/trino.formatter.ts
+++ b/src/languages/trino/trino.formatter.ts
@@ -19,6 +19,17 @@ const reservedCommands = expandPhrases([
   'LIMIT',
   'OFFSET',
   'FETCH {FIRST | NEXT}',
+  // Data manipulation
+  // - insert:
+  'INSERT INTO',
+  'VALUES',
+  // - update:
+  'UPDATE',
+  'SET',
+  // - delete:
+  'DELETE FROM',
+  // - truncate:
+  'TRUNCATE TABLE',
   // DDL
   'ALTER SCHEMA',
   'ALTER TABLE',
@@ -44,14 +55,6 @@ const reservedCommands = expandPhrases([
   'DROP MATERIALIZED VIEW',
   'DROP VIEW',
   'DROP ROLE',
-  'TRUNCATE TABLE',
-  // DML
-  'INSERT INTO',
-  'MERGE INTO',
-  'VALUES',
-  'UPDATE',
-  'SET',
-  'DELETE FROM',
   // Auxiliary
   'EXPLAIN',
   'ANALYZE',
diff --git a/src/languages/tsql/tsql.formatter.ts b/src/languages/tsql/tsql.formatter.ts
index 223e02dc..6990bac5 100644
--- a/src/languages/tsql/tsql.formatter.ts
+++ b/src/languages/tsql/tsql.formatter.ts
@@ -17,6 +17,22 @@ const reservedCommands = expandPhrases([
   'ORDER BY',
   'OFFSET',
   'FETCH {FIRST | NEXT}',
+  // Data manipulation
+  // - insert:
+  'INSERT [INTO]',
+  'VALUES',
+  // - update:
+  'UPDATE',
+  'SET',
+  'WHERE CURRENT OF',
+  // - delete:
+  'DELETE [FROM]',
+  // - truncate:
+  'TRUNCATE TABLE',
+  // - merge:
+  'MERGE [INTO]',
+  'WHEN [NOT] MATCHED [BY TARGET | BY SOURCE] [THEN]',
+  'UPDATE SET',
   // https://docs.microsoft.com/en-us/sql/t-sql/statements/statements?view=sql-server-ver15
   'ADD SENSITIVITY CLASSIFICATION',
   'ADD SIGNATURE',
@@ -66,8 +82,6 @@ const reservedCommands = expandPhrases([
   'DATEFORMAT',
   'DEADLOCK_PRIORITY',
   'DEFAULT',
-  'DELETE',
-  'DELETE FROM',
   'DENY',
   'DENY XML',
   'DISABLE TRIGGER',
@@ -97,12 +111,10 @@ const reservedCommands = expandPhrases([
   'IDENTITY_INSERT',
   'IMPLICIT_TRANSACTIONS',
   'INDEX',
-  'INSERT',
   'LANGUAGE',
   'LOCK_TIMEOUT',
   'LOGIN',
   'MASTER KEY',
-  'MERGE',
   'MESSAGE TYPE',
   'MOVE CONVERSATION',
   'NOCOUNT',
@@ -151,7 +163,6 @@ const reservedCommands = expandPhrases([
   'SERVER ROLE',
   'SERVICE',
   'SERVICE MASTER KEY',
-  'SET',
   'SETUSER',
   'SHOWPLAN_ALL',
   'SHOWPLAN_TEXT',
@@ -170,9 +181,7 @@ const reservedCommands = expandPhrases([
   'TEXTSIZE',
   'TRANSACTION ISOLATION LEVEL',
   'TRIGGER',
-  'TRUNCATE TABLE',
   'TYPE',
-  'UPDATE',
   'UPDATE STATISTICS',
   'USER',
   'VIEW',
@@ -184,9 +193,7 @@ const reservedCommands = expandPhrases([
   'ALTER COLUMN',
   'ALTER TABLE',
   'CREATE TABLE',
-  'INSERT INTO',
   'DROP TABLE',
-  'VALUES',
 ]);
 
 const reservedSetOperations = expandPhrases(['UNION [ALL]', 'EXCEPT', 'INTERSECT']);


Test patch:
diff --git a/test/behavesLikeMariaDbFormatter.ts b/test/behavesLikeMariaDbFormatter.ts
index 9d07fb54..1409c23b 100644
--- a/test/behavesLikeMariaDbFormatter.ts
+++ b/test/behavesLikeMariaDbFormatter.ts
@@ -13,6 +13,9 @@ import supportsComments from './features/comments';
 import supportsStrings from './features/strings';
 import supportsIdentifiers from './features/identifiers';
 import supportsParams from './options/param';
+import supportsInsertInto from './features/insertInto';
+import supportsUpdate from './features/update';
+import supportsTruncateTable from './features/truncateTable';
 
 /**
  * Shared tests for MySQL and MariaDB
@@ -27,6 +30,9 @@ export default function behavesLikeMariaDbFormatter(format: FormatFn) {
   supportsConstraints(format);
   supportsAlterTable(format);
   supportsDeleteFrom(format);
+  supportsInsertInto(format, { withoutInto: true });
+  supportsUpdate(format);
+  supportsTruncateTable(format, { withoutTable: true });
   supportsBetween(format);
   supportsParams(format, { positional: true });
 
@@ -98,4 +104,14 @@ export default function behavesLikeMariaDbFormatter(format: FormatFn) {
         t MODIFY col1 VARCHAR(50) CHARACTER SET greek
     `);
   });
+
+  it('supports REPLACE INTO syntax', () => {
+    expect(format(`REPLACE INTO tbl VALUES (1,'Leopard'),(2,'Dog');`)).toBe(dedent`
+      REPLACE INTO
+        tbl
+      VALUES
+        (1, 'Leopard'),
+        (2, 'Dog');
+    `);
+  });
 }
diff --git a/test/behavesLikeSqlFormatter.ts b/test/behavesLikeSqlFormatter.ts
index 8b1da8d0..0ffb0836 100644
--- a/test/behavesLikeSqlFormatter.ts
+++ b/test/behavesLikeSqlFormatter.ts
@@ -155,18 +155,6 @@ export default function behavesLikeSqlFormatter(format: FormatFn) {
     `);
   });
 
-  it('formats simple INSERT query', () => {
-    const result = format(
-      "INSERT INTO Customers (ID, MoneyBalance, Address, City) VALUES (12,-123.4, 'Skagen 2111','Stv');"
-    );
-    expect(result).toBe(dedent`
-      INSERT INTO
-        Customers (ID, MoneyBalance, Address, City)
-      VALUES
-        (12, -123.4, 'Skagen 2111', 'Stv');
-    `);
-  });
-
   it('formats open paren after comma', () => {
     const result = format('INSERT INTO TestIds (id) VALUES (4),(5), (6),(7),(9),(10),(11);');
     expect(result).toBe(dedent`
@@ -223,21 +211,6 @@ export default function behavesLikeSqlFormatter(format: FormatFn) {
     `);
   });
 
-  it('formats simple UPDATE query', () => {
-    const result = format(
-      "UPDATE Customers SET ContactName='Alfred Schmidt', City='Hamburg' WHERE CustomerName='Alfreds Futterkiste';"
-    );
-    expect(result).toBe(dedent`
-      UPDATE
-        Customers
-      SET
-        ContactName = 'Alfred Schmidt',
-        City = 'Hamburg'
-      WHERE
-        CustomerName = 'Alfreds Futterkiste';
-    `);
-  });
-
   it('formats incomplete query', () => {
     const result = format('SELECT count(');
     expect(result).toBe(dedent`
@@ -246,25 +219,6 @@ export default function behavesLikeSqlFormatter(format: FormatFn) {
     `);
   });
 
-  it('formats UPDATE query with AS part', () => {
-    const result = format(
-      'UPDATE customers SET total_orders = order_summary.total  FROM ( SELECT * FROM bank) AS order_summary'
-    );
-    expect(result).toBe(dedent`
-      UPDATE
-        customers
-      SET
-        total_orders = order_summary.total
-      FROM
-        (
-          SELECT
-            *
-          FROM
-            bank
-        ) AS order_summary
-    `);
-  });
-
   it('formats top-level and newline multi-word reserved words with inconsistent spacing', () => {
     const result = format('SELECT * FROM foo LEFT \t   \n JOIN mycol ORDER \n BY blah');
     expect(result).toBe(dedent`
diff --git a/test/bigquery.test.ts b/test/bigquery.test.ts
index d13b34e0..ba218eef 100644
--- a/test/bigquery.test.ts
+++ b/test/bigquery.test.ts
@@ -19,6 +19,10 @@ import supportsParams from './options/param';
 import supportsWindow from './features/window';
 import supportsSetOperations from './features/setOperations';
 import supportsLimiting from './features/limiting';
+import supportsInsertInto from './features/insertInto';
+import supportsUpdate from './features/update';
+import supportsTruncateTable from './features/truncateTable';
+import supportsMergeInto from './features/mergeInto';
 
 describe('BigQueryFormatter', () => {
   const language = 'bigquery';
@@ -28,7 +32,11 @@ describe('BigQueryFormatter', () => {
   supportsComments(format, { hashComments: true });
   supportsCreateTable(format);
   supportsDropTable(format);
-  supportsDeleteFrom(format);
+  supportsDeleteFrom(format, { withoutFrom: true });
+  supportsInsertInto(format, { withoutInto: true });
+  supportsUpdate(format);
+  supportsTruncateTable(format);
+  supportsMergeInto(format);
   supportsStrings(format, ['""', "''"]);
   supportsIdentifiers(format, ['``']);
   supportsArrayLiterals(format);
diff --git a/test/db2.test.ts b/test/db2.test.ts
index 456fd418..72aa83bc 100644
--- a/test/db2.test.ts
+++ b/test/db2.test.ts
@@ -19,6 +19,10 @@ import supportsIdentifiers from './features/identifiers';
 import supportsParams from './options/param';
 import supportsSetOperations from './features/setOperations';
 import supportsLimiting from './features/limiting';
+import supportsInsertInto from './features/insertInto';
+import supportsUpdate from './features/update';
+import supportsTruncateTable from './features/truncateTable';
+import supportsMergeInto from './features/mergeInto';
 
 describe('Db2Formatter', () => {
   const language = 'db2';
@@ -31,6 +35,10 @@ describe('Db2Formatter', () => {
   supportsConstraints(format);
   supportsAlterTable(format);
   supportsDeleteFrom(format);
+  supportsInsertInto(format);
+  supportsUpdate(format, { whereCurrentOf: true });
+  supportsTruncateTable(format, { withoutTable: true });
+  supportsMergeInto(format);
   supportsStrings(format, ["''", "X''", "U&''", "N''"]);
   supportsIdentifiers(format, [`""`]);
   supportsBetween(format);
@@ -86,4 +94,14 @@ describe('Db2Formatter', () => {
         :$zop
     `);
   });
+
+  it('supports WITH isolation level modifiers for UPDATE statement', () => {
+    expect(format('UPDATE foo SET x = 10 WITH CS')).toBe(dedent`
+      UPDATE
+        foo
+      SET
+        x = 10
+      WITH CS
+    `);
+  });
 });
diff --git a/test/features/deleteFrom.ts b/test/features/deleteFrom.ts
index e81a2e36..a63bfe93 100644
--- a/test/features/deleteFrom.ts
+++ b/test/features/deleteFrom.ts
@@ -2,8 +2,15 @@ import dedent from 'dedent-js';
 
 import { FormatFn } from 'src/sqlFormatter';
 
-export default function supportsDeleteFrom(format: FormatFn) {
-  it('formats simple DELETE FROM statement', () => {
+interface DeleteFromConfig {
+  withoutFrom?: boolean;
+}
+
+export default function supportsDeleteFrom(
+  format: FormatFn,
+  { withoutFrom }: DeleteFromConfig = {}
+) {
+  it('formats DELETE FROM statement', () => {
     const result = format("DELETE FROM Customers WHERE CustomerName='Alfred' AND Phone=5002132;");
     expect(result).toBe(dedent`
       DELETE FROM
@@ -13,4 +20,16 @@ export default function supportsDeleteFrom(format: FormatFn) {
         AND Phone = 5002132;
     `);
   });
+
+  if (withoutFrom) {
+    it('formats DELETE statement (without FROM)', () => {
+      const result = format("DELETE Customers WHERE CustomerName='Alfred';");
+      expect(result).toBe(dedent`
+        DELETE
+          Customers
+        WHERE
+          CustomerName = 'Alfred';
+      `);
+    });
+  }
 }
diff --git a/test/features/insertInto.ts b/test/features/insertInto.ts
new file mode 100644
index 00000000..11a8c610
--- /dev/null
+++ b/test/features/insertInto.ts
@@ -0,0 +1,38 @@
+import dedent from 'dedent-js';
+
+import { FormatFn } from 'src/sqlFormatter';
+
+interface InsertIntoConfig {
+  withoutInto?: boolean;
+}
+
+export default function supportsInsertInto(
+  format: FormatFn,
+  { withoutInto }: InsertIntoConfig = {}
+) {
+  it('formats simple INSERT INTO', () => {
+    const result = format(
+      "INSERT INTO Customers (ID, MoneyBalance, Address, City) VALUES (12,-123.4, 'Skagen 2111','Stv');"
+    );
+    expect(result).toBe(dedent`
+      INSERT INTO
+        Customers (ID, MoneyBalance, Address, City)
+      VALUES
+        (12, -123.4, 'Skagen 2111', 'Stv');
+    `);
+  });
+
+  if (withoutInto) {
+    it('formats INSERT without INTO', () => {
+      const result = format(
+        "INSERT Customers (ID, MoneyBalance, Address, City) VALUES (12,-123.4, 'Skagen 2111','Stv');"
+      );
+      expect(result).toBe(dedent`
+        INSERT
+          Customers (ID, MoneyBalance, Address, City)
+        VALUES
+          (12, -123.4, 'Skagen 2111', 'Stv');
+      `);
+    });
+  }
+}
diff --git a/test/features/mergeInto.ts b/test/features/mergeInto.ts
new file mode 100644
index 00000000..f214f351
--- /dev/null
+++ b/test/features/mergeInto.ts
@@ -0,0 +1,30 @@
+import dedent from 'dedent-js';
+
+import { FormatFn } from 'src/sqlFormatter';
+
+export default function supportsMergeInto(format: FormatFn) {
+  it('formats MERGE INTO', () => {
+    const result = format(
+      `MERGE INTO DetailedInventory AS t
+      USING Inventory AS i
+      ON t.product = i.product
+      WHEN MATCHED THEN
+        UPDATE SET quantity = t.quantity + i.quantity
+      WHEN NOT MATCHED THEN
+        INSERT (product, quantity) VALUES ('Horse saddle', 12);`
+    );
+    // The indentation here is not ideal, but at least it's not a complete crap
+    expect(result).toBe(dedent`
+      MERGE INTO
+        DetailedInventory AS t USING Inventory AS i ON t.product = i.product
+      WHEN MATCHED THEN
+      UPDATE SET
+        quantity = t.quantity + i.quantity
+      WHEN NOT MATCHED THEN
+      INSERT
+        (product, quantity)
+      VALUES
+        ('Horse saddle', 12);
+    `);
+  });
+}
diff --git a/test/features/truncateTable.ts b/test/features/truncateTable.ts
new file mode 100644
index 00000000..3346097c
--- /dev/null
+++ b/test/features/truncateTable.ts
@@ -0,0 +1,30 @@
+import dedent from 'dedent-js';
+
+import { FormatFn } from 'src/sqlFormatter';
+
+interface TruncateTableConfig {
+  withoutTable?: boolean;
+}
+
+export default function supportsTruncateTable(
+  format: FormatFn,
+  { withoutTable }: TruncateTableConfig = {}
+) {
+  it('formats TRUNCATE TABLE statement', () => {
+    const result = format('TRUNCATE TABLE Customers;');
+    expect(result).toBe(dedent`
+      TRUNCATE TABLE
+        Customers;
+    `);
+  });
+
+  if (withoutTable) {
+    it('formats TRUNCATE statement (without TABLE)', () => {
+      const result = format('TRUNCATE Customers;');
+      expect(result).toBe(dedent`
+        TRUNCATE
+          Customers;
+      `);
+    });
+  }
+}
diff --git a/test/features/update.ts b/test/features/update.ts
new file mode 100644
index 00000000..ac52893a
--- /dev/null
+++ b/test/features/update.ts
@@ -0,0 +1,57 @@
+import dedent from 'dedent-js';
+
+import { FormatFn } from 'src/sqlFormatter';
+
+interface UpdateConfig {
+  whereCurrentOf?: boolean;
+}
+
+export default function supportsUpdate(format: FormatFn, { whereCurrentOf }: UpdateConfig = {}) {
+  it('formats simple UPDATE statement', () => {
+    const result = format(
+      "UPDATE Customers SET ContactName='Alfred Schmidt', City='Hamburg' WHERE CustomerName='Alfreds Futterkiste';"
+    );
+    expect(result).toBe(dedent`
+      UPDATE
+        Customers
+      SET
+        ContactName = 'Alfred Schmidt',
+        City = 'Hamburg'
+      WHERE
+        CustomerName = 'Alfreds Futterkiste';
+    `);
+  });
+
+  it('formats UPDATE statement with AS part', () => {
+    const result = format(
+      'UPDATE customers SET total_orders = order_summary.total  FROM ( SELECT * FROM bank) AS order_summary'
+    );
+    expect(result).toBe(dedent`
+      UPDATE
+        customers
+      SET
+        total_orders = order_summary.total
+      FROM
+        (
+          SELECT
+            *
+          FROM
+            bank
+        ) AS order_summary
+    `);
+  });
+
+  if (whereCurrentOf) {
+    it('formats UPDATE statement with cursor position', () => {
+      const result = format("UPDATE Customers SET Name='John' WHERE CURRENT OF my_cursor;");
+      expect(result).toBe(dedent`
+        UPDATE
+          Customers
+        SET
+          Name = 'John'
+        WHERE CURRENT OF
+          my_cursor;
+      `);
+    });
+  }
+}
diff --git a/test/hive.test.ts b/test/hive.test.ts
index dc20e70d..67759703 100644
--- a/test/hive.test.ts
+++ b/test/hive.test.ts
@@ -19,6 +19,10 @@ import supportsIdentifiers from './features/identifiers';
 import supportsWindow from './features/window';
 import supportsSetOperations from './features/setOperations';
 import supportsLimiting from './features/limiting';
+import supportsUpdate from './features/update';
+import supportsDeleteFrom from './features/deleteFrom';
+import supportsTruncateTable from './features/truncateTable';
+import supportsMergeInto from './features/mergeInto';
 
 describe('HiveFormatter', () => {
   const language = 'hive';
@@ -29,6 +33,10 @@ describe('HiveFormatter', () => {
   supportsCreateTable(format);
   supportsDropTable(format);
   supportsAlterTable(format);
+  supportsUpdate(format);
+  supportsDeleteFrom(format);
+  supportsTruncateTable(format, { withoutTable: true });
+  supportsMergeInto(format);
   supportsStrings(format, ['""', "''"]);
   supportsIdentifiers(format, ['``']);
   supportsBetween(format);
@@ -84,4 +92,14 @@ describe('HiveFormatter', () => {
         count;
     `);
   });
+
+  it('formats INSERT INTO TABLE', () => {
+    const result = format("INSERT INTO TABLE Customers VALUES (12,-123.4, 'Skagen 2111','Stv');");
+    expect(result).toBe(dedent`
+      INSERT INTO TABLE
+        Customers
+      VALUES
+        (12, -123.4, 'Skagen 2111', 'Stv');
+    `);
+  });
 });
diff --git a/test/n1ql.test.ts b/test/n1ql.test.ts
index 5f635553..6e7709b0 100644
--- a/test/n1ql.test.ts
+++ b/test/n1ql.test.ts
@@ -19,6 +19,9 @@ import supportsParams from './options/param';
 import supportsWindow from './features/window';
 import supportsSetOperations from './features/setOperations';
 import supportsLimiting from './features/limiting';
+import supportsInsertInto from './features/insertInto';
+import supportsUpdate from './features/update';
+import supportsMergeInto from './features/mergeInto';
 
 describe('N1qlFormatter', () => {
   const language = 'n1ql';
@@ -47,6 +50,9 @@ describe('N1qlFormatter', () => {
   supportsParams(format, { positional: true, numbered: ['$'], named: ['$'] });
   supportsWindow(format);
   supportsLimiting(format, { limit: true, offset: true });
+  supportsInsertInto(format);
+  supportsUpdate(format);
+  supportsMergeInto(format);
 
   it('formats INSERT with {} object literal', () => {
     const result = format(
diff --git a/test/plsql.test.ts b/test/plsql.test.ts
index 49ec2c0c..a89ed3cc 100644
--- a/test/plsql.test.ts
+++ b/test/plsql.test.ts
@@ -21,6 +21,10 @@ import supportsIdentifiers from './features/identifiers';
 import supportsParams from './options/param';
 import supportsSetOperations from './features/setOperations';
 import supportsLimiting from './features/limiting';
+import supportsInsertInto from './features/insertInto';
+import supportsUpdate from './features/update';
+import supportsTruncateTable from './features/truncateTable';
+import supportsMergeInto from './features/mergeInto';
 
 describe('PlSqlFormatter', () => {
   const language = 'plsql';
@@ -34,6 +38,10 @@ describe('PlSqlFormatter', () => {
   supportsAlterTable(format);
   supportsAlterTableModify(format);
   supportsDeleteFrom(format);
+  supportsInsertInto(format);
+  supportsUpdate(format);
+  supportsTruncateTable(format);
+  supportsMergeInto(format);
   supportsStrings(format, ["''", "N''"]);
   supportsIdentifiers(format, [`""`]);
   supportsBetween(format);
@@ -95,18 +103,6 @@ describe('PlSqlFormatter', () => {
     expect(format("Q'Stest string S'S''")).toBe("Q'Stest string S' S ''");
   });
 
-  it('formats INSERT without INTO', () => {
-    const result = format(
-      "INSERT Customers (ID, MoneyBalance, Address, City) VALUES (12,-123.4, 'Skagen 2111','Stv');"
-    );
-    expect(result).toBe(dedent`
-      INSERT
-        Customers (ID, MoneyBalance, Address, City)
-      VALUES
-        (12, -123.4, 'Skagen 2111', 'Stv');
-    `);
-  });
-
   it('formats simple SELECT with national characters', () => {
     const result = format("SELECT N'value'");
     expect(result).toBe(dedent`
diff --git a/test/postgresql.test.ts b/test/postgresql.test.ts
index 68c4fa15..b67a11f0 100644
--- a/test/postgresql.test.ts
+++ b/test/postgresql.test.ts
@@ -22,6 +22,9 @@ import supportsArrayAndMapAccessors from './features/arrayAndMapAccessors';
 import supportsWindow from './features/window';
 import supportsSetOperations from './features/setOperations';
 import supportsLimiting from './features/limiting';
+import supportsInsertInto from './features/insertInto';
+import supportsUpdate from './features/update';
+import supportsTruncateTable from './features/truncateTable';
 
 describe('PostgreSqlFormatter', () => {
   const language = 'postgresql';
@@ -35,6 +38,9 @@ describe('PostgreSqlFormatter', () => {
   supportsArrayAndMapAccessors(format);
   supportsAlterTable(format);
   supportsDeleteFrom(format);
+  supportsInsertInto(format);
+  supportsUpdate(format, { whereCurrentOf: true });
+  supportsTruncateTable(format, { withoutTable: true });
   supportsStrings(format, ["''", "U&''", "X''"]);
   supportsIdentifiers(format, [`""`, 'U&""']);
   supportsBetween(format);
diff --git a/test/redshift.test.ts b/test/redshift.test.ts
index 37c7f4df..f92e7253 100644
--- a/test/redshift.test.ts
+++ b/test/redshift.test.ts
@@ -16,6 +16,9 @@ import supportsIdentifiers from './features/identifiers';
 import supportsParams from './options/param';
 import supportsSetOperations from './features/setOperations';
 import supportsLimiting from './features/limiting';
+import supportsInsertInto from './features/insertInto';
+import supportsUpdate from './features/update';
+import supportsTruncateTable from './features/truncateTable';
 
 describe('RedshiftFormatter', () => {
   const language = 'redshift';
@@ -26,7 +29,10 @@ describe('RedshiftFormatter', () => {
   supportsCreateTable(format);
   supportsDropTable(format);
   supportsAlterTable(format);
-  supportsDeleteFrom(format);
+  supportsDeleteFrom(format, { withoutFrom: true });
+  supportsInsertInto(format);
+  supportsUpdate(format);
+  supportsTruncateTable(format, { withoutTable: true });
   supportsStrings(format, ["''"]);
   supportsIdentifiers(format, [`""`]);
   supportsOperators(format, RedshiftFormatter.operators);
diff --git a/test/spark.test.ts b/test/spark.test.ts
index 5a828ad8..0898c469 100644
--- a/test/spark.test.ts
+++ b/test/spark.test.ts
@@ -16,6 +16,8 @@ import supportsComments from './features/comments';
 import supportsIdentifiers from './features/identifiers';
 import supportsSetOperations from './features/setOperations';
 import supportsLimiting from './features/limiting';
+import supportsInsertInto from './features/insertInto';
+import supportsTruncateTable from './features/truncateTable';
 
 describe('SparkFormatter', () => {
   const language = 'spark';
@@ -26,6 +28,8 @@ describe('SparkFormatter', () => {
   supportsCreateTable(format);
   supportsDropTable(format);
   supportsAlterTable(format);
+  supportsInsertInto(format, { withoutInto: true });
+  supportsTruncateTable(format);
   supportsStrings(format, ["''", "X''"]);
   supportsIdentifiers(format, ['``']);
   supportsBetween(format);
diff --git a/test/sql.test.ts b/test/sql.test.ts
index 9dbb0fa9..abce4330 100644
--- a/test/sql.test.ts
+++ b/test/sql.test.ts
@@ -20,6 +20,9 @@ import supportsParams from './options/param';
 import supportsWindow from './features/window';
 import supportsSetOperations from './features/setOperations';
 import supportsLimiting from './features/limiting';
+import supportsInsertInto from './features/insertInto';
+import supportsUpdate from './features/update';
+import supportsTruncateTable from './features/truncateTable';
 
 describe('SqlFormatter', () => {
   const language = 'sql';
@@ -32,6 +35,9 @@ describe('SqlFormatter', () => {
   supportsConstraints(format);
   supportsAlterTable(format);
   supportsDeleteFrom(format);
+  supportsInsertInto(format);
+  supportsUpdate(format, { whereCurrentOf: true });
+  supportsTruncateTable(format);
   supportsStrings(format, ["''", "X''"]);
   supportsIdentifiers(format, [`""`, '``']);
   supportsBetween(format);
diff --git a/test/sqlite.test.ts b/test/sqlite.test.ts
index 701a3a0d..621e411a 100644
--- a/test/sqlite.test.ts
+++ b/test/sqlite.test.ts
@@ -1,3 +1,4 @@
+import dedent from 'dedent-js';
 import { format as originalFormat, FormatFn } from 'src/sqlFormatter';
 import SqliteFormatter from 'src/languages/sqlite/sqlite.formatter';
 import behavesLikeSqlFormatter from './behavesLikeSqlFormatter';
@@ -18,6 +19,8 @@ import supportsParams from './options/param';
 import supportsWindow from './features/window';
 import supportsSetOperations from './features/setOperations';
 import supportsLimiting from './features/limiting';
+import supportsInsertInto from './features/insertInto';
+import supportsUpdate from './features/update';
 
 describe('SqliteFormatter', () => {
   const language = 'sqlite';
@@ -30,6 +33,8 @@ describe('SqliteFormatter', () => {
   supportsConstraints(format);
   supportsAlterTable(format);
   supportsDeleteFrom(format);
+  supportsInsertInto(format);
+  supportsUpdate(format);
   supportsStrings(format, ["''", "X''"]);
   supportsIdentifiers(format, [`""`, '``', '[]']);
   supportsBetween(format);
@@ -40,4 +45,14 @@ describe('SqliteFormatter', () => {
   supportsParams(format, { positional: true, numbered: ['?'], named: [':', '$', '@'] });
   supportsWindow(format);
   supportsLimiting(format, { limit: true, offset: true });
+
+  it('supports REPLACE INTO syntax', () => {
+    expect(format(`REPLACE INTO tbl VALUES (1,'Leopard'),(2,'Dog');`)).toBe(dedent`
+      REPLACE INTO
+        tbl
+      VALUES
+        (1, 'Leopard'),
+        (2, 'Dog');
+    `);
+  });
 });
diff --git a/test/trino.test.ts b/test/trino.test.ts
index b671f324..6f2917e0 100644
--- a/test/trino.test.ts
+++ b/test/trino.test.ts
@@ -19,6 +19,9 @@ import supportsParams from './options/param';
 import supportsSetOperations from './features/setOperations';
 import supportsWindow from './features/window';
 import supportsLimiting from './features/limiting';
+import supportsInsertInto from './features/insertInto';
+import supportsUpdate from './features/update';
+import supportsTruncateTable from './features/truncateTable';
 
 describe('TrinoFormatter', () => {
   const language = 'trino';
@@ -29,6 +32,9 @@ describe('TrinoFormatter', () => {
   supportsCreateTable(format);
   supportsDropTable(format);
   supportsDeleteFrom(format);
+  supportsInsertInto(format);
+  supportsUpdate(format);
+  supportsTruncateTable(format);
   supportsStrings(format, ["''", "X''", "U&''"]);
   supportsIdentifiers(format, ['""']);
   supportsBetween(format);
diff --git a/test/tsql.test.ts b/test/tsql.test.ts
index b9b94373..089de14d 100644
--- a/test/tsql.test.ts
+++ b/test/tsql.test.ts
@@ -19,6 +19,10 @@ import supportsParams from './options/param';
 import supportsWindow from './features/window';
 import supportsSetOperations from './features/setOperations';
 import supportsLimiting from './features/limiting';
+import supportsInsertInto from './features/insertInto';
+import supportsUpdate from './features/update';
+import supportsTruncateTable from './features/truncateTable';
+import supportsMergeInto from './features/mergeInto';
 
 describe('TSqlFormatter', () => {
   const language = 'tsql';
@@ -31,6 +35,10 @@ describe('TSqlFormatter', () => {
   supportsConstraints(format);
   supportsAlterTable(format);
   supportsDeleteFrom(format);
+  supportsInsertInto(format, { withoutInto: true });
+  supportsUpdate(format, { whereCurrentOf: true });
+  supportsTruncateTable(format);
+  supportsMergeInto(format);
   supportsStrings(format, ["N''", "''"]);
   supportsIdentifiers(format, [`""`, '[]']);
   supportsBetween(format);