package io.vertx.mysqlclient.impl.codec;
import io.netty.buffer.ByteBuf;
import io.vertx.core.buffer.Buffer;
import io.vertx.mysqlclient.impl.MySQLCollation;
import io.vertx.sqlclient.Tuple;
import io.vertx.sqlclient.impl.command.ExtendedQueryCommandBase;
import java.nio.charset.StandardCharsets;
import java.nio.charset.Charset;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import static io.vertx.mysqlclient.impl.codec.Packets.*;
abstract class ExtendedQueryCommandBaseCodec<R, C extends ExtendedQueryCommandBase<R>> extends QueryCommandBaseCodec<R, C> {
protected final byte sendType = 1;
protected final MySQLPreparedStatement statement;
ExtendedQueryCommandBaseCodec(C cmd) {
super(cmd, DataFormat.BINARY);
statement = (MySQLPreparedStatement) cmd.preparedStatement();
}
@Override
protected void handleInitPacket(ByteBuf payload) {
int firstByte = payload.getUnsignedByte(payload.readerIndex());
if (firstByte == OK_PACKET_HEADER) {
OkPacket okPacket = decodeOkPacketPayload(payload, StandardCharsets.UTF_8);
handleSingleResultsetDecodingCompleted(okPacket.serverStatusFlags(), (int) okPacket.affectedRows());
} else if (firstByte == ERROR_PACKET_HEADER) {
handleErrorPacketPayload(payload);
} else {
handleResultsetColumnCountPacketBody(payload);
}
}
protected void sendStatementExecuteCommand(long statementId, ColumnDefinition[] paramsColumnDefinitions, byte sendType, Tuple params, byte cursorType) {
ByteBuf packet = allocateBuffer();
int packetStartIdx = packet.writerIndex();
packet.writeMediumLE(0);
packet.writeByte(sequenceId);
packet.writeByte(CommandType.COM_STMT_EXECUTE);
packet.writeIntLE((int) statementId);
packet.writeByte(cursorType);
packet.writeIntLE(1);
int numOfParams = paramsColumnDefinitions.length;
int bitmapLength = (numOfParams + 7) / 8;
byte[] nullBitmap = new byte[bitmapLength];
int pos = packet.writerIndex();
if (numOfParams > 0) {
packet.writeBytes(nullBitmap);
packet.writeByte(sendType);
if (sendType == 1) {
for (int i = 0; i < numOfParams; i++) {
Object value = params.getValue(i);
packet.writeByte(parseDataTypeByEncodingValue(value).id);
packet.writeByte(0);
}
}
for (int i = 0; i < numOfParams; i++) {
Object value = params.getValue(i);
if (value != null) {
MySQLCollation collation = MySQLCollation.valueOfId(paramsColumnDefinitions[i].characterSet());
DataTypeCodec.encodeBinary(parseDataTypeByEncodingValue(value), Charset.forName(collation.mappedJavaCharsetName()), value, packet);
} else {
nullBitmap[i / 8] |= (1 << (i & 7));
}
}
packet.setBytes(pos, nullBitmap);
}
int payloadLength = packet.writerIndex() - packetStartIdx - 4;
packet.setMediumLE(packetStartIdx, payloadLength);
sendPacket(packet, payloadLength);
}
private DataType parseDataTypeByEncodingValue(Object value) {
if (value == null) {
return DataType.NULL;
} else if (value instanceof Byte) {
return DataType.INT1;
} else if (value instanceof Boolean) {
return DataType.INT1;
} else if (value instanceof Short) {
return DataType.INT2;
} else if (value instanceof Integer) {
return DataType.INT4;
} else if (value instanceof Long) {
return DataType.INT8;
} else if (value instanceof Double) {
return DataType.DOUBLE;
} else if (value instanceof Float) {
return DataType.FLOAT;
} else if (value instanceof LocalDate) {
return DataType.DATE;
} else if (value instanceof Duration) {
return DataType.TIME;
} else if (value instanceof Buffer) {
return DataType.BLOB;
} else if (value instanceof LocalDateTime) {
return DataType.DATETIME;
} else {
return DataType.STRING;
}
}
}