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"); } }