com.tesora.dve.db.mysql.portal.protocol.MSPComStmtExecuteRequestMessage.java Source code

Java tutorial

Introduction

Here is the source code for com.tesora.dve.db.mysql.portal.protocol.MSPComStmtExecuteRequestMessage.java

Source

package com.tesora.dve.db.mysql.portal.protocol;

/*
 * #%L
 * Tesora Inc.
 * Database Virtualization Engine
 * %%
 * Copyright (C) 2011 - 2014 Tesora Inc.
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License, version 3,
 * as published by the Free Software Foundation.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 * 
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 * #L%
 */

import com.tesora.dve.db.mysql.MyFieldType;
import com.tesora.dve.db.mysql.common.DBTypeBasedUtils;
import com.tesora.dve.db.mysql.common.MysqlAPIUtils;
import com.tesora.dve.db.mysql.libmy.MyNullBitmap;
import com.tesora.dve.db.mysql.libmy.MyParameter;
import com.tesora.dve.db.mysql.libmy.MyPreparedStatement;
import com.tesora.dve.exceptions.PECodingException;
import com.tesora.dve.exceptions.PEException;
import io.netty.buffer.ByteBuf;
import java.nio.ByteOrder;
import java.util.List;

public class MSPComStmtExecuteRequestMessage extends BaseMSPMessage<MSPComStmtExecuteRequestMessage.ParsedData> {
    public static final MSPComStmtExecuteRequestMessage PROTOTYPE = new MSPComStmtExecuteRequestMessage();
    public static final byte TYPE_IDENTIFIER = (byte) 0x17;

    static class ParsedData {
        long statementID;
        byte flags;
        long iterationCount;
        int metadataOffset;

        MyPreparedStatement<?> metadata;
        List<Object> values;
    }

    protected MSPComStmtExecuteRequestMessage() {
        super();
    }

    protected MSPComStmtExecuteRequestMessage(ByteBuf backing) {
        super(backing);
    }

    protected MSPComStmtExecuteRequestMessage(ParsedData data) {
        super(data);
    }

    @Override
    public byte getMysqlMessageType() {
        return TYPE_IDENTIFIER;
    }

    @Override
    public MSPComStmtExecuteRequestMessage newPrototype(ByteBuf source) {
        source = source.slice();
        return new MSPComStmtExecuteRequestMessage(source);
    }

    @Override
    protected ParsedData unmarshall(ByteBuf source) {
        ParsedData parseValues = new ParsedData();
        source.skipBytes(1);//skip the type identifier.
        parseValues.statementID = source.readUnsignedInt();
        parseValues.flags = source.readByte();
        parseValues.iterationCount = source.readUnsignedInt();
        parseValues.metadataOffset = source.readerIndex();

        //we don't actually unmarshall the metadata and values here, since we don't know how many parameters there are.
        parseValues.metadata = null;
        parseValues.values = null;
        return parseValues;
    }

    @Override
    protected void marshall(ParsedData state, ByteBuf destination) {
        ByteBuf leBuf = destination.order(ByteOrder.LITTLE_ENDIAN);
        leBuf.writeByte(TYPE_IDENTIFIER);
        leBuf.writeInt((int) state.statementID);
        leBuf.writeByte(state.flags);
        leBuf.writeInt((int) state.iterationCount);
        if (state.metadata == null)
            throw new IllegalStateException("Cannot build execute request, no prepare metadata provided.");

        int numParams = state.metadata.getNumParams();
        if (numParams > 0) {
            MyNullBitmap nullBitmap = new MyNullBitmap(numParams, MyNullBitmap.BitmapType.EXECUTE_REQUEST);
            int bitmapIndex = leBuf.writerIndex();
            leBuf.writeZero(nullBitmap.length());
            if (state.metadata.isNewParameterList()) {
                leBuf.writeByte(1);
                for (MyParameter param : state.metadata.getParameters()) {
                    leBuf.writeByte(param.getType().getByteValue());
                    leBuf.writeZero(1);
                }
            } else {
                leBuf.writeZero(1);
            }
            List<Object> params = state.values;
            for (int i = 0; i < params.size(); ++i) {
                if (params.get(i) != null)
                    DBTypeBasedUtils.getJavaTypeFunc(params.get(i).getClass()).writeObject(leBuf, params.get(i));
                else
                    nullBitmap.setBit(i + 1);
            }
            leBuf.setBytes(bitmapIndex, nullBitmap.getBitmapArray());
        }
    }

    public long getStatementID() {
        return readState().statementID;
    }

    public void readParameterMetadata(MyPreparedStatement<String> pStmt) throws PEException {
        //TODO: this belongs in unmarshall, but requires knowledge about the expected number of parameters, provided by a previous prepare response.
        ParsedData cachedParse = readState();
        ByteBuf backingData = readBuffer();
        int lengthOfMetadata = backingData.readableBytes() - cachedParse.metadataOffset;
        ByteBuf in = backingData.slice(cachedParse.metadataOffset, lengthOfMetadata).order(ByteOrder.LITTLE_ENDIAN);
        if (pStmt.getNumParams() > 0) {
            int nullBitmapLength = (pStmt.getNumParams() + 7) / 8;
            MyNullBitmap nullBitmap = new MyNullBitmap(MysqlAPIUtils.readBytes(in, nullBitmapLength),
                    pStmt.getNumParams(), MyNullBitmap.BitmapType.EXECUTE_REQUEST);
            if (in.readByte() == 1) { // this is new params bound flag; only
                // =1 on first stmt_execute
                pStmt.clearParameters();
                for (int i = 0; i < pStmt.getNumParams(); i++) {
                    pStmt.addParameter(new MyParameter(MyFieldType.fromByte(in.readByte())));
                    in.skipBytes(1);
                }
            }

            for (int paramNum = 1; paramNum <= pStmt.getNumParams(); paramNum++) {
                MyParameter parameter = pStmt.getParameter(paramNum);
                if (nullBitmap.getBit(paramNum)) {
                    parameter.setValue(null);
                } else {
                    //TODO - may need to figure out how to get the proper flags and length into this call
                    parameter.setValue(DBTypeBasedUtils.getMysqlTypeFunc(parameter.getType()).readObject(in));
                }
            }
        }
    }

    public static MSPComStmtExecuteRequestMessage newMessage(int statementID,
            MyPreparedStatement<MysqlGroupedPreparedStatementId> metadata, List<Object> values) {
        if (metadata.getNumParams() > 0 && metadata.getNumParams() != values.size())
            throw new PECodingException(
                    "Wrong number of parameters specified for prepared statement execution (expected"
                            + metadata.getNumParams() + ", received " + values.size() + ")");

        ParsedData data = new ParsedData();
        data.statementID = statementID;
        data.flags = 0;
        data.iterationCount = 1;
        data.metadata = metadata;
        data.values = values;
        return new MSPComStmtExecuteRequestMessage(data);
    }

}