pingcap / pingcap/tidb

[expression] TiDB can drop a collation-distinct predicate and silently delete protected rows

Open
#70,129 0 comments 0 reactions 0 assignees View on GitHub
component/expression found-by-ai may-affects-7.5 may-affects-8.1 may-affects-8.5 severity/critical type/bug
Dominant language
Go
Stars
40.5k
Forks
6.2k
PR merge metrics
PR metrics pending

Description

## Bug Report

### 1. Minimal reproduce step (Required)

**Environment**

TiDB master 05b396fb66; default strict mode; MDL ON; one TiDB/PD/real TiKV; no injection

**Steps**

Create a utf8mb4_bin table containing (1,'A'),(2,'a'),(3,'B'). Compare WHERE s=(_utf8mb4'A' COLLATE utf8mb4_general_ci) AND s=(_utf8mb4'A' COLLATE utf8mb4_bin) with the reversed predicate order and with a structural BINARY guard. Run the three predicates against fresh table copies, record ROW_COUNT(), surviving primary keys, EXPLAIN, and ADMIN CHECK TABLE. The exact SQL is in scaffolds/top-level/ai_native_collation_predicate_hash_wrong_delete_repro.sql.

### 2. What did you expect to see? (Required)

AND predicate order is semantically irrelevant. Every form selects and deletes only id=1; id=2 must survive because its binary comparison is false.

### 3. What did you see instead? (Required)

Exact current master selected ids 1,2 when the case-insensitive predicate came first, but only id 1 in reverse order. The first DELETE succeeded with affected=2 and left only id=3. Reverse-order and structural controls affected=1 and retained ids 2,3. The plan contained only one equality. ADMIN CHECK stayed green.

### 4. What is your TiDB version? (Required)

TiDB master 05b396fb66; default strict mode; MDL ON; one TiDB/PD/real TiKV; no injection

Likely root cause and fix direction

**Likely root cause**

Constant.getHashCode appends only constantFlag and codec.HashCode(Value). For KindString, codec.HashCode uses raw bytes because comparable=false, so charset and collation identity are omitted. RemoveDupExprs uses expression HashCode bytes as semantic identity. The two equality expressions therefore collide, and the first expression survives.

**Fix direction**

Make expression hash equality at least as strong as the semantic equality assumed by every consumer. For string constants, include stable charset and collation identity in the hash, then audit other equality-relevant FieldType and coercibility dimensions. Keep Equals and both canonical/noncanonical hash contracts aligned.

Contributor guide

Open the contributing guide

Research direction

Start by running scaffolds/top-level/ai_native_collation_predicate_hash_wrong_delete_repro.sql and reading Constant.getHashCode, codec.HashCode, and RemoveDupExprs. Trace how string constants are hashed and compared, then verify that collation-distinct predicates remain distinct while the reproduction selects and deletes only id=1, with ADMIN CHECK TABLE still green.

Written by the indexing model from the issue text.

Assessment

Tech stack
go, sql
Domain
database
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.