Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Linux compilation fixes #1401

Merged
merged 5 commits into from
Jul 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 24 additions & 73 deletions GRDB/Core/Database.swift
Original file line number Diff line number Diff line change
Expand Up @@ -860,31 +860,16 @@ public final class Database: CustomStringConvertible, CustomDebugStringConvertib
self.trace = trace

if options.isEmpty || trace == nil {
#if os(Linux)
sqlite3_trace(sqliteConnection, nil)
#else
sqlite3_trace_v2(sqliteConnection, 0, nil, nil)
#endif
return
}

// sqlite3_trace_v2 and sqlite3_expanded_sql were introduced in SQLite 3.14.0
// http://www.sqlite.org/changes.html#version_3_14
#if os(Linux)
let dbPointer = Unmanaged.passUnretained(self).toOpaque()
sqlite3_trace(sqliteConnection, { (dbPointer, sql) in
guard let sql = sql.map(String.init(cString:)) else { return }
let db = Unmanaged<Database>.fromOpaque(dbPointer!).takeUnretainedValue()
db.trace?(Database.TraceEvent.statement(TraceEvent.Statement(impl: .trace_v1(sql))))
}, dbPointer)
#else
let dbPointer = Unmanaged.passUnretained(self).toOpaque()
sqlite3_trace_v2(sqliteConnection, CUnsignedInt(bitPattern: options.rawValue), { (mask, dbPointer, p, x) in
let db = Unmanaged<Database>.fromOpaque(dbPointer!).takeUnretainedValue()
db.trace_v2(CInt(bitPattern: mask), p, x, sqlite3_expanded_sql)
return SQLITE_OK
}, dbPointer)
#endif
}

// Precondition: configuration.trace != nil
Expand All @@ -900,26 +885,22 @@ public final class Database: CustomStringConvertible, CustomDebugStringConvertib
case SQLITE_TRACE_STMT:
if let sqliteStatement = p, let unexpandedSQL = x {
let statement = TraceEvent.Statement(
impl: .trace_v2(
sqliteStatement: OpaquePointer(sqliteStatement),
unexpandedSQL: UnsafePointer(unexpandedSQL.assumingMemoryBound(to: CChar.self)),
sqlite3_expanded_sql: sqlite3_expanded_sql,
publicStatementArguments: configuration.publicStatementArguments))
sqliteStatement: OpaquePointer(sqliteStatement),
unexpandedSQL: UnsafePointer(unexpandedSQL.assumingMemoryBound(to: CChar.self)),
sqlite3_expanded_sql: sqlite3_expanded_sql,
publicStatementArguments: configuration.publicStatementArguments)
trace(TraceEvent.statement(statement))
}
case SQLITE_TRACE_PROFILE:
if let sqliteStatement = p, let durationP = x?.assumingMemoryBound(to: Int64.self) {
let statement = TraceEvent.Statement(
impl: .trace_v2(
sqliteStatement: OpaquePointer(sqliteStatement),
unexpandedSQL: nil,
sqlite3_expanded_sql: sqlite3_expanded_sql,
publicStatementArguments: configuration.publicStatementArguments))
sqliteStatement: OpaquePointer(sqliteStatement),
unexpandedSQL: nil,
sqlite3_expanded_sql: sqlite3_expanded_sql,
publicStatementArguments: configuration.publicStatementArguments)
let duration = TimeInterval(durationP.pointee) / 1.0e9

#if !os(Linux)
trace(TraceEvent.profile(statement: statement, duration: duration))
#endif
}
default:
break
Expand Down Expand Up @@ -1897,13 +1878,11 @@ extension Database {
/// Trace event code: `SQLITE_TRACE_STMT`.
public static let statement = TracingOptions(rawValue: SQLITE_TRACE_STMT)

#if !os(Linux)
/// The option that reports executed statements and the estimated
/// duration that the statement took to run.
///
/// Trace event code: `SQLITE_TRACE_PROFILE`.
public static let profile = TracingOptions(rawValue: SQLITE_TRACE_PROFILE)
#endif
}

