Fix dump of sqlite #1639

Merged
lunny merged 4 commits from lunny/fix_dump_sqlite into master 2020-07-09 01:41:17 +00:00
2 changed files with 124 additions and 64 deletions
Showing only changes of commit e370537ad1 - Show all commits

137
engine.go
View File

@ -412,6 +412,76 @@ func (engine *Engine) DumpTables(tables []*schemas.Table, w io.Writer, tp ...sch
return engine.dumpTables(tables, w, tp...)
}
func formatColumnValue(dstDialect dialects.Dialect, d interface{}, col *schemas.Column) string {
if d == nil {
return "NULL"
}
if dq, ok := d.(bool); ok && dstDialect.URI().DBType == schemas.SQLITE {
if dq {
return "1"
}
return "0"
}
if col.SQLType.IsText() || col.SQLType.IsTime() {
var v = fmt.Sprintf("%s", d)
if strings.HasSuffix(v, " +0000 UTC") {
return fmt.Sprintf("'%s'", v[0:len(v)-len(" +0000 UTC")])
}
return "'" + strings.Replace(v, "'", "''", -1) + "'"
} else if col.SQLType.IsBlob() {
if reflect.TypeOf(d).Kind() == reflect.Slice {
return fmt.Sprintf("%s", dstDialect.FormatBytes(d.([]byte)))
} else if reflect.TypeOf(d).Kind() == reflect.String {
return fmt.Sprintf("'%s'", d.(string))
}
} else if col.SQLType.IsNumeric() {
switch reflect.TypeOf(d).Kind() {
case reflect.Slice:
if col.SQLType.Name == schemas.Bool {
return fmt.Sprintf("%v", strconv.FormatBool(d.([]byte)[0] != byte('0')))
}
return fmt.Sprintf("%s", string(d.([]byte)))
case reflect.Int16, reflect.Int8, reflect.Int32, reflect.Int64, reflect.Int:
if col.SQLType.Name == schemas.Bool {
v := reflect.ValueOf(d).Int() > 0
if dstDialect.URI().DBType == schemas.SQLITE {
if v {
return "1"
}
return "0"
}
return fmt.Sprintf("%v", strconv.FormatBool(v))
}
return fmt.Sprintf("%v", d)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
if col.SQLType.Name == schemas.Bool {
v := reflect.ValueOf(d).Uint() > 0
if dstDialect.URI().DBType == schemas.SQLITE {
if v {
return "1"
}
return "0"
}
return fmt.Sprintf("%v", strconv.FormatBool(v))
}
return fmt.Sprintf("%v", d)
default:
return fmt.Sprintf("%v", d)
}
}
s := fmt.Sprintf("%v", d)
if strings.Contains(s, ":") || strings.Contains(s, "-") {
if strings.HasSuffix(s, " +0000 UTC") {
return fmt.Sprintf("'%s'", s[0:len(s)-len(" +0000 UTC")])
}
return fmt.Sprintf("'%s'", s)
}
return s
}
// dumpTables dump database all table structs and data to w with specify db type
func (engine *Engine) dumpTables(tables []*schemas.Table, w io.Writer, tp ...schemas.DBType) error {
var dstDialect dialects.Dialect
@ -424,7 +494,10 @@ func (engine *Engine) dumpTables(tables []*schemas.Table, w io.Writer, tp ...sch
}
uri := engine.dialect.URI()
destURI := *uri
destURI := dialects.URI{
DBType: tp[0],
DBName: uri.DBName,
}
dstDialect.Init(&destURI)
}
@ -495,67 +568,9 @@ func (engine *Engine) dumpTables(tables []*schemas.Table, w io.Writer, tp ...sch
if col == nil {
return errors.New("unknow column error")
}
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", dstDialect.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:
if col.SQLType.Name == schemas.Bool {
temp += fmt.Sprintf(", %v", strconv.FormatBool(d.([]byte)[0] != byte('0')))
} else {
temp += fmt.Sprintf(", %s", string(d.([]byte)))
}
case reflect.Int16, reflect.Int8, reflect.Int32, reflect.Int64, reflect.Int:
if col.SQLType.Name == schemas.Bool {
temp += fmt.Sprintf(", %v", strconv.FormatBool(reflect.ValueOf(d).Int() > 0))
} else {
temp += fmt.Sprintf(", %v", d)
}
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
if col.SQLType.Name == schemas.Bool {
temp += fmt.Sprintf(", %v", strconv.FormatBool(reflect.ValueOf(d).Uint() > 0))
} else {
temp += fmt.Sprintf(", %v", d)
}
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 {
if dq, ok := d.(bool); ok && dstDialect.URI().DBType == schemas.SQLITE {
if dq {
temp += ", 1"
} else {
temp += ", 0"
}
} else {
temp += fmt.Sprintf(", %s", s)
}
}
}
temp += "," + formatColumnValue(dstDialect, d, col)
}
_, err = io.WriteString(w, temp[2:]+");\n")
_, err = io.WriteString(w, temp[1:]+");\n")
if err != nil {
return err
}

View File

@ -93,14 +93,16 @@ func TestDump(t *testing.T) {
assert.NoError(t, PrepareEngine())
type TestDumpStruct struct {
Id int64
Name string
Id int64
Name string
IsMan bool
Created time.Time `xorm:"created"`
}
assertSync(t, new(TestDumpStruct))
testEngine.Insert([]TestDumpStruct{
{Name: "1"},
{Name: "1", IsMan: true},
{Name: "2\n"},
{Name: "3;"},
{Name: "4\n;\n''"},
@ -128,6 +130,49 @@ func TestDump(t *testing.T) {
}
}
func TestDumpTables(t *testing.T) {
assert.NoError(t, PrepareEngine())
type TestDumpTableStruct struct {
Id int64
Name string
IsMan bool
Created time.Time `xorm:"created"`
}
assertSync(t, new(TestDumpTableStruct))
testEngine.Insert([]TestDumpTableStruct{
{Name: "1", IsMan: true},
{Name: "2\n"},
{Name: "3;"},
{Name: "4\n;\n''"},
{Name: "5'\n"},
})
fp := fmt.Sprintf("%v-table.sql", testEngine.Dialect().URI().DBType)
os.Remove(fp)
tb, err := testEngine.TableInfo(new(TestDumpTableStruct))
assert.NoError(t, err)
assert.NoError(t, testEngine.(*xorm.Engine).DumpTablesToFile([]*schemas.Table{tb}, fp))
assert.NoError(t, PrepareEngine())
sess := testEngine.NewSession()
defer sess.Close()
assert.NoError(t, sess.Begin())
_, err = sess.ImportFile(fp)
assert.NoError(t, err)
assert.NoError(t, sess.Commit())
for _, tp := range []schemas.DBType{schemas.SQLITE, schemas.MYSQL, schemas.POSTGRES, schemas.MSSQL} {
name := fmt.Sprintf("dump_%v-table.sql", tp)
t.Run(name, func(t *testing.T) {
assert.NoError(t, testEngine.(*xorm.Engine).DumpTablesToFile([]*schemas.Table{tb}, name, tp))
})
}
}
func TestSetSchema(t *testing.T) {
assert.NoError(t, PrepareEngine())