diff --git a/README.md b/README.md index a37913c9..993fe2cb 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,10 @@ Drivers for Go's sql package which currently support database/sql includes: # Changelog +* **v0.5.0** + * logging interface changed + * some bugs fixed + * **v0.4.5** * many bugs fixed * extends support unlimited deep diff --git a/README_CN.md b/README_CN.md index fb2da570..ac6aa410 100644 --- a/README_CN.md +++ b/README_CN.md @@ -56,6 +56,10 @@ xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作 ## 更新日志 +* **v0.5.0** + * logging接口进行不兼容改变 + * Bug修正 + * **v0.4.5** * bug修正 * extends 支持无限级 diff --git a/VERSION b/VERSION index 8c5fb856..6fde5ec7 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -xorm v0.5.1.0228 +xorm v0.5.1.0229 diff --git a/engine.go b/engine.go index fe20e563..d226550c 100644 --- a/engine.go +++ b/engine.go @@ -394,9 +394,7 @@ func (engine *Engine) DBMetas() ([]*core.Table, error) { return tables, nil } -/* -dump database all table structs and data to a file -*/ +// DumpAllToFile dump database all table structs and data to a file func (engine *Engine) DumpAllToFile(fp string) error { f, err := os.Create(fp) if err != nil { @@ -406,15 +404,44 @@ func (engine *Engine) DumpAllToFile(fp string) error { return engine.DumpAll(f) } -/* -dump database all table structs and data to w -*/ +// DumpAll dump database all table structs and data to w func (engine *Engine) DumpAll(w io.Writer) error { + return engine.dumpAll(w, engine.dialect.DBType()) +} + +// DumpTablesToFile dump specified tables to SQL file. +func (engine *Engine) DumpTablesToFile(tables []*core.Table, fp string, tp ...core.DbType) error { + f, err := os.Create(fp) + if err != nil { + return err + } + defer f.Close() + return engine.DumpTables(tables, f, tp...) +} + +// DumpTables dump specify tables to io.Writer +func (engine *Engine) DumpTables(tables []*core.Table, w io.Writer, tp ...core.DbType) error { + return engine.dumpTables(tables, w, tp...) +} + +// DumpAll dump database all table structs and data to w with specify db type +func (engine *Engine) dumpAll(w io.Writer, tp ...core.DbType) error { tables, err := engine.DBMetas() if err != nil { return err } + var dialect core.Dialect + if len(tp) == 0 { + dialect = engine.dialect + } else { + dialect = core.QueryDialect(tp[0]) + if dialect == nil { + return errors.New("Unsupported database type.") + } + dialect.Init(nil, engine.dialect.URI(), "", "") + } + _, err = io.WriteString(w, fmt.Sprintf("/*Generated by xorm v%s %s*/\n\n", Version, time.Now().In(engine.TZLocation).Format("2006-01-02 15:04:05"))) if err != nil { @@ -428,12 +455,12 @@ func (engine *Engine) DumpAll(w io.Writer) error { return err } } - _, err = io.WriteString(w, engine.dialect.CreateTableSql(table, "", table.StoreEngine, "")+";\n") + _, err = io.WriteString(w, dialect.CreateTableSql(table, "", table.StoreEngine, "")+";\n") if err != nil { return err } for _, index := range table.Indexes { - _, err = io.WriteString(w, engine.dialect.CreateIndexSql(table.Name, index)+";\n") + _, err = io.WriteString(w, dialect.CreateIndexSql(table.Name, index)+";\n") if err != nil { return err } @@ -458,7 +485,7 @@ func (engine *Engine) DumpAll(w io.Writer) error { return err } - _, err = io.WriteString(w, "INSERT INTO "+engine.Quote(table.Name)+" ("+engine.Quote(strings.Join(cols, engine.Quote(", ")))+") VALUES (") + _, err = io.WriteString(w, "INSERT INTO "+dialect.Quote(table.Name)+" ("+dialect.Quote(strings.Join(cols, dialect.Quote(", ")))+") VALUES (") if err != nil { return err } @@ -473,7 +500,7 @@ func (engine *Engine) DumpAll(w io.Writer) error { temp += ", '" + strings.Replace(v, "'", "''", -1) + "'" } else if col.SQLType.IsBlob() { if reflect.TypeOf(d).Kind() == reflect.Slice { - temp += fmt.Sprintf(", %s", engine.dialect.FormatBytes(d.([]byte))) + temp += fmt.Sprintf(", %s", dialect.FormatBytes(d.([]byte))) } else if reflect.TypeOf(d).Kind() == reflect.String { temp += fmt.Sprintf(", '%s'", d.(string)) } @@ -502,6 +529,114 @@ func (engine *Engine) DumpAll(w io.Writer) error { return nil } +// DumpAll dump database all table structs and data to w with specify db type +func (engine *Engine) dumpTables(tables []*core.Table, w io.Writer, tp ...core.DbType) error { + var dialect core.Dialect + if len(tp) == 0 { + dialect = engine.dialect + } else { + dialect = core.QueryDialect(tp[0]) + if dialect == nil { + return errors.New("Unsupported database type.") + } + dialect.Init(nil, engine.dialect.URI(), "", "") + } + + _, err := io.WriteString(w, fmt.Sprintf("/*Generated by xorm v%s %s, from %s to %s*/\n\n", + Version, time.Now().In(engine.TZLocation).Format("2006-01-02 15:04:05"), engine.dialect.DBType(), dialect.DBType())) + if err != nil { + return err + } + + for i, table := range tables { + if i > 0 { + _, err = io.WriteString(w, "\n") + if err != nil { + return err + } + } + _, err = io.WriteString(w, dialect.CreateTableSql(table, "", table.StoreEngine, "")+";\n") + if err != nil { + return err + } + for _, index := range table.Indexes { + _, err = io.WriteString(w, dialect.CreateIndexSql(table.Name, index)+";\n") + if err != nil { + return err + } + } + + rows, err := engine.DB().Query("SELECT * FROM " + engine.Quote(table.Name)) + if err != nil { + return err + } + + cols, err := rows.Columns() + if err != nil { + return err + } + if len(cols) == 0 { + continue + } + for rows.Next() { + dest := make([]interface{}, len(cols)) + err = rows.ScanSlice(&dest) + if err != nil { + return err + } + + _, err = io.WriteString(w, "INSERT INTO "+dialect.Quote(table.Name)+" ("+dialect.Quote(strings.Join(cols, dialect.Quote(", ")))+") VALUES (") + if err != nil { + return err + } + + var temp string + for i, d := range dest { + col := table.GetColumn(cols[i]) + if d == nil { + temp += ", NULL" + } else if col.SQLType.IsText() || col.SQLType.IsTime() { + var v = fmt.Sprintf("%s", d) + if strings.HasSuffix(v, " +0000 UTC") { + temp += fmt.Sprintf(", '%s'", v[0:len(v)-len(" +0000 UTC")]) + } else { + temp += ", '" + strings.Replace(v, "'", "''", -1) + "'" + } + } else if col.SQLType.IsBlob() { + if reflect.TypeOf(d).Kind() == reflect.Slice { + temp += fmt.Sprintf(", %s", dialect.FormatBytes(d.([]byte))) + } else if reflect.TypeOf(d).Kind() == reflect.String { + temp += fmt.Sprintf(", '%s'", d.(string)) + } + } else if col.SQLType.IsNumeric() { + switch reflect.TypeOf(d).Kind() { + case reflect.Slice: + temp += fmt.Sprintf(", %s", string(d.([]byte))) + default: + temp += fmt.Sprintf(", %v", d) + } + } else { + s := fmt.Sprintf("%v", d) + if strings.Contains(s, ":") || strings.Contains(s, "-") { + if strings.HasSuffix(s, " +0000 UTC") { + temp += fmt.Sprintf(", '%s'", s[0:len(s)-len(" +0000 UTC")]) + } else { + temp += fmt.Sprintf(", '%s'", s) + } + } else { + temp += fmt.Sprintf(", %s", s) + } + } + } + _, err = io.WriteString(w, temp[2:]+");\n") + if err != nil { + return err + } + } + } + return nil +} + // use cascade or not func (engine *Engine) Cascade(trueOrFalse ...bool) *Session { session := engine.NewSession() diff --git a/xorm.go b/xorm.go index cc51d441..ed9e4b4e 100644 --- a/xorm.go +++ b/xorm.go @@ -17,7 +17,7 @@ import ( ) const ( - Version string = "0.5.1.0228" + Version string = "0.5.1.0229" ) func regDrvsNDialects() bool {