diff --git a/engine.go b/engine.go index 5fccf6c1..9e7053ab 100644 --- a/engine.go +++ b/engine.go @@ -47,6 +47,8 @@ type Engine struct { disableGlobalCache bool tagHandlers map[string]tagHandler + + engineGroup *EngineGroup } // ShowSQL show SQL statement or not on logger if log level is great than INFO diff --git a/engine_group.go b/engine_group.go index 88d0db0f..dd1e6380 100644 --- a/engine_group.go +++ b/engine_group.go @@ -5,122 +5,88 @@ package xorm import ( - "database/sql" - "io" - "reflect" "strings" "time" - "github.com/go-xorm/builder" "github.com/go-xorm/core" ) type EngineGroup struct { - master *Engine - slaves []*Engine - weight []int - count int - s_count int - policy GroupPolicy - p int + *Engine + slaves []*Engine + policy GroupPolicy } func NewGroup(args1 interface{}, args2 interface{}, policies ...GroupPolicy) (*EngineGroup, error) { - var policy GroupPolicy + var eg EngineGroup if len(policies) > 0 { - policy = policies[0] + eg.policy = policies[0] } else { - policy = NewRandomPolicy() + eg.policy = NewRandomPolicy() } driverName, ok1 := args1.(string) dataSourceNames, ok2 := args2.(string) if ok1 && ok2 { - return newGroup1(driverName, dataSourceNames, policy) + conns := strings.Split(dataSourceNames, ";") + engines := make([]*Engine, len(conns)) + for i, conn := range conns { + engine, err := NewEngine(driverName, conn) + if err != nil { + return nil, err + } + engine.engineGroup = &eg + engines[i] = engine + } + + eg.Engine = engines[0] + eg.slaves = engines[1:] + return &eg, nil } - Master, ok3 := args1.(*Engine) - Slaves, ok4 := args2.([]*Engine) + master, ok3 := args1.(*Engine) + slaves, ok4 := args2.([]*Engine) if ok3 && ok4 { - return newGroup2(Master, Slaves, policy) + master.engineGroup = &eg + for i := 0; i < len(slaves); i++ { + slaves[i].engineGroup = &eg + } + return &eg, nil } return nil, ErrParamsType } -func newGroup1(driverName string, dataSourceNames string, policy GroupPolicy) (*EngineGroup, error) { - conns := strings.Split(dataSourceNames, ";") - engines := make([]*Engine, len(conns)) - for i, _ := range conns { - engine, err := NewEngine(driverName, conns[i]) - if err != nil { - return nil, err - } - engines[i] = engine - } - - return &EngineGroup{ - master: engines[0], - slaves: engines[1:], - count: len(engines), - s_count: len(engines[1:]), - policy: policy, - }, nil -} - -func newGroup2(Master *Engine, Slaves []*Engine, policy GroupPolicy) (*EngineGroup, error) { - return &EngineGroup{ - master: Master, - slaves: Slaves, - count: 1 + len(Slaves), - s_count: len(Slaves), - policy: policy, - }, nil -} - func (eg *EngineGroup) SetPolicy(policy GroupPolicy) *EngineGroup { eg.policy = policy return eg } func (eg *EngineGroup) Master() *Engine { - return eg.master + return eg.Engine } // Slave returns one of the physical databases which is a slave func (eg *EngineGroup) Slave() *Engine { - if eg.count == 1 { - return eg.master + switch len(eg.slaves) { + case 0: + return eg.Engine + case 1: + return eg.slaves[0] } return eg.policy.Slave(eg) } func (eg *EngineGroup) Slaves() []*Engine { - if eg.count == 1 { - return []*Engine{eg.master} - } return eg.slaves } func (eg *EngineGroup) GetSlave(i int) *Engine { - if eg.count == 1 || i == 0 { - return eg.master - } - if i > eg.s_count { - return eg.slaves[0] - } return eg.slaves[i] } -func (eg *EngineGroup) GetEngine(i int) *Engine { - if i >= eg.count || i == 0 { - return eg.master - } - return eg.slaves[i-1] -} - // ShowSQL show SQL statement or not on logger if log level is great than INFO func (eg *EngineGroup) ShowSQL(show ...bool) { - eg.master.ShowSQL(show...) + eg.Engine.ShowSQL(show...) for i, _ := range eg.slaves { eg.slaves[i].ShowSQL(show...) } @@ -128,7 +94,7 @@ func (eg *EngineGroup) ShowSQL(show ...bool) { // ShowExecTime show SQL statement and execute time or not on logger if log level is great than INFO func (eg *EngineGroup) ShowExecTime(show ...bool) { - eg.master.ShowExecTime(show...) + eg.Engine.ShowExecTime(show...) for i, _ := range eg.slaves { eg.slaves[i].ShowExecTime(show...) } @@ -136,8 +102,8 @@ func (eg *EngineGroup) ShowExecTime(show ...bool) { // SetMapper set the name mapping rules func (eg *EngineGroup) SetMapper(mapper core.IMapper) { - eg.master.SetTableMapper(mapper) - eg.master.SetColumnMapper(mapper) + eg.Engine.SetTableMapper(mapper) + eg.Engine.SetColumnMapper(mapper) for i, _ := range eg.slaves { eg.slaves[i].SetTableMapper(mapper) eg.slaves[i].SetColumnMapper(mapper) @@ -146,7 +112,7 @@ func (eg *EngineGroup) SetMapper(mapper core.IMapper) { // SetTableMapper set the table name mapping rule func (eg *EngineGroup) SetTableMapper(mapper core.IMapper) { - eg.master.TableMapper = mapper + eg.Engine.TableMapper = mapper for i, _ := range eg.slaves { eg.slaves[i].TableMapper = mapper } @@ -154,7 +120,7 @@ func (eg *EngineGroup) SetTableMapper(mapper core.IMapper) { // SetColumnMapper set the column name mapping rule func (eg *EngineGroup) SetColumnMapper(mapper core.IMapper) { - eg.master.ColumnMapper = mapper + eg.Engine.ColumnMapper = mapper for i, _ := range eg.slaves { eg.slaves[i].ColumnMapper = mapper } @@ -162,7 +128,7 @@ func (eg *EngineGroup) SetColumnMapper(mapper core.IMapper) { // SetMaxOpenConns is only available for go 1.2+ func (eg *EngineGroup) SetMaxOpenConns(conns int) { - eg.master.db.SetMaxOpenConns(conns) + eg.Engine.db.SetMaxOpenConns(conns) for i, _ := range eg.slaves { eg.slaves[i].db.SetMaxOpenConns(conns) } @@ -170,21 +136,15 @@ func (eg *EngineGroup) SetMaxOpenConns(conns int) { // SetMaxIdleConns set the max idle connections on pool, default is 2 func (eg *EngineGroup) SetMaxIdleConns(conns int) { - eg.master.db.SetMaxIdleConns(conns) + eg.Engine.db.SetMaxIdleConns(conns) for i, _ := range eg.slaves { eg.slaves[i].db.SetMaxIdleConns(conns) } } -// NoCascade If you do not want to auto cascade load object -func (eg *EngineGroup) NoCascade() *EGSession { - egs := eg.NewEGSession() - return egs.NoCascade() -} - // Close the engine func (eg *EngineGroup) Close() error { - err := eg.master.db.Close() + err := eg.Engine.db.Close() if err != nil { return err } @@ -200,630 +160,22 @@ func (eg *EngineGroup) Close() error { // Ping tests if database is alive func (eg *EngineGroup) Ping() error { - eg.master.Ping() - return scatter(eg.s_count, func(i int) error { - return eg.slaves[i].Ping() - }) + if err := eg.Engine.Ping(); err != nil { + return err + } + + for _, slave := range eg.slaves { + if err := slave.Ping(); err != nil { + return err + } + } + return nil } // SetConnMaxLifetime sets the maximum amount of time a connection may be reused. func (eg *EngineGroup) SetConnMaxLifetime(d time.Duration) { - eg.master.db.SetConnMaxLifetime(d) + eg.Engine.db.SetConnMaxLifetime(d) for i, _ := range eg.slaves { eg.slaves[i].db.SetConnMaxLifetime(d) } } - -func scatter(n int, fn func(i int) error) error { - errors := make(chan error, n) - - var i int - for i = 0; i < n; i++ { - go func(i int) { errors <- fn(i) }(i) - } - - var err, innerErr error - for i = 0; i < cap(errors); i++ { - if innerErr = <-errors; innerErr != nil { - err = innerErr - } - } - - return err -} - -// SqlType will be deprecated, please use SQLType instead -// -// Deprecated: use SQLType instead -func (eg *EngineGroup) SqlType(c *core.Column) string { - return eg.Master().SQLType(c) -} - -// SQLType A simple wrapper to dialect's core.SqlType method -func (eg *EngineGroup) SQLType(c *core.Column) string { - return eg.Master().dialect.SqlType(c) -} - -// NewSession New a session -func (eg *EngineGroup) NewSession() *Session { - return eg.Master().NewSession() -} - -// NewSession New a session -func (eg *EngineGroup) NewEGSession() *EGSession { - args := make(map[string]interface{}) - egs := &EGSession{eg: eg, operation: []string{}, args: args} - return egs -} - -type SqlArgs struct { - query string - args []interface{} -} - -func (eg *EngineGroup) Sql(query string, args ...interface{}) *EGSession { - egs := eg.NewEGSession() - return egs.Sql(query, args...) -} - -func (eg *EngineGroup) SQL(query interface{}, args ...interface{}) *EGSession { - egs := eg.NewEGSession() - return egs.SQL(query, args...) -} - -// NoAutoTime Default if your struct has "created" or "updated" filed tag, the fields -// will automatically be filled with current time when Insert or Update -// invoked. Call NoAutoTime if you dont' want to fill automatically. -func (eg *EngineGroup) NoAutoTime() *EGSession { - egs := eg.NewEGSession() - return egs.NoAutoTime() -} - -type NoAutoConditionArgs struct { - no []bool -} - -// NoAutoCondition disable auto generate Where condition from bean or not -func (eg *EngineGroup) NoAutoCondition(no ...bool) *EGSession { - egs := eg.NewEGSession() - return egs.NoAutoCondition(no...) -} - -// DBMetas Retrieve all tables, columns, indexes' informations from database. -func (eg *EngineGroup) DBMetas() ([]*core.Table, error) { - return eg.Master().DBMetas() -} - -// DumpAllToFile dump database all table structs and data to a file -func (eg *EngineGroup) DumpAllToFile(fp string, tp ...core.DbType) error { - return eg.Master().DumpAllToFile(fp, tp...) -} - -// DumpAll dump database all table structs and data to w -func (eg *EngineGroup) DumpAll(w io.Writer, tp ...core.DbType) error { - return eg.Master().DumpAll(w, tp...) -} - -// DumpTablesToFile dump specified tables to SQL file. -func (eg *EngineGroup) DumpTablesToFile(tables []*core.Table, fp string, tp ...core.DbType) error { - return eg.Master().DumpTablesToFile(tables, fp, tp...) -} - -// DumpTables dump specify tables to io.Writer -func (eg *EngineGroup) DumpTables(tables []*core.Table, w io.Writer, tp ...core.DbType) error { - return eg.Master().DumpTables(tables, w, tp...) -} - -type CascadeArgs struct { - trueOrFalse []bool -} - -// Cascade use cascade or not -func (eg *EngineGroup) Cascade(trueOrFalse ...bool) *EGSession { - egs := eg.NewEGSession() - return egs.Cascade(trueOrFalse...) -} - -type WhereArgs struct { - query interface{} - args []interface{} -} - -// Where method provide a condition query -func (eg *EngineGroup) Where(query interface{}, args ...interface{}) *EGSession { - egs := eg.NewEGSession() - return egs.Where(query, args...) -} - -type IdArgs struct { - id interface{} -} - -// Id will be deprecated, please use ID instead -func (eg *EngineGroup) Id(id interface{}) *EGSession { - egs := eg.NewEGSession() - return egs.Id(id) -} - -type IDArgs struct { - id interface{} -} - -// ID method provoide a condition as (id) = ? -func (eg *EngineGroup) ID(id interface{}) *EGSession { - egs := eg.NewEGSession() - return egs.ID(id) -} - -type BeforeArgs struct { - closures func(interface{}) -} - -// Before apply before Processor, affected bean is passed to closure arg -func (eg *EngineGroup) Before(closures func(interface{})) *EGSession { - egs := eg.NewEGSession() - return egs.Before(closures) -} - -type AfterArgs struct { - closures func(interface{}) -} - -// After apply after insert Processor, affected bean is passed to closure arg -func (eg *EngineGroup) After(closures func(interface{})) *EGSession { - egs := eg.NewEGSession() - return egs.After(closures) -} - -type CharsetArgs struct { - charset string -} - -// Charset set charset when create table, only support mysql now -func (eg *EngineGroup) Charset(charset string) *EGSession { - egs := eg.NewEGSession() - return egs.Charset(charset) -} - -type StoreEngineArgs struct { - storeEngine string -} - -// StoreEngine set store engine when create table, only support mysql now -func (eg *EngineGroup) StoreEngine(storeEngine string) *EGSession { - egs := eg.NewEGSession() - return egs.StoreEngine(storeEngine) -} - -type DistinctArgs struct { - columns []string -} - -// Distinct use for distinct columns. Caution: when you are using cache, -// distinct will not be cached because cache system need id, -// but distinct will not provide id -func (eg *EngineGroup) Distinct(columns ...string) *EGSession { - egs := eg.NewEGSession() - return egs.Distinct(columns...) -} - -type SelectArgs struct { - str string -} - -// Select customerize your select columns or contents -func (eg *EngineGroup) Select(str string) *EGSession { - egs := eg.NewEGSession() - return egs.Select(str) -} - -type ColsArgs struct { - columns []string -} - -// Cols only use the parameters as select or update columns -func (eg *EngineGroup) Cols(columns ...string) *EGSession { - egs := eg.NewEGSession() - return egs.Cols(columns...) -} - -// AllCols indicates that all columns should be use -func (eg *EngineGroup) AllCols() *EGSession { - egs := eg.NewEGSession() - return egs.AllCols() -} - -type MustColsArgs struct { - columns []string -} - -// MustCols specify some columns must use even if they are empty -func (eg *EngineGroup) MustCols(columns ...string) *EGSession { - egs := eg.NewEGSession() - return egs.MustCols(columns...) -} - -type UseBoolArgs struct { - columns []string -} - -// UseBool xorm automatically retrieve condition according struct, but -// if struct has bool field, it will ignore them. So use UseBool -// to tell system to do not ignore them. -// If no parameters, it will use all the bool field of struct, or -// it will use parameters's columns -func (eg *EngineGroup) UseBool(columns ...string) *EGSession { - egs := eg.NewEGSession() - return egs.UseBool(columns...) -} - -type OmitArgs struct { - columns []string -} - -// Omit only not use the parameters as select or update columns -func (eg *EngineGroup) Omit(columns ...string) *EGSession { - egs := eg.NewEGSession() - return egs.Omit(columns...) -} - -type NullableArgs struct { - columns []string -} - -// Nullable set null when column is zero-value and nullable for update -func (eg *EngineGroup) Nullable(columns ...string) *EGSession { - egs := eg.NewEGSession() - return egs.Nullable(columns...) -} - -type InArgs struct { - column string - args []interface{} -} - -// In will generate "column IN (?, ?)" -func (eg *EngineGroup) In(column string, args ...interface{}) *EGSession { - egs := eg.NewEGSession() - return egs.In(column, args...) -} - -type NotInArgs struct { - column string - args []interface{} -} - -// NotIn will generate "column NOT IN (?, ?)" -func (eg *EngineGroup) NotIn(column string, args ...interface{}) *EGSession { - egs := eg.NewEGSession() - return egs.NotIn(column, args...) -} - -type IncrArgs struct { - column string - args []interface{} -} - -// Incr provides a update string like "column = column + ?" -func (eg *EngineGroup) Incr(column string, args ...interface{}) *EGSession { - egs := eg.NewEGSession() - return egs.Incr(column, args...) -} - -type DecrArgs struct { - column string - args []interface{} -} - -// Decr provides a update string like "column = column - ?" -func (eg *EngineGroup) Decr(column string, args ...interface{}) *EGSession { - egs := eg.NewEGSession() - return egs.Decr(column, args...) -} - -type SetExprArgs struct { - column string - expression string -} - -// SetExpr provides a update string like "column = {expression}" -func (eg *EngineGroup) SetExpr(column string, expression string) *EGSession { - egs := eg.NewEGSession() - return egs.SetExpr(column, expression) -} - -type TableArgs struct { - tableNameOrBean interface{} -} - -// Table temporarily change the Get, Find, Update's table -func (eg *EngineGroup) Table(tableNameOrBean interface{}) *EGSession { - egs := eg.NewEGSession() - return egs.Table(tableNameOrBean) -} - -type AliasArgs struct { - alias string -} - -// Alias set the table alias -func (eg *EngineGroup) Alias(alias string) *EGSession { - egs := eg.NewEGSession() - return egs.Alias(alias) -} - -type LimitArgs struct { - limit int - start []int -} - -// Limit will generate "LIMIT start, limit" -func (eg *EngineGroup) Limit(limit int, start ...int) *EGSession { - egs := eg.NewEGSession() - return egs.Limit(limit, start...) -} - -type DescArgs struct { - colNames []string -} - -// Desc will generate "ORDER BY column1 DESC, column2 DESC" -func (eg *EngineGroup) Desc(colNames ...string) *EGSession { - egs := eg.NewEGSession() - return egs.Desc(colNames...) -} - -type AscArgs struct { - colNames []string -} - -// Asc will generate "ORDER BY column1,column2 Asc" -// This method can chainable use. -// -// engine.Desc("name").Asc("age").Find(&users) -// // SELECT * FROM user ORDER BY name DESC, age ASC -// -func (eg *EngineGroup) Asc(colNames ...string) *EGSession { - egs := eg.NewEGSession() - return egs.Asc(colNames...) -} - -type OrderByArgs struct { - order string -} - -// OrderBy will generate "ORDER BY order" -func (eg *EngineGroup) OrderBy(order string) *EGSession { - egs := eg.NewEGSession() - return egs.OrderBy(order) -} - -type JoinArgs struct { - joinOperator string - tablename interface{} - condition string - args []interface{} -} - -// Join the join_operator should be one of INNER, LEFT OUTER, CROSS etc - this will be prepended to JOIN -func (eg *EngineGroup) Join(joinOperator string, tablename interface{}, condition string, args ...interface{}) *EGSession { - egs := eg.NewEGSession() - return egs.Join(joinOperator, tablename, condition, args...) -} - -type GroupByArgs struct { - keys string -} - -// GroupBy generate group by statement -func (eg *EngineGroup) GroupBy(keys string) *EGSession { - egs := eg.NewEGSession() - return egs.GroupBy(keys) -} - -type HavingArgs struct { - conditions string -} - -// Having generate having statement -func (eg *EngineGroup) Having(conditions string) *EGSession { - egs := eg.NewEGSession() - return egs.Having(conditions) -} - -// IdOf get id from one struct -// -// Deprecated: use IDOf instead. -func (eg *EngineGroup) IdOf(bean interface{}) core.PK { - return eg.Master().IdOf(bean) -} - -// IDOf get id from one struct -func (eg *EngineGroup) IDOf(bean interface{}) core.PK { - return eg.Master().IDOf(bean) -} - -// IdOfV get id from one value of struct -// -// Deprecated: use IDOfV instead. -func (eg *EngineGroup) IdOfV(rv reflect.Value) core.PK { - return eg.Master().IdOfV(rv) -} - -// IDOfV get id from one value of struct -func (eg *EngineGroup) IDOfV(rv reflect.Value) core.PK { - return eg.Master().IDOfV(rv) -} - -// CreateIndexes create indexes -func (eg *EngineGroup) CreateIndexes(bean interface{}) error { - return eg.Master().CreateIndexes(bean) -} - -// CreateUniques create uniques -func (eg *EngineGroup) CreateUniques(bean interface{}) error { - return eg.Master().CreateUniques(bean) -} - -// Sync the new struct changes to database, this method will automatically add -// table, column, index, unique. but will not delete or change anything. -// If you change some field, you should change the database manually. -func (eg *EngineGroup) Sync(beans ...interface{}) error { - return eg.Master().Sync(beans...) -} - -// Sync2 synchronize structs to database tables -func (eg *EngineGroup) Sync2(beans ...interface{}) error { - return eg.Master().Sync2(beans...) -} - -// CreateTables create tabls according bean -func (eg *EngineGroup) CreateTables(beans ...interface{}) error { - return eg.Master().CreateTables(beans...) -} - -// DropTables drop specify tables -func (eg *EngineGroup) DropTables(beans ...interface{}) error { - return eg.Master().DropTables(beans...) -} - -// DropIndexes drop indexes of a table -func (eg *EngineGroup) DropIndexes(bean interface{}) error { - return eg.Master().DropIndexes(bean) -} - -func (eg *EngineGroup) Exec(sql string, args ...interface{}) (sql.Result, error) { - return eg.Master().Exec(sql, args...) -} - -// Query a raw sql and return records as []map[string][]byte -func (eg *EngineGroup) Query(sql string, paramStr ...interface{}) (resultsSlice []map[string][]byte, err error) { - return eg.Slave().Query(sql, paramStr...) -} - -// QueryString runs a raw sql and return records as []map[string]string -func (eg *EngineGroup) QueryString(sqlStr string, args ...interface{}) ([]map[string]string, error) { - return eg.Slave().QueryString(sqlStr, args...) -} - -// QueryInterface runs a raw sql and return records as []map[string]interface{} -func (eg *EngineGroup) QueryInterface(sqlStr string, args ...interface{}) ([]map[string]interface{}, error) { - return eg.Slave().QueryInterface(sqlStr, args...) -} - -// Insert one or more records -func (eg *EngineGroup) Insert(beans ...interface{}) (int64, error) { - return eg.Master().Insert(beans...) -} - -// InsertOne insert only one record -func (eg *EngineGroup) InsertOne(bean interface{}) (int64, error) { - return eg.Master().InsertOne(bean) -} - -// IsTableEmpty if a table has any reocrd -func (eg *EngineGroup) IsTableEmpty(bean interface{}) (bool, error) { - return eg.Master().IsTableEmpty(bean) -} - -// IsTableExist if a table is exist -func (eg *EngineGroup) IsTableExist(beanOrTableName interface{}) (bool, error) { - return eg.Master().IsTableExist(beanOrTableName) -} - -func (eg *EngineGroup) Update(bean interface{}, condiBeans ...interface{}) (int64, error) { - return eg.Master().Update(bean, condiBeans...) -} - -// Delete records, bean's non-empty fields are conditions -func (eg *EngineGroup) Delete(bean interface{}) (int64, error) { - return eg.Master().Delete(bean) -} - -// Get retrieve one record from table, bean's non-empty fields -// are conditions -func (eg *EngineGroup) Get(bean interface{}) (bool, error) { - return eg.Slave().Get(bean) -} - -// Exist returns true if the record exist otherwise return false -func (eg *EngineGroup) Exist(bean ...interface{}) (bool, error) { - return eg.Slave().Exist(bean...) -} - -// Iterate record by record handle records from table, bean's non-empty fields -// are conditions. -func (eg *EngineGroup) Iterate(bean interface{}, fun IterFunc) error { - return eg.Master().Iterate(bean, fun) -} - -func (eg *EngineGroup) Find(beans interface{}, condiBeans ...interface{}) error { - return eg.Slave().Find(beans, condiBeans...) -} - -// Rows return sql.Rows compatible Rows obj, as a forward Iterator object for iterating record by record, bean's non-empty fields -// are conditions. -func (eg *EngineGroup) Rows(bean interface{}) (*Rows, error) { - return eg.Slave().Rows(bean) -} - -// Count counts the records. bean's non-empty fields are conditions. -func (eg *EngineGroup) Count(bean ...interface{}) (int64, error) { - return eg.Slave().Count(bean...) -} - -// Sum sum the records by some column. bean's non-empty fields are conditions. -func (eg *EngineGroup) Sum(bean interface{}, colName string) (float64, error) { - return eg.Slave().Sum(bean, colName) -} - -// SumInt sum the records by some column. bean's non-empty fields are conditions. -func (eg *EngineGroup) SumInt(bean interface{}, colName string) (int64, error) { - return eg.Slave().SumInt(bean, colName) -} - -// Sums sum the records by some columns. bean's non-empty fields are conditions. -func (eg *EngineGroup) Sums(bean interface{}, colNames ...string) ([]float64, error) { - return eg.Slave().Sums(bean, colNames...) -} - -// SumsInt like Sums but return slice of int64 instead of float64. -func (eg *EngineGroup) SumsInt(bean interface{}, colNames ...string) ([]int64, error) { - return eg.Slave().SumsInt(bean, colNames...) -} - -// ImportFile SQL DDL file -func (eg *EngineGroup) ImportFile(ddlPath string) ([]sql.Result, error) { - return eg.Master().ImportFile(ddlPath) -} - -// Import SQL DDL from io.Reader -func (eg *EngineGroup) Import(r io.Reader) ([]sql.Result, error) { - return eg.Master().Import(r) -} - -// NowTime2 return current time -func (eg *EngineGroup) NowTime2(sqlTypeName string) (interface{}, time.Time) { - return eg.Master().NowTime2(sqlTypeName) -} - -// Unscoped always disable struct tag "deleted" -func (eg *EngineGroup) Unscoped() *EGSession { - egs := eg.NewEGSession() - return egs.Unscoped() -} - -// CondDeleted returns the conditions whether a record is soft deleted. -func (eg *EngineGroup) CondDeleted(colName string) builder.Cond { - return eg.Master().CondDeleted(colName) -} - -type BufferSizeArgs struct { - size int -} - -// BufferSize sets buffer size for iterate -func (eg *EngineGroup) BufferSize(size int) *EGSession { - egs := eg.NewEGSession() - return egs.BufferSize(size) -} diff --git a/engine_group_session.go b/engine_group_session.go deleted file mode 100644 index 0f333cb1..00000000 --- a/engine_group_session.go +++ /dev/null @@ -1,764 +0,0 @@ -package xorm - -import ( - "database/sql" - - "github.com/go-xorm/builder" -) - -type EGSession struct { - eg *EngineGroup - operation []string - args map[string]interface{} - err error -} - -func (egs *EGSession) operate(session *Session) *Session { - for _, v := range egs.operation { - switch v { - case "Before": - args := egs.args["Before"].(BeforeArgs) - session = session.Before(args.closures) - case "After": - args := egs.args["After"].(AfterArgs) - session = session.After(args.closures) - case "Table": - args := egs.args["Table"].(TableArgs) - session = session.Table(args.tableNameOrBean) - case "Alias": - args := egs.args["Alias"].(AliasArgs) - session = session.Alias(args.alias) - case "NoCascade": - session = session.NoCascade() - case "ForUpdate": - session = session.ForUpdate() - case "NoAutoCondition": - args := egs.args["NoAutoCondition"].(NoAutoConditionArgs) - session = session.NoAutoCondition(args.no...) - case "Limit": - args := egs.args["Limit"].(LimitArgs) - session = session.Limit(args.limit, args.start...) - case "OrderBy": - args := egs.args["OrderBy"].(OrderByArgs) - session = session.OrderBy(args.order) - case "Desc": - args := egs.args["Desc"].(DescArgs) - session = session.Desc(args.colNames...) - case "Asc": - args := egs.args["Asc"].(AscArgs) - session = session.Asc(args.colNames...) - case "StoreEngine": - args := egs.args["StoreEngine"].(StoreEngineArgs) - session = session.StoreEngine(args.storeEngine) - case "Charset": - args := egs.args["Charset"].(CharsetArgs) - session = session.Charset(args.charset) - case "Cascade": - args := egs.args["Cascade"].(CascadeArgs) - session = session.Cascade(args.trueOrFalse...) - case "NoCache": - session = session.NoCache() - case "Join": - args := egs.args["Join"].(JoinArgs) - session = session.Join(args.joinOperator, args.tablename, args.condition, args.args...) - case "GroupBy": - args := egs.args["GroupBy"].(GroupByArgs) - session = session.GroupBy(args.keys) - case "Having": - args := egs.args["Having"].(HavingArgs) - session = session.Having(args.conditions) - case "Unscoped": - session = session.Unscoped() - case "Incr": - args := egs.args["Incr"].(IncrArgs) - session = session.Incr(args.column, args.args...) - case "Decr": - args := egs.args["Decr"].(DecrArgs) - session = session.Decr(args.column, args.args...) - case "SetExpr": - args := egs.args["SetExpr"].(SetExprArgs) - session = session.SetExpr(args.column, args.expression) - case "Select": - args := egs.args["Select"].(SelectArgs) - session = session.Select(args.str) - case "Cols": - args := egs.args["Cols"].(ColsArgs) - session = session.Cols(args.columns...) - case "AllCols": - session = session.AllCols() - case "MustCols": - args := egs.args["MustCols"].(MustColsArgs) - session = session.MustCols(args.columns...) - case "UseBool": - args := egs.args["UseBool"].(UseBoolArgs) - session = session.UseBool(args.columns...) - case "Distinct": - args := egs.args["Distinct"].(DistinctArgs) - session = session.Distinct(args.columns...) - case "Omit": - args := egs.args["Omit"].(OmitArgs) - session = session.Omit(args.columns...) - case "Nullable": - args := egs.args["Nullable"].(NullableArgs) - session = session.Nullable(args.columns...) - case "NoAutoTime": - session = session.NoAutoTime() - case "Sql": - args := egs.args["Sql"].(SqlArgs) - session = session.Sql(args.query, args.args...) - case "SQL": - args := egs.args["SQL"].(SqlArgs) - session = session.SQL(args.query, args.args...) - case "Where": - args := egs.args["Where"].(WhereArgs) - session = session.Where(args.query, args.args...) - case "And": - args := egs.args["And"].(AndArgs) - session = session.And(args.query, args.args...) - case "Or": - args := egs.args["Or"].(OrArgs) - session = session.Or(args.query, args.args...) - case "Id": - args := egs.args["Id"].(IdArgs) - session = session.Id(args.id) - case "ID": - args := egs.args["ID"].(IDArgs) - session = session.ID(args.id) - case "In": - args := egs.args["In"].(InArgs) - session = session.In(args.column, args.args...) - case "NotIn": - args := egs.args["NotIn"].(NotInArgs) - session = session.NotIn(args.column, args.args...) - case "BufferSize": - args := egs.args["BufferSize"].(BufferSizeArgs) - session = session.BufferSize(args.size) - } - } - return session -} - -// Before Apply before Processor, affected bean is passed to closure arg -func (egs *EGSession) Before(closures func(interface{})) *EGSession { - egs.operation = append(egs.operation, "Before") - args := BeforeArgs{ - closures: closures, - } - egs.args["Before"] = args - return egs -} - -// After Apply after Processor, affected bean is passed to closure arg -func (egs *EGSession) After(closures func(interface{})) *EGSession { - egs.operation = append(egs.operation, "After") - args := AfterArgs{ - closures: closures, - } - egs.args["After"] = args - return egs -} - -// Table can input a string or pointer to struct for special a table to operate. -func (egs *EGSession) Table(tableNameOrBean interface{}) *EGSession { - egs.operation = append(egs.operation, "Table") - args := TableArgs{ - tableNameOrBean: tableNameOrBean, - } - egs.args["Table"] = args - return egs -} - -// Alias set the table alias -func (egs *EGSession) Alias(alias string) *EGSession { - egs.operation = append(egs.operation, "Alias") - args := AliasArgs{ - alias: alias, - } - egs.args["Alias"] = args - return egs -} - -// NoCascade indicate that no cascade load child object -func (egs *EGSession) NoCascade() *EGSession { - egs.operation = append(egs.operation, "NoCascade") - return egs -} - -// ForUpdate Set Read/Write locking for UPDATE -func (egs *EGSession) ForUpdate() *EGSession { - egs.operation = append(egs.operation, "ForUpdate") - return egs -} - -// NoAutoCondition disable generate SQL condition from beans -func (egs *EGSession) NoAutoCondition(no ...bool) *EGSession { - egs.operation = append(egs.operation, "NoAutoCondition") - args := NoAutoConditionArgs{ - no: no, - } - egs.args["NoAutoCondition"] = args - return egs -} - -// Limit provide limit and offset query condition -func (egs *EGSession) Limit(limit int, start ...int) *EGSession { - egs.operation = append(egs.operation, "Limit") - args := LimitArgs{ - limit: limit, - start: start, - } - egs.args["Limit"] = args - return egs -} - -// OrderBy provide order by query condition, the input parameter is the content -// after order by on a sql statement. -func (egs *EGSession) OrderBy(order string) *EGSession { - egs.operation = append(egs.operation, "OrderBy") - args := OrderByArgs{ - order: order, - } - egs.args["OrderBy"] = args - return egs -} - -// Desc provide desc order by query condition, the input parameters are columns. -func (egs *EGSession) Desc(colNames ...string) *EGSession { - egs.operation = append(egs.operation, "Desc") - args := DescArgs{ - colNames: colNames, - } - egs.args["Desc"] = args - return egs -} - -// Asc provide asc order by query condition, the input parameters are columns. -func (egs *EGSession) Asc(colNames ...string) *EGSession { - egs.operation = append(egs.operation, "Asc") - args := AscArgs{ - colNames: colNames, - } - egs.args["Asc"] = args - return egs -} - -// StoreEngine is only avialble mysql dialect currently -func (egs *EGSession) StoreEngine(storeEngine string) *EGSession { - egs.operation = append(egs.operation, "StoreEngine") - args := StoreEngineArgs{ - storeEngine: storeEngine, - } - egs.args["StoreEngine"] = args - return egs -} - -// Charset is only avialble mysql dialect currently -func (egs *EGSession) Charset(charset string) *EGSession { - egs.operation = append(egs.operation, "Charset") - args := CharsetArgs{ - charset: charset, - } - egs.args["Charset"] = args - return egs -} - -// Cascade indicates if loading sub Struct -func (egs *EGSession) Cascade(trueOrFalse ...bool) *EGSession { - egs.operation = append(egs.operation, "Cascade") - args := CascadeArgs{ - trueOrFalse: trueOrFalse, - } - egs.args["Cascade"] = args - return egs -} - -// NoCache ask this session do not retrieve data from cache system and -// get data from database directly. -func (egs *EGSession) NoCache() *EGSession { - egs.operation = append(egs.operation, "NoCache") - return egs -} - -// Join join_operator should be one of INNER, LEFT OUTER, CROSS etc - this will be prepended to JOIN -func (egs *EGSession) Join(joinOperator string, tablename interface{}, condition string, args ...interface{}) *EGSession { - egs.operation = append(egs.operation, "Join") - joinArgs := JoinArgs{ - joinOperator: joinOperator, - tablename: tablename, - condition: condition, - args: args, - } - egs.args["Join"] = joinArgs - return egs -} - -// GroupBy Generate Group By statement -func (egs *EGSession) GroupBy(keys string) *EGSession { - egs.operation = append(egs.operation, "GroupBy") - args := GroupByArgs{ - keys: keys, - } - egs.args["GroupBy"] = args - return egs -} - -// Having Generate Having statement -func (egs *EGSession) Having(conditions string) *EGSession { - egs.operation = append(egs.operation, "Having") - args := HavingArgs{ - conditions: conditions, - } - egs.args["Having"] = args - return egs -} - -// Unscoped always disable struct tag "deleted" -func (egs *EGSession) Unscoped() *EGSession { - egs.operation = append(egs.operation, "Unscoped") - return egs -} - -// Incr provides a query string like "count = count + 1" -func (egs *EGSession) Incr(column string, args ...interface{}) *EGSession { - egs.operation = append(egs.operation, "Incr") - incrArgs := IncrArgs{ - column: column, - args: args, - } - egs.args["Incr"] = incrArgs - return egs -} - -// Decr provides a query string like "count = count - 1" -func (egs *EGSession) Decr(column string, args ...interface{}) *EGSession { - egs.operation = append(egs.operation, "Decr") - decrArgs := DecrArgs{ - column: column, - args: args, - } - egs.args["Decr"] = decrArgs - return egs -} - -// SetExpr provides a query string like "column = {expression}" -func (egs *EGSession) SetExpr(column string, expression string) *EGSession { - egs.operation = append(egs.operation, "SetExpr") - args := SetExprArgs{ - column: column, - expression: expression, - } - egs.args["SetExpr"] = args - return egs -} - -// Select provides some columns to special -func (egs *EGSession) Select(str string) *EGSession { - egs.operation = append(egs.operation, "Select") - args := SelectArgs{ - str: str, - } - egs.args["Select"] = args - return egs -} - -// Cols provides some columns to special -func (egs *EGSession) Cols(columns ...string) *EGSession { - egs.operation = append(egs.operation, "Cols") - args := ColsArgs{ - columns: columns, - } - egs.args["Cols"] = args - return egs -} - -// AllCols ask all columns -func (egs *EGSession) AllCols() *EGSession { - egs.operation = append(egs.operation, "AllCols") - return egs -} - -// MustCols specify some columns must use even if they are empty -func (egs *EGSession) MustCols(columns ...string) *EGSession { - egs.operation = append(egs.operation, "MustCols") - args := MustColsArgs{ - columns: columns, - } - egs.args["MustCols"] = args - return egs -} - -// UseBool automatically retrieve condition according struct, but -// if struct has bool field, it will ignore them. So use UseBool -// to tell system to do not ignore them. -// If no parameters, it will use all the bool field of struct, or -// it will use parameters's columns -func (egs *EGSession) UseBool(columns ...string) *EGSession { - egs.operation = append(egs.operation, "UseBool") - args := UseBoolArgs{ - columns: columns, - } - egs.args["UseBool"] = args - return egs -} - -// Distinct use for distinct columns. Caution: when you are using cache, -// distinct will not be cached because cache system need id, -// but distinct will not provide id -func (egs *EGSession) Distinct(columns ...string) *EGSession { - egs.operation = append(egs.operation, "Distinct") - args := DistinctArgs{ - columns: columns, - } - egs.args["Distinct"] = args - return egs -} - -// Omit Only not use the parameters as select or update columns -func (egs *EGSession) Omit(columns ...string) *EGSession { - egs.operation = append(egs.operation, "Omit") - args := OmitArgs{ - columns: columns, - } - egs.args["Omit"] = args - return egs -} - -// Nullable Set null when column is zero-value and nullable for update -func (egs *EGSession) Nullable(columns ...string) *EGSession { - egs.operation = append(egs.operation, "Nullable") - args := NullableArgs{ - columns: columns, - } - egs.args["Nullable"] = args - return egs -} - -// NoAutoTime means do not automatically give created field and updated field -// the current time on the current session temporarily -func (egs *EGSession) NoAutoTime() *EGSession { - egs.operation = append(egs.operation, "NoAutoTime") - return egs -} - -// Sql provides raw sql input parameter. When you have a complex SQL statement -// and cannot use Where, Id, In and etc. Methods to describe, you can use SQL. -// -// Deprecated: use SQL instead. -func (egs *EGSession) Sql(query string, args ...interface{}) *EGSession { - egs.operation = append(egs.operation, "Sql") - sqlArgs := SqlArgs{ - query: query, - args: args, - } - egs.args["Sql"] = sqlArgs - return egs -} - -type SQLArgs struct { - query interface{} - args []interface{} -} - -// SQL provides raw sql input parameter. When you have a complex SQL statement -// and cannot use Where, Id, In and etc. Methods to describe, you can use SQL. -func (egs *EGSession) SQL(query interface{}, args ...interface{}) *EGSession { - egs.operation = append(egs.operation, "SQL") - sqlArgs := SQLArgs{ - query: query, - args: args, - } - egs.args["SQL"] = sqlArgs - return egs -} - -// Where provides custom query condition. -func (egs *EGSession) Where(query interface{}, args ...interface{}) *EGSession { - egs.operation = append(egs.operation, "Where") - whereArgs := WhereArgs{ - query: query, - args: args, - } - egs.args["Where"] = whereArgs - return egs -} - -type AndArgs struct { - query interface{} - args []interface{} -} - -// And provides custom query condition. -func (egs *EGSession) And(query interface{}, args ...interface{}) *EGSession { - egs.operation = append(egs.operation, "And") - andArgs := AndArgs{ - query: query, - args: args, - } - egs.args["And"] = andArgs - return egs -} - -type OrArgs struct { - query interface{} - args []interface{} -} - -// Or provides custom query condition. -func (egs *EGSession) Or(query interface{}, args ...interface{}) *EGSession { - egs.operation = append(egs.operation, "Or") - orArgs := OrArgs{ - query: query, - args: args, - } - egs.args["Or"] = orArgs - return egs -} - -// Id provides converting id as a query condition -// -// Deprecated: use ID instead -func (egs *EGSession) Id(id interface{}) *EGSession { - egs.operation = append(egs.operation, "Id") - args := IdArgs{ - id: id, - } - egs.args["Id"] = args - return egs -} - -// ID provides converting id as a query condition -func (egs *EGSession) ID(id interface{}) *EGSession { - egs.operation = append(egs.operation, "ID") - args := IDArgs{ - id: id, - } - egs.args["ID"] = args - return egs -} - -// In provides a query string like "id in (1, 2, 3)" -func (egs *EGSession) In(column string, args ...interface{}) *EGSession { - egs.operation = append(egs.operation, "In") - inArgs := InArgs{ - column: column, - args: args, - } - egs.args["In"] = inArgs - return egs -} - -// NotIn provides a query string like "id in (1, 2, 3)" -func (egs *EGSession) NotIn(column string, args ...interface{}) *EGSession { - egs.operation = append(egs.operation, "NotIn") - notInArgs := NotInArgs{ - column: column, - args: args, - } - egs.args["NotIn"] = notInArgs - return egs -} - -// Conds returns session query conditions except auto bean conditions -func (egs *EGSession) Conds() builder.Cond { - return egs.eg.Master().NewSession().Conds() -} - -// Delete records, bean's non-empty fields are conditions -func (egs *EGSession) Delete(bean interface{}) (int64, error) { - session := egs.eg.Master().NewSession() - defer session.Close() - session = egs.operate(session) - return session.Delete(bean) -} - -// Exist returns true if the record exist otherwise return false -func (egs *EGSession) Exist(bean ...interface{}) (bool, error) { - session := egs.eg.Master().NewSession() - defer session.Close() - session = egs.operate(session) - return session.Exist(bean...) -} - -// Find retrieve records from table, condiBeans's non-empty fields -// are conditions. beans could be []Struct, []*Struct, map[int64]Struct -// map[int64]*Struct -func (egs *EGSession) Find(rowsSlicePtr interface{}, condiBean ...interface{}) error { - session := egs.eg.Slave().NewSession() - defer session.Close() - session = egs.operate(session) - return session.Find(rowsSlicePtr, condiBean...) -} - -// Get retrieve one record from database, bean's non-empty fields -// will be as conditions -func (egs *EGSession) Get(bean interface{}) (bool, error) { - session := egs.eg.Slave().NewSession() - defer session.Close() - session = egs.operate(session) - return session.Get(bean) -} - -// Insert insert one or more beans -func (egs *EGSession) Insert(beans ...interface{}) (int64, error) { - session := egs.eg.Master().NewSession() - defer session.Close() - session = egs.operate(session) - return session.Insert(beans...) -} - -// Rows return sql.Rows compatible Rows obj, as a forward Iterator object for iterating record by record, bean's non-empty fields -// are conditions. -func (egs *EGSession) Rows(bean interface{}) (*Rows, error) { - session := egs.eg.Slave().NewSession() - defer session.Close() - session = egs.operate(session) - return session.Rows(bean) -} - -// Iterate record by record handle records from table, condiBeans's non-empty fields -// are conditions. beans could be []Struct, []*Struct, map[int64]Struct -// map[int64]*Struct -func (egs *EGSession) Iterate(bean interface{}, fun IterFunc) error { - return egs.eg.Slave().Iterate(bean, fun) -} - -// BufferSize sets the buffersize for iterate -func (egs *EGSession) BufferSize(size int) *EGSession { - egs.operation = append(egs.operation, "BufferSize") - args := BufferSizeArgs{ - size: size, - } - egs.args["BufferSize"] = args - return egs -} - -// Query runs a raw sql and return records as []map[string][]byte -func (egs *EGSession) Query(sqlStr string, args ...interface{}) ([]map[string][]byte, error) { - session := egs.eg.Slave().NewSession() - defer session.Close() - session = egs.operate(session) - return session.Query(sqlStr, args...) -} - -// QueryString runs a raw sql and return records as []map[string]string -func (egs *EGSession) QueryString(sqlStr string, args ...interface{}) ([]map[string]string, error) { - session := egs.eg.Slave().NewSession() - defer session.Close() - session = egs.operate(session) - return session.QueryString(sqlStr, args...) -} - -// QueryInterface runs a raw sql and return records as []map[string]interface{} -func (egs *EGSession) QueryInterface(sqlStr string, args ...interface{}) ([]map[string]interface{}, error) { - session := egs.eg.Slave().NewSession() - defer session.Close() - session = egs.operate(session) - return session.QueryInterface(sqlStr, args...) -} - -// Exec raw sql -func (egs *EGSession) Exec(sqlStr string, args ...interface{}) (sql.Result, error) { - session := egs.eg.Master().NewSession() - defer session.Close() - session = egs.operate(session) - return session.Exec(sqlStr, args...) -} - -// CreateTable create a table according a bean -func (egs *EGSession) CreateTable(bean interface{}) error { - session := egs.eg.Master().NewSession() - defer session.Close() - return session.CreateTable(bean) -} - -// CreateIndexes create indexes -func (egs *EGSession) CreateIndexes(bean interface{}) error { - return egs.eg.Master().CreateIndexes(bean) -} - -// CreateUniques create uniques -func (egs *EGSession) CreateUniques(bean interface{}) error { - return egs.eg.Master().CreateUniques(bean) -} - -// DropIndexes drop indexes -func (egs *EGSession) DropIndexes(bean interface{}) error { - return egs.eg.Master().DropIndexes(bean) -} - -// DropTable drop table will drop table if exist, if drop failed, it will return error -func (egs *EGSession) DropTable(beanOrTableName interface{}) error { - session := egs.eg.Master().NewSession() - defer session.Close() - return session.DropTable(beanOrTableName) -} - -// IsTableExist if a table is exist -func (egs *EGSession) IsTableExist(beanOrTableName interface{}) (bool, error) { - return egs.eg.Master().IsTableExist(beanOrTableName) -} - -// IsTableEmpty if table have any records -func (egs *EGSession) IsTableEmpty(bean interface{}) (bool, error) { - return egs.eg.Master().IsTableEmpty(bean) -} - -// Sync2 synchronize structs to database tables -func (egs *EGSession) Sync2(beans ...interface{}) error { - return egs.eg.Master().Sync2(beans...) -} - -// Count counts the records. bean's non-empty fields -// are conditions. -func (egs *EGSession) Count(bean ...interface{}) (int64, error) { - session := egs.eg.Slave().NewSession() - defer session.Close() - session = egs.operate(session) - return session.Count(bean...) -} - -// sum call sum some column. bean's non-empty fields are conditions. -func (egs *EGSession) Sum(bean interface{}, columnName string) (res float64, err error) { - session := egs.eg.Slave().NewSession() - defer session.Close() - session = egs.operate(session) - return session.Sum(bean, columnName) -} - -// SumInt call sum some column. bean's non-empty fields are conditions. -func (egs *EGSession) SumInt(bean interface{}, columnName string) (res int64, err error) { - session := egs.eg.Slave().NewSession() - defer session.Close() - session = egs.operate(session) - return session.SumInt(bean, columnName) -} - -// Sums call sum some columns. bean's non-empty fields are conditions. -func (egs *EGSession) Sums(bean interface{}, columnNames ...string) ([]float64, error) { - session := egs.eg.Slave().NewSession() - defer session.Close() - session = egs.operate(session) - return session.Sums(bean, columnNames...) -} - -// SumsInt sum specify columns and return as []int64 instead of []float64 -func (egs *EGSession) SumsInt(bean interface{}, columnNames ...string) ([]int64, error) { - session := egs.eg.Slave().NewSession() - defer session.Close() - session = egs.operate(session) - return session.SumsInt(bean, columnNames...) -} - -// Update records, bean's non-empty fields are updated contents, -// condiBean' non-empty filds are conditions -// CAUTION: -// 1.bool will defaultly be updated content nor conditions -// You should call UseBool if you have bool to use. -// 2.float32 & float64 may be not inexact as conditions -func (egs *EGSession) Update(bean interface{}, condiBean ...interface{}) (int64, error) { - session := egs.eg.Master().NewSession() - defer session.Close() - session = egs.operate(session) - return session.Update(bean, condiBean...) - -} diff --git a/session.go b/session.go index c69ac9e5..fe2b9746 100644 --- a/session.go +++ b/session.go @@ -258,13 +258,13 @@ func (session *Session) canCache() bool { return true } -func (session *Session) doPrepare(sqlStr string) (stmt *core.Stmt, err error) { +func (session *Session) doPrepare(db *core.DB, sqlStr string) (stmt *core.Stmt, err error) { crc := crc32.ChecksumIEEE([]byte(sqlStr)) // TODO try hash(sqlStr+len(sqlStr)) var has bool stmt, has = session.stmtCache[crc] if !has { - stmt, err = session.DB().Prepare(sqlStr) + stmt, err = db.Prepare(sqlStr) if err != nil { return nil, err } diff --git a/session_raw.go b/session_raw.go index c225598e..69bf9b3c 100644 --- a/session_raw.go +++ b/session_raw.go @@ -47,9 +47,16 @@ func (session *Session) queryRows(sqlStr string, args ...interface{}) (*core.Row } if session.isAutoCommit { + var db *core.DB + if session.engine.engineGroup != nil { + db = session.engine.engineGroup.Slave().DB() + } else { + db = session.DB() + } + if session.prepareStmt { // don't clear stmt since session will cache them - stmt, err := session.doPrepare(sqlStr) + stmt, err := session.doPrepare(db, sqlStr) if err != nil { return nil, err } @@ -61,7 +68,7 @@ func (session *Session) queryRows(sqlStr string, args ...interface{}) (*core.Row return rows, nil } - rows, err := session.DB().Query(sqlStr, args...) + rows, err := db.Query(sqlStr, args...) if err != nil { return nil, err } @@ -171,7 +178,7 @@ func (session *Session) exec(sqlStr string, args ...interface{}) (sql.Result, er } if session.prepareStmt { - stmt, err := session.doPrepare(sqlStr) + stmt, err := session.doPrepare(session.DB(), sqlStr) if err != nil { return nil, err }