@@ -201,6 +201,53 @@ static int sqlite3_system_errno(sqlite3 *db) {
201
201
return 0;
202
202
}
203
203
#endif
204
+
205
+ #define GO_SQLITE3_DECL_DATE (1 << 7)
206
+ #define GO_SQLITE3_DECL_BOOL (1 << 6)
207
+ #define GO_SQLITE3_DECL_MASK (GO_SQLITE3_DECL_DATE | GO_SQLITE3_DECL_BOOL)
208
+ #define GO_SQLITE3_TYPE_MASK (GO_SQLITE3_DECL_BOOL - 1)
209
+
210
+ // _sqlite3_column_decltypes stores the declared column type in the typs array.
211
+ // This function must always be called before _sqlite3_column_types since it
212
+ // overwrites the datatype.
213
+ static void _sqlite3_column_decltypes(sqlite3_stmt* stmt, uint8_t *typs, int ntyps) {
214
+ for (int i = 0; i < ntyps; i++) {
215
+ const char *typ = sqlite3_column_decltype(stmt, i);
216
+ if (typ == NULL) {
217
+ typs[i] = 0;
218
+ continue;
219
+ }
220
+ switch (typ[0]) {
221
+ case 'b':
222
+ case 'B':
223
+ if (!sqlite3_stricmp(typ, "boolean")) {
224
+ typs[i] = GO_SQLITE3_DECL_BOOL;
225
+ }
226
+ break;
227
+ case 'd':
228
+ case 'D':
229
+ if (!sqlite3_stricmp(typ, "date") || !sqlite3_stricmp(typ, "datetime")) {
230
+ typs[i] = GO_SQLITE3_DECL_DATE;
231
+ }
232
+ break;
233
+ case 't':
234
+ case 'T':
235
+ if (!sqlite3_stricmp(typ, "timestamp")) {
236
+ typs[i] = GO_SQLITE3_DECL_DATE;
237
+ }
238
+ break;
239
+ default:
240
+ typs[i] = 0;
241
+ }
242
+ }
243
+ }
244
+
245
+ static void _sqlite3_column_types(sqlite3_stmt *stmt, uint8_t *typs, int ntyps) {
246
+ for (int i = 0; i < ntyps; i++) {
247
+ typs[i] &= GO_SQLITE3_DECL_MASK; // clear lower bits
248
+ typs[i] |= (uint8_t)sqlite3_column_type(stmt, i);
249
+ }
250
+ }
204
251
*/
205
252
import "C"
206
253
import (
@@ -239,12 +286,6 @@ var SQLiteTimestampFormats = []string{
239
286
"2006-01-02" ,
240
287
}
241
288
242
- const (
243
- columnDate string = "date"
244
- columnDatetime string = "datetime"
245
- columnTimestamp string = "timestamp"
246
- )
247
-
248
289
// This variable can be replaced with -ldflags like below:
249
290
// go build -ldflags="-X 'github.com/mattn/go-sqlite3.driverName=my-sqlite3'"
250
291
var driverName = "sqlite3"
@@ -390,13 +431,32 @@ type SQLiteResult struct {
390
431
changes int64
391
432
}
392
433
434
+ // A columnType is a compact representation of sqlite3 columns datatype and
435
+ // declared type. The first two bits store the declared type and the remaining
436
+ // six bits store the sqlite3 datatype.
437
+ type columnType uint8
438
+
439
+ // declType returns the declared type, which is currently GO_SQLITE3_DECL_DATE
440
+ // or GO_SQLITE3_DECL_BOOL, since those are the only two types that we need for
441
+ // converting values.
442
+ func (c columnType ) declType () int {
443
+ return int (c ) & C .GO_SQLITE3_DECL_MASK
444
+ }
445
+
446
+ // dataType returns the sqlite3 datatype code of the column, which is the
447
+ // result of sqlite3_column_type.
448
+ func (c columnType ) dataType () int {
449
+ return int (c ) & C .GO_SQLITE3_TYPE_MASK
450
+ }
451
+
393
452
// SQLiteRows implements driver.Rows.
394
453
type SQLiteRows struct {
395
454
s * SQLiteStmt
396
455
nc int32 // Number of columns
397
456
cls bool // True if we need to close the parent statement in Close
398
457
cols []string
399
458
decltype []string
459
+ coltype []columnType
400
460
ctx context.Context // no better alternative to pass context into Next() method
401
461
closemu sync.Mutex
402
462
}
@@ -2148,7 +2208,10 @@ func (rc *SQLiteRows) Columns() []string {
2148
2208
return rc .cols
2149
2209
}
2150
2210
2151
- func (rc * SQLiteRows ) declTypes () []string {
2211
+ // DeclTypes return column types.
2212
+ func (rc * SQLiteRows ) DeclTypes () []string {
2213
+ rc .s .mu .Lock ()
2214
+ defer rc .s .mu .Unlock ()
2152
2215
if rc .s .s != nil && rc .decltype == nil {
2153
2216
rc .decltype = make ([]string , rc .nc )
2154
2217
for i := 0 ; i < int (rc .nc ); i ++ {
@@ -2158,13 +2221,6 @@ func (rc *SQLiteRows) declTypes() []string {
2158
2221
return rc .decltype
2159
2222
}
2160
2223
2161
- // DeclTypes return column types.
2162
- func (rc * SQLiteRows ) DeclTypes () []string {
2163
- rc .s .mu .Lock ()
2164
- defer rc .s .mu .Unlock ()
2165
- return rc .declTypes ()
2166
- }
2167
-
2168
2224
// Next move cursor to next. Attempts to honor context timeout from QueryContext call.
2169
2225
func (rc * SQLiteRows ) Next (dest []driver.Value ) error {
2170
2226
rc .s .mu .Lock ()
@@ -2197,6 +2253,13 @@ func (rc *SQLiteRows) Next(dest []driver.Value) error {
2197
2253
}
2198
2254
}
2199
2255
2256
+ func (rc * SQLiteRows ) colTypePtr () * C.uint8_t {
2257
+ if len (rc .coltype ) == 0 {
2258
+ return nil
2259
+ }
2260
+ return (* C .uint8_t )(unsafe .Pointer (& rc .coltype [0 ]))
2261
+ }
2262
+
2200
2263
// nextSyncLocked moves cursor to next; must be called with locked mutex.
2201
2264
func (rc * SQLiteRows ) nextSyncLocked (dest []driver.Value ) error {
2202
2265
rv := C ._sqlite3_step_internal (rc .s .s )
@@ -2210,15 +2273,24 @@ func (rc *SQLiteRows) nextSyncLocked(dest []driver.Value) error {
2210
2273
}
2211
2274
return nil
2212
2275
}
2276
+ if len (dest ) == 0 {
2277
+ return nil
2278
+ }
2213
2279
2214
- rc .declTypes ()
2280
+ if rc .coltype == nil {
2281
+ rc .coltype = make ([]columnType , rc .nc )
2282
+ C ._sqlite3_column_decltypes (rc .s .s , rc .colTypePtr (), C .int (rc .nc ))
2283
+ }
2284
+ // Must call this each time since sqlite3 is loosely
2285
+ // typed and the column types can vary between rows.
2286
+ C ._sqlite3_column_types (rc .s .s , rc .colTypePtr (), C .int (rc .nc ))
2215
2287
2216
2288
for i := range dest {
2217
- switch C . sqlite3_column_type ( rc .s . s , C . int ( i ) ) {
2289
+ switch rc .coltype [ i ]. dataType ( ) {
2218
2290
case C .SQLITE_INTEGER :
2219
2291
val := int64 (C .sqlite3_column_int64 (rc .s .s , C .int (i )))
2220
- switch rc .decltype [i ] {
2221
- case columnTimestamp , columnDatetime , columnDate :
2292
+ switch rc .coltype [i ]. declType () {
2293
+ case C . GO_SQLITE3_DECL_DATE :
2222
2294
var t time.Time
2223
2295
// Assume a millisecond unix timestamp if it's 13 digits -- too
2224
2296
// large to be a reasonable timestamp in seconds.
@@ -2233,7 +2305,7 @@ func (rc *SQLiteRows) nextSyncLocked(dest []driver.Value) error {
2233
2305
t = t .In (rc .s .c .loc )
2234
2306
}
2235
2307
dest [i ] = t
2236
- case "boolean" :
2308
+ case C . GO_SQLITE3_DECL_BOOL :
2237
2309
dest [i ] = val > 0
2238
2310
default :
2239
2311
dest [i ] = val
@@ -2257,8 +2329,7 @@ func (rc *SQLiteRows) nextSyncLocked(dest []driver.Value) error {
2257
2329
n := int (C .sqlite3_column_bytes (rc .s .s , C .int (i )))
2258
2330
s := C .GoStringN ((* C .char )(unsafe .Pointer (C .sqlite3_column_text (rc .s .s , C .int (i )))), C .int (n ))
2259
2331
2260
- switch rc .decltype [i ] {
2261
- case columnTimestamp , columnDatetime , columnDate :
2332
+ if rc .coltype [i ].declType () == C .GO_SQLITE3_DECL_DATE {
2262
2333
var t time.Time
2263
2334
s = strings .TrimSuffix (s , "Z" )
2264
2335
for _ , format := range SQLiteTimestampFormats {
@@ -2275,7 +2346,7 @@ func (rc *SQLiteRows) nextSyncLocked(dest []driver.Value) error {
2275
2346
t = t .In (rc .s .c .loc )
2276
2347
}
2277
2348
dest [i ] = t
2278
- default :
2349
+ } else {
2279
2350
dest [i ] = s
2280
2351
}
2281
2352
}
0 commit comments