feat(sidebar): browse stored procedures, functions and triggers with a source viewer - #2386
Merged
Conversation
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Workflows to automatically generate PRs for you. |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
datlechin
force-pushed
the
feat/database-routines-triggers
branch
from
August 22, 2026 20:18
dec31c4 to
662906e
Compare
datlechin
force-pushed
the
feat/database-routines-triggers
branch
from
August 22, 2026 20:20
662906e to
de7bc51
Compare
datlechin
force-pushed
the
feat/database-routines-triggers
branch
from
August 22, 2026 20:30
de7bc51 to
4d377bf
Compare
datlechin
force-pushed
the
feat/database-routines-triggers
branch
from
August 22, 2026 20:46
4d377bf to
b9f241a
Compare
datlechin
force-pushed
the
feat/database-routines-triggers
branch
from
August 22, 2026 21:29
b9f241a to
6ac0ac3
Compare
…s-triggers # Conflicts: # CHANGELOG.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stored procedures, functions and triggers become browsable objects across every engine that has them, and selecting one opens its source in a read-only viewer.
Fixes #2383.
Root cause
The reporter asked for three sections and a viewer. Investigating why they were missing turned up three structural facts rather than one gap:
PluginDatabaseDriverplus aDriverPlugincapability static (fetchTriggers(table:schema:),supportsTriggers). Routines alone were an opt-in side protocol reached byas? PluginProcedureFunctionSupport, which returns[]on a miss. Exactly 2 of 22 drivers conformed, so 20 engines rendered "not implemented" identically to "none exist".PluginRoutineInfohad no schema and no argument signature;PluginTriggerInfohad no owning table. A database-level trigger list was unrepresentable, and the adapter compensated by writingsignature: routine.returnType.SidebarObjectKindwas six cases whose consumers were a hidden binaryisRoutine ? routines : tablessplit.showRoutineDDLdumped DDL into an editable query tab, oneCmd+Returnfrom running it, while the read-only viewer it should have used (DDLTextView) sat one folder away.What changed
PluginKit, additive only.
PluginRoutineInfoandPluginTriggerInfogain the fields needed to address an object, each keeping its shipped initializer verbatim as@_disfavoredOverload(thePluginTableInfoprecedent). Four new defaulted requirements onPluginDatabaseDriver:fetchRoutines(schema:),fetchRoutineDDL(_:),fetchAllTriggers(schema:),fetchTriggerDDL(_:).PluginProcedureFunctionSupportstays declared forever and is never removed; the defaultfetchRoutinesadopts any driver that still conforms to it, so a plugin built against the old protocol keeps working untouched and the app only ever calls the new requirement.One query where there were two.
fetchProceduresandfetchFunctionsare gone from the app-side driver protocol. The tree, the flat root and MCP each issued both; they now issue one catalog read per schema and split by kind.Sidebar.
SidebarObjectKindgains.triggerand acategorythat replaces the booleanisRoutine, so every dispatch site is a three-way switch the compiler checks.visiblegains adeclaredKindsterm that can only add a section, never hide one that has rows, keeping the invariant recorded in that type's own doc comment.Viewer. A new
TabType.objectSourcerendersObjectSourceView, extracted from the chromeTriggerDetailPanealready had rather than built a second time. Read only, with Copy, Export (through the existingSQLFileService, replacing a hand-rolledNSSavePanel), Reload, and an explicit Open in Editor for when you do want to edit. It refetches on restore, so a reopened tab shows the current definition.Engines. PostgreSQL, MySQL, MSSQL, Oracle, Dameng, Teradata, SQLite, LibSQL, Cloudflare D1, Cassandra, ClickHouse, DuckDB, Snowflake and BigQuery. Each engine's per-table and schema-wide trigger reads go through one query builder, so the Structure tab and the sidebar cannot disagree about a table's triggers.
Collateral defects fixed
All five were found while investigating, adversarially verified, and live inside the surface this rewrites:
pg_procon name. Three overloads produced nine identical rows; becauseid's discriminator was the return type, all nine collapsed to one and two overloads were unreachable. Measured on PostgreSQL 17.11, before and after, below.LIMIT 1with no argument predicate, returning an arbitrary overload.SHOW CREATE PROCEDUREresolved against the session database. Browsinganalyticsand openinganalytics.cleanupreturnedapp.cleanup's body with nothing on screen saying so.RoutineInfo.signatureheld the return type, rendered as an argument signature in four surfaces including the documented MCPlist_routinescontract.calculate_age(date) RETURNS integercopied ascalculate_ageinteger.Two more engine bugs went with the rewrite: MySQL triggers lost their
DEFINER,WHENclause and ordering, and Oracle triggers were aCREATE OR REPLACEheader with no body, becauseTRIGGER_BODYwas never selected.Measured, not assumed
scripts/check-postgres-object-queries.shis committed so a future PostgreSQL version re-checks the hand-written catalog SQL instead of trusting the transcription. Against a local PostgreSQL 17.11 with threetransformoverloads, an aggregate and two same-named triggers on different tables:The old query on the same fixture:
The new one returns five rows, three
transformentries each with its own oid and argument list, andpg_get_functiondefaddressed by oid returns the matching overload every time. The aggregate is excluded becausepg_get_functiondefgenuinely raises on one (ERROR: "my_sum" is an aggregate function), which would otherwise fail the whole listing.Verification
verify.sh buildverify.sh test(15 suites)verify.sh lint TablePro Plugins TableProTests Packagesverify.sh abi <merge-base>scripts/check-postgres-object-queries.shshellcheck --severity=warningon the new scriptverify.sh plugins(theAllPluginsaggregate) cannot run on this machine: the vendored oracle-nio fork's@TaskLocalmacro fails to expand locally, which is a pre-existing toolchain issue unrelated to this change. Every driver plugin this PR touches was compiled individually through its own scheme instead. CI'sAllPluginsstep covers the aggregate.Not done, and why
SHOW FUNCTIONS FROMerrors on connectors that cannot store them, which would show a failed Functions section on every schema. Redis functions are node-local libraries needing cluster fan-out and a RESP map parse. SurrealDB'sINFO FOR DBreturns a nested object the driver's result shape does not currently carry. Shipping a section that errors is worse than not offering one; each is a small follow-up.DamengPluginDriver+Routines.swiftandTeradataObjectQueries.swift, and a failure surfaces as a visible error row rather than silence.docs/images/routines-triggers-sidebar{,-dark}.pngare neutral 1560x960 fills at the standard size so the page renders. A real capture needs a PostgreSQL connection created through the UI, which I could not drive in this environment. Please re-capture before the docs deploy.TableProUITestscoverage. The flow needs a live server with routines in it; the bundled Chinook sample has neither procedures nor triggers, so there is nothing deterministic to drive.Self-review
A
code-reviewpass over the finished diff found fifteen defects, all fixed before this commit. The ones worth naming:project.ymlwith an over-broad line sort, soxcodegencould not parse it. My earlier builds were silently using a stale generated project because I ranverify.sh generatewith its output discarded and only checked the build. Restored and re-applied as four targeted lines, then every verification step above re-ran against a correctly generated project.PluginRoutineInfo.identity, whichRoutineInfo.idfolds in. Editing the object made the viewer's resolve-by-id miss and serve stale text forever, and it wrote kilobytes of SQL into the tab-state JSON.identityis now addressing only; a newdefinitionfield carries the body.PostgreSQLObjectQueriespicked the pre-11proisaggbranch when the server version was unknown, and libpq reports 0 for a handle it has not connected. An unknown version now reads as modern.TABLE_OWNER, which is the schema of the table a trigger fires on, not the schema that owns it. NowOWNERfor a schema browse andTABLE_OWNERfor a per-table fetch.LISTAGG, which raises ORA-01489 past 4000 bytes and would fail the whole listing over one wide signature. Dropped: Oracle only overloads inside a package, so a standalone routine needs no signature to be identified.supportsDatabaseTriggerBrowse, which gates the query and never the display.WindowTitleResolverhad no.objectSourcearm, so the window titlebar read "SQL Query" while its tab read "Procedure: ...".SidebarObjectListPresentationstill decided emptiness from tables and routines only, hiding the whole tree for a schema whose only objects are triggers.check-postgres-object-queries.shhad agrep -qunderpipefail, so psql died of SIGPIPE and the guarded assertion silently never ran.PluginKit ABI
Additive. New defaulted protocol requirements, new stored properties on two non-
@frozentransfer structs with both shipped initializers kept byte-identical under@_disfavoredOverload, two newDriverPluginstatics with defaults, and three new public types. No published requirement was removed and no existing signature changed, so nocurrentPluginKitVersionbump and no plugin re-release.Before / After
The change is visible in the sidebar (three new sections) and in what Show DDL opens (a read-only viewer rather than an editable query tab). I was not able to capture screenshots in this environment; see the docs placeholder note above.