📄 jtdsstatement.java
字号:
* @param spName optional stored procedure name * @param params optional parameters * @param returnKeys whether the statement returns generated keys * @param update whether the caller is {@link #executeUpdate} * @param useCursor whether the requested result set type or concurrency * or connection properties request usage of a cursor * @return <code>true</code> if the first result is a result set * @throws SQLException if an error condition occurs */ protected boolean executeSQL(String sql, String spName, ParamInfo[] params, boolean returnKeys, boolean update, boolean useCursor) throws SQLException { String warningMessage = null; // // For SQL Server, try to open a cursor result set if required // (and possible). // if (connection.getServerType() == Driver.SQLSERVER && !update && useCursor) { try { currentResult = new MSCursorResultSet(this, sql, spName, params, resultSetType, resultSetConcurrency); return true; } catch (SQLException e) { if (connection == null || connection.isClosed() || "HYT00".equals(e.getSQLState())) { // Serious error or timeout so return exception to caller throw e; } warningMessage = '[' + e.getSQLState() + "] " + e.getMessage(); } } // // We are talking to a Sybase server or we could not open a cursor // or we did not have a SELECT so just execute the SQL normally. // tds.executeSQL(sql, spName, params, false, queryTimeout, maxRows, maxFieldSize, true); if (warningMessage != null) { // Update warning chain if cursor was downgraded addWarning(new SQLWarning(Messages.get( "warning.cursordowngraded", warningMessage), "01000")); } if (processResults(returnKeys, update)) { Object nextResult = resultQueue.removeFirst(); // Next result is an update count if (nextResult instanceof Integer) { updateCount = ((Integer) nextResult).intValue(); return false; } // Next result is a ResultSet. Set currentResult and remove it. currentResult = (JtdsResultSet) nextResult; return true; } else { return false; } } /** * Queue up update counts into {@link #resultQueue} until the end of the * response is reached or a <code>ResultSet</code> is encountered. Calling * <code>processResults</code> while a <code>ResultSet</code> is open will * not close it, but will consume all remaining rows. * * @param returnKeys <code>true</code> if a generated keys * <code>ResultSet</code> is expected * @param update <code>true</code> if the method is called from within * <code>executeUpdate</code> * @return <code>true</code> if there are any results, * <code>false</code> otherwise * @throws SQLException if an error condition occurs */ private boolean processResults(boolean returnKeys, boolean update) throws SQLException { if (!resultQueue.isEmpty()) { throw new IllegalStateException( "There should be no queued results."); } while (!tds.isEndOfResponse()) { if (!tds.getMoreResults()) { if (tds.isUpdateCount()) { if (update && connection.isLastUpdateCount()) { resultQueue.clear(); } resultQueue.addLast(new Integer(tds.getUpdateCount())); } } else { if (returnKeys) { // This had better be the generated key // FIXME We could use SELECT @@IDENTITY AS jTDS_SOMETHING and check the column name to make sure if (tds.getNextRow()) { genKeyResultSet = new CachedResultSet(this, tds.getColumns(), tds.getRowData()); } } else { if (update && resultQueue.isEmpty()) { // Throw exception but queue up any previous ones SQLException ex = new SQLException( Messages.get("error.statement.nocount"), "07000"); ex.setNextException(messages.exceptions); throw ex; } resultQueue.add(new JtdsResultSet( this, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, tds.getColumns())); break; } } } // Check for server side errors getMessages().checkErrors(); return !resultQueue.isEmpty(); } /** * Cache as many results as possible (up to the first * <code>ResultSet</code>). Called by <code>ResultSet</code>s when the * end is reached. */ protected void cacheResults() throws SQLException { // Cache results processResults(false, false); } /** * Initialize the <code>Statement</code>, by cleaning up all queued and * unprocessed results. Called by all execute methods. * * @throws SQLException if an error occurs */ protected void initialize() throws SQLException { updateCount = -1; resultQueue.clear(); genKeyResultSet = null; tds.clearResponseQueue(); // FIXME Should old exceptions found now be thrown instead of lost? messages.exceptions = null; messages.clearWarnings(); closeAllResultSets(); } /** * Implements the common functionality for plain statement {@link #execute} * and {#link #executeUpdate}: basic checks, cleaning up of previous * results, setting up and executing the query and loading the first * results. * * @param sql an SQL <code>INSERT</code>, <code>UPDATE</code> or * <code>DELETE</code> statement or an SQL statement that * returns nothing, such as an SQL DDL statement * @param autoGeneratedKeys a flag indicating whether auto-generated keys * should be made available for retrieval * @param update boolean flag indicating whether the caller is * {@link #executeUpdate} -- in this case an exception is * thrown if the first result is not an update count and no * cursor is created (direct execution) * @return <code>true</code> if the first result is a * <code>ResultSet</code>, <code>false</code> if it's an update * count * @see #execute * @see #executeUpdate */ private boolean executeImpl(String sql, int autoGeneratedKeys, boolean update) throws SQLException { checkOpen(); initialize(); if (sql == null || sql.length() == 0) { throw new SQLException(Messages.get("error.generic.nosql"), "HY000"); } boolean returnKeys; String sqlWord = ""; if (escapeProcessing) { String tmp[] = SQLParser.parse(sql, null, connection, false); if (tmp[1].length() != 0) { throw new SQLException( Messages.get("error.statement.badsql"), "07000"); } sql = tmp[0]; sqlWord = tmp[2]; } else { // Escape processing turned off so // see if we can extract "insert" from start of statement sql = sql.trim(); if (sql.length() > 5) { sqlWord = sql.substring(0,6).toLowerCase(); } } if (autoGeneratedKeys == RETURN_GENERATED_KEYS) { returnKeys = sqlWord.equals("insert"); } else if (autoGeneratedKeys == NO_GENERATED_KEYS) { returnKeys = false; } else { throw new SQLException( Messages.get("error.generic.badoption", Integer.toString(autoGeneratedKeys), "autoGeneratedKeys"), "HY092"); } if (returnKeys) { if (connection.getServerType() == Driver.SQLSERVER && connection.getDatabaseMajorVersion() >= 8) { sql += " SELECT SCOPE_IDENTITY() AS ID"; } else { sql += " SELECT @@IDENTITY AS ID"; } } return executeSQL(sql, null, null, returnKeys, update, !update && useCursor(returnKeys, sqlWord)); } /** * Determines whether a cursor should be used based on the requested result * set type and concurrency, whether a cursor name has been set, the * <code>useCursors</code> connection property has been set, the first * word in the SQL query is either SELECT or EXEC/EXECUTE and no generated * keys are returned. * * @param returnKeys indicates whether keys will be returned by the query * @param sqlWord the first word in the SQL query; can be * <code>null</code> if the caller is * {@link #executeQuery} * @return <code>true</code> if a cursor should be used, <code>false</code> * if not */ protected boolean useCursor(boolean returnKeys, String sqlWord) { return (resultSetType != ResultSet.TYPE_FORWARD_ONLY || resultSetConcurrency != ResultSet.CONCUR_READ_ONLY || connection.getUseCursors() || cursorName != null) && !returnKeys && (sqlWord == null || sqlWord.equals("select") || sqlWord.startsWith("exec")); }// ------------------ java.sql.Statement methods ---------------------- public int getFetchDirection() throws SQLException { checkOpen(); return this.fetchDirection; } public int getFetchSize() throws SQLException { checkOpen(); return this.fetchSize; } public int getMaxFieldSize() throws SQLException { checkOpen(); return this.maxFieldSize; } public int getMaxRows() throws SQLException { checkOpen(); return this.maxRows; } public int getQueryTimeout() throws SQLException { checkOpen(); return this.queryTimeout; } public int getResultSetConcurrency() throws SQLException { checkOpen(); return this.resultSetConcurrency; } public int getResultSetHoldability() throws SQLException { checkOpen(); return JtdsResultSet.HOLD_CURSORS_OVER_COMMIT; } public int getResultSetType() throws SQLException { checkOpen(); return resultSetType; } public int getUpdateCount() throws SQLException { checkOpen(); return updateCount; } public void cancel() throws SQLException { checkOpen(); if (tds != null) { tds.cancel(); } } public void clearBatch() throws SQLException { checkOpen(); if (batchValues != null) { batchValues.clear(); } } public void clearWarnings() throws SQLException { checkOpen(); messages.clearWarnings(); } public void close() throws SQLException { if (!closed) { try { closeAllResultSets(); } finally { SQLException releaseEx = null; try { if (!connection.isClosed()) { connection.releaseTds(tds); } // Check for server side errors tds.getMessages().checkErrors(); } catch (SQLException ex) { // Remember any exception thrown releaseEx = ex; } finally { // Clean up everything closed = true; tds = null; connection.removeStatement(this); connection = null; // Re-throw any caught exception if (releaseEx != null) { throw releaseEx; } } } } } public boolean getMoreResults() throws SQLException { checkOpen(); return getMoreResults(CLOSE_ALL_RESULTS); } /** * Execute batch of SQL Statements. * <p/> * The JDBC3 standard says that for a server which does not continue * processing a batch once the first error has occurred (e.g. SQL Server), * the returned array will never contain <code>EXECUTE_FAILED</code> in any * of the elements. If a failure has occurred the array length will be less * than the count of statements in the batch. For those servers that do * continue to execute a batch containing an error (e.g. Sybase), elements * may contain <code>EXECUTE_FAILED</code>. Note: even here the array * length may also be shorter than the statement count if a serious error * has prevented the rest of the batch from being executed. In addition, * when executing batched stored procedures, Sybase will also stop after * the first error. * * @return update counts as an <code>int[]</code> */ public int[] executeBatch() throws SQLException, BatchUpdateException { checkOpen(); initialize();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -