diff --git a/ansible/files/postgresql_extension_custom_scripts/pgmq/after-create.sql b/ansible/files/postgresql_extension_custom_scripts/pgmq/after-create.sql index 19c2620bd5..a29db99415 100644 --- a/ansible/files/postgresql_extension_custom_scripts/pgmq/after-create.sql +++ b/ansible/files/postgresql_extension_custom_scripts/pgmq/after-create.sql @@ -21,14 +21,16 @@ begin this update is backwards compatible with version 1.4.4 but should be removed once we're on physical backups everywhere */ --- Detach and delete the official function -if extversion = '1.4.4' then - alter extension pgmq drop function pgmq.drop_queue; - drop function pgmq.drop_queue; -else -- 1.5.1+ - alter extension pgmq drop function pgmq.drop_queue(TEXT); - drop function pgmq.drop_queue(TEXT); -end if; + -- detach both historical drop_queue signatures, if present as extension members + if to_regprocedure('pgmq.drop_queue(text)') is not null then + alter extension pgmq drop function pgmq.drop_queue(text); + end if; + if to_regprocedure('pgmq.drop_queue(text, boolean)') is not null then + alter extension pgmq drop function pgmq.drop_queue(text, boolean); + end if; + + drop function if exists pgmq.drop_queue(text); + drop function if exists pgmq.drop_queue(text, boolean); -- Create and reattach the patched function CREATE FUNCTION pgmq.drop_queue(queue_name TEXT) @@ -143,11 +145,17 @@ BEGIN END; $func$ LANGUAGE plpgsql; -if extversion = '1.4.4' then - alter extension pgmq add function pgmq.drop_queue; -else -- 1.5.1+ - alter extension pgmq add function pgmq.drop_queue(TEXT); -end if; + alter extension pgmq add function pgmq.drop_queue(text); + +-- compat shim, not reattached: keeps ALTER EXTENSION UPDATE from ever touching it +CREATE OR REPLACE FUNCTION pgmq.drop_queue(queue_name TEXT, partitioned BOOLEAN) +RETURNS BOOLEAN AS $shim$ +BEGIN + RETURN pgmq.drop_queue(queue_name); +END; +$shim$ LANGUAGE plpgsql; + + alter function pgmq.drop_queue(text, boolean) owner to postgres; update pg_extension set extowner = 'postgres'::regrole where extname = 'pgmq'; diff --git a/ansible/files/postgresql_extension_custom_scripts/pgmq/before-create.sql b/ansible/files/postgresql_extension_custom_scripts/pgmq/before-create.sql new file mode 100644 index 0000000000..6e6ae444c7 --- /dev/null +++ b/ansible/files/postgresql_extension_custom_scripts/pgmq/before-create.sql @@ -0,0 +1,4 @@ +-- clear a leftover drop_queue(text, boolean) compat shim from a prior +-- install: it isn't an extension member, so DROP EXTENSION never removes it, +-- and pgmq's own install script would otherwise collide with it +drop function if exists pgmq.drop_queue(text, boolean); diff --git a/nix/ext/tests/pgmq-drop-queue-overload.nix b/nix/ext/tests/pgmq-drop-queue-overload.nix new file mode 100644 index 0000000000..09a591570b --- /dev/null +++ b/nix/ext/tests/pgmq-drop-queue-overload.nix @@ -0,0 +1,84 @@ +{ self, pkgs }: +let + pname = "pgmq"; + inherit (pkgs) lib; + system = pkgs.pkgsLinux.stdenv.hostPlatform.system; + testLib = import ./lib.nix { inherit self pkgs; }; + + installedExtension = self.legacyPackages.${system}."psql_15".exts."${pname}"; + versions = installedExtension.versions; +in +pkgs.testers.runNixOSTest { + name = "pgmq-drop-queue-overload"; + nodes.server = + { ... }: + { + imports = [ + (testLib.makeSupabaseTestConfig { + majorVersion = "15"; + }) + ]; + }; + testScript = + { ... }: + let + versionList = lib.concatStringsSep ", " (map (v: ''"${v}"'') versions); + in + '' + versions = [${versionList}] + + def sql(query): + return server.succeed( + "psql -U supabase_admin -d postgres -t -A -F',' -c \"" + query.replace('"', '\\"') + "\"" + ).strip() + + def drop_queue_overloads(): + # owned flag first: pg_get_function_identity_arguments() can itself + # contain a comma ("queue_name text, partitioned boolean"), so put the + # single-char flag first and split on the first comma only. + out = sql( + "select (d.objid is not null), pg_get_function_identity_arguments(p.oid) " + "from pg_proc p " + "left join pg_depend d on d.objid = p.oid and d.deptype = 'e' " + " and d.refobjid = (select oid from pg_extension where extname = 'pgmq') " + "where p.pronamespace = 'pgmq'::regnamespace and p.proname = 'drop_queue' " + "order by 2;" + ) + return [line.split(",", 1) for line in out.splitlines() if line] + + # every calling convention drop_queue has ever supported still works + def check_callers(qname): + sql(f"select pgmq.create('{qname}_a'); select pgmq.drop_queue('{qname}_a');") + sql(f"select pgmq.create('{qname}_b'); select pgmq.drop_queue('{qname}_b', false);") + # WRONG flag on purpose (queue isn't partitioned) - must still + # succeed, safely ignored in favour of pgmq.meta + sql(f"select pgmq.create('{qname}_c'); select pgmq.drop_queue('{qname}_c', true);") + sql( + f"select pgmq.create('{qname}_d'); " + f"select pgmq.drop_queue(queue_name => '{qname}_d', partitioned => true);" + ) + + start_all() + server.wait_for_unit("supabase-db-init.service") + + # fresh install of each pinned version: check the overload split, then the callers + for version in versions: + with subtest(f"install pgmq {version}"): + server.succeed("psql -U supabase_admin -d postgres -c 'DROP EXTENSION IF EXISTS pgmq;'") + server.succeed( + f"psql -U supabase_admin -d postgres -c \"CREATE EXTENSION pgmq WITH VERSION '{version}' CASCADE;\"" + ) + + overloads = drop_queue_overloads() + print(f"[{version}] drop_queue overloads: {overloads}") + assert overloads == [ + ["t", "queue_name text"], + ["f", "queue_name text, partitioned boolean"], + ], ( + f"[{version}] expected one extension-owned drop_queue(text) plus " + f"an unattached drop_queue(text, boolean) compat shim, got: {overloads}" + ) + + check_callers(f"q_{version.replace('.', '_')}") + ''; +} diff --git a/nix/tests/expected/pgmq.out b/nix/tests/expected/pgmq.out index 258d11e837..315b5f01f9 100644 --- a/nix/tests/expected/pgmq.out +++ b/nix/tests/expected/pgmq.out @@ -175,7 +175,6 @@ order by pgmq | delete | postgres pgmq | detach_archive | postgres pgmq | drop_queue | postgres - pgmq | drop_queue | postgres pgmq | format_table_name | postgres pgmq | list_queues | postgres pgmq | metrics | postgres @@ -198,7 +197,7 @@ order by pgmq | send_batch | postgres pgmq | set_vt | postgres pgmq | validate_queue_name | postgres -(40 rows) +(39 rows) -- assert search_path is preserved after after-create script is run show search_path; diff --git a/nix/tests/expected/z_15_ext_interface.out b/nix/tests/expected/z_15_ext_interface.out index e53086bdec..19b80469b0 100644 --- a/nix/tests/expected/z_15_ext_interface.out +++ b/nix/tests/expected/z_15_ext_interface.out @@ -1379,7 +1379,6 @@ order by pgmq | pgmq | delete | queue_name text, msg_ids bigint[] | SETOF bigint pgmq | pgmq | detach_archive | queue_name text | void pgmq | pgmq | drop_queue | queue_name text, partitioned boolean | boolean - pgmq | pgmq | drop_queue | queue_name text | boolean pgmq | pgmq | format_table_name | queue_name text, prefix text | text pgmq | pgmq | list_queues | | SETOF pgmq.queue_record pgmq | pgmq | metrics | queue_name text | pgmq.metrics_result @@ -5307,7 +5306,7 @@ order by xml2 | public | xpath_table | text, text, text, text, text | SETOF record xml2 | public | xslt_process | text, text | text xml2 | public | xslt_process | text, text, text | text -(5135 rows) +(5134 rows) /* diff --git a/nix/tests/expected/z_17_ext_interface.out b/nix/tests/expected/z_17_ext_interface.out index d589b8a6d1..ecda520934 100644 --- a/nix/tests/expected/z_17_ext_interface.out +++ b/nix/tests/expected/z_17_ext_interface.out @@ -1364,7 +1364,6 @@ order by pgmq | pgmq | delete | queue_name text, msg_ids bigint[] | SETOF bigint pgmq | pgmq | detach_archive | queue_name text | void pgmq | pgmq | drop_queue | queue_name text, partitioned boolean | boolean - pgmq | pgmq | drop_queue | queue_name text | boolean pgmq | pgmq | format_table_name | queue_name text, prefix text | text pgmq | pgmq | list_queues | | SETOF pgmq.queue_record pgmq | pgmq | metrics | queue_name text | pgmq.metrics_result @@ -4951,7 +4950,7 @@ order by xml2 | public | xpath_table | text, text, text, text, text | SETOF record xml2 | public | xslt_process | text, text | text xml2 | public | xslt_process | text, text, text | text -(4792 rows) +(4791 rows) /* diff --git a/nix/tests/expected/z_multigres-17_ext_interface.out b/nix/tests/expected/z_multigres-17_ext_interface.out index 978d6adffe..4590968336 100644 --- a/nix/tests/expected/z_multigres-17_ext_interface.out +++ b/nix/tests/expected/z_multigres-17_ext_interface.out @@ -1364,7 +1364,6 @@ order by pgmq | pgmq | delete | queue_name text, msg_ids bigint[] | SETOF bigint pgmq | pgmq | detach_archive | queue_name text | void pgmq | pgmq | drop_queue | queue_name text, partitioned boolean | boolean - pgmq | pgmq | drop_queue | queue_name text | boolean pgmq | pgmq | format_table_name | queue_name text, prefix text | text pgmq | pgmq | list_queues | | SETOF pgmq.queue_record pgmq | pgmq | metrics | queue_name text | pgmq.metrics_result @@ -4814,7 +4813,7 @@ order by xml2 | public | xpath_table | text, text, text, text, text | SETOF record xml2 | public | xslt_process | text, text | text xml2 | public | xslt_process | text, text, text | text -(4655 rows) +(4654 rows) /* diff --git a/nix/tests/expected/z_multigres-orioledb-17_ext_interface.out b/nix/tests/expected/z_multigres-orioledb-17_ext_interface.out index e8596ed536..83b9dde08e 100644 --- a/nix/tests/expected/z_multigres-orioledb-17_ext_interface.out +++ b/nix/tests/expected/z_multigres-orioledb-17_ext_interface.out @@ -1417,7 +1417,6 @@ order by pgmq | pgmq | delete | queue_name text, msg_ids bigint[] | SETOF bigint pgmq | pgmq | detach_archive | queue_name text | void pgmq | pgmq | drop_queue | queue_name text, partitioned boolean | boolean - pgmq | pgmq | drop_queue | queue_name text | boolean pgmq | pgmq | format_table_name | queue_name text, prefix text | text pgmq | pgmq | list_queues | | SETOF pgmq.queue_record pgmq | pgmq | metrics | queue_name text | pgmq.metrics_result @@ -4867,7 +4866,7 @@ order by xml2 | public | xpath_table | text, text, text, text, text | SETOF record xml2 | public | xslt_process | text, text | text xml2 | public | xslt_process | text, text, text | text -(4707 rows) +(4706 rows) /* diff --git a/nix/tests/expected/z_orioledb-17_ext_interface.out b/nix/tests/expected/z_orioledb-17_ext_interface.out index 84eeaac1e3..ed5e1c0f0c 100644 --- a/nix/tests/expected/z_orioledb-17_ext_interface.out +++ b/nix/tests/expected/z_orioledb-17_ext_interface.out @@ -1417,7 +1417,6 @@ order by pgmq | pgmq | delete | queue_name text, msg_ids bigint[] | SETOF bigint pgmq | pgmq | detach_archive | queue_name text | void pgmq | pgmq | drop_queue | queue_name text, partitioned boolean | boolean - pgmq | pgmq | drop_queue | queue_name text | boolean pgmq | pgmq | format_table_name | queue_name text, prefix text | text pgmq | pgmq | list_queues | | SETOF pgmq.queue_record pgmq | pgmq | metrics | queue_name text | pgmq.metrics_result @@ -5004,7 +5003,7 @@ order by xml2 | public | xpath_table | text, text, text, text, text | SETOF record xml2 | public | xslt_process | text, text | text xml2 | public | xslt_process | text, text, text | text -(4844 rows) +(4843 rows) /*