matrixorigin / matrixorigin/matrixone

[Bug]: EXPORT_SET misinterprets DECIMAL and truncates FLOAT bit masks

Open
#28,463 0 comments 0 reactions 1 assignee Claimed by @ck89119 View on GitHub
kind/bug severity/s0
Dominant language
Go
Stars
1.9k
Forks
311
Avg merge
1d 3h
Merged PRs (30d)
768

Description

### Is there an existing issue for the same bug?

- [x] I have checked the existing issues.

- #28210 concerns an INT `number_of_bits` column.
- #28211 concerns zero/negative `number_of_bits` boundaries.
- #28399 covers DECIMAL handling in `MAKE_SET`.

No existing issue covers the first `bits` argument of `EXPORT_SET()`.

### Branch Name

main

### Commit ID

`a9d3b8b857c44f1249e682c91d4d62a914eb7d20`

### Other Environment Information

- Local standalone MatrixOne built from the commit above
- Reference: MySQL 8.3.0

### Actual Behavior

`EXPORT_SET(bits, ...)` uses different and incorrect conversions for DECIMAL, FLOAT/DOUBLE, BOOL, and prepared values.

#### DECIMAL storage is used as an unscaled bit mask

```sql
SELECT
EXPORT_SET(CAST(1.4 AS DECIMAL(4,1)),'Y','N','',4),
EXPORT_SET(CAST(1.40 AS DECIMAL(4,2)),'Y','N','',4),
EXPORT_SET(CAST(1.400 AS DECIMAL(5,3)),'Y','N','',4);
```

```text
MatrixOne: NYYY, NNYY, NNNY
MySQL: YNNN, YNNN, YNNN
```

The MatrixOne results correspond to masks 14, 140, and 1400: the stored DECIMAL coefficients. Merely changing scale changes the selected bits.

#### FLOAT/DOUBLE values are truncated instead of rounded

For DOUBLE values 1.4, 1.5, 1.9, and -1.5, MatrixOne uses masks 1, 1, 1, and -1. MySQL uses 1, 2, 2, and -2. This changes both positive and negative selected-bit results.

#### Boolean inputs are rejected

`EXPORT_SET(TRUE,'Y','N','',4)` is rejected with `invalid argument function export_set`; MySQL returns `YNNN`.

#### Prepared values lose their numeric category

With a fresh server-side statement on every run, DECIMAL/DOUBLE 1.5 produces `YNNN` in MatrixOne and `NYNN` in MySQL. TRUE produces `NNNN` in MatrixOne and `YNNN` in MySQL.

All scalar, column, CTAS, and prepared forms were reproduced three times.

The executor confirms the observed split:

- FLOAT/DOUBLE getters call `int64(val)`, which truncates.
- Other accepted numeric types fall through to `GenerateFunctionFixedTypeParameter[int64]`; DECIMAL storage is then read without applying its scale.
- The checker has no accepted Boolean numeric path.

### Expected Behavior

The first `bits` argument should be converted to an integer numeric value before bit inspection. Equivalent DECIMAL values must be scale-invariant, fractional numeric values must follow MySQL's rounding rule for this argument, and Boolean values must map to 0/1.

### Steps to Reproduce

```sql
CREATE DATABASE codex_export_set_bits;
USE codex_export_set_bits;
CREATE TABLE t(
id INT PRIMARY KEY,
d1 DECIMAL(4,1),
d2 DECIMAL(5,2),
f DOUBLE,
b BOOLEAN
);
INSERT INTO t VALUES
(1,1.4,1.40,1.4,TRUE),
(2,1.5,1.50,1.5,FALSE),
(3,1.9,1.90,1.9,NULL),
(4,-1.5,-1.50,-1.5,NULL);

SELECT id,EXPORT_SET(d1,'Y','N','',4) FROM t ORDER BY id;
SELECT id,EXPORT_SET(d2,'Y','N','',4) FROM t ORDER BY id;
SELECT id,EXPORT_SET(f,'Y','N','',4) FROM t ORDER BY id;
SELECT id,EXPORT_SET(b,'Y','N','',4) FROM t ORDER BY id;
```

### Controls

- Integer masks 0, 1, 2, 3, and -1 agree with MySQL.
- NULL propagation remains correct.
- `number_of_bits` behavior is not part of this issue and remains tracked by #28210/#28211.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.