Search in sources :

Example 1 with ValueEncoder

use of com.mysql.cj.protocol.a.ValueEncoder in project aws-mysql-jdbc by awslabs.

the class ServerPreparedQuery method prepareExecutePacket.

public NativePacketPayload prepareExecutePacket() {
    ServerPreparedQueryBindValue[] parameterBindings = this.queryBindings.getBindValues();
    if (this.queryBindings.isLongParameterSwitchDetected()) {
        // Check when values were bound
        boolean firstFound = false;
        long boundTimeToCheck = 0;
        for (int i = 0; i < this.parameterCount - 1; i++) {
            if (parameterBindings[i].isStream()) {
                if (firstFound && boundTimeToCheck != parameterBindings[i].boundBeforeExecutionNum) {
                    throw ExceptionFactory.createException(Messages.getString("ServerPreparedStatement.11") + Messages.getString("ServerPreparedStatement.12"), MysqlErrorNumbers.SQL_STATE_DRIVER_NOT_CAPABLE, 0, true, null, this.session.getExceptionInterceptor());
                }
                firstFound = true;
                boundTimeToCheck = parameterBindings[i].boundBeforeExecutionNum;
            }
        }
        // Okay, we've got all "newly"-bound streams, so reset server-side state to clear out previous bindings
        serverResetStatement();
    }
    this.queryBindings.checkAllParametersSet();
    // 
    for (int i = 0; i < this.parameterCount; i++) {
        if (parameterBindings[i].isStream()) {
            serverLongData(i, parameterBindings[i]);
        }
    }
    // 
    // store the parameter values
    // 
    NativePacketPayload packet = this.session.getSharedSendPacket();
    packet.writeInteger(IntegerDataType.INT1, NativeConstants.COM_STMT_EXECUTE);
    packet.writeInteger(IntegerDataType.INT4, this.serverStatementId);
    boolean supportsQueryAttributes = this.session.getServerSession().supportsQueryAttributes();
    boolean sendQueryAttributes = false;
    if (supportsQueryAttributes) {
        // Servers between 8.0.23 8.0.25 are affected by Bug#103102, Bug#103268 and Bug#103377. Query attributes cannot be sent to these servers.
        sendQueryAttributes = this.session.getServerSession().getServerVersion().meetsMinimum(new ServerVersion(8, 0, 26));
    } else if (this.queryAttributesBindings.getCount() > 0) {
        this.session.getLog().logWarn(Messages.getString("QueryAttributes.SetButNotSupported"));
    }
    byte flags = 0;
    if (this.resultFields != null && this.resultFields.getFields() != null && this.useCursorFetch && this.resultSetType == Type.FORWARD_ONLY && this.fetchSize > 0) {
        // we only create cursor-backed result sets if
        // a) The query is a SELECT
        // b) The server supports it
        // c) We know it is forward-only (note this doesn't preclude updatable result sets)
        // d) The user has set a fetch size
        flags |= OPEN_CURSOR_FLAG;
    }
    if (sendQueryAttributes) {
        flags |= PARAMETER_COUNT_AVAILABLE;
    }
    packet.writeInteger(IntegerDataType.INT1, flags);
    // placeholder for parameter iterations
    packet.writeInteger(IntegerDataType.INT4, 1);
    int parametersAndAttributesCount = this.parameterCount;
    if (supportsQueryAttributes) {
        if (sendQueryAttributes) {
            parametersAndAttributesCount += this.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 (this.queryBindings.getSendTypesToServer().get() || sendQueryAttributes && this.queryAttributesBindings.getCount() > 0) {
            packet.writeInteger(IntegerDataType.INT1, 1);
            // Store types of parameters in the first package that is sent to the server.
            for (int i = 0; i < this.parameterCount; i++) {
                packet.writeInteger(IntegerDataType.INT2, parameterBindings[i].bufferType);
                if (supportsQueryAttributes) {
                    // Parameters have no names.
                    packet.writeBytes(StringSelfDataType.STRING_LENENC, "".getBytes());
                }
            }
            if (sendQueryAttributes) {
                this.queryAttributesBindings.runThroughAll(a -> {
                    packet.writeInteger(IntegerDataType.INT2, a.getType());
                    packet.writeBytes(StringSelfDataType.STRING_LENENC, a.getName().getBytes());
                });
            }
        } else {
            packet.writeInteger(IntegerDataType.INT1, 0);
        }
        // Store the parameter values.
        for (int i = 0; i < this.parameterCount; i++) {
            if (!parameterBindings[i].isStream()) {
                if (!parameterBindings[i].isNull()) {
                    parameterBindings[i].storeBinding(packet, this.queryBindings.isLoadDataQuery(), this.charEncoding, this.session.getExceptionInterceptor());
                } else {
                    nullBitsBuffer[i >>> 3] |= (1 << (i & 7));
                }
            }
        }
        if (sendQueryAttributes) {
            for (int i = 0; i < this.queryAttributesBindings.getCount(); i++) {
                if (this.queryAttributesBindings.getAttributeValue(i).isNull()) {
                    int b = i + this.parameterCount;
                    nullBitsBuffer[b >>> 3] |= 1 << (b & 7);
                }
            }
            ValueEncoder valueEncoder = new ValueEncoder(packet, this.charEncoding, this.session.getServerSession().getDefaultTimeZone());
            this.queryAttributesBindings.runThroughAll(a -> valueEncoder.encodeValue(a.getValue(), a.getType()));
        }
        // 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);
    }
    return packet;
}
Also used : ValueEncoder(com.mysql.cj.protocol.a.ValueEncoder) NativePacketPayload(com.mysql.cj.protocol.a.NativePacketPayload)

Example 2 with ValueEncoder

use of com.mysql.cj.protocol.a.ValueEncoder in project aws-mysql-jdbc by awslabs.

the class AbstractPreparedQuery method fillSendPacket.

/**
 * Creates the packet that contains the query to be sent to the server.
 *
 * @param bindings
 *            values
 *
 * @return a Buffer filled with the query that represents this statement
 */
@SuppressWarnings("unchecked")
@Override
public <M extends Message> M fillSendPacket(QueryBindings<?> bindings) {
    synchronized (this) {
        BindValue[] bindValues = bindings.getBindValues();
        NativePacketPayload sendPacket = this.session.getSharedSendPacket();
        sendPacket.writeInteger(IntegerDataType.INT1, NativeConstants.COM_QUERY);
        if (getSession().getServerSession().supportsQueryAttributes()) {
            if (this.queryAttributesBindings.getCount() > 0) {
                sendPacket.writeInteger(IntegerDataType.INT_LENENC, this.queryAttributesBindings.getCount());
                // parameter_set_count (always 1)
                sendPacket.writeInteger(IntegerDataType.INT_LENENC, 1);
                byte[] nullBitsBuffer = new byte[(this.queryAttributesBindings.getCount() + 7) / 8];
                for (int i = 0; i < this.queryAttributesBindings.getCount(); i++) {
                    if (this.queryAttributesBindings.getAttributeValue(i).isNull()) {
                        nullBitsBuffer[i >>> 3] |= 1 << (i & 7);
                    }
                }
                sendPacket.writeBytes(StringLengthDataType.STRING_VAR, nullBitsBuffer);
                // new_params_bind_flag (always 1)
                sendPacket.writeInteger(IntegerDataType.INT1, 1);
                this.queryAttributesBindings.runThroughAll(a -> {
                    sendPacket.writeInteger(IntegerDataType.INT2, a.getType());
                    sendPacket.writeBytes(StringSelfDataType.STRING_LENENC, a.getName().getBytes());
                });
                ValueEncoder valueEncoder = new ValueEncoder(sendPacket, this.charEncoding, this.session.getServerSession().getDefaultTimeZone());
                this.queryAttributesBindings.runThroughAll(a -> valueEncoder.encodeValue(a.getValue(), a.getType()));
            } else {
                sendPacket.writeInteger(IntegerDataType.INT_LENENC, 0);
                // parameter_set_count (always 1)
                sendPacket.writeInteger(IntegerDataType.INT_LENENC, 1);
            }
        } else if (this.queryAttributesBindings.getCount() > 0) {
            this.session.getLog().logWarn(Messages.getString("QueryAttributes.SetButNotSupported"));
        }
        sendPacket.setTag("QUERY");
        boolean useStreamLengths = this.useStreamLengthsInPrepStmts.getValue();
        // 
        // Try and get this allocation as close as possible for BLOBs
        // 
        int ensurePacketSize = 0;
        String statementComment = this.session.getProtocol().getQueryComment();
        byte[] commentAsBytes = null;
        if (statementComment != null) {
            commentAsBytes = StringUtils.getBytes(statementComment, this.charEncoding);
            ensurePacketSize += commentAsBytes.length;
            // for /*[space] [space]*/
            ensurePacketSize += 6;
        }
        for (int i = 0; i < bindValues.length; i++) {
            if (bindValues[i].isStream() && useStreamLengths) {
                ensurePacketSize += bindValues[i].getStreamLength();
            }
        }
        if (ensurePacketSize != 0) {
            sendPacket.ensureCapacity(ensurePacketSize);
        }
        if (commentAsBytes != null) {
            sendPacket.writeBytes(StringLengthDataType.STRING_FIXED, Constants.SLASH_STAR_SPACE_AS_BYTES);
            sendPacket.writeBytes(StringLengthDataType.STRING_FIXED, commentAsBytes);
            sendPacket.writeBytes(StringLengthDataType.STRING_FIXED, Constants.SPACE_STAR_SLASH_SPACE_AS_BYTES);
        }
        byte[][] staticSqlStrings = this.parseInfo.getStaticSql();
        for (int i = 0; i < bindValues.length; i++) {
            bindings.checkParameterSet(i);
            sendPacket.writeBytes(StringLengthDataType.STRING_FIXED, staticSqlStrings[i]);
            if (bindValues[i].isStream()) {
                streamToBytes(sendPacket, bindValues[i].getStreamValue(), true, bindValues[i].getStreamLength(), useStreamLengths);
            } else {
                sendPacket.writeBytes(StringLengthDataType.STRING_FIXED, bindValues[i].getByteValue());
            }
        }
        sendPacket.writeBytes(StringLengthDataType.STRING_FIXED, staticSqlStrings[bindValues.length]);
        return (M) sendPacket;
    }
}
Also used : ValueEncoder(com.mysql.cj.protocol.a.ValueEncoder) NativePacketPayload(com.mysql.cj.protocol.a.NativePacketPayload)

Aggregations

NativePacketPayload (com.mysql.cj.protocol.a.NativePacketPayload)2 ValueEncoder (com.mysql.cj.protocol.a.ValueEncoder)2