Skip to content

Commit de86a2a

Browse files
authored
Fix empty arrays decoding as List<Object?> instead of a list of their element type (#472)
1 parent e33bd80 commit de86a2a

4 files changed

Lines changed: 39 additions & 3 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
## 3.5.19
4+
5+
- Fix empty arrays decoding as `List<Object?>` instead of a list of their element type (a 3.5.18 regression).
6+
37
## 3.5.18
48

59
- Fix the statement after a failed one sometimes returning no rows.

‎lib/src/types/binary_codec.dart‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1193,16 +1193,17 @@ class PostgresBinaryDecoder {
11931193
Uint8List data,
11941194
V Function(ByteDataReader reader, int length) valueDecoder,
11951195
) {
1196+
// An empty array keeps its element type, as a non-empty one does.
11961197
if (data.length < 12) {
1197-
return (items: <Object?>[], sqlNulls: <bool>[]);
1198+
return (items: <V>[], sqlNulls: <bool>[]);
11981199
}
11991200

12001201
final reader = ByteDataReader()..add(data);
12011202
final ndim = reader.readInt32();
12021203
reader.read(8); // flags (has-null) + element type oid
12031204

12041205
if (ndim <= 0) {
1205-
return (items: <Object?>[], sqlNulls: <bool>[]);
1206+
return (items: <V>[], sqlNulls: <bool>[]);
12061207
}
12071208

12081209
// One (size, lower bound) pair per dimension; the lower bound has no

‎pubspec.yaml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: postgres
22
description: PostgreSQL database driver. Supports binary protocol, connection pooling and statement reuse.
3-
version: 3.5.18
3+
version: 3.5.19
44
homepage: https://github.com/isoos/postgresql-dart
55
topics:
66
- sql

‎test/encoding_test.dart‎

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,17 @@ void main() {
445445
);
446446
});
447447

448+
test('an empty array decodes as a list of its element type, as a '
449+
'non-empty one does', () async {
450+
final row = (await conn.execute(
451+
"SELECT '{}'::text[], '{a}'::text[], '{}'::int4[], '{}'::bool[]",
452+
)).single;
453+
expect(row[0], isA<List<String>>());
454+
expect(row[1], isA<List<String>>());
455+
expect(row[2], isA<List<int>>());
456+
expect(row[3], isA<List<bool>>());
457+
});
458+
448459
test('textArray', () async {
449460
await expectReversible(
450461
'_text',
@@ -1292,6 +1303,26 @@ void main() {
12921303
expect(result, <int>[]);
12931304
});
12941305

1306+
for (final (typeOid, elementOid, matcher) in [
1307+
(TypeOid.integerArray, TypeOid.integer, isA<List<int>>()),
1308+
(TypeOid.bigIntegerArray, TypeOid.bigInteger, isA<List<int>>()),
1309+
(TypeOid.textArray, TypeOid.text, isA<List<String>>()),
1310+
(TypeOid.varCharArray, TypeOid.varChar, isA<List<String>>()),
1311+
(TypeOid.booleanArray, TypeOid.boolean, isA<List<bool>>()),
1312+
(TypeOid.doubleArray, TypeOid.double, isA<List<double>>()),
1313+
(TypeOid.uuidArray, TypeOid.uuid, isA<List<String>>()),
1314+
]) {
1315+
test('An empty array (oid $typeOid) keeps its element type, so a cast '
1316+
'that holds for a non-empty one holds for it too', () {
1317+
final context = CodecContext.withDefaults();
1318+
// Postgres's wire format for an empty array: ndim=0, flags=0,
1319+
// elemtype, and no dimensions.
1320+
final bytes = concatInt32s([0, 0, elementOid]);
1321+
final result = PostgresBinaryDecoder.convert(context, typeOid, bytes);
1322+
expect(result, matcher);
1323+
});
1324+
}
1325+
12951326
Uint8List int64Bytes(int value) =>
12961327
(ByteData(8)..setInt64(0, value)).buffer.asUint8List();
12971328
Uint8List int32Bytes(int value) =>

0 commit comments

Comments
 (0)