/** * <pre> * This program is free software; you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, * or (at your option) any later version. * * 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 General Public License for more details. * You should have received a copy of the GNU General Public License along with this program; * if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * </pre> */ package com.meidusa.amoeba.mysql.handler; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import com.meidusa.amoeba.mysql.net.CommandInfo; import com.meidusa.amoeba.mysql.net.MysqlClientConnection; import com.meidusa.amoeba.mysql.net.MysqlServerConnection; import com.meidusa.amoeba.mysql.net.packet.CommandPacket; import com.meidusa.amoeba.mysql.net.packet.MysqlPacketBuffer; import com.meidusa.amoeba.mysql.net.packet.OKforPreparedStatementPacket; import com.meidusa.amoeba.mysql.net.packet.PreparedStatmentClosePacket; import com.meidusa.amoeba.mysql.net.packet.QueryCommandPacket; import com.meidusa.amoeba.net.Connection; import com.meidusa.amoeba.net.poolable.ObjectPool; /** * @author <a href=mailto:piratebase@sina.com>Struct chen</a> */ public class PreparedStatmentMessageHandler extends QueryCommandMessageHandler { static class PreparedStatmentSessionStatus extends SessionStatus { public static final int PREPAED_PARAMETER_EOF = 2048; public static final int PREPAED_FIELD_EOF = 4096; } static class PreparedStatmentConnectionStatuts extends QueryCommandMessageHandler.QueryConnectionStatus { OKforPreparedStatementPacket ok = null; public PreparedStatmentConnectionStatuts(Connection conn, PreparedStatmentInfo preparedStatmentInfo){ super(conn); } /** * packet step: 1:OKforPreparedStatementPacket, (parameters ==0,columns==0) end; parameters>0 [ * n*parameterFieldPacket,PREPAED_PARAMETER_EOF] columns>0 [n * columnPacket,PREPAED_FIELD_EOF] mysql version * 5.0.0 no parameter field packet */ @Override public boolean isCompleted(byte[] buffer) { if (this.commandType == QueryCommandPacket.COM_STMT_PREPARE) { MysqlServerConnection connection = (MysqlServerConnection) conn; if (MysqlPacketBuffer.isEofPacket(buffer)) { if (ok.parameters > 0 && ok.columns > 0) { if ((this.statusCode & PreparedStatmentSessionStatus.PREPAED_PARAMETER_EOF) > 0) { this.statusCode |= PreparedStatmentSessionStatus.PREPAED_FIELD_EOF; this.statusCode |= PreparedStatmentSessionStatus.COMPLETED; return true; } else { if (connection.isVersion(5, 0, 0)) { if (ok.columns == 0) { this.statusCode |= PreparedStatmentSessionStatus.PREPAED_FIELD_EOF; this.statusCode |= PreparedStatmentSessionStatus.COMPLETED; return true; } } this.statusCode |= PreparedStatmentSessionStatus.PREPAED_PARAMETER_EOF; return false; } } else { this.statusCode |= PreparedStatmentSessionStatus.PREPAED_FIELD_EOF; this.statusCode |= PreparedStatmentSessionStatus.COMPLETED; return true; } } else if (MysqlPacketBuffer.isErrorPacket(buffer)) { this.statusCode |= PreparedStatmentSessionStatus.ERROR; this.statusCode |= PreparedStatmentSessionStatus.COMPLETED; return true; } else if (packetIndex == 0 && MysqlPacketBuffer.isOkPacket(buffer)) { ok = new OKforPreparedStatementPacket(); ok.init(buffer, null); if (ok.parameters == 0 && ok.columns == 0) { this.statusCode |= PreparedStatmentSessionStatus.OK; this.statusCode |= PreparedStatmentSessionStatus.COMPLETED; return true; } else { if (connection.isVersion(5, 0, 0)) { if (ok.columns == 0) { this.statusCode |= PreparedStatmentSessionStatus.OK; this.statusCode |= PreparedStatmentSessionStatus.COMPLETED; return true; } } return false; } } return false; } else if (this.commandType == QueryCommandPacket.COM_STMT_CLOSE) { if (MysqlPacketBuffer.isErrorPacket(buffer)) { this.statusCode |= PreparedStatmentSessionStatus.ERROR; this.statusCode |= PreparedStatmentSessionStatus.COMPLETED; return true; } else { this.statusCode |= PreparedStatmentSessionStatus.COMPLETED; return true; } } else { return super.isCompleted(buffer); } } } protected PreparedStatmentInfo preparedStatmentInfo = null; /** ��ǰ���������ݰ� */ private Map<Connection, Long> statmentIdMap = Collections.synchronizedMap(new HashMap<Connection, Long>()); public PreparedStatmentMessageHandler(MysqlClientConnection source, PreparedStatmentInfo preparedStatmentInfo, byte[] query, ObjectPool[] pools, long timeout){ super(source, query, pools, timeout); this.preparedStatmentInfo = preparedStatmentInfo; } protected void afterCommandCompleted(CommandInfo currentCommand) { if (commandType == QueryCommandPacket.COM_STMT_PREPARE) { Collection<ConnectionStatuts> collection = this.commandQueue.connStatusMap.values(); for (ConnectionStatuts status : collection) { byte[] buffer = status.buffers.get(0); OKforPreparedStatementPacket ok = new OKforPreparedStatementPacket(); ok.init(buffer, source); statmentIdMap.put(status.conn, ok.statementHandlerId); } } super.afterCommandCompleted(currentCommand); } @Override protected List<byte[]> mergeMessages() { if (commandType == QueryCommandPacket.COM_STMT_PREPARE) { List<byte[]> list = new ArrayList<byte[]>(16); Collection<ConnectionStatuts> statusList = this.commandQueue.connStatusMap.values(); ConnectionStatuts status = statusList.iterator().next(); list.addAll(status.buffers); return list; } else { return super.mergeMessages(); } } /** * �滻��Ӧ�� prepared Statment id��������Ӧ�����ݰ�,������� preparedStatmentInfo ��һЩ��Ϣ */ protected void dispatchMessageTo(Connection toConn, byte[] message) { if (toConn == source) { if (commandType == QueryCommandPacket.COM_STMT_PREPARE) { /* * if(MysqlPacketBuffer.isOkPacket(message)){ //�滻statmentId Ϊ proxy statment id ���͵�mysql�ͻ��� * OKforPreparedStatementPacket ok = new OKforPreparedStatementPacket(); ok.init(message,toConn); * ok.statementHandlerId = preparedStatmentInfo.getStatmentId(); preparedStatmentInfo.setOkPrepared(ok); * message = ok.toByteBuffer(toConn).array(); } */ return; } } else { if (commandType == CommandPacket.COM_STMT_EXECUTE || commandType == CommandPacket.COM_STMT_SEND_LONG_DATA || commandType == CommandPacket.COM_STMT_CLOSE) { Long id = statmentIdMap.get(toConn); message[5] = (byte) (id & 0xff); message[6] = (byte) (id >>> 8); message[7] = (byte) (id >>> 16); message[8] = (byte) (id >>> 24); } } super.dispatchMessageTo(toConn, message); } protected void appendAfterMainCommand() { super.appendAfterMainCommand(); PreparedStatmentClosePacket preparedCloseCommandPacket = new PreparedStatmentClosePacket(); preparedCloseCommandPacket.command = CommandPacket.COM_STMT_CLOSE; final byte[] buffer = preparedCloseCommandPacket.toByteBuffer(source).array(); CommandInfo info = new CommandInfo(); info.setBuffer(buffer); info.setMain(false); info.getCompletedCount().set(commandQueue.connStatusMap.size()); info.setRunnable(new Runnable() { public void run() { Set<MysqlServerConnection> connSet = commandQueue.connStatusMap.keySet(); for (Connection conn : connSet) { statmentIdMap.remove(conn); } } }); commandQueue.appendCommand(info, true); } @Override protected ConnectionStatuts newConnectionStatuts(Connection conn) { return new PreparedStatmentConnectionStatuts(conn, this.preparedStatmentInfo); } }