matrixorigin / matrixorigin/matrixone

[Bug]: RESTORE TABLE silently skips a referenced table and leaves post-snapshot data

Open
#27,117 3 comments 0 reactions 1 assignee Claimed by @gouhongshen View on GitHub
ai-easy kind/bug severity/s0
Dominant language
Go
Stars
1.9k
Forks
311
Avg merge
1d 3h
Merged PRs (30d)
768

Description

## Problem

`RESTORE TABLE` can report success while leaving its target unchanged when another table has a foreign-key reference to that target. This is a silent data-restore failure: a historical read sees the snapshot value, but the successful restore leaves the post-snapshot value in place.

## Environment

- Branch: `main`
- Commit: `a2f89230085a0f6650ec7bb7017ba6b8a97c9efc`
- Build: local official-main binary at that commit
- Topology: isolated standalone LOG/TN/CN, with a shared temporary data path

## Steps to reproduce

```sql
DROP SNAPSHOT IF EXISTS repro_fk_control_snapshot;
DROP SNAPSHOT IF EXISTS repro_fk_parent_snapshot;
DROP DATABASE IF EXISTS repro_fk_control;
DROP DATABASE IF EXISTS repro_fk_case;

-- Normal table-restore control.
CREATE DATABASE repro_fk_control;
CREATE TABLE repro_fk_control.t (id INT PRIMARY KEY, v VARCHAR(16));
INSERT INTO repro_fk_control.t VALUES (1, 'before');
CREATE SNAPSHOT repro_fk_control_snapshot FOR TABLE repro_fk_control t;
UPDATE repro_fk_control.t SET v = 'changed';
RESTORE TABLE repro_fk_control.t{snapshot='repro_fk_control_snapshot'};
SELECT 'control_table_restore' AS case_name, v FROM repro_fk_control.t;

CREATE DATABASE repro_fk_case;
CREATE TABLE repro_fk_case.parent_t (id INT PRIMARY KEY, v VARCHAR(16));
CREATE TABLE repro_fk_case.child_t (
cid INT PRIMARY KEY,
pid INT,
CONSTRAINT fk_parent FOREIGN KEY (pid) REFERENCES repro_fk_case.parent_t(id)
);
INSERT INTO repro_fk_case.parent_t VALUES (1, 'before');
INSERT INTO repro_fk_case.child_t VALUES (1, 1);
CREATE SNAPSHOT repro_fk_parent_snapshot FOR TABLE repro_fk_case parent_t;
UPDATE repro_fk_case.parent_t SET v = 'changed';

-- Historical read control.
SELECT 'fk_snapshot_read' AS case_name, v
FROM repro_fk_case.parent_t{snapshot='repro_fk_parent_snapshot'};
RESTORE TABLE repro_fk_case.parent_t{snapshot='repro_fk_parent_snapshot'};
SELECT 'fk_table_restore' AS case_name, v FROM repro_fk_case.parent_t;
```

## Expected behavior

The restore should either restore `parent_t.v` to `before`, or return an explicit unsupported-operation error. It must not report success while leaving `changed` in the target table.

## Actual behavior

The complete repro ran 3/3 on `a2f89230085a0f6650ec7bb7017ba6b8a97c9efc`:

```text
control_table_restore before
fk_snapshot_read before
fk_table_restore changed
```

The ordinary restore and the historical read controls both return `before`. Only the restore of the referenced table returns successfully but retains `changed`.

## Root-cause hypothesis

`pkg/frontend/snapshot.go` lines 1632-1636 call `checkTableIsMaster`; for a referenced table the function logs that it will skip the restore and returns without an error. The caller therefore treats the statement as successful although the table was not recreated from the snapshot.

## Duplicate check

Searched open and closed issues, plus open pull requests, for table restore with foreign keys. Existing historical work covers other restore failures and FK refactoring, but no report matches a successful table restore that leaves the referenced target unchanged.

## Regression coverage

No test change is included with this report. After fixing, a deterministic snapshot BVT should assert that the restore either produces `before` or fails explicitly; returning success with `changed` must be prohibited.

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.