add Sync() method for sync column, index to table

This commit is contained in:
Lunny Xiao 2013-09-28 23:14:42 +08:00
parent 4cdec08cc9
commit 7ebd533407
17 changed files with 810 additions and 66 deletions

View File

@ -42,7 +42,7 @@ type Userdetail struct {
}
func directCreateTable(engine *Engine, t *testing.T) {
err := engine.CreateTables(&Userinfo{})
err := engine.Sync(&Userinfo{})
if err != nil {
t.Error(err)
panic(err)

50
benchmark_base_test.go Normal file
View File

@ -0,0 +1,50 @@
package xorm
import (
"testing"
)
type BigStruct struct {
Id int64
Name string
Title string
Age string
Alias string
NickName string
}
func doBenchCacheFind(engine *Engine, b *testing.B) {
b.StopTimer()
bs := &BigStruct{0, "fafdasf", "fadfa", "afadfsaf", "fadfafdsafd", "fadfafdsaf"}
err := engine.CreateTables(bs)
if err != nil {
b.Error(err)
return
}
for i := 0; i < 100; i++ {
bs.Id = 0
_, err = engine.Insert(bs)
if err != nil {
b.Error(err)
return
}
}
b.StartTimer()
for i := 0; i < b.N; i++ {
bss := new([]BigStruct)
err = engine.Limit(50).Find(bss)
if err != nil {
b.Error(err)
return
}
}
b.StopTimer()
err = engine.DropTables(bs)
if err != nil {
b.Error(err)
return
}
}

132
engine.go
View File

@ -2,6 +2,7 @@ package xorm
import (
"database/sql"
"errors"
"fmt"
"io"
"reflect"
@ -18,6 +19,7 @@ const (
)
type dialect interface {
Init(uri string) error
SqlType(t *Column) string
SupportInsertMany() bool
QuoteStr() string
@ -25,6 +27,9 @@ type dialect interface {
SupportEngine() bool
SupportCharset() bool
IndexOnTable() bool
IndexCheckSql(tableName, idxName string) (string, []interface{})
TableCheckSql(tableName string) (string, []interface{})
ColumnCheckSql(tableName, colName string) (string, []interface{})
}
type Engine struct {
@ -70,6 +75,7 @@ func (engine *Engine) SetPool(pool IConnectPool) error {
return engine.Pool.Init(engine)
}
// only for go 1.2+
func (engine *Engine) SetMaxConns(conns int) {
engine.Pool.SetMaxConns(conns)
}
@ -465,6 +471,132 @@ func (engine *Engine) Map(beans ...interface{}) (e error) {
return
}
// is a table has
func (engine *Engine) IsEmptyTable(bean interface{}) (bool, error) {
t := Type(bean)
if t.Kind() != reflect.Struct {
return false, errors.New("bean should be a struct or struct's point")
}
engine.AutoMapType(t)
session := engine.NewSession()
defer session.Close()
has, err := session.Get(bean)
return !has, err
}
func (engine *Engine) isTableExist(bean interface{}) (bool, error) {
t := Type(bean)
if t.Kind() != reflect.Struct {
return false, errors.New("bean should be a struct or struct's point")
}
table := engine.AutoMapType(t)
session := engine.NewSession()
defer session.Close()
has, err := session.isTableExist(table.Name)
return has, err
}
func (engine *Engine) ClearCache(beans ...interface{}) {
for _, bean := range beans {
table := engine.AutoMap(bean)
table.Cacher.ClearIds(table.Name)
}
}
// sync the new struct to database, this method will auto add column, index, unique
// but will not delete or change anything.
func (engine *Engine) Sync(beans ...interface{}) error {
for _, bean := range beans {
table := engine.AutoMap(bean)
s := engine.NewSession()
defer s.Close()
isExist, err := s.Table(bean).isTableExist(table.Name)
if err != nil {
return err
}
if !isExist {
err = engine.CreateTables(bean)
if err != nil {
return err
}
} else {
isEmpty, err := engine.IsEmptyTable(bean)
if err != nil {
return err
}
if isEmpty {
err = engine.DropTables(bean)
if err != nil {
return err
}
err = engine.CreateTables(bean)
if err != nil {
return err
}
} else {
for _, col := range table.Columns {
session := engine.NewSession()
session.Statement.RefTable = table
defer session.Close()
isExist, err := session.isColumnExist(table.Name, col.Name)
if err != nil {
return err
}
if !isExist {
session := engine.NewSession()
session.Statement.RefTable = table
defer session.Close()
err = session.addColumn(col.Name)
if err != nil {
return err
}
}
}
for idx, _ := range table.Indexes {
session := engine.NewSession()
session.Statement.RefTable = table
defer session.Close()
isExist, err := session.isIndexExist(table.Name, idx, false)
if err != nil {
return err
}
if !isExist {
session := engine.NewSession()
session.Statement.RefTable = table
defer session.Close()
err = session.addIndex(table.Name, idx)
if err != nil {
return err
}
}
}
for uqe, _ := range table.Uniques {
session := engine.NewSession()
session.Statement.RefTable = table
defer session.Close()
isExist, err := session.isIndexExist(table.Name, uqe, true)
if err != nil {
return err
}
if !isExist {
session := engine.NewSession()
session.Statement.RefTable = table
defer session.Close()
err = session.addUnique(table.Name, uqe)
if err != nil {
return err
}
}
}
}
}
}
return nil
}
func (engine *Engine) UnMap(beans ...interface{}) (e error) {
engine.mutex.Lock()
defer engine.mutex.Unlock()

64
examples/sync.go Normal file
View File

@ -0,0 +1,64 @@
package main
import (
"fmt"
_ "github.com/bylevel/pq"
_ "github.com/go-sql-driver/mysql"
_ "github.com/mattn/go-sqlite3"
"xorm"
)
type SyncUser struct {
Id int64
Name string `xorm:"unique"`
Age int `xorm:"index"`
}
type SyncLoginInfo struct {
Id int64
IP string `xorm:"index"`
UserId int64
AddedCol int
// timestamp should be updated by database, so only allow get from db
TimeStamp string
// assume
Nonuse int
}
func sync(engine *xorm.Engine) error {
return engine.Sync(&SyncLoginInfo{}, &SyncUser{})
}
func sqliteEngine() (*xorm.Engine, error) {
f := "sync.db"
//os.Remove(f)
return xorm.NewEngine("sqlite3", f)
}
func mysqlEngine() (*xorm.Engine, error) {
return xorm.NewEngine("mysql", "root:@/test?charset=utf8")
}
func postgresEngine() (*xorm.Engine, error) {
return xorm.NewEngine("postgres", "dbname=xorm_test sslmode=disable")
}
type engineFunc func() (*xorm.Engine, error)
func main() {
engines := []engineFunc{sqliteEngine, mysqlEngine, postgresEngine}
for _, enginefunc := range engines {
Orm, err := enginefunc()
fmt.Println("--------", Orm.DriverName, "----------")
if err != nil {
fmt.Println(err)
return
}
Orm.ShowSQL = true
err = sync(Orm)
if err != nil {
fmt.Println(err)
}
}
}

View File

@ -25,10 +25,10 @@ func (s *PgSeqFilter) Do(sql string, session *Session) string {
return res
}
type PgQuoteFilter struct {
type QuoteFilter struct {
}
func (s *PgQuoteFilter) Do(sql string, session *Session) string {
func (s *QuoteFilter) Do(sql string, session *Session) string {
return strings.Replace(sql, "`", session.Engine.QuoteStr(), -1)
}

65
mymysql.go Normal file
View File

@ -0,0 +1,65 @@
package xorm
import (
"errors"
"strings"
"time"
)
type mymysql struct {
mysql
proto string
raddr string
laddr string
timeout time.Duration
db string
user string
passwd string
}
func (db *mymysql) Init(uri string) error {
pd := strings.SplitN(uri, "*", 2)
if len(pd) == 2 {
// Parse protocol part of URI
p := strings.SplitN(pd[0], ":", 2)
if len(p) != 2 {
return errors.New("Wrong protocol part of URI")
}
db.proto = p[0]
options := strings.Split(p[1], ",")
db.raddr = options[0]
for _, o := range options[1:] {
kv := strings.SplitN(o, "=", 2)
var k, v string
if len(kv) == 2 {
k, v = kv[0], kv[1]
} else {
k, v = o, "true"
}
switch k {
case "laddr":
db.laddr = v
case "timeout":
to, err := time.ParseDuration(v)
if err != nil {
return err
}
db.timeout = to
default:
return errors.New("Unknown option: " + k)
}
}
// Remove protocol part
pd = pd[1:]
}
// Parse database part of URI
dup := strings.SplitN(pd[0], "/", 3)
if len(dup) != 3 {
return errors.New("Wrong database part of URI")
}
db.dbname = dup[0]
db.user = dup[1]
db.passwd = dup[2]
return nil
}

View File

@ -10,6 +10,8 @@ CREATE DATABASE IF NOT EXISTS xorm_test CHARACTER SET
utf8 COLLATE utf8_general_ci;
*/
var showTestSql bool = false
func TestMyMysql(t *testing.T) {
engine, err := NewEngine("mymysql", "xorm_test2/root/")
defer engine.Close()
@ -17,8 +19,30 @@ func TestMyMysql(t *testing.T) {
t.Error(err)
return
}
engine.ShowSQL = true
engine.ShowSQL = showTestSql
testAll(engine, t)
testAll2(engine, t)
}
func BenchmarkMyMysqlNoCache(t *testing.B) {
engine, err := NewEngine("mymysql", "xorm_test2/root/")
defer engine.Close()
if err != nil {
t.Error(err)
return
}
//engine.ShowSQL = true
doBenchCacheFind(engine, t)
}
func BenchmarkMyMysqlCache(t *testing.B) {
engine, err := NewEngine("mymysql", "xorm_test2/root/")
defer engine.Close()
if err != nil {
t.Error(err)
return
}
engine.SetDefaultCacher(NewLRUCacher(NewMemoryStore(), 1000))
doBenchCacheFind(engine, t)
}

View File

@ -1,10 +1,63 @@
package xorm
import (
"crypto/tls"
//"fmt"
"regexp"
"strconv"
//"strings"
"time"
)
type mysql struct {
user string
passwd string
net string
addr string
dbname string
params map[string]string
loc *time.Location
timeout time.Duration
tls *tls.Config
allowAllFiles bool
allowOldPasswords bool
clientFoundRows bool
}
/*func readBool(input string) (value bool, valid bool) {
switch input {
case "1", "true", "TRUE", "True":
return true, true
case "0", "false", "FALSE", "False":
return false, true
}
// Not a valid bool value
return
}*/
func (cfg *mysql) parseDSN(dsn string) (err error) {
//cfg.params = make(map[string]string)
dsnPattern := regexp.MustCompile(
`^(?:(?P<user>.*?)(?::(?P<passwd>.*))?@)?` + // [user[:password]@]
`(?:(?P<net>[^\(]*)(?:\((?P<addr>[^\)]*)\))?)?` + // [net[(addr)]]
`\/(?P<dbname>.*?)` + // /dbname
`(?:\?(?P<params>[^\?]*))?$`) // [?param1=value1&paramN=valueN]
matches := dsnPattern.FindStringSubmatch(dsn)
//tlsConfigRegister := make(map[string]*tls.Config)
names := dsnPattern.SubexpNames()
for i, match := range matches {
switch names[i] {
case "dbname":
cfg.dbname = match
}
}
return
}
func (db *mysql) Init(uri string) error {
return db.parseDSN(uri)
}
func (db *mysql) SqlType(c *Column) string {
@ -46,14 +99,14 @@ func (db *mysql) QuoteStr() string {
return "`"
}
func (db *mysql) AutoIncrStr() string {
return "AUTO_INCREMENT"
}
func (db *mysql) SupportEngine() bool {
return true
}
func (db *mysql) AutoIncrStr() string {
return "AUTO_INCREMENT"
}
func (db *mysql) SupportCharset() bool {
return true
}
@ -61,3 +114,22 @@ func (db *mysql) SupportCharset() bool {
func (db *mysql) IndexOnTable() bool {
return true
}
func (db *mysql) IndexCheckSql(tableName, idxName string) (string, []interface{}) {
args := []interface{}{db.dbname, tableName, idxName}
sql := "SELECT `INDEX_NAME` FROM `INFORMATION_SCHEMA`.`STATISTICS`"
sql += " WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ? AND `INDEX_NAME`=?"
return sql, args
}
func (db *mysql) ColumnCheckSql(tableName, colName string) (string, []interface{}) {
args := []interface{}{db.dbname, tableName, colName}
sql := "SELECT `COLUMN_NAME` FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ? AND `COLUMN_NAME` = ?"
return sql, args
}
func (db *mysql) TableCheckSql(tableName string) (string, []interface{}) {
args := []interface{}{db.dbname, tableName}
sql := "SELECT `TABLE_NAME` from `INFORMATION_SCHEMA`.`TABLES` WHERE `TABLE_SCHEMA`=? and `TABLE_NAME`=?"
return sql, args
}

View File

@ -17,8 +17,30 @@ func TestMysql(t *testing.T) {
t.Error(err)
return
}
engine.ShowSQL = true
engine.ShowSQL = showTestSql
testAll(engine, t)
testAll2(engine, t)
}
func BenchmarkMysqlNoCache(t *testing.B) {
engine, err := NewEngine("mysql", "root:@/xorm_test?charset=utf8")
defer engine.Close()
if err != nil {
t.Error(err)
return
}
//engine.ShowSQL = true
doBenchCacheFind(engine, t)
}
func BenchmarkMysqlCache(t *testing.B) {
engine, err := NewEngine("mysql", "root:@/xorm_test?charset=utf8")
defer engine.Close()
if err != nil {
t.Error(err)
return
}
engine.SetDefaultCacher(NewLRUCacher(NewMemoryStore(), 1000))
doBenchCacheFind(engine, t)
}

View File

@ -1,8 +1,58 @@
package xorm
import "strconv"
import (
"errors"
"fmt"
"strconv"
"strings"
)
type postgres struct {
dbname string
}
type Values map[string]string
func (vs Values) Set(k, v string) {
vs[k] = v
}
func (vs Values) Get(k string) (v string) {
return vs[k]
}
type Error error
func errorf(s string, args ...interface{}) {
panic(Error(fmt.Errorf("pq: %s", fmt.Sprintf(s, args...))))
}
func parseOpts(name string, o Values) {
if len(name) == 0 {
return
}
name = strings.TrimSpace(name)
ps := strings.Split(name, " ")
for _, p := range ps {
kv := strings.Split(p, "=")
if len(kv) < 2 {
errorf("invalid option: %q", p)
}
o.Set(kv[0], kv[1])
}
}
func (db *postgres) Init(uri string) error {
o := make(Values)
parseOpts(uri, o)
db.dbname = o.Get("dbname")
if db.dbname == "" {
return errors.New("dbname is empty")
}
return nil
}
func (db *postgres) SqlType(c *Column) string {
@ -68,3 +118,20 @@ func (db *postgres) SupportCharset() bool {
func (db *postgres) IndexOnTable() bool {
return false
}
func (db *postgres) IndexCheckSql(tableName, idxName string) (string, []interface{}) {
args := []interface{}{tableName, idxName}
return `SELECT indexname FROM pg_indexes ` +
`WHERE tablename = ? AND indexname = ?`, args
}
func (db *postgres) TableCheckSql(tableName string) (string, []interface{}) {
args := []interface{}{tableName}
return `SELECT tablename FROM pg_tables WHERE tablename = ?`, args
}
func (db *postgres) ColumnCheckSql(tableName, colName string) (string, []interface{}) {
args := []interface{}{tableName, colName}
return "SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = ?" +
" AND column_name = ?", args
}

View File

@ -13,7 +13,7 @@ func TestPostgres(t *testing.T) {
return
}
defer engine.Close()
engine.ShowSQL = true
engine.ShowSQL = showTestSql
testAll(engine, t)
testAll2(engine, t)
@ -26,7 +26,7 @@ func TestPostgres2(t *testing.T) {
return
}
defer engine.Close()
engine.ShowSQL = true
engine.ShowSQL = showTestSql
engine.Mapper = SameMapper{}
fmt.Println("-------------- directCreateTable --------------")
@ -98,3 +98,27 @@ func TestPostgres2(t *testing.T) {
fmt.Println("-------------- testIndexAndUnique --------------")
testIndexAndUnique(engine, t)
}
func BenchmarkPostgresNoCache(t *testing.B) {
engine, err := NewEngine("postgres", "dbname=xorm_test sslmode=disable")
defer engine.Close()
if err != nil {
t.Error(err)
return
}
//engine.ShowSQL = true
doBenchCacheFind(engine, t)
}
func BenchmarkPostgresCache(t *testing.B) {
engine, err := NewEngine("postgres", "dbname=xorm_test sslmode=disable")
defer engine.Close()
if err != nil {
t.Error(err)
return
}
engine.SetDefaultCacher(NewLRUCacher(NewMemoryStore(), 1000))
doBenchCacheFind(engine, t)
}

View File

@ -293,10 +293,18 @@ func (session *Session) CreateTable(bean interface{}) error {
return session.createOneTable()
}
func (session *Session) createOneTable() error {
sql := session.Statement.genCreateSQL()
_, err := session.exec(sql)
if err == nil {
func (session *Session) CreateIndexes(bean interface{}) error {
session.Statement.RefTable = session.Engine.AutoMap(bean)
err := session.newDb()
if err != nil {
return err
}
defer session.Statement.Init()
if session.IsAutoClose {
defer session.Close()
}
sqls := session.Statement.genIndexSQL()
for _, sql := range sqls {
_, err = session.exec(sql)
@ -304,8 +312,21 @@ func (session *Session) createOneTable() error {
return err
}
}
return nil
}
func (session *Session) CreateUniques(bean interface{}) error {
session.Statement.RefTable = session.Engine.AutoMap(bean)
err := session.newDb()
if err != nil {
return err
}
if err == nil {
defer session.Statement.Init()
if session.IsAutoClose {
defer session.Close()
}
sqls := session.Statement.genUniqueSQL()
for _, sql := range sqls {
_, err = session.exec(sql)
@ -313,7 +334,12 @@ func (session *Session) createOneTable() error {
return err
}
}
}
return nil
}
func (session *Session) createOneTable() error {
sql := session.Statement.genCreateSQL()
_, err := session.exec(sql)
return err
}
@ -337,6 +363,26 @@ func (session *Session) CreateAll() error {
return nil
}
func (session *Session) DropIndexes(bean interface{}) error {
err := session.newDb()
if err != nil {
return err
}
defer session.Statement.Init()
if session.IsAutoClose {
defer session.Close()
}
sqls := session.Statement.genDelIndexSQL()
for _, sql := range sqls {
_, err = session.exec(sql)
if err != nil {
return err
}
}
return nil
}
// DropTable drop a table and all indexes of the table
func (session *Session) DropTable(bean interface{}) error {
err := session.newDb()
@ -355,14 +401,6 @@ func (session *Session) DropTable(bean interface{}) error {
session.Statement.AltTableName = bean.(string)
} else if t.Kind() == reflect.Struct {
session.Statement.RefTable = session.Engine.AutoMap(bean)
sqls := session.Statement.genDelIndexSQL()
for _, sql := range sqls {
_, err = session.exec(sql)
if err != nil {
return err
}
}
} else {
return errors.New("Unsupported type")
}
@ -727,6 +765,7 @@ func (session *Session) Find(rowsSlicePtr interface{}, condiBean ...interface{})
return nil
}
// test if database is ok
func (session *Session) Ping() error {
err := session.newDb()
if err != nil {
@ -740,6 +779,102 @@ func (session *Session) Ping() error {
return session.Db.Ping()
}
func (session *Session) isColumnExist(tableName, colName string) (bool, error) {
err := session.newDb()
if err != nil {
return false, err
}
defer session.Statement.Init()
if session.IsAutoClose {
defer session.Close()
}
sql, args := session.Engine.Dialect.ColumnCheckSql(tableName, colName)
results, err := session.query(sql, args...)
return len(results) > 0, err
}
func (session *Session) isTableExist(tableName string) (bool, error) {
err := session.newDb()
if err != nil {
return false, err
}
defer session.Statement.Init()
if session.IsAutoClose {
defer session.Close()
}
sql, args := session.Engine.Dialect.TableCheckSql(tableName)
results, err := session.query(sql, args...)
return len(results) > 0, err
}
func (session *Session) isIndexExist(tableName, idxName string, unique bool) (bool, error) {
err := session.newDb()
if err != nil {
return false, err
}
defer session.Statement.Init()
if session.IsAutoClose {
defer session.Close()
}
var idx string
if unique {
idx = uniqueName(tableName, idxName)
} else {
idx = indexName(tableName, idxName)
}
sql, args := session.Engine.Dialect.IndexCheckSql(tableName, idx)
results, err := session.query(sql, args...)
return len(results) > 0, err
}
func (session *Session) addColumn(colName string) error {
err := session.newDb()
if err != nil {
return err
}
defer session.Statement.Init()
if session.IsAutoClose {
defer session.Close()
}
//fmt.Println(session.Statement.RefTable)
col := session.Statement.RefTable.Columns[colName]
sql, args := session.Statement.genAddColumnStr(col)
_, err = session.exec(sql, args...)
return err
}
func (session *Session) addIndex(tableName, idxName string) error {
err := session.newDb()
if err != nil {
return err
}
defer session.Statement.Init()
if session.IsAutoClose {
defer session.Close()
}
//fmt.Println(idxName)
cols := session.Statement.RefTable.Indexes[idxName]
sql, args := session.Statement.genAddIndexStr(indexName(tableName, idxName), cols)
_, err = session.exec(sql, args...)
return err
}
func (session *Session) addUnique(tableName, uqeName string) error {
err := session.newDb()
if err != nil {
return err
}
defer session.Statement.Init()
if session.IsAutoClose {
defer session.Close()
}
//fmt.Println(uqeName, session.Statement.RefTable.Uniques)
cols := session.Statement.RefTable.Uniques[uqeName]
sql, args := session.Statement.genAddUniqueStr(uniqueName(tableName, uqeName), cols)
_, err = session.exec(sql, args...)
return err
}
func (session *Session) DropAll() error {
err := session.newDb()
if err != nil {

View File

@ -3,6 +3,10 @@ package xorm
type sqlite3 struct {
}
func (db *sqlite3) Init(uri string) error {
return nil
}
func (db *sqlite3) SqlType(c *Column) string {
switch t := c.SQLType.Name; t {
case Date, DateTime, TimeStamp, Time:
@ -50,3 +54,18 @@ func (db *sqlite3) SupportCharset() bool {
func (db *sqlite3) IndexOnTable() bool {
return false
}
func (db *sqlite3) IndexCheckSql(tableName, idxName string) (string, []interface{}) {
args := []interface{}{idxName}
return "SELECT name FROM sqlite_master WHERE type='index' and name = ?", args
}
func (db *sqlite3) TableCheckSql(tableName string) (string, []interface{}) {
args := []interface{}{tableName}
return "SELECT name FROM sqlite_master WHERE type='table' and name = ?", args
}
func (db *sqlite3) ColumnCheckSql(tableName, colName string) (string, []interface{}) {
args := []interface{}{tableName}
return "SELECT name FROM sqlite_master WHERE type='table' and name = ? and sql like '%`" + colName + "`%'", args
}

View File

@ -14,8 +14,32 @@ func TestSqlite3(t *testing.T) {
t.Error(err)
return
}
engine.ShowSQL = true
engine.ShowSQL = showTestSql
testAll(engine, t)
testAll2(engine, t)
}
func BenchmarkSqlite3NoCache(t *testing.B) {
os.Remove("./test.db")
engine, err := NewEngine("sqlite3", "./test.db")
defer engine.Close()
if err != nil {
t.Error(err)
return
}
//engine.ShowSQL = true
doBenchCacheFind(engine, t)
}
func BenchmarkSqlite3Cache(t *testing.B) {
os.Remove("./test.db")
engine, err := NewEngine("sqlite3", "./test.db")
defer engine.Close()
if err != nil {
t.Error(err)
return
}
engine.SetDefaultCacher(NewLRUCacher(NewMemoryStore(), 1000))
doBenchCacheFind(engine, t)
}

View File

@ -279,47 +279,57 @@ func (statement *Statement) genCreateSQL() string {
return sql
}
func (statement *Statement) genIndexSQL() []string {
func indexName(tableName, idxName string) string {
return fmt.Sprintf("IDX_%v_%v", tableName, idxName)
}
func (s *Statement) genIndexSQL() []string {
var sqls []string = make([]string, 0)
for indexName, cols := range statement.RefTable.Indexes {
sql := fmt.Sprintf("CREATE INDEX IDX_%v_%v ON %v (%v);", statement.TableName(), indexName,
statement.Engine.Quote(statement.TableName()), statement.Engine.Quote(strings.Join(cols, statement.Engine.Quote(","))))
tbName := s.TableName()
quote := s.Engine.Quote
for idxName, cols := range s.RefTable.Indexes {
sql := fmt.Sprintf("CREATE INDEX %v ON %v (%v);", quote(indexName(tbName, idxName)),
quote(tbName), quote(strings.Join(cols, quote(","))))
sqls = append(sqls, sql)
}
return sqls
}
func uniqueName(tableName, uqeName string) string {
return fmt.Sprintf("UQE_%v_%v", tableName, uqeName)
}
func (statement *Statement) genUniqueSQL() []string {
var sqls []string = make([]string, 0)
for indexName, cols := range statement.RefTable.Uniques {
sql := fmt.Sprintf("CREATE UNIQUE INDEX `UQE_%v_%v` ON %v (%v);", statement.TableName(), indexName,
sql := fmt.Sprintf("CREATE UNIQUE INDEX `%v` ON %v (%v);", uniqueName(statement.TableName(), indexName),
statement.Engine.Quote(statement.TableName()), statement.Engine.Quote(strings.Join(cols, statement.Engine.Quote(","))))
sqls = append(sqls, sql)
}
return sqls
}
func (statement *Statement) genDelIndexSQL() []string {
func (s *Statement) genDelIndexSQL() []string {
var sqls []string = make([]string, 0)
for indexName, _ := range statement.RefTable.Uniques {
sql := fmt.Sprintf("DROP INDEX `UQE_%v_%v`", statement.TableName(), indexName)
if statement.Engine.Dialect.IndexOnTable() {
sql += fmt.Sprintf(" ON %v", statement.Engine.Quote(statement.TableName()))
for indexName, _ := range s.RefTable.Uniques {
sql := fmt.Sprintf("DROP INDEX %v", s.Engine.Quote(uniqueName(s.TableName(), indexName)))
if s.Engine.Dialect.IndexOnTable() {
sql += fmt.Sprintf(" ON %v", s.Engine.Quote(s.TableName()))
}
sqls = append(sqls, sql)
}
for indexName, _ := range statement.RefTable.Indexes {
sql := fmt.Sprintf("DROP INDEX IDX_%v_%v", statement.TableName(), indexName)
if statement.Engine.Dialect.IndexOnTable() {
sql += fmt.Sprintf(" ON %v", statement.Engine.Quote(statement.TableName()))
for indexName, _ := range s.RefTable.Indexes {
sql := fmt.Sprintf("DROP INDEX %v", s.Engine.Quote(uniqueName(s.TableName(), indexName)))
if s.Engine.Dialect.IndexOnTable() {
sql += fmt.Sprintf(" ON %v", s.Engine.Quote(s.TableName()))
}
sqls = append(sqls, sql)
}
return sqls
}
func (statement *Statement) genDropSQL() string {
sql := "DROP TABLE IF EXISTS " + statement.Engine.Quote(statement.TableName()) + ";"
func (s *Statement) genDropSQL() string {
sql := "DROP TABLE IF EXISTS " + s.Engine.Quote(s.TableName()) + ";"
return sql
}
@ -339,6 +349,27 @@ func (statement Statement) genGetSql(bean interface{}) (string, []interface{}) {
return statement.genSelectSql(columnStr), append(statement.Params, statement.BeanArgs...)
}
func (s *Statement) genAddColumnStr(col *Column) (string, []interface{}) {
quote := s.Engine.Quote
sql := fmt.Sprintf("ALTER TABLE %v ADD COLUMN %v;", quote(s.TableName()),
col.String(s.Engine))
return sql, []interface{}{}
}
func (s *Statement) genAddIndexStr(idxName string, cols []string) (string, []interface{}) {
quote := s.Engine.Quote
colstr := quote(strings.Join(cols, quote(", ")))
sql := fmt.Sprintf("CREATE INDEX %v ON %v (%v);", quote(idxName), quote(s.TableName()), colstr)
return sql, []interface{}{}
}
func (s *Statement) genAddUniqueStr(uqeName string, cols []string) (string, []interface{}) {
quote := s.Engine.Quote
colstr := quote(strings.Join(cols, quote(", ")))
sql := fmt.Sprintf("CREATE UNIQUE INDEX %v ON %v (%v);", quote(uqeName), quote(s.TableName()), colstr)
return sql, []interface{}{}
}
func (statement Statement) genCountSql(bean interface{}) (string, []interface{}) {
table := statement.Engine.AutoMap(bean)
statement.RefTable = table

View File

@ -161,6 +161,16 @@ const (
UNIONUNIQUE
)
type Index struct {
Name string
IsUnique bool
Cols []*Column
}
func NewIndex(name string, isUnique bool) *Index {
return &Index{name, isUnique, make([]*Column, 0)}
}
type Column struct {
Name string
FieldName string

27
xorm.go
View File

@ -17,16 +17,12 @@ func close(engine *Engine) {
engine.Close()
}
// new a db manager according to the parameter. Currently support three
// driver
// new a db manager according to the parameter. Currently support four
// drivers
func NewEngine(driverName string, dataSourceName string) (*Engine, error) {
engine := &Engine{ShowSQL: false, DriverName: driverName, Mapper: SnakeMapper{},
DataSourceName: dataSourceName}
engine := &Engine{DriverName: driverName, Mapper: SnakeMapper{},
DataSourceName: dataSourceName, Filters: make([]Filter, 0)}
engine.Tables = make(map[reflect.Type]*Table)
engine.mutex = &sync.Mutex{}
engine.TagIdentifier = "xorm"
engine.Filters = make([]Filter, 0)
if driverName == SQLITE {
engine.Dialect = &sqlite3{}
} else if driverName == MYSQL {
@ -34,19 +30,28 @@ func NewEngine(driverName string, dataSourceName string) (*Engine, error) {
} else if driverName == POSTGRES {
engine.Dialect = &postgres{}
engine.Filters = append(engine.Filters, &PgSeqFilter{})
engine.Filters = append(engine.Filters, &PgQuoteFilter{})
engine.Filters = append(engine.Filters, &QuoteFilter{})
} else if driverName == MYMYSQL {
engine.Dialect = &mysql{}
engine.Dialect = &mymysql{}
} else {
return nil, errors.New(fmt.Sprintf("Unsupported driver name: %v", driverName))
}
err := engine.Dialect.Init(dataSourceName)
if err != nil {
return nil, err
}
engine.Tables = make(map[reflect.Type]*Table)
engine.mutex = &sync.Mutex{}
engine.TagIdentifier = "xorm"
engine.Filters = append(engine.Filters, &IdFilter{})
engine.Logger = os.Stdout
//engine.Pool = NewSimpleConnectPool()
//engine.Pool = NewNoneConnectPool()
//engine.Cacher = NewLRUCacher()
err := engine.SetPool(NewSysConnectPool())
err = engine.SetPool(NewSysConnectPool())
runtime.SetFinalizer(engine, close)
return engine, err
}