Skip to content

Commit

Permalink
support parsing ALTER EVENT statements (#233)
Browse files Browse the repository at this point in the history
  • Loading branch information
jennifersp committed May 8, 2023
1 parent 3ba14ce commit fc3ee4c
Show file tree
Hide file tree
Showing 4 changed files with 10,189 additions and 9,878 deletions.
96 changes: 81 additions & 15 deletions go/vt/sqlparser/ast.go
Expand Up @@ -1785,15 +1785,35 @@ type EventSpec struct {
Definer string
IfNotExists bool
OnSchedule *EventScheduleSpec
OnCompletionPreserve bool
OnCompletionPreserve EventOnCompletion
Status EventStatus
Comment *SQLVal
Body Statement

// used for ALTER EVENT statement
RenameName EventName
}

// ValidateAlterEvent checks that at least one event field is defined to alter.
func (es *EventSpec) ValidateAlterEvent() error {
if es.OnSchedule == nil && es.OnCompletionPreserve == EventOnCompletion_Undefined && es.RenameName.IsEmpty() && es.Status == EventStatus_Undefined && es.Comment == nil && es.Body == nil {
return fmt.Errorf("You have an error in your SQL syntax; At least one event field to alter needs to be defined")
}
return nil
}

type EventOnCompletion string

const (
EventOnCompletion_Undefined EventOnCompletion = ""
EventOnCompletion_Preserve EventOnCompletion = "on completion preserve"
EventOnCompletion_NotPreserve EventOnCompletion = "on completion not preserve"
)

type EventStatus string

const (
EventStatus_Undefined EventStatus = ""
EventStatus_Enable EventStatus = "enable"
EventStatus_Disable EventStatus = "disable"
EventStatus_DisableOnSlave EventStatus = "disable on slave"
Expand All @@ -1815,9 +1835,9 @@ type EventScheduleTimeSpec struct {
func (est *EventScheduleTimeSpec) Format(buf *TrackedBuffer) {
sb := strings.Builder{}

sb.WriteString(fmt.Sprintf("%s ", String(est.EventTimestamp)))
sb.WriteString(fmt.Sprintf("%s", String(est.EventTimestamp)))
for _, interval := range est.EventIntervals {
sb.WriteString(fmt.Sprintf("+ interval %v %s ", interval.Expr, interval.Unit))
sb.WriteString(fmt.Sprintf(" + interval %v %s", interval.Expr, interval.Unit))
}

buf.Myprintf("%s", sb.String())
Expand Down Expand Up @@ -2071,19 +2091,22 @@ func (node *DDL) Format(buf *TrackedBuffer) {
sb.WriteString(fmt.Sprintf("event%s %s ", notExists, event.EventName))

if event.OnSchedule.At != nil {
sb.WriteString(fmt.Sprintf("on schedule at %s", event.OnSchedule.At.String()))
sb.WriteString(fmt.Sprintf("on schedule at %s ", event.OnSchedule.At.String()))
} else {
sb.WriteString(fmt.Sprintf("on schedule every %s %s ", String(event.OnSchedule.EveryInterval.Expr), event.OnSchedule.EveryInterval.Unit))
if event.OnSchedule.Starts != nil {
sb.WriteString(fmt.Sprintf("starts %s", event.OnSchedule.Starts.String()))
sb.WriteString(fmt.Sprintf("starts %s ", event.OnSchedule.Starts.String()))
}
if event.OnSchedule.Ends != nil {
sb.WriteString(fmt.Sprintf("ends %s", event.OnSchedule.Ends.String()))
sb.WriteString(fmt.Sprintf("ends %s ", event.OnSchedule.Ends.String()))
}
}

if event.OnCompletionPreserve {
sb.WriteString("on completion preserve ")
if event.OnCompletionPreserve == EventOnCompletion_Preserve {
sb.WriteString(fmt.Sprintf("%s ", event.OnCompletionPreserve))
}
if event.Status != EventStatus_Undefined {
sb.WriteString(fmt.Sprintf("%s ", event.Status))
}
if event.Comment != nil {
sb.WriteString(fmt.Sprintf("comment %s ", event.Comment))
Expand Down Expand Up @@ -2149,12 +2172,55 @@ func (node *DDL) Format(buf *TrackedBuffer) {
buf.Myprintf(", %v to %v", node.FromTables[i], node.ToTables[i])
}
case AlterStr:
buf.Myprintf("%s table %v", node.Action, node.Table)
node.alterFormat(buf)
if node.EventSpec != nil {
event := node.EventSpec
sb := strings.Builder{}
sb.WriteString("alter")
if event.Definer != "" {
sb.WriteString(fmt.Sprintf(" definer = %s", event.Definer))
}

sb.WriteString(fmt.Sprintf(" event %s", event.EventName))

if event.OnSchedule != nil {
if event.OnSchedule.At != nil {
sb.WriteString(fmt.Sprintf(" on schedule at %s", event.OnSchedule.At.String()))
} else {
sb.WriteString(fmt.Sprintf(" on schedule every %s %s", String(event.OnSchedule.EveryInterval.Expr), event.OnSchedule.EveryInterval.Unit))
if event.OnSchedule.Starts != nil {
sb.WriteString(fmt.Sprintf(" starts %s", event.OnSchedule.Starts.String()))
}
if event.OnSchedule.Ends != nil {
sb.WriteString(fmt.Sprintf(" ends %s", event.OnSchedule.Ends.String()))
}
}
}

if event.OnCompletionPreserve != EventOnCompletion_Undefined {
sb.WriteString(fmt.Sprintf(" %s", event.OnCompletionPreserve))
}
if !event.RenameName.IsEmpty() {
sb.WriteString(fmt.Sprintf(" rename to %s", event.RenameName))
}
if event.Status != EventStatus_Undefined {
sb.WriteString(fmt.Sprintf(" %s", event.Status))
}
if event.Comment != nil {
sb.WriteString(fmt.Sprintf(" comment %s", event.Comment))
}
if event.Body != nil {
buf.Myprintf("%s do %v", sb.String(), event.Body)
} else {
buf.Myprintf("%s", sb.String())
}
} else {
buf.Myprintf("%s table %v", node.Action, node.Table)
node.alterFormat(buf)
}
case FlushStr:
buf.Myprintf("%s", node.Action)
case AddAutoIncStr:
buf.Myprintf("alter vschema on %v add auto_increment %v", node.Table, node.AutoIncSpec)
buf.Myprintf("alter schema on %v add auto_increment %v", node.Table, node.AutoIncSpec)
default:
buf.Myprintf("%s table %v", node.Action, node.Table)
}
Expand Down Expand Up @@ -3177,12 +3243,12 @@ func (node *Explain) Format(buf *TrackedBuffer) {
const (
CreateTriggerStr = "create trigger"
CreateProcedureStr = "create procedure"
CreateEventStr = "create event"
CreateTableStr = "create table"
CreateEventStr = "create event"
CreateTableStr = "create table"

ProcedureStatusStr = "procedure status"
FunctionStatusStr = "function status"
TableStatusStr = "table status"
FunctionStatusStr = "function status"
TableStatusStr = "table status"
)

// Show represents a show statement.
Expand Down
68 changes: 55 additions & 13 deletions go/vt/sqlparser/parse_test.go
Expand Up @@ -1736,7 +1736,7 @@ var (
}, {
input: "show triggers like 'pattern'",
}, {
input: "show TRIGGERS where v = 'x'",
input: "show TRIGGERS where v = 'x'",
output: "show triggers where v = 'x'",
}, {
input: "show variables",
Expand Down Expand Up @@ -2879,32 +2879,68 @@ var (
input: "CREATE DEFINER = `root`@`localhost` EVENT event1 ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 3 WEEK + INTERVAL 2 DAY DO INSERT INTO mytable VALUES (NOW())",
output: "create definer = `root`@`localhost` event event1 on schedule at CURRENT_TIMESTAMP() + interval 3 WEEK + interval 2 DAY do insert into mytable values (NOW())",
}, {
input: "CREATE EVENT event1 ON SCHEDULE EVERY 1 MINUTE ENDS CURRENT_TIMESTAMP + INTERVAL 3 HOUR ON COMPLETION PRESERVE COMMENT 'new event' DO INSERT INTO mytable VALUES (1)",
output: "create event event1 on schedule every 1 MINUTE ends CURRENT_TIMESTAMP() + interval 3 HOUR on completion preserve comment 'new event' do insert into mytable values (1)",
input: "CREATE EVENT event1 ON SCHEDULE EVERY 1 MINUTE ENDS CURRENT_TIMESTAMP + INTERVAL 3 HOUR ON COMPLETION PRESERVE disable COMMENT 'new event' DO INSERT INTO mytable VALUES (1)",
output: "create event event1 on schedule every 1 MINUTE ends CURRENT_TIMESTAMP() + interval 3 HOUR on completion preserve disable comment 'new event' do insert into mytable values (1)",
}, {
input: "CREATE EVENT event1 ON SCHEDULE EVERY 1 MINUTE STARTS CURRENT_TIMESTAMP + INTERVAL 2 HOUR ENDS CURRENT_TIMESTAMP + INTERVAL 3 HOUR ON COMPLETION NOT PRESERVE DO INSERT INTO mytable VALUES (1)",
output: "create event event1 on schedule every 1 MINUTE starts CURRENT_TIMESTAMP() + interval 2 HOUR ends CURRENT_TIMESTAMP() + interval 3 HOUR do insert into mytable values (1)",
input: "CREATE EVENT event1 ON SCHEDULE EVERY 1 MINUTE STARTS CURRENT_TIMESTAMP + INTERVAL 2 HOUR ENDS CURRENT_TIMESTAMP + INTERVAL 3 HOUR ON COMPLETION NOT PRESERVE enable DO INSERT INTO mytable VALUES (1)",
output: "create event event1 on schedule every 1 MINUTE starts CURRENT_TIMESTAMP() + interval 2 HOUR ends CURRENT_TIMESTAMP() + interval 3 HOUR enable do insert into mytable values (1)",
}, {
input: "CREATE EVENT e_call_myproc ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 DAY DO CALL myproc(5, 27)",
output: "create event e_call_myproc on schedule at CURRENT_TIMESTAMP() + interval 1 DAY do call myproc(5, 27)",
input: "CREATE EVENT e_call_myproc ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 DAY disable on slave DO CALL myproc(5, 27)",
output: "create event e_call_myproc on schedule at CURRENT_TIMESTAMP() + interval 1 DAY disable on slave do call myproc(5, 27)",
}, {
input: "SHOW EVENTS",
input: "CREATE EVENT e_call_myproc ON SCHEDULE AT CURRENT_TIMESTAMP DO CALL myproc(5, 27)",
output: "create event e_call_myproc on schedule at CURRENT_TIMESTAMP() do call myproc(5, 27)",
}, {
input: "CREATE EVENT e_call_myproc ON SCHEDULE AT CURRENT_TIMESTAMP DISABLE DO CALL myproc(5, 27)",
output: "create event e_call_myproc on schedule at CURRENT_TIMESTAMP() disable do call myproc(5, 27)",
}, {
input: "SHOW EVENTS",
output: "show events",
}, {
input: "SHOW EVENTS FROM dbName",
input: "SHOW EVENTS FROM dbName",
output: "show events from dbName",
}, {
input: "SHOW EVENTS IN dbName",
input: "SHOW EVENTS IN dbName",
output: "show events from dbName",
}, {
input: "SHOW EVENTS IN dbName LIKE 'pattern'",
input: "SHOW EVENTS IN dbName LIKE 'pattern'",
output: "show events from dbName like 'pattern'",
}, {
input: "SHOW EVENTS FROM dbName WHERE status = 'enabled'",
input: "SHOW EVENTS FROM dbName WHERE status = 'enabled'",
output: "show events from dbName where `status` = 'enabled'",
}, {
input: "SHOW CREATE EVENT myevent",
input: "SHOW CREATE EVENT myevent",
output: "show create event myevent",
}, {
input: "ALTER EVENT myevent ON SCHEDULE AT CURRENT_TIMESTAMP;",
output: "alter event myevent on schedule at CURRENT_TIMESTAMP()",
}, {
input: "ALTER EVENT myevent ON COMPLETION NOT PRESERVE",
output: "alter event myevent on completion not preserve",
}, {
input: "ALTER EVENT myevent RENAME TO event1",
output: "alter event myevent rename to event1",
}, {
input: "ALTER EVENT mydb.myevent RENAME TO newdb.event1",
output: "alter event mydb.myevent rename to newdb.event1",
}, {
input: "ALTER EVENT myevent ENABLE",
output: "alter event myevent enable",
}, {
input: "ALTER EVENT myevent COMMENT 'add comment'",
output: "alter event myevent comment 'add comment'",
}, {
input: "ALTER EVENT myevent DO INSERT INTO mytable values (1)",
output: "alter event myevent do insert into mytable values (1)",
}, {
input: "ALTER EVENT myevent ON SCHEDULE EVERY 1 MINUTE STARTS CURRENT_TIMESTAMP DO INSERT INTO mytable values (1)",
output: "alter event myevent on schedule every 1 MINUTE starts CURRENT_TIMESTAMP() do insert into mytable values (1)",
}, {
input: "ALTER EVENT myevent RENAME TO new_event DISABLE COMMENT 'renaming and disabling the event'",
output: "alter event myevent rename to new_event disable comment 'renaming and disabling the event'",
}, {
input: "ALTER DEFINER = `newuser`@`localhost` EVENT myevent ON COMPLETION NOT PRESERVE;",
output: "alter definer = `newuser`@`localhost` event myevent on completion not preserve",
},
}
// Any tests that contain multiple statements within the body (such as BEGIN/END blocks) should go here.
Expand Down Expand Up @@ -6057,6 +6093,12 @@ var (
input: "CREATE PROCEDURE testproc() BEGIN while1: WHILE a > 7 DO BEGIN END; END WHILE while2; END",
output: "End-label while2 without match at position 85 near 'while2'",
excludeMulti: true,
}, {
input: "ALTER EVENT myevent",
output: "You have an error in your SQL syntax; At least one event field to alter needs to be defined at position 20 near 'myevent'",
}, {
input: "ALTER DEFINER = `newuser`@`localhost` EVENT myevent",
output: "You have an error in your SQL syntax; At least one event field to alter needs to be defined at position 52 near 'myevent'",
},
}
)
Expand Down

0 comments on commit fc3ee4c

Please sign in to comment.