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
{{ message }}
Repository navigation
plpgsql-parser: walkSql silently returns aborted:false with zero visits when the PL/pgSQL body fails to parse #351
walkSql (packages/plpgsql-parser) returns { aborted: false } with zeroPLpgSQL_* node visits when a LANGUAGE plpgsql function body fails to parse. A syntactically broken body is indistinguishable from a clean body with "no matching constructs". The doc comment on walkSql says unparseable input is reported as an abort; that holds only for the outer SQL parse, not the PL/pgSQL body.
Observed on plpgsql-parser@18.5.8 (libpg-query 18.1.4 WASM), Node 22.23.2.
Where
src/parse.ts (~lines 101-103): any throw from parsePlPgSQLSync / hydratePlpgsqlAst is caught and the function is returned with plpgsql: null; the item is then pushed as a plain kind: 'stmt'.
walk.ts (~lines 296-297): if (!hydrated) continue; skips the body silently.
hydratePlpgsqlAst's errors[] is never consulted by walkSql / walk.
import{loadModule,walkSql,parseSql}from'plpgsql-parser';awaitloadModule();constbroken=`CREATE OR REPLACE FUNCTION public.f() RETURNS voidLANGUAGE plpgsql AS $$BEGIN UPDATE connectors SET instance_id = ; -- syntax error inside the bodyEND;$$;`;letplpgsqlNodes=0;constresult=walkSql(broken,(node)=>{if(String(node?.type??'').startsWith('PLpgSQL_'))plpgsqlNodes++;});console.log(result);// { aborted: false }console.log(plpgsqlNodes);// 0constparsed=parseSql(broken);console.log(parsed.functions.length);// 0 (declared plpgsql functions: 1)
Compare: a valid body with BEGIN END; visits 5 PLpgSQL_* nodes, and an outer-SQL syntax error (e.g. a typo before LANGUAGE) correctly yields { aborted: true, reason }.
Expected
One of:
walkSql returns { aborted: true, reason } when a declared plpgsql function fails hydration (fail-closed by default), or
the result exposes the hydration failures (e.g. errors[] / unhydrated: [...]) so callers can fail closed, optionally behind a strict option if backward compatibility matters.
Why it matters
Consumers using the walker as a structural assertion over function bodies (e.g. "this body contains no UPDATE on table X") get a false green on a broken body. We currently wrap it with a caller-side guard (declared function count vs hydrated count, errors.length, and zero-PLpgSQL_*-visit check); happy to open a PR with the fix + a test from this reproducer if you'd like — say which of (1)/(2) you prefer.
Activity
Merge pull request #352 from constructive-io/fix/deparser-issues-292-…
pyramation commentedon Sep 17, 2026
appreciate @mib00038 the issue, fixing asap!
pyramation commentedon Sep 17, 2026
thanks again!
#352 (comment)