Skip to main content

Module edit

Module edit 

Source
Expand description

Cell-level row editing for the explorer.

Sprint 14 model: editing is enabled only on tabs opened from the schema browser (“double-click a relation”), where the explorer knows the (schema, table) and the auto-generated SELECT carries ctid AS __pg_rowid__. The UI extracts that hidden column to use as the row identifier for UPDATEs.

§Why ctid

ctid is Postgres’s internal per-row identifier on heap tables. It is:

  • Always unique within a relation (so the WHERE matches at most one row).
  • Always present (no PK assumption needed).
  • Mutated on every UPDATE — which gives us free optimistic locking. If two clients race to edit the same row, the second UPDATE matches zero rows and we surface “row no longer there” instead of clobbering.

Limitation: views, materialized views, and foreign tables don’t have a meaningful ctid. We don’t try to edit them; the UI gates editing on the relation kind already.

§Type binding

Values cross the FFI as String. We bind $1 as text and cast it to the column’s declared type server-side: SET "col" = $1::int4. Postgres’s text-input parser handles the heavy lifting (timestamps, arrays, ranges, JSON). Setting NULL skips the parameter entirely since ''::int4 would fail.

Identifiers are quoted defensively (PG allows mixed-case and reserved-word identifiers; an unquoted Order would target a lowercase order). Type names from pg_type.typname are also quoted to be safe — most don’t need it but the cost is zero.

Structs§

InsertColumnInput
One column’s worth of input for an INSERT. Caller emits a list of these for the columns it wants to set explicitly; columns not in the list are left to the server’s DEFAULT (which honors pg_attrdef-defined defaults, sequences, generated values, etc).
InsertedRow
UpdateOutcome

Functions§

delete_rows
Delete one or more rows identified by their ctids. Returns the number of rows actually deleted (callers compare against the requested count to surface “some rows were already gone” — the same optimistic-locking semantic as cell UPDATEs).
insert_row
Insert one row, returning the requested columns for the new row.
update_cell
Issue a single-cell UPDATE. new_value: None means SET NULL. column_type is the column’s pg_type.typname (e.g. int4, timestamptz); used for the server-side text→typed cast.