Skip to content

feat(parser): support MySQL REPLACE syntax variants - #25083

Merged
mergify[bot] merged 8 commits into
matrixorigin:mainfrom
ck89119:issue-24947-main
Jul 1, 2026
Merged

feat(parser): support MySQL REPLACE syntax variants#25083
mergify[bot] merged 8 commits into
matrixorigin:mainfrom
ck89119:issue-24947-main

Conversation

@ck89119

@ck89119 ck89119 commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

What type of PR is this?

  • API-change
  • BUG
  • Improvement
  • Documentation
  • Feature
  • Test and CI
  • Code Refactoring

Which issue(s) this PR fixes:

issue #24947

What this PR does / why we need it:

Accept the MySQL-compatible REPLACE forms that MatrixOne previously rejected at the parser:

  • REPLACE INTO dst TABLE src — equivalent to REPLACE INTO dst SELECT * FROM src (MySQL 8.0.19+)
  • REPLACE LOW_PRIORITY INTO ...
  • REPLACE DELAYED INTO ...

Implementation notes

  • The priority modifiers (LOW_PRIORITY / DELAYED, and also HIGH_PRIORITY) are parsed and ignored, since MatrixOne has no corresponding scheduling behavior. The resulting statement is identical to a plain REPLACE — same execution path and semantics. This matches MySQL 8.0, where DELAYED is downgraded to a plain REPLACE (MatrixOne simply does not emit the deprecation warning).
  • The TABLE src source form is rewritten in the grammar into a SELECT * over the source table, reusing the existing REPLACE ... SELECT execution path. No AST struct or planner changes are required.
  • This is a parser-only change. mysql_sql.go is regenerated from mysql_sql.y via make; the large generated diff is the goyacc state-table renumbering caused by the two new grammar rules (no new shift/reduce conflicts).

Tests

  • Parser round-trip unit tests in mysql_sql_test.go for the TABLE form and all three priority modifiers.
  • End-to-end BVT cases in test/distributed/cases/dml/replace/ (verified 201/201, 100%).

Parent issue: #24918

Accept the MySQL-compatible REPLACE forms that MatrixOne previously
rejected at the parser:

- `REPLACE INTO dst TABLE src` (equivalent to `REPLACE INTO dst SELECT * FROM src`)
- `REPLACE LOW_PRIORITY INTO ...`
- `REPLACE DELAYED INTO ...`

The priority modifiers (LOW_PRIORITY / DELAYED, plus HIGH_PRIORITY) are
parsed and ignored, since MatrixOne has no corresponding scheduling
behavior; the resulting statement is identical to a plain REPLACE. The
TABLE source form is rewritten into a `SELECT *` over the source table,
reusing the existing `REPLACE ... SELECT` execution path, so no AST or
planner changes are needed.

Adds parser round-trip unit tests and end-to-end BVT cases.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@qodo-code-review

Copy link
Copy Markdown

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

# Conflicts:
#	pkg/sql/parsers/dialect/mysql/mysql_sql.go

@XuPeng-SH XuPeng-SH left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I found one blocker here.

This parser only accepts the bare TABLE table_name form (with or without a target column list), but MySQL TABLE syntax also supports ORDER BY and LIMIT, and REPLACE ... TABLE ... inherits that source form. So valid MySQL statements such as REPLACE INTO dst TABLE src ORDER BY id LIMIT 1 will still fail to parse.

The current implementation rewrites directly to tree.NewSelect(makeSelectStarFromTable(...), nil, nil), so there is nowhere to preserve ORDER BY / LIMIT even if we want to. That makes the new compatibility support incomplete.

Suggested fix:

  1. parse a reusable TABLE source form with optional ORDER BY / LIMIT;
  2. thread those clauses into the rewritten tree.NewSelect(...);
  3. add parser + BVT coverage for REPLACE ... TABLE ... ORDER BY ... LIMIT ....

I re-checked the rest of the patch and did not find another substantive code issue beyond this gap.

@XuPeng-SH XuPeng-SH left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I re-reviewed the current head from MySQL compatibility, parser-generation consistency, mergeability, and unhappy-path/resource-risk angles.

The previous blockers are addressed:

  • REPLACE ... (cols) TABLE src is now supported and covered.
  • REPLACE ... TABLE src ORDER BY ... LIMIT/OFFSET ... is now preserved through the TABLE-to-SELECT rewrite and covered.
  • REPLACE HIGH_PRIORITY is rejected via the REPLACE-specific priority rule and an invalid parser test.
  • The checked-in generated parser is consistent with mysql_sql.y.

Local checks I ran:

