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 }