package org.opencloudb.jdbc;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import org.opencloudb.backend.BackendConnection;
import org.opencloudb.config.ErrorCode;
import org.opencloudb.mysql.nio.handler.ResponseHandler;
import org.opencloudb.net.mysql.EOFPacket;
import org.opencloudb.net.mysql.ErrorPacket;
import org.opencloudb.net.mysql.FieldPacket;
import org.opencloudb.net.mysql.OkPacket;
import org.opencloudb.net.mysql.ResultSetHeaderPacket;
import org.opencloudb.net.mysql.RowDataPacket;
import org.opencloudb.route.RouteResultsetNode;
import org.opencloudb.server.ServerConnection;
import org.opencloudb.server.parser.ServerParse;
import org.opencloudb.util.ResultSetUtil;
public class JDBCConnection implements BackendConnection {
private JDBCDatasource pool;
private volatile String schema;
private volatile String oldSchema;
private byte packetId;
private int txIsolation;
private volatile boolean running = false;
private volatile boolean borrowed;
private long id = 0;
private String host;
private int port;
private Connection con;
private ResponseHandler respHandler;
private volatile Object attachement;
boolean headerOutputed = false;
private volatile boolean modifiedSQLExecuted;
private final long startTime;
private long lastTime;
public JDBCConnection() {
startTime = System.currentTimeMillis();
}
public Connection getCon() {
return con;
}
public void setCon(Connection con) {
this.con = con;
}
@Override
public void close(String reason) {
try {
con.close();
} catch (SQLException e) {
}
}
public void setPool(JDBCDatasource pool) {
this.pool = pool;
}
public void setHost(String host) {
this.host = host;
}
public void setPort(int port) {
this.port = port;
}
@Override
public boolean isClosed() {
try {
return con == null || con.isClosed();
} catch (SQLException e) {
return true;
}
}
@Override
public void idleCheck() {
// TODO Auto-generated method stub
}
@Override
public long getStartupTime() {
return startTime;
}
@Override
public String getHost() {
return this.host;
}
@Override
public int getPort() {
return this.port;
}
@Override
public int getLocalPort() {
return 0;
}
@Override
public long getNetInBytes() {
return 0;
}
@Override
public long getNetOutBytes() {
return 0;
}
@Override
public boolean isModifiedSQLExecuted() {
return modifiedSQLExecuted;
}
@Override
public boolean isFromSlaveDB() {
return false;
}
@Override
public String getSchema() {
return this.schema;
}
@Override
public void setSchema(String newSchema) {
this.oldSchema = this.schema;
this.schema = newSchema;
}
@Override
public long getLastTime() {
return lastTime;
}
@Override
public boolean isClosedOrQuit() {
return this.isClosed();
}
@Override
public void setAttachment(Object attachment) {
this.attachement = attachment;
}
@Override
public void quit() {
this.close("client quit");
}
@Override
public void setLastTime(long currentTimeMillis) {
this.lastTime=currentTimeMillis;
}
@Override
public void release() {
modifiedSQLExecuted = false;
setResponseHandler(null);
pool.releaseChannel(this);
}
@Override
public void setRunning(boolean running) {
this.running = running;
}
@Override
public boolean setResponseHandler(ResponseHandler commandHandler) {
respHandler = commandHandler;
return false;
}
@Override
public void commit() {
try {
con.commit();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
private void executeSQL(RouteResultsetNode rrn, ServerConnection sc,
boolean autocommit) throws IOException {
String orgin = rrn.getStatement();
String sql = rrn.getStatement().toLowerCase();
try {
if (!this.schema.equals(this.oldSchema)) {
con.setCatalog(schema);
this.oldSchema = schema;
}
con.setAutoCommit(autocommit);
int sqlType=rrn.getSqlType();
if (sqlType==ServerParse.SELECT||sqlType==ServerParse.SHOW) {
ouputResultSet(sc, orgin);
} else {
executeddl(sc, sql);
}
} catch (SQLException e) {
e.printStackTrace();
ErrorPacket error = new ErrorPacket();
error.packetId = ++packetId;
error.errno = ErrorCode.ERR_NOT_SUPPORTED;
error.message = "not supporeted yet".getBytes();
this.respHandler.errorResponse(error.writeToBytes(sc), this);
} finally {
this.running = false;
}
}
private void executeddl(ServerConnection sc, String sql)
throws SQLException {
Statement stmt = null;
try {
int count = con.createStatement().executeUpdate(sql);
OkPacket okPck = new OkPacket();
okPck.affectedRows = count;
okPck.insertId = 0;
okPck.packetId = ++packetId;
okPck.message = " OK!".getBytes();
this.respHandler.okResponse(okPck.writeToBytes(sc), this);
} finally {
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
}
}
}
}
private void ouputResultSet(ServerConnection sc, String sql)
throws SQLException {
ResultSet rs = null;
Statement stmt = null;
try {
stmt = con.createStatement();
rs = stmt.executeQuery(sql);
List<RowDataPacket> rowsPkg = new LinkedList<RowDataPacket>();
List<FieldPacket> fieldPks = new LinkedList<FieldPacket>();
ResultSetUtil.resultSetToPacket(sc.getCharset(), con, fieldPks, rs,
rowsPkg);
ByteBuffer byteBuf = sc.allocate();
ResultSetHeaderPacket headerPkg = new ResultSetHeaderPacket();
headerPkg.fieldCount = fieldPks.size();
headerPkg.packetId = ++packetId;
byteBuf = headerPkg.write(byteBuf, sc, true);
byteBuf.flip();
byte[] header = new byte[byteBuf.limit()];
byteBuf.get(header);
byteBuf.clear();
List<byte[]> fields = new ArrayList<byte[]>(fieldPks.size());
Iterator<FieldPacket> itor = fieldPks.iterator();
while (itor.hasNext()) {
FieldPacket curField = itor.next();
curField.packetId = ++packetId;
byteBuf = curField.write(byteBuf, sc, false);
byteBuf.flip();
byte[] field = new byte[byteBuf.limit()];
byteBuf.get(field);
byteBuf.clear();
fields.add(field);
itor.remove();
}
EOFPacket eofPckg = new EOFPacket();
eofPckg.packetId = ++packetId;
byteBuf = eofPckg.write(byteBuf, sc, false);
byteBuf.flip();
byte[] eof = new byte[byteBuf.limit()];
byteBuf.get(eof);
byteBuf.clear();
this.respHandler.fieldEofResponse(header, fields, eof, this);
// output row
Iterator<RowDataPacket> rowItor = rowsPkg.iterator();
while (rowItor.hasNext()) {
RowDataPacket curRow = rowItor.next();
curRow.packetId = ++packetId;
rowItor.remove();
byteBuf = curRow.write(byteBuf, sc, false);
byteBuf.flip();
byte[] row = new byte[byteBuf.limit()];
byteBuf.get(row);
byteBuf.clear();
this.respHandler.rowResponse(row, this);
}
// end row
eofPckg = new EOFPacket();
eofPckg.packetId = ++packetId;
byteBuf = eofPckg.write(byteBuf, sc, false);
byteBuf.flip();
eof = new byte[byteBuf.limit()];
byteBuf.get(eof);
sc.recycle(byteBuf);
this.respHandler.rowEofResponse(eof, this);
} finally {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
}
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
}
}
}
}
@Override
public void query(String sql) throws UnsupportedEncodingException {
}
@Override
public Object getAttachment() {
return this.attachement;
}
@Override
public String getCharset() {
return null;
}
@Override
public void execute(RouteResultsetNode node, ServerConnection source,
boolean autocommit) throws IOException {
executeSQL(node, source, autocommit);
}
@Override
public void recordSql(String host, String schema, String statement) {
}
@Override
public boolean syncAndExcute() {
return true;
}
@Override
public void rollback() {
try {
con.rollback();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
@Override
public boolean isRunning() {
return this.running;
}
@Override
public boolean isBorrowed() {
return this.borrowed;
}
@Override
public void setBorrowed(boolean borrowed) {
this.borrowed = borrowed;
}
@Override
public int getTxIsolation() {
if (con != null) {
try {
return con.getTransactionIsolation();
} catch (SQLException e) {
return 0;
}
} else {
return -1;
}
}
@Override
public boolean isAutocommit() {
if (con == null) {
return true;
} else {
try {
return con.getAutoCommit();
} catch (SQLException e) {
}
}
return true;
}
@Override
public long getId() {
return id;
}
@Override
public String toString() {
return "JDBCConnection [autocommit=" + this.isAutocommit()
+ ", txIsolation=" + txIsolation + ", running=" + running
+ ", borrowed=" + borrowed + ", id=" + id + ", host=" + host
+ ", port=" + port + "]";
}
@Override
public boolean isFake(){
return false;
}
}