You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
SQL: CREATE PROCEDURE/FUNCTION/TRIGGER symbols lack body ranges — callers/callees/impact return zero for every SQL symbol, yet graph_supported capability flag still reports true #429
SQL is listed in ReferenceExtractor.SupportedLanguages and every graph-capability surface (inspect --json, MCP analyze_symbol, zero-result payloads for references / callers / callees / impact) reports graph_supported: true with reason "Call-graph extraction is indexed for 'sql'.". In practice, SQL callers / callees / impact return zero for every stored procedure / function / trigger on every indexed SQL file, because CREATE PROCEDURE / CREATE FUNCTION / CREATE TRIGGER symbols are extracted with BodyStyle.None in SymbolExtractor:
Without a body range on the caller symbol, ResolveContainerForCall can't attribute a call inside the procedure body to the enclosing procedure — so every row in symbol_references for SQL ends up with container_kind=NULL / container_name=NULL. callers <proc> joins symbols to symbol_references via container_name, so it matches zero rows even when the reference row itself is correct.
The capability metadata claims the opposite:
$ dotnet ./src/CodeIndex/bin/Debug/net8.0/cdidx.dll inspect dbo.sp_Target --lang sql --json
... "graph_supported": true,
"graph_support_reason": "Call-graph extraction is indexed for 'sql'." ...
AI clients and MCP consumers trust this JSON (not the README) to decide whether to call callers / callees / impact, so the current state gives silent-zero answers instead of "use search for SQL graph questions".
This is a distinct root cause from #296 (SQL schema-qualified symbol name mismatch). #296 is about the name-vocabulary mismatch between SymbolExtractor and ReferenceExtractor; this ticket is about container resolution: even after #296 aligns names, callers will still return zero on SQL because no SQL reference row carries a container_name.
callers sp_Target → 1 row (dbo.sp_Caller at procs.sql:10), or
graph_supported: false (or graph_degraded: true with a reason like \"sql_container_resolution_missing\") so AI clients don't route callers / callees / impact queries to SQL indexes.
Suspected root cause
Two contributing gaps, both in SQL SymbolExtractor patterns:
BodyStyle.None — SQL CREATE PROCEDURE/FUNCTION/TRIGGER symbols carry only a line number for the CREATE statement, no body_start_line / body_end_line. ReferenceExtractor.ResolveContainerForCall relies on walking indexed symbols that contain the current line inside their body range; with no body range, nothing contains the call site and container_name stays NULL on every row.
Capability metadata not gated on body-range support — ReferenceExtractor.SupportsSymbolGraph returns true for any language in SupportedLanguages. It doesn't know that SQL's symbol shape precludes caller attribution. Downstream the graph_supported JSON claim therefore overstates reality.
Suggested direction
Two independent fixes:
A. Give SQL PROCEDURE / FUNCTION / TRIGGER a real body range
T-SQL / MySQL / PostgreSQL all delimit proc/function bodies in slightly different ways. Pragmatic shapes worth supporting:
T-SQL: AS BEGIN ... END[;] [GO] or AS BEGIN ... END[;]\nGO at top-level.
T-SQL: AS followed by a single statement until the next GO or the next CREATE.
MySQL / MariaDB: BEGIN ... END; inside a DELIMITER // block.
PostgreSQL: AS $$ ... $$ LANGUAGE plpgsql; / AS $tag$ ... $tag$.
Option: add a SQL-specific body-range resolver that scans forward from the CREATE line for the statement terminator (GO, END at top-level, ; outside a string). Even a coarse "body = everything from CREATE PROCEDURE line to the first GO or end-of-file" heuristic is enough to let ResolveContainerForCall find the enclosing procedure on the common T-SQL shape.
B. Make graph_supported honest for SQL until A lands
Minimum change: in SupportsSymbolGraph, return false (or a new graph_degraded=true with reason) for sql symbols that don't carry a body range. Propagate graph_support_reason = \"SQL references are indexed, but caller/callee/impact container resolution is not yet end-to-end for SQL; use 'search' for 'who calls this proc?' questions.\" so AI clients route around it instead of getting silent zeros.
Scope
src/CodeIndex/Indexer/SymbolExtractor.cs — SQL PROCEDURE / FUNCTION / TRIGGER patterns gain a body-range strategy (not BodyStyle.None). Consider adding a SQL-specific body resolver.
src/CodeIndex/Indexer/ReferenceExtractor.cs — SupportsSymbolGraph / GetGraphSupportReason gain SQL-specific degradation (pending A).
src/CodeIndex/Cli/QueryCommandRunner.cs / src/CodeIndex/Mcp/McpToolHandlers.cs — surface the degraded reason in zero-result payloads and inspect output.
tests/CodeIndex.Tests/SymbolExtractorTests.cs — fixture asserting body range is assigned to CREATE PROCEDURE dbo.sp_X AS BEGIN ... END.
Summary
SQL is listed in
ReferenceExtractor.SupportedLanguagesand every graph-capability surface (inspect --json, MCPanalyze_symbol, zero-result payloads forreferences/callers/callees/impact) reportsgraph_supported: truewith reason"Call-graph extraction is indexed for 'sql'.". In practice, SQLcallers/callees/impactreturn zero for every stored procedure / function / trigger on every indexed SQL file, becauseCREATE PROCEDURE/CREATE FUNCTION/CREATE TRIGGERsymbols are extracted withBodyStyle.NoneinSymbolExtractor:Without a body range on the caller symbol,
ResolveContainerForCallcan't attribute a call inside the procedure body to the enclosing procedure — so every row insymbol_referencesfor SQL ends up withcontainer_kind=NULL/container_name=NULL.callers <proc>joinssymbolstosymbol_referencesviacontainer_name, so it matches zero rows even when the reference row itself is correct.The capability metadata claims the opposite:
AI clients and MCP consumers trust this JSON (not the README) to decide whether to call
callers/callees/impact, so the current state gives silent-zero answers instead of "usesearchfor SQL graph questions".This is a distinct root cause from #296 (SQL schema-qualified symbol name mismatch). #296 is about the name-vocabulary mismatch between
SymbolExtractorandReferenceExtractor; this ticket is about container resolution: even after #296 aligns names,callerswill still return zero on SQL because no SQL reference row carries acontainer_name.Repro
Observed (cdidx v1.11.0):
Expected:
callers sp_Target→ 1 row (dbo.sp_Calleratprocs.sql:10), orgraph_supported: false(orgraph_degraded: truewith a reason like\"sql_container_resolution_missing\") so AI clients don't routecallers/callees/impactqueries to SQL indexes.Suspected root cause
Two contributing gaps, both in SQL SymbolExtractor patterns:
BodyStyle.None— SQLCREATE PROCEDURE/FUNCTION/TRIGGERsymbols carry only a line number for theCREATEstatement, nobody_start_line/body_end_line.ReferenceExtractor.ResolveContainerForCallrelies on walking indexed symbols that contain the current line inside their body range; with no body range, nothing contains the call site andcontainer_namestays NULL on every row.ReferenceExtractor.SupportsSymbolGraphreturns true for any language inSupportedLanguages. It doesn't know that SQL's symbol shape precludes caller attribution. Downstream thegraph_supportedJSON claim therefore overstates reality.Suggested direction
Two independent fixes:
A. Give SQL PROCEDURE / FUNCTION / TRIGGER a real body range
T-SQL / MySQL / PostgreSQL all delimit proc/function bodies in slightly different ways. Pragmatic shapes worth supporting:
AS BEGIN ... END[;] [GO]orAS BEGIN ... END[;]\nGOat top-level.ASfollowed by a single statement until the nextGOor the nextCREATE.BEGIN ... END;inside aDELIMITER //block.AS $$ ... $$ LANGUAGE plpgsql;/AS $tag$ ... $tag$.Option: add a SQL-specific body-range resolver that scans forward from the
CREATEline for the statement terminator (GO,ENDat top-level,;outside a string). Even a coarse "body = everything fromCREATE PROCEDUREline to the firstGOor end-of-file" heuristic is enough to letResolveContainerForCallfind the enclosing procedure on the common T-SQL shape.B. Make
graph_supportedhonest for SQL until A landsMinimum change: in
SupportsSymbolGraph, return false (or a newgraph_degraded=truewith reason) forsqlsymbols that don't carry a body range. Propagategraph_support_reason=\"SQL references are indexed, but caller/callee/impact container resolution is not yet end-to-end for SQL; use 'search' for 'who calls this proc?' questions.\"so AI clients route around it instead of getting silent zeros.Scope
src/CodeIndex/Indexer/SymbolExtractor.cs— SQL PROCEDURE / FUNCTION / TRIGGER patterns gain a body-range strategy (notBodyStyle.None). Consider adding a SQL-specific body resolver.src/CodeIndex/Indexer/ReferenceExtractor.cs—SupportsSymbolGraph/GetGraphSupportReasongain SQL-specific degradation (pending A).src/CodeIndex/Cli/QueryCommandRunner.cs/src/CodeIndex/Mcp/McpToolHandlers.cs— surface the degraded reason in zero-result payloads andinspectoutput.tests/CodeIndex.Tests/SymbolExtractorTests.cs— fixture asserting body range is assigned toCREATE PROCEDURE dbo.sp_X AS BEGIN ... END.tests/CodeIndex.Tests/QueryCommandRunnerTests.csorMcpServerTests.cs— end-to-endcallers dbo.sp_Targetreturns the enclosing caller after SQL: schema-qualified symbol names (dbo.fn_X) don't match bare reference names (fn_X) —callersalways returns zero,referenceson the definition line produces a phantom self-reference #296 and this ticket both land, and meanwhilegraph_supportedfor SQL is degraded with the correct reason.Related
EXEC <proc>/EXECUTE <proc>(no parentheses, optional argument list) #232 — T-SQLEXEC/CALLno-parens reference extraction (extractor-only, now fixed). Left this gap explicit in the PR description as out-of-scope because it requires changing SymbolExtractor body-range strategy.dbo.fn_X) don't match bare reference names (fn_X) —callersalways returns zero,referenceson the definition line produces a phantom self-reference #296 — SQL schema-qualified symbol name mismatch (dbo.fn_Xvs barefn_X). Orthogonal root cause: even after SQL: schema-qualified symbol names (dbo.fn_X) don't match bare reference names (fn_X) —callersalways returns zero,referenceson the definition line produces a phantom self-reference #296 aligns names,callerswill still return zero without container resolution.FROM table,JOIN table,INSERT INTO table, CTE usage,EXEC usp_*, and view references are all invisible — plusINSERT INTO audit_log (col, …)is captured as a spurious function call #284 — Broader SQL reference coverage (FROM/JOIN/INTOetc.). Also distinct: SQL:FROM table,JOIN table,INSERT INTO table, CTE usage,EXEC usp_*, and view references are all invisible — plusINSERT INTO audit_log (col, …)is captured as a spurious function call #284 is about what references are captured; this ticket is about attributing captured references to an enclosing procedure.Environment
fix/issue-232-tsql-exec-references).EXEC <proc>/EXECUTE <proc>(no parentheses, optional argument list) #232 iteration loop.