Published

Carbon SQL v0 — contrato de superficie

Connect any source, model it as an ontology, transform it, and operationalize it, analytics, automation and machine learning, under one governed, self-hostable roof. --- Most teams stitch the...

Carbon SQL v0 — contrato de superficie

⚠️ ESTE DOCUMENTO SE GENERA. No lo edites a mano.

Lo produce scripts/duckdb/carbon-sql-conformance.ts ejecutando cada sintaxis
contra el motor real
. La matriz anterior se escribía a mano, se midió contra un
shim de Postgres que se retiró en julio de 2026, y siguió publicada semanas
describiendo un motor que ya no existía. Por eso ésta se mide.

npx dotenv -e .env.local -- npx tsx scripts/duckdb/carbon-sql-conformance.ts
Medido2026-07-31
MotorDuckDB 1.5.4 · duck-server 0.1.2
Extensionesavro=f9d5902 · httpfs=c3f215a · iceberg=75726455 · icu=v1.5.4
Conformidad72/76 sondas

Qué es Carbon SQL

Un contrato de superficie declarado, versionado y medido — no un parser propio.

PiezaDe quién es
Gramática de querydel motor (DuckDB). La única fuente sintáctica que no puede divergir del ejecutor es el ejecutor
Gramática de catálogonuestra, cerrada (SHOW · DESCRIBE · ALTER TABLE … RENAME · CREATE/DROP VIEW)
Resolución de nombresde Index — no es parsing, es un pase de análisis contra el catálogo
Este contratonuestro: qué se acepta, con qué estrictez y con qué límites

Dialecto de registro: duckdb. No «SQL estándar» (no lo es) ni «paridad Databricks» (eso es una aspiración de superficie, no un contrato). Las sintaxis marcadas paridad Databricks se miden explícitamente porque son las que un usuario que viene de allí teclea sin pensar.

Alcance de esta medición

Cubre la gramática de query (lo que ejecuta el motor). No cubre la gramática de catálogo, que es nuestra y se especifica en M3, ni la resolución de nombres, que es de Index. Las escrituras sólo aparecen si el harness se corre con --verbos.


Núcleo relacional

SintaxisEstadoNota
SELECT … WHERE … GROUP BY … HAVING
ORDER BY · LIMIT · OFFSET
DISTINCT
INNER / LEFT / FULL OUTER JOIN
CROSS JOIN · LATERAL
UNION · INTERSECT · EXCEPT
WITH (CTE)
WITH RECURSIVE
Subconsulta escalar · IN · EXISTS
CASE WHEN · COALESCE · NULLIF

Funciones de ventana

SintaxisEstadoNota
ROW_NUMBER · RANK · DENSE_RANK
LAG · LEAD
PARTITION BY + agregado con ventana
Marcos ROWS BETWEEN / RANGE
NTILE · FIRST_VALUE · LAST_VALUE
QUALIFYfiltra sobre ventana sin subconsulta

Agregación

SintaxisEstadoNota
COUNT · SUM · AVG · MIN · MAX
COUNT(DISTINCT …)
APPROX_COUNT_DISTINCTparidad Databricks
MEDIAN · QUANTILE_CONT
ARRAY_AGG · STRING_AGG
Cláusula FILTER (WHERE …)
GROUPING SETS · ROLLUP · CUBE
PIVOT … USING (dinámico, sin IN)⚠️ puertalo bloquea NUESTRA puerta, no el motorwrite_blocked: el verbo 'PIVOT' no es de lectura; usa allow_writes=true para DML (camino gobernado, F4) · paridad Databricks · el motor lo tipa CREATE+SELECT (materializa los valores distintos): no es lectura pura
PIVOT … ON … IN (…) USING (estático)⚠️ puertalo bloquea NUESTRA puerta, no el motorwrite_blocked: el verbo 'PIVOT' no es de lectura; usa allow_writes=true para DML (camino gobernado, F4) · paridad Databricks · con los valores explícitos SÍ es una lectura
UNPIVOT⚠️ puertalo bloquea NUESTRA puerta, no el motorwrite_blocked: el verbo 'UNPIVOT' no es de lectura; usa allow_writes=true para DML (camino gobernado, F4)

Cadenas y regex

