-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathinsert_many.go
120 lines (101 loc) · 2.53 KB
/
insert_many.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
package mysqlx
import (
"bytes"
"database/sql"
"errors"
"fmt"
"log"
"reflect"
"strings"
)
// InsertMany insert multiple records into table. If additional option with table name is not given,
// mysqlx will use the FIRST table name in records for all. All auto-increment fields will be ignored.
func (d *xdb) InsertMany(records interface{}, opts ...Options) (result sql.Result, err error) {
return d.insertMany(d.db, records, opts...)
}
func (d *xdb) insertMany(obj sqlObj, records interface{}, opts ...Options) (result sql.Result, err error) {
// records could be *[]*Xxx, []*Xxx, *[]Xxx, []Xxx
// firstly, get []*Xxx or []Xxx
va := reflect.ValueOf(records)
if reflect.Ptr == va.Type().Kind() {
va = va.Elem()
}
// must be []*Xxx or []Xxx
if reflect.Slice != va.Type().Kind() {
err = fmt.Errorf("records should be a slice of struct, current type invalid (%v)", va.Type())
return
}
total := va.Len()
log.Printf("%d record(s) given", total)
if 0 == total {
return nil, errors.New("no records provided")
}
// get first element
isPtr := false
first := va.Index(0)
if reflect.Ptr == first.Type().Kind() {
first = first.Elem()
isPtr = true
}
if reflect.Struct != first.Type().Kind() {
err = fmt.Errorf("records should be a slice of struct, element type invalid (%v)", first.Type())
return
}
// should be Xxx
v := first.Interface()
// get options
opt := mergeOptions(v, opts...)
if "" == opt.TableName {
return nil, fmt.Errorf("empty table name for type %v", reflect.TypeOf(v))
}
keys, values, err := d.insertFields(v, true, true)
if err != nil {
return
}
buffVal := bytes.Buffer{}
buffVal.WriteString(fmt.Sprintf(
"INSERT INTO `%s` (%s) VALUES\n",
opt.TableName,
strings.Join(keys, ", "),
))
writeValueToBuff(&buffVal, values)
// parse other records
for i := 1; i < total; i++ {
if isPtr {
v = va.Index(i).Elem().Interface()
} else {
v = va.Index(i).Interface()
}
_, values, err = d.insertFields(v, true, true)
if err != nil {
return
}
buffVal.WriteString(",\n")
writeValueToBuff(&buffVal, values)
}
query := buffVal.String()
if opt.DoNotExec {
return nil, newError(doNotExec, query)
}
err = d.checkAutoCreateTable(v, opt)
if err != nil {
return nil, err
}
result, err = obj.Exec(query)
if err != nil {
err = newError(err.Error(), query)
return
}
return
}
func writeValueToBuff(buff *bytes.Buffer, values []string) {
buff.WriteRune('(')
for i, v := range values {
if i > 0 {
buff.WriteString(", ")
}
buff.WriteString(v)
}
buff.WriteRune(')')
return
}