Code & Engineering

SQL Dump to SQLite: MySQL and Postgres Rows, Unchanged

Converts a MySQL or PostgreSQL dump (CREATE TABLE, INSERT rows, COPY blocks) into SQL that SQLite, Cloudflare D1 and Turso execute, with every value in every row unchanged, and answers with the SQL only, no code fence. Decodes string escapes the right way for each source (MySQL backslash sequences, Postgres E strings and dollar quotes, COPY escapes with its null marker), keeps strings that look like numbers as strings, turns booleans into 0 and 1, writes hex values as real blobs, keeps dates as the text the dump has, maps enum to text with a CHECK, maps auto-increment keys, drops what SQLite does not have (engine, charset, session settings, locks, begin and commit, schema prefixes), orders tables and rows so foreign keys hold, and splits long inserts. A type with no exact equivalent, a COPY row with the wrong number of fields and a paste cut in the middle get a one-line CANNOT CONVERT answer naming the place, instead of a guess. Use when asked to move a MySQL or Postgres dump into SQLite, D1 or Turso, to load a dump file, or to fix a dump that fails there.

SQL Dump to SQLite: MySQL and Postgres Rows, Unchanged is a tested SKILL.md that converts a MySQL or PostgreSQL dump (CREATE TABLE, INSERT rows, COPY blocks) into SQL that SQLite, Cloudflare D1 and Turso execute, with every value in every row unchanged, and answers with the SQL only, no code fence; an agent buys it once for $0.03 over x402.

Tested 2026-10-08No code, no hidden instructionsv1.0.0 · 12.4 KB · perpetual license

Not for

Designing a new schema, tuning queries, running the load or reading your live database. It converts the dump you paste, so a table you did not paste is unknown. Spatial types, arrays, ranges, a NUL character in a string, a COPY row with the wrong number of fields and a paste cut in the middle get a CANNOT CONVERT line instead of a guess. Stored procedures, views and triggers are not converted.

Tested, honestly

Tested 2026-10-08 with a strong and a weak model.

With and without the skill

Results with and without the skill, for Sonnet and Haiku
SonnetHaiku
withwithoutwithwithout
Dumps converted or refused right (24 dumps)24/2422/2423/2421/24

Same request on both sides, a fence removed first. Read by hand, Sonnet without the skill already carried over backticks, escapes, enums, booleans, numerics and COPY blocks with every value intact. It missed two: it kept a BEGIN in a file meant for D1, which D1 refuses, and it turned a spatial POINT column into plain text without a word instead of refusing. Haiku without the skill missed three: escaped percent and underscore, the key and BEGIN, and an exact numeric.

Same cases and the same checks with and without the skill. The cases are ours, written around what the skill is for; with a handful of cases, a difference of one or two is within noise.

SonnetStrong model, claude-sonnet-5-5
Right on all 24 dumps, read by hand: every converted dump ran in SQLite and returned the same values as the source, with MySQL backticks, AUTO_INCREMENT keys, unsigned and enum columns, escaped quotes, percent and underscore in strings, Postgres booleans written as t and f, exact numerics, sequences, COPY blocks and timestamps carried over; no BEGIN or COMMIT left in a file meant for D1; and a refusal where SQLite cannot hold the column, such as a spatial POINT, instead of a silent change of type.
HaikuWeak model, claude-haiku-5-5
Right on 23 of 24 dumps, read by hand, but it missed one: in a Postgres dump it turned one boolean written as t into 0 instead of 1.

Full test summary

Example

Our own test text, before and after the skill ran. Excerpts only.

English · claude-sonnet-5-5

Before

-- MySQL dump 10.13 Distrib 8.0.36, for Linux (x86_64) /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; /*!40101 SET NAMES utf8mb4 */; CREATE TABLE `people` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(60) NOT NULL, `note` text, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;…

After

