Skip to content

fix: restore v19 per-shard UPDATE+LIMIT behavior - #837

Closed
sbaker617 wants to merge 3 commits into
slack-22.0from
restore-non-schema-tracking-vtgate-v22
Closed

fix: restore v19 per-shard UPDATE+LIMIT behavior#837
sbaker617 wants to merge 3 commits into
slack-22.0from
restore-non-schema-tracking-vtgate-v22

Conversation

@sbaker617

@sbaker617 sbaker617 commented Apr 6, 2026

Copy link
Copy Markdown

What's this?

Restores v19 per-shard LIMIT behavior for all UPDATE ... LIMIT N queries. v22 introduced a two-phase DMLWithInput plan (SELECT PKs then UPDATE by PK) for UPDATE+LIMIT, but we don't want that — v19's per-shard LIMIT is the expected behavior for our fork (with MULTI_SHARD_AUTOCOMMIT=1 / ALLOW_SCATTER).

How it works

v22 changed UPDATE+LIMIT to create a separate Limit operator above the Route, which triggers the dmlWithInput phase requiring PrimaryKey metadata. This change unconditionally reverts to v19's approach: embed the LIMIT directly on the Update operator so it pushes under the Route. No DMLWithInput, no PK select-then-update — LIMIT applies per-shard.

This means UPDATE ... LIMIT 10 across 10 shards may update up to 100 rows total (10 per shard), which is the intended behavior.

Changes

  • update.go: Add Limit field to Update struct, embed LIMIT unconditionally (no separate Limit operator)
  • SQL_builder.go: Include embedded Limit in generated SQL
  • unknown_schema_cases.json: 2 regression tests (UPDATE+LIMIT without PK)
  • dml_cases.json: Updated 2 existing test expectations
  • dml_test.go: Updated e2e tests — TestUniqueLookupDuplicateEntries error expectation, skip TestUpdateWithLimit (validates v22 total-count LIMIT)

Root cause

PR vitessio#15107 replaced Update's direct Limit field with a separate Limit operator and renamed deleteWithInputdmlWithInput (now covering UPDATEs). The Limit operator between Update and Route prevents tryPushUpdate from pushing Update under Route, forcing the dmlWithInput phase which requires PK.


Most of this was written by Claude Code — I provided direction and review.

v22 changed UPDATE+LIMIT to use a two-phase DMLWithInput plan (SELECT
PKs first, then UPDATE by PK) which requires schema tracking to know
the PrimaryKey columns. This broke UPDATE+LIMIT on tables without
schema tracking, returning VT09015 instead of planning the query.

This restores the v19 behavior conditionally: when PrimaryKey info is
not available, the LIMIT is embedded directly on the Update operator
(as v19 did) so it pushes under the Route without needing DMLWithInput.
When PrimaryKey IS available, the v22 DMLWithInput path is preserved.

Root cause: PR vitessio#15107 replaced the Update struct's direct Limit field
with a separate Limit operator, and renamed the deleteWithInput phase
to dmlWithInput (now covering UPDATEs too). The separate Limit operator
between Update and Route prevents tryPushUpdate from pushing the Update
under the Route, forcing the dmlWithInput phase which requires PK.

Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
Signed-off-by: Steve Baker <s.baker@slack-corp.com>
@github-actions github-actions Bot added this to the v22.0.4 milestone Apr 6, 2026
@codecov-commenter

codecov-commenter commented Apr 6, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 69.52%. Comparing base (b1ab347) to head (bd9bc78).
⚠️ Report is 67 commits behind head on slack-22.0.

Additional details and impacted files
@@              Coverage Diff               @@
##           slack-22.0     #837      +/-   ##
==============================================
+ Coverage       67.53%   69.52%   +1.99%     
==============================================
  Files            1600     1606       +6     
  Lines          261782   214260   -47522     
==============================================
- Hits           176786   148964   -27822     
+ Misses          84996    65296   -19700     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@sbaker617
sbaker617 marked this pull request as ready for review April 6, 2026 22:23
@sbaker617
sbaker617 requested a review from a team as a code owner April 6, 2026 22:23
@sbaker617
sbaker617 requested a review from tanjinx April 6, 2026 22:23
sbaker617 and others added 2 commits April 6, 2026 19:06
Switch from conditional (PK check) to unconditional v19-style LIMIT
embedding on the Update operator. This avoids the DMLWithInput
two-phase plan (SELECT PKs then UPDATE) for all UPDATE+LIMIT queries,
matching v19 per-shard LIMIT semantics.

Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
Signed-off-by: Steve Baker <s.baker@slack-corp.com>
- TestUniqueLookupDuplicateEntries: vindex update without ORDER BY now
  errors at plan time (VT12001) instead of execution time
- TestUpdateWithLimit: skip, validates v22 DMLWithInput total-count
  LIMIT which our fork doesn't use

Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
Signed-off-by: Steve Baker <s.baker@slack-corp.com>
@sbaker617 sbaker617 changed the title fix: restore v19 UPDATE+LIMIT behavior without schema tracking fix: restore v19 per-shard UPDATE+LIMIT behavior Apr 6, 2026
@github-actions

github-actions Bot commented May 7, 2026

Copy link
Copy Markdown

This PR is being marked as stale because it has been open for 30 days with no activity. To rectify, you may do any of the following:

  • Push additional commits to the associated branch.
  • Remove the stale label.
  • Add a comment indicating why it is not stale.

If no action is taken within 7 days, this PR will be closed.

@github-actions github-actions Bot added the Stale label May 7, 2026
@github-actions

Copy link
Copy Markdown

This PR was closed because it has been stale for 7 days with no activity.

@github-actions github-actions Bot closed this May 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants