MySQLBinaryResultSetRowPacket.decode constructor

MySQLBinaryResultSetRowPacket.decode(
  1. Uint8List buffer,
  2. List<MySQLColumnDefinitionPacket> colDefs, {
  3. List<bool>? textualColumns,
})

Decodifica um pacote de linha de result set no modo binário.

buffer é o pacote recebido do servidor. colDefs é a lista de definições de coluna que contém os tipos de cada coluna.

Retorna uma instância de MySQLBinaryResultSetRowPacket com os valores decodificados.

Lança MySQLProtocolException se o header do pacote não for 0x00.

Implementation

factory MySQLBinaryResultSetRowPacket.decode(
    Uint8List buffer, List<MySQLColumnDefinitionPacket> colDefs,
    {List<bool>? textualColumns}) {
  final byteData = ByteData.sublistView(buffer);
  int offset = 0;

  // O primeiro byte do pacote deve ser 0x00 (header).
  final type = byteData.getUint8(offset);
  offset += 1;
  if (type != 0) {
    throw MySQLProtocolException(
      "Cannot decode MySQLBinaryResultSetRowPacket: packet type is not 0x00",
    );
  }

  // Inicializa a lista de valores (pode conter diferentes tipos).
  final values = List<dynamic>.filled(colDefs.length, null, growable: false);

  // Calcula o tamanho do null bitmap.
  // O tamanho do bitmap é determinado por: ((numCols + 9) / 8).floor()
  final nullBitmapSize = (colDefs.length + 9) >> 3;
  final nullBitmapOffset = offset;
  offset += nullBitmapSize;

  // Itera sobre cada coluna para decodificar os dados.
  for (int x = 0; x < colDefs.length; x++) {
    // Determina qual byte e bit verificar no bitmap.
    final bit = x + 2;
    final bitmapByteIndex = bit >> 3;
    final bitmapBitIndex = bit & 7;
    final byteToCheck = buffer[nullBitmapOffset + bitmapByteIndex];
    final isNull = (byteToCheck & (1 << bitmapBitIndex)) != 0;

    if (isNull) {
      // Já inicializado com null.
    } else {
      final colDef = colDefs[x];
      final colType = colDef.type.intVal;
      if (_isLengthEncodedBinaryColumnType(colType)) {
        final packedLength = _readLengthEncodedHeader(buffer, offset);
        final headerLength = packedLength & 0x0f;
        final valueLength = packedLength >> 4;
        final valueStart = offset + headerLength;
        final valueEnd = valueStart + valueLength;

        if (valueEnd > buffer.length) {
          throw MySQLProtocolException(
            "Cannot decode MySQLBinaryResultSetRowPacket: length-encoded column exceeds packet size",
          );
        }

        final fieldBytes =
            Uint8List.sublistView(buffer, valueStart, valueEnd);
        offset = valueEnd;
        values[x] = _shouldDecodeLengthEncodedColumnAsText(
          colDef,
          textualColumns?[x],
        )
            ? utf8.decode(fieldBytes, allowMalformed: true)
            : fieldBytes;
        continue;
      }

      // Caso contrário, chama a função parseBinaryColumnData para ler o valor.
      final parseResult = parseBinaryColumnData(
        colType,
        byteData,
        buffer,
        offset,
      );
      // Avança o offset de acordo com o número de bytes lidos.
      offset += parseResult.item2;
      var value = parseResult.item1;
      if (value is Uint8List &&
          (textualColumns?[x] ?? columnShouldBeTextual(colDefs[x]))) {
        // Prepared statements also deliver textual blobs using the negotiated charset; decode accordingly.
        value = utf8.decode(value, allowMalformed: true);
      }
      values[x] = value;
    }
  }

  return MySQLBinaryResultSetRowPacket(
    values: values,
  );
}