github.com/dolthub/go-mysql-server@v0.18.0/sql/plan/show_events.go (about) 1 // Copyright 2023 Dolthub, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package plan 16 17 import ( 18 gmstime "github.com/dolthub/go-mysql-server/internal/time" 19 "github.com/dolthub/go-mysql-server/sql" 20 "github.com/dolthub/go-mysql-server/sql/types" 21 ) 22 23 type ShowEvents struct { 24 db sql.Database 25 Events []sql.EventDefinition 26 } 27 28 var _ sql.Databaser = (*ShowEvents)(nil) 29 var _ sql.Node = (*ShowEvents)(nil) 30 var _ sql.CollationCoercible = (*ShowEvents)(nil) 31 32 var showEventsSchema = sql.Schema{ 33 &sql.Column{Name: "Db", Type: types.LongText, Nullable: false}, 34 &sql.Column{Name: "Name", Type: types.LongText, Nullable: false}, 35 &sql.Column{Name: "Definer", Type: types.LongText, Nullable: false}, 36 &sql.Column{Name: "Time zone", Type: types.LongText, Nullable: false}, 37 &sql.Column{Name: "Type", Type: types.LongText, Nullable: false}, 38 &sql.Column{Name: "Execute At", Type: types.Datetime, Nullable: false}, 39 &sql.Column{Name: "Interval Value", Type: types.Uint64, Nullable: false}, 40 &sql.Column{Name: "Interval Field", Type: types.LongText, Nullable: false}, 41 &sql.Column{Name: "Starts", Type: types.Datetime, Nullable: false}, 42 &sql.Column{Name: "Ends", Type: types.Datetime, Nullable: false}, 43 &sql.Column{Name: "Status", Type: types.LongText, Nullable: false}, 44 &sql.Column{Name: "Originator", Type: types.Uint64, Nullable: false}, 45 &sql.Column{Name: "character_set_client", Type: types.LongText, Nullable: false}, 46 &sql.Column{Name: "collation_connection", Type: types.LongText, Nullable: false}, 47 &sql.Column{Name: "Database Collation", Type: types.LongText, Nullable: false}, 48 } 49 50 // NewShowEvents creates a new ShowEvents node for SHOW EVENTS statements. 51 func NewShowEvents(db sql.Database) *ShowEvents { 52 return &ShowEvents{ 53 db: db, 54 } 55 } 56 57 // String implements the sql.Node interface. 58 func (s *ShowEvents) String() string { 59 return "SHOW EVENTS" 60 } 61 62 func (s *ShowEvents) IsReadOnly() bool { 63 return true 64 } 65 66 // Resolved implements the sql.Node interface. 67 func (s *ShowEvents) Resolved() bool { 68 _, ok := s.db.(sql.UnresolvedDatabase) 69 return !ok 70 } 71 72 // Children implements the sql.Node interface. 73 func (s *ShowEvents) Children() []sql.Node { 74 return nil 75 } 76 77 // Schema implements the sql.Node interface. 78 func (s *ShowEvents) Schema() sql.Schema { 79 return showEventsSchema 80 } 81 82 // RowIter implements the sql.Node interface. 83 func (s *ShowEvents) RowIter(ctx *sql.Context, row sql.Row) (sql.RowIter, error) { 84 var rows []sql.Row 85 dbName := s.db.Name() 86 87 characterSetClient, err := ctx.GetSessionVariable(ctx, "character_set_client") 88 if err != nil { 89 return nil, err 90 } 91 collationConnection, err := ctx.GetSessionVariable(ctx, "collation_connection") 92 if err != nil { 93 return nil, err 94 } 95 collationServer, err := ctx.GetSessionVariable(ctx, "collation_server") 96 if err != nil { 97 return nil, err 98 } 99 100 for _, event := range s.Events { 101 eventType := "RECURRING" 102 var executeAt, intervalVal, intervalField, starts, ends, status interface{} 103 e := event.ConvertTimesFromUTCToTz(gmstime.SystemTimezoneOffset()) 104 if e.HasExecuteAt { 105 eventType = "ONE TIME" 106 executeAt = e.ExecuteAt.Format(sql.EventDateSpaceTimeFormat) 107 } else { 108 interval, err := sql.EventOnScheduleEveryIntervalFromString(e.ExecuteEvery) 109 if err != nil { 110 return nil, err 111 } 112 intervalVal, intervalField = interval.GetIntervalValAndField() 113 // STARTS will always have defined value 114 starts = e.Starts.Format(sql.EventDateSpaceTimeFormat) 115 if e.HasEnds { 116 ends = e.Ends.Format(sql.EventDateSpaceTimeFormat) 117 } 118 } 119 120 eventStatus, err := sql.EventStatusFromString(e.Status) 121 if err != nil { 122 return nil, err 123 } 124 switch eventStatus { 125 case sql.EventStatus_Enable: 126 status = "ENABLED" 127 case sql.EventStatus_Disable: 128 status = "DISABLED" 129 case sql.EventStatus_DisableOnSlave: 130 status = "SLAVESIDE_DISABLED" 131 } 132 133 // TODO: Time zone and Originator are set to default for now. 134 rows = append(rows, sql.Row{ 135 dbName, // Db 136 e.Name, // Name 137 e.Definer, // Definer 138 "SYSTEM", // Time zone 139 eventType, // Type 140 executeAt, // Execute At 141 intervalVal, // Interval Value 142 intervalField, // Interval Field 143 starts, // Starts 144 ends, // Ends 145 status, // Status 146 0, // Originator 147 characterSetClient, // character_set_client 148 collationConnection, // collation_connection 149 collationServer, // Database Collation 150 }) 151 } 152 153 return sql.RowsToRowIter(rows...), nil 154 } 155 156 // WithChildren implements the sql.Node interface. 157 func (s *ShowEvents) WithChildren(children ...sql.Node) (sql.Node, error) { 158 return NillaryWithChildren(s, children...) 159 } 160 161 // CheckPrivileges implements the interface sql.Node. 162 func (s *ShowEvents) CheckPrivileges(ctx *sql.Context, opChecker sql.PrivilegedOperationChecker) bool { 163 //TODO: figure out what privileges are needed here 164 return true 165 } 166 167 // CollationCoercibility implements the interface sql.CollationCoercible. 168 func (*ShowEvents) CollationCoercibility(ctx *sql.Context) (collation sql.CollationID, coercibility byte) { 169 return sql.Collation_binary, 7 170 } 171 172 // Database implements the sql.Databaser interface. 173 func (s *ShowEvents) Database() sql.Database { 174 return s.db 175 } 176 177 // WithDatabase implements the sql.Databaser interface. 178 func (s *ShowEvents) WithDatabase(db sql.Database) (sql.Node, error) { 179 ns := *s 180 ns.db = db 181 return &ns, nil 182 }