matrixorigin / matrixorigin/matrixone

[Bug]: prepared UPDATE of ENUM and SET rejects parameter markers

Open
#27,332 1 comment 0 reactions 1 assignee Assigned to @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 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

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.