Version
codebase-memory-mcp 0.10.3 (release binary, macOS arm64 / Darwin 27.0.0).
What happened
Two PostgreSQL constructs are not handled by the vendored tree-sitter SQL grammar, and both are
ubiquitous in Supabase projects:
set search_path = ... in a create function options list — flags the file parse_partial
starting at the set line.
do $$ ... $$ blocks — flags the whole block.
On a real Supabase migration set this means 39 of 39 SQL files report parse_partial, with the
damage cascading well past the offending clause: one 795-line file reports 97-674 (the entire
function body), another reports 18-226, and a 55-line do $$ migration reports 1-55 — the whole
file.
This matters disproportionately because set search_path is
Supabase's own hardening recommendation
for security definer / security invoker functions. Their linter actively tells you to add it, so
any hardened Supabase codebase will hit this on essentially every RPC.
Reproduction
Isolating the clause — identical function body each time, only the options list changes:
create or replace function public.f_v1()
returns integer
language plpgsql
<CLAUSE>
as $fn$
declare
v_count integer;
begin
select 1 into v_count;
return v_count;
end
$fn$;
<CLAUSE> |
Result |
| (none) |
clean |
volatile |
clean |
security invoker |
clean |
set search_path = pg_catalog |
parse_partial 4-4 |
| all three combined |
parse_partial 6-6 |
The flagged range points exactly at the set line. volatile and security invoker parse fine, so
the gap is specifically the SET configuration_parameter { TO \| = } value production in
create function's options list.
Separately, a bare do $$ ... $$ block:
do $$
declare
t text;
begin
foreach t in array array['accounts'] loop
execute format('alter table public.%I enable row level security', t);
end loop;
end
$$;
→ parse_partial 1-3,5-6,7-7,8-9.
Both reproduced with --mode full on a fresh single-file repo, so this is not incremental-reload
staleness.
Interaction with #1287 (makes this easy to miss)
Re-indexing an already-indexed repo returns parse_partial_count: 0 while
check_index_coverage — same generation, generation_matches: true,
recording_status: complete — still reports every file partial with unchanged ranges. Node and
edge counts are byte-identical across the re-index, confirming nothing was re-parsed.
So the surface most likely to be checked after a re-index reports the index as coverage-clean while
the authoritative metadata disagrees. This is #1287, confirmed here on a release build on macOS
arm64 (the original report was dev on Linux x86_64).
Scope — what still works
Worth stating so this is triaged at the right severity. Despite the flags:
search_code finds identifiers inside the unparsed ranges correctly, and attributes them to the
right containing function.
- Top-level
create function nodes still exist with accurate line spans.
- Cross-file links from SQL to application code still resolve.
What is lost is intra-body structure: statement-level nodes, call edges between plpgsql
statements, and declare-block variables. So this degrades search_graph / trace_path inside
function bodies, not text discovery.
Relationship to existing issues
Suggested direction
Handling the SET production in the create function options list looks like the cheap, high-yield
fix — it is a small grammar addition and unblocks the majority of real Supabase migrations. Full
PL/pgSQL body parsing (a do block or dollar-quoted body as an embedded-language region) is the
larger follow-on.
Version
codebase-memory-mcp 0.10.3(release binary, macOS arm64 / Darwin 27.0.0).What happened
Two PostgreSQL constructs are not handled by the vendored tree-sitter SQL grammar, and both are
ubiquitous in Supabase projects:
set search_path = ...in acreate functionoptions list — flags the fileparse_partialstarting at the
setline.do $$ ... $$blocks — flags the whole block.On a real Supabase migration set this means 39 of 39 SQL files report
parse_partial, with thedamage cascading well past the offending clause: one 795-line file reports
97-674(the entirefunction body), another reports
18-226, and a 55-linedo $$migration reports1-55— the wholefile.
This matters disproportionately because
set search_pathisSupabase's own hardening recommendation
for
security definer/security invokerfunctions. Their linter actively tells you to add it, soany hardened Supabase codebase will hit this on essentially every RPC.
Reproduction
Isolating the clause — identical function body each time, only the options list changes:
<CLAUSE>volatilesecurity invokerset search_path = pg_catalogparse_partial4-4parse_partial6-6The flagged range points exactly at the
setline.volatileandsecurity invokerparse fine, sothe gap is specifically the
SET configuration_parameter { TO \| = } valueproduction increate function's options list.Separately, a bare
do $$ ... $$block:→
parse_partial1-3,5-6,7-7,8-9.Both reproduced with
--mode fullon a fresh single-file repo, so this is not incremental-reloadstaleness.
Interaction with #1287 (makes this easy to miss)
Re-indexing an already-indexed repo returns
parse_partial_count: 0whilecheck_index_coverage— same generation,generation_matches: true,recording_status: complete— still reports every filepartialwith unchanged ranges. Node andedge counts are byte-identical across the re-index, confirming nothing was re-parsed.
So the surface most likely to be checked after a re-index reports the index as coverage-clean while
the authoritative metadata disagrees. This is #1287, confirmed here on a release build on macOS
arm64 (the original report was
devon Linux x86_64).Scope — what still works
Worth stating so this is triaged at the right severity. Despite the flags:
search_codefinds identifiers inside the unparsed ranges correctly, and attributes them to theright containing function.
create functionnodes still exist with accurate line spans.What is lost is intra-body structure: statement-level nodes, call edges between plpgsql
statements, and
declare-block variables. So this degradessearch_graph/trace_pathinsidefunction bodies, not text discovery.
Relationship to existing issues
that: the body is never parsed at all, so no amount of relabeling reaches it.
a second language embedded in a host-language string.
Suggested direction
Handling the
SETproduction in thecreate functionoptions list looks like the cheap, high-yieldfix — it is a small grammar addition and unblocks the majority of real Supabase migrations. Full
PL/pgSQL body parsing (a
doblock or dollar-quoted body as an embedded-language region) is thelarger follow-on.