Skip to content

Commit 9d8e43b

Browse files
authored
Allow drop trigger ... when trigger is invalid (#3034)
1 parent cc8357c commit 9d8e43b

File tree

3 files changed

+56
-10
lines changed

3 files changed

+56
-10
lines changed

enginetest/queries/trigger_queries.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3784,6 +3784,42 @@ end;
37843784
},
37853785
},
37863786
},
3787+
3788+
// Invalid triggers
3789+
{
3790+
Name: "insert trigger with subquery projections",
3791+
SetUpScript: []string{
3792+
"create table t (i int);",
3793+
"create trigger trig before insert on t for each row begin replace into t select 1; end;",
3794+
"alter table t add column j int;",
3795+
},
3796+
Assertions: []ScriptTestAssertion{
3797+
{
3798+
Query: "show create trigger trig",
3799+
Expected: []sql.Row{
3800+
{
3801+
"trig",
3802+
"",
3803+
"create trigger trig before insert on t for each row begin replace into t select 1; end",
3804+
sql.Collation_Default.CharacterSet().String(),
3805+
sql.Collation_Default.String(),
3806+
sql.Collation_Default.String(),
3807+
time.Unix(0, 0).UTC(),
3808+
},
3809+
},
3810+
},
3811+
{
3812+
Query: "insert into t values (1, 2);",
3813+
ExpectedErr: sql.ErrInsertIntoMismatchValueCount,
3814+
},
3815+
{
3816+
Query: "drop trigger trig;",
3817+
Expected: []sql.Row{
3818+
{types.NewOkResult(0)},
3819+
},
3820+
},
3821+
},
3822+
},
37873823
}
37883824

37893825
var TriggerCreateInSubroutineTests = []ScriptTest{

sql/analyzer/load_triggers.go

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ func loadTriggers(ctx *sql.Context, a *Analyzer, n sql.Node, scope *plan.Scope,
3333
switch node := n.(type) {
3434
case *plan.ShowTriggers:
3535
newShowTriggers := *node
36-
loadedTriggers, err := loadTriggersFromDb(ctx, a, newShowTriggers.Database())
36+
loadedTriggers, err := loadTriggersFromDb(ctx, a, newShowTriggers.Database(), false)
3737
if err != nil {
3838
return nil, transform.SameTree, err
3939
}
@@ -44,16 +44,16 @@ func loadTriggers(ctx *sql.Context, a *Analyzer, n sql.Node, scope *plan.Scope,
4444
}
4545
return &newShowTriggers, transform.NewTree, nil
4646
case *plan.DropTrigger:
47-
loadedTriggers, err := loadTriggersFromDb(ctx, a, node.Database())
47+
loadedTriggers, err := loadTriggersFromDb(ctx, a, node.Database(), true)
4848
if err != nil {
4949
return nil, transform.SameTree, err
5050
}
51-
lowercasedTriggerName := strings.ToLower(node.TriggerName)
5251
for _, trigger := range loadedTriggers {
53-
if strings.ToLower(trigger.TriggerName) == lowercasedTriggerName {
52+
if strings.EqualFold(node.TriggerName, trigger.TriggerName) {
5453
node.TriggerName = trigger.TriggerName
55-
} else if trigger.TriggerOrder != nil &&
56-
strings.ToLower(trigger.TriggerOrder.OtherTriggerName) == lowercasedTriggerName {
54+
continue
55+
}
56+
if trigger.TriggerOrder != nil && strings.EqualFold(node.TriggerName, trigger.TriggerOrder.OtherTriggerName) {
5757
return nil, transform.SameTree, sql.ErrTriggerCannotBeDropped.New(node.TriggerName, trigger.TriggerName)
5858
}
5959
}
@@ -70,7 +70,7 @@ func loadTriggers(ctx *sql.Context, a *Analyzer, n sql.Node, scope *plan.Scope,
7070
dropTableDb = t.SqlDatabase
7171
}
7272

73-
loadedTriggers, err := loadTriggersFromDb(ctx, a, dropTableDb)
73+
loadedTriggers, err := loadTriggersFromDb(ctx, a, dropTableDb, false)
7474
if err != nil {
7575
return nil, transform.SameTree, err
7676
}
@@ -95,7 +95,7 @@ func loadTriggers(ctx *sql.Context, a *Analyzer, n sql.Node, scope *plan.Scope,
9595
})
9696
}
9797

98-
func loadTriggersFromDb(ctx *sql.Context, a *Analyzer, db sql.Database) ([]*plan.CreateTrigger, error) {
98+
func loadTriggersFromDb(ctx *sql.Context, a *Analyzer, db sql.Database, ignoreParseErrors bool) ([]*plan.CreateTrigger, error) {
9999
var loadedTriggers []*plan.CreateTrigger
100100
if triggerDb, ok := db.(sql.TriggerDatabase); ok {
101101
triggers, err := triggerDb.GetTriggers(ctx)
@@ -108,7 +108,17 @@ func loadTriggersFromDb(ctx *sql.Context, a *Analyzer, db sql.Database) ([]*plan
108108
// TODO: should perhaps add the auth query handler to the analyzer? does this even use auth?
109109
parsedTrigger, _, err = planbuilder.ParseWithOptions(ctx, a.Catalog, trigger.CreateStatement, sqlMode.ParserOptions())
110110
if err != nil {
111-
return nil, err
111+
// We want to be able to drop invalid triggers, so ignore any parser errors and return the name of the trigger
112+
if !ignoreParseErrors {
113+
return nil, err
114+
}
115+
// TODO: we won't have TriggerOrder information for this unparseable trigger,
116+
// but it will still be referenced by any valid triggers.
117+
fakeTrigger := &plan.CreateTrigger{
118+
TriggerName: trigger.Name,
119+
}
120+
loadedTriggers = append(loadedTriggers, fakeTrigger)
121+
continue
112122
}
113123
triggerPlan, ok := parsedTrigger.(*plan.CreateTrigger)
114124
if !ok {

sql/analyzer/process_truncate.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ func deleteToTruncate(ctx *sql.Context, a *Analyzer, deletePlan *plan.DeleteFrom
100100
return deletePlan, transform.SameTree, nil
101101
}
102102

103-
triggers, err := loadTriggersFromDb(ctx, a, currentDb)
103+
triggers, err := loadTriggersFromDb(ctx, a, currentDb, false)
104104
if err != nil {
105105
return nil, transform.SameTree, err
106106
}

0 commit comments

Comments
 (0)