Skip to content

Commit f0cfde6

Browse files
committed
Update outdated documentation
1 parent 096a3b2 commit f0cfde6

File tree

3 files changed

+33
-27
lines changed

3 files changed

+33
-27
lines changed

GRDB/Core/Cursor.swift

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,9 @@ extension RangeReplaceableCollection {
2121
/// - parameter cursor: The cursor whose elements feed the collection.
2222
public init<C: Cursor>(_ cursor: C) throws where C.Element == Element {
2323
self.init()
24-
// Use `forEach` in order to deal with <https://github.com/groue/GRDB.swift/issues/1124>.
25-
// See `Statement.forEachStep(_:)` for more information.
24+
// Prefer `forEach` over `next()` looping, as a slight performance
25+
// improvement due to the single `sqlite3_stmt_busy` check for
26+
// database cursors.
2627
try cursor.forEach { append($0) }
2728
}
2829

@@ -38,6 +39,9 @@ extension RangeReplaceableCollection {
3839
public init<C: Cursor>(_ cursor: C, minimumCapacity: Int) throws where C.Element == Element {
3940
self.init()
4041
reserveCapacity(minimumCapacity)
42+
// Prefer `forEach` over `next()` looping, as a slight performance
43+
// improvement due to the single `sqlite3_stmt_busy` check for
44+
// database cursors.
4145
try cursor.forEach { append($0) }
4246
}
4347
}
@@ -58,6 +62,9 @@ extension Dictionary {
5862
throws where Value == [C.Element]
5963
{
6064
self.init()
65+
// Prefer `forEach` over `next()` looping, as a slight performance
66+
// improvement due to the single `sqlite3_stmt_busy` check for
67+
// database cursors.
6168
try cursor.forEach { value in
6269
try self[keyForValue(value), default: []].append(value)
6370
}
@@ -84,6 +91,9 @@ extension Dictionary {
8491
throws where Value == [C.Element]
8592
{
8693
self.init(minimumCapacity: minimumCapacity)
94+
// Prefer `forEach` over `next()` looping, as a slight performance
95+
// improvement due to the single `sqlite3_stmt_busy` check for
96+
// database cursors.
8797
try cursor.forEach { value in
8898
try self[keyForValue(value), default: []].append(value)
8999
}
@@ -106,6 +116,9 @@ extension Dictionary {
106116
throws where C.Element == (Key, Value)
107117
{
108118
self.init()
119+
// Prefer `forEach` over `next()` looping, as a slight performance
120+
// improvement due to the single `sqlite3_stmt_busy` check for
121+
// database cursors.
109122
try keysAndValues.forEach { key, value in
110123
if updateValue(value, forKey: key) != nil {
111124
fatalError("Duplicate values for key: '\(String(describing: key))'")
@@ -135,6 +148,9 @@ extension Dictionary {
135148
throws where C.Element == (Key, Value)
136149
{
137150
self.init(minimumCapacity: minimumCapacity)
151+
// Prefer `forEach` over `next()` looping, as a slight performance
152+
// improvement due to the single `sqlite3_stmt_busy` check for
153+
// database cursors.
138154
try keysAndValues.forEach { key, value in
139155
if updateValue(value, forKey: key) != nil {
140156
fatalError("Duplicate values for key: '\(String(describing: key))'")
@@ -153,6 +169,9 @@ extension Set {
153169
/// - parameter cursor: A cursor of values to gather into a set.
154170
public init<C: Cursor>(_ cursor: C) throws where C.Element == Element {
155171
self.init()
172+
// Prefer `forEach` over `next()` looping, as a slight performance
173+
// improvement due to the single `sqlite3_stmt_busy` check for
174+
// database cursors.
156175
try cursor.forEach { insert($0) }
157176
}
158177

@@ -168,6 +187,9 @@ extension Set {
168187
/// storage buffer.
169188
public init<C: Cursor>(_ cursor: C, minimumCapacity: Int) throws where C.Element == Element {
170189
self.init(minimumCapacity: minimumCapacity)
190+
// Prefer `forEach` over `next()` looping, as a slight performance
191+
// improvement due to the single `sqlite3_stmt_busy` check for
192+
// database cursors.
171193
try cursor.forEach { insert($0) }
172194
}
173195
}

GRDB/Core/Statement.swift

Lines changed: 9 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -316,24 +316,15 @@ public final class Statement {
316316

317317
/// Calls the given closure after each successful call to `sqlite3_step()`.
318318
///
319-
/// Unlike multiple calls to `step(_:)`, this method is able to deal with
320-
/// statements that need a specific authorizer.
321-
///
322-
/// That's how we deal with TransactionObservers that observe deletion:
323-
/// the authorizer prevents the truncate optimization
324-
/// <https://www.sqlite.org/lang_delete.html#the_truncate_optimization>.
325-
///
326-
/// That's also how we deal with <https://github.com/groue/GRDB.swift/issues/1124>,
327-
/// in four steps:
328-
///
329-
/// 1. `T.fetchAll(...)` calls `Array(T.fetchCursor(...))`
330-
/// 2. `Array(T.fetchCursor(...))` calls `Cursor.forEach(...)`
331-
/// 3. `DatabaseCursor.forEach(...)` calls `Statement.forEachStep(...)`
332-
/// 4. `Statement.forEachStep(...)` deals with the eventual authorizer.
319+
/// This method is slighly faster than calling `step(_:)` repeatedly, due
320+
/// to the single `sqlite3_stmt_busy` check.
333321
@usableFromInline
334322
func forEachStep(_ body: (SQLiteStatement) throws -> Void) throws {
335323
SchedulingWatchdog.preconditionValidQueue(database)
336-
try database.statementWillExecute(self)
324+
325+
if sqlite3_stmt_busy(sqliteStatement) == 0 {
326+
try database.statementWillExecute(self)
327+
}
337328

338329
while true {
339330
switch sqlite3_step(sqliteStatement) {
@@ -349,12 +340,8 @@ public final class Statement {
349340
}
350341

351342
/// Calls the given closure after one successful call to `sqlite3_step()`.
352-
///
353-
/// This method is unable to deal with statements that need a specific
354-
/// authorizer. See `forEachStep(_:)`.
355343
@usableFromInline
356-
func step<Element>(_ body: (SQLiteStatement) throws -> Element) throws -> Element? {
357-
// This check takes 0 time when profiled. It is, practically speaking, free.
344+
func step<T>(_ body: (SQLiteStatement) throws -> T) throws -> T? {
358345
if sqlite3_stmt_busy(sqliteStatement) == 0 {
359346
try database.statementWillExecute(self)
360347
}
@@ -439,9 +426,8 @@ extension DatabaseCursor {
439426
return nil
440427
}
441428

442-
// Specific implementation of `forEach` in order to deal with
443-
// <https://github.com/groue/GRDB.swift/issues/1124>.
444-
// See `Statement.forEachStep(_:)` for more information.
429+
/// Specific implementation of `forEach`, for a slight performance
430+
/// improvement due to the single `sqlite3_stmt_busy` check.
445431
@inlinable
446432
public func forEach(_ body: (Element) throws -> Void) throws {
447433
if _isDone { return }

GRDB/Record/FetchableRecord.swift

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -196,8 +196,6 @@ extension FetchableRecord {
196196
adapter: RowAdapter? = nil)
197197
throws -> [Self]
198198
{
199-
// Use Array initializer in order to deal with <https://github.com/groue/GRDB.swift/issues/1124>.
200-
// See `Statement.forEachStep(_:)` for more information.
201199
try Array(fetchCursor(statement, arguments: arguments, adapter: adapter))
202200
}
203201

0 commit comments

Comments
 (0)