Files
graphify/tests/fixtures/sample_plpgsql_quoted.sql
T
Souptik Chakraborty ffa2a2471a fix: recover every declared SQL routine from unparseable PL/pgSQL (#2180)
tree-sitter-sql cannot parse PL/pgSQL-only statements, and #1910's ERROR-node
name recovery only covered one of the shapes that produces. Two others dropped
the routine silently -- no node, no warning, exit code 0:

1. The statement is shredded into loose top-level tokens (keyword_create,
   keyword_function, object_reference, ..., keyword_begin) and the ERROR node
   holds only the offending body line, e.g. `PERFORM other_fn();` or `x := 1;`.
   No ERROR node contains any CREATE text, so scanning ERROR nodes finds
   nothing. This is what still dropped PERFORM and := after #1910.
2. The routine name is a quoted identifier -- CREATE OR REPLACE FUNCTION
   "public"."fn"(...) -- which the recovery's bare [\w$.]+ pattern cannot match,
   because it stops dead at the leading quote. Generated schema dumps quote
   every identifier, so whole files recovered nothing.

Verified on the reported repro: the same body that drops under a quoted name is
recovered fine under an unquoted one, which is why the drop looked like it
depended only on the body statement.

Fix mirrors the global REFERENCES fallback already in this extractor: after the
tree walk, scan the raw source for every CREATE [OR REPLACE] FUNCTION/PROCEDURE
and emit any routine the walk missed. Name parts accept bare or double-quoted
identifiers. _add_node dedupes by node id, so routines already recovered from
the tree are not emitted twice.

Adds tests/fixtures/sample_plpgsql_quoted.sql -- generated-style quoted DDL whose
bodies use RAISE, RAISE NOTICE, PERFORM, :=, IF..THEN and bare NULL; -- plus
tests that every routine is recovered and that the file stays clean (tables
before and after still extract, no duplicate ids or labels, no empty/ERROR
labels, and every routine keeps its contains edge from the file node).
2026-07-26 11:08:10 +01:00

63 lines
1.6 KiB
PL/PgSQL

-- Generated-style PostgreSQL DDL (#2180): every identifier is double-quoted and
-- each body uses a PL/pgSQL-only statement, so tree-sitter-sql parses these as
-- ERROR nodes. Name recovery is the only path that can see them, and a bare
-- [\w$.]+ name pattern stops at the leading quote -- which silently dropped
-- every routine in files shaped like this.
CREATE TABLE "public"."accounts" (
"id" INT PRIMARY KEY,
"name" TEXT
);
CREATE OR REPLACE FUNCTION "public"."raise_exception_fn"("p_id" "uuid") RETURNS "void"
LANGUAGE "plpgsql" SECURITY DEFINER
SET "search_path" TO 'public'
AS $$
BEGIN
RAISE EXCEPTION 'insufficient_privilege' USING ERRCODE = '42501';
END;
$$;
CREATE OR REPLACE FUNCTION "public"."raise_notice_fn"() RETURNS "void" LANGUAGE "plpgsql" AS $$
BEGIN
RAISE NOTICE 'hi';
END;
$$;
CREATE OR REPLACE FUNCTION "public"."perform_fn"() RETURNS "void" LANGUAGE "plpgsql" AS $$
BEGIN
PERFORM "public"."raise_notice_fn"();
END;
$$;
CREATE OR REPLACE FUNCTION "public"."assign_fn"() RETURNS "void" LANGUAGE "plpgsql" AS $$
DECLARE
"x" int;
BEGIN
x := 1;
END;
$$;
CREATE OR REPLACE FUNCTION "public"."if_then_fn"() RETURNS "void" LANGUAGE "plpgsql" AS $$
BEGIN
IF true THEN RAISE EXCEPTION 'x'; END IF;
END;
$$;
CREATE OR REPLACE FUNCTION "public"."null_body_fn"() RETURNS "void" LANGUAGE "plpgsql" AS $$
BEGIN
NULL;
END;
$$;
CREATE PROCEDURE "public"."quoted_proc"() LANGUAGE "plpgsql" AS $$
BEGIN
PERFORM 1;
END;
$$;
CREATE TABLE "public"."audit_log" (
"id" INT PRIMARY KEY,
"account_id" INT REFERENCES "public"."accounts"
);