From 96e82c838c30c454438e1a52f2edbd66d2ca7cbc Mon Sep 17 00:00:00 2001 From: pavanmanishd Date: Sat, 21 Mar 2026 13:00:46 +0530 Subject: [PATCH 1/3] [#9626] Add toast_tuple_target to Materialized View properties properties.sql: extract toast_tuple_target from c.reloptions create.sql: include TOAST_TUPLE_TARGET in WITH clause when set update.sql: SET/RESET TOAST_TUPLE_TARGET when value changes mview.ui.js: add int field (128-8160, PG11+) in Definition group Mirrors the existing fillfactor pattern throughout. --- .../databases/schemas/views/static/js/mview.ui.js | 5 +++++ .../templates/mviews/pg/default/sql/create.sql | 6 ++++-- .../templates/mviews/pg/default/sql/properties.sql | 2 ++ .../templates/mviews/pg/default/sql/update.sql | 14 ++++++++++++++ 4 files changed, 25 insertions(+), 2 deletions(-) diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/static/js/mview.ui.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/static/js/mview.ui.js index e31f202e30d..104ba82e18b 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/static/js/mview.ui.js +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/static/js/mview.ui.js @@ -106,6 +106,11 @@ export default class MViewSchema extends BaseUISchema { id: 'fillfactor', label: gettext('Fill factor'), group: gettext('Definition'), mode: ['edit', 'create'], noEmpty: false, type: 'int', controlProps: {min: 10, max: 100} + },{ + id: 'toast_tuple_target', label: gettext('Toast tuple target'), + group: gettext('Definition'), mode: ['edit', 'create'], + noEmpty: false, type: 'int', controlProps: {min: 128, max: 8160}, + min_version: 110000, }, { id: 'dependsonextensions', diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/default/sql/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/default/sql/create.sql index 56b2fcef671..614e3f04c4a 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/default/sql/create.sql +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/default/sql/create.sql @@ -7,11 +7,13 @@ {% endif %} {% if data.name and data.schema and data.definition %} CREATE MATERIALIZED VIEW{% if add_not_exists_clause %} IF NOT EXISTS{% endif %} {{ conn|qtIdent(data.schema, data.name) }} -{% if(data.fillfactor or data.autovacuum_enabled in ('t', 'f') or data.toast_autovacuum_enabled in ('t', 'f') or data['vacuum_data']|length > 0) %} +{% if(data.fillfactor or data.toast_tuple_target or data.autovacuum_enabled in ('t', 'f') or data.toast_autovacuum_enabled in ('t', 'f') or data['vacuum_data']|length > 0) %} {% set ns = namespace(add_comma=false) %} WITH ( {% if data.fillfactor %} - FILLFACTOR = {{ data.fillfactor }}{% set ns.add_comma = true%}{% endif %}{% if data.autovacuum_enabled in ('t', 'f') %} + FILLFACTOR = {{ data.fillfactor }}{% set ns.add_comma = true%}{% endif %}{% if data.toast_tuple_target %} +{% if ns.add_comma %}, +{% endif %} TOAST_TUPLE_TARGET = {{ data.toast_tuple_target }}{% set ns.add_comma = true%}{% endif %}{% if data.autovacuum_enabled in ('t', 'f') %} {% if ns.add_comma %}, {% endif %} autovacuum_enabled = {% if data.autovacuum_enabled == 't' %}TRUE{% else %}FALSE{% endif %}{% set ns.add_comma = true%}{% endif %}{% if data.toast_autovacuum_enabled in ('t', 'f') %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/default/sql/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/default/sql/properties.sql index d63c1b7cdad..3a873514bce 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/default/sql/properties.sql +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/default/sql/properties.sql @@ -24,6 +24,8 @@ SELECT (SELECT pg_catalog.array_agg(provider || '=' || label) FROM pg_catalog.pg_seclabels sl1 WHERE sl1.objoid=c.oid AND sl1.objsubid=0) AS seclabels, substring(pg_catalog.array_to_string(c.reloptions, ',') FROM 'fillfactor=([0-9]*)') AS fillfactor, + substring(pg_catalog.array_to_string(c.reloptions, ',') + FROM 'toast_tuple_target=([0-9]*)') AS toast_tuple_target, (substring(pg_catalog.array_to_string(c.reloptions, ',') FROM 'autovacuum_enabled=([a-z|0-9]*)'))::BOOL AS autovacuum_enabled, substring(pg_catalog.array_to_string(c.reloptions, ',') FROM 'autovacuum_vacuum_threshold=([0-9]*)') AS autovacuum_vacuum_threshold, diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/default/sql/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/default/sql/update.sql index a9c742de75b..56b46ea3886 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/default/sql/update.sql +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/default/sql/update.sql @@ -79,6 +79,20 @@ RESET( FILLFACTOR ); +{% endif %} +{# ======= SET/RESET Toast Tuple Target ========= #} +{% if data.toast_tuple_target and o_data.toast_tuple_target != data.toast_tuple_target %} +ALTER MATERIALIZED VIEW IF EXISTS {{ conn|qtIdent(view_schema, view_name) }} +SET( + TOAST_TUPLE_TARGET = {{ data.toast_tuple_target }} +); + +{% elif data.toast_tuple_target == '' and o_data.toast_tuple_target|default('', 'true') != data.toast_tuple_target %} +ALTER MATERIALIZED VIEW IF EXISTS {{ conn|qtIdent(view_schema, view_name) }} +RESET( + TOAST_TUPLE_TARGET +); + {% endif %} {# ===== Check for with_data property ===== #} {% if data.with_data is defined and o_data.with_data|lower != data.with_data|lower %} From 497228e5d33e9930d910f70ab4c2ede766a5bb16 Mon Sep 17 00:00:00 2001 From: pavanmanishd Date: Sun, 22 Mar 2026 18:03:53 +0530 Subject: [PATCH 2/3] [#9626] Preserve toast_tuple_target on mview recreation --- .../templates/mviews/pg/default/sql/update.sql | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/default/sql/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/default/sql/update.sql index 56b46ea3886..24742ef5e70 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/default/sql/update.sql +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/default/sql/update.sql @@ -27,16 +27,25 @@ ALTER TABLE IF EXISTS {{ conn|qtIdent(view_schema, view_name) }} {% if def and def != o_data.definition.rstrip(';') %} DROP MATERIALIZED VIEW IF EXISTS {{ conn|qtIdent(view_schema, view_name) }}; CREATE MATERIALIZED VIEW IF NOT EXISTS {{ conn|qtIdent(view_schema, view_name) }} -{% if data.fillfactor or o_data.fillfactor %} +{% if data.fillfactor or o_data.fillfactor or data.toast_tuple_target or o_data.toast_tuple_target %} +{% set ns = namespace(add_comma=false) %} WITH( {% if data.fillfactor %} - FILLFACTOR = {{ data.fillfactor }}{% if (data['vacuum_data'] is defined and data['vacuum_data']['changed']|length > 0) %},{% endif %} + FILLFACTOR = {{ data.fillfactor }}{% set ns.add_comma = true %} {% elif o_data.fillfactor %} - FILLFACTOR = {{ o_data.fillfactor }}{% if (data['vacuum_data'] is defined and data['vacuum_data']['changed']|length > 0) %},{% endif %} + FILLFACTOR = {{ o_data.fillfactor }}{% set ns.add_comma = true %} +{% endif %} +{% if data.toast_tuple_target %} +{% if ns.add_comma %}, +{% endif %} TOAST_TUPLE_TARGET = {{ data.toast_tuple_target }}{% set ns.add_comma = true %} +{% elif o_data.toast_tuple_target %} +{% if ns.add_comma %}, +{% endif %} TOAST_TUPLE_TARGET = {{ o_data.toast_tuple_target }}{% set ns.add_comma = true %} {% endif %} {% if data['vacuum_data']['changed']|length > 0 %} -{% for field in data['vacuum_data']['changed'] %} {{ field.name }} = {{ field.value|lower }}{% if not loop.last %}, +{% if ns.add_comma %}, +{% endif %}{% for field in data['vacuum_data']['changed'] %} {{ field.name }} = {{ field.value|lower }}{% if not loop.last %}, {% endif %} {% endfor %} {% endif %} From da672cf64f3ad37c6e6ddf0f380f579b091ab219 Mon Sep 17 00:00:00 2001 From: pavanmanishd Date: Sun, 22 Mar 2026 19:16:11 +0530 Subject: [PATCH 3/3] [#9626] Handle NULL toast_tuple_target reset in mview update --- .../schemas/views/templates/mviews/pg/default/sql/update.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/default/sql/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/default/sql/update.sql index 24742ef5e70..f76008566b8 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/default/sql/update.sql +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/default/sql/update.sql @@ -96,7 +96,7 @@ SET( TOAST_TUPLE_TARGET = {{ data.toast_tuple_target }} ); -{% elif data.toast_tuple_target == '' and o_data.toast_tuple_target|default('', 'true') != data.toast_tuple_target %} +{% elif (data.toast_tuple_target == '' or data.toast_tuple_target == None) and data.toast_tuple_target != o_data.toast_tuple_target %} ALTER MATERIALIZED VIEW IF EXISTS {{ conn|qtIdent(view_schema, view_name) }} RESET( TOAST_TUPLE_TARGET