serializeParams function

Uint8List serializeParams(
  1. List<ParamValue> params
)

Serializes a list of parameter values to binary format.

The params list should contain ParamValue instances in the order they appear in the prepared statement.

Returns a Uint8List containing the serialized parameters.

Uses a two-pass strategy: phase 1 sizes the buffer (ASCII text writes code units directly in phase 2; non-ASCII is UTF-8 encoded once); phase 2 writes into a single pre-sized Uint8List.

Implementation

Uint8List serializeParams(List<ParamValue> params) {
  if (params.isEmpty) return Uint8List(0);

  // Phase 1: size payloads. `encodedText[i] == null` means ASCII (or unused);
  // non-null holds a one-shot UTF-8 encoding for non-ASCII text.
  var totalBytes = 0;
  final encodedText = List<List<int>?>.filled(params.length, null);
  for (var i = 0; i < params.length; i++) {
    switch (params[i]) {
      case ParamValueNull():
        totalBytes += 5;
      case ParamValueString(:final value):
        if (_isAsciiOnly(value)) {
          totalBytes += 5 + value.length;
        } else {
          final b = utf8.encode(value);
          encodedText[i] = b;
          totalBytes += 5 + b.length;
        }
      case ParamValueInt32():
        totalBytes += 9;
      case ParamValueInt64():
        totalBytes += 13;
      case ParamValueDecimal(:final value):
        if (_isAsciiOnly(value)) {
          totalBytes += 5 + value.length;
        } else {
          final b = utf8.encode(value);
          encodedText[i] = b;
          totalBytes += 5 + b.length;
        }
      case ParamValueBinary(:final value):
        totalBytes += 5 + value.length;
      case ParamValueRefCursorOut():
        totalBytes += 5;
    }
  }

  // Phase 2: write all params into the pre-sized buffer.
  final out = Uint8List(totalBytes);
  final bd = ByteData.sublistView(out);
  var off = 0;
  for (var i = 0; i < params.length; i++) {
    switch (params[i]) {
      case ParamValueNull():
        out[off] = _tagNull;
        bd.setUint32(off + 1, 0, _littleEndian);
        off += 5;
      case ParamValueString(:final value):
        final encoded = encodedText[i];
        if (encoded != null) {
          out[off] = _tagString;
          bd.setUint32(off + 1, encoded.length, _littleEndian);
          out.setRange(off + 5, off + 5 + encoded.length, encoded);
          off += 5 + encoded.length;
        } else {
          out[off] = _tagString;
          bd.setUint32(off + 1, value.length, _littleEndian);
          _writeAsciiString(out, off + 5, value);
          off += 5 + value.length;
        }
      case ParamValueInt32(:final value):
        out[off] = _tagInteger;
        bd.setUint32(off + 1, 4, _littleEndian);
        bd.setInt32(off + 5, value, _littleEndian);
        off += 9;
      case ParamValueInt64(:final value):
        out[off] = _tagBigInt;
        bd.setUint32(off + 1, 8, _littleEndian);
        bd.setInt64(off + 5, value, _littleEndian);
        off += 13;
      case ParamValueDecimal(:final value):
        final encoded = encodedText[i];
        if (encoded != null) {
          out[off] = _tagDecimal;
          bd.setUint32(off + 1, encoded.length, _littleEndian);
          out.setRange(off + 5, off + 5 + encoded.length, encoded);
          off += 5 + encoded.length;
        } else {
          out[off] = _tagDecimal;
          bd.setUint32(off + 1, value.length, _littleEndian);
          _writeAsciiString(out, off + 5, value);
          off += 5 + value.length;
        }
      case ParamValueBinary(:final value):
        final vLen = value.length;
        out[off] = _tagBinary;
        bd.setUint32(off + 1, vLen, _littleEndian);
        out.setRange(off + 5, off + 5 + vLen, value);
        off += 5 + vLen;
      case ParamValueRefCursorOut():
        out[off] = _tagRefCursorOut;
        bd.setUint32(off + 1, 0, _littleEndian);
        off += 5;
    }
  }

  return out;
}