parse static method

ParsedRowBuffer parse(
  1. Uint8List data
)

Parses binary protocol data into a ParsedRowBuffer.

The data parameter must contain valid binary protocol data starting with the magic number, version, column count, row count, and followed by column metadata and row data.

Throws FormatException if the data is invalid or malformed.

Implementation

static ParsedRowBuffer parse(Uint8List data) {
  if (data.length < messageLengthFromHeader(data)) {
    throw const FormatException('Buffer too small for header');
  }

  final reader = _BufferReader(data);

  final version = reader.readUint16();
  if (version != 1) {
    throw FormatException('Unsupported protocol version: $version');
  }

  final columnCount = reader.readUint16();
  if (columnCount < 0 || columnCount > 255) {
    throw FormatException('Invalid column count: $columnCount');
  }

  final rowCount = reader.readUint32();

  final columns = <ColumnMetadata>[];
  for (var i = 0; i < columnCount; i++) {
    final nameLength = reader.readUint8();
    final name = reader.readString(nameLength);
    final odbcType = reader.readUint16();

    columns.add(
      ColumnMetadata(
        name: name,
        odbcType: odbcType,
      ),
    );
  }

  final rows = <List<dynamic>>[];
  for (var i = 0; i < rowCount; i++) {
    final rowValues = <dynamic>[];

    for (var j = 0; j < columnCount; j++) {
      final isNull = reader.readUint8() == 1;
      final type = reader.readUint8();

      switch (type) {
        case 0:
          rowValues.add(null);
        case 1:
          final length = reader.readUint32();
          if (isNull) {
            rowValues.add(null);
          } else {
            final string = reader.readString(length);
            rowValues.add(string);
          }
        case 2:
          reader.readUint32();
          rowValues.add(reader.readUint32());
        case 3:
          reader.readUint32();
          rowValues.add(reader.readUint64());
        case 4:
          reader.readUint32();
          final hasValue = reader.readUint8() == 1;
          if (hasValue) {
            final doubleValue = reader.readFloat64();
            rowValues.add(doubleValue);
          } else {
            rowValues.add(null);
          }
        case 5:
          reader.readUint32();
          rowValues.add(reader.readFloat64());
        case 6:
          reader.readUint32();
          final hasDate = reader.readUint8() == 1;
          if (hasDate) {
            final dateValue = DateTime.fromMillisecondsSinceEpoch(
              reader.readUint64(),
              isUtc: true,
            );
            rowValues.add(dateValue);
          } else {
            rowValues.add(null);
          }
        case 7:
          final length = reader.readUint32();
          rowValues.add(reader.readBinary(length));
        default:
          rowValues.add(null);
      }
    }

    rows.add(rowValues);
  }

  return ParsedRowBuffer(
    columns: columns,
    rows: rows,
    rowCount: rowCount,
    columnCount: columnCount,
  );
}