@@ -3,7 +3,7 @@ import Logging
3
3
4
4
struct QueryResult {
5
5
enum Value : Equatable {
6
- case noRows( String )
6
+ case noRows( PSQLRowStream . StatementSummary )
7
7
case rowDescription( [ RowDescription . Column ] )
8
8
}
9
9
@@ -16,25 +16,30 @@ struct QueryResult {
16
16
final class PSQLRowStream : @unchecked Sendable {
17
17
private typealias AsyncSequenceSource = NIOThrowingAsyncSequenceProducer < DataRow , Error , AdaptiveRowBuffer , PSQLRowStream > . Source
18
18
19
+ enum StatementSummary : Equatable {
20
+ case tag( String )
21
+ case emptyResponse
22
+ }
23
+
19
24
enum Source {
20
25
case stream( [ RowDescription . Column ] , PSQLRowsDataSource )
21
- case noRows( Result < String , Error > )
26
+ case noRows( Result < StatementSummary , Error > )
22
27
}
23
28
24
29
let eventLoop : EventLoop
25
30
let logger : Logger
26
-
31
+
27
32
private enum BufferState {
28
33
case streaming( buffer: CircularBuffer < DataRow > , dataSource: PSQLRowsDataSource )
29
- case finished( buffer: CircularBuffer < DataRow > , commandTag : String )
34
+ case finished( buffer: CircularBuffer < DataRow > , summary : StatementSummary )
30
35
case failure( Error )
31
36
}
32
-
37
+
33
38
private enum DownstreamState {
34
39
case waitingForConsumer( BufferState )
35
40
case iteratingRows( onRow: ( PostgresRow ) throws -> ( ) , EventLoopPromise < Void > , PSQLRowsDataSource )
36
41
case waitingForAll( [ PostgresRow ] , EventLoopPromise < [ PostgresRow ] > , PSQLRowsDataSource )
37
- case consumed( Result < String , Error > )
42
+ case consumed( Result < StatementSummary , Error > )
38
43
case asyncSequence( AsyncSequenceSource , PSQLRowsDataSource , onFinish: @Sendable ( ) -> ( ) )
39
44
}
40
45
@@ -52,9 +57,9 @@ final class PSQLRowStream: @unchecked Sendable {
52
57
case . stream( let rowDescription, let dataSource) :
53
58
self . rowDescription = rowDescription
54
59
bufferState = . streaming( buffer: . init( ) , dataSource: dataSource)
55
- case . noRows( . success( let commandTag ) ) :
60
+ case . noRows( . success( let summary ) ) :
56
61
self . rowDescription = [ ]
57
- bufferState = . finished( buffer: . init( ) , commandTag : commandTag )
62
+ bufferState = . finished( buffer: . init( ) , summary : summary )
58
63
case . noRows( . failure( let error) ) :
59
64
self . rowDescription = [ ]
60
65
bufferState = . failure( error)
@@ -98,12 +103,12 @@ final class PSQLRowStream: @unchecked Sendable {
98
103
self . downstreamState = . asyncSequence( source, dataSource, onFinish: onFinish)
99
104
self . executeActionBasedOnYieldResult ( yieldResult, source: dataSource)
100
105
101
- case . finished( let buffer, let commandTag ) :
106
+ case . finished( let buffer, let summary ) :
102
107
_ = source. yield ( contentsOf: buffer)
103
108
source. finish ( )
104
109
onFinish ( )
105
- self . downstreamState = . consumed( . success( commandTag ) )
106
-
110
+ self . downstreamState = . consumed( . success( summary ) )
111
+
107
112
case . failure( let error) :
108
113
source. finish ( error)
109
114
self . downstreamState = . consumed( . failure( error) )
@@ -190,12 +195,12 @@ final class PSQLRowStream: @unchecked Sendable {
190
195
dataSource. request ( for: self )
191
196
return promise. futureResult
192
197
193
- case . finished( let buffer, let commandTag ) :
198
+ case . finished( let buffer, let summary ) :
194
199
let rows = buffer. map {
195
200
PostgresRow ( data: $0, lookupTable: self . lookupTable, columns: self . rowDescription)
196
201
}
197
202
198
- self . downstreamState = . consumed( . success( commandTag ) )
203
+ self . downstreamState = . consumed( . success( summary ) )
199
204
return self . eventLoop. makeSucceededFuture ( rows)
200
205
201
206
case . failure( let error) :
@@ -247,8 +252,8 @@ final class PSQLRowStream: @unchecked Sendable {
247
252
}
248
253
249
254
return promise. futureResult
250
-
251
- case . finished( let buffer, let commandTag ) :
255
+
256
+ case . finished( let buffer, let summary ) :
252
257
do {
253
258
for data in buffer {
254
259
let row = PostgresRow (
@@ -259,7 +264,7 @@ final class PSQLRowStream: @unchecked Sendable {
259
264
try onRow ( row)
260
265
}
261
266
262
- self . downstreamState = . consumed( . success( commandTag ) )
267
+ self . downstreamState = . consumed( . success( summary ) )
263
268
return self . eventLoop. makeSucceededVoidFuture ( )
264
269
} catch {
265
270
self . downstreamState = . consumed( . failure( error) )
@@ -292,7 +297,7 @@ final class PSQLRowStream: @unchecked Sendable {
292
297
293
298
case . waitingForConsumer( . finished) , . waitingForConsumer( . failure) :
294
299
preconditionFailure ( " How can new rows be received, if an end was already signalled? " )
295
-
300
+
296
301
case . iteratingRows( let onRow, let promise, let dataSource) :
297
302
do {
298
303
for data in newRows {
@@ -347,25 +352,25 @@ final class PSQLRowStream: @unchecked Sendable {
347
352
private func receiveEnd( _ commandTag: String ) {
348
353
switch self . downstreamState {
349
354
case . waitingForConsumer( . streaming( buffer: let buffer, _) ) :
350
- self . downstreamState = . waitingForConsumer( . finished( buffer: buffer, commandTag : commandTag) )
351
-
352
- case . waitingForConsumer( . finished) , . waitingForConsumer( . failure) :
355
+ self . downstreamState = . waitingForConsumer( . finished( buffer: buffer, summary : . tag ( commandTag) ) )
356
+
357
+ case . waitingForConsumer( . finished) , . waitingForConsumer( . failure) , . consumed ( . success ( . emptyResponse ) ) :
353
358
preconditionFailure ( " How can we get another end, if an end was already signalled? " )
354
359
355
360
case . iteratingRows( _, let promise, _) :
356
- self . downstreamState = . consumed( . success( commandTag) )
361
+ self . downstreamState = . consumed( . success( . tag ( commandTag) ) )
357
362
promise. succeed ( ( ) )
358
363
359
364
case . waitingForAll( let rows, let promise, _) :
360
- self . downstreamState = . consumed( . success( commandTag) )
365
+ self . downstreamState = . consumed( . success( . tag ( commandTag) ) )
361
366
promise. succeed ( rows)
362
367
363
368
case . asyncSequence( let source, _, let onFinish) :
364
- self . downstreamState = . consumed( . success( commandTag) )
369
+ self . downstreamState = . consumed( . success( . tag ( commandTag) ) )
365
370
source. finish ( )
366
371
onFinish ( )
367
372
368
- case . consumed:
373
+ case . consumed( . success ( . tag ) ) , . consumed ( . failure ) :
369
374
break
370
375
}
371
376
}
@@ -375,7 +380,7 @@ final class PSQLRowStream: @unchecked Sendable {
375
380
case . waitingForConsumer( . streaming) :
376
381
self . downstreamState = . waitingForConsumer( . failure( error) )
377
382
378
- case . waitingForConsumer( . finished) , . waitingForConsumer( . failure) :
383
+ case . waitingForConsumer( . finished) , . waitingForConsumer( . failure) , . consumed ( . success ( . emptyResponse ) ) :
379
384
preconditionFailure ( " How can we get another end, if an end was already signalled? " )
380
385
381
386
case . iteratingRows( _, let promise, _) :
@@ -391,7 +396,7 @@ final class PSQLRowStream: @unchecked Sendable {
391
396
consumer. finish ( error)
392
397
onFinish ( )
393
398
394
- case . consumed:
399
+ case . consumed( . success ( . tag ) ) , . consumed ( . failure ) :
395
400
break
396
401
}
397
402
}
@@ -413,10 +418,15 @@ final class PSQLRowStream: @unchecked Sendable {
413
418
}
414
419
415
420
var commandTag : String {
416
- guard case . consumed( . success( let commandTag ) ) = self . downstreamState else {
421
+ guard case . consumed( . success( let consumed ) ) = self . downstreamState else {
417
422
preconditionFailure ( " commandTag may only be called if all rows have been consumed " )
418
423
}
419
- return commandTag
424
+ switch consumed {
425
+ case . tag( let tag) :
426
+ return tag
427
+ case . emptyResponse:
428
+ return " "
429
+ }
420
430
}
421
431
}
422
432
0 commit comments