Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 33 additions & 6 deletions go/cmd/dolt/commands/engine/sqlengine.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,9 @@ type SqlEngineConfig struct {
// Intended for embedded-driver use-cases that need to influence dbfactory / storage open behavior.
DBLoadParams map[string]interface{}

// ProviderFactory controls how the DatabaseProvider is created. If nil, sqle.DoltProviderFactory is used.
ProviderFactory sqle.ProviderFactory

FatalBehavior dherrors.FatalBehavior
}

Expand Down Expand Up @@ -181,12 +184,31 @@ func NewSqlEngine(
locations = append(locations, nil)
}

factory := config.ProviderFactory
if factory == nil {
factory = sqle.DoltProviderFactory{}
}

b := env.GetDefaultInitBranch(mrEnv.Config())
pro, err := sqle.NewDoltDatabaseProviderWithDatabases(b, mrEnv.FileSystem(), all, locations, config.EngineOverrides)
engineProvider, err := factory.NewProvider(b, mrEnv.FileSystem(), all, locations, config.EngineOverrides)
if err != nil {
return nil, err
}
pro = pro.WithRemoteDialer(mrEnv.RemoteDialProvider())

// Extract the underlying *DoltDatabaseProvider for Dolt-specific configuration. For the
// default DoltProviderFactory the result IS a *DoltDatabaseProvider; custom factories
// (e.g. Doltgres) return a wrapper and implement DoltProviderUnwrapper to expose it.
var pro *sqle.DoltDatabaseProvider
switch p := engineProvider.(type) {
case *sqle.DoltDatabaseProvider:
pro = p
case sqle.DoltProviderUnwrapper:
pro = p.UnderlyingDoltProvider()
default:
return nil, fmt.Errorf("provider %T must be or wrap a *sqle.DoltDatabaseProvider", engineProvider)
}

