@@ -472,50 +472,7 @@ async Task<bool> NextResult(bool async, bool isConsuming = false, CancellationTo
472472
473473 if ( ( Command . WrappingBatch is not null || StatementIndex is 0 ) && Command . InternalBatchCommands [ StatementIndex ] is { HasOutputParameters : true } command )
474474 {
475- // If output parameters are present and this is the first row of the resultset,
476- // we must always read it in non-sequential mode because it will be traversed twice (once
477- // here for the parameters, then as a regular row).
478- msg = await Connector . ReadMessage ( async , dataRowLoadingMode : DataRowLoadingMode . NonSequential ) . ConfigureAwait ( false ) ;
479- ProcessMessage ( msg ) ;
480- if ( msg . Code == BackendMessageCode . DataRow )
481- {
482- Debug . Assert ( RowDescription != null ) ;
483- Debug . Assert ( State == ReaderState . BeforeResult ) ;
484-
485- try
486- {
487- // Temporarily set our state to InResult and non-sequential to allow us to read the values, and in any order.
488- var isSequential = _isSequential ;
489- var currentPosition = Buffer . ReadPosition ;
490- State = ReaderState . InResult ;
491- _isSequential = false ;
492- try
493- {
494- command . PopulateOutputParameters ( this , _commandLogger ) ;
495-
496- // On success we want to revert any row and column state for the user to be able to read the same row again.
497- if ( async)
498- await PgReader . CommitAsync ( ) . ConfigureAwait ( false ) ;
499- else
500- PgReader . Commit ( ) ;
501-
502- State = ReaderState . BeforeResult ; // Set the state back
503- Buffer . ReadPosition = currentPosition ; // Restore position
504- _column = - 1 ;
505- }
506- finally
507- {
508- // To be on the safe side we always revert this CommandBehavior state change, including on failure.
509- _isSequential = isSequential ;
510- }
511- }
512- catch ( Exception e )
513- {
514- // TODO: ideally we should flow down to global exception filter and consume there
515- await Consume ( async , firstException : e ) . ConfigureAwait( false) ;
516- throw ;
517- }
518- }
475+ msg = await ReadMessageWithOutputParameters ( async , command ) . ConfigureAwait ( false ) ;
519476 }
520477 else
521478 {
@@ -647,6 +604,56 @@ async ValueTask ConsumeResultSet(bool async)
647604 }
648605 }
649606
607+ async ValueTask < IBackendMessage > ReadMessageWithOutputParameters ( bool async, NpgsqlBatchCommand command )
608+ {
609+ // If output parameters are present and this is the first row of the resultset,
610+ // we must always read it in non-sequential mode because it will be traversed twice (once
611+ // here for the parameters, then as a regular row).
612+ var msg = await Connector. ReadMessage( async, dataRowLoadingMode : DataRowLoadingMode . NonSequential ) . ConfigureAwait ( false) ;
613+ ProcessMessage ( msg ) ;
614+ if ( msg. Code == BackendMessageCode. DataRow)
615+ {
616+ Debug. Assert( RowDescription != null ) ;
617+ Debug. Assert( State == ReaderState. BeforeResult) ;
618+
619+ try
620+ {
621+ // Temporarily set our state to InResult and non-sequential to allow us to read the values, and in any order.
622+ var isSequential = _isSequential;
623+ var currentPosition = Buffer. ReadPosition;
624+ State = ReaderState. InResult;
625+ _isSequential = false;
626+ try
627+ {
628+ command. PopulateOutputParameters( this , _commandLogger) ;
629+
630+ // On success we want to revert any row and column state for the user to be able to read the same row again.
631+ if ( async)
632+ await PgReader. CommitAsync( ) . ConfigureAwait( false) ;
633+ else
634+ PgReader. Commit( ) ;
635+
636+ State = ReaderState. BeforeResult; // Set the state back
637+ Buffer. ReadPosition = currentPosition; // Restore position
638+ _column = - 1 ;
639+ }
640+ finally
641+ {
642+ // To be on the safe side we always revert this CommandBehavior state change, including on failure.
643+ _isSequential = isSequential;
644+ }
645+ }
646+ catch ( Exception e)
647+ {
648+ // TODO: ideally we should flow down to global exception filter and consume there
649+ await Consume( async, firstException: e) . ConfigureAwait( false) ;
650+ throw ;
651+ }
652+ }
653+
654+ return msg ;
655+ }
656+
650657 /// <summary>
651658 /// Note that in SchemaOnly mode there are no resultsets, and we read nothing from the backend (all
652659 /// RowDescriptions have already been processed and are available)
@@ -971,7 +978,7 @@ public override int FieldCount
971978 /// Consumes all result sets for this reader, leaving the connector ready for sending and processing further
972979 /// queries
973980 /// </summary>
974- async Task Consume ( bool async , Exception ? firstException = null )
981+ async ValueTask Consume ( bool async , Exception ? firstException = null )
975982 {
976983 var exceptions = firstException is null ? null : new List < Exception > { firstException } ;
977984
0 commit comments