matrixorigin / matrixorigin/matrixone
[Bug]: JSON boolean sort and comparison precedence is incorrect
- Dominant language
- Go
- Stars
- 1.9k
- Forks
- 311
- Avg merge
- 1d 3h
- Merged PRs (30d)
- 768
Description
## Description
MatrixOne orders JSON boolean literals below JSON numeric and string scalars. This makes direct JSON comparisons and ascending `ORDER BY` on JSON scalar columns differ from MySQL.
## Environment
- Branch: `main`
- Commit: `17c161a31b47a22e71ca222839143f66717ac365`
- Deployment: local single-CN test service
- Test date: 2026-09-03
- MySQL control: isolated MySQL `8.0.45`
## Steps to reproduce
```sql
SELECT
CAST('true' AS JSON) > CAST('[]' AS JSON) AS bool_gt_array,
CAST('true' AS JSON) > CAST('{}' AS JSON) AS bool_gt_object,
CAST('true' AS JSON) > CAST('\"a\"' AS JSON) AS bool_gt_string,
CAST('true' AS JSON) > CAST('1' AS JSON) AS bool_gt_number;
CREATE TABLE t (id INT PRIMARY KEY, j JSON);
INSERT INTO t VALUES
(1, CAST('null' AS JSON)), (2, CAST('false' AS JSON)),
(3, CAST('true' AS JSON)), (4, CAST('0' AS JSON)),
(5, CAST('\"a\"' AS JSON));
SELECT JSON_TYPE(j) FROM t ORDER BY j, id;
```
## Actual behavior
Three independent MatrixOne executions return:
```text
bool_gt_array bool_gt_object bool_gt_string bool_gt_number
0 0 0 0
NULL
BOOLEAN
BOOLEAN
INTEGER
STRING
```
## Expected behavior
The isolated MySQL 8.0.45 control returns `1,1,1,1` for the pairwise predicates and orders the scalar JSON column as:
```text
NULL
INTEGER
STRING
BOOLEAN
BOOLEAN
```
This matches MySQL JSON type precedence: booleans compare above arrays, objects, strings, and numbers; JSON `null` is lowest. Reference: https://dev.mysql.com/doc/refman/8.0/en/json.html#json-comparison
## Stability and controls
- MatrixOne reproducer: `3/3`.
- MySQL 8.0.45 control: all pairwise predicates return `1`; scalar ordering is as shown above.
- Controls in MatrixOne: `ARRAY > OBJECT`, `OBJECT > STRING`, `STRING > INTEGER`, and `INTEGER > NULL` each return `1`, isolating the problem to the literal/boolean precedence category.
- No DDL or DML persists after the probe.
## Code analysis
`pkg/container/bytejson/types.go` assigns every `LITERAL` (JSON `null`, `false`, and `true`) one `jsonTpOrder` value of `-11`, below numeric and container types. `CompareByteJson` uses that map for cross-type comparisons; it is used by SQL JSON comparisons and the JSON sort comparator in `pkg/sort/sort.go`. This collapses JSON null and JSON booleans into one low-precedence category, whereas MySQL requires JSON null to be lowest and JSON booleans to have high precedence.
## Regression coverage
After the fix, add deterministic JSON comparison/sort coverage for JSON `null`, booleans, numeric scalars, and strings. Include pairwise boolean comparisons with arrays/objects, but do not assert an order for nonscalar `ORDER BY`, because MySQL documents that nonscalar JSON sorting is not supported.
Contributor guide
Assessment
This issue has not been assessed yet.