github.com/gogf/gf@v1.16.9/database/gdb/gdb.go (about)

     1  // Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
     2  //
     3  // This Source Code Form is subject to the terms of the MIT License.
     4  // If a copy of the MIT was not distributed with this file,
     5  // You can obtain one at https://github.com/gogf/gf.
     6  
     7  // Package gdb provides ORM features for popular relationship databases.
     8  package gdb
     9  
    10  import (
    11  	"context"
    12  	"database/sql"
    13  	"github.com/gogf/gf/errors/gcode"
    14  	"time"
    15  
    16  	"github.com/gogf/gf/errors/gerror"
    17  	"github.com/gogf/gf/os/gcmd"
    18  
    19  	"github.com/gogf/gf/container/gvar"
    20  	"github.com/gogf/gf/internal/intlog"
    21  
    22  	"github.com/gogf/gf/os/glog"
    23  
    24  	"github.com/gogf/gf/container/gmap"
    25  	"github.com/gogf/gf/container/gtype"
    26  	"github.com/gogf/gf/os/gcache"
    27  	"github.com/gogf/gf/util/grand"
    28  )
    29  
    30  // DB defines the interfaces for ORM operations.
    31  type DB interface {
    32  	// ===========================================================================
    33  	// Model creation.
    34  	// ===========================================================================
    35  
    36  	// Table function is deprecated, use Model instead.
    37  	// The DB interface is designed not only for
    38  	// relational databases but also for NoSQL databases in the future. The name
    39  	// "Table" is not proper for that purpose any more.
    40  	// Also see Core.Table.
    41  	// Deprecated.
    42  	Table(tableNameOrStruct ...interface{}) *Model
    43  
    44  	// Model creates and returns a new ORM model from given schema.
    45  	// The parameter `table` can be more than one table names, and also alias name, like:
    46  	// 1. Model names:
    47  	//    Model("user")
    48  	//    Model("user u")
    49  	//    Model("user, user_detail")
    50  	//    Model("user u, user_detail ud")
    51  	// 2. Model name with alias: Model("user", "u")
    52  	// Also see Core.Model.
    53  	Model(tableNameOrStruct ...interface{}) *Model
    54  
    55  	// Raw creates and returns a model based on a raw sql not a table.
    56  	Raw(rawSql string, args ...interface{}) *Model
    57  
    58  	// Schema creates and returns a schema.
    59  	// Also see Core.Schema.
    60  	Schema(schema string) *Schema
    61  
    62  	// With creates and returns an ORM model based on meta data of given object.
    63  	// Also see Core.With.
    64  	With(objects ...interface{}) *Model
    65  
    66  	// Open creates a raw connection object for database with given node configuration.
    67  	// Note that it is not recommended using the this function manually.
    68  	// Also see DriverMysql.Open.
    69  	Open(config *ConfigNode) (*sql.DB, error)
    70  
    71  	// Ctx is a chaining function, which creates and returns a new DB that is a shallow copy
    72  	// of current DB object and with given context in it.
    73  	// Also see Core.Ctx.
    74  	Ctx(ctx context.Context) DB
    75  
    76  	// Close closes the database and prevents new queries from starting.
    77  	// Close then waits for all queries that have started processing on the server
    78  	// to finish.
    79  	//
    80  	// It is rare to Close a DB, as the DB handle is meant to be
    81  	// long-lived and shared between many goroutines.
    82  	Close(ctx context.Context) error
    83  
    84  	// ===========================================================================
    85  	// Query APIs.
    86  	// ===========================================================================
    87  
    88  	Query(sql string, args ...interface{}) (*sql.Rows, error) // See Core.Query.
    89  	Exec(sql string, args ...interface{}) (sql.Result, error) // See Core.Exec.
    90  	Prepare(sql string, execOnMaster ...bool) (*Stmt, error)  // See Core.Prepare.
    91  
    92  	// ===========================================================================
    93  	// Common APIs for CURD.
    94  	// ===========================================================================
    95  
    96  	Insert(table string, data interface{}, batch ...int) (sql.Result, error)                               // See Core.Insert.
    97  	InsertIgnore(table string, data interface{}, batch ...int) (sql.Result, error)                         // See Core.InsertIgnore.
    98  	InsertAndGetId(table string, data interface{}, batch ...int) (int64, error)                            // See Core.InsertAndGetId.
    99  	Replace(table string, data interface{}, batch ...int) (sql.Result, error)                              // See Core.Replace.
   100  	Save(table string, data interface{}, batch ...int) (sql.Result, error)                                 // See Core.Save.
   101  	Update(table string, data interface{}, condition interface{}, args ...interface{}) (sql.Result, error) // See Core.Update.
   102  	Delete(table string, condition interface{}, args ...interface{}) (sql.Result, error)                   // See Core.Delete.
   103  
   104  	// ===========================================================================
   105  	// Internal APIs for CURD, which can be overwritten by custom CURD implements.
   106  	// ===========================================================================
   107  
   108  	DoGetAll(ctx context.Context, link Link, sql string, args ...interface{}) (result Result, err error)                                           // See Core.DoGetAll.
   109  	DoInsert(ctx context.Context, link Link, table string, data List, option DoInsertOption) (result sql.Result, err error)                        // See Core.DoInsert.
   110  	DoUpdate(ctx context.Context, link Link, table string, data interface{}, condition string, args ...interface{}) (result sql.Result, err error) // See Core.DoUpdate.
   111  	DoDelete(ctx context.Context, link Link, table string, condition string, args ...interface{}) (result sql.Result, err error)                   // See Core.DoDelete.
   112  	DoQuery(ctx context.Context, link Link, sql string, args ...interface{}) (rows *sql.Rows, err error)                                           // See Core.DoQuery.
   113  	DoExec(ctx context.Context, link Link, sql string, args ...interface{}) (result sql.Result, err error)                                         // See Core.DoExec.
   114  	DoCommit(ctx context.Context, link Link, sql string, args []interface{}) (newSql string, newArgs []interface{}, err error)                     // See Core.DoCommit.
   115  	DoPrepare(ctx context.Context, link Link, sql string) (*Stmt, error)                                                                           // See Core.DoPrepare.
   116  
   117  	// ===========================================================================
   118  	// Query APIs for convenience purpose.
   119  	// ===========================================================================
   120  
   121  	GetAll(sql string, args ...interface{}) (Result, error)                // See Core.GetAll.
   122  	GetOne(sql string, args ...interface{}) (Record, error)                // See Core.GetOne.
   123  	GetValue(sql string, args ...interface{}) (Value, error)               // See Core.GetValue.
   124  	GetArray(sql string, args ...interface{}) ([]Value, error)             // See Core.GetArray.
   125  	GetCount(sql string, args ...interface{}) (int, error)                 // See Core.GetCount.
   126  	GetScan(objPointer interface{}, sql string, args ...interface{}) error // See Core.GetScan.
   127  	Union(unions ...*Model) *Model                                         // See Core.Union.
   128  	UnionAll(unions ...*Model) *Model                                      // See Core.UnionAll.
   129  
   130  	// ===========================================================================
   131  	// Master/Slave specification support.
   132  	// ===========================================================================
   133  
   134  	Master(schema ...string) (*sql.DB, error) // See Core.Master.
   135  	Slave(schema ...string) (*sql.DB, error)  // See Core.Slave.
   136  
   137  	// ===========================================================================
   138  	// Ping-Pong.
   139  	// ===========================================================================
   140  
   141  	PingMaster() error // See Core.PingMaster.
   142  	PingSlave() error  // See Core.PingSlave.
   143  
   144  	// ===========================================================================
   145  	// Transaction.
   146  	// ===========================================================================
   147  
   148  	Begin() (*TX, error)                                                              // See Core.Begin.
   149  	Transaction(ctx context.Context, f func(ctx context.Context, tx *TX) error) error // See Core.Transaction.
   150  
   151  	// ===========================================================================
   152  	// Configuration methods.
   153  	// ===========================================================================
   154  
   155  	GetCache() *gcache.Cache            // See Core.GetCache.
   156  	SetDebug(debug bool)                // See Core.SetDebug.
   157  	GetDebug() bool                     // See Core.GetDebug.
   158  	SetSchema(schema string)            // See Core.SetSchema.
   159  	GetSchema() string                  // See Core.GetSchema.
   160  	GetPrefix() string                  // See Core.GetPrefix.
   161  	GetGroup() string                   // See Core.GetGroup.
   162  	SetDryRun(enabled bool)             // See Core.SetDryRun.
   163  	GetDryRun() bool                    // See Core.GetDryRun.
   164  	SetLogger(logger *glog.Logger)      // See Core.SetLogger.
   165  	GetLogger() *glog.Logger            // See Core.GetLogger.
   166  	GetConfig() *ConfigNode             // See Core.GetConfig.
   167  	SetMaxIdleConnCount(n int)          // See Core.SetMaxIdleConnCount.
   168  	SetMaxOpenConnCount(n int)          // See Core.SetMaxOpenConnCount.
   169  	SetMaxConnLifeTime(d time.Duration) // See Core.SetMaxConnLifeTime.
   170  
   171  	// ===========================================================================
   172  	// Utility methods.
   173  	// ===========================================================================
   174  
   175  	GetCtx() context.Context                                                                         // See Core.GetCtx.
   176  	GetCore() *Core                                                                                  // See Core.GetCore
   177  	GetChars() (charLeft string, charRight string)                                                   // See Core.GetChars.
   178  	Tables(ctx context.Context, schema ...string) (tables []string, err error)                       // See Core.Tables.
   179  	TableFields(ctx context.Context, table string, schema ...string) (map[string]*TableField, error) // See Core.TableFields.
   180  	FilteredLink() string                                                                            // FilteredLink is used for filtering sensitive information in `Link` configuration before output it to tracing server.
   181  }
   182  
   183  // Core is the base struct for database management.
   184  type Core struct {
   185  	db     DB              // DB interface object.
   186  	ctx    context.Context // Context for chaining operation only. Do not set a default value in Core initialization.
   187  	group  string          // Configuration group name.
   188  	debug  *gtype.Bool     // Enable debug mode for the database, which can be changed in runtime.
   189  	cache  *gcache.Cache   // Cache manager, SQL result cache only.
   190  	links  *gmap.StrAnyMap // links caches all created links by node.
   191  	schema *gtype.String   // Custom schema for this object.
   192  	logger *glog.Logger    // Logger for logging functionality.
   193  	config *ConfigNode     // Current config node.
   194  }
   195  
   196  // Driver is the interface for integrating sql drivers into package gdb.
   197  type Driver interface {
   198  	// New creates and returns a database object for specified database server.
   199  	New(core *Core, node *ConfigNode) (DB, error)
   200  }
   201  
   202  // Link is a common database function wrapper interface.
   203  type Link interface {
   204  	Query(sql string, args ...interface{}) (*sql.Rows, error)
   205  	Exec(sql string, args ...interface{}) (sql.Result, error)
   206  	Prepare(sql string) (*sql.Stmt, error)
   207  	QueryContext(ctx context.Context, sql string, args ...interface{}) (*sql.Rows, error)
   208  	ExecContext(ctx context.Context, sql string, args ...interface{}) (sql.Result, error)
   209  	PrepareContext(ctx context.Context, sql string) (*sql.Stmt, error)
   210  	IsTransaction() bool
   211  }
   212  
   213  // Logger is the logging interface for DB.
   214  type Logger interface {
   215  	Error(ctx context.Context, s string)
   216  	Debug(ctx context.Context, s string)
   217  }
   218  
   219  // Sql is the sql recording struct.
   220  type Sql struct {
   221  	Sql           string        // SQL string(may contain reserved char '?').
   222  	Type          string        // SQL operation type.
   223  	Args          []interface{} // Arguments for this sql.
   224  	Format        string        // Formatted sql which contains arguments in the sql.
   225  	Error         error         // Execution result.
   226  	Start         int64         // Start execution timestamp in milliseconds.
   227  	End           int64         // End execution timestamp in milliseconds.
   228  	Group         string        // Group is the group name of the configuration that the sql is executed from.
   229  	IsTransaction bool          // IsTransaction marks whether this sql is executed in transaction.
   230  }
   231  
   232  // DoInsertOption is the input struct for function DoInsert.
   233  type DoInsertOption struct {
   234  	OnDuplicateStr string
   235  	OnDuplicateMap map[string]interface{}
   236  	InsertOption   int // Insert operation.
   237  	BatchCount     int // Batch count for batch inserting.
   238  }
   239  
   240  // TableField is the struct for table field.
   241  type TableField struct {
   242  	Index   int         // For ordering purpose as map is unordered.
   243  	Name    string      // Field name.
   244  	Type    string      // Field type.
   245  	Null    bool        // Field can be null or not.
   246  	Key     string      // The index information(empty if it's not a index).
   247  	Default interface{} // Default value for the field.
   248  	Extra   string      // Extra information.
   249  	Comment string      // Comment.
   250  }
   251  
   252  // Counter  is the type for update count.
   253  type Counter struct {
   254  	Field string
   255  	Value float64
   256  }
   257  
   258  type (
   259  	Raw    string                   // Raw is a raw sql that will not be treated as argument but as a direct sql part.
   260  	Value  = *gvar.Var              // Value is the field value type.
   261  	Record map[string]Value         // Record is the row record of the table.
   262  	Result []Record                 // Result is the row record array.
   263  	Map    = map[string]interface{} // Map is alias of map[string]interface{}, which is the most common usage map type.
   264  	List   = []Map                  // List is type of map array.
   265  )
   266  
   267  const (
   268  	queryTypeNormal         = 0
   269  	queryTypeCount          = 1
   270  	unionTypeNormal         = 0
   271  	unionTypeAll            = 1
   272  	insertOptionDefault     = 0
   273  	insertOptionReplace     = 1
   274  	insertOptionSave        = 2
   275  	insertOptionIgnore      = 3
   276  	defaultBatchNumber      = 10               // Per count for batch insert/replace/save.
   277  	defaultMaxIdleConnCount = 10               // Max idle connection count in pool.
   278  	defaultMaxOpenConnCount = 100              // Max open connection count in pool.
   279  	defaultMaxConnLifeTime  = 30 * time.Second // Max life time for per connection in pool in seconds.
   280  	ctxTimeoutTypeExec      = iota
   281  	ctxTimeoutTypeQuery
   282  	ctxTimeoutTypePrepare
   283  	commandEnvKeyForDryRun = "gf.gdb.dryrun"
   284  	ctxStrictKeyName       = "gf.gdb.CtxStrictEnabled"
   285  	ctxStrictErrorStr      = "context is required for database operation, did you missing call function Ctx"
   286  )
   287  
   288  var (
   289  	// instances is the management map for instances.
   290  	instances = gmap.NewStrAnyMap(true)
   291  
   292  	// driverMap manages all custom registered driver.
   293  	driverMap = map[string]Driver{
   294  		"mysql":  &DriverMysql{},
   295  		"mssql":  &DriverMssql{},
   296  		"pgsql":  &DriverPgsql{},
   297  		"oracle": &DriverOracle{},
   298  		"sqlite": &DriverSqlite{},
   299  	}
   300  
   301  	// lastOperatorRegPattern is the regular expression pattern for a string
   302  	// which has operator at its tail.
   303  	lastOperatorRegPattern = `[<>=]+\s*$`
   304  
   305  	// regularFieldNameRegPattern is the regular expression pattern for a string
   306  	// which is a regular field name of table.
   307  	regularFieldNameRegPattern = `^[\w\.\-]+$`
   308  
   309  	// regularFieldNameWithoutDotRegPattern is similar to regularFieldNameRegPattern but not allows '.'.
   310  	// Note that, although some databases allow char '.' in the field name, but it here does not allow '.'
   311  	// in the field name as it conflicts with "db.table.field" pattern in SOME situations.
   312  	regularFieldNameWithoutDotRegPattern = `^[\w\-]+$`
   313  
   314  	// tableFieldsMap caches the table information retrived from database.
   315  	tableFieldsMap = gmap.New(true)
   316  
   317  	// allDryRun sets dry-run feature for all database connections.
   318  	// It is commonly used for command options for convenience.
   319  	allDryRun = false
   320  )
   321  
   322  func init() {
   323  	// allDryRun is initialized from environment or command options.
   324  	allDryRun = gcmd.GetOptWithEnv(commandEnvKeyForDryRun, false).Bool()
   325  }
   326  
   327  // Register registers custom database driver to gdb.
   328  func Register(name string, driver Driver) error {
   329  	driverMap[name] = driver
   330  	return nil
   331  }
   332  
   333  // New creates and returns an ORM object with global configurations.
   334  // The parameter `name` specifies the configuration group name,
   335  // which is DefaultGroupName in default.
   336  func New(group ...string) (db DB, err error) {
   337  	groupName := configs.group
   338  	if len(group) > 0 && group[0] != "" {
   339  		groupName = group[0]
   340  	}
   341  	configs.RLock()
   342  	defer configs.RUnlock()
   343  
   344  	if len(configs.config) < 1 {
   345  		return nil, gerror.NewCode(
   346  			gcode.CodeInvalidConfiguration,
   347  			"database configuration is empty, please set the database configuration before using",
   348  		)
   349  	}
   350  	if _, ok := configs.config[groupName]; ok {
   351  		if node, err := getConfigNodeByGroup(groupName, true); err == nil {
   352  			c := &Core{
   353  				group:  groupName,
   354  				debug:  gtype.NewBool(),
   355  				cache:  gcache.New(),
   356  				links:  gmap.NewStrAnyMap(true),
   357  				schema: gtype.NewString(),
   358  				logger: glog.New(),
   359  				config: node,
   360  			}
   361  			if v, ok := driverMap[node.Type]; ok {
   362  				c.db, err = v.New(c, node)
   363  				if err != nil {
   364  					return nil, err
   365  				}
   366  				return c.db, nil
   367  			} else {
   368  				return nil, gerror.NewCodef(
   369  					gcode.CodeInvalidConfiguration,
   370  					`cannot find database driver for specified database type "%s", did you misspell type name "%s" or forget importing the database driver?`,
   371  					node.Type, node.Type,
   372  				)
   373  			}
   374  		} else {
   375  			return nil, err
   376  		}
   377  	} else {
   378  		return nil, gerror.NewCodef(
   379  			gcode.CodeInvalidConfiguration,
   380  			`database configuration node "%s" is not found, did you misspell group name "%s" or miss the database configuration?`,
   381  			groupName, groupName,
   382  		)
   383  	}
   384  }
   385  
   386  // Instance returns an instance for DB operations.
   387  // The parameter `name` specifies the configuration group name,
   388  // which is DefaultGroupName in default.
   389  func Instance(name ...string) (db DB, err error) {
   390  	group := configs.group
   391  	if len(name) > 0 && name[0] != "" {
   392  		group = name[0]
   393  	}
   394  	v := instances.GetOrSetFuncLock(group, func() interface{} {
   395  		db, err = New(group)
   396  		return db
   397  	})
   398  	if v != nil {
   399  		return v.(DB), nil
   400  	}
   401  	return
   402  }
   403  
   404  // getConfigNodeByGroup calculates and returns a configuration node of given group. It
   405  // calculates the value internally using weight algorithm for load balance.
   406  //
   407  // The parameter `master` specifies whether retrieving a master node, or else a slave node
   408  // if master-slave configured.
   409  func getConfigNodeByGroup(group string, master bool) (*ConfigNode, error) {
   410  	if list, ok := configs.config[group]; ok {
   411  		// Separates master and slave configuration nodes array.
   412  		masterList := make(ConfigGroup, 0)
   413  		slaveList := make(ConfigGroup, 0)
   414  		for i := 0; i < len(list); i++ {
   415  			if list[i].Role == "slave" {
   416  				slaveList = append(slaveList, list[i])
   417  			} else {
   418  				masterList = append(masterList, list[i])
   419  			}
   420  		}
   421  		if len(masterList) < 1 {
   422  			return nil, gerror.NewCode(gcode.CodeInvalidConfiguration, "at least one master node configuration's need to make sense")
   423  		}
   424  		if len(slaveList) < 1 {
   425  			slaveList = masterList
   426  		}
   427  		if master {
   428  			return getConfigNodeByWeight(masterList), nil
   429  		} else {
   430  			return getConfigNodeByWeight(slaveList), nil
   431  		}
   432  	} else {
   433  		return nil, gerror.NewCodef(gcode.CodeInvalidConfiguration, "empty database configuration for item name '%s'", group)
   434  	}
   435  }
   436  
   437  // getConfigNodeByWeight calculates the configuration weights and randomly returns a node.
   438  //
   439  // Calculation algorithm brief:
   440  // 1. If we have 2 nodes, and their weights are both 1, then the weight range is [0, 199];
   441  // 2. Node1 weight range is [0, 99], and node2 weight range is [100, 199], ratio is 1:1;
   442  // 3. If the random number is 99, it then chooses and returns node1;
   443  func getConfigNodeByWeight(cg ConfigGroup) *ConfigNode {
   444  	if len(cg) < 2 {
   445  		return &cg[0]
   446  	}
   447  	var total int
   448  	for i := 0; i < len(cg); i++ {
   449  		total += cg[i].Weight * 100
   450  	}
   451  	// If total is 0 means all the nodes have no weight attribute configured.
   452  	// It then defaults each node's weight attribute to 1.
   453  	if total == 0 {
   454  		for i := 0; i < len(cg); i++ {
   455  			cg[i].Weight = 1
   456  			total += cg[i].Weight * 100
   457  		}
   458  	}
   459  	// Exclude the right border value.
   460  	r := grand.N(0, total-1)
   461  	min := 0
   462  	max := 0
   463  	for i := 0; i < len(cg); i++ {
   464  		max = min + cg[i].Weight*100
   465  		//fmt.Printf("r: %d, min: %d, max: %d\n", r, min, max)
   466  		if r >= min && r < max {
   467  			return &cg[i]
   468  		} else {
   469  			min = max
   470  		}
   471  	}
   472  	return nil
   473  }
   474  
   475  // getSqlDb retrieves and returns a underlying database connection object.
   476  // The parameter `master` specifies whether retrieves master node connection if
   477  // master-slave nodes are configured.
   478  func (c *Core) getSqlDb(master bool, schema ...string) (sqlDb *sql.DB, err error) {
   479  	// Load balance.
   480  	node, err := getConfigNodeByGroup(c.group, master)
   481  	if err != nil {
   482  		return nil, err
   483  	}
   484  	// Default value checks.
   485  	if node.Charset == "" {
   486  		node.Charset = "utf8"
   487  	}
   488  	// Changes the schema.
   489  	nodeSchema := c.schema.Val()
   490  	if len(schema) > 0 && schema[0] != "" {
   491  		nodeSchema = schema[0]
   492  	}
   493  	if nodeSchema != "" {
   494  		// Value copy.
   495  		n := *node
   496  		n.Name = nodeSchema
   497  		node = &n
   498  	}
   499  	// Cache the underlying connection pool object by node.
   500  	v := c.links.GetOrSetFuncLock(node.String(), func() interface{} {
   501  		intlog.Printf(
   502  			c.db.GetCtx(),
   503  			`open new connection, master:%#v, config:%#v, node:%#v`,
   504  			master, c.config, node,
   505  		)
   506  		defer func() {
   507  			if err != nil {
   508  				intlog.Printf(c.db.GetCtx(), `open new connection failed: %v, %#v`, err, node)
   509  			} else {
   510  				intlog.Printf(
   511  					c.db.GetCtx(),
   512  					`open new connection success, master:%#v, config:%#v, node:%#v`,
   513  					master, c.config, node,
   514  				)
   515  			}
   516  		}()
   517  
   518  		sqlDb, err = c.db.Open(node)
   519  		if err != nil {
   520  			return nil
   521  		}
   522  
   523  		if c.config.MaxIdleConnCount > 0 {
   524  			sqlDb.SetMaxIdleConns(c.config.MaxIdleConnCount)
   525  		} else {
   526  			sqlDb.SetMaxIdleConns(defaultMaxIdleConnCount)
   527  		}
   528  		if c.config.MaxOpenConnCount > 0 {
   529  			sqlDb.SetMaxOpenConns(c.config.MaxOpenConnCount)
   530  		} else {
   531  			sqlDb.SetMaxOpenConns(defaultMaxOpenConnCount)
   532  		}
   533  		if c.config.MaxConnLifeTime > 0 {
   534  			// Automatically checks whether MaxConnLifetime is configured using string like: "30s", "60s", etc.
   535  			// Or else it is configured just using number, which means value in seconds.
   536  			if c.config.MaxConnLifeTime > time.Second {
   537  				sqlDb.SetConnMaxLifetime(c.config.MaxConnLifeTime)
   538  			} else {
   539  				sqlDb.SetConnMaxLifetime(c.config.MaxConnLifeTime * time.Second)
   540  			}
   541  		} else {
   542  			sqlDb.SetConnMaxLifetime(defaultMaxConnLifeTime)
   543  		}
   544  		return sqlDb
   545  	})
   546  	if v != nil && sqlDb == nil {
   547  		sqlDb = v.(*sql.DB)
   548  	}
   549  	if node.Debug {
   550  		c.db.SetDebug(node.Debug)
   551  	}
   552  	if node.DryRun {
   553  		c.db.SetDryRun(node.DryRun)
   554  	}
   555  	return
   556  }