@Override public void write(DataOutput out) throws IOException { int numCol = colType.length; boolean[] nullBits = new boolean[numCol]; int[] colLength = new int[numCol]; byte[] enumType = new byte[numCol]; int[] padLength = new int[numCol]; byte[] padbytes = new byte[8]; /** * Compute the total payload and header length header = total length (4 byte), Version (2 byte), * Error (1 byte), #col (2 byte) col type array = #col * 1 byte null bit array = ceil(#col/8) */ int datlen = 4 + 2 + 1 + 2; datlen += numCol; datlen += getNullByteArraySize(numCol); for (int i = 0; i < numCol; i++) { /* Get the enum type */ DBType coldbtype; switch (DataType.get(colType[i])) { case BIGINT: coldbtype = DBType.BIGINT; break; case BOOLEAN: coldbtype = DBType.BOOLEAN; break; case FLOAT8: coldbtype = DBType.FLOAT8; break; case INTEGER: coldbtype = DBType.INTEGER; break; case REAL: coldbtype = DBType.REAL; break; case SMALLINT: coldbtype = DBType.SMALLINT; break; case BYTEA: coldbtype = DBType.BYTEA; break; default: coldbtype = DBType.TEXT; } enumType[i] = (byte) (coldbtype.ordinal()); /* Get the actual value, and set the null bit */ if (colValue[i] == null) { nullBits[i] = true; colLength[i] = 0; } else { nullBits[i] = false; /* * For fixed length type, we get the fixed length. * For var len binary format, the length is in the col value. * For text format, we must convert encoding first. */ if (!coldbtype.isVarLength()) { colLength[i] = coldbtype.getTypeLength(); } else if (!isTextForm(colType[i])) { colLength[i] = ((byte[]) colValue[i]).length; } else { colLength[i] = ((String) colValue[i]).getBytes(CHARSET).length; } /* calculate and add the type alignment padding */ padLength[i] = roundUpAlignment(datlen, coldbtype.getAlignment()) - datlen; datlen += padLength[i]; /* for variable length type, we add a 4 byte length header */ if (coldbtype.isVarLength()) { datlen += 4; } } datlen += colLength[i]; } /* * Add the final alignment padding for the next record */ int endpadding = roundUpAlignment(datlen, 8) - datlen; datlen += endpadding; /* Construct the packet header */ out.writeInt(datlen); out.writeShort(VERSION); out.writeByte(errorFlag); out.writeShort(numCol); /* Write col type */ for (int i = 0; i < numCol; i++) { out.writeByte(enumType[i]); } /* Nullness */ byte[] nullBytes = boolArrayToByteArray(nullBits); out.write(nullBytes); /* Column Value */ for (int i = 0; i < numCol; i++) { if (!nullBits[i]) { /* Pad the alignment byte first */ if (padLength[i] > 0) { out.write(padbytes, 0, padLength[i]); } /* Now, write the actual column value */ switch (DataType.get(colType[i])) { case BIGINT: out.writeLong(((Long) colValue[i])); break; case BOOLEAN: out.writeBoolean(((Boolean) colValue[i])); break; case FLOAT8: out.writeDouble(((Double) colValue[i])); break; case INTEGER: out.writeInt(((Integer) colValue[i])); break; case REAL: out.writeFloat(((Float) colValue[i])); break; case SMALLINT: out.writeShort(((Short) colValue[i])); break; /* For BYTEA format, add 4byte length header at the beginning */ case BYTEA: out.writeInt(colLength[i]); out.write((byte[]) colValue[i]); break; /* For text format, add 4byte length header. string is already '\0' terminated */ default: { out.writeInt(colLength[i]); byte[] data = ((String) colValue[i]).getBytes(CHARSET); out.write(data); break; } } } } /* End padding */ out.write(padbytes, 0, endpadding); }