@@ -25,6 +25,7 @@ import (
25
25
"github.com/gogf/gf/v2/errors/gerror"
26
26
"github.com/gogf/gf/v2/os/gfile"
27
27
"github.com/gogf/gf/v2/text/gstr"
28
+ "github.com/gogf/gf/v2/util/gconv"
28
29
)
29
30
30
31
// Driver is the driver for sqlite database.
@@ -35,6 +36,8 @@ type Driver struct {
35
36
var (
36
37
// tableFieldsMap caches the table information retrieved from database.
37
38
tableFieldsMap = gmap .New (true )
39
+ // Error
40
+ ErrorSave = gerror .NewCode (gcode .CodeNotSupported , `Save operation is not supported by sqlite driver` )
38
41
)
39
42
40
43
func init () {
@@ -147,10 +150,17 @@ func (d *Driver) TableFields(ctx context.Context, table string, schema ...string
147
150
}
148
151
fields = make (map [string ]* gdb.TableField )
149
152
for i , m := range result {
153
+ mKey := ""
154
+ if m ["pk" ].Bool () {
155
+ mKey = "pri"
156
+ }
150
157
fields [strings .ToLower (m ["name" ].String ())] = & gdb.TableField {
151
- Index : i ,
152
- Name : strings .ToLower (m ["name" ].String ()),
153
- Type : strings .ToLower (m ["type" ].String ()),
158
+ Index : i ,
159
+ Name : strings .ToLower (m ["name" ].String ()),
160
+ Type : strings .ToLower (m ["type" ].String ()),
161
+ Key : mKey ,
162
+ Default : m ["dflt_value" ].Val (),
163
+ Null : ! m ["notnull" ].Bool (),
154
164
}
155
165
}
156
166
return fields
@@ -166,11 +176,73 @@ func (d *Driver) TableFields(ctx context.Context, table string, schema ...string
166
176
func (d * Driver ) DoInsert (ctx context.Context , link gdb.Link , table string , list gdb.List , option gdb.DoInsertOption ) (result sql.Result , err error ) {
167
177
switch option .InsertOption {
168
178
case gdb .InsertOptionSave :
169
- return nil , gerror .NewCode (gcode .CodeNotSupported , `Save operation is not supported by sqlite driver` )
170
-
171
- case gdb .InsertOptionReplace :
172
- return nil , gerror .NewCode (gcode .CodeNotSupported , `Replace operation is not supported by sqlite driver` )
179
+ return nil , ErrorSave
180
+ case gdb .InsertOptionIgnore , gdb .InsertOptionReplace :
181
+ var (
182
+ keys []string // Field names.
183
+ values []string // Value holder string array, like: (?,?,?)
184
+ params []interface {} // Values that will be committed to underlying database driver.
185
+ onDuplicateStr string // onDuplicateStr is used in "ON DUPLICATE KEY UPDATE" statement.
186
+ )
187
+ // Handle the field names and placeholders.
188
+ for k := range list [0 ] {
189
+ keys = append (keys , k )
190
+ }
191
+ // Prepare the batch result pointer.
192
+ var (
193
+ charL , charR = d .GetChars ()
194
+ batchResult = new (gdb.SqlResult )
195
+ keysStr = charL + strings .Join (keys , charR + "," + charL ) + charR
196
+ operation = "INSERT OR IGNORE"
197
+ )
173
198
199
+ if option .InsertOption == gdb .InsertOptionReplace {
200
+ operation = "INSERT OR REPLACE"
201
+ }
202
+ var (
203
+ listLength = len (list )
204
+ valueHolder = make ([]string , 0 )
205
+ )
206
+ for i := 0 ; i < listLength ; i ++ {
207
+ values = values [:0 ]
208
+ // Note that the map type is unordered,
209
+ // so it should use slice+key to retrieve the value.
210
+ for _ , k := range keys {
211
+ if s , ok := list [i ][k ].(gdb.Raw ); ok {
212
+ values = append (values , gconv .String (s ))
213
+ } else {
214
+ values = append (values , "?" )
215
+ params = append (params , list [i ][k ])
216
+ }
217
+ }
218
+ valueHolder = append (valueHolder , "(" + gstr .Join (values , "," )+ ")" )
219
+ // Batch package checks: It meets the batch number, or it is the last element.
220
+ if len (valueHolder ) == option .BatchCount || (i == listLength - 1 && len (valueHolder ) > 0 ) {
221
+ var (
222
+ stdSqlResult sql.Result
223
+ affectedRows int64
224
+ )
225
+ stdSqlResult , err = d .DoExec (ctx , link , fmt .Sprintf (
226
+ "%s INTO %s(%s) VALUES%s %s" ,
227
+ operation , d .QuotePrefixTableName (table ), keysStr ,
228
+ gstr .Join (valueHolder , "," ),
229
+ onDuplicateStr ,
230
+ ), params ... )
231
+ if err != nil {
232
+ return stdSqlResult , err
233
+ }
234
+ if affectedRows , err = stdSqlResult .RowsAffected (); err != nil {
235
+ err = gerror .WrapCode (gcode .CodeDbOperationError , err , `sql.Result.RowsAffected failed` )
236
+ return stdSqlResult , err
237
+ } else {
238
+ batchResult .Result = stdSqlResult
239
+ batchResult .Affected += affectedRows
240
+ }
241
+ params = params [:0 ]
242
+ valueHolder = valueHolder [:0 ]
243
+ }
244
+ }
245
+ return batchResult , nil
174
246
default :
175
247
return d .Core .DoInsert (ctx , link , table , list , option )
176
248
}
0 commit comments