📄 jtdsstatement.java
字号:
/**
* Execute the SQL batch on a MS server.
*
* @param size the total size of the batch
* @param executeSize the maximum number of statements to send in one request
* @param counts the returned update counts
* @return chained exceptions linked to a <code>SQLException</code>
* @throws SQLException if a serious error occurs during execution
*/
protected SQLException executeMSBatch(int size, int executeSize, ArrayList counts) throws SQLException {
SQLException sqlEx = null;
for (int i = 0; i < size;) {
Object value = batchValues.get(i);
++i;
// Execute batch now if max size reached or end of batch
boolean executeNow = (i % executeSize == 0) || i == size;
tds.startBatch();
tds.executeSQL((String) value, null, null, false, 0, -1, -1, executeNow);
// If the batch has been sent, process the results
if (executeNow) {
sqlEx = tds.getBatchCounts(counts, sqlEx);
// If a serious error then we stop execution now as count
// is too small.
if (sqlEx != null && counts.size() != i) {
break;
}
}
}
return sqlEx;
}
/**
* Execute the SQL batch on a Sybase server.
* <p/>
* Sybase needs to have the SQL concatenated into one TDS language packet. This method will be overriden for
* <code>PreparedStatements</code>.
*
* @param size the total size of the batch
* @param executeSize the maximum number of statements to send in one request
* @param counts the returned update counts
* @return chained exceptions linked to a <code>SQLException</code>
* @throws SQLException if a serious error occurs during execution
*/
protected SQLException executeSybaseBatch(int size, int executeSize, ArrayList counts) throws SQLException {
StringBuffer sql = new StringBuffer(size * 32); // Make buffer reasonable size
SQLException sqlEx = null;
for (int i = 0; i < size;) {
Object value = batchValues.get(i);
++i;
// Execute batch now if max size reached or end of batch
boolean executeNow = (i % executeSize == 0) || i == size;
sql.append((String) value).append(' ');
if (executeNow) {
tds.executeSQL(sql.toString(), null, null, false, 0, -1, -1, true);
sql.setLength(0);
// If the batch has been sent, process the results
sqlEx = tds.getBatchCounts(counts, sqlEx);
// If a serious error or a server error then we stop
// execution now as count is too small.
if (sqlEx != null && counts.size() != i) {
break;
}
}
}
return sqlEx;
}
/**
* Executes SQL to obtain a result set.
*
* @param sql the SQL statement to execute
* @param spName optional stored procedure name
* @param params optional parameters
* @param useCursor whether a cursor should be created for the SQL
* @return the result set generated by the query
*/
protected ResultSet executeSQLQuery(String sql,
String spName,
ParamInfo[] params,
boolean useCursor)
throws SQLException {
String warningMessage = null;
//
// Try to open a cursor result set if required
//
if (useCursor) {
try {
if (connection.getServerType() == Driver.SQLSERVER) {
currentResult =
new MSCursorResultSet(this,
sql,
spName,
params,
resultSetType,
resultSetConcurrency);
return currentResult;
} else {
// Use client side cursor for Sybase
currentResult =
new CachedResultSet(this,
sql,
spName,
params,
resultSetType,
resultSetConcurrency);
return currentResult;
}
} catch (SQLException e) {
checkCursorException(e);
warningMessage = '[' + e.getSQLState() + "] " + e.getMessage();
}
}
//
// Could not open a cursor (or was not requested) so try a direct select
//
if (spName != null
&& connection.getUseMetadataCache()
&& connection.getPrepareSql() == TdsCore.PREPARE
&& colMetaData != null
&& connection.getServerType() == Driver.SQLSERVER) {
// There is cached meta data available for this
// prepared statement
tds.setColumns(colMetaData);
tds.executeSQL(sql, spName, params, true, queryTimeout, maxRows,
maxFieldSize, true);
} else {
tds.executeSQL(sql, spName, params, false, queryTimeout, maxRows,
maxFieldSize, true);
}
// Update warning chain if cursor was downgraded before processing results
if (warningMessage != null) {
addWarning(new SQLWarning(
Messages.get("warning.cursordowngraded", warningMessage), "01000"));
}
// Ignore update counts preceding the result set. All drivers seem to
// do this.
while (!tds.getMoreResults() && !tds.isEndOfResponse());
// check for server side errors
messages.checkErrors();
if (tds.isResultSet()) {
currentResult = new JtdsResultSet(this,
ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_READ_ONLY,
tds.getColumns());
} else {
throw new SQLException(
Messages.get("error.statement.noresult"), "24000");
}
return currentResult;
}
/**
* Executes any type of SQL.
*
* @param sql the SQL statement to execute
* @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) {
checkCursorException(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.getLastUpdateCount()) {
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();
}
/**
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -