📄 tdscore.java
字号:
}
/**
* Retrieve the status of the next result item.
*
* @return <code>boolean</code> true if the next item is an update count.
*/
boolean isUpdateCount() {
return currentToken.isUpdateCount();
}
/**
* Retrieve the update count from the current TDS token.
*
* @return The update count as an <code>int</code>.
*/
int getUpdateCount() {
if (currentToken.isEndToken()) {
return currentToken.updateCount;
}
return -1;
}
/**
* Retrieve the status of the response stream.
*
* @return <code>boolean</code> true if the response has been entirely consumed
*/
boolean isEndOfResponse() {
return endOfResponse;
}
/**
* Empty the server response queue.
*
* @throws SQLException if an error occurs
*/
void clearResponseQueue() throws SQLException {
checkOpen();
while (!endOfResponse) {
nextToken();
}
}
/**
* Consume packets from the server response queue up to (and including) the
* first response terminator.
*
* @throws SQLException if an I/O or protocol error occurs; server errors
* are queued up and not thrown
*/
void consumeOneResponse() throws SQLException {
checkOpen();
while (!endOfResponse) {
nextToken();
// If it's a response terminator, return
if (currentToken.isEndToken()
&& (currentToken.status & DONE_END_OF_RESPONSE) != 0) {
return;
}
}
}
/**
* Retrieve the next data row from the result set.
*
* @return <code>false</code> if at the end of results, <code>true</code>
* otherwise
* @throws SQLException if an I/O or protocol error occurs; server errors
* are queued up and not thrown
*/
boolean getNextRow() throws SQLException {
if (endOfResponse || endOfResults) {
return false;
}
checkOpen();
nextToken();
// Will either be first or next data row or end.
while (!currentToken.isRowData() && !currentToken.isEndToken()) {
nextToken(); // Could be messages
}
return currentToken.isRowData();
}
/**
* Retrieve the status of result set.
* <p>
* This does a quick read ahead and is needed to support the isLast()
* method in the ResultSet.
*
* @return <code>boolean</code> - <code>true</code> if there is more data
* in the result set.
*/
boolean isDataInResultSet() throws SQLException {
byte x;
checkOpen();
try {
x = (endOfResponse) ? TDS_DONE_TOKEN : (byte) in.peek();
while (x != TDS_ROW_TOKEN
&& x != TDS_DONE_TOKEN
&& x != TDS_DONEINPROC_TOKEN
&& x != TDS_DONEPROC_TOKEN) {
nextToken();
x = (byte) in.peek();
}
messages.checkErrors();
} catch (IOException e) {
connection.setClosed();
throw Support.linkException(
new SQLException(
Messages.get(
"error.generic.ioerror", e.getMessage()),
"08S01"), e);
}
return x == TDS_ROW_TOKEN;
}
/**
* Retrieve the return status for the current stored procedure.
*
* @return The return status as an <code>Integer</code>.
*/
Integer getReturnStatus() {
return this.returnStatus;
}
/**
* Inform the server that this connection is closing.
* <p>
* Used by Sybase a no-op for Microsoft.
*/
synchronized void closeConnection() {
try {
if (tdsVersion == Driver.TDS50) {
socket.setTimeout(1000);
out.setPacketType(SYBQUERY_PKT);
out.write((byte)TDS_CLOSE_TOKEN);
out.write((byte)0);
out.flush();
endOfResponse = false;
clearResponseQueue();
}
} catch (Exception e) {
// Ignore any exceptions as this connection
// is closing anyway.
}
}
/**
* Close the <code>TdsCore</code> connection object and associated streams.
*/
void close() throws SQLException {
if (!isClosed) {
try {
clearResponseQueue();
out.close();
in.close();
} finally {
isClosed = true;
}
}
}
/**
* Send (only) one cancel packet to the server.
*
* @param timeout true if this is a query timeout cancel
*/
void cancel(boolean timeout) {
Semaphore mutex = null;
try {
mutex = connection.getMutex();
synchronized (cancelMonitor) {
if (!cancelPending && !endOfResponse) {
cancelPending = socket.cancel(out.getStreamId());
}
// If a cancel request was sent, reset the end of response flag
if (cancelPending) {
cancelMonitor[0] = timeout ? TIMEOUT_CANCEL : ASYNC_CANCEL;
endOfResponse = false;
}
}
} finally {
if (mutex != null) {
mutex.release();
}
}
}
/**
* Submit a simple SQL statement to the server and process all output.
*
* @param sql the statement to execute
* @throws SQLException if an error is returned by the server
*/
void submitSQL(String sql) throws SQLException {
checkOpen();
messages.clearWarnings();
if (sql.length() == 0) {
throw new IllegalArgumentException("submitSQL() called with empty SQL String");
}
executeSQL(sql, null, null, false, 0, -1, -1, true);
clearResponseQueue();
messages.checkErrors();
}
/**
* Notifies the <code>TdsCore</code> that a batch is starting. This is so
* that it knows to use <code>sp_executesql</code> for parameterized
* queries (because there's no way to prepare a statement in the middle of
* a batch).
* <p>
* Sets the {@link #inBatch} flag.
*/
void startBatch() {
inBatch = true;
}
/**
* Send an SQL statement with optional parameters to the server.
*
* @param sql SQL statement to execute
* @param procName stored procedure to execute or <code>null</code>
* @param parameters parameters for call or null
* @param noMetaData suppress meta data for cursor calls
* @param timeOut optional query timeout or 0
* @param maxRows the maximum number of data rows to return (-1 to
* leave unaltered)
* @param maxFieldSize the maximum number of bytes in a column to return
* (-1 to leave unaltered)
* @param sendNow whether to send the request now or not
* @throws SQLException if an error occurs
*/
synchronized void executeSQL(String sql,
String procName,
ParamInfo[] parameters,
boolean noMetaData,
int timeOut,
int maxRows,
int maxFieldSize,
boolean sendNow)
throws SQLException {
boolean sendFailed = true; // Used to ensure mutex is released.
try {
//
// Obtain a lock on the connection giving exclusive access
// to the network connection for this thread
//
if (connectionLock == null) {
connectionLock = connection.getMutex();
}
// Also checks if connection is open
clearResponseQueue();
messages.exceptions = null;
//
// Set the connection row count and text size if required.
// Once set these will not be changed within a
// batch so execution of the set rows query will
// only occur once a the start of a batch.
// No other thread can send until this one has finished.
//
setRowCountAndTextSize(maxRows, maxFieldSize);
messages.clearWarnings();
this.returnStatus = null;
//
// Normalize the parameters argument to simplify later checks
//
if (parameters != null && parameters.length == 0) {
parameters = null;
}
this.parameters = parameters;
//
// Normalise the procName argument as well
//
if (procName != null && procName.length() == 0) {
procName = null;
}
if (parameters != null && parameters[0].isRetVal) {
returnParam = parameters[0];
nextParam = 0;
} else {
returnParam = null;
nextParam = -1;
}
if (parameters != null) {
if (procName == null && sql.startsWith("EXECUTE ")) {
//
// If this is a callable statement that could not be fully parsed
// into an RPC call convert to straight SQL now.
// An example of non RPC capable SQL is {?=call sp_example('literal', ?)}
//
for (int i = 0; i < parameters.length; i++){
// Output parameters not allowed.
if (!parameters[i].isRetVal && parameters[i].isOutput){
throw new SQLException(Messages.get("error.prepare.nooutparam",
Integer.toString(i + 1)), "07000");
}
}
sql = Support.substituteParameters(sql, parameters, connection);
parameters = null;
} else {
//
// Check all parameters are either output or have values set
//
for (int i = 0; i < parameters.length; i++){
if (!parameters[i].isSet && !parameters[i].isOutput){
throw new SQLException(Messages.get("error.prepare.paramnotset",
Integer.toString(i + 1)), "07000");
}
parameters[i].clearOutValue();
// FIXME Should only set TDS type if not already set
// but we might need to take a lot of care not to
// exceed size limitations (e.g. write 11 chars in a
// VARCHAR(10) )
TdsData.getNativeType(connection, parameters[i]);
}
}
}
try {
switch (tdsVersion) {
case Driver.TDS42:
executeSQL42(sql, procName, parameters, noMetaData, sendNow);
break;
case Driver.TDS50:
executeSQL50(sql, procName, parameters);
break;
case Driver.TDS70:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -