Known Limitations
sql-splitter is a streaming statement splitter, not a full SQL parser. It recognizes six statement types — CREATE TABLE, INSERT, CREATE INDEX, ALTER TABLE, DROP TABLE, and PostgreSQL COPY — and attributes each to a table. Everything else (views, triggers, procedures, grants, session commands) passes through as unknown and is skipped by split, since it cannot be attributed to a table.
This page lists what does not work, so you can check your dump against it before relying on the output.
All dialects
Section titled “All dialects”- Statements without a table are dropped by
split.CREATE VIEW,CREATE TRIGGER,CREATE PROCEDURE/FUNCTION,GRANT/REVOKE,TRUNCATE,SET, andUSEare not written to any output file. Runvalidateor compare statement counts if your dump relies on them. - Schema qualifiers are discarded. Table attribution keys on the bare table name:
sales.ordersandhr.ordersboth land inorders.sql. Multi-schema dumps merge colliding names into one file. - A
;inside a backtick-quoted identifier or inside a/* */block comment splits the statement early. Quoted strings are handled correctly; backtick identifiers and mid-statement block comments are not. - A leading UTF-8 BOM can make the first statement unrecognized. Strip it first (
sed -i '1s/^\xEF\xBB\xBF//' dump.sql). - No character-set transcoding. Input bytes pass through verbatim; latin1 dumps are not converted to UTF-8.
validateemits anENCODINGwarning for statements containing invalid UTF-8. - Compressed input (
.gz,.bz2,.xz,.zst) requires thecompressionCargo feature (on by default in released binaries).
MySQL / MariaDB
Section titled “MySQL / MariaDB”DELIMITERis not supported. Dumps containing stored procedures, functions, or triggers wrapped inDELIMITER $$ ... $$are split at every internal;, producing broken fragments thatsplitthen drops. Dump with--skip-triggersand without--routines, or handle routine definitions separately.- Conditional comments (
/*!40101 SET ... */;) are tolerated as leading comments; the wrapped statement is still detected. - Multi-database dumps using
USE db;are not namespaced — same-named tables from different databases collide into one file.
PostgreSQL
Section titled “PostgreSQL”- Plain-text format only.
pg_dump -Fc(custom),-Fd(directory), and-Ft(tar) are binary formats and will not parse. Usepg_dump -Fp, or convert an existing archive withpg_restore -f dump.sql archive.dump. COPYdata must be text format: tab-separated with\Nfor NULL (pg_dump’s default).COPY ... WITH (FORMAT csv)andWITH BINARYare not supported.- Dollar-quoted bodies (
$$ ... $$,$tag$ ... $tag$) are handled — function bodies with internal;split correctly. CREATE FUNCTION/TYPE/DOMAIN/SEQUENCE/EXTENSION,COMMENT ON,GRANT, andALTER ... OWNER TOcarry no table and are dropped bysplit(and skipped with a warning byconvert).
SQLite
Section titled “SQLite”PRAGMA,BEGIN TRANSACTION, andCOMMITare dropped bysplit— re-add them when re-importing (sql-splitter merge --transactionrestores a transaction wrapper).CREATE VIEWandCREATE TRIGGERare dropped bysplit.
GOmust be alone on its own line (optionallyGO <count>). An inlineGOor one followed by a comment does not separate batches.- Both
GOand;terminate statements, so multi-statement batches (procedure bodies,BEGIN ... ENDblocks with internal semicolons) are split apart. CREATE PROCEDURE/FUNCTION/TRIGGER/VIEW,MERGE, andEXECare dropped bysplit.
Dialect auto-detection
Section titled “Dialect auto-detection”Detection reads the first 8 KB of the file and scores dialect markers (pg_dump headers, backticks, GO lines, IDENTITY(, square brackets, …). The highest score wins; ties default to MySQL.
It can guess wrong when:
- Marker text appears inside data or comments in the first 8 KB — matching is substring-based, so a literal
pg_dumporSQLitein a value counts. - A MySQL or PostgreSQL dump contains
[...]orN'...'early in the file — MSSQL markers are weighted heavily. - A long license or comment banner pushes real markers past the first 8 KB.
Detection confidence is advisory: commands proceed even on a low-confidence guess. Pass --dialect explicitly whenever you know the source — a wrong guess silently produces wrong splits (for example, unrecognized COPY blocks).
Conversion (convert)
Section titled “Conversion (convert)”Conversion is string-based rewriting, not AST transformation. It is deliberately lossy for constructs the target dialect lacks; every drop or rewrite is reported as a warning (deduplicated per feature, capped at 100).
- Skipped: session commands (
SET NAMES,SET ANSI_NULLS,LOCK TABLES,PRAGMA, …), and PostgreSQL-only DDL (CREATE FUNCTION/TYPE/DOMAIN/SEQUENCE/EXTENSION/TRIGGER,COMMENT ON,GRANT) — each with a warning. - Rewritten lossily: MySQL
ENUM(...)andSET(...)becomeVARCHAR(255)/TEXT(constraint semantics lost);UNSIGNEDandZEROFILLare removed; inlineCOMMENTclauses are stripped for PostgreSQL targets. - Warned but left as-is: PostgreSQL array types (
integer[]) andINHERITS— no equivalent is generated. - Not detectable: SQLite auto-increment (
INTEGER PRIMARY KEY) passes through unchanged when converting from SQLite; MSSQLTIMESTAMP(rowversion) is only converted when written as[TIMESTAMP]. COPYblocks are converted to multi-rowINSERTs (1000 rows per statement) for non-PostgreSQL targets.
Use --strict to fail on the first unsupported construct instead of collecting warnings. See Type Mappings for the full type conversion matrix.
Practical guidance
Section titled “Practical guidance”- Dumps that are schema + data only (the common
mysqldump/pg_dump -Fpcase, no routines) split and convert reliably — this is the designed-for path. - Always spot-check with
sql-splitter validate "output/*.sql" --strictafter splitting or converting a dump that contains anything beyond tables, indexes, and rows. - If in doubt, run with
--dry-runfirst and compare the reported table list against your expectations.