Skip to content

Commit cc8772d

Browse files
committed
Fix delayed converter resolution for nullables (#6453)
(cherry picked from commit 013e771)
1 parent d5c5bff commit cc8772d

File tree

3 files changed

+48
-41
lines changed

3 files changed

+48
-41
lines changed

src/Npgsql/Internal/Converters/ArrayConverter.cs

Lines changed: 33 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -619,45 +619,40 @@ protected override PgConverter<T> CreateConverter(PgConverterResolution effectiv
619619
protected override PgConverterResolution? GetEffectiveResolution(T? values, PgTypeId? expectedEffectivePgTypeId)
620620
{
621621
PgConverterResolution? resolution = null;
622-
if (values is null)
622+
switch (values)
623623
{
624-
resolution = EffectiveTypeInfo.GetDefaultResolution(expectedEffectivePgTypeId);
625-
}
626-
else
627-
{
628-
switch (values)
629-
{
630-
case TElement[] array:
631-
foreach (var value in array)
632-
{
633-
var result = EffectiveTypeInfo.GetResolution(value, resolution?.PgTypeId ?? expectedEffectivePgTypeId);
634-
resolution ??= result;
635-
}
636-
break;
637-
case List<TElement> list:
638-
foreach (var value in list)
639-
{
640-
var result = EffectiveTypeInfo.GetResolution(value, resolution?.PgTypeId ?? expectedEffectivePgTypeId);
641-
resolution ??= result;
642-
}
643-
break;
644-
case IList<TElement> list:
645-
foreach (var value in list)
646-
{
647-
var result = EffectiveTypeInfo.GetResolution(value, resolution?.PgTypeId ?? expectedEffectivePgTypeId);
648-
resolution ??= result;
649-
}
650-
break;
651-
case Array array:
652-
foreach (var value in array)
653-
{
654-
var result = EffectiveTypeInfo.GetResolutionAsObject(value, resolution?.PgTypeId ?? expectedEffectivePgTypeId);
655-
resolution ??= result;
656-
}
657-
break;
658-
default:
659-
throw new NotSupportedException();
660-
}
624+
case TElement[] array:
625+
foreach (var value in array)
626+
{
627+
var result = EffectiveTypeInfo.GetResolution(value, resolution?.PgTypeId ?? expectedEffectivePgTypeId);
628+
resolution ??= result;
629+
}
630+
break;
631+
case List<TElement> list:
632+
foreach (var value in list)
633+
{
634+
var result = EffectiveTypeInfo.GetResolution(value, resolution?.PgTypeId ?? expectedEffectivePgTypeId);
635+
resolution ??= result;
636+
}
637+
break;
638+
case IList<TElement> list:
639+
foreach (var value in list)
640+
{
641+
var result = EffectiveTypeInfo.GetResolution(value, resolution?.PgTypeId ?? expectedEffectivePgTypeId);
642+
resolution ??= result;
643+
}
644+
break;
645+
case Array array:
646+
foreach (var value in array)
647+
{
648+
var result = EffectiveTypeInfo.GetResolutionAsObject(value, resolution?.PgTypeId ?? expectedEffectivePgTypeId);
649+
resolution ??= result;
650+
}
651+
break;
652+
case null:
653+
break;
654+
default:
655+
throw new NotSupportedException();
661656
}
662657

663658
return resolution;

src/Npgsql/Internal/Converters/NullableConverter.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ sealed class NullableConverterResolver<T>(PgResolverTypeInfo effectiveTypeInfo)
5050
=> new NullableConverter<T>(effectiveResolution.GetConverter<T>());
5151

5252
protected override PgConverterResolution? GetEffectiveResolution(T? value, PgTypeId? expectedEffectivePgTypeId)
53-
=> value is null
54-
? EffectiveTypeInfo.GetDefaultResolution(expectedEffectivePgTypeId)
55-
: EffectiveTypeInfo.GetResolution(value.GetValueOrDefault(), expectedEffectivePgTypeId);
53+
=> value is { } inner
54+
? EffectiveTypeInfo.GetResolution(inner, expectedEffectivePgTypeId)
55+
: null;
5656
}

test/Npgsql.Tests/Types/DateTimeTests.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,18 @@ await AssertType(datasource,
491491
"timestamp with time zone[]",
492492
NpgsqlDbType.TimestampTz | NpgsqlDbType.Array);
493493

494+
// Make sure delayed converter resolution works when null precedes a non-null value.
495+
// We expect the resolution of null values to not lock in the default type timestamp.
496+
// This would cause the subsequent non-null value to fail to convert, as it requires timestamptz.
497+
await AssertType(datasource,
498+
new DateTime?[]
499+
{
500+
null,
501+
new DateTime(1998, 4, 12, 13, 26, 38, DateTimeKind.Utc)
502+
},
503+
@"{NULL,""1998-04-12 15:26:38+02""}",
504+
"timestamp with time zone[]");
505+
494506
await AssertType(datasource,
495507
new DateTime?[]
496508
{

0 commit comments

Comments
 (0)