github.com/dolthub/go-mysql-server@v0.18.0/sql/databases.go (about)

     1  // Copyright 2022 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 sql
    16  
    17  import (
    18  	"strings"
    19  	"time"
    20  )
    21  
    22  const (
    23  	// InformationSchemaDatabaseName is the name of the information schema database.
    24  	InformationSchemaDatabaseName = "information_schema"
    25  )
    26  
    27  // DatabaseProvider is the fundamental interface to integrate with the engine. It provides access to all databases in
    28  // a given backend. A DatabaseProvider is provided to the Catalog when the engine is initialized.
    29  type DatabaseProvider interface {
    30  	// Database gets a Database from the provider.
    31  	Database(ctx *Context, name string) (Database, error)
    32  	// HasDatabase checks if the Database exists in the provider.
    33  	HasDatabase(ctx *Context, name string) bool
    34  	// AllDatabases returns a slice of all Databases in the provider.
    35  	AllDatabases(ctx *Context) []Database
    36  }
    37  
    38  // MutableDatabaseProvider is a DatabaseProvider that can create and drop databases.
    39  type MutableDatabaseProvider interface {
    40  	DatabaseProvider
    41  
    42  	// CreateDatabase creates a database and adds it to the provider's collection.
    43  	CreateDatabase(ctx *Context, name string) error
    44  
    45  	// DropDatabase removes a database from the provider's collection.
    46  	DropDatabase(ctx *Context, name string) error
    47  }
    48  
    49  // CollatedDatabaseProvider is a DatabaseProvider that can create a Database with a specific collation.
    50  type CollatedDatabaseProvider interface {
    51  	MutableDatabaseProvider
    52  
    53  	// CreateCollatedDatabase creates a collated database and adds it to the provider's collection.
    54  	CreateCollatedDatabase(ctx *Context, name string, collation CollationID) error
    55  }
    56  
    57  // TableFunctionProvider is an interface that allows custom table functions to be provided. It's usually (but not
    58  // always) implemented by a DatabaseProvider.
    59  type TableFunctionProvider interface {
    60  	// TableFunction returns the table function with the name provided, case-insensitive
    61  	TableFunction(ctx *Context, name string) (TableFunction, error)
    62  	// WithTableFunctions returns a new provider with (only) the list of table functions arguments
    63  	WithTableFunctions(fns ...TableFunction) (TableFunctionProvider, error)
    64  }
    65  
    66  // Database represents the database. Its primary job is to provide access to all tables.
    67  type Database interface {
    68  	Nameable
    69  	// GetTableInsensitive retrieves a table by its case-insensitive name. To be SQL compliant, databases should not
    70  	// allow two tables with the same case-insensitive name. Behavior is undefined when two tables have the same
    71  	// case-insensitive name.
    72  	GetTableInsensitive(ctx *Context, tblName string) (Table, bool, error)
    73  	// GetTableNames returns the table names of every table in the database. It does not return the names of temporary
    74  	// tables
    75  	GetTableNames(ctx *Context) ([]string, error)
    76  }
    77  
    78  // Databaser is a node that contains a reference to a database.
    79  type Databaser interface {
    80  	// Database the current database.
    81  	Database() Database
    82  	// WithDatabase returns a new node instance with the database replaced with
    83  	// the one given as parameter.
    84  	WithDatabase(Database) (Node, error)
    85  }
    86  
    87  // Databaseable is a node with a string reference to a database
    88  type Databaseable interface {
    89  	Database() string
    90  }
    91  
    92  // MultiDatabaser is a node that contains a reference to a database provider. This interface is intended for very
    93  // specific nodes that must resolve databases during execution time rather than during analysis, such as block
    94  // statements where the execution of a nested statement in the block may affect future statements within that same block.
    95  type MultiDatabaser interface {
    96  	// DatabaseProvider returns the current DatabaseProvider.
    97  	DatabaseProvider() DatabaseProvider
    98  	// WithDatabaseProvider returns a new node instance with the database provider replaced with the one given as parameter.
    99  	WithDatabaseProvider(DatabaseProvider) (Node, error)
   100  }
   101  
   102  // ReadOnlyDatabase is an extension of Database that may declare itself read-only, which will disallow any DDL or DML
   103  // statements from executing.
   104  type ReadOnlyDatabase interface {
   105  	Database
   106  	// IsReadOnly returns whether this database is read-only.
   107  	IsReadOnly() bool
   108  }
   109  
   110  // TableCreator is a Database that can create new tables.
   111  type TableCreator interface {
   112  	Database
   113  	// CreateTable creates the table with the given name, schema, collation, and comment. Integrators are
   114  	// responsible for persisting all provided table metadata. Comment may be optionally persisted, and if
   115  	// so, sql.Table implementations should also implement sql.CommentedTable so that the comment may be
   116  	// retrieved.
   117  	CreateTable(ctx *Context, name string, schema PrimaryKeySchema, collation CollationID, comment string) error
   118  }
   119  
   120  // IndexedTableCreator is a Database that can create new tables which have a Primary Key with columns that have
   121  // prefix lengths.
   122  type IndexedTableCreator interface {
   123  	Database
   124  	// CreateIndexedTable creates the table with the given name and schema using the index definition provided for its
   125  	// primary key index.
   126  	CreateIndexedTable(ctx *Context, name string, schema PrimaryKeySchema, idxDef IndexDef, collation CollationID) error
   127  }
   128  
   129  // TemporaryTableCreator is a database that can create temporary tables that persist only as long as the session.
   130  // Note that temporary tables with the same name as persisted tables take precedence in most SQL operations.
   131  type TemporaryTableCreator interface {
   132  	Database
   133  	// CreateTemporaryTable creates the table with the given name and schema. If a temporary table with that name already exists, must
   134  	// return sql.ErrTableAlreadyExists
   135  	CreateTemporaryTable(ctx *Context, name string, schema PrimaryKeySchema, collation CollationID) error
   136  }
   137  
   138  // TableDropper is a Datagbase that can drop tables.
   139  type TableDropper interface {
   140  	Database
   141  	DropTable(ctx *Context, name string) error
   142  }
   143  
   144  // TableRenamer is a database that can rename tables.
   145  type TableRenamer interface {
   146  	Database
   147  	// RenameTable renames a table from oldName to newName as given.
   148  	RenameTable(ctx *Context, oldName, newName string) error
   149  }
   150  
   151  // VersionedDatabase is a Database that can return tables as they existed at different points in time. The engine
   152  // supports queries on historical table data via the AS OF construct introduced in SQL 2011.
   153  type VersionedDatabase interface {
   154  	Database
   155  	// GetTableInsensitiveAsOf retrieves a table by its case-insensitive name with the same semantics as
   156  	// Database.GetTableInsensitive, but at a particular revision of the database. Implementors must choose which types
   157  	// of expressions to accept as revision names.
   158  	GetTableInsensitiveAsOf(ctx *Context, tblName string, asOf interface{}) (Table, bool, error)
   159  	// GetTableNamesAsOf returns the table names of every table in the database as of the revision given. Implementors
   160  	// must choose which types of expressions to accept as revision names.
   161  	GetTableNamesAsOf(ctx *Context, asOf interface{}) ([]string, error)
   162  }
   163  
   164  // CollatedDatabase is a Database that can store and update its collation.
   165  type CollatedDatabase interface {
   166  	Database
   167  	// GetCollation returns this database's collation.
   168  	GetCollation(ctx *Context) CollationID
   169  	// SetCollation updates this database's collation.
   170  	SetCollation(ctx *Context, collation CollationID) error
   171  }
   172  
   173  // TriggerDatabase is a Database that supports creating and storing triggers. The engine handles all parsing and
   174  // execution logic for triggers. Integrators are not expected to parse or understand the trigger definitions, but must
   175  // store and return them when asked.
   176  type TriggerDatabase interface {
   177  	Database
   178  	// GetTriggers returns all trigger definitions for the database
   179  	GetTriggers(ctx *Context) ([]TriggerDefinition, error)
   180  	// CreateTrigger is called when an integrator is asked to create a trigger. The CREATE TRIGGER statement string is
   181  	// provided to store, along with the name of the trigger.
   182  	CreateTrigger(ctx *Context, definition TriggerDefinition) error
   183  	// DropTrigger is called when a trigger should no longer be stored. The name has already been validated.
   184  	// Returns ErrTriggerDoesNotExist if the trigger was not found.
   185  	DropTrigger(ctx *Context, name string) error
   186  }
   187  
   188  // TriggerDefinition defines a trigger. Integrators are not expected to parse or understand the trigger definitions,
   189  // but must store and return them when asked.
   190  type TriggerDefinition struct {
   191  	// The name of this trigger. Trigger names in a database are unique.
   192  	Name string
   193  	// The text of the statement to create this trigger.
   194  	CreateStatement string
   195  	// The time that the trigger was created.
   196  	CreatedAt time.Time
   197  	// SqlMode holds the SQL_MODE that was in use when this trigger was originally defined. It contains information
   198  	// needed for how to parse the trigger's SQL, such as whether ANSI_QUOTES mode is enabled.
   199  	SqlMode string
   200  }
   201  
   202  // TemporaryTableDatabase is a database that can query the session (which manages the temporary table state) to
   203  // retrieve the name of all temporary tables.
   204  type TemporaryTableDatabase interface {
   205  	// GetAllTemporaryTables returns the names of all temporary tables in the session.
   206  	GetAllTemporaryTables(ctx *Context) ([]Table, error)
   207  }
   208  
   209  // TableCopierDatabase is a database that can copy a source table's data (without preserving indexed, fks, etc.) into
   210  // another destination table.
   211  type TableCopierDatabase interface {
   212  	// CopyTableData copies the sourceTable data to the destinationTable and returns the number of rows copied.
   213  	CopyTableData(ctx *Context, sourceTable string, destinationTable string) (uint64, error)
   214  }
   215  
   216  // StoredProcedureDatabase is a database that supports the creation and execution of stored procedures. The engine will
   217  // handle all parsing and execution logic for stored procedures. Integrators only need to store and retrieve
   218  // StoredProcedureDetails, while verifying that all stored procedures have a unique name without regard to
   219  // case-sensitivity.
   220  type StoredProcedureDatabase interface {
   221  	Database
   222  	// GetStoredProcedure returns the desired StoredProcedureDetails from the database.
   223  	GetStoredProcedure(ctx *Context, name string) (StoredProcedureDetails, bool, error)
   224  	// GetStoredProcedures returns all StoredProcedureDetails for the database.
   225  	GetStoredProcedures(ctx *Context) ([]StoredProcedureDetails, error)
   226  	// SaveStoredProcedure stores the given StoredProcedureDetails to the database. The integrator should verify that
   227  	// the name of the new stored procedure is unique amongst existing stored procedures.
   228  	SaveStoredProcedure(ctx *Context, spd StoredProcedureDetails) error
   229  	// DropStoredProcedure removes the StoredProcedureDetails with the matching name from the database.
   230  	DropStoredProcedure(ctx *Context, name string) error
   231  }
   232  
   233  // EventDatabase is a database that supports the creation and execution of events. The engine will
   234  // handle execution logic for events. Integrators only need to store and retrieve EventDefinition.
   235  type EventDatabase interface {
   236  	Database
   237  	// GetEvent returns the desired EventDefinition and if it exists in the database.
   238  	// All time values of EventDefinition needs to be converted into appropriate TZ.
   239  	GetEvent(ctx *Context, name string) (EventDefinition, bool, error)
   240  	// GetEvents returns all EventDefinition for the database, as well as an opaque token that is used to
   241  	// track if events need to be reloaded. This token is specific to an EventDatabase and is passed to
   242  	// NeedsToReloadEvents so that integrators can examine it and signal if events need to be reloaded. If
   243  	// integrators do not need to implement out-of-band event reloading, then they can simply return nil for
   244  	// the token. All time values of EventDefinition needs to be converted into appropriate TZ.
   245  	GetEvents(ctx *Context) (events []EventDefinition, token interface{}, err error)
   246  	// SaveEvent stores the given EventDefinition to the database. The integrator should verify that
   247  	// the name of the new event is unique amongst existing events. The time values are converted
   248  	// into UTC TZ for storage. It returns whether the event status is enabled.
   249  	SaveEvent(ctx *Context, ed EventDefinition) (bool, error)
   250  	// DropEvent removes the EventDefinition with the matching name from the database.
   251  	DropEvent(ctx *Context, name string) error
   252  	// UpdateEvent updates existing event stored in the database with the given EventDefinition
   253  	// with the updates. The original name event is required for renaming of an event.
   254  	// The time values are converted into UTC TZ for storage. It returns whether the event status is enabled.
   255  	UpdateEvent(ctx *Context, originalName string, ed EventDefinition) (bool, error)
   256  	// UpdateLastExecuted updated the lastExecuted metadata for the given event.
   257  	// The lastExecuted time is converted into UTC TZ for storage.
   258  	UpdateLastExecuted(ctx *Context, eventName string, lastExecuted time.Time) error
   259  	// NeedsToReloadEvents allows integrators to signal that out-of-band changes have modified an event (i.e. an
   260  	// event was modified without going through the SaveEvent or UpdateEvent methods in this interface), and that
   261  	// event definitions need to be reloaded. The event executor will periodically check to see if it needs to reload
   262  	// the events from a database by calling this method and if this method returns true, then the event executor will
   263  	// call the ReloadEvents method next to load in the new event definitions. The opaque token is the same token
   264  	// returned from the last call to GetEvents and integrators are free to use whatever underlying data they
   265  	// need to track whether an out-of-band event change has occurred. If integrators to do not support events
   266  	// changing out-of-band, then they can simply return false from this method.
   267  	NeedsToReloadEvents(ctx *Context, token interface{}) (bool, error)
   268  }
   269  
   270  // ViewDatabase is implemented by databases that persist view definitions
   271  type ViewDatabase interface {
   272  	// CreateView persists the definition a view with the name and select statement given. If a view with that name
   273  	// already exists, should return ErrExistingView
   274  	CreateView(ctx *Context, name string, selectStatement, createViewStmt string) error
   275  
   276  	// DropView deletes the view named from persistent storage. If the view doesn't exist, should return
   277  	// ErrViewDoesNotExist
   278  	DropView(ctx *Context, name string) error
   279  
   280  	// GetViewDefinition returns the ViewDefinition of the view with the name given, or false if it doesn't exist.
   281  	GetViewDefinition(ctx *Context, viewName string) (ViewDefinition, bool, error)
   282  
   283  	// AllViews returns the definitions of all views in the database
   284  	AllViews(ctx *Context) ([]ViewDefinition, error)
   285  }
   286  
   287  // ViewDefinition is the named textual definition of a view
   288  type ViewDefinition struct {
   289  	Name                string
   290  	TextDefinition      string
   291  	CreateViewStatement string
   292  	SqlMode             string
   293  }
   294  
   295  // GetTableInsensitive implements a case-insensitive map lookup for tables keyed off of the table name.
   296  // Looks for exact matches first.  If no exact matches are found then any table matching the name case insensitively
   297  // should be returned.  If there is more than one table that matches a case-insensitive comparison the resolution
   298  // strategy is not defined.
   299  func GetTableInsensitive(tblName string, tables map[string]Table) (Table, bool) {
   300  	if tbl, ok := tables[tblName]; ok {
   301  		return tbl, true
   302  	}
   303  
   304  	lwrName := strings.ToLower(tblName)
   305  
   306  	for k, tbl := range tables {
   307  		if lwrName == strings.ToLower(k) {
   308  			return tbl, true
   309  		}
   310  	}
   311  
   312  	return nil, false
   313  }
   314  
   315  // GetTableNameInsensitive implements a case-insensitive search of a slice of table names. It looks for exact matches
   316  // first.  If no exact matches are found then any table matching the name case insensitively should be returned.  If
   317  // there is more than one table that matches a case-insensitive comparison the resolution strategy is not defined.
   318  func GetTableNameInsensitive(tblName string, tableNames []string) (string, bool) {
   319  	for _, name := range tableNames {
   320  		if tblName == name {
   321  			return name, true
   322  		}
   323  	}
   324  
   325  	lwrName := strings.ToLower(tblName)
   326  
   327  	for _, name := range tableNames {
   328  		if lwrName == strings.ToLower(name) {
   329  			return name, true
   330  		}
   331  	}
   332  
   333  	return "", false
   334  }
   335  
   336  // DBTableIter iterates over all tables returned by db.GetTableNames() calling cb for each one until all tables have
   337  // been processed, or an error is returned from the callback, or the cont flag is false when returned from the callback.
   338  func DBTableIter(ctx *Context, db Database, cb func(Table) (cont bool, err error)) error {
   339  	names, err := db.GetTableNames(ctx)
   340  
   341  	if err != nil {
   342  		return err
   343  	}
   344  
   345  	for _, name := range names {
   346  		tbl, ok, err := db.GetTableInsensitive(ctx, name)
   347  
   348  		if err != nil {
   349  			return err
   350  		} else if !ok {
   351  			return ErrTableNotFound.New(name)
   352  		}
   353  
   354  		cont, err := cb(tbl)
   355  
   356  		if err != nil {
   357  			return err
   358  		}
   359  
   360  		if !cont {
   361  			break
   362  		}
   363  	}
   364  
   365  	return nil
   366  }
   367  
   368  // UnresolvedDatabase is a database which has not been resolved yet.
   369  type UnresolvedDatabase string
   370  
   371  var _ Database = UnresolvedDatabase("")
   372  
   373  // Name returns the database name.
   374  func (d UnresolvedDatabase) Name() string {
   375  	return string(d)
   376  }
   377  
   378  // Tables returns the tables in the database.
   379  func (UnresolvedDatabase) Tables() map[string]Table {
   380  	return make(map[string]Table)
   381  }
   382  
   383  func (UnresolvedDatabase) GetTableInsensitive(ctx *Context, tblName string) (Table, bool, error) {
   384  	return nil, false, nil
   385  }
   386  
   387  func (UnresolvedDatabase) GetTableNames(ctx *Context) ([]string, error) {
   388  	return []string{}, nil
   389  }