cherry-pick, revert and rebase discard the schema-merge actions: phantom unresolvable conflict on every DDL x DDL pair
- Dominant language
- C
- Stars
- 268
- Forks
- 18
- Avg merge
- 2h 27m
- Merged PRs (30d)
- 447
Description
Found in a full-repo review at `0ba280f06f`.
`dolt_cherry_pick`, `dolt_revert` and `dolt_rebase` report a conflict that has no rows, on any commit that changes columns when the target branch also changed columns. `dolt_merge` of the same two commits succeeds, and so does Dolt.
Setup: `base` = `t(id,a)`; branch `f` = `ADD COLUMN c INT DEFAULT 5` + `UPDATE t SET c=42 WHERE id=1`; `main` = `ADD COLUMN d INT DEFAULT 1`.
```
-- DoltLite, dolt_merge('f'): succeeds
cols: id,a,d,c
rows: 1,1,1,42 / 2,2,1,5
-- DoltLite, dolt_cherry_pick(fc) -- the same two commits:
Error: cannot merge: conflicts detected, autocommit transaction rolled back.
```
Inside a transaction the conflict turns out to be empty, and there is no way forward:
```
BEGIN;
SELECT dolt_cherry_pick(fc);
-- Error: Cherry-pick has 1 conflict(s). Resolve and then commit with dolt_commit.
SELECT "table"||'/'||num_conflicts FROM dolt_conflicts; -- t/0
SELECT count(*) FROM dolt_conflicts_t; -- 0
SELECT count(*) FROM dolt_schema_conflicts; -- 0
SELECT dolt_commit('-A','-m','try');
-- Error: cannot commit: unresolved schema conflicts. Abort the merge, align the
-- schemas on one side, then rerun the merge.
```
There is nothing to resolve and nothing to align, so `ROLLBACK` is the only exit.
Dolt 2.3.1 cherry-picks the same commit cleanly and produces exactly what DoltLite's own merge produces:
```
CALL dolt_cherry_pick('ev04raqufmi2j3u6hhe5t8hhddbrcd72');
hash,data_conflicts,schema_conflicts,constraint_violations
7m7cs109hfflbhu7gsemtmoenk2q3sq4,0,0,0
id,a,d,c
1,1,1,42
2,2,1,5
```
## Scope
Cherry-pick, source action × target action. Every DDL × DDL pair fails; every DDL × row-change pair is fine:
```
cp\target ADDCOL DROPCOL RENCOL ROWONLY
ADDCOL CONFLICT CONFLICT CONFLICT ok
DROPCOL CONFLICT CONFLICT CONFLICT ok
RENCOL CONFLICT CONFLICT CONFLICT ok
```
A second manifestation of the same cause: `dolt_revert` of a `CREATE INDEX` commit, where a later commit renamed the indexed column, reports `nothing to commit` and leaves the index in place. Dolt reverts it.
A third: cherry-picking a `CREATE INDEX` onto a branch that renamed the indexed column hits the decreed index refusal (`index 'ia' covers column 'a' ... which the other branch renamed`), while `dolt_merge` of the same two commits succeeds and keeps the index.
## Cause
`src/doltlite_cherry_pick.c:191` and `src/doltlite_rebase.c:1003` call `doltliteMergeCatalogs` with NULL schema-action out-params (`dolt_revert` reaches the same helper via `src/doltlite_revert.c:244`):
```c
rc = doltliteMergeCatalogs(db, ancCatHash, ourCatHash, theirCatHash,
&mergedCatHash, pnConflicts, &zMergeErr, 0, 0,
bPreferOurMaster, 0,
&azReindex, &nReindex,
&azRebuild, &nRebuild);
```
`tryResolveSchemaDivergence` (`src/doltlite_merge.c:803` and `:812`) computes the add/drop/rename-column actions and then discards them when those out-params are NULL, while still treating the divergence as resolved and setting `*pSkipRowMerge`:
```c
if( nAddCols==0 && resolvedDivergence
&& ppSchemaActions && pnSchemaActions ){
rc = recordSchemaAddColumns(...);
```
Only the branch-merge path applies them, at `doltliteApplyMergeSchemaActions` (`src/doltlite_merge_cmd.c:754`, called from `mergeRefInstallMergedCatalog` at `:926`). So the rows are relaid out for a merged schema the live catalog never adopts, and the leftover divergence surfaces as a schema conflict with no rows behind it.
## Fix
Thread the real action out-params through the cherry-pick / revert / rebase paths and apply them with the merge path's own applier. `doltliteApplyMergeSchemaActions` is `static` with a self-contained signature — `(db, ancCatHash, theirCatHash, actions, nActions, *mergedCatHash, **err)` — so this is plumbing rather than a redesign: un-`static` it (or move it into the shared merge internals) and call it from the one place that currently has no equivalent.
## Test gap
`test/oracle_schema_change_cherry_pick_revert_test.sh` has 12 scenarios and in **every one the target branch performs no DDL**. The whole broken quadrant is outside the suite named for this feature. The fix wants the 3×4 matrix above, not another example.
Contributor guide
No contributing guide indexed for this repository
Research direction
Start with the cherry-pick, rebase, and revert call sites in src/doltlite_cherry_pick.c, src/doltlite_rebase.c, and src/doltlite_revert.c, then trace doltliteMergeCatalogs and doltliteApplyMergeSchemaActions in src/doltlite_merge.c and src/doltlite_merge_cmd.c. Extend test/oracle_schema_change_cherry_pick_revert_test.sh with the 3×4 DDL matrix and verify cherry-pick, revert, and rebase produce no phantom conflicts and match merge results.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- c, sqlite
- Domain
- databases
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 64/100