@@ -90,10 +90,30 @@ type DB struct {
9090 declTypes map [string ]string
9191}
9292
93+ // cStmt is a wrapper around an sqlite3 *sqlite3_stmt. Except it's stored as
94+ // uintptr to avoid allocations due to poor interactions between cgo's pointer
95+ // checker and Go's escape analysis.
96+ //
97+ // The ptr method returns the value as a pointer, for call sites that haven't
98+ // yet or don't need the optimization. This lets us migrate incrementally.
99+ //
100+ // See http://go/corp/9919.
101+ type cStmt struct {
102+ v C.handle_sqlite3_stmt
103+ }
104+
105+ // cStmtFromPtr returns a cStmt from a C pointer.
106+ func cStmtFromPtr (p * C.sqlite3_stmt ) cStmt {
107+ return cStmt {v : C .handle_sqlite3_stmt (uintptr (unsafe .Pointer (p )))}
108+ }
109+
110+ func (h cStmt ) int () C.handle_sqlite3_stmt { return h .v }
111+ func (h cStmt ) ptr () * C.sqlite3_stmt { return (* C .sqlite3_stmt )(unsafe .Pointer (uintptr (h .v ))) }
112+
93113// Stmt implements sqliteh.Stmt.
94114type Stmt struct {
95115 db * DB
96- stmt * C. sqlite3_stmt
116+ stmt cStmt
97117 start C.struct_timespec
98118
99119 // used as scratch space when calling into cgo
@@ -199,60 +219,60 @@ func (db *DB) Prepare(query string, prepFlags sqliteh.PrepareFlags) (stmt sqlite
199219 return nil , "" , err
200220 }
201221 remainingQuery = query [len (query )- int (C .strlen (csqlTail )):]
202- return & Stmt {db : db , stmt : cstmt }, remainingQuery , nil
222+ return & Stmt {db : db , stmt : cStmtFromPtr ( cstmt ) }, remainingQuery , nil
203223}
204224
205225func (stmt * Stmt ) DBHandle () sqliteh.DB {
206- cdb := C .sqlite3_db_handle (stmt .stmt )
226+ cdb := C .sqlite3_db_handle (stmt .stmt . ptr () )
207227 if cdb != nil {
208228 return & DB {db : cdb }
209229 }
210230 return nil
211231}
212232
213233func (stmt * Stmt ) SQL () string {
214- return C .GoString (C .sqlite3_sql (stmt .stmt ))
234+ return C .GoString (C .sqlite3_sql (stmt .stmt . ptr () ))
215235}
216236
217237func (stmt * Stmt ) ExpandedSQL () string {
218- return C .GoString (C .sqlite3_expanded_sql (stmt .stmt ))
238+ return C .GoString (C .sqlite3_expanded_sql (stmt .stmt . ptr () ))
219239}
220240
221241func (stmt * Stmt ) Reset () error {
222- return errCode (C .sqlite3_reset (stmt .stmt ))
242+ return errCode (C .sqlite3_reset (stmt .stmt . ptr () ))
223243}
224244
225245func (stmt * Stmt ) Finalize () error {
226- return errCode (C .sqlite3_finalize (stmt .stmt ))
246+ return errCode (C .sqlite3_finalize (stmt .stmt . ptr () ))
227247}
228248
229249func (stmt * Stmt ) ClearBindings () error {
230- return errCode (C .sqlite3_clear_bindings (stmt .stmt ))
250+ return errCode (C .sqlite3_clear_bindings (stmt .stmt . ptr () ))
231251}
232252
233253func (stmt * Stmt ) ResetAndClear () (time.Duration , error ) {
234254 if stmt .start != (C.struct_timespec {}) {
235255 stmt .duration = 0
236- err := errCode (C .reset_and_clear (stmt .stmt , & stmt .start , & stmt .duration ))
256+ err := errCode (C .reset_and_clear (stmt .stmt . int () , & stmt .start , & stmt .duration ))
237257 return time .Duration (stmt .duration ), err
238258 }
239- return 0 , errCode (C .reset_and_clear (stmt .stmt , nil , nil ))
259+ return 0 , errCode (C .reset_and_clear (stmt .stmt . int () , nil , nil ))
240260}
241261
242262func (stmt * Stmt ) StartTimer () {
243263 C .monotonic_clock_gettime (& stmt .start )
244264}
245265
246266func (stmt * Stmt ) ColumnDatabaseName (col int ) string {
247- return C .GoString ((* C .char )(unsafe .Pointer (C .sqlite3_column_database_name (stmt .stmt , C .int (col )))))
267+ return C .GoString ((* C .char )(unsafe .Pointer (C .sqlite3_column_database_name (stmt .stmt . ptr () , C .int (col )))))
248268}
249269
250270func (stmt * Stmt ) ColumnTableName (col int ) string {
251- return C .GoString ((* C .char )(unsafe .Pointer (C .sqlite3_column_table_name (stmt .stmt , C .int (col )))))
271+ return C .GoString ((* C .char )(unsafe .Pointer (C .sqlite3_column_table_name (stmt .stmt . ptr () , C .int (col )))))
252272}
253273
254274func (stmt * Stmt ) Step () (row bool , err error ) {
255- res := C .sqlite3_step (stmt .stmt )
275+ res := C .ts_sqlite3_step (stmt .stmt . int () )
256276 switch res {
257277 case C .SQLITE_ROW :
258278 return true , nil
@@ -265,7 +285,7 @@ func (stmt *Stmt) Step() (row bool, err error) {
265285
266286func (stmt * Stmt ) StepResult () (row bool , lastInsertRowID , changes int64 , d time.Duration , err error ) {
267287 stmt .rowid , stmt .changes , stmt .duration = 0 , 0 , 0
268- res := C .step_result (stmt .stmt , & stmt .rowid , & stmt .changes , & stmt .duration )
288+ res := C .step_result (stmt .stmt . int () , & stmt .rowid , & stmt .changes , & stmt .duration )
269289 lastInsertRowID = int64 (stmt .rowid )
270290 changes = int64 (stmt .changes )
271291 d = time .Duration (stmt .duration )
@@ -281,51 +301,51 @@ func (stmt *Stmt) StepResult() (row bool, lastInsertRowID, changes int64, d time
281301}
282302
283303func (stmt * Stmt ) BindDouble (col int , val float64 ) error {
284- return errCode (C .sqlite3_bind_double (stmt .stmt , C .int (col ), C .double (val )))
304+ return errCode (C .sqlite3_bind_double (stmt .stmt . ptr () , C .int (col ), C .double (val )))
285305}
286306
287307func (stmt * Stmt ) BindInt64 (col int , val int64 ) error {
288- return errCode (C .sqlite3_bind_int64 (stmt .stmt , C .int (col ), C .sqlite3_int64 (val )))
308+ return errCode (C .sqlite3_bind_int64 (stmt .stmt . ptr () , C .int (col ), C .sqlite3_int64 (val )))
289309}
290310
291311func (stmt * Stmt ) BindNull (col int ) error {
292- return errCode (C .sqlite3_bind_null (stmt .stmt , C .int (col )))
312+ return errCode (C .sqlite3_bind_null (stmt .stmt . ptr () , C .int (col )))
293313}
294314
295315func (stmt * Stmt ) BindText64 (col int , val string ) error {
296316 if len (val ) == 0 {
297- return errCode (C .bind_text64_empty (stmt .stmt , C .int (col )))
317+ return errCode (C .bind_text64_empty (stmt .stmt . int () , C .int (col )))
298318 }
299319 v := C .CString (val ) // freed by sqlite
300- return errCode (C .bind_text64 (stmt .stmt , C .int (col ), v , C .sqlite3_uint64 (len (val ))))
320+ return errCode (C .bind_text64 (stmt .stmt . int () , C .int (col ), v , C .sqlite3_uint64 (len (val ))))
301321}
302322
303323func (stmt * Stmt ) BindZeroBlob64 (col int , n uint64 ) error {
304- return errCode (C .sqlite3_bind_zeroblob64 (stmt .stmt , C .int (col ), C .sqlite3_uint64 (n )))
324+ return errCode (C .sqlite3_bind_zeroblob64 (stmt .stmt . ptr () , C .int (col ), C .sqlite3_uint64 (n )))
305325}
306326
307327func (stmt * Stmt ) BindBlob64 (col int , val []byte ) error {
308328 var str * C.char
309329 if len (val ) > 0 {
310330 str = (* C .char )(unsafe .Pointer (& val [0 ]))
311331 }
312- return errCode (C .bind_blob64 (stmt .stmt , C .int (col ), str , C .sqlite3_uint64 (len (val ))))
332+ return errCode (C .bind_blob64 (stmt .stmt . int () , C .int (col ), str , C .sqlite3_uint64 (len (val ))))
313333}
314334
315335func (stmt * Stmt ) BindParameterCount () int {
316- return int (C .sqlite3_bind_parameter_count (stmt .stmt ))
336+ return int (C .sqlite3_bind_parameter_count (stmt .stmt . ptr () ))
317337}
318338
319339func (stmt * Stmt ) BindParameterName (col int ) string {
320- cstr := C .sqlite3_bind_parameter_name (stmt .stmt , C .int (col ))
340+ cstr := C .sqlite3_bind_parameter_name (stmt .stmt . ptr () , C .int (col ))
321341 if cstr == nil {
322342 return ""
323343 }
324344 return C .GoString (cstr )
325345}
326346
327347func (stmt * Stmt ) BindParameterIndex (name string ) int {
328- return int (C .bind_parameter_index (stmt .stmt , name ))
348+ return int (C .bind_parameter_index (stmt .stmt . int () , name ))
329349}
330350
331351func (stmt * Stmt ) BindParameterIndexSearch (name string ) int {
@@ -340,51 +360,45 @@ func (stmt *Stmt) BindParameterIndexSearch(name string) int {
340360}
341361
342362func (stmt * Stmt ) ColumnCount () int {
343- return int (C .sqlite3_column_count (stmt .stmt ))
363+ return int (C .sqlite3_column_count (stmt .stmt . ptr () ))
344364}
345365
346366func (stmt * Stmt ) ColumnName (col int ) string {
347- return C .GoString (C .sqlite3_column_name (stmt .stmt , C .int (col )))
367+ return C .GoString (C .sqlite3_column_name (stmt .stmt . ptr () , C .int (col )))
348368}
349369
350370func (stmt * Stmt ) ColumnText (col int ) string {
351- str := (* C .char )(unsafe .Pointer (C .sqlite3_column_text (stmt .stmt , C .int (col ))))
352- n := C .sqlite3_column_bytes (stmt .stmt , C .int (col ))
371+ str := (* C .char )(unsafe .Pointer (C .ts_sqlite3_column_text (stmt .stmt . int () , C .int (col ))))
372+ n := C .ts_sqlite3_column_bytes (stmt .stmt . int () , C .int (col ))
353373 if str == nil || n == 0 {
354374 return ""
355375 }
356376 return C .GoStringN (str , n )
357377}
358378
359379func (stmt * Stmt ) ColumnBlob (col int ) []byte {
360- res := C .sqlite3_column_blob (stmt .stmt , C .int (col ))
380+ res := C .sqlite3_column_blob (stmt .stmt . ptr () , C .int (col ))
361381 if res == nil {
362382 return nil
363383 }
364- n := int (C .sqlite3_column_bytes (stmt .stmt , C .int (col )))
365-
366- slice := struct {
367- data unsafe.Pointer
368- len int
369- cap int
370- }{data : unsafe .Pointer (res ), len : n , cap : n }
371- return * (* []byte )(unsafe .Pointer (& slice ))
384+ n := int (C .ts_sqlite3_column_bytes (stmt .stmt .int (), C .int (col )))
385+ return unsafe .Slice ((* byte )(unsafe .Pointer (res )), n )
372386}
373387
374388func (stmt * Stmt ) ColumnDouble (col int ) float64 {
375- return float64 (C .sqlite3_column_double (stmt .stmt , C .int (col )))
389+ return float64 (C .ts_sqlite3_column_double (stmt .stmt . int () , C .int (col )))
376390}
377391
378392func (stmt * Stmt ) ColumnInt64 (col int ) int64 {
379- return int64 (C .sqlite3_column_int64 (stmt .stmt , C .int (col )))
393+ return int64 (C .ts_sqlite3_column_int64 (stmt .stmt . int () , C .int (col )))
380394}
381395
382396func (stmt * Stmt ) ColumnType (col int ) sqliteh.ColumnType {
383- return sqliteh .ColumnType (C .sqlite3_column_type (stmt .stmt , C .int (col )))
397+ return sqliteh .ColumnType (C .ts_sqlite3_column_type (stmt .stmt . int () , C .int (col )))
384398}
385399
386400func (stmt * Stmt ) ColumnDeclType (col int ) string {
387- cstr := C .sqlite3_column_decltype (stmt .stmt , C .int (col ))
401+ cstr := C .sqlite3_column_decltype (stmt .stmt . ptr () , C .int (col ))
388402 if cstr == nil {
389403 return ""
390404 }
0 commit comments