/// A trace event.
Expand All @@ -1914,39 +1893,23 @@ extension Database {

/// Information about an executed statement.
public struct Statement: CustomStringConvertible {
enum Impl {
case trace_v1(String)
case trace_v2(
sqliteStatement: SQLiteStatement,
unexpandedSQL: UnsafePointer<CChar>?,
sqlite3_expanded_sql: @convention(c) (OpaquePointer?) -> UnsafeMutablePointer<Int8>?,
publicStatementArguments: Bool) // See Configuration.publicStatementArguments
}
var impl: Impl
var sqliteStatement: SQLiteStatement
var unexpandedSQL: UnsafePointer<CChar>?
var sqlite3_expanded_sql: @convention(c) (OpaquePointer?) -> UnsafeMutablePointer<Int8>?
var publicStatementArguments: Bool // See Configuration.publicStatementArguments

#if !os(Linux)
/// The executed SQL, where bound parameters are not expanded.
///
/// For example:
///
/// ```sql
/// SELECT * FROM player WHERE email = ?
/// ```
public var sql: String { _sql }
#endif

var _sql: String {
switch impl {
case .trace_v1:
// Likely a GRDB bug: this api is not supposed to be available
fatalError("Unavailable statement SQL")

case let .trace_v2(sqliteStatement, unexpandedSQL, _, _):
if let unexpandedSQL {
return String(cString: unexpandedSQL).trimmedSQLStatement
} else {
return String(cString: sqlite3_sql(sqliteStatement)).trimmedSQLStatement
}
public var sql: String {
if let unexpandedSQL {
return String(cString: unexpandedSQL).trimmedSQLStatement
} else {
return String(cString: sqlite3_sql(sqliteStatement)).trimmedSQLStatement
}
}

Expand All @@ -1962,30 +1925,18 @@ extension Database {
/// information from leaking in unexpected locations, so use this
/// property with care.
public var expandedSQL: String {
switch impl {
case let .trace_v1(expandedSQL):
return expandedSQL

case let .trace_v2(sqliteStatement, _, sqlite3_expanded_sql, _):
guard let cString = sqlite3_expanded_sql(sqliteStatement) else {
return ""
}
defer { sqlite3_free(cString) }
return String(cString: cString).trimmedSQLStatement
guard let cString = sqlite3_expanded_sql(sqliteStatement) else {
return ""
}
defer { sqlite3_free(cString) }
return String(cString: cString).trimmedSQLStatement
}

public var description: String {
switch impl {
case let .trace_v1(expandedSQL):
if publicStatementArguments {
return expandedSQL

case let .trace_v2(_, _, _, publicStatementArguments):
if publicStatementArguments {
return expandedSQL
} else {
return _sql
}
} else {
return sql
}
}
}
Expand Down
40 changes: 19 additions & 21 deletions GRDB/Core/DatabasePool.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ public final class DatabasePool {

@LockedBox var databaseSnapshotCount = 0

/// If Database Suspension is enabled, this array contains the necessary `NotificationCenter` observers.
private var suspensionObservers: [NSObjectProtocol] = []

// MARK: - Database Information

public var configuration: Configuration {
Expand Down Expand Up @@ -121,6 +124,9 @@ public final class DatabasePool {
}

deinit {
// Remove block-based Notification observers.
suspensionObservers.forEach(NotificationCenter.default.removeObserver(_:))

// Undo job done in setupMemoryManagement()
//
// https://developer.apple.com/library/mac/releasenotes/Foundation/RN-Foundation/index.html#10_11Error
Expand Down Expand Up @@ -169,7 +175,7 @@ public final class DatabasePool {
}
}

// @unchecked because of databaseSnapshotCount and readerPool
// @unchecked because of databaseSnapshotCount, readerPool and suspensionObservers
extension DatabasePool: @unchecked Sendable { }

extension DatabasePool {
Expand Down Expand Up @@ -345,29 +351,21 @@ extension DatabasePool: DatabaseReader {
private func setupSuspension() {
if configuration.observesSuspensionNotifications {
let center = NotificationCenter.default
center.addObserver(
self,
selector: #selector(DatabasePool.suspend(_:)),
name: Database.suspendNotification,
object: nil)
center.addObserver(
self,
selector: #selector(DatabasePool.resume(_:)),
name: Database.resumeNotification,
object: nil)
suspensionObservers.append(center.addObserver(
forName: Database.suspendNotification,
object: nil,
queue: nil,
using: { [weak self] _ in self?.suspend() }
))
suspensionObservers.append(center.addObserver(
forName: Database.resumeNotification,
object: nil,
queue: nil,
using: { [weak self] _ in self?.resume() }
))
}
}

@objc
private func suspend(_ notification: Notification) {
suspend()
}

@objc
private func resume(_ notification: Notification) {
resume()
}

// MARK: - Reading from Database

@_disfavoredOverload // SR-15150 Async overloading in protocol implementation fails
Expand Down
41 changes: 21 additions & 20 deletions GRDB/Core/DatabaseQueue.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ import UIKit
public final class DatabaseQueue {
private let writer: SerializedDatabase

/// If Database Suspension is enabled, this array contains the necessary `NotificationCenter` observers.
private var suspensionObservers: [NSObjectProtocol] = []

// MARK: - Configuration

public var configuration: Configuration {
Expand Down Expand Up @@ -100,6 +103,9 @@ public final class DatabaseQueue {
}

deinit {
// Remove block-based Notification observers.
suspensionObservers.forEach(NotificationCenter.default.removeObserver(_:))

// Undo job done in setupMemoryManagement()
//
// https://developer.apple.com/library/mac/releasenotes/Foundation/RN-Foundation/index.html#10_11Error
Expand All @@ -108,6 +114,9 @@ public final class DatabaseQueue {
}
}

// @unchecked because of suspensionObservers
extension DatabaseQueue: @unchecked Sendable { }

extension DatabaseQueue {

// MARK: - Memory management
Expand Down Expand Up @@ -189,29 +198,21 @@ extension DatabaseQueue: DatabaseReader {
private func setupSuspension() {
if configuration.observesSuspensionNotifications {
let center = NotificationCenter.default
center.addObserver(
self,
selector: #selector(DatabaseQueue.suspend(_:)),
name: Database.suspendNotification,
object: nil)
center.addObserver(
self,
selector: #selector(DatabaseQueue.resume(_:)),
name: Database.resumeNotification,
object: nil)
suspensionObservers.append(center.addObserver(
forName: Database.suspendNotification,
object: nil,
queue: nil,
using: { [weak self] _ in self?.suspend() }
))
suspensionObservers.append(center.addObserver(
forName: Database.resumeNotification,
object: nil,
queue: nil,
using: { [weak self] _ in self?.resume() }
))
}
}

@objc
private func suspend(_ notification: Notification) {
suspend()
}

@objc
private func resume(_ notification: Notification) {
resume()
}

// MARK: - Reading from Database

@_disfavoredOverload // SR-15150 Async overloading in protocol implementation fails
Expand Down
2 changes: 1 addition & 1 deletion GRDB/Migration/DatabaseMigrator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -446,7 +446,7 @@ public struct DatabaseMigrator {
//
// So let's create a "regular" temporary database:
let tmpURL = URL(fileURLWithPath: NSTemporaryDirectory())
.appendingPathComponent(ProcessInfo().globallyUniqueString)
.appendingPathComponent(ProcessInfo.processInfo.globallyUniqueString)
defer {
try? FileManager().removeItem(at: tmpURL)
}
Expand Down
4 changes: 4 additions & 0 deletions GRDB/Utils/Utils.swift
Original file line number Diff line number Diff line change
Expand Up @@ -190,3 +190,7 @@ extension NSLocking {
sideEffect?()
}
}

#if !canImport(ObjectiveC)
@inlinable func autoreleasepool<Result>(invoking body: () throws -> Result) rethrows -> Result { try body() }
#endif