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  }