Skip to content

UpdateColumns can reuse cached update plans across column filters #15

Closed

Description

@akshithg

Summary

DbMap.UpdateColumns can reuse an update plan generated by an earlier Update
or UpdateColumns call with a different ColumnFilter. The filter is part of
the caller's intended write set, so a filtered update can still generate SQL and
bind values for columns rejected by the current filter.

Affected area

Tested on main at c0288adf3b533244dd2bf2fca08ca4418b25d281.

Affected paths:

  • DbMap.Update
  • DbMap.UpdateColumns
  • TableMap.bindUpdate

Reproduction

A focused regression uses a database/sql capture driver. First call Update
for a row with PublicNote, Admin, and Balance. Then call UpdateColumns
with a filter that only accepts PublicNote.

Expected second query:

update "security_rows" set "PublicNote"=? where "ID"=?;

Actual second query:

update "security_rows" set "PublicNote"=?, "Admin"=?, "Balance"=? where "ID"=?;

The second call also binds values for Admin and Balance.

Impact

Consumer code that treats UpdateColumns as an allowed-column boundary can
unintentionally write protected fields after another path has primed the
table's cached update plan.

Root cause

TableMap.bindUpdate caches one updatePlan per table through plan.once.Do.
The cached plan is keyed by the table, not by the supplied ColumnFilter, so
the first call's filter controls later calls.

Suggested fix

Keep cached update plans for unfiltered updates, but build filtered update plans
per call, or key filtered plans by an explicit stable filter identity.

Add regression coverage for full-to-filtered and filtered-to-filtered update
sequences.

Activity

  1. jsha commented on Jun 11, 2026

    @jsha

    Thanks for the report. Since Boulder doesn't use UpdateColumns, and borp is maintained for Boulder's use, I'd like to delete UpdateColumns and the concept of a column filter.

  2. akshithg commented on Jun 11, 2026

    @akshithg
    Author

    That makes sense. I checked Boulder usage and only found UpdateColumns / ColumnFilter in the vendored borp copy, not in Boulder application code.

    I will stop pursuing the cached-plan preservation patch and switch to a smaller removal PR that deletes DbMap.UpdateColumns, Transaction.UpdateColumns, ColumnFilter, and the filter plumbing/tests. I will keep the removal PR linked here.

  3. akshithg commented on Jun 11, 2026

    @akshithg
    Author

    @jsha #19 removes UpdateColumns and the concept of a column filter

  4. added a commit that references this issue on Sep 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions