class RecordType extends PGType<Row> {

    static final int OID = 2249;
    static final String NAME = "record";

    static final RecordType EMPTY_RECORD = new RecordType(List.of());

    private final List<PGType<?>> fieldTypes;

    RecordType(List<PGType<?>> fieldTypes) {
        super(OID, -1, -1, NAME);
        this.fieldTypes = fieldTypes;
    }

    @Override
    public int typArray() {
        return 2287;
    }

    @Override
    public String typeCategory() {
        return TypeCategory.PSEUDO.code();
    }

    @Override
    public String type() {
        return Type.PSEUDO.code();
    }

    @Override
    public Regproc typSend() {
        return Regproc.of(NAME + "_send");
    }

    @Override
    public Regproc typReceive() {
        return Regproc.of(NAME + "_recv");
    }

    @SuppressWarnings({"unchecked", "rawtypes"})
    @Override
    public int writeAsBinary(ByteBuf buffer, Row record) {
        final int startWriterIndex = buffer.writerIndex();
        buffer.writeInt(0); // reserve space for the length of the record; updated later
        buffer.writeInt(fieldTypes.size());
        int bytesWritten = 4;
        for (int i = 0; i < fieldTypes.size(); i++) {
            PGType fieldType = fieldTypes.get(i);

            buffer.writeInt(fieldType.oid());
            bytesWritten += 4;

            var value = record.get(i);
            if (value == null) {
                buffer.writeInt(-1); // -1 data length signals a NULL
                continue;
            }

            bytesWritten += fieldType.writeAsBinary(buffer, value);
        }
        buffer.setInt(startWriterIndex, bytesWritten);
        return 4 + bytesWritten;
    }

    @Override
    public Row readBinaryValue(ByteBuf buffer, int valueLength) {
        throw new UnsupportedOperationException("Input of anonymous record type values is not implemented");
    }

    @SuppressWarnings({"unchecked", "rawtypes"})
    @Override
    byte[] encodeAsUTF8Text(Row record) {<FILL_FUNCTION_BODY>}

    @Override
    Row decodeUTF8Text(byte[] bytes) {
        throw new UnsupportedOperationException("Input of record type values is not implemented");
    }
}

        ByteArrayList bytes = new ByteArrayList();
        // See PostgreSQL src/backend/utils/adt/rowtypes.c record_out(PG_FUNCTION_ARGS)
        bytes.add((byte) '(');
        for (int i = 0; i < record.numColumns(); i++) {
            PGType fieldType = fieldTypes.get(i);
            var value = record.get(i);

            if (i > 0) {
                bytes.add((byte) ',');
            }
            if (value == null) {
                continue;
            }

            byte[] encodedValue = fieldType.encodeAsUTF8Text(value);
            boolean needQuotes = encodedValue.length == 0;
            for (int j = 0; j < encodedValue.length; j++) {
                char c = (char) encodedValue[j];
                if (c == '"' || c == '\\' || c == '(' || c == ')' || c == ',' || Character.isWhitespace(c)) {
                    needQuotes = true;
                    break;
                }
            }
            if (needQuotes) {
                bytes.add((byte) '\"');
            }
            bytes.add(encodedValue);
            if (needQuotes) {
                bytes.add((byte) '\"');
            }
        }
        bytes.add((byte) ')');
        return bytes.toArray();
    
<methods>public int oid() ,public abstract io.crate.data.Row readBinaryValue(ByteBuf, int) ,public io.crate.data.Row readTextValue(ByteBuf, int) ,public abstract int typArray() ,public java.lang.String typDelim() ,public int typElem() ,public io.crate.types.Regproc typInput() ,public java.lang.String typName() ,public io.crate.types.Regproc typOutput() ,public io.crate.types.Regproc typReceive() ,public io.crate.types.Regproc typSend() ,public abstract java.lang.String type() ,public abstract java.lang.String typeCategory() ,public short typeLen() ,public int typeMod() ,public abstract int writeAsBinary(ByteBuf, io.crate.data.Row) ,public int writeAsText(ByteBuf, io.crate.data.Row) <variables>static final int INT32_BYTE_SIZE,private static final Logger LOGGER,private final non-sealed int oid,private final non-sealed java.lang.String typName,private final non-sealed int typeLen,private final non-sealed int typeMod