package io.mycat.sqlengine; import io.mycat.MycatServer; import io.mycat.backend.BackendConnection; import io.mycat.backend.PhysicalDBNode; import io.mycat.backend.PhysicalDatasource; import io.mycat.route.RouteResultsetNode; import io.mycat.server.config.node.MycatConfig; import io.mycat.server.executors.ResponseHandler; import io.mycat.server.packet.ErrorPacket; import io.mycat.server.parser.ServerParse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.List; /** * asyn execute in EngineCtx or standalone (EngineCtx=null) * * @author wuzhih * */ public class SQLJob implements ResponseHandler, Runnable { public static final Logger LOGGER = LoggerFactory .getLogger(SQLJob.class); private final String sql; private final String dataNodeOrDatabase; private BackendConnection connection; private final SQLJobHandler jobHandler; private final EngineCtx ctx; private final PhysicalDatasource ds; private final int id; private volatile boolean finished; public SQLJob(int id, String sql, String dataNode, SQLJobHandler jobHandler, EngineCtx ctx) { super(); this.id = id; this.sql = sql; this.dataNodeOrDatabase = dataNode; this.jobHandler = jobHandler; this.ctx = ctx; this.ds = null; } public SQLJob(String sql, String databaseName, SQLJobHandler jobHandler, PhysicalDatasource ds) { super(); this.id = 0; this.sql = sql; this.dataNodeOrDatabase = databaseName; this.jobHandler = jobHandler; this.ctx = null; this.ds = ds; } public void run() { try { if (ds == null) { RouteResultsetNode node = new RouteResultsetNode( dataNodeOrDatabase, ServerParse.SELECT, sql); // create new connection MycatConfig conf = MycatServer.getInstance().getConfig(); PhysicalDBNode dn = conf.getDataNodes().get(node.getName()); dn.getConnection(dn.getDatabase(), true, node, this, node); } else { ds.getConnection(dataNodeOrDatabase, true, this, null); } } catch (Exception e) { LOGGER.info("can't get connection for sql ,error:" + e); doFinished(true); } } public void teminate(String reason) { LOGGER.info("terminate this job reason:" + reason + " con:" + connection + " sql " + this.sql); if (connection != null) { connection.close(reason); } } @Override public void connectionAcquired(final BackendConnection conn) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("con query sql:" + sql + " to con:" + conn); } conn.setResponseHandler(this); try { conn.query(sql); connection = conn; } catch (Exception e) {// (UnsupportedEncodingException e) { doFinished(true); } } public boolean isFinished() { return finished; } private void doFinished(boolean failed) { finished = true; jobHandler.finished(dataNodeOrDatabase, failed); if (ctx != null) { ctx.onJobFinished(this); } } @Override public void connectionError(Throwable e, BackendConnection conn) { LOGGER.info("can't get connection for sql :" + sql); doFinished(true); } @Override public void errorResponse(byte[] err, BackendConnection conn) { ErrorPacket errPg = new ErrorPacket(); errPg.read(err); LOGGER.info("error response " + new String(errPg.message) + " from of sql :" + sql + " at con:" + conn); conn.release(); doFinished(true); } @Override public void okResponse(byte[] ok, BackendConnection conn) { // not called for query sql } @Override public void fieldEofResponse(byte[] header, List<byte[]> fields, byte[] eof, BackendConnection conn) { jobHandler.onHeader(dataNodeOrDatabase, header, fields); } @Override public void rowResponse(byte[] row, BackendConnection conn) { boolean finsihed = jobHandler.onRowData(dataNodeOrDatabase, row); if (finsihed) { conn.close("not needed by user proc"); doFinished(false); } } @Override public void rowEofResponse(byte[] eof, BackendConnection conn) { //connection do synchronization conn.syncAndExcute(); conn.release(); doFinished(false); } @Override public void connectionClose(BackendConnection conn, String reason) { doFinished(true); } public int getId() { return id; } @Override public String toString() { return "SQLJob [ id=" + id + ",dataNodeOrDatabase=" + dataNodeOrDatabase + ",sql=" + sql + ", jobHandler=" + jobHandler + "]"; } }