Files
wehub-resource-sync 5357c39144
Fuzzer / Run Fuzzer (push) Has been cancelled
Race tests / Go race tests (ubuntu-22.04) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:01:40 +08:00

167 lines
6.2 KiB
Go

// Copyright 2023 Dolthub, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cli
import (
"context"
"errors"
"github.com/dolthub/go-mysql-server/sql"
"github.com/dolthub/dolt/go/cmd/dolt/errhand"
"github.com/dolthub/dolt/go/libraries/doltcore/env"
"github.com/dolthub/dolt/go/libraries/utils/argparser"
"github.com/dolthub/dolt/go/libraries/utils/filesys"
)
type LateBindQueryistResult struct {
Queryist Queryist
Context *sql.Context
IsRemote bool
Closer func()
}
type LateBindQueryistConfig struct {
EnableAutoGC bool
}
type LateBindQueryistOption func(*LateBindQueryistConfig)
// LateBindQueryist is a function that will be called the first time Queryist is needed for use. Input is a context which
// is appropriate for the call to commence. Output is a LateBindQueryistResult, which includes a Queryist, a sql.Context, and
// a closer function. It can also result in an error.
//
// The Closer function should be called when the Queryist is no longer needed. If the result is cached and returned to
// multiple callers, it should be called after the cached result itself is no longer needed.
//
// A LateBindqueryistResult includes enough information for a caller to know if it is connecting to a remote Dolt instance
// or if it running the SqlEngine locally in-process. The CliContext uses this, in addition to its own local state, to
// let a caller know if they are connected to a remote and if this is the first QueryEngine fetch of the process lifecycle.
// This is reflected in |IsRemote| and, in the case of QueryEngineResult, |IsFirstUse|.
//
// This state is useful for determining whether a command making use of the CliContext is being run within the context of
// another command. This is particularly interesting when running a \checkout in a dolt sql session. It makes sense to do
// so in the context of `dolt sql`, but not in the context of `dolt checkout` when connected to a remote server.
type LateBindQueryist func(ctx context.Context, opts ...LateBindQueryistOption) (LateBindQueryistResult, error)
// CliContexct is used to pass top level command information down to subcommands.
type CliContext interface {
// GlobalArgs returns the arguments passed before the subcommand.
GlobalArgs() *argparser.ArgParseResults
WorkingDir() filesys.Filesys
Config() *env.DoltCliConfig
QueryEngine(ctx context.Context, opts ...LateBindQueryistOption) (QueryEngineResult, error)
// Release resources associated with the CliContext, including
// any QueryEngines which were provisioned over the lifetime
// of the CliContext.
Close()
}
// NewCliContext creates a new CliContext instance. Arguments must not be nil.
func NewCliContext(args *argparser.ArgParseResults, config *env.DoltCliConfig, cwd filesys.Filesys, latebind LateBindQueryist) (CliContext, errhand.VerboseError) {
if args == nil || config == nil || cwd == nil || latebind == nil {
return nil, errhand.VerboseErrorFromError(errors.New("Invariant violated. args, config, cwd, and latebind must be non nil."))
}
return LateBindCliContext{
globalArgs: args,
config: config,
cwd: cwd,
activeContext: &QueryistContext{},
bind: latebind,
}, nil
}
type QueryistContext struct {
sqlCtx *sql.Context
qryist *Queryist
isRemote bool
close func()
}
// LateBindCliContext is a struct that implements CliContext. Its primary purpose is to wrap the global arguments and
// provide an implementation of the QueryEngine function. This instance is stateful to ensure that the Queryist is only
// created once.
type LateBindCliContext struct {
globalArgs *argparser.ArgParseResults
cwd filesys.Filesys
config *env.DoltCliConfig
activeContext *QueryistContext
bind LateBindQueryist
}
type QueryEngineResult struct {
Queryist Queryist
Context *sql.Context
// |true| if this is the first time the CliContext is returning a QueryEngineResult.
// Otherwise it will be |false|, which means this CliContext has already been used
// to retrieve a Queryist, and the Queryist coming back is the cached result.
IsFirstResult bool
IsRemote bool
}
// GlobalArgs returns the arguments passed before the subcommand.
func (lbc LateBindCliContext) GlobalArgs() *argparser.ArgParseResults {
return lbc.globalArgs
}
// QueryEngine returns a Queryist, a sql.Context, a closer function, and an error. It ensures that only one call to the
// LateBindQueryist is made, and caches the result. Note that if this is called twice, the closer function returns will
// be nil, callers should check if is nil.
func (lbc LateBindCliContext) QueryEngine(ctx context.Context, opts ...LateBindQueryistOption) (res QueryEngineResult, err error) {
if lbc.activeContext != nil && lbc.activeContext.qryist != nil && lbc.activeContext.sqlCtx != nil {
res.Queryist = *lbc.activeContext.qryist
res.Context = lbc.activeContext.sqlCtx
res.IsRemote = lbc.activeContext.isRemote
// Returning a cached result.
res.IsFirstResult = false
return res, nil
}
bindRes, err := lbc.bind(ctx, opts...)
if err != nil {
return res, err
}
lbc.activeContext.qryist = &bindRes.Queryist
lbc.activeContext.sqlCtx = bindRes.Context
lbc.activeContext.close = bindRes.Closer
lbc.activeContext.isRemote = bindRes.IsRemote
res.Queryist = bindRes.Queryist
res.Context = bindRes.Context
res.IsRemote = bindRes.IsRemote
res.IsFirstResult = true
return res, nil
}
func (lbc LateBindCliContext) Close() {
if lbc.activeContext != nil && lbc.activeContext.close != nil {
lbc.activeContext.close()
}
}
func (lbc LateBindCliContext) WorkingDir() filesys.Filesys {
return lbc.cwd
}
// Config returns the dolt config stored in CliContext
func (lbc LateBindCliContext) Config() *env.DoltCliConfig {
return lbc.config
}
var _ CliContext = LateBindCliContext{}