RFC: Use provided type to create the dstTable rather than inferring from the SQL types #1872

Merged
lunny merged 18 commits from zeripath/xorm:dump-infer-from-type into master 2021-05-07 01:19:04 +00:00
2 changed files with 91 additions and 31 deletions

View File

@ -243,4 +243,4 @@ test-tidb\#%: go-check
.PHONY: vet
vet:
$(GO) vet $(shell $(GO) list ./...)
$(GO) vet $(shell $(GO) list ./...)

120
engine.go
View File

@ -460,6 +460,11 @@ func formatColumnValue(dstDialect dialects.Dialect, d interface{}, col *schemas.
var v = fmt.Sprintf("%s", d)
return "'" + strings.Replace(v, "'", "''", -1) + "'"
} else if col.SQLType.IsTime() {
if dstDialect.URI().DBType == schemas.MSSQL && col.SQLType.Name == schemas.DateTime {
if t, ok := d.(time.Time); ok {
return "'" + t.UTC().Format("2006-01-02 15:04:05") + "'"
}
}
var v = fmt.Sprintf("%s", d)
if strings.HasSuffix(v, " +0000 UTC") {
return fmt.Sprintf("'%s'", v[0:len(v)-len(" +0000 UTC")])
@ -537,6 +542,8 @@ func (engine *Engine) dumpTables(tables []*schemas.Table, w io.Writer, tp ...sch
}
dstDialect.Init(&destURI)
}
cacherMgr := caches.NewManager()
dstTableCache := tags.NewParser("xorm", dstDialect, engine.GetTableMapper(), engine.GetColumnMapper(), cacherMgr)
_, err := io.WriteString(w, fmt.Sprintf("/*Generated by xorm %s, from %s to %s*/\n\n",
time.Now().In(engine.TZLocation).Format("2006-01-02 15:04:05"), engine.dialect.URI().DBType, dstDialect.URI().DBType))
@ -545,9 +552,18 @@ func (engine *Engine) dumpTables(tables []*schemas.Table, w io.Writer, tp ...sch
}
for i, table := range tables {
tableName := table.Name
dstTable := table
if table.Type != nil {
dstTable, err = dstTableCache.Parse(reflect.New(table.Type))
if err != nil {
engine.logger.Errorf("Unable to infer table for %s in new dialect. Error: %v", table.Name)
dstTable = table
}
}
dstTableName := dstTable.Name
if dstDialect.URI().Schema != "" {
tableName = fmt.Sprintf("%s.%s", dstDialect.URI().Schema, table.Name)
dstTableName = fmt.Sprintf("%s.%s", dstDialect.URI().Schema, dstTable.Name)
}
originalTableName := table.Name
if engine.dialect.URI().Schema != "" {
@ -559,27 +575,30 @@ func (engine *Engine) dumpTables(tables []*schemas.Table, w io.Writer, tp ...sch
return err
}
}
sqls, _ := dstDialect.CreateTableSQL(table, tableName)
sqls, _ := dstDialect.CreateTableSQL(dstTable, dstTableName)
for _, s := range sqls {
_, err = io.WriteString(w, s+";\n")
if err != nil {
return err
}
}
if len(table.PKColumns()) > 0 && dstDialect.URI().DBType == schemas.MSSQL {
fmt.Fprintf(w, "SET IDENTITY_INSERT [%s] ON;\n", table.Name)
if len(dstTable.PKColumns()) > 0 && dstDialect.URI().DBType == schemas.MSSQL {
fmt.Fprintf(w, "SET IDENTITY_INSERT [%s] ON;\n", dstTable.Name)
}
for _, index := range table.Indexes {
_, err = io.WriteString(w, dstDialect.CreateIndexSQL(table.Name, index)+";\n")
for _, index := range dstTable.Indexes {
_, err = io.WriteString(w, dstDialect.CreateIndexSQL(dstTable.Name, index)+";\n")
if err != nil {
return err
}
}
cols := table.ColumnsSeq()
dstCols := dstTable.ColumnsSeq()
colNames := engine.dialect.Quoter().Join(cols, ", ")
destColNames := dstDialect.Quoter().Join(cols, ", ")
destColNames := dstDialect.Quoter().Join(dstCols, ", ")
rows, err := engine.DB().QueryContext(engine.defaultContext, "SELECT "+colNames+" FROM "+engine.Quote(originalTableName))
if err != nil {
@ -587,35 +606,76 @@ func (engine *Engine) dumpTables(tables []*schemas.Table, w io.Writer, tp ...sch
}
defer rows.Close()
for rows.Next() {
dest := make([]interface{}, len(cols))
err = rows.ScanSlice(&dest)
if err != nil {
return err
}
_, err = io.WriteString(w, "INSERT INTO "+dstDialect.Quoter().Quote(tableName)+" ("+destColNames+") VALUES (")
if err != nil {
return err
}
var temp string
for i, d := range dest {
col := table.GetColumn(cols[i])
if col == nil {
return errors.New("unknow column error")
if table.Type != nil {
sess := engine.NewSession()
defer sess.Close()
for rows.Next() {
bean := reflect.New(table.Type)
fields, err := rows.Columns()
if err != nil {
return err
}
scanResults, err := sess.row2Slice(rows, fields, bean)
if err != nil {
return err
}
dataStruct := utils.ReflectValue(bean.Interface())
_, err = sess.slice2Bean(scanResults, fields, bean.Interface(), &dataStruct, table)
if err != nil {
return err
}
_, err = io.WriteString(w, "INSERT INTO "+dstDialect.Quoter().Quote(dstTableName)+" ("+destColNames+") VALUES (")
if err != nil {
return err
}
var temp string
for _, d := range dstCols {
col := table.GetColumn(d)
if col == nil {
return errors.New("unknown column error")
}
temp += "," + formatColumnValue(dstDialect, bean.Elem().FieldByName(col.FieldName).Interface(), col)
}
_, err = io.WriteString(w, temp[1:]+");\n")
if err != nil {
return err
}
temp += "," + formatColumnValue(dstDialect, d, col)
}
_, err = io.WriteString(w, temp[1:]+");\n")
if err != nil {
return err
} else {
for rows.Next() {
dest := make([]interface{}, len(cols))
err = rows.ScanSlice(&dest)
if err != nil {
return err
}
_, err = io.WriteString(w, "INSERT INTO "+dstDialect.Quoter().Quote(dstTableName)+" ("+destColNames+") VALUES (")
if err != nil {
return err
}
var temp string
for i, d := range dest {
col := table.GetColumn(cols[i])
if col == nil {
return errors.New("unknow column error")
}
temp += "," + formatColumnValue(dstDialect, d, col)
}
_, err = io.WriteString(w, temp[1:]+");\n")
if err != nil {
return err
}
}
}
// FIXME: Hack for postgres
if dstDialect.URI().DBType == schemas.POSTGRES && table.AutoIncrColumn() != nil {
_, err = io.WriteString(w, "SELECT setval('"+tableName+"_id_seq', COALESCE((SELECT MAX("+table.AutoIncrColumn().Name+") + 1 FROM "+dstDialect.Quoter().Quote(tableName)+"), 1), false);\n")
_, err = io.WriteString(w, "SELECT setval('"+dstTableName+"_id_seq', COALESCE((SELECT MAX("+table.AutoIncrColumn().Name+") + 1 FROM "+dstDialect.Quoter().Quote(dstTableName)+"), 1), false);\n")
if err != nil {
return err
}