diff --git a/cmd/dump/dump_integration_test.go b/cmd/dump/dump_integration_test.go index 8318d58b..3e0883cb 100644 --- a/cmd/dump/dump_integration_test.go +++ b/cmd/dump/dump_integration_test.go @@ -95,6 +95,13 @@ func TestDumpCommand_Issue183GeneratedColumn(t *testing.T) { runExactMatchTest(t, "issue_183_generated_column") } +func TestDumpCommand_Issue275TruncatedFunctionGrants(t *testing.T) { + if testing.Short() { + t.Skip("Skipping integration test in short mode") + } + runExactMatchTest(t, "issue_275_truncated_function_grants") +} + func runExactMatchTest(t *testing.T, testDataDir string) { runExactMatchTestWithContext(t, context.Background(), testDataDir) } diff --git a/ir/queries/queries.sql b/ir/queries/queries.sql index ad0fb171..b5baeab5 100644 --- a/ir/queries/queries.sql +++ b/ir/queries/queries.sql @@ -1237,7 +1237,7 @@ WITH acl_data AS ( -- Tables and Views SELECT n.nspname AS schema_name, - c.relname AS object_name, + c.relname::text AS object_name, CASE c.relkind WHEN 'r' THEN 'TABLE' WHEN 'v' THEN 'VIEW' @@ -1287,7 +1287,7 @@ WITH acl_data AS ( -- Types (ENUM, COMPOSITE, DOMAIN) SELECT n.nspname AS schema_name, - t.typname AS object_name, + t.typname::text AS object_name, 'TYPE' AS object_type, t.typacl AS acl, pg_get_userbyid(t.typowner) AS owner @@ -1337,7 +1337,7 @@ WITH objects_with_acl AS ( -- Types SELECT - t.typname AS object_name, + t.typname::text AS object_name, 'TYPE' AS object_type, t.typacl AS acl FROM pg_type t diff --git a/ir/queries/queries.sql.go b/ir/queries/queries.sql.go index 647114d9..67fe7f2a 100644 --- a/ir/queries/queries.sql.go +++ b/ir/queries/queries.sql.go @@ -1919,7 +1919,7 @@ WITH acl_data AS ( -- Tables and Views SELECT n.nspname AS schema_name, - c.relname AS object_name, + c.relname::text AS object_name, CASE c.relkind WHEN 'r' THEN 'TABLE' WHEN 'v' THEN 'VIEW' @@ -1969,7 +1969,7 @@ WITH acl_data AS ( -- Types (ENUM, COMPOSITE, DOMAIN) SELECT n.nspname AS schema_name, - t.typname AS object_name, + t.typname::text AS object_name, 'TYPE' AS object_type, t.typacl AS acl, pg_get_userbyid(t.typowner) AS owner @@ -2425,7 +2425,7 @@ WITH objects_with_acl AS ( -- Types SELECT - t.typname AS object_name, + t.typname::text AS object_name, 'TYPE' AS object_type, t.typacl AS acl FROM pg_type t diff --git a/testdata/dump/issue_275_truncated_function_grants/manifest.json b/testdata/dump/issue_275_truncated_function_grants/manifest.json new file mode 100644 index 00000000..a6310bed --- /dev/null +++ b/testdata/dump/issue_275_truncated_function_grants/manifest.json @@ -0,0 +1,10 @@ +{ + "name": "issue_275_truncated_function_grants", + "description": "Test case for truncated function signatures in GRANT statements (GitHub issue #275)", + "source": "https://github.com/pgplex/pgschema/issues/275", + "notes": [ + "Reproduces the bug where function signatures in GRANT EXECUTE statements are truncated to 63 characters", + "The truncation is caused by PostgreSQL name type (63 char limit) in UNION ALL type resolution", + "Tests that function signatures longer than 63 characters are preserved in full in GRANT statements" + ] +} diff --git a/testdata/dump/issue_275_truncated_function_grants/pgdump.sql b/testdata/dump/issue_275_truncated_function_grants/pgdump.sql new file mode 100644 index 00000000..05d5f3f3 --- /dev/null +++ b/testdata/dump/issue_275_truncated_function_grants/pgdump.sql @@ -0,0 +1,41 @@ +-- +-- PostgreSQL database dump +-- + +SET statement_timeout = 0; +SET lock_timeout = 0; +SET client_encoding = 'UTF8'; +SET standard_conforming_strings = on; +SET check_function_bodies = false; +SET client_min_messages = warning; +SET row_security = off; + +-- Create test role +DO $$ +BEGIN + IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'api_role') THEN + CREATE ROLE api_role; + END IF; +END $$; + +-- +-- Name: process_user_data(uuid, text, text, boolean); Type: FUNCTION; Schema: public; Owner: - +-- + +CREATE FUNCTION public.process_user_data(user_id uuid, user_name text, user_email text, is_active boolean) RETURNS void + LANGUAGE plpgsql + AS $$ +BEGIN + -- no-op +END; +$$; + +-- +-- Name: FUNCTION process_user_data(user_id uuid, user_name text, user_email text, is_active boolean); Type: ACL; Schema: public; Owner: - +-- + +GRANT EXECUTE ON FUNCTION public.process_user_data(user_id uuid, user_name text, user_email text, is_active boolean) TO api_role; + +-- +-- PostgreSQL database dump complete +-- diff --git a/testdata/dump/issue_275_truncated_function_grants/pgschema.sql b/testdata/dump/issue_275_truncated_function_grants/pgschema.sql new file mode 100644 index 00000000..26ca1408 --- /dev/null +++ b/testdata/dump/issue_275_truncated_function_grants/pgschema.sql @@ -0,0 +1,33 @@ +-- +-- pgschema database dump +-- + +-- Dumped from database version PostgreSQL 18.0 +-- Dumped by pgschema version 1.5.1 + + +-- +-- Name: process_user_data(uuid, text, text, boolean); Type: FUNCTION; Schema: -; Owner: - +-- + +CREATE OR REPLACE FUNCTION process_user_data( + user_id uuid, + user_name text, + user_email text, + is_active boolean +) +RETURNS void +LANGUAGE plpgsql +VOLATILE +AS $$ +BEGIN + -- no-op +END; +$$; + +-- +-- Name: process_user_data(user_id uuid, user_name text, user_email text, is_active boolean); Type: PRIVILEGE; Schema: privileges; Owner: - +-- + +GRANT EXECUTE ON FUNCTION process_user_data(user_id uuid, user_name text, user_email text, is_active boolean) TO api_role; + diff --git a/testdata/dump/issue_275_truncated_function_grants/raw.sql b/testdata/dump/issue_275_truncated_function_grants/raw.sql new file mode 100644 index 00000000..451ac778 --- /dev/null +++ b/testdata/dump/issue_275_truncated_function_grants/raw.sql @@ -0,0 +1,27 @@ +-- +-- Test case for GitHub issue #275: Truncated functions in grants +-- +-- This test case reproduces a bug where function signatures in GRANT EXECUTE +-- statements are truncated to 63 characters (PostgreSQL name type limit). +-- +-- The function signature "process_user_data(user_id uuid, user_name text, user_email text, is_active boolean)" +-- gets truncated to 63 chars without the fix. +-- + +DO $$ +BEGIN + IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'api_role') THEN + CREATE ROLE api_role; + END IF; +END $$; + +CREATE FUNCTION process_user_data(user_id uuid, user_name text, user_email text, is_active boolean) +RETURNS void +LANGUAGE plpgsql +AS $$ +BEGIN + -- no-op +END; +$$; + +GRANT EXECUTE ON FUNCTION process_user_data(uuid, text, text, boolean) TO api_role;