Skip to content

SQL: statements wrapped in BEGIN; … COMMIT; extract 0 nodes — 59 CREATE TABLEs silently absent across 8 migrations #2953

Description

@brogollack

SQL: no nodes are extracted from statements wrapped in BEGIN; … COMMIT;

graphifyy 0.9.33 · tree-sitter-sql 0.3.11 · tree-sitter 0.25.2 · Python 3.13.14 · macOS 27 (arm64)

Related to #1745 (the "install graphifyy[sql]" warning). Installing the extra removes the
warning, but SQL files still contribute almost nothing — for a different reason.

Summary

CREATE TABLE statements are extracted correctly on their own, but the same statements
produce no nodes when the file wraps them in a transaction block
. Since wrapping a
migration in BEGIN; … COMMIT; is the normal way to make it atomic, this silently hides
entire schemas.

In our repo it hides 59 CREATE TABLE statements across 8 migration files — every table
the application has. The graph looked healthy (the files themselves appear as nodes), so the
loss is invisible unless you count.

Minimal reproduction

Two files, identical except for the transaction wrapper.

sin_transaccion.sql:

CREATE TABLE alfa (id integer PRIMARY KEY);
CREATE TABLE beta (id integer PRIMARY KEY);

con_transaccion.sql:

BEGIN;

CREATE TABLE gamma (id integer PRIMARY KEY);
CREATE TABLE delta (id integer PRIMARY KEY);

COMMIT;

Then:

graphify .

Expected: four table nodes — alfa, beta, gamma, delta.

Actual: two. Only the ones outside the transaction.

  sin_transaccion.sql    'alfa'
  sin_transaccion.sql    'beta'

con_transaccion.sql appears as a file node, with nothing inside it. No warning, no error.

What is not the cause

I bisected before filing. Each of these works fine on its own — a table node is produced
with correct source_file and source_location:

Construct Extracted?
plain CREATE TABLE yes
CREATE TABLE IF NOT EXISTS yes
leading comment block (incl. non-ASCII) yes
inline CHECK (col IN (…)) yes
ALTER TABLE … ENABLE ROW LEVEL SECURITY between two CREATE TABLEs yes, both
DO $$ … END $$; before a CREATE TABLE yes
BEGIN; … COMMIT; wrapper no

So the dialect features aren't the problem; only the transaction block is.

Secondary oddity: nodes with empty attribution

Running against our real migrations (all of them BEGIN/COMMIT-wrapped), three table nodes
do survive — avisos, sv_casos, sv_motivos_alias — but with empty source_file and
source_location
:

label='avisos'            source_file='' source_location='' _origin='ast'
label='sv_motivos_alias'  source_file='' source_location='' _origin='ast'
label='sv_casos'          source_file='' source_location='' _origin='ast'

Nodes that survive the same file keep their attribution (_motivos_nuevos from a
CREATE TEMP TABLE … AS came through with loc=L68 intact), so this looks like partial
recovery after a failed parse rather than a separate issue. Mentioning it in case it points
at the same code path.

Why it matters

The failure is silent. graphify update . reports a healthy rebuild, the .sql files show up
as nodes, and the #1745 warning is gone — so it reads as "SQL support is working". A query
for a table name still returns hits, but they come from the Python that mentions the table,
never from the DDL that defines it. The schema is simply absent from the graph, and nothing
says so.

A count of extracted CREATE TABLE vs. CREATE TABLE occurrences would have caught this, if
that is a cheap check to add.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions