@@ -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,12 +431,31 @@ 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        int 
397456	cols      []string 
398457	decltype  []string 
458+ 	coltype   []columnType 
399459	cls       bool 
400460	closed    bool 
401461	ctx       context.Context  // no better alternative to pass context into Next() method 
@@ -2146,7 +2206,10 @@ func (rc *SQLiteRows) Columns() []string {
21462206	return  rc .cols 
21472207}
21482208
2149- func  (rc  * SQLiteRows ) declTypes () []string  {
2209+ // DeclTypes return column types. 
2210+ func  (rc  * SQLiteRows ) DeclTypes () []string  {
2211+ 	rc .s .mu .Lock ()
2212+ 	defer  rc .s .mu .Unlock ()
21502213	if  rc .s .s  !=  nil  &&  rc .decltype  ==  nil  {
21512214		rc .decltype  =  make ([]string , rc .nc )
21522215		for  i  :=  0 ; i  <  rc .nc ; i ++  {
@@ -2156,13 +2219,6 @@ func (rc *SQLiteRows) declTypes() []string {
21562219	return  rc .decltype 
21572220}
21582221
2159- // DeclTypes return column types. 
2160- func  (rc  * SQLiteRows ) DeclTypes () []string  {
2161- 	rc .s .mu .Lock ()
2162- 	defer  rc .s .mu .Unlock ()
2163- 	return  rc .declTypes ()
2164- }
2165- 
21662222// Next move cursor to next. Attempts to honor context timeout from QueryContext call. 
21672223func  (rc  * SQLiteRows ) Next (dest  []driver.Value ) error  {
21682224	rc .s .mu .Lock ()
@@ -2195,6 +2251,13 @@ func (rc *SQLiteRows) Next(dest []driver.Value) error {
21952251	}
21962252}
21972253
2254+ func  (rc  * SQLiteRows ) colTypePtr () * C.uint8_t  {
2255+ 	if  len (rc .coltype ) ==  0  {
2256+ 		return  nil 
2257+ 	}
2258+ 	return  (* C .uint8_t )(unsafe .Pointer (& rc .coltype [0 ]))
2259+ }
2260+ 
21982261// nextSyncLocked moves cursor to next; must be called with locked mutex. 
21992262func  (rc  * SQLiteRows ) nextSyncLocked (dest  []driver.Value ) error  {
22002263	rv  :=  C ._sqlite3_step_internal (rc .s .s )
@@ -2208,15 +2271,24 @@ func (rc *SQLiteRows) nextSyncLocked(dest []driver.Value) error {
22082271		}
22092272		return  nil 
22102273	}
2274+ 	if  len (dest ) ==  0  {
2275+ 		return  nil 
2276+ 	}
22112277
2212- 	rc .declTypes ()
2278+ 	if  rc .coltype  ==  nil  {
2279+ 		rc .coltype  =  make ([]columnType , rc .nc )
2280+ 		C ._sqlite3_column_decltypes (rc .s .s , rc .colTypePtr (), C .int (rc .nc ))
2281+ 	}
2282+ 	// Must call this each time since sqlite3 is loosely 
2283+ 	// typed and the column types can vary between rows. 
2284+ 	C ._sqlite3_column_types (rc .s .s , rc .colTypePtr (), C .int (rc .nc ))
22132285
22142286	for  i  :=  range  dest  {
2215- 		switch  C . sqlite3_column_type ( rc .s . s ,  C . int ( i ) ) {
2287+ 		switch  rc .coltype [ i ]. DataType ( ) {
22162288		case  C .SQLITE_INTEGER :
22172289			val  :=  int64 (C .sqlite3_column_int64 (rc .s .s , C .int (i )))
2218- 			switch  rc .decltype [i ] {
2219- 			case  columnTimestamp ,  columnDatetime ,  columnDate :
2290+ 			switch  rc .coltype [i ]. DeclType ()  {
2291+ 			case  C . GO_SQLITE3_DECL_DATE :
22202292				var  t  time.Time 
22212293				// Assume a millisecond unix timestamp if it's 13 digits -- too 
22222294				// large to be a reasonable timestamp in seconds. 
@@ -2231,7 +2303,7 @@ func (rc *SQLiteRows) nextSyncLocked(dest []driver.Value) error {
22312303					t  =  t .In (rc .s .c .loc )
22322304				}
22332305				dest [i ] =  t 
2234- 			case  "boolean" :
2306+ 			case  C . GO_SQLITE3_DECL_BOOL :
22352307				dest [i ] =  val  >  0 
22362308			default :
22372309				dest [i ] =  val 
@@ -2255,8 +2327,7 @@ func (rc *SQLiteRows) nextSyncLocked(dest []driver.Value) error {
22552327			n  :=  int (C .sqlite3_column_bytes (rc .s .s , C .int (i )))
22562328			s  :=  C .GoStringN ((* C .char )(unsafe .Pointer (C .sqlite3_column_text (rc .s .s , C .int (i )))), C .int (n ))
22572329
2258- 			switch  rc .decltype [i ] {
2259- 			case  columnTimestamp , columnDatetime , columnDate :
2330+ 			if  rc .coltype [i ].DeclType () ==  C .GO_SQLITE3_DECL_DATE  {
22602331				var  t  time.Time 
22612332				s  =  strings .TrimSuffix (s , "Z" )
22622333				for  _ , format  :=  range  SQLiteTimestampFormats  {
@@ -2273,7 +2344,7 @@ func (rc *SQLiteRows) nextSyncLocked(dest []driver.Value) error {
22732344					t  =  t .In (rc .s .c .loc )
22742345				}
22752346				dest [i ] =  t 
2276- 			default : 
2347+ 			}  else  { 
22772348				dest [i ] =  s 
22782349			}
22792350		}
0 commit comments