package com.tesora.dve.sql.util; /* * #%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 java.util.List; import java.util.Properties; import java.util.concurrent.Callable; import com.tesora.dve.server.global.HostService; import com.tesora.dve.singleton.Singletons; import org.apache.commons.lang.StringUtils; import com.tesora.dve.common.DBHelper; import com.tesora.dve.comms.client.messages.DisconnectRequest; import com.tesora.dve.exceptions.PEException; import com.tesora.dve.server.connectionmanager.SSConnection; import com.tesora.dve.server.connectionmanager.messages.ExecuteRequestExecutor; import com.tesora.dve.sql.SchemaException; import com.tesora.dve.sql.SchemaTest; import com.tesora.dve.sql.parser.ParserInvoker.LineInfo; import com.tesora.dve.worker.DBConnectionParameters; import com.tesora.dve.worker.MysqlTextResultChunkProvider; import com.tesora.dve.worker.UserCredentials; public class ProxyConnectionResource extends ConnectionResource { private DBConnectionParameters connectionParams; private SSConnection proxy; private String userName = null; private String password = null; private boolean lastHadWarning = false; public ProxyConnectionResource() throws Throwable { this(null,null); } public ProxyConnectionResource(String userName, String password) throws Throwable { super(null); this.userName = userName; this.password = password; Properties props = (Properties) Singletons.require(HostService.class).getProperties().clone(); if (userName != null) props.setProperty(DBHelper.CONN_USER, userName); if (password != null) props.setProperty(DBHelper.CONN_PASSWORD, password); connectionParams = new DBConnectionParameters(props); proxy = null; connect(); } protected ProxyConnectionResource(ProxyConnectionResource pcr) throws Throwable { super(pcr); this.userName = pcr.userName; this.password = pcr.password; this.connectionParams = new DBConnectionParameters(pcr.connectionParams); this.proxy = null; connect(); } @Override public void connect() throws Throwable { if (proxy != null) return; proxy = new SSConnection(); try { proxy.startConnection(new UserCredentials(connectionParams.getUserid(), connectionParams.getPassword())); executePostConnectCmds(); } catch ( Throwable t ) { proxy.close(); throw t; } } @Override public void disconnect() throws Throwable { if (proxy == null) return; DisconnectRequest discon = new DisconnectRequest(); proxy.executeMessageDirect(discon); proxy.close(); proxy = null; } public ResourceResponse execute(LineInfo info, final byte[] stmt) throws Throwable { if (info != null) SchemaTest.echo("Executing@" + info + ": '" + stmt + "'"); else SchemaTest.echo("Executing: '" + stmt + "'"); // final NativeCharSet clientCharSet = MysqlNativeCharSet.UTF8; final MysqlTextResultChunkProvider results = new MysqlTextResultChunkProvider(); proxy.executeInContext(new Callable<Void>() { @SuppressWarnings("synthetic-access") @Override public Void call() throws Exception { try { ExecuteRequestExecutor.execute(proxy, results, stmt); } catch (PEException e) { throw e; } catch (SchemaException se) { throw se; } catch (Throwable e) { throw new PEException("Test statement encountered exception", e); } return null; } }); lastHadWarning = results.getWarnings() > 0; return new ProxyConnectionResourceResponse(results); } @Override public ResourceResponse execute(LineInfo info, String stmt) throws Throwable { if (info != null) SchemaTest.echo("Executing@" + info + ": '" + stmt + "'"); else SchemaTest.echo("Executing: '" + stmt + "'"); return execute(info, stmt.getBytes()); } @Override public ResourceResponse fetch(LineInfo info, String stmt) throws Throwable { return execute(info, stmt); } @Override public ExceptionClassification classifyException(Throwable t) { if (t.getMessage() == null) return null; String msg = t.getMessage().trim(); if (StringUtils.containsIgnoreCase(msg, "No such Table:") || StringUtils.containsIgnoreCase(msg, "No such Column:")) return ExceptionClassification.DNE; if (StringUtils.containsIgnoreCase(msg, "No value found for required") && StringUtils.endsWithIgnoreCase(msg, "and no default specified")) return ExceptionClassification.DNE; if (StringUtils.containsIgnoreCase(msg, "Unsupported statement kind for planning:") && StringUtils.endsWithIgnoreCase(msg, "RollbackTransactionStatement")) return ExceptionClassification.DNE; if (StringUtils.containsIgnoreCase(msg, "Data Truncation:")) return ExceptionClassification.OUT_OF_RANGE; if (StringUtils.containsIgnoreCase(msg, "Unable to parse") || StringUtils.containsIgnoreCase(msg, "Unable to build plan") || StringUtils.containsIgnoreCase(msg, "Parsing FAILED:")) return ExceptionClassification.SYNTAX; if (StringUtils.containsIgnoreCase(msg, "Duplicate entry")) return ExceptionClassification.DUPLICATE; if (StringUtils.containsIgnoreCase(msg, "option not supported")) return ExceptionClassification.UNSUPPORTED_OPERATION; return null; } @Override public ConnectionResource getNewConnection() throws Throwable { return new ProxyConnectionResource(this); } @Override public boolean isConnected() throws Throwable { return proxy != null; } @Override public String describe() { if (userName == null && password == null) return "null/null"; return userName + "/" + password; } @Override public Object prepare(LineInfo info, String stmt) throws Throwable { throw new PEException("prepare() method not implemented for ProxyConnectionResource"); } @Override public ResourceResponse executePrepared(Object ps, List<Object> parameters) throws Throwable { throw new PEException("executePrepared() method not implemented for ProxyConnectionResource"); } @Override public void destroyPrepared(Object ps) throws Throwable { throw new PEException("destroyPrepared() method not implemented for ProxyConnectionResource"); } @Override public boolean hasWarnings() { return lastHadWarning; } public SSConnection getBackingConnection() { return proxy; } }