dolthub / dolthub/dolt

Triggers bind to their table by name string: RENAME TABLE silently detaches them, and the orphan rebinds to any future table with the old name

Open
#11,588 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Go
Stars
24.4k
Forks
873
Avg merge
1d 8h
Merged PRs (30d)
120

Description

Triggers are associated with their table by the stored name string in `dolt_schemas`, not by table identity. Three consequences, escalating in severity — the third silently rewrites data the user never asked a trigger to touch.

Related: #11587 (`information_schema.triggers` errors after a column rename). Same underlying family — the trigger body is stored as raw text and resolved by name at use time — but that issue is introspection-only; this one changes data behavior.

## 1. `RENAME TABLE` detaches triggers, which silently stop firing

```sql
create table t(k int primary key, n int);
create trigger tg0 before insert on t for each row set new.n = 42;
rename table t to t9;
insert into t9 values (1, 0);
select n from t9;
```

```
n
0 -- MySQL: 42. The trigger silently did not fire.
```

MySQL keeps triggers attached through `RENAME TABLE`. Dolt leaves the `dolt_schemas` row naming `t`, so the trigger detaches without any error or warning.

## 2. While the orphan exists, trigger introspection errors database-wide

```sql
show triggers;
-- table not found: t
select trigger_name from information_schema.triggers;
-- table not found: t
```

One orphaned row makes every trigger unlistable.

## 3. The orphan rebinds to any future table with the old name

Continuing the same session:

```sql
create table t(k int primary key, n int); -- a brand-new, unrelated table
insert into t values (1, 0);
select n from t;
```

```
n
42 -- tg0 revived and rewrote the new table's data
```

A trigger the user never created on this table fires on it. Anyone who renames a table away and later reuses the name inherits dormant behavior from the old one.

## Merges reach the same state across branches

No single-branch misuse is needed. Branch A creates a trigger on `t`; branch B drops (or renames) `t`; the merge succeeds and composes them:

```sql
-- after merging: show tables is empty, yet
select type,name,fragment from dolt_schemas;
-- trigger, tg0, create trigger tg0 after insert on t for each row ...
show triggers;
-- table not found: t
```

MySQL semantics are that a trigger cannot exist without its table (`DROP TABLE` drops its triggers; `RENAME TABLE` carries them along). A schema conflict on the merge, or applying MySQL's own rules, would both avoid the orphan; today the merge quietly manufactures a state MySQL cannot represent, with consequence 3 waiting downstream.

Found while building DoltLite's schema-merge oracle against Dolt (dolthub/doltlite#2333); reproduced on the version below.

Contributor guide

No contributing guide indexed for this repository

Research direction

Start by reproducing the RENAME TABLE, trigger introspection, name reuse, and merge cases described in the issue, then inspect the dolt_schemas rows and the paths behind SHOW TRIGGERS and information_schema.triggers. Done means triggers remain associated with the correct table through renames and merges, orphaned triggers cannot affect future tables, and introspection remains usable.

Written by the indexing model from the issue text.

Assessment

Tech stack
go, mysql
Domain
databases
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.