Skip to content

CLI Reference

sqlquack convert

Convert Snowflake SQL into DuckDB SQL, or refuse it with a reason.

sqlquack convert prints the DuckDB SQL for Snowflake SQL, or refuses it. Every statement it prints has passed DuckDB’s own parse-and-bind check.

sqlquack convert [OPTIONS] [PATH]
sqlquack convert query.sql --schema schema.json --builtin-policy
echo "SELECT 1 AS total" | sqlquack convert --builtin-policy --json

PATH is a SQL file. Without one, or with -, convert reads standard input. The DuckDB SQL goes to standard output, laid out with each clause on its own line, select items one per line, and nested queries and long CASE expressions indented; short statements stay on one line. Progress, the known divergences and assumptions it relies on, and refusals go to standard error.

$ sqlquack convert revenue.sql --schema schema.json --builtin-policy
SELECT
"ORDERS"."CUSTOMER_ID" AS "CUSTOMER_ID",
CAST(sum("ORDERS"."TOTAL") AS DECIMAL(24,2)) AS "REVENUE"
FROM "ORDERS" AS "ORDERS"
WHERE ("ORDERS"."STATUS" = 'shipped')
GROUP BY "ORDERS"."CUSTOMER_ID"
sqlquack convert: done, converted under the built-in default

A refused statement prints its refusals instead, each as a coded diagnostic, and convert exits 1. Each refusal is one of these:

Code Why
SQ0002 No verified rule converts the construct yet.
SQ0003 A rule exists, but not for these operand types.
SQ0004 A relation or column name does not resolve in the schema.
SQ0005 DuckDB cannot express the construct’s Snowflake meaning.
SQ0006 Conversion exceeded its time or size budget.
SQ0007 The session parameters match no recorded profile.
SQ0008 The conversion needs a known divergence the policy refuses.
SQ0009 A select item has no alias, and SQLQuack has not verified the column name Snowflake gives it.

SQL that does not parse, or that Snowflake rejects, is refused with the same codes as check. A VALUES list of more than 1,000 rows is refused.

Option Meaning
--schema <file> The relations and functions the SQL reads. See Schema files.
--session NAME=VALUE A Snowflake session parameter of your session. Repeatable. See Sessions.
--overrides <path> User overrides: a FUNCTION() file, or a directory of them, each with replaces and dialect duckdb.
--verified-override NAME=SHA256 An override verified for the body with that hash, as convert --json reports.
--compact Print each statement on one line instead, in the JSON report too.
--format text|json, --json Print the report as text or JSON.

convert also takes the policy flags: --policy, --builtin-policy, --strict, --utc-session, --confirm-declared-offsets, --python-runtime and --loud-divergences-only. See Policy and sessions.

With --json, convert prints one object:

{
"converted": true,
"profile": "the built-in default",
"sql": "SELECT CAST(1 AS DECIMAL(1,0)) AS \"TOTAL\"",
"refusals": [],
"divergences": {},
"assumptions": [],
"divergence_failures": {},
"notes": [],
"python_functions": [],
"macros": [],
"overrides": []
}

sql is laid out as the text output prints it, or on one line with --compact. A refusal in refusals carries the same diagnostic fields.

Code Meaning
0 Converted.
1 Something was refused; the reasons are on standard error.
2 It could not run: bad arguments, an unreadable file, a missing --policy file or an invalid policy file, or input without SQL.