Configuration

public struct Configuration

Configuration for a DatabaseQueue or DatabasePool.

Misc options

  • If true (the default), support for foreign keys is enabled. See https://www.sqlite.org/foreignkeys.html for more information.

    Default: true

    Declaration

    Swift

    public var foreignKeysEnabled: Bool
  • If true, database modifications are disallowed.

    Default: false

    Declaration

    Swift

    public var readonly: Bool
  • The configuration label.

    You can query this label at runtime:

    var configuration = Configuration()
    configuration.label = "MyDatabase"
    let dbQueue = try DatabaseQueue(path: ..., configuration: configuration)
    
    try dbQueue.read { db in
        print(db.configuration.label) // Prints "MyDatabase"
    }
    

    The configuration label is also used to name Database connections (the Database.description property), and the various dispatch queues created by GRDB, visible in debugging sessions and crash logs.

    Those connection names and dispatch queue labels are intended for debugging only. Their format may change between GRDB releases. Applications should not depend on connection names and dispatch queue labels.

    If the configuration label is nil, the current GRDB implementation uses the following names:

    • GRDB.DatabaseQueue: the (unique) connection of a DatabaseQueue
    • GRDB.DatabasePool.writer: the (unique) writer connection of a DatabasePool
    • GRDB.DatabasePool.reader.N, where N is 1, 2, …: one of the reader connection(s) of a DatabasePool. N may get bigger than the maximum number of concurrent readers, as SQLite connections get closed and new ones are opened.
    • GRDB.DatabasePool.snapshot.N: the connection of a DatabaseSnapshot. N grows with the number of snapshots.

    If the configuration label is not nil, for example “MyDatabase”, the current GRDB implementation uses the following names:

    • MyDatabase: the (unique) connection of a DatabaseQueue
    • MyDatabase.writer: the (unique) writer connection of a DatabasePool
    • MyDatabase.reader.N, where N is 1, 2, …: one of the reader connection(s) of a DatabasePool. N may get bigger than the maximum number of concurrent readers, as SQLite connections get closed and new ones are opened.
    • MyDatabase.snapshot.N: the connection of a DatabaseSnapshot. N grows with the number of snapshots.

    The default configuration label is nil.

    Declaration

    Swift

    public var label: String?
  • If false, SQLite from version 3.29.0 will not interpret a double-quoted string as a string literal if it does not match any valid identifier.

    For example:

    // Error: no such column: foo
    let name = try String.fetchOne(db, sql: """
        SELECT "foo" FROM "player"
        """)
    

    When true, or before version 3.29.0, such strings are interpreted as string literals, as in the example below. This is a well known SQLite misfeature.

    // Success: "foo"
    let name = try String.fetchOne(db, sql: """
        SELECT "foo" FROM "player"
        """)
    
    • Default value: false

    Declaration

    Swift

    public var acceptsDoubleQuotedStringLiterals: Bool
  • When true, the Database.suspendNotification and Database.resumeNotification suspend and resume the database. Database suspension helps avoiding the 0xdead10cc exception.

    During suspension, all database accesses but reads in WAL mode may throw a DatabaseError of code SQLITE_INTERRUPT, or SQLITE_ABORT. You can check for those error codes with the DatabaseError.isInterruptionError property.

    Experimental

    Declaration

    Swift

    public var observesSuspensionNotifications: Bool
  • If false (the default), statement arguments are not visible in the description of database errors and trace events, preventing sensitive information from leaking in unexpected places.

    For example:

    // Error: sensitive information is not printed when an error occurs:
    do {
        let email = "..." // sensitive information
        let player = try Player.filter(Column("email") == email).fetchOne(db)
    } catch {
        print(error)
    }
    
    // Trace: sensitive information is not printed when a statement is traced:
    db.trace { event in
        print(event)
    }
    let email = "..." // sensitive information
    let player = try Player.filter(Column("email") == email).fetchOne(db)
    

    For debugging purpose, you can set this flag to true, and get more precise database reports. It is your responsibility to prevent sensitive information from leaking in unexpected locations, so you should not set this flag in release builds (think about GDPR and other privacy-related rules):

    var config = Configuration()
    #if DEBUG
    // Protect sensitive information by enabling verbose debugging in DEBUG builds only
    config.publicStatementArguments = true
    #endif
    
    // The descriptions of trace events and errors now contain the
    // sensitive information:
    db.trace { event in
        print(event)
    }
    do {
        let email = "..."
        let player = try Player.filter(Column("email") == email).fetchOne(db)
    } catch {
        print(error)
    }
    

    Declaration

    Swift

    public var publicStatementArguments: Bool

Managing SQLite Connections

  • The function argument is run when an SQLite connection is opened, before the connection is made available for database access methods.

    This method can be called several times. The preparation functions are run in the same order.

    For example:

    var config = Configuration()
    config.prepareDatabase { db in
        try db.execute(sql: "PRAGMA kdf_iter = 10000")
    }
    

    When you use a DatabasePool, preparation functions are called for the writer connection and all reader connections. You can distinguish them by querying db.configuration.readonly:

    var config = Configuration()
    config.prepareDatabase { db in
        if db.configuration.readonly {
            // reader connection
        } else {
            // writer connection
        }
    }
    

    On newly created databases, DatabasePool the WAL mode is activated after the preparation functions have run.

    Declaration

    Swift

    public mutating func prepareDatabase(_ setup: @escaping (Database) throws -> Void)

Transactions

  • The default kind of transaction.

    Default: deferred

    Declaration

    Swift

    public var defaultTransactionKind: Database.TransactionKind
  • If false, it is a programmer error to leave a transaction opened at the end of a database access block.

    For example:

    let dbQueue = DatabaseQueue()
    
    // fatal error: A transaction has been left opened at the end of a database access
    try dbQueue.inDatabase { db in
        try db.beginTransaction()
    }
    

    If true, one can leave opened transaction at the end of database access blocks:

    var config = Configuration()
    config.allowsUnsafeTransactions = true
    let dbQueue = DatabaseQueue(configuration: config)
    
    try dbQueue.inDatabase { db in
        try db.beginTransaction()
    }
    
    try dbQueue.inDatabase { db in
        try db.commit()
    }
    

    This configuration flag has no effect on DatabasePool readers: those never allow leaving a transaction opened at the end of a read access.

    Default: false

    Declaration

    Swift

    public var allowsUnsafeTransactions: Bool

Concurrency

  • The behavior in case of SQLITE_BUSY error. See https://www.sqlite.org/rescode.html#busy

    Default: immediateError

    Declaration

    Swift

    public var busyMode: Database.BusyMode
  • The maximum number of concurrent readers (applies to database pools only).

    Default: 5

    Declaration

    Swift

    public var maximumReaderCount: Int
  • qos

    The quality of service class for the work performed by the database.

    The quality of service is ignored if you supply a target queue.

    Default: .userInitiated

    Declaration

    Swift

    public var qos: DispatchQoS
  • A target queue for database accesses.

    Database connections which are not read-only will prefer writeTargetQueue instead, if it is not nil.

    When you use a database pool, make sure this queue is concurrent. This is because in a serial dispatch queue, no concurrent database access can happen, and you may experience deadlocks.

    If the queue is nil, all database accesses happen in unspecified dispatch queues whose quality of service is determined by the qos property.

    Default: nil

    Declaration

    Swift

    public var targetQueue: DispatchQueue?
  • The target queue for database connections which are not read-only.

    If this queue is nil, writer connections are controlled by targetQueue.

    Default: nil

    Declaration

    Swift

    public var writeTargetQueue: DispatchQueue?

Factory Configuration