package com.meidusa.amoeba.mysql.handler; import org.apache.log4j.Logger; import com.meidusa.amoeba.context.ProxyRuntimeContext; import com.meidusa.amoeba.exception.AmoebaRuntimeException; import com.meidusa.amoeba.mysql.net.MysqlClientConnection; import com.meidusa.amoeba.mysql.net.MysqlConnection; import com.meidusa.amoeba.mysql.net.packet.ConstantPacketBuffer; import com.meidusa.amoeba.mysql.net.packet.ErrorPacket; import com.meidusa.amoeba.net.Sessionable; import com.meidusa.amoeba.parser.expression.Expression; import com.meidusa.amoeba.parser.statement.PropertyStatement; import com.meidusa.amoeba.parser.statement.Statement; import com.meidusa.amoeba.route.SqlBaseQueryRouter; import com.meidusa.amoeba.route.SqlQueryObject; public class PropertyCommand { private long timeout; private MysqlClientConnection conn; public PropertyCommand(long timeout, MysqlClientConnection conn) { this.timeout = timeout; this.conn = conn; } public static Logger logger = Logger.getLogger(PropertyCommand.class); public void execute(Statement statement, SqlQueryObject queryObject) throws Exception { PropertyStatement st = (PropertyStatement) statement; Expression value = null; // set autocommit 语句 if ((value = st.getValue("autocommit")) != null) { setAutocommit(value, queryObject); logger.debug("set autocommit=" + conn.isAutoCommit()); } // set names 语句 else if ((value = st.getValue("names")) != null) { setNames(value, queryObject); logger.debug("set names=" + conn.getCharset()); } // Set 字符集 语句 else if ((value = st.getValue("charset")) != null || (value = st.getValue("character_set_results")) != null) { setCharset(value, queryObject); logger.debug("set charset=" + conn.getCharset()); } // 事务隔离级别语句 else if ((value = st.getValue("transactionisolation")) != null) { conn.setIsolationLevel(((Integer) value.evaluate(null)).intValue()); conn.postMessage(ConstantPacketBuffer.STATIC_OK_BUFFER); logger.debug("set isolationLevel= " + conn.getIsolationLevel()); } // use schema语句 else if ((value = st.getValue("schema")) != null) { setSchema(value, queryObject); logger.debug("use " + conn.getSchema()); } // 标记是否xa else if ((value = st.getValue("isXA")) != null) { if (((Long) value.evaluate(null)).longValue() == 1) { conn.setIsXaActive(true); } else { conn.setIsXaActive(false); } logger.debug("set isXA=" + conn.isXaActive()); conn.postMessage(ConstantPacketBuffer.STATIC_OK_BUFFER); } // 直接忽略不支持的语句 else { logger.warn(queryObject.sql + " is not executed"); conn.postMessage(ConstantPacketBuffer.STATIC_OK_BUFFER); } } private void setAutocommit(Expression value, SqlQueryObject queryObject) throws Exception { if (((Long) value.evaluate(null)).longValue() == 1) { if (conn.getStickyConnMap().size() > 0) { // 构造完提交命令,开始提交 CommitCommand commitCMD = new CommitCommand(timeout, conn); commitCMD.execute(); // 因为session是读写是两个线程,为了让两个线程同步,这里需要阻塞到session结束 Sessionable commitSession = commitCMD.getSession(); if (commitSession == null) { throw new AmoebaRuntimeException("session start error when implict commit execute"); } else { while(!commitSession.isEnded()) { if (commitSession.isEnded()) { break; } } } // 检测会话是否成功执行 if (commitSession.isSuccess()) { conn.setAutoCommit(true); } else { throw new AmoebaRuntimeException("command execute error, pls retry again"); } } else { conn.setAutoCommit(true); conn.postMessage(ConstantPacketBuffer.STATIC_OK_BUFFER); } } else { conn.setAutoCommit(false); conn.postMessage(ConstantPacketBuffer.STATIC_OK_BUFFER); } } private void setSchema(Expression value, SqlQueryObject queryObject) { String schemaName = (String) value.evaluate(queryObject.parameters); String userName = conn.getUser(); SqlBaseQueryRouter router = (SqlBaseQueryRouter) ProxyRuntimeContext.getInstance().getQueryRouter(); if (conn.isAdmin() || router.isSchemaExistedForUser(userName, schemaName)) { conn.setSchema(schemaName); conn.postMessage(ConstantPacketBuffer.STATIC_OK_BUFFER); } else { ErrorPacket error = new ErrorPacket(); error.errno = 1049; error.packetId = 1; error.sqlstate = "42000"; error.serverErrorMessage = "Unknown database=" + schemaName; conn.postMessage(error.toByteBuffer(conn).array()); } } private void setNames(Expression value, SqlQueryObject queryObject) { String names = (String) value.evaluate(queryObject.parameters); if (((MysqlConnection) conn).setCharset(names)) { conn.postMessage(ConstantPacketBuffer.STATIC_OK_BUFFER); } else { ErrorPacket error = new ErrorPacket(); error.errno = 1115; error.packetId = 1; error.sqlstate = "42000"; error.serverErrorMessage = "Unknown charset '" + names + "'"; conn.postMessage(error.toByteBuffer(null).array()); } } private void setCharset(Expression value, SqlQueryObject queryObject) { String charset = (String) value.evaluate(queryObject.parameters); if (charset.equals("null")) { conn.postMessage(ConstantPacketBuffer.STATIC_OK_BUFFER); } else if ( ((MysqlConnection) conn).setCharset(charset)) { conn.postMessage(ConstantPacketBuffer.STATIC_OK_BUFFER); } else { ErrorPacket error = new ErrorPacket(); error.errno = 1115; error.packetId = 1; error.sqlstate = "42000"; error.serverErrorMessage = "Unknown charset '" + charset + "'"; conn.postMessage(error.toByteBuffer(null).array()); } } }