pro.SetRemoteDialer(mrEnv.RemoteDialProvider())
if config != nil && len(config.DBLoadParams) > 0 {
pro.SetDBLoadParams(config.DBLoadParams)
}
Expand All @@ -200,7 +222,7 @@ func NewSqlEngine(

sqlEngine := &SqlEngine{}
// Create the engine
engine := gms.New(analyzer.NewBuilder(pro).AddOverrides(config.EngineOverrides).Build(), &gms.Config{
engine := gms.New(analyzer.NewBuilder(engineProvider).AddOverrides(config.EngineOverrides).Build(), &gms.Config{
IsReadOnly: config.IsReadOnly,
IsServerLocked: config.IsServerLocked,
}).WithBackgroundThreads(bThreads)
Expand Down Expand Up @@ -372,7 +394,7 @@ func applySystemVariables(vars sql.SystemVariableRegistry, cfg SystemVariables)
func (se *SqlEngine) InitStats(ctx context.Context) error {
// configuring stats depends on sessionBuilder
// sessionBuilder needs ref to statsProv
pro := se.GetUnderlyingEngine().Analyzer.Catalog.DbProvider.(*sqle.DoltDatabaseProvider)
pro := se.GetUnderlyingEngine().Analyzer.Catalog.DbProvider.(dsess.DoltDatabaseProvider)
sqlCtx, err := se.NewLocalContext(ctx)
if err != nil {
return err
Expand All @@ -386,8 +408,13 @@ func (se *SqlEngine) InitStats(ctx context.Context) error {
_, memOnly, _ := sql.SystemVariables.GetGlobal(dsess.DoltStatsMemoryOnly)
sc.SetMemOnly(memOnly.(int8) == 1)

pro.InitDatabaseHooks = append(pro.InitDatabaseHooks, statspro.NewInitDatabaseHook(sc))
pro.DropDatabaseHooks = append(pro.DropDatabaseHooks, statspro.NewDropDatabaseHook(sc))
if adder, ok := se.GetUnderlyingEngine().Analyzer.Catalog.DbProvider.(interface {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably want a named interface for this

AddInitDatabaseHook(sqle.InitDatabaseHook)
AddDropDatabaseHook(sqle.DropDatabaseHook)
}); ok {
adder.AddInitDatabaseHook(statspro.NewInitDatabaseHook(sc))
adder.AddDropDatabaseHook(statspro.NewDropDatabaseHook(sc))
}

var sqlDbs []sql.Database
for _, db := range dbs {
Expand Down
4 changes: 4 additions & 0 deletions go/cmd/dolt/commands/sqlserver/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ type Config struct {
Controller *svcs.Controller
ProtocolListenerFactory server.ProtocolListenerFunc
MCP *MCPConfig

// ProviderFactory controls how the DatabaseProvider is instantiated
ProviderFactory sqle.ProviderFactory
}

// Serve starts a MySQL-compatible server. Returns any errors that were encountered.
Expand Down Expand Up @@ -277,6 +280,7 @@ func ConfigureServices(
BinlogReplicaController: binlogreplication.DoltBinlogReplicaController,
SkipRootUserInitialization: cfg.SkipRootUserInit,
EngineOverrides: cfg.ServerConfig.Overrides(),
ProviderFactory: cfg.ProviderFactory,
}
return nil
},
Expand Down
2 changes: 1 addition & 1 deletion go/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ require (
github.com/dolthub/dolt-mcp v0.3.4
github.com/dolthub/eventsapi_schema v0.0.0-20260310172945-37a9265ade69
github.com/dolthub/flatbuffers/v23 v23.3.3-dh.2
github.com/dolthub/go-mysql-server v0.20.1-0.20260529165710-0c9baca7aa28
github.com/dolthub/go-mysql-server v0.20.1-0.20260529204403-6d1b298fbfe3
github.com/dolthub/gozstd v0.0.0-20240423170813-23a2903bca63
github.com/edsrzf/mmap-go v1.2.0
github.com/esote/minmaxheap v1.0.0
Expand Down
2 changes: 2 additions & 0 deletions go/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,8 @@ github.com/dolthub/go-icu-regex v0.0.0-20260412212219-49724d547866 h1:U6gSf5I0e6
github.com/dolthub/go-icu-regex v0.0.0-20260412212219-49724d547866/go.mod h1:F3cnm+vMRK1HaU6+rNqQrOCyR03HHhR1GWG2gnPOqaE=
github.com/dolthub/go-mysql-server v0.20.1-0.20260529165710-0c9baca7aa28 h1:7/u3ZCuzvCLF7u8oE3ZhdqhtXHnjXIf7fsdqevHa7ms=
github.com/dolthub/go-mysql-server v0.20.1-0.20260529165710-0c9baca7aa28/go.mod h1:UTL4UvG/y8PMBcI8I60gf0DH4YPBALW/8UQCcvft95Y=
github.com/dolthub/go-mysql-server v0.20.1-0.20260529204403-6d1b298fbfe3 h1:YQjGSg7fWpaoNGzsFfvevHYP0aHETm24IZnncsUg4Tc=
github.com/dolthub/go-mysql-server v0.20.1-0.20260529204403-6d1b298fbfe3/go.mod h1:UTL4UvG/y8PMBcI8I60gf0DH4YPBALW/8UQCcvft95Y=
github.com/dolthub/gozstd v0.0.0-20240423170813-23a2903bca63 h1:OAsXLAPL4du6tfbBgK0xXHZkOlos63RdKYS3Sgw/dfI=
github.com/dolthub/gozstd v0.0.0-20240423170813-23a2903bca63/go.mod h1:lV7lUeuDhH5thVGDCKXbatwKy2KW80L4rMT46n+Y2/Q=
github.com/dolthub/ishell v0.0.0-20260414231531-5f031e3e9037 h1:oIW9HwuWrhxv+4HZxA+QQSKHLqWFyXZ2FmNjUYwkdiM=
Expand Down
34 changes: 19 additions & 15 deletions go/libraries/doltcore/sqle/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,15 @@ type Database struct {
revName string
editOpts editor.Options
revType dsess.RevisionType

// SchemaWrap, when non-nil, is called by GetSchema and AllSchemas to transform the
// returned sql.DatabaseSchema before passing it to the caller. The first argument is
// the original requested schema name (preserving case); the second is the Database
// value with schemaName set to the stored (canonical) name.
// TODO: This is currently used by Doltgres to wrap databases, but we should be able
// to completely remove this in a future refactoring if Doltgres overrides
// GetTableInsensitive().
SchemaWrap func(requestedName string, db Database) sql.DatabaseSchema
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comment on doltgres PR

}

var _ dsess.SqlDatabase = Database{}
Expand Down Expand Up @@ -2331,28 +2340,27 @@ func (db Database) GetSchema(ctx *sql.Context, schemaName string) (sql.DatabaseS
for _, schema := range schemas {
if strings.EqualFold(schema.Name, schemaName) {
db.schemaName = schema.Name
handledSchema, err := HandleSchema(ctx, schemaName, db)
if err != nil {
return nil, false, err
}
return handledSchema, true, nil
return db.applySchemaWrap(schemaName, db), true, nil
}
}

// For a temporary backwards compatibility solution, always pretend the public schema exists.
// We create it explicitly for new databases.
if strings.EqualFold(schemaName, "public") {
db.schemaName = "public"
return db, true, nil
return db.applySchemaWrap(schemaName, db), true, nil
}

return nil, false, nil
}

// HandleSchema is used by Doltgres to intercept a database for the purposes of system tables. In Dolt, this just
// returns the given database.
var HandleSchema = func(ctx *sql.Context, schemaName string, db Database) (sql.DatabaseSchema, error) {
return db, nil
// applySchemaWrap calls SchemaWrap if set, otherwise returns sdb as-is. requestedName is
// the original schema name from the caller (before EqualFold normalization).
func (db Database) applySchemaWrap(requestedName string, sdb Database) sql.DatabaseSchema {
if db.SchemaWrap != nil {
return db.SchemaWrap(requestedName, sdb)
}
return sdb
}

// AllSchemas implements sql.SchemaDatabase
Expand All @@ -2375,11 +2383,7 @@ func (db Database) AllSchemas(ctx *sql.Context) ([]sql.DatabaseSchema, error) {
for i, schema := range schemas {
sdb := db
sdb.schemaName = schema.Name
handledDb, err := HandleSchema(ctx, schema.Name, sdb)
if err != nil {
return nil, err
}
dbSchemas[i] = handledDb
dbSchemas[i] = db.applySchemaWrap(schema.Name, sdb)
}

// For doltgres, the information_schema database should be a schema.
Expand Down
31 changes: 26 additions & 5 deletions go/libraries/doltcore/sqle/database_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,29 @@ type DoltDatabaseProvider struct {
InitDatabaseHooks []InitDatabaseHook
}

// ProviderFactory creates a sql.DatabaseProvider for use as the engine's analyzer catalog
// provider.
type ProviderFactory interface {
NewProvider(defaultBranch string, fs filesys.Filesys, databases []dsess.SqlDatabase, locations []filesys.Filesys, overrides sql.EngineOverrides) (sql.DatabaseProvider, error)
}

// DoltProviderUnwrapper is an optional interface for sql.DatabaseProvider implementations
// that wrap a *DoltDatabaseProvider. NewSqlEngine uses it to access the underlying
// provider for Dolt-specific configuration (hooks, dialer, etc.) that is not part of
// the sql.DatabaseProvider interface.
type DoltProviderUnwrapper interface {
UnderlyingDoltProvider() *DoltDatabaseProvider
}

// DoltProviderFactory is the default ProviderFactory used by Dolt.
type DoltProviderFactory struct{}

var _ ProviderFactory = DoltProviderFactory{}

func (DoltProviderFactory) NewProvider(defaultBranch string, fs filesys.Filesys, databases []dsess.SqlDatabase, locations []filesys.Filesys, overrides sql.EngineOverrides) (sql.DatabaseProvider, error) {
return NewDoltDatabaseProviderWithDatabases(defaultBranch, fs, databases, locations, overrides)
}

type remoteDialerWithGitCacheRoot struct {
dbfactory.GRPCDialProvider
root string
Expand Down Expand Up @@ -220,11 +243,9 @@ func (p *DoltDatabaseProvider) WithDbFactoryUrl(url string) *DoltDatabaseProvide
return &cp
}

// WithRemoteDialer returns a copy of this provider with the dialer provided
func (p *DoltDatabaseProvider) WithRemoteDialer(provider dbfactory.GRPCDialProvider) *DoltDatabaseProvider {
cp := *p
cp.remoteDialer = provider
return &cp
// SetRemoteDialer sets the remote dialer on this provider in place and returns it.
func (p *DoltDatabaseProvider) SetRemoteDialer(provider dbfactory.GRPCDialProvider) {
p.remoteDialer = provider
}

// SetDBLoadParams sets optional DB load params for newly created / registered databases. The provided map is cloned.
Expand Down
2 changes: 1 addition & 1 deletion go/libraries/doltcore/sqle/statspro/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ func (k tableIndexesKey) String() string {

type StatsController struct {
logger *logrus.Logger
pro *sqle.DoltDatabaseProvider
pro dsess.DoltDatabaseProvider
bgThreads *sql.BackgroundThreads
statsBackingDb filesys.Filesys

Expand Down
2 changes: 1 addition & 1 deletion go/libraries/doltcore/sqle/statspro/listener.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ func (sc *StatsController) Restart(ctx *sql.Context) error {
}

// Init should only be called once
func (sc *StatsController) Init(ctx context.Context, pro *sqle.DoltDatabaseProvider, ctxGen ctxFactory, dbs []sql.Database) error {
func (sc *StatsController) Init(ctx context.Context, pro dsess.DoltDatabaseProvider, ctxGen ctxFactory, dbs []sql.Database) error {
sc.pro = pro

ctxGenWrap := func(ctx context.Context) (*sql.Context, error) {
Expand Down
Loading