package com.tesora.dve.db.mysql.portal; /* * #%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.libmy.MyErrorResponse; import com.tesora.dve.db.mysql.portal.protocol.MSPComQueryRequestMessage; import com.tesora.dve.db.mysql.portal.protocol.MSPMessage; import io.netty.channel.ChannelHandlerContext; import java.util.concurrent.ExecutorService; import java.util.regex.Pattern; import org.apache.log4j.Logger; import com.tesora.dve.db.mysql.PEMysqlErrorException; import com.tesora.dve.errmap.ErrorMapper; import com.tesora.dve.errmap.FormattedErrorInfo; import com.tesora.dve.exceptions.HasErrorInfo; import com.tesora.dve.exceptions.PEException; import com.tesora.dve.exceptions.PEMappedException; import com.tesora.dve.exceptions.PEMappedRuntimeException; import com.tesora.dve.server.connectionmanager.SSConnection; import com.tesora.dve.server.connectionmanager.messages.ExecuteRequestExecutor; import com.tesora.dve.worker.MysqlTextResultForwarder; public class MSPComQueryRequest extends MSPActionBase { static final Logger logger = Logger.getLogger(MSPComQueryRequest.class); static final Pattern IS_LOAD_DATA_STATEMENT = Pattern.compile("^\\s*load\\s*data.*", Pattern.CASE_INSENSITIVE); public static final MSPComQueryRequest INSTANCE = new MSPComQueryRequest(); public MSPComQueryRequest() { } @Override public void execute(ExecutorService clientExecutorService, ChannelHandlerContext ctx, SSConnection ssCon, MSPMessage protocolMessage) throws PEException { MSPComQueryRequestMessage queryMessage = castProtocolMessage(MSPComQueryRequestMessage.class,protocolMessage); byte[] query = queryMessage.getQueryBytes(); executeQuery(ctx, ssCon, query); } public static void executeQuery(ChannelHandlerContext ctx, final SSConnection ssCon, final byte[] query) throws PEException { // final NativeCharSet clientCharSet = MysqlNativeCharSet.UTF8; final MysqlTextResultForwarder resultConsumer = new MysqlTextResultForwarder(ctx); try { ExecuteRequestExecutor.execute(ssCon, resultConsumer, query); //TODO: this response should really be generated inside execution. Doing it here forces synchronous behavior and extra locking + context switching. -sgossard. resultConsumer.sendSuccess(ssCon); } catch (PEMysqlErrorException e) { if (logger.isDebugEnabled()) logger.debug("Exception returned directly to user: ", e); // The result consumer has already processed the error, so we do nothing here } catch (PEMappedRuntimeException se) { if (handleMappedError(resultConsumer,se)) return; } catch (PEMappedException se) { if (handleMappedError(resultConsumer,se)) return; } catch (PEException e) { if (logger.isInfoEnabled()) logger.info("Exception returned to user: ", e); if (!e.hasCause(PEMysqlErrorException.class)) { resultConsumer.sendError(e.rootCause()); } } catch (Throwable t) { if (logger.isInfoEnabled()) logger.info("Exception returned to user: ", t); resultConsumer.sendError(new Exception(t)); } } @Override public byte getMysqlMessageType() { return (byte) 0x03; } private static <T extends HasErrorInfo> boolean handleMappedError(MysqlTextResultForwarder resultConsumer, T ex) { FormattedErrorInfo fei = ErrorMapper.makeResponse(ex); if (fei != null) { MyErrorResponse err = new MyErrorResponse(fei); if (logger.isInfoEnabled() && ex.getErrorInfo().getCode().log()) logger.info("Exception returned to user: ", (Exception)ex); resultConsumer.sendError(err); return true; } else { resultConsumer.sendError((Exception)ex); } return false; } }