From fdfd6ffb24eb56ca535cd5d31db6012baf70d80f Mon Sep 17 00:00:00 2001 From: Kundan Sable Date: Thu, 23 Jul 2026 12:11:12 +0530 Subject: [PATCH] fix: return Response as-is and pass conn when expanding a trigger's function Expanding a Trigger node under a Table to view its function threw 'Response' object is not iterable, crashing the tree. get_children_nodes() can legitimately return a Flask Response instead of a list (e.g. gone("Could not find the specified trigger function") when the trigger's function has no matching row in the trigger-function node query, as happens for a genuine internal- language function such as suppress_redundant_updates_trigger). NodeView.children() / PGChildNodeView.children() unconditionally sorted whatever get_children_nodes() returned, crashing on a Response instead of passing it through. Separately, TriggerView.get_children_nodes() rendered the trigger- function node.sql template (which quotes fnid via qtLiteral(conn)) without passing conn into the template context. This call site predates qtLiteral requiring a connection; after qtLiteral was hardened in 658bb585d to raise ValueError instead of silently degrading when conn is missing, this broke node.sql rendering for every trigger, not just the internal-language case. Fix both: check isinstance(children, flask.Response) in children() before sorting/iterating and return it as-is, and pass conn=self.conn into the node.sql render call, matching every other render_template call site in the file. Fixes #10117 --- .../schemas/tables/triggers/__init__.py | 3 ++- web/pgadmin/browser/utils.py | 16 +++++++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/triggers/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/triggers/__init__.py index 055607479eb..5e74f17f72d 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/triggers/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/triggers/__init__.py @@ -322,7 +322,8 @@ def get_children_nodes(self, manager, **kwargs): sql = render_template("/".join( [self.trigger_function_template_path, self._NODE_SQL]), scid=trigger_function_schema_oid, - fnid=rset['rows'][0]['tfuncoid'] + fnid=rset['rows'][0]['tfuncoid'], + conn=self.conn ) status, res = self.conn.execute_2darray(sql) if not status: diff --git a/web/pgadmin/browser/utils.py b/web/pgadmin/browser/utils.py index 7acb0afde80..6c0a71b984d 100644 --- a/web/pgadmin/browser/utils.py +++ b/web/pgadmin/browser/utils.py @@ -343,6 +343,12 @@ def children(self, *args, **kwargs): """Build a list of treeview nodes from the child nodes.""" children = self.get_children_nodes(*args, **kwargs) + # get_children_nodes may return a Flask Response (e.g. an error + # response) instead of a list of nodes. In that case return it as-is + # rather than trying to iterate/sort it. + if isinstance(children, flask.Response): + return children + # Return sorted nodes based on label return make_json_response( data=sorted( @@ -453,10 +459,18 @@ def children(self, **kwargs): ) ) + children = self.get_children_nodes(manager, **kwargs) + + # get_children_nodes may return a Flask Response (e.g. an error + # response) instead of a list of nodes. In that case return it as-is + # rather than trying to iterate/sort it. + if isinstance(children, flask.Response): + return children + # Return sorted nodes based on label return make_json_response( data=sorted( - self.get_children_nodes(manager, **kwargs), + children, key=lambda c: c['label'] ) )