git diff --check origin/main...HEAD
make -B -C pkg/sql/parsers/dialect/mysql mysql_sql.go
git diff --exit-code -- pkg/sql/parsers/dialect/mysql/mysql_sql.go pkg/sql/parsers/dialect/mysql/mysql_sql.y
go test ./pkg/sql/parsers/dialect/mysql -run 'TestValid|TestInvalid|TestDebug' -count=1\ngo test ./pkg/sql/parsers/dialect/mysql -count=1\ngo test ./pkg/sql/parsers -count=1\ngit merge-tree --write-tree origin/main HEAD\n```\n\nNo further code issue found. Non-blocking: the PR description still appears to contain stale wording from the earlier `HIGH_PRIORITY` iteration, so it would be clearer to update that before merge.

@mergify

mergify Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Merge Queue Status

  • Entered queue2026-07-01 07:46 UTC · Rule: main · triggered by rule Automatic queue on approval for main
  • Checks passed · in-place
  • Merged2026-07-01 08:59 UTC · at 7b0a098d50e980b36e1b77029f93c727af749510 · squash

This pull request spent 1 hour 12 minutes 42 seconds in the queue, including 1 hour 12 minutes 24 seconds running CI.

Required conditions to merge
  • #approved-reviews-by >= 1 [🛡 GitHub branch protection]
  • #review-threads-unresolved = 0 [🛡 GitHub branch protection]
  • github-review-decision = APPROVED [🛡 GitHub branch protection]
  • any of [🛡 GitHub branch protection]:
    • check-success = Matrixone Compose CI / multi cn e2e bvt test docker compose(PESSIMISTIC)
    • check-neutral = Matrixone Compose CI / multi cn e2e bvt test docker compose(PESSIMISTIC)
    • check-skipped = Matrixone Compose CI / multi cn e2e bvt test docker compose(PESSIMISTIC)
  • any of [🛡 GitHub branch protection]:
    • check-success = Matrixone Standlone CI / Multi-CN e2e BVT Test on Linux/x64(LAUNCH, PROXY)
    • check-neutral = Matrixone Standlone CI / Multi-CN e2e BVT Test on Linux/x64(LAUNCH, PROXY)
    • check-skipped = Matrixone Standlone CI / Multi-CN e2e BVT Test on Linux/x64(LAUNCH, PROXY)
  • any of [🛡 GitHub branch protection]:
    • check-success = Matrixone Standlone CI / e2e BVT Test on Linux/x64(LAUNCH, PESSIMISTIC)
    • check-neutral = Matrixone Standlone CI / e2e BVT Test on Linux/x64(LAUNCH, PESSIMISTIC)
    • check-skipped = Matrixone Standlone CI / e2e BVT Test on Linux/x64(LAUNCH, PESSIMISTIC)
  • any of [🛡 GitHub branch protection]:
    • check-success = Matrixone CI / UT Test on Ubuntu/x86
    • check-neutral = Matrixone CI / UT Test on Ubuntu/x86
    • check-skipped = Matrixone CI / UT Test on Ubuntu/x86
  • any of [🛡 GitHub branch protection]:
    • check-success = Matrixone Compose CI / multi cn e2e bvt test docker compose(Optimistic/PUSH)
    • check-neutral = Matrixone Compose CI / multi cn e2e bvt test docker compose(Optimistic/PUSH)
    • check-skipped = Matrixone Compose CI / multi cn e2e bvt test docker compose(Optimistic/PUSH)
  • any of [🛡 GitHub branch protection]:
    • check-success = Matrixone Standlone CI / e2e BVT Test on Linux/x64(LAUNCH,Optimistic)
    • check-neutral = Matrixone Standlone CI / e2e BVT Test on Linux/x64(LAUNCH,Optimistic)
    • check-skipped = Matrixone Standlone CI / e2e BVT Test on Linux/x64(LAUNCH,Optimistic)
  • any of [🛡 GitHub branch protection]:
    • check-success = Matrixone Upgrade CI / Compatibility Test With Target on Linux/x64(LAUNCH)
    • check-neutral = Matrixone Upgrade CI / Compatibility Test With Target on Linux/x64(LAUNCH)
    • check-skipped = Matrixone Upgrade CI / Compatibility Test With Target on Linux/x64(LAUNCH)
  • any of [🛡 GitHub branch protection]:
    • check-success = Matrixone Utils CI / Coverage
    • check-neutral = Matrixone Utils CI / Coverage
    • check-skipped = Matrixone Utils CI / Coverage
  • any of [🛡 GitHub branch protection]:
    • check-success = Matrixone CI / SCA Test on Linux/arm64
    • check-neutral = Matrixone CI / SCA Test on Linux/arm64
    • check-skipped = Matrixone CI / SCA Test on Linux/arm64

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

kind/feature size/XXL Denotes a PR that changes 2000+ lines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants