package jef.database.routing.jdbc; import java.io.StringReader; 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.LinkedList; import java.util.List; import jef.database.DbUtils; import jef.database.innerpool.JConnection; import jef.database.jdbc.GenerateKeyReturnOper; import jef.database.jsqlparser.parser.ParseException; import jef.database.jsqlparser.parser.StSqlParser; import org.apache.commons.lang.ArrayUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @SuppressWarnings("unchecked") public class JStatement implements java.sql.Statement { private static final Logger log = LoggerFactory.getLogger(JStatement.class); private JConnection conn; /** * 经过计算后的结果集,允许使用 getResult函数调用. * * 一个statement只允许有一个结果集 */ protected ResultSet resultSet; /** * 插入等操作产生的自增主键 */ protected UpdateReturn updateReturn; /** * 貌似是只有存储过程中会出现多结果集 因此不支持 */ protected boolean moreResults; /** * 判断当前statment 是否是关闭的 */ protected boolean closed; /** * */ private int resultSetType = -1; /** * */ private int resultSetConcurrency = -1; /** * */ private int resultSetHoldability = -1; /** * 超时时间 */ protected int queryTimeout = 0; /** * 最大结果限制 */ protected int maxRows = 0; /** * 获取批大小 */ protected int fetchSize = 0; protected List<String> batchedArgs; public JStatement(JConnection routingConnection) { this.conn = routingConnection; } public JStatement(JConnection routingConnection, int resultsetType, int resultSetConcurrency, int resultSetHoldability) { this.conn = routingConnection; this.resultSetType = resultsetType; this.resultSetConcurrency = resultSetConcurrency; this.resultSetHoldability = resultSetHoldability; } public int executeUpdate(String sql) throws SQLException { return executeUpdateInternal(sql, GenerateKeyReturnOper.NONE, null); } public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException { return executeUpdateInternal(sql, autoGeneratedKeys == Statement.RETURN_GENERATED_KEYS ? GenerateKeyReturnOper.RETURN_KEY : GenerateKeyReturnOper.NONE, null); } public int executeUpdate(String sql, int[] columnIndexes) throws SQLException { return executeUpdateInternal(sql, new GenerateKeyReturnOper.ReturnByColumnIndex(columnIndexes), null); } public int executeUpdate(String sql, String[] columnNames) throws SQLException { return executeUpdateInternal(sql, new GenerateKeyReturnOper.ReturnByColumnNames(columnNames), null); } private boolean executeInternal(String sql, GenerateKeyReturnOper oper) throws SQLException { if (SqlTypeParser.isQuerySql(sql)) { this.resultSet = executeQuery(sql); return true; } else { executeUpdateInternal(sql, oper, Collections.EMPTY_LIST); return false; } } public boolean execute(String sql) throws SQLException { return executeInternal(sql, GenerateKeyReturnOper.NONE); } public boolean execute(String sql, int autoGeneratedKeys) throws SQLException { return executeInternal(sql, autoGeneratedKeys == Statement.RETURN_GENERATED_KEYS ? GenerateKeyReturnOper.RETURN_KEY : GenerateKeyReturnOper.NONE); } public boolean execute(String sql, int[] columnIndexes) throws SQLException { return executeInternal(sql, new GenerateKeyReturnOper.ReturnByColumnIndex(columnIndexes)); } public boolean execute(String sql, String[] columnNames) throws SQLException { return executeInternal(sql, new GenerateKeyReturnOper.ReturnByColumnNames(columnNames)); } 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 void close() throws SQLException { if (closed) { return; } if (updateReturn != null) { updateReturn.close(); } this.updateReturn = null; closed = true; if (resultSet != null) { DbUtils.close(resultSet); resultSet = null; } } public Connection getConnection() throws SQLException { return conn; } /** * 以下为不支持的方法 */ public int getFetchDirection() throws SQLException { throw new UnsupportedOperationException("getFetchDirection"); } public int getFetchSize() throws SQLException { return this.fetchSize; } public int getMaxFieldSize() throws SQLException { throw new UnsupportedOperationException("getMaxFieldSize"); } public int getMaxRows() throws SQLException { return this.maxRows; } public boolean getMoreResults() throws SQLException { return moreResults; } public int getQueryTimeout() throws SQLException { return queryTimeout; } public void setQueryTimeout(int queryTimeout) throws SQLException { this.queryTimeout = queryTimeout; } public void setCursorName(String cursorName) throws SQLException { throw new UnsupportedOperationException("setCursorName"); } public void setEscapeProcessing(boolean escapeProcessing) throws SQLException { throw new UnsupportedOperationException("setEscapeProcessing"); } public SQLWarning getWarnings() throws SQLException { return null; } public void clearWarnings() throws SQLException { } public boolean getMoreResults(int current) throws SQLException { throw new UnsupportedOperationException("getMoreResults"); } public ResultSet getResultSet() throws SQLException { return resultSet; } public int getResultSetConcurrency() throws SQLException { return resultSetConcurrency; } public int getResultSetHoldability() throws SQLException { return resultSetHoldability; } public int getResultSetType() throws SQLException { return resultSetType; } public int getUpdateCount() throws SQLException { if (updateReturn == null) return 0; return updateReturn.getAffectedRows(); } public void setFetchDirection(int fetchDirection) throws SQLException { throw new UnsupportedOperationException("setFetchDirection"); } public void setFetchSize(int fetchSize) throws SQLException { this.fetchSize = fetchSize; } public void setMaxFieldSize(int maxFieldSize) throws SQLException { throw new UnsupportedOperationException("setMaxFieldSize"); } public void setMaxRows(int maxRows) throws SQLException { this.maxRows = maxRows; } /* * 这也是在PreparedStatement上才支持的 */ public ResultSet getGeneratedKeys() throws SQLException { if (updateReturn != null) { return updateReturn.getGeneratedKeys(); } else { throw new UnsupportedOperationException("getGeneratedKeys"); } } public void cancel() throws SQLException { throw new UnsupportedOperationException("cancel"); } public int getQueryTimeOut() { return queryTimeout; } 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 boolean isWrapperFor(Class<?> iface) throws SQLException { return this.getClass().isAssignableFrom(iface); } public <T> T unwrap(Class<T> iface) throws SQLException { try { return (T) this; } catch (Exception e) { throw new SQLException(e); } } public boolean isClosed() throws SQLException { return closed; } public void setPoolable(boolean poolable) throws SQLException { throw new SQLException("not support exception"); } public boolean isPoolable() throws SQLException { return false; } public ResultSet executeQuery(String sql) throws SQLException { return executeQueryInternal(sql, Collections.EMPTY_LIST); } /* * */ protected ResultSet executeQueryInternal(String sql, List<ParameterContext> params) throws SQLException { jef.database.jsqlparser.visitor.Statement st = parse(sql); SQLExecutor executor; if (st == null) { executor = new SimpleSQLExecutor(conn.get().selectTarget(null), sql); } else { executor = new RoutingSQLExecutor(conn.get(), st); } executor.setFetchSize(this.fetchSize); executor.setMaxResults(this.maxRows); executor.setQueryTimeout(this.queryTimeout); return executor.getResultSet(resultSetType, resultSetConcurrency, resultSetHoldability, params); } protected int[] executeBatchInternal(String sql, GenerateKeyReturnOper oper, List<List<ParameterContext>> params) throws SQLException { jef.database.jsqlparser.visitor.Statement st = parse(sql); SQLExecutor se; if (st == null) { // 无法解析,直接运行 se = new SimpleSQLExecutor(conn.get().selectTarget(null), sql); } else { se = new RoutingSQLExecutor(conn.get(), st); } if (queryTimeout > 0) se.setQueryTimeout(queryTimeout); BatchReturn br = se.executeBatch(oper, params); updateReturn = br; return br.getBatchResult(); } protected int executeUpdateInternal(String sql, GenerateKeyReturnOper oper, List<ParameterContext> params) throws SQLException { jef.database.jsqlparser.visitor.Statement st = parse(sql); SQLExecutor se; if (st == null) { // 无法解析,直接运行 se = new SimpleSQLExecutor(conn.get().selectTarget(null), sql); } else { se = new RoutingSQLExecutor(conn.get(), st); } if (queryTimeout > 0) se.setQueryTimeout(queryTimeout); this.updateReturn = se.executeUpdate(oper, params); return updateReturn.getAffectedRows(); } /* * Batch一般都在PrepraredStatement上执行 */ public int[] executeBatch() throws SQLException { if (batchedArgs == null) return ArrayUtils.EMPTY_INT_ARRAY; int[] result = new int[batchedArgs.size()]; for (int i = 0; i < batchedArgs.size(); i++) { String sql = batchedArgs.get(i); result[i] = executeUpdate(sql); } return result; } /** * 如果新建了查询,那么上一次查询的结果集应该被显示的关闭掉。这才是符合jdbc规范的 * * @throws SQLException */ protected void ensureResultSetIsEmpty() throws SQLException { if (resultSet != null) { log.debug("result set is not null,close current result set"); try { resultSet.close(); } catch (SQLException e) { log.error("exception on close last result set . can do nothing..", e); } finally { // 最终要显示的关闭它 resultSet = null; } } } protected jef.database.jsqlparser.visitor.Statement parse(String sql) { StSqlParser parser = new StSqlParser(new StringReader(sql)); try { return parser.Statement(); } catch (ParseException e) { log.error("Parse Error: {}", sql); return null; } } protected void checkClosed() throws SQLException { if (closed) { throw new SQLException("No operations allowed after statement closed."); } } @Override public void closeOnCompletion() throws SQLException { } @Override public boolean isCloseOnCompletion() throws SQLException { return false; } }