From 1723b6d023cca5a0bc5525b3dcecd97ae2a81f08 Mon Sep 17 00:00:00 2001 From: Bob Jackman Date: Thu, 18 Apr 2019 11:25:02 -0700 Subject: [PATCH 1/3] Move some common functionality in both `StandardDataPacket` and `BinaryDataPacket` up to their parent class `Row` --- connection.options | 2 +- .../binary_data_packet.dart | 36 ++--- lib/src/query/standard_data_packet.dart | 153 +++++++++--------- lib/src/results/row.dart | 33 +++- 4 files changed, 117 insertions(+), 107 deletions(-) diff --git a/connection.options b/connection.options index 0774c9d..23aab01 100644 --- a/connection.options +++ b/connection.options @@ -4,4 +4,4 @@ user=root port=3306 db=sqljockeytest #defaults to localhost -host=localhost \ No newline at end of file +host=localhost diff --git a/lib/src/prepared_statements/binary_data_packet.dart b/lib/src/prepared_statements/binary_data_packet.dart index ca56cf2..28d34a6 100644 --- a/lib/src/prepared_statements/binary_data_packet.dart +++ b/lib/src/prepared_statements/binary_data_packet.dart @@ -11,20 +11,18 @@ import '../results/field.dart'; import '../results/row.dart'; class BinaryDataPacket extends Row { - List values; - final Logger log; + final Logger log = new Logger("BinaryDataPacket"); - BinaryDataPacket.forTests(this.values) : log = new Logger("BinaryDataPacket"); + BinaryDataPacket.forTests(List _values) { values = _values; } - BinaryDataPacket(Buffer buffer, List fields) - : log = new Logger("BinaryDataPacket") { + BinaryDataPacket(Buffer buffer, List fieldPackets) { buffer.skip(1); - var nulls = buffer.readList(((fields.length + 7 + 2) / 8).floor().toInt()); + var nulls = buffer.readList(((fieldPackets.length + 7 + 2) / 8).floor().toInt()); log.fine("Nulls: $nulls"); - var nullMap = new List(fields.length); + var nullMap = new List(fieldPackets.length); var shift = 2; var byte = 0; - for (var i = 0; i < fields.length; i++) { + for (var i = 0; i < fieldPackets.length; i++) { var mask = 1 << shift; nullMap[i] = (nulls[byte] & mask) != 0; shift++; @@ -34,15 +32,15 @@ class BinaryDataPacket extends Row { } } - values = new List(fields.length); - for (var i = 0; i < fields.length; i++) { - log.fine("$i: ${fields[i].name}"); + values = new List(fieldPackets.length); + for (var i = 0; i < fieldPackets.length; i++) { + log.fine("$i: ${fieldPackets[i].name}"); if (nullMap[i]) { log.fine("Value: null"); values[i] = null; continue; } - var field = fields[i]; + var field = fieldPackets[i]; values[i] = readField(field, buffer); } } @@ -218,18 +216,4 @@ class BinaryDataPacket extends Row { } return null; } - - int get length => values.length; - - dynamic operator [](int index) => values[index]; - - void operator []=(int index, dynamic value) { - throw new UnsupportedError("Cannot modify row"); - } - - set length(int newLength) { - throw new UnsupportedError("Cannot set length of results"); - } - - String toString() => "Value: $values"; } diff --git a/lib/src/query/standard_data_packet.dart b/lib/src/query/standard_data_packet.dart index e264bf5..d2b08de 100644 --- a/lib/src/query/standard_data_packet.dart +++ b/lib/src/query/standard_data_packet.dart @@ -3,6 +3,7 @@ library mysql1.standard_data_packet; import 'dart:convert'; +import 'package:logging/logging.dart'; import '../constants.dart'; import '../blob.dart'; @@ -12,93 +13,87 @@ import '../results/row.dart'; import '../results/field.dart'; class StandardDataPacket extends Row { - /// Values as List - final List values; + final Logger log = new Logger("StandardDataPacket"); + /// Values as Map final Map fields = {}; - StandardDataPacket(Buffer buffer, List fieldPackets) - : values = new List(fieldPackets.length) { + StandardDataPacket(Buffer buffer, List fieldPackets) { + values = new List(fieldPackets.length); for (var i = 0; i < fieldPackets.length; i++) { - var list; - int length = buffer.readLengthCodedBinary(); - if (length != null) { - list = buffer.readList(length); - } else { - values[i] = null; - continue; - } - switch (fieldPackets[i].type) { - case FIELD_TYPE_TINY: // tinyint/bool - case FIELD_TYPE_SHORT: // smallint - case FIELD_TYPE_INT24: // mediumint - case FIELD_TYPE_LONGLONG: // bigint/serial - case FIELD_TYPE_LONG: // int - var s = utf8.decode(list); - values[i] = int.parse(s); - break; - case FIELD_TYPE_NEWDECIMAL: // decimal - case FIELD_TYPE_FLOAT: // float - case FIELD_TYPE_DOUBLE: // double - var s = utf8.decode(list); - values[i] = double.parse(s); - break; - case FIELD_TYPE_BIT: // bit - var value = 0; - for (var num in list) { - value = (value << 8) + num; - } - values[i] = value; - break; - case FIELD_TYPE_DATE: // date - case FIELD_TYPE_DATETIME: // datetime - case FIELD_TYPE_TIMESTAMP: // timestamp - var s = utf8.decode(list); - values[i] = DateTime.parse(s).toUtc(); - break; - case FIELD_TYPE_TIME: // time - var s = utf8.decode(list); - var parts = s.split(":"); - values[i] = new Duration( - days: 0, - hours: int.parse(parts[0]), - minutes: int.parse(parts[1]), - seconds: int.parse(parts[2]), - milliseconds: 0); - break; - case FIELD_TYPE_YEAR: // year - var s = utf8.decode(list); - values[i] = int.parse(s); - break; - case FIELD_TYPE_STRING: // char/binary/enum/set - case FIELD_TYPE_VAR_STRING: // varchar/varbinary - var s = utf8.decode(list); - values[i] = s; - break; - case FIELD_TYPE_BLOB: // tinytext/text/mediumtext/longtext/tinyblob/mediumblob/blob/longblob - values[i] = new Blob.fromBytes(list); - break; - case FIELD_TYPE_GEOMETRY: // geometry - var s = utf8.decode(list); - values[i] = s; - break; - } - fields[fieldPackets[i].name] = values[i]; - } - } - - StandardDataPacket.forTests(this.values); - - int get length => values.length; + var field = fieldPackets[i]; - dynamic operator [](int index) => values[index]; + log.fine("$i: ${field.name}"); - void operator []=(int index, dynamic value) { - throw new UnsupportedError("Cannot modify row"); + values[i] = readField(field, buffer); + fields[field.name] = values[i]; + } } - set length(int newLength) { - throw new UnsupportedError("Cannot set length of results"); + Object readField(Field field, Buffer buffer) { + var list; + int length = buffer.readLengthCodedBinary(); + if (length != null) { + list = buffer.readList(length); + } else { + return null; + } + + switch (field.type) { + case FIELD_TYPE_TINY: // tinyint/bool + case FIELD_TYPE_SHORT: // smallint + case FIELD_TYPE_INT24: // mediumint + case FIELD_TYPE_LONGLONG: // bigint/serial + case FIELD_TYPE_LONG: // int + var s = utf8.decode(list); + return int.parse(s); + break; + case FIELD_TYPE_NEWDECIMAL: // decimal + case FIELD_TYPE_FLOAT: // float + case FIELD_TYPE_DOUBLE: // double + var s = utf8.decode(list); + return double.parse(s); + break; + case FIELD_TYPE_BIT: // bit + var value = 0; + for (var num in list) { + value = (value << 8) + num; + } + return value; + break; + case FIELD_TYPE_DATE: // date + case FIELD_TYPE_DATETIME: // datetime + case FIELD_TYPE_TIMESTAMP: // timestamp + var s = utf8.decode(list); + return DateTime.parse(s).toUtc(); + break; + case FIELD_TYPE_TIME: // time + var s = utf8.decode(list); + var parts = s.split(":"); + return new Duration( + days: 0, + hours: int.parse(parts[0]), + minutes: int.parse(parts[1]), + seconds: int.parse(parts[2]), + milliseconds: 0); + break; + case FIELD_TYPE_YEAR: // year + var s = utf8.decode(list); + return int.parse(s); + break; + case FIELD_TYPE_STRING: // char/binary/enum/set + case FIELD_TYPE_VAR_STRING: // varchar/varbinary + var s = utf8.decode(list); + return s; + break; + case FIELD_TYPE_BLOB: // tinytext/text/mediumtext/longtext/tinyblob/mediumblob/blob/longblob + return new Blob.fromBytes(list); + break; + case FIELD_TYPE_GEOMETRY: // geometry + var s = utf8.decode(list); + return s; + break; + } } String toString() => "Fields: $fields"; diff --git a/lib/src/results/row.dart b/lib/src/results/row.dart index 68a3e58..55f6e80 100644 --- a/lib/src/results/row.dart +++ b/lib/src/results/row.dart @@ -2,10 +2,41 @@ library mysql1.row; import 'dart:collection'; +import 'field.dart'; +import '../buffer.dart'; + /** * A row of data. Fields can be retrieved by index, or by name. * * When retrieving a field by name, only fields which are valid Dart * identifiers, and which aren't part of the List object, can be used. */ -abstract class Row extends ListBase {} +abstract class Row extends ListBase { + /// Values as List + List values; + + /// Values as Map + final Map fields = {}; + + int get length => values.length; + + set length(int newLength) { + throw new UnsupportedError("Cannot set length of results"); + } + + dynamic operator [](dynamic index) { + if (index is int) { + return values[index]; + } else { + return fields[index.toString()]; + } + } + + void operator []=(int index, dynamic value) { + throw new UnsupportedError("Cannot modify row"); + } + + String toString() => "Value: $values"; + + Object readField(Field field, Buffer buffer); +} From 3dc7af8d93511258a8f3a3cde6fb7baedf9dccd8 Mon Sep 17 00:00:00 2001 From: Bob Jackman Date: Thu, 18 Apr 2019 11:33:41 -0700 Subject: [PATCH 2/3] Make fields accessible by name in `BinaryDataPacket`s, too --- .../binary_data_packet.dart | 1 + lib/src/results/row.dart | 2 +- test/integration/one_test.dart | 35 +++++++++++++++++++ 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/lib/src/prepared_statements/binary_data_packet.dart b/lib/src/prepared_statements/binary_data_packet.dart index 28d34a6..6d0c004 100644 --- a/lib/src/prepared_statements/binary_data_packet.dart +++ b/lib/src/prepared_statements/binary_data_packet.dart @@ -42,6 +42,7 @@ class BinaryDataPacket extends Row { } var field = fieldPackets[i]; values[i] = readField(field, buffer); + fields[field.name] = values[i]; } } diff --git a/lib/src/results/row.dart b/lib/src/results/row.dart index 55f6e80..728bca7 100644 --- a/lib/src/results/row.dart +++ b/lib/src/results/row.dart @@ -36,7 +36,7 @@ abstract class Row extends ListBase { throw new UnsupportedError("Cannot modify row"); } - String toString() => "Value: $values"; + String toString() => "Fields: $fields"; Object readField(Field field, Buffer buffer); } diff --git a/test/integration/one_test.dart b/test/integration/one_test.dart index 09ebb8c..b3fbccd 100644 --- a/test/integration/one_test.dart +++ b/test/integration/one_test.dart @@ -380,6 +380,41 @@ void main() { expect(dt, equals(dt2)); }); + test('result fields are accessible by name', () async { + var results = await conn.query( + "insert into test1 (atinyint, asmallint, amediumint, abigint, aint, " + "adecimal, afloat, adouble, areal, " + "aboolean, abit, aserial, " + "adate, adatetime, atimestamp, atime, ayear, " + "achar, avarchar, atinytext, atext, amediumtext, alongtext, " + "abinary, avarbinary, atinyblob, amediumblob, ablob, alongblob, " + "aenum, aset) values" + "(?, ?, ?, ?, ?, " + "?, ?, ?, ?, " + "?, ?, ?, " + "?, ?, ?, ?, ?, " + "?, ?, ?, ?, ?, ?, " + "?, ?, ?, ?, ?, ?, " + "?, ?)", + insertValues); + + // Normal + results = await conn.query('select atinyint from test1'); + int v1 = results.first.fields['atinyint']; + int v2 = results.first['atinyint']; + expect(v1, isNotNull); + expect(v2, equals(v1)); + + // Binary packet + results = await conn.query('select atinyint from test1 WHERE ? = ?', [1, 1]); + int v3 = results.first.fields['atinyint']; + int v4 = results.first['atinyint']; + expect(v3, isNotNull); + expect(v4, equals(v3)); + + expect(v1, equals(v3)); + }); + test('disallow non-utc datetime serialization', () async { expect(() async { var results = await conn.query( From 45e2d0a64c60869f0df0a6c16d50f9d289809ef8 Mon Sep 17 00:00:00 2001 From: Bob Jackman Date: Thu, 18 Apr 2019 12:09:17 -0700 Subject: [PATCH 3/3] Adjustments to pass dartfmt checks --- lib/src/prepared_statements/binary_data_packet.dart | 7 +++++-- lib/src/query/standard_data_packet.dart | 2 ++ test/integration/one_test.dart | 3 ++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/src/prepared_statements/binary_data_packet.dart b/lib/src/prepared_statements/binary_data_packet.dart index 6d0c004..daad932 100644 --- a/lib/src/prepared_statements/binary_data_packet.dart +++ b/lib/src/prepared_statements/binary_data_packet.dart @@ -13,11 +13,14 @@ import '../results/row.dart'; class BinaryDataPacket extends Row { final Logger log = new Logger("BinaryDataPacket"); - BinaryDataPacket.forTests(List _values) { values = _values; } + BinaryDataPacket.forTests(List _values) { + values = _values; + } BinaryDataPacket(Buffer buffer, List fieldPackets) { buffer.skip(1); - var nulls = buffer.readList(((fieldPackets.length + 7 + 2) / 8).floor().toInt()); + var nulls = + buffer.readList(((fieldPackets.length + 7 + 2) / 8).floor().toInt()); log.fine("Nulls: $nulls"); var nullMap = new List(fieldPackets.length); var shift = 2; diff --git a/lib/src/query/standard_data_packet.dart b/lib/src/query/standard_data_packet.dart index d2b08de..58bf541 100644 --- a/lib/src/query/standard_data_packet.dart +++ b/lib/src/query/standard_data_packet.dart @@ -93,6 +93,8 @@ class StandardDataPacket extends Row { var s = utf8.decode(list); return s; break; + default: + return null; } } diff --git a/test/integration/one_test.dart b/test/integration/one_test.dart index b3fbccd..fee456d 100644 --- a/test/integration/one_test.dart +++ b/test/integration/one_test.dart @@ -406,7 +406,8 @@ void main() { expect(v2, equals(v1)); // Binary packet - results = await conn.query('select atinyint from test1 WHERE ? = ?', [1, 1]); + results = + await conn.query('select atinyint from test1 WHERE ? = ?', [1, 1]); int v3 = results.first.fields['atinyint']; int v4 = results.first['atinyint']; expect(v3, isNotNull);