diff --git a/internal/diff/function.go b/internal/diff/function.go index 4fa51ab6..d71cf46a 100644 --- a/internal/diff/function.go +++ b/internal/diff/function.go @@ -243,10 +243,17 @@ func generateFunctionSQL(function *ir.Function, targetSchema string) string { // Note: Don't output PARALLEL UNSAFE (it's the default) // Add SET search_path if specified - // Note: Output without outer quotes to handle multi-schema paths correctly - // e.g., "SET search_path = pg_catalog, public" not "SET search_path = 'pg_catalog, public'" + // Note: Multi-schema paths are output unquoted (e.g., "SET search_path = pg_catalog, public"), + // except for the empty search_path case which requires single quotes: SET search_path = '' if function.SearchPath != "" { - stmt.WriteString(fmt.Sprintf("\nSET search_path = %s", function.SearchPath)) + // PostgreSQL stores SET search_path = '' as search_path="" in proconfig. + // The extracted value is "" (two double-quote chars). Render as '' (single-quoted empty string). + // Only the whole-value empty case is handled; mixed paths (e.g. pg_catalog, "") are not expected. + if function.SearchPath == `""` { + stmt.WriteString("\nSET search_path = ''") + } else { + stmt.WriteString(fmt.Sprintf("\nSET search_path = %s", function.SearchPath)) + } } // Add the function body diff --git a/testdata/diff/create_function/issue_354_empty_search_path/diff.sql b/testdata/diff/create_function/issue_354_empty_search_path/diff.sql new file mode 100644 index 00000000..b01d1a00 --- /dev/null +++ b/testdata/diff/create_function/issue_354_empty_search_path/diff.sql @@ -0,0 +1,12 @@ +CREATE OR REPLACE FUNCTION create_hello( + p_title text +) +RETURNS void +LANGUAGE plpgsql +VOLATILE +SET search_path = '' +AS $$ +BEGIN + INSERT INTO test (title) VALUES (p_title); +END; +$$; diff --git a/testdata/diff/create_function/issue_354_empty_search_path/new.sql b/testdata/diff/create_function/issue_354_empty_search_path/new.sql new file mode 100644 index 00000000..15d5c695 --- /dev/null +++ b/testdata/diff/create_function/issue_354_empty_search_path/new.sql @@ -0,0 +1,17 @@ +CREATE TABLE public.test ( + id bigint GENERATED BY DEFAULT AS IDENTITY NOT NULL, + title text, + created_at timestamp with time zone DEFAULT now() NOT NULL, + CONSTRAINT test_pkey PRIMARY KEY (id) +); + +CREATE OR REPLACE FUNCTION create_hello(p_title text) +RETURNS void +LANGUAGE plpgsql +SECURITY INVOKER +SET search_path = '' +AS $$ +BEGIN + INSERT INTO public.test (title) VALUES (p_title); +END; +$$; diff --git a/testdata/diff/create_function/issue_354_empty_search_path/old.sql b/testdata/diff/create_function/issue_354_empty_search_path/old.sql new file mode 100644 index 00000000..466001a5 --- /dev/null +++ b/testdata/diff/create_function/issue_354_empty_search_path/old.sql @@ -0,0 +1,6 @@ +CREATE TABLE public.test ( + id bigint GENERATED BY DEFAULT AS IDENTITY NOT NULL, + title text, + created_at timestamp with time zone DEFAULT now() NOT NULL, + CONSTRAINT test_pkey PRIMARY KEY (id) +); diff --git a/testdata/diff/create_function/issue_354_empty_search_path/plan.json b/testdata/diff/create_function/issue_354_empty_search_path/plan.json new file mode 100644 index 00000000..674f3a36 --- /dev/null +++ b/testdata/diff/create_function/issue_354_empty_search_path/plan.json @@ -0,0 +1,20 @@ +{ + "version": "1.0.0", + "pgschema_version": "1.7.4", + "created_at": "1970-01-01T00:00:00Z", + "source_fingerprint": { + "hash": "742d612cedabf2d80d87df6c7d9fac8911e008b29ef8e15d16a32d2edf43ddd9" + }, + "groups": [ + { + "steps": [ + { + "sql": "CREATE OR REPLACE FUNCTION create_hello(\n p_title text\n)\nRETURNS void\nLANGUAGE plpgsql\nVOLATILE\nSET search_path = ''\nAS $$\nBEGIN\n INSERT INTO test (title) VALUES (p_title);\nEND;\n$$;", + "type": "function", + "operation": "create", + "path": "public.create_hello" + } + ] + } + ] +} diff --git a/testdata/diff/create_function/issue_354_empty_search_path/plan.sql b/testdata/diff/create_function/issue_354_empty_search_path/plan.sql new file mode 100644 index 00000000..b01d1a00 --- /dev/null +++ b/testdata/diff/create_function/issue_354_empty_search_path/plan.sql @@ -0,0 +1,12 @@ +CREATE OR REPLACE FUNCTION create_hello( + p_title text +) +RETURNS void +LANGUAGE plpgsql +VOLATILE +SET search_path = '' +AS $$ +BEGIN + INSERT INTO test (title) VALUES (p_title); +END; +$$; diff --git a/testdata/diff/create_function/issue_354_empty_search_path/plan.txt b/testdata/diff/create_function/issue_354_empty_search_path/plan.txt new file mode 100644 index 00000000..1c1a2b22 --- /dev/null +++ b/testdata/diff/create_function/issue_354_empty_search_path/plan.txt @@ -0,0 +1,23 @@ +Plan: 1 to add. + +Summary by type: + functions: 1 to add + +Functions: + + create_hello + +DDL to be executed: +-------------------------------------------------- + +CREATE OR REPLACE FUNCTION create_hello( + p_title text +) +RETURNS void +LANGUAGE plpgsql +VOLATILE +SET search_path = '' +AS $$ +BEGIN + INSERT INTO test (title) VALUES (p_title); +END; +$$;