1212
1313namespace Npgsql . BackendMessages ;
1414
15+ readonly struct ColumnInfo
16+ {
17+ public ColumnInfo ( PgConverterInfo converterInfo , DataFormat dataFormat , bool asObject )
18+ {
19+ ConverterInfo = converterInfo ;
20+ DataFormat = dataFormat ;
21+ AsObject = asObject ;
22+ }
23+
24+ public PgConverterInfo ConverterInfo { get ; }
25+ public DataFormat DataFormat { get ; }
26+ public bool AsObject { get ; }
27+ }
28+
1529/// <summary>
1630/// A RowDescription message sent from the backend.
1731/// </summary>
@@ -24,7 +38,7 @@ sealed class RowDescriptionMessage : IBackendMessage, IReadOnlyList<FieldDescrip
2438 FieldDescription ? [ ] _fields ;
2539 readonly Dictionary < string , int > _nameIndex ;
2640 Dictionary < string , int > ? _insensitiveIndex ;
27- PgConverterInfo [ ] ? _lastConverterInfoCache ;
41+ ColumnInfo [ ] ? _lastConverterInfoCache ;
2842
2943 internal RowDescriptionMessage ( bool connectorOwned , int numFields = 10 )
3044 {
@@ -119,14 +133,14 @@ public FieldDescription this[int index]
119133 }
120134 }
121135
122- internal void SetConverterInfoCache ( ReadOnlySpan < PgConverterInfo > values )
136+ internal void SetConverterInfoCache ( ReadOnlySpan < ColumnInfo > values )
123137 {
124138 if ( _connectorOwned || _lastConverterInfoCache is not null )
125139 return ;
126140 Interlocked . CompareExchange ( ref _lastConverterInfoCache , values . ToArray ( ) , null ) ;
127141 }
128142
129- internal void LoadConverterInfoCache ( PgConverterInfo [ ] values )
143+ internal void LoadConverterInfoCache ( ColumnInfo [ ] values )
130144 {
131145 if ( _lastConverterInfoCache is not { } cache )
132146 return ;
@@ -328,17 +342,17 @@ internal void Populate(
328342
329343 internal Type FieldType => ObjectOrDefaultInfo . TypeToConvert ;
330344
331- PgConverterInfo _objectOrDefaultInfo ;
345+ ColumnInfo _objectOrDefaultInfo ;
332346 internal PgConverterInfo ObjectOrDefaultInfo
333347 {
334348 get
335349 {
336- if ( ! _objectOrDefaultInfo . IsDefault )
337- return _objectOrDefaultInfo ;
350+ if ( ! _objectOrDefaultInfo . ConverterInfo . IsDefault )
351+ return _objectOrDefaultInfo . ConverterInfo ;
338352
339353 ref var info = ref _objectOrDefaultInfo ;
340- GetInfo ( null , ref _objectOrDefaultInfo , out _ ) ;
341- return info ;
354+ GetInfo ( null , ref _objectOrDefaultInfo ) ;
355+ return info . ConverterInfo ;
342356 }
343357 }
344358
@@ -350,64 +364,60 @@ internal FieldDescription Clone()
350364 return field ;
351365 }
352366
353- internal void GetInfo ( Type ? type , ref PgConverterInfo lastConverterInfo , out bool asObject )
367+ internal void GetInfo ( Type ? type , ref ColumnInfo lastColumnInfo )
354368 {
355- Debug . Assert ( lastConverterInfo . IsDefault || (
356- ReferenceEquals ( _serializerOptions , lastConverterInfo . TypeInfo . Options ) &&
357- lastConverterInfo . TypeInfo . PgTypeId == _serializerOptions . ToCanonicalTypeId ( PostgresType ) ) , "Cache is bleeding over" ) ;
369+ Debug . Assert ( lastColumnInfo . ConverterInfo . IsDefault || (
370+ ReferenceEquals ( _serializerOptions , lastColumnInfo . ConverterInfo . TypeInfo . Options ) &&
371+ lastColumnInfo . ConverterInfo . TypeInfo . PgTypeId == _serializerOptions . ToCanonicalTypeId ( PostgresType ) ) , "Cache is bleeding over" ) ;
358372
359- if ( ! lastConverterInfo . IsDefault && lastConverterInfo . TypeToConvert == type )
360- {
361- asObject = lastConverterInfo . IsBoxingConverter ;
373+ if ( ! lastColumnInfo . ConverterInfo . IsDefault && lastColumnInfo . ConverterInfo . TypeToConvert == type )
362374 return ;
363- }
364375
365- var odfInfo = DataFormat is DataFormat . Text && type is not null ? ObjectOrDefaultInfo : _objectOrDefaultInfo ;
376+ var odfInfo = DataFormat is DataFormat . Text && type is not null ? ObjectOrDefaultInfo : _objectOrDefaultInfo . ConverterInfo ;
366377 if ( odfInfo is { IsDefault : false } )
367378 {
368379 if ( typeof ( object ) == type )
369380 {
370- lastConverterInfo = odfInfo ;
371- asObject = true ;
381+ lastColumnInfo = new ( odfInfo , DataFormat , true ) ;
372382 return ;
373383 }
374384 if ( odfInfo . TypeToConvert == type )
375385 {
376- lastConverterInfo = odfInfo ;
377- asObject = lastConverterInfo . IsBoxingConverter ;
386+ lastColumnInfo = new ( odfInfo , DataFormat , odfInfo . IsBoxingConverter ) ;
378387 return ;
379388 }
380389 }
381390
382- GetInfoSlow ( out lastConverterInfo , out asObject ) ;
391+ GetInfoSlow ( out lastColumnInfo ) ;
383392
384393 [ MethodImpl ( MethodImplOptions . NoInlining ) ]
385- void GetInfoSlow ( out PgConverterInfo lastConverterInfo , out bool asObject )
394+ void GetInfoSlow ( out ColumnInfo lastColumnInfo )
386395 {
387396 var typeInfo = AdoSerializerHelpers . GetTypeInfoForReading ( type ?? typeof ( object ) , PostgresType , _serializerOptions ) ;
397+ PgConverterInfo converterInfo ;
388398 switch ( DataFormat )
389399 {
390400 case DataFormat . Binary :
391401 // If we don't support binary we'll just throw.
392- lastConverterInfo = typeInfo . Bind ( Field , DataFormat ) ;
393- asObject = typeof ( object ) == type || lastConverterInfo . IsBoxingConverter ;
402+ converterInfo = typeInfo . Bind ( Field , DataFormat ) ;
403+ lastColumnInfo = new ( converterInfo , DataFormat . Binary , typeof ( object ) == type || converterInfo . IsBoxingConverter ) ;
394404 break ;
395405 default :
396406 // For text we'll fall back to any available text converter for the expected clr type or throw.
397- if ( ! typeInfo . TryBind ( Field , DataFormat , out lastConverterInfo ) )
407+ if ( ! typeInfo . TryBind ( Field , DataFormat , out converterInfo ) )
398408 {
399409 typeInfo = AdoSerializerHelpers . GetTypeInfoForReading ( type ?? typeof ( string ) , _serializerOptions . UnknownPgType , _serializerOptions ) ;
400- lastConverterInfo = typeInfo . Bind ( Field , DataFormat ) ;
401- asObject = type != lastConverterInfo . TypeToConvert || lastConverterInfo . IsBoxingConverter ;
410+ converterInfo = typeInfo . Bind ( Field , DataFormat ) ;
411+ lastColumnInfo = new ( converterInfo , DataFormat , type != converterInfo . TypeToConvert || converterInfo . IsBoxingConverter ) ;
402412 }
403413 else
404- asObject = typeof ( object ) == type || lastConverterInfo . IsBoxingConverter ;
414+ lastColumnInfo = new ( converterInfo , DataFormat , typeof ( object ) == type || converterInfo . IsBoxingConverter ) ;
405415 break ;
406416 }
407417
408418 // We delay initializing ObjectOrDefaultInfo until after the first lookup (unless it is itself the first lookup).
409419 // When passed in an unsupported type it allows the error to be more specific, instead of just having object/null to deal with.
410- if ( _objectOrDefaultInfo . IsDefault && type is not null )
420+ if ( _objectOrDefaultInfo . ConverterInfo . IsDefault && type is not null )
411421 _ = ObjectOrDefaultInfo ;
412422 }
413423 }
0 commit comments