package com.taobao.tddl.matrix.jdbc;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.Statement;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import com.taobao.tddl.common.exception.TddlRuntimeException;
import com.taobao.tddl.common.jdbc.ParameterContext;
import com.taobao.tddl.common.model.ExtraCmd;
import com.taobao.tddl.common.model.SqlType;
import com.taobao.tddl.common.utils.GeneralUtil;
import com.taobao.tddl.executor.common.ExecutionContext;
import com.taobao.tddl.matrix.jdbc.utils.PreParser;
import com.taobao.tddl.common.utils.logger.Logger;
import com.taobao.tddl.common.utils.logger.LoggerFactory;
/**
* @author mengshi.sunmengshi 2013-11-22 下午3:26:28
* @since 5.0.0
*/
public class TStatement implements Statement {
private static final Logger log = LoggerFactory.getLogger(TStatement.class);
protected String sql;
protected TDataSource ds;
protected TConnection conn;
protected ExecutionContext executionContext = null;
/**
* 更新计数,如果执行了多次,那么这个值只会返回最后一次执行的结果。 如果是一个query,那么返回的数据应该是-1
*/
protected int updateCount;
/**
* 经过计算后的结果集,允许使用 getResult函数调用. 一个statement只允许有一个结果集
*/
protected ResultSet currentResultSet;
protected Map<String, Object> extraCmd = new HashMap<String, Object>(4);
/**
* 当前statment 是否是关闭的
*/
protected boolean closed;
private int maxFieldSize;
private int maxRows;
private int queryTimeOut;
private int direction;
protected List<String> batchedArgs;
private int resultSetType = -1;
private int resultSetConcurrency = -1;
private int resultSetHoldability = -1;
public TStatement(TDataSource ds, TConnection tConnection, ExecutionContext executionContext){
this.ds = ds;
this.conn = tConnection;
this.executionContext = executionContext;
}
public TStatement(TDataSource ds, TConnection tConnection, String sql, ExecutionContext executionContext){
this.ds = ds;
this.conn = tConnection;
this.sql = sql;
this.executionContext = executionContext;
}
protected void checkClosed() throws SQLException {
if (closed) {
throw new SQLException("No operations allowed after statement closed.");
}
}
// jdbc规范: 返回true表示executeQuery,false表示executeUpdate
public boolean execute(String sql) throws SQLException {
return executeInternal(sql, -1, null, null);
}
public boolean execute(String sql, int autoGeneratedKeys) throws SQLException {
throw new UnsupportedOperationException();
}
public boolean execute(String sql, int[] columnIndexes) throws SQLException {
throw new UnsupportedOperationException();
}
public boolean execute(String sql, String[] columnNames) throws SQLException {
throw new UnsupportedOperationException();
}
private boolean executeInternal(String sql, int autoGeneratedKeys, int[] columnIndexes, String[] columnNames)
throws SQLException {
SqlType sqlType = PreParser.getSqlType(sql);
if (sqlType == SqlType.SELECT || sqlType == SqlType.SELECT_FOR_UPDATE/**
*
* || sqlType == SqlType.SHOW
**/
) {
executeQuery(sql);
return true;
} else if (sqlType == SqlType.INSERT || sqlType == SqlType.UPDATE || sqlType == SqlType.DELETE
|| sqlType == SqlType.REPLACE || sqlType == SqlType.TRUNCATE || sqlType == SqlType.CREATE
|| sqlType == SqlType.DROP || sqlType == SqlType.LOAD || sqlType == SqlType.MERGE) {
if (autoGeneratedKeys == -1 && columnIndexes == null && columnNames == null) {
executeUpdate(sql);
} else if (autoGeneratedKeys != -1) {
executeUpdate(sql, autoGeneratedKeys);
} else if (columnIndexes != null) {
executeUpdate(sql, columnIndexes);
} else if (columnNames != null) {
executeUpdate(sql, columnNames);
} else {
executeUpdate(sql);
}
return false;
} else {
throw new SQLException("only select, insert, update, delete,replace,truncate,create,drop,load,merge sql is supported");
}
}
/*
* ========================================================================
* executeQuery 查询逻辑 这里按照mysql
* connection逻辑,调用connection的executeSQL方法返回resultset Connection 的 execSQL方法
* ======================================================================
*/
public ResultSet executeQuery(String sql) throws SQLException {
checkClosed();
ensureResultSetIsEmpty();
currentResultSet = this.conn.executeSQL(sql,
(Map<Integer, ParameterContext>) Collections.EMPTY_MAP,
this,
extraCmd,
this.executionContext);
return currentResultSet;
}
/*
* ========================================================================
* executeUpdate逻辑 这里按照mysql
* connection逻辑,调用connection的executeSQL方法返回resultset
* ,然后根据resultset获得affertrows Connection 的 execSQL方法
* ======================================================================
*/
public int executeUpdate(String sql) throws SQLException {
checkClosed();
ensureResultSetIsEmpty();
currentResultSet = this.conn.executeSQL(sql,
((Map<Integer, ParameterContext>) Collections.EMPTY_MAP),
this,
extraCmd,
this.executionContext);
return ((TResultSet) currentResultSet).getAffectRows();
}
public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException {
throw new UnsupportedOperationException();
}
public int executeUpdate(String sql, int[] columnIndexes) throws SQLException {
throw new UnsupportedOperationException();
}
public int executeUpdate(String sql, String[] columnNames) throws SQLException {
throw new UnsupportedOperationException();
}
public void addBatch(String sql) throws SQLException {
checkClosed();
if (batchedArgs == null) {
batchedArgs = new LinkedList<String>();
}
if (sql != null) {
batchedArgs.add(sql);
}
}
public void clearBatch() throws SQLException {
checkClosed();
if (batchedArgs != null) {
batchedArgs.clear();
}
}
public int[] executeBatch() throws SQLException {
throw new UnsupportedOperationException("executeBatch");
}
public boolean isClosed() throws SQLException {
return this.closed;
}
public void close() throws SQLException {
close(true);
}
void close(boolean removeThis) throws SQLException {
if (closed) {
return;
}
try {
if (currentResultSet != null) {
currentResultSet.close();
}
if (removeThis) {
conn.removeStatement(this);
}
} catch (Exception e) {
throw new TddlRuntimeException(e);
} finally {
currentResultSet = null;
}
closed = true;
}
/**
* 如果新建了查询,那么上一次查询的结果集应该被显示的关闭掉。这才是符合jdbc规范的
*
* @throws SQLException
*/
protected void ensureResultSetIsEmpty() throws SQLException {
if (currentResultSet != null) {
// log.debug("result set is not null,close current result set");
try {
currentResultSet.close();
} catch (SQLException e) {
log.error("exception on close last result set . can do nothing..", e);
} finally {
// 最终要显示的关闭它
currentResultSet = null;
}
}
}
public int getMaxFieldSize() throws SQLException {
return this.maxFieldSize;
}
public void setMaxFieldSize(int max) throws SQLException {
this.maxFieldSize = max;
}
public int getMaxRows() throws SQLException {
return this.maxRows;
}
public void setMaxRows(int max) throws SQLException {
this.maxRows = max;
}
public ResultSet getResultSet() throws SQLException {
return currentResultSet;
}
public int getUpdateCount() throws SQLException {
return updateCount;
}
public Connection getConnection() throws SQLException {
return this.conn;
}
public int getQueryTimeout() throws SQLException {
return this.queryTimeOut;
}
public void setQueryTimeout(int seconds) throws SQLException {
this.queryTimeOut = seconds;
}
public <T> T unwrap(Class<T> iface) throws SQLException {
try {
return (T) this;
} catch (Exception e) {
throw new SQLException(e);
}
}
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return this.getClass().isAssignableFrom(iface);
}
public void setFetchDirection(int direction) throws SQLException {
this.direction = direction;
}
public int getFetchDirection() throws SQLException {
return this.direction;
}
public void setFetchSize(int rows) throws SQLException {
extraCmd.put(ExtraCmd.FETCH_SIZE, rows);
}
public int getFetchSize() throws SQLException {
return (int) GeneralUtil.getExtraCmdLong(extraCmd, ExtraCmd.FETCH_SIZE, 0L);
}
public int getResultSetConcurrency() throws SQLException {
return resultSetConcurrency;
}
public int getResultSetType() throws SQLException {
return resultSetType;
}
public int getResultSetHoldability() throws SQLException {
return resultSetHoldability;
}
public SQLWarning getWarnings() throws SQLException {
return null;
}
public void clearWarnings() throws SQLException {
}
public void setResultSetType(int resultSetType) {
this.resultSetType = resultSetType;
}
public void setResultSetConcurrency(int resultSetConcurrency) {
this.resultSetConcurrency = resultSetConcurrency;
}
public void setResultSetHoldability(int resultSetHoldability) {
this.resultSetHoldability = resultSetHoldability;
}
/*---------------------后面是未实现的方法------------------------------*/
public void setPoolable(boolean poolable) throws SQLException {
throw new SQLException("not support exception");
}
public boolean isPoolable() throws SQLException {
throw new SQLException("not support exception");
}
public void setEscapeProcessing(boolean enable) throws SQLException {
throw new UnsupportedOperationException("setEscapeProcessing");
}
public void setCursorName(String cursorName) throws SQLException {
throw new UnsupportedOperationException("setCursorName");
}
public boolean getMoreResults() throws SQLException {
throw new UnsupportedOperationException("getMoreResults");
}
public boolean getMoreResults(int current) throws SQLException {
throw new UnsupportedOperationException("getMoreResults");
}
public ResultSet getGeneratedKeys() throws SQLException {
throw new UnsupportedOperationException("getGeneratedKeys");
}
public void cancel() throws SQLException {
throw new UnsupportedOperationException("cancel");
}
}