CREATE TABLE "people" ( "id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "name" TEXT NOT NULL, "note" TEXT ); INSERT INTO "people" ("id", "name", "note") VALUES (1, 'O''Brien', 'He said "hi"'), (2, 'Ann', 'line one' || char(10) || 'line two'), (3, 'Bo', 'C:\temp\new'), (4, 'Cy', 'tab' || char(9) || 'here');

Bulgarian · claude-sonnet-5-5

Before

-- Дъмп на таблицата с клиенти CREATE TABLE `clients` (`id` int NOT NULL, `name` varchar(80) NOT NULL, `city` varchar(40) DEFAULT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; INSERT INTO `clients` VALUES (1,'Иван Петров','гр. София'),(2,'Мария \'Мими\' Георгиева','Пловдив'),(3,'Стоян Димитров',NULL);

After

CREATE TABLE clients ( id INTEGER NOT NULL PRIMARY KEY, name TEXT NOT NULL, city TEXT DEFAULT NULL ); INSERT INTO clients (id, name, city) VALUES (1, 'Иван Петров', 'гр. София'), (2, 'Мария ''Мими'' Георгиева', 'Пловдив'), (3, 'Стоян Димитров', NULL);

What is in the file

  • The answer
  • What goes, what stays
  • Strings
  • Types
  • Keys and order
  • COPY blocks (Postgres)
  • NULL and empty
  • When to refuse
  • Work in this order
  • Short examples

Languages

Any language. Tried in: English, Bulgarian.

License

Perpetual, non-exclusive; use and modify for yourself incl. paid work; no resale or republishing. Holder: Georgi Kalchev, aiskills402.com. Full terms.

Versions

Current version 1.0.0, updated 2026-10-08. Whoever bought an earlier version gets new ones free through the same re-download token.

  1. v1.0.0 · 2026-10-08

    First release (draft, not yet measured): converts a MySQL or PostgreSQL dump piece (CREATE TABLE, INSERT rows, COPY blocks) into SQL that SQLite, Cloudflare D1 and Turso execute, SQL only, every value unchanged, with a one-line CANNOT CONVERT refusal for a type with no exact equivalent, a COPY row with the wrong number of fields and a paste that stops in the middle.

    Facts re-checked on 2026-10-08 (free, read-only, no account needed): - SQLite: a hexadecimal literal 0x... is an integer, a blob is X'...' (SQLite expression documentation, fetched); node:sqlite 3.53.0 locally: a quoted 20-digit decimal stored in a NUMERIC column becomes a floating point number (measured by the case control), so only the TEXT column type protects the digits. - PostgreSQL: COPY text format (null marker backslash-N, backslash sequences, end-of-data line, error on a wrong field count), escape strings and dollar quoting (documentation, fetched). - Cloudflare D1 limits: 100 KB per SQL statement, 100 bound parameters (limits page, fetched). - MariaDB string literal page fetched (backslash escape table, unknown escapes ignored); the MySQL manual page returned 403 to the fetch, so the MySQL rules rest on that page plus the MySQL manual from memory. Backslash-percent and backslash-underscore keeping their backslash is the MySQL rule and is NOT re-checked here. - BEGIN refused by D1 with code 7500 and foreign_keys = OFF being a no-op in a D1 migration are owner-measured on 2026-10-08 (d1-migrations note), not re-checked.

    Tests: 24 cases (15 traps, 3 refusals, 6 controls), `test/control.mjs` makes zero model calls. Model results are not in yet; price and the "Sonnet got N of M" sentence in the listing are written after the baseline.

FAQ

Backticks, booleans, escapes: what does a plain conversion break?

The quiet ones. MySQL writes a quote inside a string as backslash and quote, which SQLite reads as a string that ends early. A MySQL backslash before a percent sign keeps the backslash, a plain Postgres string never decodes its backslashes, a COPY field that is only backslash and N is NULL while an empty field is an empty string, a hex literal written 0x is an integer in SQLite and not bytes, and a code like 007 must stay text. It also puts parent tables before child tables, because D1 checks foreign keys while the file runs and a dump lists tables alphabetically.

What happens when the dump has something SQLite cannot hold?

What comes back is one short line opening with CANNOT CONVERT and names the table and the column or row, for example a spatial point column or a COPY row that has two fields where the list names three. A table loaded halfway is worse than none, so the skill does not convert the fine part and skip the rest. Send the dump again without that column and the SQL follows. A value that is only unusual, such as a zero date or an empty string, is not a reason to refuse: it is carried over as written.

Does it change any value?

Only one kind, and it says so in a comment: boolean values become 0 and 1, because a text f is not false in SQLite. Dates stay the text the dump has, numbers stay as written, and a number with more digits than a floating point value can carry goes into a TEXT column quoted, so no digit is rounded.

Does it help Claude Sonnet?

Two points that bite on D1 make the difference. Twenty-four dumps were converted by both Claude models, loaded and unloaded, and each answer was executed in SQLite. On its own Sonnet kept every value, but left a BEGIN in a file meant for D1, which D1 refuses, and quietly turned a POINT column into text instead of saying it cannot be carried over: 22 right, 24 with the file. Haiku went from 21 to 23. You get plain SQL, ready for sqlite3 or wrangler d1 execute.

Share

Read this page as Markdown: /skills/sql-dump-to-sqlite.md.

  • D1 Migration Writer: SQLite Migrations That Apply

    Code & Engineering

    SKILL.md · v1.0.1 · 9.8 KB

    Writes a SQL migration for Cloudflare D1 or SQLite from the current schema and the change wanted, so it applies on the first try and leaves the rows already in the database right. Knows what D1 refuses or breaks on, measured on a real D1 database - BEGIN and COMMIT in the file, foreign keys that cannot be switched off (a rebuild defers them, keeps the table name, and never closes with defer_foreign_keys = false, which on D1 silently skips the check), NOT NULL columns without a default, REFERENCES columns with a default, indexed columns dropped before their index. Backfills a new status or marker column so old rows are not picked up as pending work, fills a new counter from the existing rows, orders index columns for the query that needs them, and keeps upserts working against a partial unique index. Use when asked to write, check or fix a D1, SQLite or Turso migration, add or change a column, add an index, make a column unique or required, or rebuild a table.

    $0.07once

    • x402
    • USDC
    • Base
    Get skill

    Tested with Sonnet and Haiku, 8 Oct 2026

  • SQL Query Optimizer for D1, SQLite and Turso

    Code & Engineering

    SKILL.md · v1.0.2 · 9.8 KB

    Reviews SQL queries, schemas and migrations for SQLite, Cloudflare D1 and Turso, where the bill and the speed follow the rows a query READS, not the rows it returns. Finds full scans hidden behind LIMIT, aggregates over growing tables, index column gaps, NOT IN, OR, functions and LIKE patterns that switch an index off, OFFSET pagination, N+1 loops, the D1 limit of 100 bound parameters, tables that never shrink and new flag columns that turn the whole history into pending work; ranks them by cost and gives the index or rewrite that fixes each. Use when asked to optimize a SQL query, review a database schema or a migration, find a slow query, or cut rows read on D1, SQLite or Turso.

    $0.05once

    • x402
    • USDC
    • Base
    Get skill

    Tested with Sonnet and Haiku, 3 Oct 2026

  • CSV Repair: Fix the Form, Keep Every Cell

    Data & Analysis

    SKILL.md · v1.0.0 · 8.3 KB

    Repairs broken or messy CSV so a standard parser reads it, without changing the text of a single cell, and answers with the CSV only, no code fence. Fixes quotes that do not close, a quote inside an unquoted cell, cells that hold the delimiter or a line break, rows shorter than the header, a Markdown table, and chat text or a fence around the data. Numbers such as 1,250, 007 and 1.10, dates, spaces inside cells and values that look like formulas stay exactly as written. Semicolon and tab files keep their delimiter. A row longer than the header, a row that could be read two ways, an unbalanced quote that no reading closes, an HTML page and prose with no table get a fixed one-line CANNOT REPAIR answer instead of a guess that moves data between columns. Use when an export, an API or another model returned CSV that does not parse, or when asked to fix, clean up, close or convert a table to valid CSV.

    $0.05once

    • x402
    • USDC
    • Base
    Get skill

    Tested with Sonnet and Haiku, 8 Oct 2026