From b136bbd6b5b4a80412c8f241b3d0e5c99460a49b Mon Sep 17 00:00:00 2001 From: Dave Page Date: Wed, 26 Aug 2026 15:12:39 +0100 Subject: [PATCH 1/4] Fix MAINTAIN privilege silently dropped for views/mviews on PG17+ allowed_privs.json for the 17_plus bucket lived directly under the bucket directory instead of under a sql/ subdirectory like every other bucket (including default), so render_template() looked for views/pg/17_plus/sql/allowed_privs.json, didn't find it, and silently fell back to the default bucket's list - which predates MAINTAIN and lacks 'm'. Moved the four affected files (views/mviews x pg/ppas) to match the default bucket's layout. Closes #10350 --- .../pg/17_plus/{ => sql}/allowed_privs.json | 0 .../ppas/17_plus/{ => sql}/allowed_privs.json | 0 .../pg/17_plus/{ => sql}/allowed_privs.json | 0 .../ppas/17_plus/{ => sql}/allowed_privs.json | 0 .../tests/test_allowed_privs_json_path.py | 54 +++++++++++++++++++ 5 files changed, 54 insertions(+) rename web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/17_plus/{ => sql}/allowed_privs.json (100%) rename web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/ppas/17_plus/{ => sql}/allowed_privs.json (100%) rename web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/views/pg/17_plus/{ => sql}/allowed_privs.json (100%) rename web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/views/ppas/17_plus/{ => sql}/allowed_privs.json (100%) create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/test_allowed_privs_json_path.py diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/17_plus/allowed_privs.json b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/17_plus/sql/allowed_privs.json similarity index 100% rename from web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/17_plus/allowed_privs.json rename to web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/17_plus/sql/allowed_privs.json diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/ppas/17_plus/allowed_privs.json b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/ppas/17_plus/sql/allowed_privs.json similarity index 100% rename from web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/ppas/17_plus/allowed_privs.json rename to web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/ppas/17_plus/sql/allowed_privs.json diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/views/pg/17_plus/allowed_privs.json b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/views/pg/17_plus/sql/allowed_privs.json similarity index 100% rename from web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/views/pg/17_plus/allowed_privs.json rename to web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/views/pg/17_plus/sql/allowed_privs.json diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/views/ppas/17_plus/allowed_privs.json b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/views/ppas/17_plus/sql/allowed_privs.json similarity index 100% rename from web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/views/ppas/17_plus/allowed_privs.json rename to web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/views/ppas/17_plus/sql/allowed_privs.json diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/test_allowed_privs_json_path.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/test_allowed_privs_json_path.py new file mode 100644 index 00000000000..cc036ee894f --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/test_allowed_privs_json_path.py @@ -0,0 +1,54 @@ +########################################################################## +# +# pgAdmin 4 - PostgreSQL Tools +# +# Copyright (C) 2013 - 2026, The pgAdmin Development Team +# This software is released under the PostgreSQL Licence +# +########################################################################## + +"""Verify that the PG17+ allowed_privs.json for views/materialized views +resolves via the versioned template loader (issue #10350). It previously +lived directly under the 17_plus bucket instead of under a sql/ +subdirectory like every other bucket, so it was never found and the +MAINTAIN privilege ('m') silently fell back to the default bucket's list, +which lacks it. +""" + +import json + +from flask import render_template + +from pgadmin.utils.route import BaseTestGenerator + +# PG17 in pgAdmin's version-number-times-10000 scheme. +PG17 = 170000 + +_ALLOWED_PRIVS_JSON = 'sql/allowed_privs.json' + + +class AllowedPrivsJsonPathTestCase(BaseTestGenerator): + """Loading allowed_privs.json for PG17+ must pick up the 17_plus + bucket's list (with MAINTAIN), not silently fall back to default. + """ + + scenarios = [ + ('views on pg', dict(base_template='views/pg/#{0}#')), + ('views on ppas', dict(base_template='views/ppas/#{0}#')), + ('materialized views on pg', dict( + base_template='mviews/pg/#{0}#')), + ('materialized views on ppas', dict( + base_template='mviews/ppas/#{0}#')), + ] + + def setUp(self): + pass + + def runTest(self): + template_path = self.base_template.format(PG17) + with self.app.app_context(): + rendered = render_template( + '/'.join([template_path, _ALLOWED_PRIVS_JSON]) + ) + allowed_acls = json.loads(rendered) + self.assertIn('m', allowed_acls['datacl']['acl']) From c3d065b11cf93f4799f571b9efb10c6b3a7461a5 Mon Sep 17 00:00:00 2001 From: Dave Page Date: Wed, 26 Aug 2026 15:39:08 +0100 Subject: [PATCH 2/4] Add PG17+ RE-SQL fixture overrides for mview privilege grants Now that allowed_acls for views/mviews correctly includes MAINTAIN on PG17+, granting the same non-MAINTAIN privilege set as before no longer equals the full allowed set, so the generated SQL expands to the explicit privilege list instead of collapsing to "GRANT ALL" - this is the correct new behaviour, but it left the two mview msql fixtures (which fell back to the default bucket, written before MAINTAIN existed) stale. Added 17_plus overrides with the corrected expected output, alongside the existing 15_plus/16_plus buckets for these fixtures. --- .../tests/pg/17_plus/alter_mview_change_grantee_priv_msql.sql | 2 ++ .../schemas/views/tests/pg/17_plus/alter_mview_msql.sql | 1 + .../tests/ppas/17_plus/alter_mview_change_grantee_priv_msql.sql | 2 ++ .../schemas/views/tests/ppas/17_plus/alter_mview_msql.sql | 1 + 4 files changed, 6 insertions(+) create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/17_plus/alter_mview_change_grantee_priv_msql.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/17_plus/alter_mview_msql.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/17_plus/alter_mview_change_grantee_priv_msql.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/17_plus/alter_mview_msql.sql diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/17_plus/alter_mview_change_grantee_priv_msql.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/17_plus/alter_mview_change_grantee_priv_msql.sql new file mode 100644 index 00000000000..c92eb9d341c --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/17_plus/alter_mview_change_grantee_priv_msql.sql @@ -0,0 +1,2 @@ +REVOKE ALL ON TABLE public."testmview_$%{}[]()&*^!/@`#" FROM ; +GRANT INSERT, SELECT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER ON TABLE public."testmview_$%{}[]()&*^!/@`#" TO PUBLIC; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/17_plus/alter_mview_msql.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/17_plus/alter_mview_msql.sql new file mode 100644 index 00000000000..bdf4b291a36 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/17_plus/alter_mview_msql.sql @@ -0,0 +1 @@ +GRANT INSERT, SELECT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER ON TABLE public."testmview_$%{}[]()&*^!/@`#" TO PUBLIC; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/17_plus/alter_mview_change_grantee_priv_msql.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/17_plus/alter_mview_change_grantee_priv_msql.sql new file mode 100644 index 00000000000..81ce5fe812e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/17_plus/alter_mview_change_grantee_priv_msql.sql @@ -0,0 +1,2 @@ +REVOKE ALL ON TABLE public."testmview_$%{}[]()&*^!/@`#" FROM enterprisedb; +GRANT INSERT, SELECT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER ON TABLE public."testmview_$%{}[]()&*^!/@`#" TO PUBLIC; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/17_plus/alter_mview_msql.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/17_plus/alter_mview_msql.sql new file mode 100644 index 00000000000..bdf4b291a36 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/17_plus/alter_mview_msql.sql @@ -0,0 +1 @@ +GRANT INSERT, SELECT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER ON TABLE public."testmview_$%{}[]()&*^!/@`#" TO PUBLIC; From 0ac9067a3d376c01773838c6de2769e2b6340f60 Mon Sep 17 00:00:00 2001 From: Dave Page Date: Mon, 14 Sep 2026 10:20:43 +0100 Subject: [PATCH 3/4] Complete the PG17+ RE-SQL fixtures for views and materialised views The 17_plus test directories added for the msql fixtures contained only .sql files, and get_test_folder() in the RE-SQL runner resolves at folder level rather than per file, unlike get_test_file(): it picks the first existing version directory and then lists the .json scenario files in it. On a PG17+ server the runner therefore resolved to a directory with no JSON in it and ran no view or materialised view scenarios at all, which is why the stale expected SQL below went unnoticed. Each bucket carries its own copy of tests.json and test_mview.json for that reason, so the 17_plus buckets now do too. With the scenarios running again, the reverse engineered SQL for the two scenarios that grant the seven-privilege set to PUBLIC needs the same 17_plus treatment as the msql fixtures, since sql() re-filters through parse_priv_to_db() with the version's allowed ACLs and no longer collapses seven of eight privileges to ALL. The owner's grant still collapses, as the owner holds MAINTAIN as well. Verified against PostgreSQL 18: 43 scenarios now run, where none ran before, and all pass. --- .../views/tests/pg/17_plus/alter_mview.sql | 18 + .../alter_mview_change_grantee_priv.sql | 17 + .../views/tests/pg/17_plus/test_mview.json | 345 ++++++++++++++++++ .../schemas/views/tests/pg/17_plus/tests.json | 246 +++++++++++++ .../views/tests/ppas/17_plus/alter_mview.sql | 18 + .../alter_mview_change_grantee_priv.sql | 17 + .../views/tests/ppas/17_plus/test_mview.json | 339 +++++++++++++++++ .../views/tests/ppas/17_plus/tests.json | 207 +++++++++++ .../tests/test_allowed_privs_json_path.py | 3 + 9 files changed, 1210 insertions(+) create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/17_plus/alter_mview.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/17_plus/alter_mview_change_grantee_priv.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/17_plus/test_mview.json create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/17_plus/tests.json create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/17_plus/alter_mview.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/17_plus/alter_mview_change_grantee_priv.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/17_plus/test_mview.json create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/17_plus/tests.json diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/17_plus/alter_mview.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/17_plus/alter_mview.sql new file mode 100644 index 00000000000..1a1ad3e3b44 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/17_plus/alter_mview.sql @@ -0,0 +1,18 @@ +-- View: public.testmview_$%{}[]()&*^!/@`# + +-- DROP MATERIALIZED VIEW IF EXISTS public."testmview_$%{}[]()&*^!/@`#"; + +CREATE MATERIALIZED VIEW IF NOT EXISTS public."testmview_$%{}[]()&*^!/@`#" +TABLESPACE pg_default +AS + SELECT 1 AS col1 +WITH NO DATA; + +ALTER TABLE IF EXISTS public."testmview_$%{}[]()&*^!/@`#" + OWNER TO ; + +COMMENT ON MATERIALIZED VIEW public."testmview_$%{}[]()&*^!/@`#" + IS 'comment1'; + +GRANT TRUNCATE, INSERT, DELETE, SELECT, TRIGGER, UPDATE, REFERENCES ON TABLE public."testmview_$%{}[]()&*^!/@`#" TO PUBLIC; +GRANT ALL ON TABLE public."testmview_$%{}[]()&*^!/@`#" TO ; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/17_plus/alter_mview_change_grantee_priv.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/17_plus/alter_mview_change_grantee_priv.sql new file mode 100644 index 00000000000..dcba43c9d26 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/17_plus/alter_mview_change_grantee_priv.sql @@ -0,0 +1,17 @@ +-- View: public.testmview_$%{}[]()&*^!/@`# + +-- DROP MATERIALIZED VIEW IF EXISTS public."testmview_$%{}[]()&*^!/@`#"; + +CREATE MATERIALIZED VIEW IF NOT EXISTS public."testmview_$%{}[]()&*^!/@`#" +TABLESPACE pg_default +AS + SELECT 1 AS col1 +WITH NO DATA; + +ALTER TABLE IF EXISTS public."testmview_$%{}[]()&*^!/@`#" + OWNER TO ; + +COMMENT ON MATERIALIZED VIEW public."testmview_$%{}[]()&*^!/@`#" + IS 'comment1'; + +GRANT TRUNCATE, INSERT, DELETE, SELECT, TRIGGER, UPDATE, REFERENCES ON TABLE public."testmview_$%{}[]()&*^!/@`#" TO PUBLIC; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/17_plus/test_mview.json b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/17_plus/test_mview.json new file mode 100644 index 00000000000..ac63312cb0a --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/17_plus/test_mview.json @@ -0,0 +1,345 @@ +{ + "scenarios": [ + { + "type": "create", + "name": "Create Extension", + "endpoint": "NODE-extension.obj", + "sql_endpoint": "NODE-extension.sql_id", + "data": { + "name": "postgres_fdw", + "version": "", + "relocatable": true + }, + "store_object_id": true + }, + { + "type": "create", + "name": "Create Materialised Views with extensions.", + "endpoint": "NODE-mview.obj", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql", + "data": { + "spcname": "pg_default", + "schema": "public", + "owner": "", + "datacl": [], + "seclabels": [], + "name": "testmview_$%{}[]()&*^!/@`#", + "comment": "comment1", + "definition": "SELECT 1 AS col1", + "dependsonextensions": [ + "plpgsql", + "postgres_fdw" + ] + }, + "expected_sql_file": "create_mview_no_depends.sql", + "expected_msql_file": "create_mview_no_depends.msql" + }, + { + "type": "alter", + "name": "Alter Materialised Views with NO DEPENDS.", + "endpoint": "NODE-mview.obj_id", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql_id", + "data": { + "dependsonextensions": [ + "plpgsql" + ] + }, + "expected_sql_file": "alter_mview_no_depends.sql", + "expected_msql_file": "alter_mview_no_depends.msql" + }, + { + "type": "delete", + "name": "Drop Materialised Views", + "endpoint": "NODE-mview.delete_id", + "data": {} + }, + { + "type": "delete", + "name": "Drop Extension", + "endpoint": "NODE-extension.delete", + "data": { + "ids": [ + "" + ] + }, + "preprocess_data": true + }, + { + "type": "create", + "name": "Create Materialised Views", + "endpoint": "NODE-mview.obj", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql", + "data": { + "spcname": "pg_default", + "schema": "public", + "owner": "", + "datacl": [], + "seclabels": [], + "name": "testmview_$%{}[]()&*^!/@`#", + "comment": "comment1", + "definition": "SELECT 1 AS col1" + }, + "expected_sql_file": "create_mview.sql", + "expected_msql_file": "create_mview_msql.sql" + }, + { + "type": "alter", + "name": "Alter Materialised Views (Adding privileges)", + "endpoint": "NODE-mview.obj_id", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql_id", + "data": { + "datacl": { + "added": [ + { + "grantee": "PUBLIC", + "grantor": "", + "privileges": [ + { + "privilege_type": "a", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "r", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "w", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "d", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "D", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "x", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "t", + "privilege": true, + "with_grant": false + } + ] + } + ] + } + }, + "expected_sql_file": "alter_mview.sql", + "expected_msql_file": "alter_mview_msql.sql" + }, + { + "type": "alter", + "name": "Alter Materialised Views (Remove all privileges)", + "endpoint": "NODE-mview.obj_id", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql_id", + "data": { + "datacl": { + "deleted": [ + { + "grantee": "PUBLIC", + "grantor": "", + "privileges": [ + { + "privilege_type": "a", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "r", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "w", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "d", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "D", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "x", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "t", + "privilege": true, + "with_grant": false + } + ] + } + ] + } + }, + "expected_sql_file": "alter_mview_drop_all_priv.sql", + "expected_msql_file": "alter_mview_drop_all_priv_msql.sql" + }, + { + "type": "alter", + "name": "Alter Materialised Views (change grantee in privileges)", + "endpoint": "NODE-mview.obj_id", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql_id", + "data": { + "datacl": { + "changed": [ + { + "grantee": "PUBLIC", + "grantor": "", + "old_grantee": "", + "privileges": [ + { + "privilege_type": "a", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "r", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "w", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "d", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "D", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "x", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "t", + "privilege": true, + "with_grant": false + } + ] + } + ] + } + }, + "expected_sql_file": "alter_mview_change_grantee_priv.sql", + "expected_msql_file": "alter_mview_change_grantee_priv_msql.sql" + }, + { + "type": "alter", + "name": "Alter Materialised Views (change definition)", + "endpoint": "NODE-mview.obj_id", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql_id", + "data": { + "definition": "SELECT 12 AS col1;" + }, + "expected_sql_file": "alter_mview_definition.sql", + "expected_msql_file": "alter_mview_definition_msql.sql" + }, + { + "type": "alter", + "name": "Alter Materialised Views (Fillfactor)", + "endpoint": "NODE-mview.obj_id", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql_id", + "data": { + "fillfactor": "18", + "with_data": true + }, + "expected_sql_file": "alter_mview_add_fillfactor.sql", + "expected_msql_file": "alter_mview_add_fillfactor_msql.sql" + }, + { + "type": "alter", + "name": "Alter Materialised Views (add table parameters)", + "endpoint": "NODE-mview.obj_id", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql_id", + "data": { + "autovacuum_custom": true, + "autovacuum_enabled": "t", + "vacuum_table": { + "changed": [ + { + "name": "autovacuum_analyze_scale_factor", + "value": 0.2 + } + ] + } + }, + "expected_sql_file": "alter_mview_add_table_parameter.sql", + "expected_msql_file": "alter_mview_add_table_parameter_msql.sql" + }, + { + "type": "alter", + "name": "Alter Materialised Views (remove table parameters)", + "endpoint": "NODE-mview.obj_id", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql_id", + "data": { + "autovacuum_custom": true, + "autovacuum_enabled": "x", + "vacuum_table": { + "changed": [ + { + "name": "autovacuum_analyze_scale_factor", + "value": null + } + ] + } + }, + "expected_sql_file": "alter_mview_remove_table_parameter.sql", + "expected_msql_file": "alter_mview_remove_table_parameter_msql.sql" + }, + { + "type": "create", + "name": "Create Materialised Views with access method", + "endpoint": "NODE-mview.obj", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql", + "data": { + "spcname": "pg_default", + "schema": "public", + "owner": "", + "datacl": [], + "seclabels": [], + "name": "testmview_am_$%{}[]()&*^!/@`#", + "comment": "comment1", + "definition": "SELECT 1 AS col1", + "amname": "heap" + }, + "expected_msql_file": "create_mview_with_am_msql.sql", + "expected_sql_file": "create_mview_with_am.sql" + } + ] +} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/17_plus/tests.json b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/17_plus/tests.json new file mode 100644 index 00000000000..534503f9ebb --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/17_plus/tests.json @@ -0,0 +1,246 @@ +{ + "scenarios": [ + { + "type": "create", + "name": "Create Table for Views", + "endpoint": "NODE-table.obj", + "sql_endpoint": "NODE-table.sql_id", + "data": { + "name": "test_view_table", + "check_constraint": [], + "coll_inherits": "[]", + "columns": [ + { + "name": "col1", + "cltype": "integer" + } + ], + "schema": "public" + } + }, + { + "type": "create", + "name": "Create View", + "endpoint": "NODE-view.obj", + "sql_endpoint": "NODE-view.sql_id", + "msql_endpoint": "NODE-view.msql", + "data": { + "definition": "select col1 from test_view_table;", + "name": "testview_$%{}[]()&*^!@\"'`\\/#", + "owner": "", + "schema": "public", + "check_option": "local", + "security_barrier": false, + "security_invoker": false, + "comment": "Testcomment", + "datacl": [ + { + "grantee": "", + "old_grantee": "", + "grantor": "", + "privileges": [ + { + "privilege_type": "a", + "privilege": true, + "with_grant": false + } + ] + } + ] + }, + "expected_sql_file": "create_view.sql", + "expected_msql_file": "create_view_msql.sql" + }, + { + "type": "alter", + "name": "Alter View", + "endpoint": "NODE-view.obj_id", + "sql_endpoint": "NODE-view.sql_id", + "msql_endpoint": "NODE-view.msql_id", + "data": { + "name": "testview_$%{}[]()&*^!@\"'`\\/#", + "owner": "", + "schema": "public", + "check_option": "cascaded", + "security_barrier": true, + "security_invoker": true, + "comment": "Testcomment-updated", + "datacl": [ + { + "grantee": "", + "grantor": "", + "old_grantee": "", + "privileges": [ + { + "privilege_type": "a", + "privilege": true, + "with_grant": false + } + ] + } + ] + }, + "expected_sql_file": "alter_view.sql", + "expected_msql_file": "alter_view_msql.sql" + }, + { + "type": "alter", + "name": "Alter View (changing code)", + "endpoint": "NODE-view.obj_id", + "sql_endpoint": "NODE-view.sql_id", + "msql_endpoint": "NODE-view.msql_id", + "data": { + "definition": "SELECT * FROM test_view_table;" + }, + "expected_sql_file": "alter_view_definition.sql", + "expected_msql_file": "alter_view_definition_msql.sql" + }, + { + "type": "alter", + "name": "Alter View (adding privileges)", + "endpoint": "NODE-view.obj_id", + "sql_endpoint": "NODE-view.sql_id", + "msql_endpoint": "NODE-view.msql_id", + "data": { + "name": "testview_$%{}[]()&*^!@\"'`\\/#", + "owner": "", + "schema": "public", + "check_option": "cascaded", + "security_barrier": true, + "comment": "Testcomment-updated", + "datacl": { + "added": [ + { + "grantee": "PUBLIC", + "grantor": "", + "privileges": [ + { + "privilege_type": "r", + "privilege": true, + "with_grant": false + } + ] + } + ] + } + }, + "expected_sql_file": "alter_view_add_some_priv.sql", + "expected_msql_file": "alter_view_add_some_priv_msql.sql" + }, + { + "type": "alter", + "name": "Alter View (deleting privileges (PUBLIC))", + "endpoint": "NODE-view.obj_id", + "sql_endpoint": "NODE-view.sql_id", + "msql_endpoint": "NODE-view.msql_id", + "data": { + "name": "testview_$%{}[]()&*^!@\"'`\\/#", + "owner": "", + "schema": "public", + "check_option": "cascaded", + "security_barrier": true, + "comment": "Testcomment-updated", + "datacl": { + "deleted": [ + { + "grantee": "PUBLIC", + "grantor": "", + "privileges": [ + { + "privilege_type": "r", + "privilege": true, + "with_grant": false + } + ] + } + ] + } + } + }, + { + "type": "alter", + "name": "Alter View (changing privileges (postgres to PUBLIC))", + "endpoint": "NODE-view.obj_id", + "sql_endpoint": "NODE-view.sql_id", + "msql_endpoint": "NODE-view.msql_id", + "data": { + "name": "testview_$%{}[]()&*^!@\"'`\\/#", + "owner": "", + "schema": "public", + "check_option": "cascaded", + "security_barrier": true, + "comment": "Testcomment-updated", + "datacl": { + "changed": [ + { + "grantee": "PUBLIC", + "grantor": "", + "old_grantee": "", + "privileges": [ + { + "privilege_type": "r", + "privilege": true, + "with_grant": false + } + ] + } + ] + } + }, + "expected_sql_file": "alter_view_update_priv.sql", + "expected_msql_file": "alter_view_update_priv_msql.sql" + }, + { + "type": "alter", + "name": "Alter View (deleting privileges)", + "endpoint": "NODE-view.obj_id", + "sql_endpoint": "NODE-view.sql_id", + "msql_endpoint": "NODE-view.msql_id", + "data": { + "name": "testview_$%{}[]()&*^!@\"'`\\/#", + "owner": "", + "schema": "public", + "check_option": "cascaded", + "security_barrier": true, + "comment": "Testcomment-updated", + "datacl": { + "deleted": [ + { + "grantee": "PUBLIC", + "grantor": "", + "privileges": [ + { + "privilege_type": "r", + "privilege": true, + "with_grant": false + } + ] + } + ] + } + }, + "expected_sql_file": "alter_view_delete_priv.sql", + "expected_msql_file": "alter_view_delete_priv_msql.sql" + }, + { + "type": "delete", + "name": "Drop View", + "endpoint": "NODE-view.obj_id", + "data": { + "name": "testview_$%{}[]()&*^!@\"'`\\/#", + "owner": "", + "schema": "public" + } + }, + { + "type": "delete", + "name": "Drop Table for view", + "endpoint": "NODE-table.obj_id", + "data": { + "name": "test_view_table", + "owner": "", + "schema": "public" + } + } + ] +} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/17_plus/alter_mview.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/17_plus/alter_mview.sql new file mode 100644 index 00000000000..2ed9346fbac --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/17_plus/alter_mview.sql @@ -0,0 +1,18 @@ +-- View: public.testmview_$%{}[]()&*^!/@`# + +-- DROP MATERIALIZED VIEW public."testmview_$%{}[]()&*^!/@`#"; + +CREATE MATERIALIZED VIEW IF NOT EXISTS public."testmview_$%{}[]()&*^!/@`#" +TABLESPACE pg_default +AS + SELECT 1 AS col1 +WITH NO DATA; + +ALTER TABLE IF EXISTS public."testmview_$%{}[]()&*^!/@`#" + OWNER TO enterprisedb; + +COMMENT ON MATERIALIZED VIEW public."testmview_$%{}[]()&*^!/@`#" + IS 'comment1'; + +GRANT TRUNCATE, INSERT, DELETE, SELECT, TRIGGER, UPDATE, REFERENCES ON TABLE public."testmview_$%{}[]()&*^!/@`#" TO PUBLIC; +GRANT ALL ON TABLE public."testmview_$%{}[]()&*^!/@`#" TO enterprisedb; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/17_plus/alter_mview_change_grantee_priv.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/17_plus/alter_mview_change_grantee_priv.sql new file mode 100644 index 00000000000..4794ef4a051 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/17_plus/alter_mview_change_grantee_priv.sql @@ -0,0 +1,17 @@ +-- View: public.testmview_$%{}[]()&*^!/@`# + +-- DROP MATERIALIZED VIEW public."testmview_$%{}[]()&*^!/@`#"; + +CREATE MATERIALIZED VIEW IF NOT EXISTS public."testmview_$%{}[]()&*^!/@`#" +TABLESPACE pg_default +AS + SELECT 1 AS col1 +WITH NO DATA; + +ALTER TABLE IF EXISTS public."testmview_$%{}[]()&*^!/@`#" + OWNER TO enterprisedb; + +COMMENT ON MATERIALIZED VIEW public."testmview_$%{}[]()&*^!/@`#" + IS 'comment1'; + +GRANT TRUNCATE, INSERT, DELETE, SELECT, TRIGGER, UPDATE, REFERENCES ON TABLE public."testmview_$%{}[]()&*^!/@`#" TO PUBLIC; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/17_plus/test_mview.json b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/17_plus/test_mview.json new file mode 100644 index 00000000000..9e18388d61a --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/17_plus/test_mview.json @@ -0,0 +1,339 @@ +{ + "scenarios": [ + { + "type": "create", + "name": "Create Extension", + "endpoint": "NODE-extension.obj", + "sql_endpoint": "NODE-extension.sql_id", + "data": { + "name": "postgres_fdw", + "version": "", + "relocatable": true + }, + "store_object_id": true + }, + { + "type": "create", + "name": "Create Materialised Views with extensions.", + "endpoint": "NODE-mview.obj", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql", + "data": { + "spcname": "pg_default", + "schema": "public", + "owner": "enterprisedb", + "datacl": [], + "seclabels": [], + "name": "testmview_$%{}[]()&*^!/@`#", + "comment": "comment1", + "definition": "SELECT 1 AS col1", + "dependsonextensions": ["plpgsql", "postgres_fdw"] + }, + "expected_sql_file": "create_mview_no_depends.sql", + "expected_msql_file": "create_mview_no_depends.msql" + }, + { + "type": "alter", + "name": "Alter Materialised Views with NO DEPENDS ON.", + "endpoint": "NODE-mview.obj_id", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql_id", + "data": { + "dependsonextensions": ["plpgsql"] + }, + "expected_sql_file": "alter_mview_no_depends.sql", + "expected_msql_file": "alter_mview_no_depends.msql" + }, + { + "type": "delete", + "name": "Drop Materialised Views", + "endpoint": "NODE-mview.delete_id", + "data": { + } + }, + { + "type": "delete", + "name": "Drop Extension", + "endpoint": "NODE-extension.delete", + "data": { + "ids": [""] + }, + "preprocess_data": true + }, + { + "type": "create", + "name": "Create Materialised Views", + "endpoint": "NODE-mview.obj", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql", + "data": { + "spcname": "pg_default", + "schema": "public", + "owner": "enterprisedb", + "datacl": [], + "seclabels": [], + "name": "testmview_$%{}[]()&*^!/@`#", + "comment": "comment1", + "definition": "SELECT 1 AS col1" + }, + "expected_sql_file": "create_mview.sql", + "expected_msql_file": "create_mview_msql.sql" + }, + { + "type": "alter", + "name": "Alter Materialised Views (Adding privileges)", + "endpoint": "NODE-mview.obj_id", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql_id", + "data": { + "datacl": { + "added": [ + { + "grantee": "PUBLIC", + "grantor": "enterprisedb", + "privileges": [ + { + "privilege_type": "a", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "r", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "w", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "d", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "D", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "x", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "t", + "privilege": true, + "with_grant": false + } + ] + } + ] + } + }, + "expected_sql_file": "alter_mview.sql", + "expected_msql_file": "alter_mview_msql.sql" + }, + { + "type": "alter", + "name": "Alter Materialised Views (Remove all privileges)", + "endpoint": "NODE-mview.obj_id", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql_id", + "data": { + "datacl": { + "deleted": [ + { + "grantee": "PUBLIC", + "grantor": "enterprisedb", + "privileges": [ + { + "privilege_type": "a", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "r", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "w", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "d", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "D", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "x", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "t", + "privilege": true, + "with_grant": false + } + ] + } + ] + } + }, + "expected_sql_file": "alter_mview_drop_all_priv.sql", + "expected_msql_file": "alter_mview_drop_all_priv_msql.sql" + }, + { + "type": "alter", + "name": "Alter Materialised Views (change grantee in privileges)", + "endpoint": "NODE-mview.obj_id", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql_id", + "data": { + "datacl": { + "changed": [ + { + "grantee": "PUBLIC", + "grantor": "enterprisedb", + "old_grantee": "enterprisedb", + "privileges": [ + { + "privilege_type": "a", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "r", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "w", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "d", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "D", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "x", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "t", + "privilege": true, + "with_grant": false + } + ] + } + ] + } + }, + "expected_sql_file": "alter_mview_change_grantee_priv.sql", + "expected_msql_file": "alter_mview_change_grantee_priv_msql.sql" + }, + { + "type": "alter", + "name": "Alter Materialised Views (change definition)", + "endpoint": "NODE-mview.obj_id", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql_id", + "data": { + "definition": "SELECT 12 AS col1;" + }, + "expected_sql_file": "alter_mview_definition.sql", + "expected_msql_file": "alter_mview_definition_msql.sql" + }, + { + "type": "alter", + "name": "Alter Materialised Views (Fillfactor)", + "endpoint": "NODE-mview.obj_id", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql_id", + "data": { + "fillfactor": "18", + "with_data": true + }, + "expected_sql_file": "alter_mview_add_fillfactor.sql", + "expected_msql_file": "alter_mview_add_fillfactor_msql.sql" + }, + { + "type": "alter", + "name": "Alter Materialised Views (add table parameters)", + "endpoint": "NODE-mview.obj_id", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql_id", + "data": { + "autovacuum_custom": true, + "autovacuum_enabled": "t", + "vacuum_table": { + "changed": [ + { + "name": "autovacuum_analyze_scale_factor", + "value": 0.2 + } + ] + } + }, + "expected_sql_file": "alter_mview_add_table_parameter.sql", + "expected_msql_file": "alter_mview_add_table_parameter_msql.sql" + }, + { + "type": "alter", + "name": "Alter Materialised Views (remove table parameters)", + "endpoint": "NODE-mview.obj_id", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql_id", + "data": { + "autovacuum_custom": true, + "autovacuum_enabled": "x", + "vacuum_table": { + "changed": [ + { + "name": "autovacuum_analyze_scale_factor", + "value": null + } + ] + } + }, + "expected_sql_file": "alter_mview_remove_table_parameter.sql", + "expected_msql_file": "alter_mview_remove_table_parameter_msql.sql" + }, + { + "type": "create", + "name": "Create Materialised Views with access method", + "endpoint": "NODE-mview.obj", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql", + "data": { + "spcname": "pg_default", + "schema": "public", + "owner": "enterprisedb", + "datacl": [], + "seclabels": [], + "name": "testmview_am_$%{}[]()&*^!/@`#", + "comment": "comment1", + "definition": "SELECT 1 AS col1", + "amname": "heap" + }, + "expected_msql_file": "create_mview_with_am_msql.sql", + "expected_sql_file": "create_mview_with_am.sql" + } + ] +} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/17_plus/tests.json b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/17_plus/tests.json new file mode 100644 index 00000000000..c8111f9f557 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/17_plus/tests.json @@ -0,0 +1,207 @@ +{ + "scenarios": [ + { + "type": "create", + "name": "Create Table for Views", + "endpoint": "NODE-table.obj", + "sql_endpoint": "NODE-table.sql_id", + "data": { + "name": "test_view_table", + "check_constraint": [], + "coll_inherits": "[]", + "columns": [ + { + "name": "col1", + "cltype": "integer" + } + ], + "schema": "public" + } + }, + { + "type": "create", + "name": "Create View", + "endpoint": "NODE-view.obj", + "sql_endpoint": "NODE-view.sql_id", + "msql_endpoint": "NODE-view.msql", + "data": { + "definition": "select col1 from test_view_table;", + "name": "testview_$%{}[]()&*^!@\"'`\\/#", + "owner": "enterprisedb", + "schema": "public", + "check_option": "local", + "security_barrier": false, + "security_invoker": false, + "comment":"Testcomment", + "datacl":[{"grantee":"enterprisedb", "grantor":"enterprisedb", "privileges":[{"privilege_type": "a", "privilege": true, + "with_grant":false}]}] + }, + "expected_sql_file": "create_view.sql", + "expected_msql_file": "create_view_msql.sql" + }, + { + "type": "alter", + "name": "Alter View", + "endpoint": "NODE-view.obj_id", + "sql_endpoint": "NODE-view.sql_id", + "msql_endpoint": "NODE-view.msql_id", + "data": { + "name": "testview_$%{}[]()&*^!@\"'`\\/#", + "owner": "enterprisedb", + "schema": "public", + "check_option": "cascaded", + "security_barrier": true, + "security_invoker": true, + "comment":"Testcomment-updated", + "datacl":[{"grantee":"enterprisedb", "grantor":"enterprisedb", "privileges":[{"privilege_type": "a", "privilege": true, + "with_grant":false}]}] + }, + "expected_sql_file": "alter_view.sql", + "expected_msql_file": "alter_view_msql.sql" + }, + { + "type": "alter", + "name": "Alter View (adding privileges)", + "endpoint": "NODE-view.obj_id", + "sql_endpoint": "NODE-view.sql_id", + "msql_endpoint": "NODE-view.msql_id", + "data": { + "datacl":{ + "added":[ + { + "grantee":"PUBLIC", + "grantor":"enterprisedb", + "privileges":[ + { + "privilege_type":"r", + "privilege":true, + "with_grant":false + } + ] + } + ] + } + }, + "expected_sql_file": "alter_view_add_some_priv.sql", + "expected_msql_file": "alter_view_add_some_priv_msql.sql" + }, + { + "type": "alter", + "name": "Alter View (deleting privileges (PUBLIC))", + "endpoint": "NODE-view.obj_id", + "sql_endpoint": "NODE-view.sql_id", + "msql_endpoint": "NODE-view.msql_id", + "data": { + "name": "testview_$%{}[]()&*^!@\"'`\\/#", + "owner": "enterprisedb", + "schema": "public", + "check_option": "cascaded", + "security_barrier": true, + "comment":"Testcomment-updated", + "datacl": + { + "deleted":[ + { + "grantee":"PUBLIC", + "grantor":"enterprisedb", + "privileges":[ + { + "privilege_type":"r", + "privilege":true, + "with_grant":false + } + ] + } + ] + } + } + }, + { + "type": "alter", + "name": "Alter View (changing privileges (enterprisedb to PUBLIC))", + "endpoint": "NODE-view.obj_id", + "sql_endpoint": "NODE-view.sql_id", + "msql_endpoint": "NODE-view.msql_id", + "data": { + "name": "testview_$%{}[]()&*^!@\"'`\\/#", + "owner": "enterprisedb", + "schema": "public", + "check_option": "cascaded", + "security_barrier": true, + "comment":"Testcomment-updated", + "datacl": + { + "changed":[ + { + "grantee":"PUBLIC", + "grantor":"enterprisedb", + "old_grantee": "enterprisedb", + "privileges":[ + { + "privilege_type":"r", + "privilege":true, + "with_grant":false + } + ] + } + ] + } + }, + "expected_sql_file": "alter_view_update_priv.sql", + "expected_msql_file": "alter_view_update_priv_msql.sql" + }, + { + "type": "alter", + "name": "Alter View (deleting privileges)", + "endpoint": "NODE-view.obj_id", + "sql_endpoint": "NODE-view.sql_id", + "msql_endpoint": "NODE-view.msql_id", + "data": { + "name": "testview_$%{}[]()&*^!@\"'`\\/#", + "owner": "enterprisedb", + "schema": "public", + "check_option": "cascaded", + "security_barrier": true, + "comment":"Testcomment-updated", + "datacl": + { + "deleted":[ + { + "grantee":"PUBLIC", + "grantor":"enterprisedb", + "privileges":[ + { + "privilege_type":"r", + "privilege":true, + "with_grant":false + } + ] + } + ] + } + }, + "expected_sql_file": "alter_view_delete_priv.sql", + "expected_msql_file": "alter_view_delete_priv_msql.sql" + }, + { + "type": "delete", + "name": "Drop View", + "endpoint": "NODE-view.obj_id", + "data": { + "name": "testview_$%{}[]()&*^!@\"'`\\/#", + "owner": "enterprisedb", + "schema": "public" + } + }, + { + "type": "delete", + "name": "Drop Table for view", + "endpoint": "NODE-table.obj_id", + "data": { + "name": "test_view_table", + "owner": "enterprisedb", + "schema": "public" + } + } + ] +} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/test_allowed_privs_json_path.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/test_allowed_privs_json_path.py index cc036ee894f..2b43f4a22b4 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/test_allowed_privs_json_path.py +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/test_allowed_privs_json_path.py @@ -42,6 +42,9 @@ class AllowedPrivsJsonPathTestCase(BaseTestGenerator): ] def setUp(self): + # BaseTestGenerator.setUp() connects to the test server, which this + # test has no use for: it only renders a template, and the Flask app + # it needs is set up by the regression harness rather than here. pass def runTest(self): From 5fd9721ab87b3d01544024e48c5c5e38b8f21fd3 Mon Sep 17 00:00:00 2001 From: Dave Page Date: Thu, 24 Sep 2026 13:17:43 +0100 Subject: [PATCH 4/4] Test granting MAINTAIN on views and materialised views on PG17+ The allowed_privs.json test only proves the privilege list loads; add RE-SQL scenarios that grant MAINTAIN to PUBLIC on a view and on a materialised view, so the generated and reverse engineered SQL are checked end to end. The materialised view's ACL is NULL at that point, so the grant also materialises the owner's default ACL, hence the owner's GRANT ALL line in its expected SQL. --- .../17_plus/alter_mview_add_maintain_priv.sql | 21 +++++++++++++++ .../alter_mview_add_maintain_priv_msql.sql | 1 + .../17_plus/alter_view_add_maintain_priv.sql | 19 ++++++++++++++ .../alter_view_add_maintain_priv_msql.sql | 1 + .../views/tests/pg/17_plus/test_mview.json | 26 +++++++++++++++++++ .../schemas/views/tests/pg/17_plus/tests.json | 26 +++++++++++++++++++ .../17_plus/alter_mview_add_maintain_priv.sql | 21 +++++++++++++++ .../alter_mview_add_maintain_priv_msql.sql | 1 + .../17_plus/alter_view_add_maintain_priv.sql | 19 ++++++++++++++ .../alter_view_add_maintain_priv_msql.sql | 1 + .../views/tests/ppas/17_plus/test_mview.json | 26 +++++++++++++++++++ .../views/tests/ppas/17_plus/tests.json | 26 +++++++++++++++++++ 12 files changed, 188 insertions(+) create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/17_plus/alter_mview_add_maintain_priv.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/17_plus/alter_mview_add_maintain_priv_msql.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/17_plus/alter_view_add_maintain_priv.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/17_plus/alter_view_add_maintain_priv_msql.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/17_plus/alter_mview_add_maintain_priv.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/17_plus/alter_mview_add_maintain_priv_msql.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/17_plus/alter_view_add_maintain_priv.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/17_plus/alter_view_add_maintain_priv_msql.sql diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/17_plus/alter_mview_add_maintain_priv.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/17_plus/alter_mview_add_maintain_priv.sql new file mode 100644 index 00000000000..2b7487cd255 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/17_plus/alter_mview_add_maintain_priv.sql @@ -0,0 +1,21 @@ +-- View: public.testmview_$%{}[]()&*^!/@`# + +-- DROP MATERIALIZED VIEW IF EXISTS public."testmview_$%{}[]()&*^!/@`#"; + +CREATE MATERIALIZED VIEW IF NOT EXISTS public."testmview_$%{}[]()&*^!/@`#" +WITH ( + FILLFACTOR = 18 +) +TABLESPACE pg_default +AS + SELECT 12 AS col1 +WITH DATA; + +ALTER TABLE IF EXISTS public."testmview_$%{}[]()&*^!/@`#" + OWNER TO ; + +COMMENT ON MATERIALIZED VIEW public."testmview_$%{}[]()&*^!/@`#" + IS 'comment1'; + +GRANT MAINTAIN ON TABLE public."testmview_$%{}[]()&*^!/@`#" TO PUBLIC; +GRANT ALL ON TABLE public."testmview_$%{}[]()&*^!/@`#" TO ; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/17_plus/alter_mview_add_maintain_priv_msql.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/17_plus/alter_mview_add_maintain_priv_msql.sql new file mode 100644 index 00000000000..53e5058276e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/17_plus/alter_mview_add_maintain_priv_msql.sql @@ -0,0 +1 @@ +GRANT MAINTAIN ON TABLE public."testmview_$%{}[]()&*^!/@`#" TO PUBLIC; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/17_plus/alter_view_add_maintain_priv.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/17_plus/alter_view_add_maintain_priv.sql new file mode 100644 index 00000000000..6b59adab429 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/17_plus/alter_view_add_maintain_priv.sql @@ -0,0 +1,19 @@ +-- View: public.testview_$%{}[]()&*^!@"'`\/# + +-- DROP VIEW public."testview_$%{}[]()&*^!@""'`\/#"; + +CREATE OR REPLACE VIEW public."testview_$%{}[]()&*^!@""'`\/#" +WITH ( + check_option=cascaded, + security_barrier=true, + security_invoker=true +) AS + SELECT col1 + FROM test_view_table; + +ALTER TABLE public."testview_$%{}[]()&*^!@""'`\/#" + OWNER TO ; +COMMENT ON VIEW public."testview_$%{}[]()&*^!@""'`\/#" + IS 'Testcomment-updated'; + +GRANT MAINTAIN ON TABLE public."testview_$%{}[]()&*^!@""'`\/#" TO PUBLIC; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/17_plus/alter_view_add_maintain_priv_msql.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/17_plus/alter_view_add_maintain_priv_msql.sql new file mode 100644 index 00000000000..8e9b818697a --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/17_plus/alter_view_add_maintain_priv_msql.sql @@ -0,0 +1 @@ +GRANT MAINTAIN ON TABLE public."testview_$%{}[]()&*^!@""'`\/#" TO PUBLIC; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/17_plus/test_mview.json b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/17_plus/test_mview.json index ac63312cb0a..6e6b1a7f64a 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/17_plus/test_mview.json +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/17_plus/test_mview.json @@ -321,6 +321,32 @@ "expected_sql_file": "alter_mview_remove_table_parameter.sql", "expected_msql_file": "alter_mview_remove_table_parameter_msql.sql" }, + { + "type": "alter", + "name": "Alter Materialised Views (adding MAINTAIN privilege)", + "endpoint": "NODE-mview.obj_id", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql_id", + "data": { + "datacl": { + "added": [ + { + "grantee": "PUBLIC", + "grantor": "", + "privileges": [ + { + "privilege_type": "m", + "privilege": true, + "with_grant": false + } + ] + } + ] + } + }, + "expected_sql_file": "alter_mview_add_maintain_priv.sql", + "expected_msql_file": "alter_mview_add_maintain_priv_msql.sql" + }, { "type": "create", "name": "Create Materialised Views with access method", diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/17_plus/tests.json b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/17_plus/tests.json index 534503f9ebb..db9b628983d 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/17_plus/tests.json +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/17_plus/tests.json @@ -222,6 +222,32 @@ "expected_sql_file": "alter_view_delete_priv.sql", "expected_msql_file": "alter_view_delete_priv_msql.sql" }, + { + "type": "alter", + "name": "Alter View (adding MAINTAIN privilege)", + "endpoint": "NODE-view.obj_id", + "sql_endpoint": "NODE-view.sql_id", + "msql_endpoint": "NODE-view.msql_id", + "data": { + "datacl": { + "added": [ + { + "grantee": "PUBLIC", + "grantor": "", + "privileges": [ + { + "privilege_type": "m", + "privilege": true, + "with_grant": false + } + ] + } + ] + } + }, + "expected_sql_file": "alter_view_add_maintain_priv.sql", + "expected_msql_file": "alter_view_add_maintain_priv_msql.sql" + }, { "type": "delete", "name": "Drop View", diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/17_plus/alter_mview_add_maintain_priv.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/17_plus/alter_mview_add_maintain_priv.sql new file mode 100644 index 00000000000..9e4f22a56f3 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/17_plus/alter_mview_add_maintain_priv.sql @@ -0,0 +1,21 @@ +-- View: public.testmview_$%{}[]()&*^!/@`# + +-- DROP MATERIALIZED VIEW public."testmview_$%{}[]()&*^!/@`#"; + +CREATE MATERIALIZED VIEW IF NOT EXISTS public."testmview_$%{}[]()&*^!/@`#" +WITH ( + FILLFACTOR = 18 +) +TABLESPACE pg_default +AS + SELECT 12 AS col1 +WITH DATA; + +ALTER TABLE IF EXISTS public."testmview_$%{}[]()&*^!/@`#" + OWNER TO enterprisedb; + +COMMENT ON MATERIALIZED VIEW public."testmview_$%{}[]()&*^!/@`#" + IS 'comment1'; + +GRANT MAINTAIN ON TABLE public."testmview_$%{}[]()&*^!/@`#" TO PUBLIC; +GRANT ALL ON TABLE public."testmview_$%{}[]()&*^!/@`#" TO enterprisedb; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/17_plus/alter_mview_add_maintain_priv_msql.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/17_plus/alter_mview_add_maintain_priv_msql.sql new file mode 100644 index 00000000000..53e5058276e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/17_plus/alter_mview_add_maintain_priv_msql.sql @@ -0,0 +1 @@ +GRANT MAINTAIN ON TABLE public."testmview_$%{}[]()&*^!/@`#" TO PUBLIC; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/17_plus/alter_view_add_maintain_priv.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/17_plus/alter_view_add_maintain_priv.sql new file mode 100644 index 00000000000..a8af55b775f --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/17_plus/alter_view_add_maintain_priv.sql @@ -0,0 +1,19 @@ +-- View: public.testview_$%{}[]()&*^!@"'`\/# + +-- DROP VIEW public."testview_$%{}[]()&*^!@""'`\/#"; + +CREATE OR REPLACE VIEW public."testview_$%{}[]()&*^!@""'`\/#" +WITH ( + check_option=cascaded, + security_barrier=true, + security_invoker=true +) AS + SELECT col1 + FROM test_view_table; + +ALTER TABLE IF EXISTS public."testview_$%{}[]()&*^!@""'`\/#" + OWNER TO enterprisedb; +COMMENT ON VIEW public."testview_$%{}[]()&*^!@""'`\/#" + IS 'Testcomment-updated'; + +GRANT MAINTAIN ON TABLE public."testview_$%{}[]()&*^!@""'`\/#" TO PUBLIC; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/17_plus/alter_view_add_maintain_priv_msql.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/17_plus/alter_view_add_maintain_priv_msql.sql new file mode 100644 index 00000000000..8e9b818697a --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/17_plus/alter_view_add_maintain_priv_msql.sql @@ -0,0 +1 @@ +GRANT MAINTAIN ON TABLE public."testview_$%{}[]()&*^!@""'`\/#" TO PUBLIC; diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/17_plus/test_mview.json b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/17_plus/test_mview.json index 9e18388d61a..3e81fa14dd3 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/17_plus/test_mview.json +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/17_plus/test_mview.json @@ -315,6 +315,32 @@ "expected_sql_file": "alter_mview_remove_table_parameter.sql", "expected_msql_file": "alter_mview_remove_table_parameter_msql.sql" }, + { + "type": "alter", + "name": "Alter Materialised Views (adding MAINTAIN privilege)", + "endpoint": "NODE-mview.obj_id", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql_id", + "data": { + "datacl": { + "added": [ + { + "grantee": "PUBLIC", + "grantor": "", + "privileges": [ + { + "privilege_type": "m", + "privilege": true, + "with_grant": false + } + ] + } + ] + } + }, + "expected_sql_file": "alter_mview_add_maintain_priv.sql", + "expected_msql_file": "alter_mview_add_maintain_priv_msql.sql" + }, { "type": "create", "name": "Create Materialised Views with access method", diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/17_plus/tests.json b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/17_plus/tests.json index c8111f9f557..a62b99f1dd0 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/17_plus/tests.json +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/17_plus/tests.json @@ -183,6 +183,32 @@ "expected_sql_file": "alter_view_delete_priv.sql", "expected_msql_file": "alter_view_delete_priv_msql.sql" }, + { + "type": "alter", + "name": "Alter View (adding MAINTAIN privilege)", + "endpoint": "NODE-view.obj_id", + "sql_endpoint": "NODE-view.sql_id", + "msql_endpoint": "NODE-view.msql_id", + "data": { + "datacl": { + "added": [ + { + "grantee": "PUBLIC", + "grantor": "", + "privileges": [ + { + "privilege_type": "m", + "privilege": true, + "with_grant": false + } + ] + } + ] + } + }, + "expected_sql_file": "alter_view_add_maintain_priv.sql", + "expected_msql_file": "alter_view_add_maintain_priv_msql.sql" + }, { "type": "delete", "name": "Drop View",