@@ -201,6 +201,53 @@ static int sqlite3_system_errno(sqlite3 *db) {
201201 return 0;
202202}
203203#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+ }
204251*/
205252import "C"
206253import (
@@ -239,12 +286,6 @@ var SQLiteTimestampFormats = []string{
239286 "2006-01-02" ,
240287}
241288
242- const (
243- columnDate string = "date"
244- columnDatetime string = "datetime"
245- columnTimestamp string = "timestamp"
246- )
247-
248289// This variable can be replaced with -ldflags like below:
249290// go build -ldflags="-X 'github.com/mattn/go-sqlite3.driverName=my-sqlite3'"
250291var driverName = "sqlite3"
@@ -390,13 +431,32 @@ type SQLiteResult struct {
390431 changes int64
391432}
392433
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+
393452// SQLiteRows implements driver.Rows.
394453type SQLiteRows struct {
395454 s * SQLiteStmt
396455 nc int32 // Number of columns
397456 cls bool // True if we need to close the parent statement in Close
398457 cols []string
399458 decltype []string
459+ coltype []columnType
400460 ctx context.Context // no better alternative to pass context into Next() method
401461 closemu sync.Mutex
402462}
@@ -2148,7 +2208,10 @@ func (rc *SQLiteRows) Columns() []string {
21482208 return rc .cols
21492209}
21502210
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 ()
21522215 if rc .s .s != nil && rc .decltype == nil {
21532216 rc .decltype = make ([]string , rc .nc )
21542217 for i := 0 ; i < int (rc .nc ); i ++ {
@@ -2158,13 +2221,6 @@ func (rc *SQLiteRows) declTypes() []string {
21582221 return rc .decltype
21592222}
21602223
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-
21682224// Next move cursor to next. Attempts to honor context timeout from QueryContext call.
21692225func (rc * SQLiteRows ) Next (dest []driver.Value ) error {
21702226 rc .s .mu .Lock ()
@@ -2197,6 +2253,13 @@ func (rc *SQLiteRows) Next(dest []driver.Value) error {
21972253 }
21982254}
21992255
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+
22002263// nextSyncLocked moves cursor to next; must be called with locked mutex.
22012264func (rc * SQLiteRows ) nextSyncLocked (dest []driver.Value ) error {
22022265 rv := C ._sqlite3_step_internal (rc .s .s )
@@ -2210,15 +2273,24 @@ func (rc *SQLiteRows) nextSyncLocked(dest []driver.Value) error {
22102273 }
22112274 return nil
22122275 }
2276+ if len (dest ) == 0 {
2277+ return nil
2278+ }
22132279
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 ))
22152287
22162288 for i := range dest {
2217- switch C . sqlite3_column_type ( rc .s . s , C . int ( i ) ) {
2289+ switch rc .coltype [ i ]. dataType ( ) {
22182290 case C .SQLITE_INTEGER :
22192291 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 :
22222294 var t time.Time
22232295 // Assume a millisecond unix timestamp if it's 13 digits -- too
22242296 // large to be a reasonable timestamp in seconds.
@@ -2233,7 +2305,7 @@ func (rc *SQLiteRows) nextSyncLocked(dest []driver.Value) error {
22332305 t = t .In (rc .s .c .loc )
22342306 }
22352307 dest [i ] = t
2236- case "boolean" :
2308+ case C . GO_SQLITE3_DECL_BOOL :
22372309 dest [i ] = val > 0
22382310 default :
22392311 dest [i ] = val
@@ -2257,8 +2329,7 @@ func (rc *SQLiteRows) nextSyncLocked(dest []driver.Value) error {
22572329 n := int (C .sqlite3_column_bytes (rc .s .s , C .int (i )))
22582330 s := C .GoStringN ((* C .char )(unsafe .Pointer (C .sqlite3_column_text (rc .s .s , C .int (i )))), C .int (n ))
22592331
2260- switch rc .decltype [i ] {
2261- case columnTimestamp , columnDatetime , columnDate :
2332+ if rc .coltype [i ].declType () == C .GO_SQLITE3_DECL_DATE {
22622333 var t time.Time
22632334 s = strings .TrimSuffix (s , "Z" )
22642335 for _ , format := range SQLiteTimestampFormats {
@@ -2275,7 +2346,7 @@ func (rc *SQLiteRows) nextSyncLocked(dest []driver.Value) error {
22752346 t = t .In (rc .s .c .loc )
22762347 }
22772348 dest [i ] = t
2278- default :
2349+ } else {
22792350 dest [i ] = s
22802351 }
22812352 }
0 commit comments