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 pre-encodes text payloads and computes the exact total byte count; phase 2 writes directly into a single pre-sized Uint8List — avoiding all intermediate list allocations and the final Uint8List.fromList copy that the old approach required.

Implementation

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

  // Phase 1: pre-encode text payloads and compute total byte size.
  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):
        final b = utf8.encode(value);
        encodedText[i] = b;
        totalBytes += 5 + b.length;
      case ParamValueInt32():
        totalBytes += 9;
      case ParamValueInt64():
        totalBytes += 13;
      case ParamValueDecimal(:final value):
        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 b = encodedText[i]!;
        out[off] = _tagString;
        bd.setUint32(off + 1, b.length, _littleEndian);
        out.setRange(off + 5, off + 5 + b.length, b);
        off += 5 + b.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 b = encodedText[i]!;
        out[off] = _tagDecimal;
        bd.setUint32(off + 1, b.length, _littleEndian);
        out.setRange(off + 5, off + 5 + b.length, b);
        off += 5 + b.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;
}