matrixorigin / matrixorigin/matrixone

[Bug]: prepared SET inserts reject label strings as uint64

Open
#27,331 2 comments 0 reactions 1 assignee Claimed by @jiangxinmeng1 View on GitHub
kind/bug needs-triage
Dominant language
Go
Stars
1.9k
Forks
311
Avg merge
1d 3h
Merged PRs (30d)
768

Description

## Description

Prepared INSERTs into a MySQL `SET` column reject normal label strings such as
`a` or `a,b` by trying to convert them to an unsigned integer. Numeric SET
indexes still work. Literal SQL, Connector/J client-prepared statements, and
MySQL server-prepared statements accept the same label values.

The failure affects both MySQL binary-protocol prepared statements and SQL
`PREPARE` / `EXECUTE`.

## Environment

- Branch: `main`
- Commit: `47e022e10f2dbdf5f6b440417f8be80908027e63`
- Deployment: local `mo-service`, 1 Log / 1 TN / 1 CN
- Connector/J: 8.0.33 and 8.0.15
- JDBC server path: `useServerPrepStmts=true`, `cachePrepStmts=false`,
`emulateUnsupportedPstmts=false`
- Control: MySQL 8.0.46

## Steps to reproduce

```sql
create database prepared_set_repro;
use prepared_set_repro;
create table t(id int primary key, tags set('a','b','c'));
```

JDBC binary prepared statement:

```java
try (PreparedStatement ps = connection.prepareStatement(
"insert into t(id,tags) values (?,?)")) {
ps.setInt(1, 1);
ps.setString(2, "a,b");
ps.executeUpdate();
}
```

SQL prepared statement:

```sql
prepare p from 'insert into t(id,tags) values (?,?)';
set @id = 2, @tags = 'a,b';
execute p using @id, @tags;
```

## Actual behavior

Both prepared paths fail without inserting a row:

```text
SQLState HY000 / error 20203
invalid argument cast to uint64, bad value a,b
```

`setString("a")` fails in the same way. Binding integer `3`, or the numeric
string `"3"`, succeeds and stores `a,b`.

## Expected behavior

Prepared INSERT should apply normal MySQL SET assignment semantics and store
label strings such as `a` and `a,b`. MySQL 8.0 accepts both values through the
same binary and SQL prepared paths.

## Stability and controls

- MatrixOne binary server-prepared reproduction: 3/3 with Connector/J 8.0.33.
- MatrixOne SQL `PREPARE` reproduction: 3/3.
- Connector/J 8.0.15: same MatrixOne failure in 3/3 runs.
- MatrixOne `useServerPrepStmts=false`: label INSERT succeeds in 3/3 runs.
- MatrixOne literal `INSERT ... 'a,b'`: succeeds.
- MySQL 8.0.46 server/client prepared and SQL prepared controls: all succeed in
3/3 runs.
- Failed executions leave no partial row; the connection remains usable.
- ENUM label INSERT is a passing control.

## Code analysis

MatrixOne represents a SET column with a `uint64` storage type plus its member
definition. The special assignment conversion is selected in
`pkg/sql/plan/make.go` (`funcCastForSetType`) from the prepare-time expression
type. In this path the late-bound string reaches numeric index conversion,
which is consistent with the exact `cast to uint64` error and with integer
bindings succeeding. The fix should preserve label conversion for string
bindings while retaining numeric-index semantics.

## Regression coverage

Add real binary-protocol and SQL prepared regressions for single and multiple
SET labels, numeric indexes, NULL, invalid labels, repeated rebinding, batch
INSERT, and recovery after a rejected value. Keep literal/client-prepared and
MySQL-compatible stored-value controls.

## Related

- #26873 concerns ENUM/YEAR covering-index extraction, not SET assignment.
- #27328 concerns input parameter metadata, not SET value conversion.

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.