in src/main/protocol-impl/java/com/mysql/cj/protocol/a/NativeMessageBuilder.java [378:477]
public NativePacketPayload buildComStmtExecute(NativePacketPayload sharedPacket, long serverStatementId, byte flags, boolean sendQueryAttributes,
PreparedQuery preparedQuery) {
NativePacketPayload packet = sharedPacket != null ? sharedPacket : new NativePacketPayload(5);
Session sess = preparedQuery.getSession();
int parameterCount = preparedQuery.getParameterCount();
QueryBindings queryBindings = preparedQuery.getQueryBindings();
BindValue[] parameterBindings = queryBindings.getBindValues();
QueryAttributesBindings queryAttributesBindings = preparedQuery.getQueryAttributesBindings();
packet.writeInteger(IntegerDataType.INT1, NativeConstants.COM_STMT_EXECUTE);
packet.writeInteger(IntegerDataType.INT4, serverStatementId);
packet.writeInteger(IntegerDataType.INT1, flags);
packet.writeInteger(IntegerDataType.INT4, 1); // placeholder for parameter iterations
boolean contextPropagationAttributeWasInjected = false;
int parametersAndAttributesCount = parameterCount;
if (this.supportsQueryAttributes) {
if (sendQueryAttributes) {
if (!queryAttributesBindings.containsAttribute(sess.getTelemetryHandler().getContextPropagationKey())) {
sess.getTelemetryHandler().propagateContext(queryAttributesBindings::setAttribute);
contextPropagationAttributeWasInjected = true;
}
parametersAndAttributesCount += queryAttributesBindings.getCount();
}
if (sendQueryAttributes || parametersAndAttributesCount > 0) {
// Servers between 8.0.23 and 8.0.25 don't expect a 'parameter_count' value if the statement was prepared without parameters.
packet.writeInteger(IntegerDataType.INT_LENENC, parametersAndAttributesCount);
}
}
if (parametersAndAttributesCount > 0) {
/* Reserve place for null-marker bytes */
int nullCount = (parametersAndAttributesCount + 7) / 8;
int nullBitsPosition = packet.getPosition();
for (int i = 0; i < nullCount; i++) {
packet.writeInteger(IntegerDataType.INT1, 0);
}
byte[] nullBitsBuffer = new byte[nullCount];
// In case if buffers (type) changed or there are query attributes to send.
if (queryBindings.getSendTypesToServer().get() || sendQueryAttributes && queryAttributesBindings.getCount() > 0) {
packet.writeInteger(IntegerDataType.INT1, 1);
// Store types of parameters in the first packet that is sent to the server.
for (int i = 0; i < parameterCount; i++) {
packet.writeInteger(IntegerDataType.INT2, parameterBindings[i].getFieldType());
if (this.supportsQueryAttributes) {
packet.writeBytes(StringSelfDataType.STRING_LENENC, "".getBytes()); // Parameters have no names.
}
}
if (sendQueryAttributes) {
queryAttributesBindings.runThroughAll(a -> {
packet.writeInteger(IntegerDataType.INT2, a.getFieldType());
packet.writeBytes(StringSelfDataType.STRING_LENENC, a.getName().getBytes());
});
}
} else {
packet.writeInteger(IntegerDataType.INT1, 0);
}
// Store the parameter values.
for (int i = 0; i < parameterCount; i++) {
if (!parameterBindings[i].isStream()) {
if (!parameterBindings[i].isNull()) {
parameterBindings[i].writeAsBinary(packet);
} else {
nullBitsBuffer[i >>> 3] |= 1 << (i & 7);
}
}
}
if (sendQueryAttributes) {
for (int i = 0; i < queryAttributesBindings.getCount(); i++) {
if (queryAttributesBindings.getAttributeValue(i).isNull()) {
int b = i + parameterCount;
nullBitsBuffer[b >>> 3] |= 1 << (b & 7);
}
}
queryAttributesBindings.runThroughAll(a -> {
if (!a.isNull()) {
a.writeAsQueryAttribute(packet);
}
});
}
// Go back and write the NULL flags to the beginning of the packet
int endPosition = packet.getPosition();
packet.setPosition(nullBitsPosition);
packet.writeBytes(StringLengthDataType.STRING_FIXED, nullBitsBuffer);
packet.setPosition(endPosition);
}
if (contextPropagationAttributeWasInjected) {
queryAttributesBindings.removeAttribute(sess.getTelemetryHandler().getContextPropagationKey());
}
return packet;
}