From 8e95bb45e1748af8fcaaa1b42a5195bd7387e400 Mon Sep 17 00:00:00 2001 From: Kundan Sable Date: Wed, 22 Jul 2026 14:20:00 +0530 Subject: [PATCH] fix: exclude non-editable/alias columns from Query Tool row UPDATE The added (INSERT) branch of save_changed_data() already filtered out columns that aren't backed by a real table column (added for #9939 / #10015), but the updated (UPDATE) branch did not. Editing a row that includes an aliased/expression column (e.g. first_name || ' ' || last_name AS the_name) sent that alias into the generated UPDATE's SET clause, which fails with "column ... does not exist" even though the grid already marks the column read-only. Apply the same editable-columns guard to the updated branch, and skip the row entirely if nothing editable remains after filtering. Fixes #10103 --- .../tools/sqleditor/utils/save_changed_data.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/web/pgadmin/tools/sqleditor/utils/save_changed_data.py b/web/pgadmin/tools/sqleditor/utils/save_changed_data.py index 78776697ff3..3965daa9aa9 100644 --- a/web/pgadmin/tools/sqleditor/utils/save_changed_data.py +++ b/web/pgadmin/tools/sqleditor/utils/save_changed_data.py @@ -177,6 +177,21 @@ def save_changed_data(changed_data, columns_info, conn, command_obj, list_of_sql[of_type] = [] for each_row in changed_data[of_type]: data = changed_data[of_type][each_row]['data'] + # Drop any column that isn't a real editable column of the + # underlying table (e.g. an expression/alias column such as + # `first_name || ' ' || last_name as the_name`). Such columns + # carry the read-only lock icon in the grid, but without this + # guard the rendered UPDATE references a non-existent column + # and Postgres rejects the change. Issue #10103. + data = { + k: v for k, v in data.items() + if k in columns_info and + columns_info[k].get('is_editable', True) + } + # Nothing editable left to persist for this row, skip it so we + # don't render an invalid `SET` clause. + if not data: + continue pk_escaped = { pk: pk_val.replace('%', '%%') if hasattr( pk_val, 'replace') else pk_val