/* * Copyright (c) 2013, OpenCloudDB/MyCAT and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software;Designed and Developed mainly by many Chinese * opensource volunteers. you can redistribute it and/or modify it under the * terms of the GNU General Public License version 2 only, as published by the * Free Software Foundation. * * This code 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 * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Any questions about this component can be directed to it's project Web address * https://code.google.com/p/opencloudb/. * */ package org.opencloudb.net.mysql; import io.netty.channel.ChannelHandlerContext; import java.io.UnsupportedEncodingException; import org.apache.log4j.Logger; import org.opencloudb.config.ErrorCode; import org.opencloudb.mysql.MySQLMessage; import org.opencloudb.net.ChannelDataHandler; import org.opencloudb.net.ConnectionInfo; import org.opencloudb.net.FrontSession; import org.opencloudb.server.parser.ServerParse; /** * 前端命令处理器 * * @author mycat */ public class FrontendCommandHandler implements ChannelDataHandler { private static final Logger LOGGER = Logger .getLogger(FrontendCommandHandler.class); public static FrontendCommandHandler INSTANCE = new FrontendCommandHandler(); @Override public void handle(ChannelHandlerContext ctx, byte[] data) { FrontSession session = NettyUtil.getFrontSession(ctx); switch (data[4]) { case MySQLPacket.COM_INIT_DB: initDB(ctx, data); break; case MySQLPacket.COM_QUERY: queryCmd(session, data); break; case MySQLPacket.COM_PING: ping(session); break; case MySQLPacket.COM_QUIT: LOGGER.info("quit comd ,close connection"); NettyUtil.getFrontSession(ctx).close("quit cmd"); break; case MySQLPacket.COM_PROCESS_KILL: kill(session, data); break; case MySQLPacket.COM_STMT_PREPARE: notSupported(session, data); break; case MySQLPacket.COM_STMT_EXECUTE: notSupported(session, data); break; case MySQLPacket.COM_STMT_CLOSE: notSupported(session, data); break; case MySQLPacket.COM_HEARTBEAT: heartbeat(session, data); break; default: notSupported(session, data); } } public void initDB(ChannelHandlerContext ctx, byte[] data) { MySQLMessage mm = new MySQLMessage(data); mm.position(5); String db = mm.readString(); FrontSession session = NettyUtil.getFrontSession(ctx); ConnectionInfo conInfo=session.getConInfo(); String user = conInfo.getUser(); if (!FrontendAuthenticator.schemaAllowed(ctx, db, user, conInfo.getHost())) { return; } conInfo.setSchema(db); NettyUtil.writeBytes(ctx, OkPacket.OK); } public void queryCmd(FrontSession session, byte[] data) { ConnectionInfo conInfo = session.getConInfo(); // 取得语句 MySQLMessage mm = new MySQLMessage(data); mm.position(5); String sql = null; String charSet = conInfo.getCharset(); try { sql = mm.readString(charSet); } catch (UnsupportedEncodingException e) { session.writeErrMessage(ErrorCode.ER_UNKNOWN_CHARACTER_SET, "Unknown charset '" + charSet + "'"); return; } if (sql == null || sql.isEmpty()) { session.writeErrMessage(ErrorCode.ER_NOT_ALLOWED_COMMAND, "Empty SQL"); return; } // remove last ';' if (sql.endsWith(";")) { sql = sql.substring(0, sql.length() - 1); } // 执行查询 query(session, sql); } private void ping(FrontSession session) { session.writeOK(); } private void heartbeat(FrontSession session, byte[] data) { session.writeOK(); } private void kill(FrontSession session, byte[] data) { session.writeErrMessage(ErrorCode.ER_UNKNOWN_COM_ERROR, "Unknown command"); } private void notSupported(FrontSession session, byte[] data) { session.writeErrMessage(ErrorCode.ER_UNKNOWN_COM_ERROR, "Not supported yet"); } public void unknown(FrontSession session, byte[] data) { session.writeErrMessage(ErrorCode.ER_UNKNOWN_COM_ERROR, "Unknown command"); } public void query(FrontSession session, String sql) { if (LOGGER.isDebugEnabled()) { LOGGER.debug(new StringBuilder() .append(session.getCtx().channel().remoteAddress()) .append(sql).toString()); } // int rs = ServerParse.parse(sql); int sqlType = rs & 0xff; switch (sqlType) { case ServerParse.EXPLAIN: ExplainHandler.handle(sql, session, rs >>> 8); break; case ServerParse.SET: SetHandler.handle(sql, session, rs >>> 8); break; case ServerParse.SHOW: ShowHandler.handle(sql, session, rs >>> 8); break; case ServerParse.SELECT: SelectHandler.handle(sql, session, rs >>> 8); break; case ServerParse.START: StartHandler.handle(sql, session, rs >>> 8); break; case ServerParse.BEGIN: BeginHandler.handle(sql, session); break; case ServerParse.SAVEPOINT: SavepointHandler.handle(sql, session); break; case ServerParse.KILL: KillHandler.handle(sql, rs >>> 8, session); break; case ServerParse.KILL_QUERY: LOGGER.warn(new StringBuilder().append("Unsupported command:") .append(sql).toString()); session.writeErrMessage(ErrorCode.ER_UNKNOWN_COM_ERROR, "Unsupported command"); break; case ServerParse.USE: UseHandler.handle(sql, session, rs >>> 8); break; case ServerParse.COMMIT: session.commit(); break; case ServerParse.ROLLBACK: session.rollback(); break; case ServerParse.HELP: LOGGER.warn(new StringBuilder().append("Unsupported command:") .append(sql).toString()); session.writeErrMessage(ErrorCode.ER_SYNTAX_ERROR, "Unsupported command"); break; case ServerParse.MYSQL_CMD_COMMENT: session.writeOK(); break; case ServerParse.MYSQL_COMMENT: session.writeOK(); break; default: if (session.isReadOnly()) { LOGGER.warn(new StringBuilder().append("User readonly:") .append(sql).toString()); session.writeErrMessage(ErrorCode.ER_USER_READ_ONLY, "User readonly"); break; } session.execute(sql, rs & 0xff); } } }