github.com/dolthub/go-mysql-server@v0.18.0/memory/provider.go (about)

     1  package memory
     2  
     3  import (
     4  	"sort"
     5  	"strings"
     6  	"sync"
     7  
     8  	"github.com/dolthub/go-mysql-server/internal/similartext"
     9  	"github.com/dolthub/go-mysql-server/sql"
    10  )
    11  
    12  var _ sql.DatabaseProvider = (*DbProvider)(nil)
    13  var _ sql.MutableDatabaseProvider = (*DbProvider)(nil)
    14  var _ sql.TableFunctionProvider = (*DbProvider)(nil)
    15  var _ sql.ExternalStoredProcedureProvider = (*DbProvider)(nil)
    16  
    17  // DbProvider is a provider for in-memory databases
    18  type DbProvider struct {
    19  	dbs                       map[string]sql.Database
    20  	history                   bool
    21  	readOnly                  bool
    22  	nativeIndexes             bool
    23  	mu                        *sync.RWMutex
    24  	tableFunctions            map[string]sql.TableFunction
    25  	externalProcedureRegistry sql.ExternalStoredProcedureRegistry
    26  }
    27  
    28  type ProviderOption func(*DbProvider)
    29  
    30  // NewDBProvider creates a new DbProvider with the default options and the databases specified
    31  func NewDBProvider(dbs ...sql.Database) *DbProvider {
    32  	dbMap := make(map[string]sql.Database, len(dbs))
    33  	for _, db := range dbs {
    34  		dbMap[strings.ToLower(db.Name())] = db
    35  	}
    36  
    37  	externalProcedureRegistry := sql.NewExternalStoredProcedureRegistry()
    38  	for _, esp := range ExternalStoredProcedures {
    39  		externalProcedureRegistry.Register(esp)
    40  	}
    41  
    42  	return &DbProvider{
    43  		dbs:                       dbMap,
    44  		mu:                        &sync.RWMutex{},
    45  		tableFunctions:            make(map[string]sql.TableFunction),
    46  		externalProcedureRegistry: externalProcedureRegistry,
    47  	}
    48  }
    49  
    50  // NewDBProviderWithOpts creates a new DbProvider with the given options and no databases
    51  func NewDBProviderWithOpts(opts ...ProviderOption) sql.MutableDatabaseProvider {
    52  	pro := NewDBProvider()
    53  	for _, opt := range opts {
    54  		opt(pro)
    55  	}
    56  
    57  	return pro
    58  }
    59  
    60  func (pro *DbProvider) WithTableFunctions(fns ...sql.TableFunction) (sql.TableFunctionProvider, error) {
    61  	funcs := make(map[string]sql.TableFunction)
    62  	for _, fn := range fns {
    63  		funcs[strings.ToLower(fn.Name())] = fn
    64  	}
    65  	cp := *pro
    66  	cp.tableFunctions = funcs
    67  	return &cp, nil
    68  }
    69  
    70  // WithOption modifies the provider with the given option
    71  func (pro *DbProvider) WithOption(opt ProviderOption) {
    72  	opt(pro)
    73  }
    74  
    75  // ReadOnlyProvider returns a ProviderOption to construct a memoryDBProvider that is read-only
    76  func ReadOnlyProvider(enableReadOnly bool) ProviderOption {
    77  	return func(pro *DbProvider) {
    78  		pro.readOnly = enableReadOnly
    79  	}
    80  }
    81  
    82  func NativeIndexProvider(useNativeIndexes bool) ProviderOption {
    83  	return func(pro *DbProvider) {
    84  		pro.nativeIndexes = useNativeIndexes
    85  	}
    86  }
    87  
    88  // HistoryProvider returns a ProviderOption to construct a memoryDBProvider that uses history databases
    89  func HistoryProvider(enableHistory bool) ProviderOption {
    90  	return func(pro *DbProvider) {
    91  		pro.history = enableHistory
    92  	}
    93  }
    94  
    95  // WithDbsOption returns a ProviderOption to construct a DbProvider with the given databases
    96  func WithDbsOption(dbs []sql.Database) ProviderOption {
    97  	return func(pro *DbProvider) {
    98  		pro.dbs = make(map[string]sql.Database, len(dbs))
    99  		for _, db := range dbs {
   100  			pro.dbs[strings.ToLower(db.Name())] = db
   101  		}
   102  	}
   103  }
   104  
   105  // Database returns the Database with the given name if it exists.
   106  func (pro *DbProvider) Database(_ *sql.Context, name string) (sql.Database, error) {
   107  	pro.mu.RLock()
   108  	defer pro.mu.RUnlock()
   109  
   110  	db, ok := pro.dbs[strings.ToLower(name)]
   111  	if ok {
   112  		return db, nil
   113  	}
   114  
   115  	names := make([]string, 0, len(pro.dbs))
   116  	for n := range pro.dbs {
   117  		names = append(names, n)
   118  	}
   119  
   120  	similar := similartext.Find(names, name)
   121  	return nil, sql.ErrDatabaseNotFound.New(name + similar)
   122  }
   123  
   124  // HasDatabase returns the Database with the given name if it exists.
   125  func (pro *DbProvider) HasDatabase(_ *sql.Context, name string) bool {
   126  	pro.mu.RLock()
   127  	defer pro.mu.RUnlock()
   128  
   129  	_, ok := pro.dbs[strings.ToLower(name)]
   130  	return ok
   131  }
   132  
   133  // AllDatabases returns the Database with the given name if it exists.
   134  func (pro *DbProvider) AllDatabases(*sql.Context) []sql.Database {
   135  	pro.mu.RLock()
   136  	defer pro.mu.RUnlock()
   137  
   138  	all := make([]sql.Database, 0, len(pro.dbs))
   139  	for _, db := range pro.dbs {
   140  		all = append(all, db)
   141  	}
   142  
   143  	sort.Slice(all, func(i, j int) bool {
   144  		return all[i].Name() < all[j].Name()
   145  	})
   146  
   147  	return all
   148  }
   149  
   150  // CreateDatabase implements MutableDatabaseProvider.
   151  func (pro *DbProvider) CreateDatabase(_ *sql.Context, name string) (err error) {
   152  	pro.mu.Lock()
   153  	defer pro.mu.Unlock()
   154  
   155  	var db sql.Database
   156  	if pro.readOnly {
   157  		db = NewReadOnlyDatabase(name)
   158  		if pro.nativeIndexes {
   159  			db.(ReadOnlyDatabase).EnablePrimaryKeyIndexes()
   160  		}
   161  	} else if pro.history {
   162  		db = NewHistoryDatabase(name)
   163  		if pro.nativeIndexes {
   164  			db.(*HistoryDatabase).EnablePrimaryKeyIndexes()
   165  		}
   166  	} else {
   167  		db = NewDatabase(name)
   168  		if pro.nativeIndexes {
   169  			db.(*Database).EnablePrimaryKeyIndexes()
   170  		}
   171  	}
   172  
   173  	pro.dbs[strings.ToLower(db.Name())] = db
   174  	return
   175  }
   176  
   177  // DropDatabase implements MutableDatabaseProvider.
   178  func (pro *DbProvider) DropDatabase(_ *sql.Context, name string) (err error) {
   179  	pro.mu.Lock()
   180  	defer pro.mu.Unlock()
   181  
   182  	delete(pro.dbs, strings.ToLower(name))
   183  	return
   184  }
   185  
   186  // ExternalStoredProcedure implements sql.ExternalStoredProcedureProvider
   187  func (pro *DbProvider) ExternalStoredProcedure(_ *sql.Context, name string, numOfParams int) (*sql.ExternalStoredProcedureDetails, error) {
   188  	return pro.externalProcedureRegistry.LookupByNameAndParamCount(name, numOfParams)
   189  }
   190  
   191  // ExternalStoredProcedures implements sql.ExternalStoredProcedureProvider
   192  func (pro *DbProvider) ExternalStoredProcedures(_ *sql.Context, name string) ([]sql.ExternalStoredProcedureDetails, error) {
   193  	return pro.externalProcedureRegistry.LookupByName(name)
   194  }
   195  
   196  // TableFunction implements sql.TableFunctionProvider
   197  func (pro *DbProvider) TableFunction(_ *sql.Context, name string) (sql.TableFunction, error) {
   198  	if tableFunction, ok := pro.tableFunctions[name]; ok {
   199  		return tableFunction, nil
   200  	}
   201  
   202  	return nil, sql.ErrTableFunctionNotFound.New(name)
   203  }