add Sync() method for sync column, index to table
This commit is contained in:
parent
4cdec08cc9
commit
7ebd533407
|
@ -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)
|
||||
|
|
|
@ -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
132
engine.go
|
@ -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()
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
|
|
80
mysql.go
80
mysql.go
|
@ -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¶mN=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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
69
postgres.go
69
postgres.go
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
161
session.go
161
session.go
|
@ -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
|
||||
}
|
||||
if err == nil {
|
||||
|
||||
func (session *Session) CreateUniques(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.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 {
|
||||
|
|
19
sqlite3.go
19
sqlite3.go
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
63
statement.go
63
statement.go
|
@ -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
|
||||
|
|
10
table.go
10
table.go
|
@ -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
27
xorm.go
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue