Skip to content

Fix View/Edit Data crash on a stale/non-filter session transaction object (#9744)#10071

Open
dpage wants to merge 2 commits into
pgadmin-org:masterfrom
dpage:fix/issue-9744-viewdata-restore
Open

Fix View/Edit Data crash on a stale/non-filter session transaction object (#9744)#10071
dpage wants to merge 2 commits into
pgadmin-org:masterfrom
dpage:fix/issue-9744-viewdata-restore

Conversation

@dpage

@dpage dpage commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Summary

initialize_viewdata() restores the filter and data-sorting from any command
object previously stored in session['gridData'] under the same trans_id,
and assumed that object was always a filter-capable (View/Edit Data) command —
accessing old_trans_obj._row_filter / ._data_sorting directly.

That assumption is wrong. The same trans_id may have been used by the Query
Tool (a QueryToolCommand, which does not inherit SQLFilter), or the
session may contain an incompatible object persisted by an older version after
an upgrade. In those cases the attribute access raised AttributeError,
returning a 500 from the endpoint and — in desktop mode, where this runs during
startup — preventing the application from loading at all (issue #9744:
'QueryToolCommand' object has no attribute '_row_filter').

The fix guards the restore with isinstance(old_trans_obj, SQLFilter),
short-circuited before the did/obj_id checks, so a non-filter or stale
object is simply skipped (there is no meaningful filter/sorting to restore from
it anyway).

Changes

  • web/pgadmin/tools/sqleditor/__init__.py — guard the filter/sorting restore
    with an isinstance(..., SQLFilter) check.
  • web/pgadmin/tools/sqleditor/tests/test_view_data_restore_stale_trans.py
    new regression test: seeds a pickled QueryToolCommand under the trans_id
    and asserts initialize/viewdata returns 200.
  • docs/en_US/release_notes_9_16.rst — changelog entry.

Test plan

  • New regression test passes.
  • Reverting the guard makes the new test fail with the exact reported error.
  • PEP8 clean.

Closes #9744

Summary by CodeRabbit

  • Bug Fixes
    • Fixed a crash in View/Edit Data that could prevent the desktop app from loading after upgrading from older versions when session data from prior runs was incompatible.
  • Tests
    • Added a regression test to ensure View/Edit Data no longer fails when encountering stale session data.

…ject

initialize_viewdata restores the filter and data-sorting from any command
object previously stored in session['gridData'] under the same trans_id. It
assumed that object was always a filter-capable (View/Edit Data) command and
accessed old_trans_obj._row_filter / ._data_sorting directly.

That assumption is wrong: the same trans_id may have been used by the Query
Tool (a QueryToolCommand, which does not inherit SQLFilter), or the session
may contain an incompatible object persisted by an older version after an
upgrade. In those cases the attribute access raised AttributeError, returning
a 500 from the endpoint and - in desktop mode, where this runs during startup
- preventing the application from loading at all.

Guard the restore with isinstance(old_trans_obj, SQLFilter) (short-circuited
before the did/obj_id checks) so a non-filter object is simply skipped. Add a
regression test that seeds a pickled QueryToolCommand under the trans_id and
asserts initialize/viewdata returns 200.

Closes pgadmin-org#9744
@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 0192c157-1930-4d0c-aae8-3aad9a66b2c8

📥 Commits

Reviewing files that changed from the base of the PR and between b0e35fd and 65c3027.

📒 Files selected for processing (1)
  • web/pgadmin/tools/sqleditor/tests/test_view_data_restore_stale_trans.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • web/pgadmin/tools/sqleditor/tests/test_view_data_restore_stale_trans.py

Walkthrough

Adds a guard in View/Edit Data initialization to only restore filter/sorting from session objects that are SQLFilter and match the current view, adds a regression test seeding a stale pickled command to session to verify no crash, and documents the bug fix in the 9.16 release notes.

Changes

Stale Transaction Object Fix

Layer / File(s) Summary
Guard validation for session-restored transaction objects
web/pgadmin/tools/sqleditor/__init__.py
The initialize_viewdata function validates that a restored command_obj is an instance of SQLFilter and that its did/obj_id match the current request before restoring _row_filter and _data_sorting; incompatible objects are skipped.
Regression test for stale transaction objects
web/pgadmin/tools/sqleditor/tests/test_view_data_restore_stale_trans.py
Test class seeds the session with a pickled QueryToolCommand lacking _row_filter, posts to the View/Edit Data initialize endpoint using the seeded trans_id, and asserts HTTP 200; includes DB setup and teardown.
Release notes for bug fix
docs/en_US/release_notes_9_16.rst
Adds a Bug fixes entry (#9744) documenting the View/Edit Data crash scenario when non-filter-capable transaction objects persist in the session after upgrade.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main fix: preventing a crash in View/Edit Data when session contains non-filter transaction objects.
Linked Issues check ✅ Passed The PR successfully addresses issue #9744 by adding an isinstance(SQLFilter) guard to prevent AttributeError when restoring filter/sorting from incompatible command objects, includes a regression test, and updates release notes.
Out of Scope Changes check ✅ Passed All changes are directly scoped to fixing issue #9744: core fix in sqleditor/init.py, regression test, and documentation update. No extraneous modifications detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
web/pgadmin/tools/sqleditor/tests/test_view_data_restore_stale_trans.py (1)

75-76: ⚡ Quick win

Use parameterized query instead of string formatting.

While self.table is constructed from a UUID and not user-controlled, it's still better practice to use parameterized queries to avoid SQL injection patterns being flagged by static analysis and to set a good example in test code.

♻️ Proposed fix
-        pg_cursor.execute("""Select oid FROM pg_catalog.pg_class WHERE
-         relname = '%s' AND relkind IN ('r','s','t')""" % self.table)
+        pg_cursor.execute("""Select oid FROM pg_catalog.pg_class WHERE
+         relname = %s AND relkind IN ('r','s','t')""", (self.table,))
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/pgadmin/tools/sqleditor/tests/test_view_data_restore_stale_trans.py`
around lines 75 - 76, Replace the string-formatted SQL passed to
pg_cursor.execute with a parameterized query: call pg_cursor.execute with a SQL
string containing a placeholder for relname and pass self.table as a separate
parameter tuple (so the DB driver binds it), e.g. use "SELECT oid FROM
pg_catalog.pg_class WHERE relname = %s AND relkind IN ('r','s','t')" and supply
(self.table,) as the params for the pg_cursor.execute call to avoid inline
string formatting.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@web/pgadmin/tools/sqleditor/tests/test_view_data_restore_stale_trans.py`:
- Around line 75-76: Replace the string-formatted SQL passed to
pg_cursor.execute with a parameterized query: call pg_cursor.execute with a SQL
string containing a placeholder for relname and pass self.table as a separate
parameter tuple (so the DB driver binds it), e.g. use "SELECT oid FROM
pg_catalog.pg_class WHERE relname = %s AND relkind IN ('r','s','t')" and supply
(self.table,) as the params for the pg_cursor.execute call to avoid inline
string formatting.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a4de1cb5-8a59-4572-a7e3-89ad729c27c7

📥 Commits

Reviewing files that changed from the base of the PR and between 04fa05c and b0e35fd.

📒 Files selected for processing (3)
  • docs/en_US/release_notes_9_16.rst
  • web/pgadmin/tools/sqleditor/__init__.py
  • web/pgadmin/tools/sqleditor/tests/test_view_data_restore_stale_trans.py

The regression test created its table with a fixed 'table_pk' primary key
constraint name, which collides with the same name used by TestViewData in
this package when the full suite runs against one database. That made the
CREATE TABLE fail in CI (table not found -> IndexError on the OID lookup).
Let PostgreSQL auto-name the primary key instead.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes a crash in View/Edit Data initialization when session['gridData'] contains a stale/non-filter command object under the same trans_id (e.g., a QueryToolCommand), preventing AttributeError and a resulting 500 (notably breaking desktop startup after upgrades).

Changes:

  • Guard filter/sorting restoration in initialize_viewdata() with isinstance(old_trans_obj, SQLFilter) to skip incompatible session objects.
  • Add a regression test that seeds a pickled QueryToolCommand into session['gridData'] and asserts initialization succeeds.
  • Add a release note entry for issue #9744.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
web/pgadmin/tools/sqleditor/init.py Prevents View/Edit Data from crashing when restoring state from a non-filter/stale session transaction object.
web/pgadmin/tools/sqleditor/tests/test_view_data_restore_stale_trans.py Adds regression coverage for stale session transaction objects (Query Tool → View/Edit Data).
docs/en_US/release_notes_9_16.rst Documents the fix in the 9.16 release notes.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 331 to 333
command_obj.set_filter(old_trans_obj._row_filter)
command_obj.set_data_sorting(
dict(data_sorting=old_trans_obj._data_sorting), True)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9.13 does not start on Windows 11

2 participants