📄 tdscore.java
字号:
case 1: // Set OLE transaction ID
if (oleTranID != null) {
out.write((short)oleTranID.length);
out.write(oleTranID);
} else {
// Delist the connection from all transactions.
out.write((short)0);
}
break;
}
out.flush();
endOfResponse = false;
endOfResults = true;
} catch (IOException ioe) {
connection.setClosed();
throw Support.linkException(
new SQLException(
Messages.get(
"error.generic.ioerror", ioe.getMessage()),
"08S01"),
ioe);
} finally {
if (mutex != null) {
mutex.release();
}
}
byte[] tmAddress = null;
if (getMoreResults() && getNextRow()) {
if (rowData.length == 1) {
Object x = rowData[0];
if (x instanceof byte[]) {
tmAddress = (byte[])x;
}
}
}
clearResponseQueue();
messages.checkErrors();
return tmAddress;
}
/**
* Obtain the counts from a batch of SQL updates.
* <p/>
* If an error occurs Sybase will continue processing a batch consisting of
* TDS_LANGUAGE records whilst SQL Server will usually stop after the first
* error except when the error is caused by a duplicate key.
* Sybase will also stop after the first error when executing RPC calls.
* Care is taken to ensure that <code>SQLException</code>s are chained
* because there could be several errors reported in a batch.
*
* @param counts the <code>ArrayList</code> containing the update counts
* @param sqlEx any previous <code>SQLException</code>(s) encountered
* @return updated <code>SQLException</code> or <code>null</code> if no
* error has yet occured
*/
SQLException getBatchCounts(ArrayList counts, SQLException sqlEx) {
Integer lastCount = JtdsStatement.SUCCESS_NO_INFO;
try {
checkOpen();
while (!endOfResponse) {
nextToken();
if (currentToken.isResultSet()) {
// Serious error, statement must not return a result set
throw new SQLException(
Messages.get("error.statement.batchnocount"),
"07000");
}
//
// Analyse type of end token and try to extract correct
// update count when calling stored procs.
//
switch (currentToken.token) {
case TDS_DONE_TOKEN:
if ((currentToken.status & DONE_ERROR) != 0
|| lastCount == JtdsStatement.EXECUTE_FAILED) {
counts.add(JtdsStatement.EXECUTE_FAILED);
} else {
if (currentToken.isUpdateCount()) {
counts.add(new Integer(currentToken.updateCount));
} else {
counts.add(lastCount);
}
}
lastCount = JtdsStatement.SUCCESS_NO_INFO;
break;
case TDS_DONEINPROC_TOKEN:
if ((currentToken.status & DONE_ERROR) != 0) {
lastCount = JtdsStatement.EXECUTE_FAILED;
} else if (currentToken.isUpdateCount()) {
lastCount = new Integer(currentToken.updateCount);
}
break;
case TDS_DONEPROC_TOKEN:
if ((currentToken.status & DONE_ERROR) != 0
|| lastCount == JtdsStatement.EXECUTE_FAILED) {
counts.add(JtdsStatement.EXECUTE_FAILED);
} else {
counts.add(lastCount);
}
lastCount = JtdsStatement.SUCCESS_NO_INFO;
break;
}
}
//
// Check for any exceptions
//
messages.checkErrors();
} catch (SQLException e) {
//
// Chain all exceptions
//
if (sqlEx != null) {
sqlEx.setNextException(e);
} else {
sqlEx = e;
}
} finally {
while (!endOfResponse) {
// Flush rest of response
try {
nextToken();
} catch (SQLException ex) {
// Chain any exceptions to the BatchUpdateException
if (sqlEx != null) {
sqlEx.setNextException(ex);
} else {
sqlEx = ex;
}
}
}
}
return sqlEx;
}
// ---------------------- Private Methods from here ---------------------
/**
* Write a TDS login packet string. Text followed by padding followed
* by a byte sized length.
*/
private void putLoginString(String txt, int len)
throws IOException {
byte[] tmp = Support.encodeString(connection.getCharset(), txt);
out.write(tmp, 0, len);
out.write((byte) (tmp.length < len ? tmp.length : len));
}
/**
* Send the SQL Server 2000 pre login packet.
* <p>Packet contains; netlib version, ssl mode, instance
* and process ID.
* @param instance
* @param forceEncryption
* @throws IOException
*/
private void sendPreLoginPacket(String instance, boolean forceEncryption)
throws IOException {
out.setPacketType(PRELOGIN_PKT);
// Write Netlib pointer
out.write((short)0);
out.write((short)21);
out.write((byte)6);
// Write Encrypt flag pointer
out.write((short)1);
out.write((short)27);
out.write((byte)1);
// Write Instance name pointer
out.write((short)2);
out.write((short)28);
out.write((byte)(instance.length()+1));
// Write process ID pointer
out.write((short)3);
out.write((short)(28+instance.length()+1));
out.write((byte)4);
// Write terminator
out.write((byte)0xFF);
// Write fake net lib ID 8.341.0
out.write(new byte[]{0x08, 0x00, 0x01, 0x55, 0x00, 0x00});
// Write force encryption flag
out.write((byte)(forceEncryption? 1: 0));
// Write instance name
out.writeAscii(instance);
out.write((byte)0);
// Write dummy process ID
out.write(new byte[]{0x01, 0x02, 0x00, 0x00});
//
out.flush();
}
/**
* Process the pre login acknowledgement from the server.
* <p>Packet contains; server version no, SSL mode, instance name
* and process id.
* <p>Server returns the following values for SSL mode:
* <ol>
* <ll>0 = Certificate installed encrypt login packet only.
* <li>1 = Certificate installed client requests force encryption.
* <li>2 = No certificate no encryption possible.
* <li>3 = Server requests force encryption.
* </ol>
* @return The server side SSL mode.
* @throws IOException
*/
private int readPreLoginPacket() throws IOException {
byte list[][] = new byte[8][];
byte data[][] = new byte[8][];
int recordCount = 0;
byte record[] = new byte[5];
// Read entry pointers
record[0] = (byte)in.read();
while ((record[0] & 0xFF) != 0xFF) {
if (recordCount == list.length) {
throw new IOException("Pre Login packet has more than 8 entries");
}
// Read record
in.read(record, 1, 4);
list[recordCount++] = record;
record = new byte[5];
record[0] = (byte)in.read();
}
// Read entry data
for (int i = 0; i < recordCount; i++) {
byte value[] = new byte[(byte)list[i][4]];
in.read(value);
data[i] = value;
}
if (Logger.isActive()) {
// Diagnostic dump
Logger.println("PreLogin server response");
for (int i = 0; i < recordCount; i++) {
Logger.println("Record " + i+ " = " +
Support.toHex(data[i]));
}
}
if (recordCount > 1) {
return data[1][0]; // This is the server side SSL mode
} else {
// Response too short to include SSL mode!
return SSL_NO_ENCRYPT;
}
}
/**
* TDS 4.2 Login Packet.
*
* @param serverName server host name
* @param user user name
* @param password user password
* @param charset required server character set
* @param appName application name
* @param progName program name
* @param wsid workstation ID
* @param language server language for messages
* @param packetSize required network packet size
* @throws IOException if an I/O error occurs
*/
private void send42LoginPkt(final String serverName,
final String user,
final String password,
final String charset,
final String appName,
final String progName,
final String wsid,
final String language,
final int packetSize)
throws IOException {
final byte[] empty = new byte[0];
out.setPacketType(LOGIN_PKT);
putLoginString(wsid, 30); // Host name
putLoginString(user, 30); // user name
putLoginString(password, 30); // password
putLoginString("00000123", 30); // hostproc (offset 93 0x5d)
out.write((byte) 3); // type of int2
out.write((byte) 1); // type of int4
out.write((byte) 6); // type of char
out.write((byte) 10);// type of flt
out.write((byte) 9); // type of date
out.write((byte) 1); // notify of use db
out.write((byte) 1); // disallow dump/load and bulk insert
out.write((byte) 0); // sql interface type
out.write((byte) 0); // type of network connection
out.write(empty, 0, 7);
putLoginString(appName, 30); // appname
putLoginString(serverName, 30); // server name
out.write((byte)0); // remote passwords
out.write((byte)password.length());
byte[] tmp = Support.encodeString(connection.getCharset(), password);
out.write(tmp, 0, 253);
out.write((byte) (tmp.length + 2));
out.write((byte) 4); // tds version
out.write((byte) 2);
out.write((byte) 0);
out.write((byte) 0);
putLoginString(progName, 10); // prog name
out.write((byte) 6); // prog version
out.write((byte) 0);
out.write((byte) 0);
out.write((byte) 0);
out.write((byte) 0); // auto convert short
out.write((byte) 0x0D); // type of flt4
out.write((byte) 0x11); // type of date4
putLoginString(language, 30); // language
out.write((byte) 1); // notify on lang change
out.write((short) 0); // security label hierachy
out.write((byte) 0); // security encrypted
out.write(empty, 0, 8); // security components
out.write((short) 0); // security spare
putLoginString(charset, 30); // Character set
out.write((byte) 1); // notify on charset change
putLoginString(String.valueOf(packetSize), 6); // length of tds packets
out.write(empty, 0, 8); // pad out to a longword
out.flush(); // Send the packet
endOfResponse = false;
}
/**
* TDS 5.0 Login Packet.
* <P>
* @param serverName server host name
* @par
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -