The defect
extract_sql emits no node for T-SQL stored procedures or functions. Tables and views from the same files extract fine, so the gap is invisible unless you count: on a real 391-file SQL Server DACPAC corpus (staging/model/transform layers, [Schema].[Object] naming throughout), 0 of 26 procedures produced a node, no warning, exit 0.
Two independent defects stack:
- The grammar cannot parse the T-SQL routine shape.
CREATE PROCEDURE ... AS BEGIN ... END has no create_procedure production in tree-sitter-sql (the AS BEGIN body idiom never parses structurally), so the ERROR-node regex recovery in graphify/extractors/sql.py is these objects' only path into the graph.
- The recovery regex does not speak T-SQL. It accepts only bare or double-quoted names — no bracket-delimited identifiers (
CREATE PROCEDURE [dbo].[usp_Load]), no CREATE OR ALTER (T-SQL has no OR REPLACE), no PROC shorthand. On a corpus where every routine is bracket-named, recovery recovers nothing.
A third, smaller defect surfaces once you look: the two recovery sites (the walk-time ERROR-node scan and the whole-file has_error fallback) carry two copies of the regex that have drifted, so a mixed-delimiter name (CREATE PROCEDURE dbo.[usp_Mixed]) mints a phantom dbo() node from the second site while the first captures dbo.[usp_Mixed].
Reproduce
graphifyy 0.9.51 (current v8), tree-sitter-sql installed.
-- routines.sql
CREATE PROCEDURE [dbo].[usp_Load]
AS
BEGIN
SELECT 1;
END
GO
CREATE OR ALTER PROC [dbo].[usp_Refresh] AS BEGIN SELECT 2; END
from pathlib import Path
from graphify.extractors.sql import extract_sql
sorted(n["label"] for n in extract_sql(Path("routines.sql"))["nodes"])
# v8: ['routines.sql'] -- no routine nodes
# expected: ['[dbo].[usp_Load]()', '[dbo].[usp_Refresh]()', 'routines.sql']
Expected
usp_Load() and usp_Refresh() as nodes, recovered through the same ERROR-node path that already recovers PL/pgSQL routines (#2180).
Adjacent, not addressed here
A bracket-named CREATE FUNCTION [dbo].[fn_Total]() RETURNS INT AS BEGIN RETURN 1; END does parse structurally, but its label comes out as dbo].[fn_Total( — the outer delimiters are stripped as if the whole [dbo].[fn_Total] were one bracketed token. That is a separate defect in the structural create_function path; noting it so it is not mistaken for a recovery gap.
Proposed fix
A PR is ready: one shared module-level recovery pattern used by both sites (fixes the drift/phantom), bracket-delimited identifiers including the ]] escape, CREATE OR ALTER, PROC, a \b before CREATE, and a comment/string-masked whole-file scan so commented-out or dynamic-SQL DDL cannot fabricate routines when an unrelated parse error arms recovery. All changes are in graphify/extractors/sql.py; tests in tests/test_multilang.py.
The defect
extract_sqlemits no node for T-SQL stored procedures or functions. Tables and views from the same files extract fine, so the gap is invisible unless you count: on a real 391-file SQL Server DACPAC corpus (staging/model/transform layers,[Schema].[Object]naming throughout), 0 of 26 procedures produced a node, no warning, exit 0.Two independent defects stack:
CREATE PROCEDURE ... AS BEGIN ... ENDhas nocreate_procedureproduction in tree-sitter-sql (theAS BEGINbody idiom never parses structurally), so the ERROR-node regex recovery ingraphify/extractors/sql.pyis these objects' only path into the graph.CREATE PROCEDURE [dbo].[usp_Load]), noCREATE OR ALTER(T-SQL has noOR REPLACE), noPROCshorthand. On a corpus where every routine is bracket-named, recovery recovers nothing.A third, smaller defect surfaces once you look: the two recovery sites (the walk-time ERROR-node scan and the whole-file
has_errorfallback) carry two copies of the regex that have drifted, so a mixed-delimiter name (CREATE PROCEDURE dbo.[usp_Mixed]) mints a phantomdbo()node from the second site while the first capturesdbo.[usp_Mixed].Reproduce
graphifyy 0.9.51 (current
v8),tree-sitter-sqlinstalled.Expected
usp_Load()andusp_Refresh()as nodes, recovered through the same ERROR-node path that already recovers PL/pgSQL routines (#2180).Adjacent, not addressed here
A bracket-named
CREATE FUNCTION [dbo].[fn_Total]() RETURNS INT AS BEGIN RETURN 1; ENDdoes parse structurally, but its label comes out asdbo].[fn_Total(— the outer delimiters are stripped as if the whole[dbo].[fn_Total]were one bracketed token. That is a separate defect in the structuralcreate_functionpath; noting it so it is not mistaken for a recovery gap.Proposed fix
A PR is ready: one shared module-level recovery pattern used by both sites (fixes the drift/phantom), bracket-delimited identifiers including the
]]escape,CREATE OR ALTER,PROC, a\bbeforeCREATE, and a comment/string-masked whole-file scan so commented-out or dynamic-SQL DDL cannot fabricate routines when an unrelated parse error arms recovery. All changes are ingraphify/extractors/sql.py; tests intests/test_multilang.py.