SintaxisEstadoNota
CONCAT · SUBSTRING · TRIM · UPPER
LIKE · ILIKE
REGEXP_MATCHES · REGEXP_EXTRACT · REGEXP_REPLACE
SPLIT_PART · STRING_SPLIT
~ (regex de PostgreSQL)
RLIKEno soportado — Parser: syntax error at or near "RLIKE" · paridad Databricks

Fecha y hora

SintaxisEstadoNota
DATE_TRUNC · EXTRACT
INTERVAL
DATE_DIFF
DATEDIFFparidad Databricks
DATE_ADDparidad Databricks
AT TIME ZONE
STRFTIME · STRPTIME

Semi-estructurado y colecciones

SintaxisEstadoNota
UNNEST
Listas y su indexado
STRUCT y acceso por punto
MAP
JSON -> · ->>
json_extract_string
Comprensión de listasazúcar moderno de DuckDB

Azúcar moderno (DuckDB)

SintaxisEstadoNota
SELECT * EXCLUDE (…)proyectar sin listar 20 columnas
SELECT * REPLACE (…)
GROUP BY ALL
ORDER BY ALL
SELECT posicional en GROUP BY
Sintaxis FROM primero
COLUMNS(…)

Estrictez (el contrato)

SintaxisEstadoNota
Desbordamiento de entero✅ rechazalanza — ANSI
Cast inválido 'abc'::INTEGER✅ rechazalanza — ANSI
Cast estrechante 300::TINYINT✅ rechazalanza — ANSI
Fecha imposible '2026-02-30'✅ rechazalanza — ANSI
Subconsulta escalar con varias filas✅ rechazaerror, no fila al azar
TRY_CASTdevuelve NULL — la vía de escape explícita
División por cero⚠️ divergencia publicada: devuelve Infinity, no lanza
No-finitos en el sobre JSONse serializan como string ("Infinity", "NaN")

Lo que el motor contesta gratis

SintaxisEstadoNota
DESCRIBE <tabla>columnas y tipos, forma Databricks
SHOW ALL TABLES⚠️ devuelve identidades FÍSICAS (ds_<uuid>)
information_schema.tables / .columns⚠️ ídem: físicas, sin tenencia
iceberg_snapshots(<tabla>)historia de snapshots — sustituye DESCRIBE HISTORY
iceberg_metadata(<tabla>)conteo sin escanear datos
EXPLAIN
EXPLAIN ANALYZE
SUMMARIZEperfilado de columnas en un gesto

Escritura (verbos)

SintaxisEstadoNota
CREATE TABLE … AS SELECT
INSERT INTO
UPDATE
DELETE
MERGE INTO
ALTER TABLE … ADD COLUMN
ALTER TABLE … RENAME TO

Límites publicados

Estrechar la superficie es legítimo — Cloudflare documenta los de R2 SQL — siempre que esté declarado. Los nuestros:

  • División por cero devuelve Infinity/NULL en vez de lanzar. Es la única divergencia ANSI conocida y no tiene palanca: ieee_floating_point_ops=false la pasa de Infinity a NULL, pero sigue sin lanzar. Se documenta, no se simula.
  • No-finitos (Infinity, NaN) viajan como string en el sobre JSON, porque JSON no los representa (RFC 8259). El camino Arrow los lleva nativos.
  • Funciones de tabla limitadas a generate_series · range · unnest · repeat (la puerta las restringe: el Warehouse es la única fuente).
  • Verbos de escritura acotados hoy a DELETE y MERGE — restricción pendiente de re-medir (M6): el código dice que su motivo original ya no existe.
  • SHOW/information_schema del motor devuelven identidades físicas (ds_<uuid>) y no conocen tenencia ni tier. Por eso los contesta Index (M5).

Estrictez

Los defaults de DuckDB son el contrato, y se declaran explícitamente en build_engine para que un default ajeno no pueda moverlo: old_implicit_casting=false · ieee_floating_point_ops=true · scalar_subquery_error_on_multiple_rows=true · errors_as_json=true.

DuckDB ya es ANSI-estricto exactamente donde Spark 4 rompió compatibilidad: desbordamiento, casts inválidos, casts estrechantes y fechas imposibles lanzan, no devuelven null. TRY_CAST es la vía de escape explícita.


Generado por scripts/duckdb/carbon-sql-conformance.ts. Contrato: warehouse-sql-dialect-spec.md · plan: carbon-sql-milestones.md.