Skip to content

Commit fead2ea

Browse files
committed
Merge branch 'development'
2 parents 744aa82 + 5b254ee commit fead2ea

File tree

12 files changed

+281
-65
lines changed

12 files changed

+281
-65
lines changed

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ GRDB adheres to [Semantic Versioning](https://semver.org/), with one exception:
77

88
#### 5.x Releases
99

10+
- `5.24.x` Releases - [5.24.0](#5240)
1011
- `5.23.x` Releases - [5.23.0](#5230)
1112
- `5.22.x` Releases - [5.22.0](#5220) | [5.22.1](#5221) | [5.22.2](#5222)
1213
- `5.21.x` Releases - [5.21.0](#5210)
@@ -90,6 +91,15 @@ GRDB adheres to [Semantic Versioning](https://semver.org/), with one exception:
9091

9192
---
9293

94+
## 5.24.0
95+
96+
Released May 1, 2022 • [diff](https://github.com/groue/GRDB.swift/compare/v5.23.0...v5.24.0)
97+
98+
- **Fixed**: [#1203](https://github.com/groue/GRDB.swift/pull/1203) by [@EvanHahn](https://github.com/EvanHahn): Fix changelog links
99+
- **Fixed**: [#1212](https://github.com/groue/GRDB.swift/pull/1212) by [@MartinP7r](https://github.com/MartinP7r): Fix apple docs links
100+
- **Fixed**: [#1213](https://github.com/groue/GRDB.swift/pull/1213) by [@groue](https://github.com/groue): Fix crash when the number of active ValueObservations is high
101+
- **Breaking Change**: Transactions performed during a read-only database access are no longer notified to transaction observers. This is, strictly speaking, a breaking change. However it should have no impact since read-only transactions have very little interest.
102+
93103
## 5.23.0
94104

95105
Released April 16, 2022 • [diff](https://github.com/groue/GRDB.swift/compare/v5.22.2...v5.23.0)

Documentation/FullTextSearch.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ let pattern = FTS3Pattern(matchingAnyTokenIn: "") // nil
304304
let pattern = FTS3Pattern(matchingAnyTokenIn: "*") // nil
305305
```
306306

307-
FTS3Pattern are regular [values](../README.md#values). You can use them as query [arguments](http://groue.github.io/GRDB.swift/docs/5.23/Structs/StatementArguments.html):
307+
FTS3Pattern are regular [values](../README.md#values). You can use them as query [arguments](http://groue.github.io/GRDB.swift/docs/5.24/Structs/StatementArguments.html):
308308

309309
```swift
310310
let documents = try Document.fetchAll(db,
@@ -587,7 +587,7 @@ let pattern = FTS5Pattern(matchingAnyTokenIn: "") // nil
587587
let pattern = FTS5Pattern(matchingAnyTokenIn: "*") // nil
588588
```
589589

590-
FTS5Pattern are regular [values](../README.md#values). You can use them as query [arguments](http://groue.github.io/GRDB.swift/docs/5.23/Structs/StatementArguments.html):
590+
FTS5Pattern are regular [values](../README.md#values). You can use them as query [arguments](http://groue.github.io/GRDB.swift/docs/5.24/Structs/StatementArguments.html):
591591

592592
```swift
593593
let documents = try Document.fetchAll(db,
@@ -737,11 +737,11 @@ The SQLite built-in tokenizers for [FTS3, FTS4](#fts3-and-fts4-tokenizers) and [
737737

738738
Generally speaking, matches may fail when content and query don't use the same [unicode normalization](http://unicode.org/reports/tr15/). SQLite actually exhibits inconsistent behavior in this regard.
739739

740-
For example, for "aimé" to match "aimé", they better have the same normalization: the NFC "aim\u{00E9}" form may not match its NFD "aime\u{0301}" equivalent. Most strings that you get from Swift, UIKit and Cocoa use NFC, so be careful with NFD inputs (such as strings from the HFS+ file system, or strings that you can't trust like network inputs). Use [String.precomposedStringWithCanonicalMapping](https://developer.apple.com/reference/swift/string/1407210-precomposedstringwithcanonicalma) to turn a string into NFC.
740+
For example, for "aimé" to match "aimé", they better have the same normalization: the NFC "aim\u{00E9}" form may not match its NFD "aime\u{0301}" equivalent. Most strings that you get from Swift, UIKit and Cocoa use NFC, so be careful with NFD inputs (such as strings from the HFS+ file system, or strings that you can't trust like network inputs). Use [String.precomposedStringWithCanonicalMapping](https://developer.apple.com/documentation/foundation/nsstring/1412645-precomposedstringwithcanonicalma) to turn a string into NFC.
741741

742-
Besides, if you want "fi" to match the ligature "fi" (U+FB01), then you need to normalize your indexed contents and inputs to NFKC or NFKD. Use [String.precomposedStringWithCompatibilityMapping](https://developer.apple.com/reference/swift/string/1407834-precomposedstringwithcompatibili) to turn a string into NFKC.
742+
Besides, if you want "fi" to match the ligature "fi" (U+FB01), then you need to normalize your indexed contents and inputs to NFKC or NFKD. Use [String.precomposedStringWithCompatibilityMapping](https://developer.apple.com/documentation/foundation/nsstring/1412625-precomposedstringwithcompatibili) to turn a string into NFKC.
743743

744-
Unicode normalization is not the end of the story, because it won't help "Encyclopaedia" match "Encyclopædia", "Mueller", "Müller", "Grossmann", "Großmann", or "Diyarbakır", "DIYARBAKIR". The [String.applyingTransform](https://developer.apple.com/reference/swift/string/1643133-applyingtransform) method can help.
744+
Unicode normalization is not the end of the story, because it won't help "Encyclopaedia" match "Encyclopædia", "Mueller", "Müller", "Grossmann", "Großmann", or "Diyarbakır", "DIYARBAKIR". The [String.applyingTransform](https://developer.apple.com/documentation/foundation/nsstring/1407787-applyingtransform) method can help.
745745

746746
GRDB lets you write [custom FTS5 tokenizers](FTS5Tokenizers.md) that can transparently deal with all these issues. For FTS3 and FTS4, you'll need to pre-process your strings before injecting them in the full-text engine.
747747

Documentation/Migrations.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ try dbQueue.read { db in
7777
}
7878
```
7979

80-
See the [DatabaseMigrator reference](http://groue.github.io/GRDB.swift/docs/5.23/Structs/DatabaseMigrator.html) for more migrator methods.
80+
See the [DatabaseMigrator reference](http://groue.github.io/GRDB.swift/docs/5.24/Structs/DatabaseMigrator.html) for more migrator methods.
8181

8282

8383
## The `eraseDatabaseOnSchemaChange` Option

GRDB.swift.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Pod::Spec.new do |s|
22
s.name = 'GRDB.swift'
3-
s.version = '5.23.0'
3+
s.version = '5.24.0'
44

55
s.license = { :type => 'MIT', :file => 'LICENSE' }
66
s.summary = 'A toolkit for SQLite databases, with a focus on application development.'

GRDB/Core/Database.swift

Lines changed: 44 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,9 @@ public final class Database: CustomStringConvertible, CustomDebugStringConvertib
233233
setupDefaultFunctions()
234234
setupDefaultCollations()
235235
setupAuthorizer()
236-
observationBroker.installCommitAndRollbackHooks()
236+
if !configuration.readonly {
237+
observationBroker.installCommitAndRollbackHooks()
238+
}
237239
try activateExtendedCodes()
238240

239241
#if SQLITE_HAS_CODEC
@@ -546,6 +548,11 @@ public final class Database: CustomStringConvertible, CustomDebugStringConvertib
546548
finally: endReadOnly)
547549
}
548550

551+
/// Returns whether database connection is read-only.
552+
var isReadOnly: Bool {
553+
_readOnlyDepth > 0 || configuration.readonly
554+
}
555+
549556
// MARK: - Snapshots
550557

551558
#if SQLITE_ENABLE_SNAPSHOT
@@ -939,10 +946,16 @@ public final class Database: CustomStringConvertible, CustomDebugStringConvertib
939946
/// This method is not reentrant: you can't nest transactions.
940947
///
941948
/// - parameters:
942-
/// - kind: The transaction type (default nil). If nil, the transaction
943-
/// type is configuration.defaultTransactionKind, which itself
944-
/// defaults to .deferred. See <https://www.sqlite.org/lang_transaction.html>
945-
/// for more information.
949+
/// - kind: The transaction type (default nil).
950+
///
951+
/// If nil, and the database connection is read-only, the transaction
952+
/// kind is `.deferred`.
953+
///
954+
/// If nil, and the database connection is not read-only, the
955+
/// transaction kind is `configuration.defaultTransactionKind`.
956+
///
957+
/// See <https://www.sqlite.org/lang_transaction.html> for
958+
/// more information.
946959
/// - block: A block that executes SQL statements and return either
947960
/// .commit or .rollback.
948961
/// - throws: The error thrown by the block.
@@ -1005,13 +1018,20 @@ public final class Database: CustomStringConvertible, CustomDebugStringConvertib
10051018
/// - parameter readOnly: If true, writes are forbidden.
10061019
func isolated<T>(readOnly: Bool = false, _ block: () throws -> T) throws -> T {
10071020
var result: T?
1008-
try inSavepoint {
1009-
if readOnly {
1010-
result = try self.readOnly(block)
1011-
} else {
1021+
if readOnly {
1022+
// Enter read-only mode before starting a transaction, so that the
1023+
// transaction commit does not trigger database observation.
1024+
try self.readOnly {
1025+
try inSavepoint {
1026+
result = try block()
1027+
return .commit
1028+
}
1029+
}
1030+
} else {
1031+
try inSavepoint {
10121032
result = try block()
1033+
return .commit
10131034
}
1014-
return .commit
10151035
}
10161036
return result!
10171037
}
@@ -1055,7 +1075,7 @@ public final class Database: CustomStringConvertible, CustomDebugStringConvertib
10551075
//
10561076
// For those two reasons, we open a transaction instead of a
10571077
// top-level savepoint.
1058-
try inTransaction(configuration.defaultTransactionKind, block)
1078+
try inTransaction { try block() }
10591079
return
10601080
}
10611081

@@ -1123,13 +1143,20 @@ public final class Database: CustomStringConvertible, CustomDebugStringConvertib
11231143

11241144
/// Begins a database transaction.
11251145
///
1126-
/// - parameter kind: The transaction type (default nil). If nil, the
1127-
/// transaction type is configuration.defaultTransactionKind, which itself
1128-
/// defaults to .deferred. See <https://www.sqlite.org/lang_transaction.html>
1129-
/// for more information.
1130-
/// - throws: The error thrown by the block.
1146+
/// - parameter kind: The transaction type (default nil).
1147+
///
1148+
/// If nil, and the database connection is read-only, the transaction kind
1149+
/// is `.deferred`.
1150+
///
1151+
/// If nil, and the database connection is not read-only, the transaction
1152+
/// kind is `configuration.defaultTransactionKind`.
1153+
///
1154+
/// See <https://www.sqlite.org/lang_transaction.html> for
1155+
/// more information.
1156+
/// - throws: A DatabaseError whenever an SQLite error occurs.
11311157
public func beginTransaction(_ kind: TransactionKind? = nil) throws {
1132-
let kind = kind ?? configuration.defaultTransactionKind
1158+
// SQLite throws an error for non-deferred transactions when read-only.
1159+
let kind = kind ?? (isReadOnly ? .deferred : configuration.defaultTransactionKind)
11331160
try execute(sql: "BEGIN \(kind.rawValue) TRANSACTION")
11341161
assert(sqlite3_get_autocommit(sqliteConnection) == 0)
11351162
}

GRDB/Core/TransactionObserver.swift

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -220,8 +220,7 @@ class DatabaseObservationBroker {
220220

221221
/// Prepares observation of changes that are about to be performed by the statement.
222222
func statementWillExecute(_ statement: Statement) {
223-
// If any observer observes row deletions, we'll have to disable
224-
if transactionObservations.isEmpty == false {
223+
if !database.isReadOnly && !transactionObservations.isEmpty {
225224
// As statement executes, it may trigger database changes that will
226225
// be notified to transaction observers. As a consequence, observers
227226
// may disable themselves with stopObservingDatabaseChangesUntilNextTransaction()
@@ -310,7 +309,7 @@ class DatabaseObservationBroker {
310309
// SQLITE_CONSTRAINT error)
311310
databaseDidRollback(notifyTransactionObservers: false)
312311
case .cancelledCommit(let error):
313-
databaseDidRollback(notifyTransactionObservers: true)
312+
databaseDidRollback(notifyTransactionObservers: !database.isReadOnly)
314313
throw error
315314
default:
316315
break
@@ -382,7 +381,7 @@ class DatabaseObservationBroker {
382381
case .commit:
383382
databaseDidCommit()
384383
case .rollback:
385-
databaseDidRollback(notifyTransactionObservers: true)
384+
databaseDidRollback(notifyTransactionObservers: !database.isReadOnly)
386385
default:
387386
break
388387
}
@@ -391,6 +390,8 @@ class DatabaseObservationBroker {
391390
#if SQLITE_ENABLE_PREUPDATE_HOOK
392391
// Called from sqlite3_preupdate_hook
393392
private func databaseWillChange(with event: DatabasePreUpdateEvent) {
393+
assert(!database.isReadOnly, "Read-only transactions are not notified")
394+
394395
if savepointStack.isEmpty {
395396
// Notify now
396397
for (observation, predicate) in statementObservations where predicate.evaluate(event) {
@@ -405,6 +406,8 @@ class DatabaseObservationBroker {
405406

406407
// Called from sqlite3_update_hook
407408
private func databaseDidChange(with event: DatabaseEvent) {
409+
assert(!database.isReadOnly, "Read-only transactions are not notified")
410+
408411
// We're about to call the databaseDidChange(with:) method of
409412
// transaction observers. In this method, observers may disable
410413
// themselves with stopObservingDatabaseChangesUntilNextTransaction()
@@ -430,18 +433,23 @@ class DatabaseObservationBroker {
430433
// Called from sqlite3_commit_hook and databaseDidCommitEmptyDeferredTransaction()
431434
private func databaseWillCommit() throws {
432435
notifyBufferedEvents()
433-
for observation in transactionObservations {
434-
try observation.databaseWillCommit()
436+
if !database.isReadOnly {
437+
for observation in transactionObservations {
438+
try observation.databaseWillCommit()
439+
}
435440
}
436441
}
437442

438443
// Called from statementDidExecute
439444
private func databaseDidCommit() {
440445
savepointStack.clear()
441446

442-
for observation in transactionObservations {
443-
observation.databaseDidCommit(database)
447+
if !database.isReadOnly {
448+
for observation in transactionObservations {
449+
observation.databaseDidCommit(database)
450+
}
444451
}
452+
445453
databaseDidEndTransaction()
446454
}
447455

@@ -485,7 +493,7 @@ class DatabaseObservationBroker {
485493
try databaseWillCommit()
486494
databaseDidCommit()
487495
} catch {
488-
databaseDidRollback(notifyTransactionObservers: true)
496+
databaseDidRollback(notifyTransactionObservers: !database.isReadOnly)
489497
throw error
490498
}
491499
}
@@ -495,6 +503,7 @@ class DatabaseObservationBroker {
495503
savepointStack.clear()
496504

497505
if notifyTransactionObservers {
506+
assert(!database.isReadOnly, "Read-only transactions are not notified")
498507
for observation in transactionObservations {
499508
observation.databaseDidRollback(database)
500509
}
@@ -566,6 +575,7 @@ class DatabaseObservationBroker {
566575
savepointStack.clear()
567576

568577
for (event, statementObservations) in eventsBuffer {
578+
assert(statementObservations.isEmpty || !database.isReadOnly, "Read-only transactions are not notified")
569579
for (observation, predicate) in statementObservations where predicate.evaluate(event) {
570580
event.send(to: observation)
571581
}

Makefile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -538,10 +538,10 @@ ifdef JAZZY
538538
--author 'Gwendal Roué' \
539539
--author_url https://github.com/groue \
540540
--github_url https://github.com/groue/GRDB.swift \
541-
--github-file-prefix https://github.com/groue/GRDB.swift/tree/v5.23.0 \
542-
--module-version 5.23.0 \
541+
--github-file-prefix https://github.com/groue/GRDB.swift/tree/v5.24.0 \
542+
--module-version 5.24.0 \
543543
--module GRDB \
544-
--root-url http://groue.github.io/GRDB.swift/docs/5.23/ \
544+
--root-url http://groue.github.io/GRDB.swift/docs/5.24/ \
545545
--output Documentation/Reference \
546546
--xcodebuild-arguments -project,GRDB.xcodeproj,-scheme,GRDBiOS
547547
else

0 commit comments

Comments
 (0)