pingcap / pingcap/tidb

Support shared-lock upgrade in foreign key check

Open
#68,815 1 comment 0 reactions 1 assignee Claimed by @wfxr View on GitHub
type/feature-request
Dominant language
Go
Stars
40.5k
Forks
6.2k
PR merge metrics
PR metrics pending

Description

## Summary

When `tidb_foreign_key_check_in_shared_lock` is enabled, a transaction that:

1. inserts or updates a child row that references a parent row, and then
2. updates that same parent row in the same transaction

fails with:

```text
ERROR 1105 (HY000): upgrading a shared lock to an exclusive lock is not supported
```

This makes a common foreign-key workflow fail even when the parent row update does not modify the referenced key column.

## Describe the solution you'd like

Support this transaction pattern when foreign-key shared-lock checking is enabled.

## Describe alternatives you've considered

- Disable `tidb_foreign_key_check_in_shared_lock`
- This avoids the failure, but it also changes the locking behavior and is not a real fix.
- Split the logic into multiple transactions
- This is a workaround, but it changes application semantics and is not always acceptable.
- Reorder application SQL
- In some flows this is hard or impossible once the child insert and parent update are both required in one atomic transaction.

## Minimal reproduction

Note: reproduction requires `tidb_foreign_key_check_in_shared_lock` to be enabled in the reproducing session.

```sql
DROP DATABASE IF EXISTS fk_issue_repro;
CREATE DATABASE fk_issue_repro;
USE fk_issue_repro;

CREATE TABLE parent (
id BIGINT PRIMARY KEY,
v BIGINT NOT NULL
);

CREATE TABLE child (
id BIGINT PRIMARY KEY,
parent_id BIGINT NOT NULL,
CONSTRAINT fk_child_parent FOREIGN KEY (parent_id) REFERENCES parent(id)
);

INSERT INTO parent VALUES (1, 0);

SET SESSION tidb_foreign_key_check_in_shared_lock = 1;

START TRANSACTION;
INSERT INTO child VALUES (1, 1);
UPDATE parent SET v = v + 1 WHERE id = 1;
COMMIT;
```

## Actual behavior

The `UPDATE parent ...` statement fails with:

```text
ERROR 1105 (HY000): upgrading a shared lock to an exclusive lock is not supported
```

## Expected behavior

The transaction should commit successfully. Updating a non-key column on the parent row after the child row passes FK checking should be supported in the same transaction.

## Additional context

- Verified locally against `8.0.11-TiDB-v8.5.6`
- Verified that the same SQL succeeds when `SET SESSION tidb_foreign_key_check_in_shared_lock = 0`

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.