📄 connectionjdbc2.java
字号:
// with cached TDS versions at this point.
tdsVersion = baseTds.getTdsVersion();
if (tdsVersion < Driver.TDS70 && databaseName.length() > 0) {
// Need to select the default database
setCatalog(databaseName);
}
} catch (UnknownHostException e) {
throw Support.linkException(
new SQLException(Messages.get("error.connection.badhost",
e.getMessage()), "08S03"), e);
} catch (IOException e) {
if (loginTimeout > 0 && e.getMessage().indexOf("timed out") >= 0) {
throw Support.linkException(
new SQLException(Messages.get("error.connection.timeout"), "HYT01"), e);
}
throw Support.linkException(
new SQLException(Messages.get("error.connection.ioerror",
e.getMessage()), "08S01"), e);
} catch (SQLException e) {
if (loginTimeout > 0 && e.getMessage().indexOf("socket closed") >= 0) {
throw Support.linkException(
new SQLException(Messages.get("error.connection.timeout"), "HYT01"), e);
}
throw e;
}
// If charset is still unknown and the collation is not set either,
// determine the charset by querying (we're using Sybase or SQL Server
// 6.5)
if ((serverCharset == null || serverCharset.length() == 0)
&& collation == null) {
loadCharset(determineServerCharset());
}
// Initial database settings.
// Sets: auto commit mode = true
// transaction isolation = read committed.
if (serverType == Driver.SYBASE) {
baseTds.submitSQL(SYBASE_INITIAL_SQL);
} else {
// Also discover the maximum decimal precision: 28 (default)
// or 38 for MS SQL Server 6.5/7, or 38 for 2000 and later.
Statement stmt = this.createStatement();
ResultSet rs = stmt.executeQuery(SQL_SERVER_INITIAL_SQL);
if (rs.next()) {
maxPrecision = rs.getByte(1);
}
rs.close();
stmt.close();
}
//
// Restore any login warnings so that the user can retrieve them
// by calling Connection.getWarnings()
//
messages.warnings = warn;
}
/**
* Creates a {@link SharedSocket} object representing a connection to a named
* pipe. If the <code>os.name</code> system property starts with "Windows"
* (case-insensitive) and the <code>useJCIFS</code> parameter is
* <code>false</code>, a {@link SharedLocalNamedPipe} object is created.
* Else a {@link SharedNamedPipe} is created which uses
* <a href="http://jcifs.samba.org/">jCIFS</a> to provide a pure-Java
* implementation of Windows named pipes.
* <p>
* This method will retry for <code>loginTimeout</code> seconds to create a
* named pipe if an <code>IOException</code> continues to be thrown stating,
* "All pipe instances are busy". If <code>loginTimeout</code> is set to
* zero (e.g., not set), a default of 20 seconds will be used.
*
* @param connection the connection object
* @return an object representing the named pipe connection
* @throws IOException on error; if an <code>IOException</code> is thrown with
* a message stating "All pipe instances are busy", then the method timed out
* after <code>loginTimeout</code> milliseconds attempting to create a named pipe.
*/
private SharedSocket createNamedPipe(ConnectionJDBC2 connection) throws IOException {
final long loginTimeout = connection.getLoginTimeout();
final long retryTimeout = (loginTimeout > 0 ? loginTimeout : 20) * 1000;
final long startLoginTimeout = System.currentTimeMillis();
final Random random = new Random(startLoginTimeout);
final boolean isWindowsOS = Support.isWindowsOS();
SharedSocket socket = null;
IOException lastIOException = null;
int exceptionCount = 0;
do {
try {
if (isWindowsOS && !connection.getUseJCIFS()) {
socket = new SharedLocalNamedPipe(connection);
}
else {
socket = new SharedNamedPipe(connection);
}
}
catch (IOException ioe) {
exceptionCount++;
lastIOException = ioe;
if (ioe.getMessage().toLowerCase().indexOf("all pipe instances are busy") >= 0) {
// Per a Microsoft knowledgebase article, wait 200 ms to 1 second each time
// we get an "All pipe instances are busy" error.
// http://support.microsoft.com/default.aspx?scid=KB;EN-US;165189
final int randomWait = random.nextInt(800) + 200;
if (Logger.isActive()) {
Logger.println("Retry #" + exceptionCount + " Wait " + randomWait + " ms: " +
ioe.getMessage());
}
try {
Thread.sleep(randomWait);
}
catch (InterruptedException ie) {
// Do nothing; retry again
}
}
else {
throw ioe;
}
}
} while (socket == null && (System.currentTimeMillis() - startLoginTimeout) < retryTimeout);
if (socket == null) {
final IOException ioException = new IOException("Connection timed out to named pipe");
Support.linkException(ioException, lastIOException);
throw ioException;
}
return socket;
}
/**
* Retrive the shared socket.
*
* @return The <code>SharedSocket</code> object.
*/
SharedSocket getSocket() {
return this.socket;
}
/**
* Retrieve the TDS protocol version.
*
* @return The TDS version as an <code>int</code>.
*/
int getTdsVersion() {
return this.tdsVersion;
}
/**
* Retrieves the next unique stored procedure name.
* <p>Notes:
* <ol>
* <li>Some versions of Sybase require an id with
* a length of <= 10.
* <li>The format of this name works for sybase and Microsoft
* and allows for 16M names per session.
* <li>The leading '#jtds' indicates this is a temporary procedure and
* the '#' is removed by the lower level TDS5 routines.
* </ol>
* Not synchronized because it's only called from the synchronized
* {@link #prepareSQL} method.
*
* @return the next temporary SP name as a <code>String</code>
*/
String getProcName() {
String seq = "000000" + Integer.toHexString(spSequenceNo++).toUpperCase();
return "#jtds" + seq.substring(seq.length() - 6, seq.length());
}
/**
* Retrieves the next unique cursor name.
*
* @return the next cursor name as a <code>String</code>
*/
synchronized String getCursorName() {
String seq = "000000" + Integer.toHexString(cursorSequenceNo++).toUpperCase();
return "_jtds" + seq.substring(seq.length() - 6, seq.length());
}
/**
* Try to convert the SQL statement into a statement prepare.
* <p>
* Synchronized because it accesses the procedure cache and the
* <code>baseTds</code>, but the method call also needs to made in a
* <code>synchronized (connection)</code> block together with the execution
* (if the prepared statement is actually executed) to ensure the
* transaction isn't rolled back between this method call and the actual
* execution.
*
* @param pstmt the target prepared statement
* @param sql the SQL statement to prepare
* @param params the parameters
* @param returnKeys indicates whether the statement will return
* generated keys
* @param cursorNeeded indicates whether a cursor prepare is needed
* @return the SQL procedure name as a <code>String</code> or null if the
* SQL cannot be prepared
*/
synchronized String prepareSQL(JtdsPreparedStatement pstmt,
String sql,
ParamInfo[] params,
boolean returnKeys,
boolean cursorNeeded)
throws SQLException {
if (prepareSql == TdsCore.UNPREPARED
|| prepareSql == TdsCore.EXECUTE_SQL) {
return null; // User selected not to use procs
}
if (serverType == Driver.SYBASE) {
if (tdsVersion != Driver.TDS50) {
return null; // No longer support stored procs with 4.2
}
if (returnKeys) {
return null; // Sybase cannot use @@IDENTITY in proc
}
if (cursorNeeded) {
//
// We are going to use the CachedResultSet so there is
// no point in preparing the SQL as it will be discarded
// in favour of a version with "FOR BROWSE" appended.
//
return null;
}
}
//
// Check parameters set and obtain native types
//
for (int i = 0; i < params.length; i++) {
if (!params[i].isSet) {
throw new SQLException(Messages.get("error.prepare.paramnotset",
Integer.toString(i+1)),
"07000");
}
TdsData.getNativeType(this, params[i]);
if (serverType == Driver.SYBASE) {
if ("text".equals(params[i].sqlType)
|| "image".equals(params[i].sqlType)) {
return null; // Sybase does not support text/image params
}
}
}
String key = Support.getStatementKey(sql, params, serverType,
getCatalog(), autoCommit, cursorNeeded);
//
// See if we have already built this one
//
ProcEntry proc = (ProcEntry) statementCache.get(key);
if (proc != null) {
//
// Yes found in cache OK
//
// If already used by the statement, decrement use count
if (pstmt.handles != null && pstmt.handles.contains(proc)) {
proc.release();
}
pstmt.setColMetaData(proc.getColMetaData());
if (serverType == Driver.SYBASE) {
pstmt.setParamMetaData(proc.getParamMetaData());
}
} else {
//
// No, so create the stored procedure now
//
proc = new ProcEntry();
if (serverType == Driver.SQLSERVER) {
proc.setName(
baseTds.microsoftPrepare(
sql, params, cursorNeeded,
pstmt.getResultSetType(),
pstmt.getResultSetConcurrency()));
if (proc.toString() == null) {
proc.setType(ProcEntry.PREP_FAILED);
} else if (prepareSql == TdsCore.TEMPORARY_STORED_PROCEDURES) {
proc.setType(ProcEntry.PROCEDURE);
} else {
proc.setType((cursorNeeded) ? ProcEntry.CURSOR : ProcEntry.PREPARE);
// Meta data may be returned by sp_prepare
proc.setColMetaData(baseTds.getColumns());
pstmt.setColMetaData(proc.getColMetaData());
}
// TODO Find some way of getting parameter meta data for MS
} else {
proc.setName(baseTds.sybasePrepare(sql, params));
if (proc.toString() == null) {
proc.setType(ProcEntry.PREP_FAILED);
} else {
proc.setType(ProcEntry.PROCEDURE);
}
// Sybase gives us lots of useful information about the result set
proc.setColMetaData(baseTds.getColumns());
proc.setParamMetaData(baseTds.getParameters());
pstmt.setColMetaData(proc.getColMetaData());
pstmt.setParamMetaData(proc.getParamMetaData());
}
// OK we have built a proc so add it to the cache.
addCachedProcedure(key, proc);
}
// Add the handle to the prepared statement so that the handles
// can be used to clean up the statement cache properly when the
// prepared statement is closed.
if (pstmt.handles == null) {
pstmt.handles = new HashSet(10);
}
pstmt.handles.add(proc);
// Give the user the name will be null if prepare failed
return proc.toString();
}
/**
* Add a stored procedure to the cache.
* <p>
* Not explicitly synchronized because it's only called by synchronized
* methods.
*
* @param key The signature of the procedure to cache.
* @param proc The stored procedure descriptor.
*/
void addCachedProcedure(String key, ProcEntry proc) {
statementCache.put(key, proc);
if (!autoCommit
&& proc.getType() == ProcEntry.PROCEDURE
&& serverType == Driver.SQLSERVER) {
procInTran.add(key);
}
}
/**
* Remove a stored procedure from the cache.
* <p>
* Not explicitly synchronized because it's only called by synchronized
* methods.
*
* @param key The signature of the procedure to remove from the cache.
*/
void removeCachedProcedure(String key) {
statementCache.remove(key);
if (!autoCommit) {
procInTran.remove(key);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -