Fix dump/import bug #1603
|
@ -1071,6 +1071,8 @@ WHERE c.relkind = 'r'::char AND c.relname = $1%s AND f.attnum > 0 ORDER BY f.att
|
||||||
col.DefaultIsEmpty = false
|
col.DefaultIsEmpty = false
|
||||||
if strings.HasPrefix(col.Default, "nextval(") {
|
if strings.HasPrefix(col.Default, "nextval(") {
|
||||||
col.IsAutoIncrement = true
|
col.IsAutoIncrement = true
|
||||||
|
col.Default = ""
|
||||||
|
col.DefaultIsEmpty = true
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
col.DefaultIsEmpty = true
|
col.DefaultIsEmpty = true
|
||||||
|
|
51
engine.go
51
engine.go
|
@ -5,8 +5,6 @@
|
||||||
package xorm
|
package xorm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
|
||||||
"bytes"
|
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"errors"
|
"errors"
|
||||||
|
@ -389,6 +387,10 @@ func (engine *Engine) dumpTables(tables []*schemas.Table, w io.Writer, tp ...sch
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if len(table.PKColumns()) > 0 && engine.dialect.URI().DBType == schemas.MSSQL {
|
||||||
|
fmt.Fprintf(w, "SET IDENTITY_INSERT [%s] ON;\n", table.Name)
|
||||||
|
}
|
||||||
|
|
||||||
for _, index := range table.Indexes {
|
for _, index := range table.Indexes {
|
||||||
_, err = io.WriteString(w, dialect.CreateIndexSQL(table.Name, index)+";\n")
|
_, err = io.WriteString(w, dialect.CreateIndexSQL(table.Name, index)+";\n")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1160,49 +1162,16 @@ func (engine *Engine) SumsInt(bean interface{}, colNames ...string) ([]int64, er
|
||||||
|
|
||||||
// ImportFile SQL DDL file
|
// ImportFile SQL DDL file
|
||||||
func (engine *Engine) ImportFile(ddlPath string) ([]sql.Result, error) {
|
func (engine *Engine) ImportFile(ddlPath string) ([]sql.Result, error) {
|
||||||
file, err := os.Open(ddlPath)
|
session := engine.NewSession()
|
||||||
if err != nil {
|
defer session.Close()
|
||||||
return nil, err
|
return session.ImportFile(ddlPath)
|
||||||
}
|
|
||||||
defer file.Close()
|
|
||||||
return engine.Import(file)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Import SQL DDL from io.Reader
|
// Import SQL DDL from io.Reader
|
||||||
func (engine *Engine) Import(r io.Reader) ([]sql.Result, error) {
|
func (engine *Engine) Import(r io.Reader) ([]sql.Result, error) {
|
||||||
var results []sql.Result
|
session := engine.NewSession()
|
||||||
var lastError error
|
defer session.Close()
|
||||||
scanner := bufio.NewScanner(r)
|
return session.Import(r)
|
||||||
|
|
||||||
semiColSpliter := func(data []byte, atEOF bool) (advance int, token []byte, err error) {
|
|
||||||
if atEOF && len(data) == 0 {
|
|
||||||
return 0, nil, nil
|
|
||||||
}
|
|
||||||
if i := bytes.IndexByte(data, ';'); i >= 0 {
|
|
||||||
return i + 1, data[0:i], nil
|
|
||||||
}
|
|
||||||
// If we're at EOF, we have a final, non-terminated line. Return it.
|
|
||||||
if atEOF {
|
|
||||||
return len(data), data, nil
|
|
||||||
}
|
|
||||||
// Request more data.
|
|
||||||
return 0, nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
scanner.Split(semiColSpliter)
|
|
||||||
|
|
||||||
for scanner.Scan() {
|
|
||||||
query := strings.Trim(scanner.Text(), " \t\n\r")
|
|
||||||
if len(query) > 0 {
|
|
||||||
result, err := engine.DB().ExecContext(engine.defaultContext, query)
|
|
||||||
results = append(results, result)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return results, lastError
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// nowTime return current time
|
// nowTime return current time
|
||||||
|
|
|
@ -7,6 +7,7 @@ package xorm
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -64,3 +65,35 @@ func TestAutoTransaction(t *testing.T) {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.EqualValues(t, false, has)
|
assert.EqualValues(t, false, has)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDump(t *testing.T) {
|
||||||
|
assert.NoError(t, prepareEngine())
|
||||||
|
|
||||||
|
type TestDumpStruct struct {
|
||||||
|
Id int64
|
||||||
|
Name string
|
||||||
|
}
|
||||||
|
|
||||||
|
assertSync(t, new(TestDumpStruct))
|
||||||
|
|
||||||
|
testEngine.Insert([]TestDumpStruct{
|
||||||
|
{Name: "1"},
|
||||||
|
{Name: "2\n"},
|
||||||
|
{Name: "3;"},
|
||||||
|
{Name: "4\n;\n''"},
|
||||||
|
{Name: "5'\n"},
|
||||||
|
})
|
||||||
|
|
||||||
|
fp := testEngine.Dialect().URI().DBName + ".sql"
|
||||||
|
os.Remove(fp)
|
||||||
|
assert.NoError(t, testEngine.DumpAllToFile(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())
|
||||||
|
}
|
||||||
|
|
|
@ -92,6 +92,7 @@ type EngineInterface interface {
|
||||||
GetTableMapper() names.Mapper
|
GetTableMapper() names.Mapper
|
||||||
GetTZDatabase() *time.Location
|
GetTZDatabase() *time.Location
|
||||||
GetTZLocation() *time.Location
|
GetTZLocation() *time.Location
|
||||||
|
ImportFile(fp string) ([]sql.Result, error)
|
||||||
MapCacher(interface{}, caches.Cacher) error
|
MapCacher(interface{}, caches.Cacher) error
|
||||||
NewSession() *Session
|
NewSession() *Session
|
||||||
NoAutoTime() *Session
|
NoAutoTime() *Session
|
||||||
|
|
|
@ -5,8 +5,11 @@
|
||||||
package xorm
|
package xorm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"xorm.io/xorm/internal/utils"
|
"xorm.io/xorm/internal/utils"
|
||||||
|
@ -432,3 +435,56 @@ func (session *Session) Sync2(beans ...interface{}) error {
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ImportFile SQL DDL file
|
||||||
|
func (session *Session) ImportFile(ddlPath string) ([]sql.Result, error) {
|
||||||
|
file, err := os.Open(ddlPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
return session.Import(file)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Import SQL DDL from io.Reader
|
||||||
|
func (session *Session) Import(r io.Reader) ([]sql.Result, error) {
|
||||||
|
var results []sql.Result
|
||||||
|
var lastError error
|
||||||
|
scanner := bufio.NewScanner(r)
|
||||||
|
|
||||||
|
var inSingleQuote bool
|
||||||
|
semiColSpliter := func(data []byte, atEOF bool) (advance int, token []byte, err error) {
|
||||||
|
if atEOF && len(data) == 0 {
|
||||||
|
return 0, nil, nil
|
||||||
|
}
|
||||||
|
for i, b := range data {
|
||||||
|
if b == '\'' {
|
||||||
|
inSingleQuote = !inSingleQuote
|
||||||
|
}
|
||||||
|
if !inSingleQuote && b == ';' {
|
||||||
|
return i + 1, data[0:i], nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If we're at EOF, we have a final, non-terminated line. Return it.
|
||||||
|
if atEOF {
|
||||||
|
return len(data), data, nil
|
||||||
|
}
|
||||||
|
// Request more data.
|
||||||
|
return 0, nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
scanner.Split(semiColSpliter)
|
||||||
|
|
||||||
|
for scanner.Scan() {
|
||||||
|
query := strings.Trim(scanner.Text(), " \t\n\r")
|
||||||
|
if len(query) > 0 {
|
||||||
|
result, err := session.Exec(query)
|
||||||
|
results = append(results, result)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return results, lastError
|
||||||
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@ package xorm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -210,14 +209,6 @@ func TestCustomTableName(t *testing.T) {
|
||||||
assert.NoError(t, testEngine.CreateTables(c))
|
assert.NoError(t, testEngine.CreateTables(c))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDump(t *testing.T) {
|
|
||||||
assert.NoError(t, prepareEngine())
|
|
||||||
|
|
||||||
fp := testEngine.Dialect().URI().DBName + ".sql"
|
|
||||||
os.Remove(fp)
|
|
||||||
assert.NoError(t, testEngine.DumpAllToFile(fp))
|
|
||||||
}
|
|
||||||
|
|
||||||
type IndexOrUnique struct {
|
type IndexOrUnique struct {
|
||||||
Id int64
|
Id int64
|
||||||
Index int `xorm:"index"`
|
Index int `xorm:"index"`
|
||||||
|
|
Loading…
Reference in New Issue
Block a user