@@ -412,23 +412,67 @@ public final class Connection {
412412 ///
413413 /// db.trace { SQL in print(SQL) }
414414 public func trace( _ callback: ( ( String ) -> Void ) ? ) {
415+ if #available( iOS 10 . 0 , OSX 10 . 12 , tvOS 10 . 0 , watchOS 3 . 0 , * ) {
416+ trace_v2 ( callback)
417+ } else {
418+ trace_v1 ( callback)
419+ }
420+ }
421+
422+ fileprivate func trace_v1( _ callback: ( ( String ) -> Void ) ? ) {
415423 guard let callback = callback else {
416- sqlite3_trace ( handle, nil , nil )
424+ sqlite3_trace ( handle, nil /* xCallback */ , nil /* pCtx */ )
417425 trace = nil
418426 return
419427 }
420-
421- let box : Trace = { callback ( String ( cString: $0) ) }
422- sqlite3_trace ( handle, {
423- ( callback: UnsafeMutableRawPointer ? , SQL: UnsafePointer < Int8 > ? ) in
424- guard let callback = callback, let SQL = SQL else { return }
425- unsafeBitCast ( callback, to: Trace . self) ( SQL)
428+ let box : Trace = { ( pointer: UnsafeRawPointer ) in
429+ callback ( String ( cString: pointer. assumingMemoryBound ( to: UInt8 . self) ) )
430+ }
431+ sqlite3_trace ( handle,
432+ {
433+ ( C: UnsafeMutableRawPointer ? , SQL: UnsafePointer < Int8 > ? ) in
434+ if let C = C, let SQL = SQL {
435+ unsafeBitCast ( C, to: Trace . self) ( SQL)
436+ }
426437 } ,
427438 unsafeBitCast ( box, to: UnsafeMutableRawPointer . self)
428439 )
429440 trace = box
430441 }
431- fileprivate typealias Trace = @convention ( block) ( UnsafePointer < Int8 > ) -> Void
442+
443+ @available ( iOS 10 . 0 , OSX 10 . 12 , tvOS 10 . 0 , watchOS 3 . 0 , * )
444+ fileprivate func trace_v2( _ callback: ( ( String ) -> Void ) ? ) {
445+ guard let callback = callback else {
446+ // If the X callback is NULL or if the M mask is zero, then tracing is disabled.
447+ sqlite3_trace_v2 ( handle, 0 /* mask */, nil /* xCallback */, nil /* pCtx */)
448+ trace = nil
449+ return
450+ }
451+
452+ let box : Trace = { ( pointer: UnsafeRawPointer ) in
453+ callback ( String ( cString: pointer. assumingMemoryBound ( to: UInt8 . self) ) )
454+ }
455+ sqlite3_trace_v2 ( handle,
456+ UInt32 ( SQLITE_TRACE_STMT) /* mask */,
457+ {
458+ // A trace callback is invoked with four arguments: callback(T,C,P,X).
459+ // The T argument is one of the SQLITE_TRACE constants to indicate why the
460+ // callback was invoked. The C argument is a copy of the context pointer.
461+ // The P and X arguments are pointers whose meanings depend on T.
462+ ( T: UInt32 , C: UnsafeMutableRawPointer ? , P: UnsafeMutableRawPointer ? , X: UnsafeMutableRawPointer ? ) in
463+ if let P = P,
464+ let expandedSQL = sqlite3_expanded_sql ( OpaquePointer ( P) ) {
465+ unsafeBitCast ( C, to: Trace . self) ( expandedSQL)
466+ sqlite3_free ( expandedSQL)
467+ }
468+ return Int32 ( 0 ) // currently ignored
469+ } ,
470+ unsafeBitCast ( box, to: UnsafeMutableRawPointer . self) /* pCtx */
471+ )
472+ trace = box
473+ }
474+
475+ fileprivate typealias Trace = @convention ( block) ( UnsafeRawPointer ) -> Void
432476 fileprivate var trace : Trace ?
433477
434478 /// Registers a callback to be invoked whenever a row is inserted, updated,
0 commit comments