matrixorigin / matrixorigin/matrixone
[Bug]: prepared UPDATE of ENUM and SET rejects parameter markers
- Dominant language
- Go
- Stars
- 1.9k
- Forks
- 311
- Avg merge
- 1d 3h
- Merged PRs (30d)
- 768
Description
## Description
Prepared UPDATEs that assign a parameter marker to an ENUM or SET column are
rejected during prepare with `only prepare statement can use ? expr`.
Ordinary UPDATE parameters work, literal ENUM/SET updates work, Connector/J
client-prepared statements work, and MySQL accepts the same server-prepared
statements.
The failure affects both MySQL binary `COM_STMT_PREPARE` and SQL `PREPARE`.
## 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_update_special_repro;
use prepared_update_special_repro;
create table t(
id int primary key,
e enum('low','high'),
tags set('a','b','c')
);
insert into t values (1,'low','c');
```
JDBC binary prepared statements:
```java
connection.prepareStatement("update t set e=? where id=?");
connection.prepareStatement("update t set tags=? where id=?");
```
SQL prepared statement:
```sql
prepare p_enum from 'update t set e=? where id=?';
prepare p_set from 'update t set tags=? where id=?';
```
## Actual behavior
Each statement fails during prepare, before any value can be bound:
```text
SQLState HY000 / error 20301
invalid input: only prepare statement can use ? expr
```
The original row remains unchanged and the connection remains usable.
## Expected behavior
The statements should prepare successfully and accept compatible label or
numeric values at execute time. MySQL 8.0 prepares and executes all four
controls, storing `high` and `a,b` as expected.
## Stability and controls
- MatrixOne binary server-prepared ENUM and SET UPDATE: each fails 3/3 with
Connector/J 8.0.33.
- MatrixOne SQL `PREPARE` ENUM and SET UPDATE: each fails 3/3.
- Connector/J 8.0.15: same MatrixOne failures in 3/3 runs.
- MatrixOne `useServerPrepStmts=false`: both UPDATEs succeed in 3/3 runs.
- Literal UPDATE and ordinary typed-parameter UPDATE controls succeed.
- MySQL 8.0.46 server/client prepared and SQL prepared controls: all succeed in
3/3 runs.
- Prepare failures leave the row unchanged; subsequent statements work.
## Code analysis
`pkg/sql/plan/bind_update.go` applies `funcCastForEnumType` or
`funcCastForSetType` to special-column update expressions. The resulting
binding path reaches `BaseBinder` without a builder marked as a prepared
statement; `pkg/sql/plan/base_binder.go` therefore rejects the still-valid
`ParamExpr` with the observed message. This is distinct from execute-time SET
label conversion in the INSERT path.
## Regression coverage
Add binary-protocol and SQL prepared UPDATE coverage for ENUM and SET using
labels, numeric indexes, NULL, invalid values, repeated rebinding, transaction
rollback, and reuse after failure. Include literal/client-prepared controls
and a normal integer UPDATE to protect the prepare-context boundary.
## Related
- #26873 concerns ENUM/YEAR covering-index reads, not UPDATE assignment.
- #25996 concerns prepared SQL `SET` statements, not SET column types.
Contributor guide
Assessment
This issue has not been assessed yet.