dolt
dolt copied to clipboard
JSON default column normalization issue causing merge conflict
Customer ran into a schema conflict on a JSON column that defines a default value. The repro is still being investigated.
The specific error message reported by the customer is:
ERROR 1105 (HY000): schema conflict found, merge aborted. Please alter schema to prevent schema conflicts before merging.
schema conflicts for table $table:
different column definitions for our column $col and their column $col
This error is thrown when $col has changed in both branches with differring schema. The type of $col must not have been changed otherwise a new tag would have been generated. The factors that affect column equality are tag, type, primary key membership, column constraints, and the column's default value.
I focused on trying to produce a situation where the column's default value looks identical in the information schema, but is not equivalent in dolt merge.
The first thing I checked was to see if information schema normalized the json value when being printed. But that is not the case. I created a json column with the default of {"hi": 1}
on one branch and {"hi": 1}
(an extra space) on another branch. A conflict was thrown when merged, but the information schema also showed the extra space.
I also investigated how the column defaults are being pulled from postgres, but in the end couldn't find anything obviously wrong.
I am suspicious about some of the customer code that dumps the column default to a json file and the reads it back before running an alter statement. I would like to inspect the exact bytes of the default value on both branches.
Investigating further, the customer's database clearly shows two different values in storage. On one branch the value is ("{\"free\": 1}")
and on another the value is ('{"free": 1}')
.
We iterated on a couple different sql statements on the latest Dolt and version v0.41.5 (which is prior to a recent change in the area) and could not get the value in storage to equal ("{\"free\": 1}")
. The string is formatted to ('{"free": 1}')
in the latest version before being put into storage.
The fix for now, is to re-set the column default.
dolt sql <<SQL
ALTER TABLE $table_name ALTER COLUMN $col_name SET DEFAULT ('{"free": 1}');
SQL
If necessary, a filter-branch query could be useful to rewrite the column default value in storage across all commits in the history.
I'm going to resolve this because it's a compatibnility with really old versions bug.