/* * Microsoft JDBC Driver for SQL Server * * Copyright(c) Microsoft Corporation All rights reserved. * * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; import java.io.PrintWriter; import java.sql.Connection; import java.sql.SQLException; import java.sql.SQLFeatureNotSupportedException; import java.util.Enumeration; import java.util.Properties; import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.Level; import java.util.logging.Logger; import javax.naming.Reference; import javax.naming.StringRefAddr; import javax.sql.DataSource; import org.ietf.jgss.GSSCredential; /** * This datasource lists properties specific for the SQLServerConnection class. */ public class SQLServerDataSource implements ISQLServerDataSource, DataSource, java.io.Serializable, javax.naming.Referenceable { // dsLogger is logger used for all SQLServerDataSource instances. static final java.util.logging.Logger dsLogger = java.util.logging.Logger.getLogger("com.microsoft.sqlserver.jdbc.internals.SQLServerDataSource"); static final java.util.logging.Logger loggerExternal = java.util.logging.Logger.getLogger("com.microsoft.sqlserver.jdbc.DataSource"); static final private java.util.logging.Logger parentLogger = java.util.logging.Logger.getLogger("com.microsoft.sqlserver.jdbc"); final private String loggingClassName; private boolean trustStorePasswordStripped = false; private static final long serialVersionUID = 654861379544314296L; private Properties connectionProps; // Properties passed to SQLServerConnection class. private String dataSourceURL; // URL for datasource. private String dataSourceDescription; // Description for datasource. static private final AtomicInteger baseDataSourceID = new AtomicInteger(0); // Unique id generator for each DataSource instance (used for // logging). final private String traceID; /** * Initializes a new instance of the SQLServerDataSource class. */ public SQLServerDataSource() { connectionProps = new Properties(); int dataSourceID = nextDataSourceID(); String nameL = getClass().getName(); traceID = nameL.substring(1 + nameL.lastIndexOf('.')) + ":" + dataSourceID; loggingClassName = "com.microsoft.sqlserver.jdbc." + nameL.substring(1 + nameL.lastIndexOf('.')) + ":" + dataSourceID; } String getClassNameLogging() { return loggingClassName; } public String toString() { return traceID; } // DataSource interface public methods public Connection getConnection() throws SQLServerException { loggerExternal.entering(getClassNameLogging(), "getConnection"); Connection con = getConnectionInternal(null, null, null); loggerExternal.exiting(getClassNameLogging(), "getConnection", con); return con; } public Connection getConnection(String username, String password) throws SQLServerException { if (loggerExternal.isLoggable(Level.FINER)) loggerExternal.entering(getClassNameLogging(), "getConnection", new Object[] {username, "Password not traced"}); Connection con = getConnectionInternal(username, password, null); loggerExternal.exiting(getClassNameLogging(), "getConnection", con); return con; } // Sets the maximum time in seconds that this data source will wait while // attempting to connect to a database. Note default value is 0. public void setLoginTimeout(int loginTimeout) { setIntProperty(connectionProps, SQLServerDriverIntProperty.LOGIN_TIMEOUT.toString(), loginTimeout); } public int getLoginTimeout() { int defaultTimeOut = SQLServerDriverIntProperty.LOGIN_TIMEOUT.getDefaultValue(); final int logintimeout = getIntProperty(connectionProps, SQLServerDriverIntProperty.LOGIN_TIMEOUT.toString(), defaultTimeOut); // even if the user explicitly sets the timeout to zero, convert to 15 return (logintimeout == 0) ? defaultTimeOut : logintimeout; } // Sets the log writer for this DataSource. // Currently we just hold onto this logWriter and pass it back to callers, nothing else. private transient PrintWriter logWriter; public void setLogWriter(PrintWriter out) { loggerExternal.entering(getClassNameLogging(), "setLogWriter", out); logWriter = out; loggerExternal.exiting(getClassNameLogging(), "setLogWriter"); } // Retrieves the log writer for this DataSource. public PrintWriter getLogWriter() { loggerExternal.entering(getClassNameLogging(), "getLogWriter"); loggerExternal.exiting(getClassNameLogging(), "getLogWriter", logWriter); return logWriter; } public Logger getParentLogger() throws SQLFeatureNotSupportedException { return parentLogger; } // Core Connection property setters/getters. // applicationName is used to identify the specific application in various SQL Server // profiling and logging tools. public void setApplicationName(String applicationName) { setStringProperty(connectionProps, SQLServerDriverStringProperty.APPLICATION_NAME.toString(), applicationName); } public String getApplicationName() { return getStringProperty(connectionProps, SQLServerDriverStringProperty.APPLICATION_NAME.toString(), SQLServerDriverStringProperty.APPLICATION_NAME.getDefaultValue()); } // databaseName is the name of the database to connect to. If databaseName is not set, // getDatabaseName returns the default value of null. public void setDatabaseName(String databaseName) { setStringProperty(connectionProps, SQLServerDriverStringProperty.DATABASE_NAME.toString(), databaseName); } public String getDatabaseName() { return getStringProperty(connectionProps, SQLServerDriverStringProperty.DATABASE_NAME.toString(), null); } // instanceName is the SQL Server instance name to connect to. // If instanceName is not set, getInstanceName returns the default value of null. public void setInstanceName(String instanceName) { setStringProperty(connectionProps, SQLServerDriverStringProperty.INSTANCE_NAME.toString(), instanceName); } public String getInstanceName() { return getStringProperty(connectionProps, SQLServerDriverStringProperty.INSTANCE_NAME.toString(), null); } public void setIntegratedSecurity(boolean enable) { setBooleanProperty(connectionProps, SQLServerDriverBooleanProperty.INTEGRATED_SECURITY.toString(), enable); } public void setAuthenticationScheme(String authenticationScheme) { setStringProperty(connectionProps, SQLServerDriverStringProperty.AUTHENTICATION_SCHEME.toString(), authenticationScheme); } /** * sets the authentication mode * * @param authentication * the authentication mode */ public void setAuthentication(String authentication) { setStringProperty(connectionProps, SQLServerDriverStringProperty.AUTHENTICATION.toString(), authentication); } /** * Retrieves the authentication mode * * @return the authentication value */ public String getAuthentication() { return getStringProperty(connectionProps, SQLServerDriverStringProperty.AUTHENTICATION.toString(), SQLServerDriverStringProperty.AUTHENTICATION.getDefaultValue()); } /** * sets GSSCredential * * @param userCredential */ public void setGSSCredentials(GSSCredential userCredential){ setObjectProperty(connectionProps,SQLServerDriverObjectProperty.GSS_CREDENTIAL.toString(), userCredential); } /** * Retrieves the GSSCredential * * @return GSSCredential */ public GSSCredential getGSSCredentials(){ return (GSSCredential) getObjectProperty(connectionProps, SQLServerDriverObjectProperty.GSS_CREDENTIAL.toString(), SQLServerDriverObjectProperty.GSS_CREDENTIAL.getDefaultValue()); } /** * Sets the access token. * * @param accessToken * to be set in the string property. */ public void setAccessToken(String accessToken) { setStringProperty(connectionProps, SQLServerDriverStringProperty.ACCESS_TOKEN.toString(), accessToken); } /** * Retrieves the access token. * * @return the access token. */ public String getAccessToken() { return getStringProperty(connectionProps, SQLServerDriverStringProperty.ACCESS_TOKEN.toString(), null); } // If lastUpdateCount is set to true, the driver will return only the last update // count from all the update counts returned by a batch. The default of false will // return all update counts. If lastUpdateCount is not set, getLastUpdateCount // returns the default value of false. /** * Enables/disables Always Encrypted functionality for the data source object. The default is Disabled. * * @param columnEncryptionSetting * Enables/disables Always Encrypted functionality for the data source object. The default is Disabled. */ public void setColumnEncryptionSetting(String columnEncryptionSetting) { setStringProperty(connectionProps, SQLServerDriverStringProperty.COLUMN_ENCRYPTION.toString(), columnEncryptionSetting); } /** * Retrieves the Always Encrypted functionality setting for the data source object. * * @return the Always Encrypted functionality setting for the data source object. */ public String getColumnEncryptionSetting() { return getStringProperty(connectionProps, SQLServerDriverStringProperty.COLUMN_ENCRYPTION.toString(), SQLServerDriverStringProperty.COLUMN_ENCRYPTION.getDefaultValue()); } /** * Sets the name that identifies a key store. Only value supported is the "JavaKeyStorePassword" for identifying the Java Key Store. The default * is null. * * @param keyStoreAuthentication * the name that identifies a key store. */ public void setKeyStoreAuthentication(String keyStoreAuthentication) { setStringProperty(connectionProps, SQLServerDriverStringProperty.KEY_STORE_AUTHENTICATION.toString(), keyStoreAuthentication); } /** * Gets the value of the keyStoreAuthentication setting for the data source object. * * @return the value of the keyStoreAuthentication setting for the data source object. */ public String getKeyStoreAuthentication() { return getStringProperty(connectionProps, SQLServerDriverStringProperty.KEY_STORE_AUTHENTICATION.toString(), SQLServerDriverStringProperty.KEY_STORE_AUTHENTICATION.getDefaultValue()); } /** * Sets the password for the Java keystore. Note that, for Java Key Store provider the password for the keystore and the key must be the same. * Note that, keyStoreAuthentication must be set with "JavaKeyStorePassword". * * @param keyStoreSecret * the password to use for the keystore as well as for the key */ public void setKeyStoreSecret(String keyStoreSecret) { setStringProperty(connectionProps, SQLServerDriverStringProperty.KEY_STORE_SECRET.toString(), keyStoreSecret); } /** * Sets the location including the file name for the Java keystore. Note that, keyStoreAuthentication must be set with "JavaKeyStorePassword". * * @param keyStoreLocation * the location including the file name for the Java keystore. */ public void setKeyStoreLocation(String keyStoreLocation) { setStringProperty(connectionProps, SQLServerDriverStringProperty.KEY_STORE_LOCATION.toString(), keyStoreLocation); } /** * Retrieves the keyStoreLocation for the Java Key Store. * * @return the keyStoreLocation for the Java Key Store. */ public String getKeyStoreLocation() { return getStringProperty(connectionProps, SQLServerDriverStringProperty.KEY_STORE_LOCATION.toString(), SQLServerDriverStringProperty.KEY_STORE_LOCATION.getDefaultValue()); } public void setLastUpdateCount(boolean lastUpdateCount) { setBooleanProperty(connectionProps, SQLServerDriverBooleanProperty.LAST_UPDATE_COUNT.toString(), lastUpdateCount); } public boolean getLastUpdateCount() { return getBooleanProperty(connectionProps, SQLServerDriverBooleanProperty.LAST_UPDATE_COUNT.toString(), SQLServerDriverBooleanProperty.LAST_UPDATE_COUNT.getDefaultValue()); } // Encryption public void setEncrypt(boolean encrypt) { setBooleanProperty(connectionProps, SQLServerDriverBooleanProperty.ENCRYPT.toString(), encrypt); } public boolean getEncrypt() { return getBooleanProperty(connectionProps, SQLServerDriverBooleanProperty.ENCRYPT.toString(), SQLServerDriverBooleanProperty.ENCRYPT.getDefaultValue()); } /** * Beginning in version 6.0 of the Microsoft JDBC Driver for SQL Server, a new connection property transparentNetworkIPResolution (TNIR) is added * for transparent connection to Always On availability groups or to a server which has multiple IP addresses associated. When * transparentNetworkIPResolution is true, the driver attempts to connect to the first IP address available. If the first attempt fails, the * driver tries to connect to all IP addresses in parallel until the timeout expires, discarding any pending connection attempts when one of them * succeeds. * <p> * transparentNetworkIPResolution is ignored if multiSubnetFailover is true * <p> * transparentNetworkIPResolution is ignored if database mirroring is used * <p> * transparentNetworkIPResolution is ignored if there are more than 64 IP addresses * * @param tnir * if set to true, the driver attempts to connect to the first IP address available. It is true by default. */ public void setTransparentNetworkIPResolution(boolean tnir) { setBooleanProperty(connectionProps, SQLServerDriverBooleanProperty.TRANSPARENT_NETWORK_IP_RESOLUTION.toString(), tnir); } /** * Retrieves the TransparentNetworkIPResolution value. * * @return if enabled, returns true. Otherwise, false. */ public boolean getTransparentNetworkIPResolution() { return getBooleanProperty(connectionProps, SQLServerDriverBooleanProperty.TRANSPARENT_NETWORK_IP_RESOLUTION.toString(), SQLServerDriverBooleanProperty.TRANSPARENT_NETWORK_IP_RESOLUTION.getDefaultValue()); } public void setTrustServerCertificate(boolean e) { setBooleanProperty(connectionProps, SQLServerDriverBooleanProperty.TRUST_SERVER_CERTIFICATE.toString(), e); } public boolean getTrustServerCertificate() { return getBooleanProperty(connectionProps, SQLServerDriverBooleanProperty.TRUST_SERVER_CERTIFICATE.toString(), SQLServerDriverBooleanProperty.TRUST_SERVER_CERTIFICATE.getDefaultValue()); } public void setTrustStoreType(String trustStoreType) { setStringProperty(connectionProps, SQLServerDriverStringProperty.TRUST_STORE_TYPE.toString(), trustStoreType); } public String getTrustStoreType() { return getStringProperty(connectionProps, SQLServerDriverStringProperty.TRUST_STORE_TYPE.toString(), SQLServerDriverStringProperty.TRUST_STORE_TYPE.getDefaultValue()); } public void setTrustStore(String st) { setStringProperty(connectionProps, SQLServerDriverStringProperty.TRUST_STORE.toString(), st); } public String getTrustStore() { return getStringProperty(connectionProps, SQLServerDriverStringProperty.TRUST_STORE.toString(), null); } public void setTrustStorePassword(String p) { // if a non value property is set if (p != null) trustStorePasswordStripped = false; setStringProperty(connectionProps, SQLServerDriverStringProperty.TRUST_STORE_PASSWORD.toString(), p); } public void setHostNameInCertificate(String host) { setStringProperty(connectionProps, SQLServerDriverStringProperty.HOSTNAME_IN_CERTIFICATE.toString(), host); } public String getHostNameInCertificate() { return getStringProperty(connectionProps, SQLServerDriverStringProperty.HOSTNAME_IN_CERTIFICATE.toString(), null); } // lockTimeout is the number of milliseconds to wait before the database reports // a lock timeout. The default value of -1 means wait forever. If specified, // this value will be the default for all statements on the connection. Note a // value of 0 means no wait. If lockTimeout is not set, getLockTimeout returns // the default of -1. public void setLockTimeout(int lockTimeout) { setIntProperty(connectionProps, SQLServerDriverIntProperty.LOCK_TIMEOUT.toString(), lockTimeout); } public int getLockTimeout() { return getIntProperty(connectionProps, SQLServerDriverIntProperty.LOCK_TIMEOUT.toString(), SQLServerDriverIntProperty.LOCK_TIMEOUT.getDefaultValue()); } // setPassword sets the password that will be used when connecting to SQL Server. // Note getPassword is deliberately declared non-public for security reasons. // If the password is not set, getPassword returns the default value of null. public void setPassword(String password) { setStringProperty(connectionProps, SQLServerDriverStringProperty.PASSWORD.toString(), password); } String getPassword() { return getStringProperty(connectionProps, SQLServerDriverStringProperty.PASSWORD.toString(), null); } // portNumber is the TCP-IP port number used when opening a socket connection // to SQL Server. If portNumber is not set, getPortNumber returns the default // of 1433. Note as mentioned above, setPortNumber does not do any range // checking on the port value passed in, invalid port numbers like 99999 can // be passed in without triggering any error. public void setPortNumber(int portNumber) { setIntProperty(connectionProps, SQLServerDriverIntProperty.PORT_NUMBER.toString(), portNumber); } public int getPortNumber() { return getIntProperty(connectionProps, SQLServerDriverIntProperty.PORT_NUMBER.toString(), SQLServerDriverIntProperty.PORT_NUMBER.getDefaultValue()); } // selectMethod is the default cursor type used for the result set. This // property is useful when you are dealing with large result sets and don't // want to store the whole result set in memory on the client side. By setting // the property to "cursor" you will be able to create a server side cursor that // can fetch smaller chunks of data at a time. If selectMethod is not set, // getSelectMethod returns the default value of "direct". public void setSelectMethod(String selectMethod) { setStringProperty(connectionProps, SQLServerDriverStringProperty.SELECT_METHOD.toString(), selectMethod); } public String getSelectMethod() { return getStringProperty(connectionProps, SQLServerDriverStringProperty.SELECT_METHOD.toString(), SQLServerDriverStringProperty.SELECT_METHOD.getDefaultValue()); } public void setResponseBuffering(String respo) { setStringProperty(connectionProps, SQLServerDriverStringProperty.RESPONSE_BUFFERING.toString(), respo); } public String getResponseBuffering() { return getStringProperty(connectionProps, SQLServerDriverStringProperty.RESPONSE_BUFFERING.toString(), SQLServerDriverStringProperty.RESPONSE_BUFFERING.getDefaultValue()); } public void setApplicationIntent(String applicationIntent) { setStringProperty(connectionProps, SQLServerDriverStringProperty.APPLICATION_INTENT.toString(), applicationIntent); } public String getApplicationIntent() { return getStringProperty(connectionProps, SQLServerDriverStringProperty.APPLICATION_INTENT.toString(), SQLServerDriverStringProperty.APPLICATION_INTENT.getDefaultValue()); } public void setSendTimeAsDatetime(boolean sendTimeAsDatetime) { setBooleanProperty(connectionProps, SQLServerDriverBooleanProperty.SEND_TIME_AS_DATETIME.toString(), sendTimeAsDatetime); } public boolean getSendTimeAsDatetime() { return getBooleanProperty(connectionProps, SQLServerDriverBooleanProperty.SEND_TIME_AS_DATETIME.toString(), SQLServerDriverBooleanProperty.SEND_TIME_AS_DATETIME.getDefaultValue()); } // If sendStringParametersAsUnicode is set to true (which is the default), // string parameters are sent to the server in UNICODE format. If sendStringParametersAsUnicode // is set to false, string parameters are sent to the server in the native TDS collation // format of the database, not in UNICODE. If sendStringParametersAsUnicode is not set, // getSendStringParametersAsUnicode returns the default of true. public void setSendStringParametersAsUnicode(boolean sendStringParametersAsUnicode) { setBooleanProperty(connectionProps, SQLServerDriverBooleanProperty.SEND_STRING_PARAMETERS_AS_UNICODE.toString(), sendStringParametersAsUnicode); } public boolean getSendStringParametersAsUnicode() { return getBooleanProperty(connectionProps, SQLServerDriverBooleanProperty.SEND_STRING_PARAMETERS_AS_UNICODE.toString(), SQLServerDriverBooleanProperty.SEND_STRING_PARAMETERS_AS_UNICODE.getDefaultValue()); } /** * Translates the serverName from Unicode to ASCII Compatible Encoding (ACE) * * @param serverNameAsACE * if enabled the servername will be translated to ASCII Compatible Encoding (ACE) */ public void setServerNameAsACE(boolean serverNameAsACE) { setBooleanProperty(connectionProps, SQLServerDriverBooleanProperty.SERVER_NAME_AS_ACE.toString(), serverNameAsACE); } /** * Retrieves if the serverName should be translated from Unicode to ASCII Compatible Encoding (ACE) * * @return if enabled, will return true. Otherwise, false. */ public boolean getServerNameAsACE() { return getBooleanProperty(connectionProps, SQLServerDriverBooleanProperty.SERVER_NAME_AS_ACE.toString(), SQLServerDriverBooleanProperty.SERVER_NAME_AS_ACE.getDefaultValue()); } // serverName is the host name of the target SQL Server. If serverName is not set, // getServerName returns the default value of null is returned. public void setServerName(String serverName) { setStringProperty(connectionProps, SQLServerDriverStringProperty.SERVER_NAME.toString(), serverName); } public String getServerName() { return getStringProperty(connectionProps, SQLServerDriverStringProperty.SERVER_NAME.toString(), null); } // Specify an Service Principal Name (SPN) of the target SQL Server. // https://msdn.microsoft.com/en-us/library/cc280459.aspx public void setServerSpn(String serverSpn) { setStringProperty(connectionProps, SQLServerDriverStringProperty.SERVER_SPN.toString(), serverSpn); } public String getServerSpn() { return getStringProperty(connectionProps, SQLServerDriverStringProperty.SERVER_SPN.toString(), null); } // serverName is the host name of the target SQL Server. If serverName is not set, // getServerName returns the default value of null is returned. public void setFailoverPartner(String serverName) { setStringProperty(connectionProps, SQLServerDriverStringProperty.FAILOVER_PARTNER.toString(), serverName); } public String getFailoverPartner() { return getStringProperty(connectionProps, SQLServerDriverStringProperty.FAILOVER_PARTNER.toString(), null); } public void setMultiSubnetFailover(boolean multiSubnetFailover) { setBooleanProperty(connectionProps, SQLServerDriverBooleanProperty.MULTI_SUBNET_FAILOVER.toString(), multiSubnetFailover); } public boolean getMultiSubnetFailover() { return getBooleanProperty(connectionProps, SQLServerDriverBooleanProperty.MULTI_SUBNET_FAILOVER.toString(), SQLServerDriverBooleanProperty.MULTI_SUBNET_FAILOVER.getDefaultValue()); } // setUser set's the user name that will be used when connecting to SQL Server. // If user is not set, getUser returns the default value of null. public void setUser(String user) { setStringProperty(connectionProps, SQLServerDriverStringProperty.USER.toString(), user); } public String getUser() { return getStringProperty(connectionProps, SQLServerDriverStringProperty.USER.toString(), null); } // workstationID is the name of the client machine (or client workstation). // workstationID is the host name of the client in other words. If workstationID // is not set, the default value is constructed by calling InetAddress.getLocalHost().getHostName() // or if getHostName() returns blank then getHostAddress().toString(). public void setWorkstationID(String workstationID) { setStringProperty(connectionProps, SQLServerDriverStringProperty.WORKSTATION_ID.toString(), workstationID); } public String getWorkstationID() { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "getWorkstationID"); String getWSID = connectionProps.getProperty(SQLServerDriverStringProperty.WORKSTATION_ID.toString()); // Per spec, return what the logon will send here if workstationID property is not set. if (null == getWSID) { getWSID = Util.lookupHostName(); } loggerExternal.exiting(getClassNameLogging(), "getWorkstationID", getWSID); return getWSID; } // If xopenStates is set to true, the driver will convert SQL states to XOPEN // compliant states. The default is false which causes the driver to generate SQL 99 // state codes. If xopenStates is not set, getXopenStates returns the default value // of false. public void setXopenStates(boolean xopenStates) { setBooleanProperty(connectionProps, SQLServerDriverBooleanProperty.XOPEN_STATES.toString(), xopenStates); } public boolean getXopenStates() { return getBooleanProperty(connectionProps, SQLServerDriverBooleanProperty.XOPEN_STATES.toString(), SQLServerDriverBooleanProperty.XOPEN_STATES.getDefaultValue()); } public void setFIPS(boolean fips) { setBooleanProperty(connectionProps, SQLServerDriverBooleanProperty.FIPS.toString(), fips); } public boolean getFIPS() { return getBooleanProperty(connectionProps, SQLServerDriverBooleanProperty.FIPS.toString(), SQLServerDriverBooleanProperty.FIPS.getDefaultValue()); } public void setFIPSProvider(String fipsProvider) { setStringProperty(connectionProps, SQLServerDriverStringProperty.FIPS_PROVIDER.toString(), fipsProvider); } public String getFIPSProvider() { return getStringProperty(connectionProps, SQLServerDriverStringProperty.FIPS_PROVIDER.toString(), null); } // The URL property is exposed for backwards compatibility reasons. Also, several // Java Application servers expect a setURL function on the DataSource and set it // by default (JBoss and WebLogic). // Note for security reasons we do not recommend that customers include the password // in the url supplied to setURL. The reason for this is third-party Java Application // Servers will very often display the value set to URL property in their DataSource // configuration GUI. We recommend instead that clients use the setPassword method // to set the password value. The Java Application Servers will not display a password // that is set on the DataSource in the configuration GUI. // Note if setURL is not called, getURL returns the default value of "jdbc:sqlserver://". public void setURL(String url) { loggerExternal.entering(getClassNameLogging(), "setURL", url); // URL is not stored in a property set, it is maintained separately. dataSourceURL = url; loggerExternal.exiting(getClassNameLogging(), "setURL"); } public String getURL() { String url = dataSourceURL; loggerExternal.entering(getClassNameLogging(), "getURL"); if (null == dataSourceURL) url = "jdbc:sqlserver://"; loggerExternal.exiting(getClassNameLogging(), "getURL", url); return url; } // DataSource specific property setters/getters. // Per JDBC specification 16.1.1 "...the only property that all DataSource // implementations are required to support is the description property". public void setDescription(String description) { loggerExternal.entering(getClassNameLogging(), "setDescription", description); dataSourceDescription = description; loggerExternal.exiting(getClassNameLogging(), "setDescription"); } public String getDescription() { loggerExternal.entering(getClassNameLogging(), "getDescription"); loggerExternal.exiting(getClassNameLogging(), "getDescription", dataSourceDescription); return dataSourceDescription; } // packetSize is the size (in bytes) to use for the TCP/IP send and receive // buffer. It is also the value used for the TDS packet size (SQL Server // Network Packet Size). Validity of the value is checked at connect time. // If no value is set for this property, its default value is 4KB. public void setPacketSize(int packetSize) { setIntProperty(connectionProps, SQLServerDriverIntProperty.PACKET_SIZE.toString(), packetSize); } public int getPacketSize() { return getIntProperty(connectionProps, SQLServerDriverIntProperty.PACKET_SIZE.toString(), SQLServerDriverIntProperty.PACKET_SIZE.getDefaultValue()); } public void setQueryTimeout(int queryTimeout) { setIntProperty(connectionProps, SQLServerDriverIntProperty.QUERY_TIMEOUT.toString(), queryTimeout); } public int getQueryTimeout() { return getIntProperty(connectionProps, SQLServerDriverIntProperty.QUERY_TIMEOUT.toString(), SQLServerDriverIntProperty.QUERY_TIMEOUT.getDefaultValue()); } /** * If this configuration is false the first execution of a prepared statement will call sp_executesql and not prepare * a statement, once the second execution happens it will call sp_prepexec and actually setup a prepared statement handle. Following * executions will call sp_execute. This relieves the need for sp_unprepare on prepared statement close if the statement is only * executed once. * * @param enablePrepareOnFirstPreparedStatementCall * Changes the setting per the description. */ public void setEnablePrepareOnFirstPreparedStatementCall(boolean enablePrepareOnFirstPreparedStatementCall) { setBooleanProperty(connectionProps, SQLServerDriverBooleanProperty.ENABLE_PREPARE_ON_FIRST_PREPARED_STATEMENT.toString(), enablePrepareOnFirstPreparedStatementCall); } /** * If this configuration returns false the first execution of a prepared statement will call sp_executesql and not prepare * a statement, once the second execution happens it will call sp_prepexec and actually setup a prepared statement handle. Following * executions will call sp_execute. This relieves the need for sp_unprepare on prepared statement close if the statement is only * executed once. * * @return Returns the current setting per the description. */ public boolean getEnablePrepareOnFirstPreparedStatementCall() { return getBooleanProperty(connectionProps, SQLServerDriverBooleanProperty.ENABLE_PREPARE_ON_FIRST_PREPARED_STATEMENT.toString(), SQLServerConnection.getDefaultEnablePrepareOnFirstPreparedStatementCall()); } /** * This setting controls how many outstanding prepared statement discard actions (sp_unprepare) can be outstanding per connection * before a call to clean-up the outstanding handles on the server is executed. If the setting is <= 1 unprepare actions will be * executed immedietely on prepared statement close. If it is set to >1 these calls will be batched together to avoid overhead of * calling sp_unprepare too often. * * @param serverPreparedStatementDiscardThreshold * Changes the setting per the description. */ public void setServerPreparedStatementDiscardThreshold(int serverPreparedStatementDiscardThreshold) { setIntProperty(connectionProps, SQLServerDriverIntProperty.SERVER_PREPARED_STATEMENT_DISCARD_THRESHOLD.toString(), serverPreparedStatementDiscardThreshold); } /** * This setting controls how many outstanding prepared statement discard actions (sp_unprepare) can be outstanding per connection * before a call to clean-up the outstanding handles on the server is executed. If the setting is <= 1 unprepare actions will be * executed immedietely on prepared statement close. If it is set to >1 these calls will be batched together to avoid overhead of * calling sp_unprepare too often. * * @return Returns the current setting per the description. */ public int getServerPreparedStatementDiscardThreshold() { return getIntProperty(connectionProps, SQLServerDriverIntProperty.SERVER_PREPARED_STATEMENT_DISCARD_THRESHOLD.toString(), SQLServerConnection.getDefaultServerPreparedStatementDiscardThreshold()); } public void setSocketTimeout(int socketTimeout) { setIntProperty(connectionProps, SQLServerDriverIntProperty.SOCKET_TIMEOUT.toString(), socketTimeout); } public int getSocketTimeout() { int defaultTimeOut = SQLServerDriverIntProperty.SOCKET_TIMEOUT.getDefaultValue(); return getIntProperty(connectionProps, SQLServerDriverIntProperty.SOCKET_TIMEOUT.toString(), defaultTimeOut); } /** * Sets the login configuration file for Kerberos authentication. This * overrides the default configuration <i> SQLJDBCDriver </i> * * @param configurationName */ public void setJASSConfigurationName(String configurationName) { setStringProperty(connectionProps, SQLServerDriverStringProperty.JAAS_CONFIG_NAME.toString(), configurationName); } /** * Retrieves the login configuration file for Kerberos authentication. * * @return */ public String getJASSConfigurationName() { return getStringProperty(connectionProps, SQLServerDriverStringProperty.JAAS_CONFIG_NAME.toString(), SQLServerDriverStringProperty.JAAS_CONFIG_NAME.getDefaultValue()); } // responseBuffering controls the driver's buffering of responses from SQL Server. // Possible values are: // // "full" - Fully buffer the response at execution time. // Advantages: // 100% back compat with v1.1 driver // Maximizes concurrency on the server // Disadvantages: // Consumes more client-side memory // Client scalability limits with large responses // More execute latency // // "adaptive" - Data Pipe adaptive buffering // Advantages: // Buffers only when necessary, only as much as necessary // Enables handling very large responses, values // Disadvantages // Reduced concurrency on the server // Internal functions for setting/getting property values. // Set a string property value. // Caller will always supply a non-null props and propKey. // Caller may supply a null propValue, in this case no property value is set. private void setStringProperty(Properties props, String propKey, String propValue) { if (loggerExternal.isLoggable(java.util.logging.Level.FINER) && !propKey.contains("password") && !propKey.contains("Password")) { loggerExternal.entering(getClassNameLogging(), "set" + propKey, propValue); } else loggerExternal.entering(getClassNameLogging(), "set" + propKey); if (null != propValue) props.setProperty(propKey, propValue); loggerExternal.exiting(getClassNameLogging(), "set" + propKey); } // Reads property value in String format. // Caller will always supply a non-null props and propKey. // Returns null if the specific property value is not set. private String getStringProperty(Properties props, String propKey, String defaultValue) { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "get" + propKey); String propValue = props.getProperty(propKey); if (null == propValue) propValue = defaultValue; if (loggerExternal.isLoggable(java.util.logging.Level.FINER) && !propKey.contains("password") && !propKey.contains("Password")) loggerExternal.exiting(getClassNameLogging(), "get" + propKey, propValue); return propValue; } // Set an integer property value. // Caller will always supply a non-null props and propKey. private void setIntProperty(Properties props, String propKey, int propValue) { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "set" + propKey, new Integer(propValue)); props.setProperty(propKey, new Integer(propValue).toString()); loggerExternal.exiting(getClassNameLogging(), "set" + propKey); } // Reads a property value in int format. // Caller will always supply a non-null props and propKey. // Returns defaultValue if the specific property value is not set. private int getIntProperty(Properties props, String propKey, int defaultValue) { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "get" + propKey); String propValue = props.getProperty(propKey); int value = defaultValue; if (null != propValue) { try { value = Integer.parseInt(propValue); } catch (NumberFormatException nfe) { // This exception cannot occur as all of our properties // are set internally by int -> Integer.toString. assert false : "Bad portNumber:-" + propValue; } } if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.exiting(getClassNameLogging(), "get" + propKey, new Integer(value)); return value; } // Set a boolean property value. // Caller will always supply a non-null props and propKey. private void setBooleanProperty(Properties props, String propKey, boolean propValue) { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "set" + propKey, Boolean.valueOf(propValue)); props.setProperty(propKey, (propValue) ? "true" : "false"); loggerExternal.exiting(getClassNameLogging(), "set" + propKey); } // Reads a property value in boolean format. // Caller will always supply a non-null props and propKey. // Returns defaultValue if the specific property value is not set. private boolean getBooleanProperty(Properties props, String propKey, boolean defaultValue) { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "get" + propKey); String propValue = props.getProperty(propKey); Boolean value; if (null == propValue) { value = defaultValue; } else { // Since we set the value of the String property ourselves to // "true" or "false", we can do this. value = Boolean.valueOf(propValue); } loggerExternal.exiting(getClassNameLogging(), "get" + propKey, value); return value.booleanValue(); } private void setObjectProperty(Properties props, String propKey, Object propValue) { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) { loggerExternal.entering(getClassNameLogging(), "set" + propKey); } if (null != propValue) { props.put(propKey, propValue); } loggerExternal.exiting(getClassNameLogging(), "set" + propKey); } private Object getObjectProperty(Properties props, String propKey, Object defaultValue) { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "get" + propKey); Object propValue = props.get(propKey); if (null == propValue) propValue = defaultValue; loggerExternal.exiting(getClassNameLogging(), "get" + propKey); return propValue; } // Returns a SQLServerConnection given username, password, and pooledConnection. // Note that the DataSource properties set to connectionProps are used when creating // the connection. // Both username and password can be null. // If pooledConnection is not null, then connection returned is attached to the pooledConnection // and participates in connection pooling. SQLServerConnection getConnectionInternal(String username, String password, SQLServerPooledConnection pooledConnection) throws SQLServerException { Properties userSuppliedProps = null; Properties mergedProps = null; // Trust store password stripped and this object got created via Objectfactory referencing. if (trustStorePasswordStripped) SQLServerException.makeFromDriverError(null, null, SQLServerException.getErrString("R_referencingFailedTSP"), null, true); // If username or password is passed in, clone the property set so we // don't alter original connectionProps. if (null != username || null != password) { userSuppliedProps = (Properties) this.connectionProps.clone(); // Remove user and password from connectionProps if set. // We want the user supplied user+password to replace // whatever is set in connectionProps. userSuppliedProps.remove(SQLServerDriverStringProperty.USER.toString()); userSuppliedProps.remove(SQLServerDriverStringProperty.PASSWORD.toString()); if (null != username) userSuppliedProps.put(SQLServerDriverStringProperty.USER.toString(), username); if (null != password) userSuppliedProps.put(SQLServerDriverStringProperty.PASSWORD.toString(), password); } else { userSuppliedProps = connectionProps; } // Merge in URL properties into userSuppliedProps if URL is set. if (null != dataSourceURL) { Properties urlProps = Util.parseUrl(dataSourceURL, dsLogger); // null returned properties means that the passed in URL is not supported. if (null == urlProps) SQLServerException.makeFromDriverError(null, null, SQLServerException.getErrString("R_errorConnectionString"), null, true); // Manually merge URL props and user supplied props. mergedProps = SQLServerDriver.mergeURLAndSuppliedProperties(urlProps, userSuppliedProps); } else { mergedProps = userSuppliedProps; } // Create new connection and connect. if (dsLogger.isLoggable(Level.FINER)) dsLogger.finer(toString() + " Begin create new connection."); SQLServerConnection result = new SQLServerConnection(toString()); result.connect(mergedProps, pooledConnection); if (dsLogger.isLoggable(Level.FINER)) dsLogger.finer(toString() + " End create new connection " + result.toString()); return result; } // Implement javax.naming.Referenceable interface methods. public Reference getReference() { loggerExternal.entering(getClassNameLogging(), "getReference"); Reference ref = getReferenceInternal("com.microsoft.sqlserver.jdbc.SQLServerDataSource"); loggerExternal.exiting(getClassNameLogging(), "getReference", ref); return ref; } Reference getReferenceInternal(String dataSourceClassString) { if (dsLogger.isLoggable(Level.FINER)) dsLogger.finer(toString() + " creating reference for " + dataSourceClassString + "."); Reference ref = new Reference(this.getClass().getName(), "com.microsoft.sqlserver.jdbc.SQLServerDataSourceObjectFactory", null); if (null != dataSourceClassString) ref.add(new StringRefAddr("class", dataSourceClassString)); if (trustStorePasswordStripped) ref.add(new StringRefAddr("trustStorePasswordStripped", "true")); // Add each property name+value pair found in connectionProps. Enumeration<?> e = connectionProps.keys(); while (e.hasMoreElements()) { String propertyName = (String) e.nextElement(); // If a trustStore password is set, it is omitted and a trustStorePasswordSet flag is set. if (propertyName.equals(SQLServerDriverStringProperty.TRUST_STORE_PASSWORD.toString())) { // The property set and the variable set at the same time is not possible assert trustStorePasswordStripped == false; ref.add(new StringRefAddr("trustStorePasswordStripped", "true")); } else { // do not add passwords to the collection. we have normal password if (!propertyName.contains(SQLServerDriverStringProperty.PASSWORD.toString())) ref.add(new StringRefAddr(propertyName, connectionProps.getProperty(propertyName))); } } // Add dataSourceURL and dataSourceDescription as these will not appear in connectionProps. if (null != dataSourceURL) ref.add(new StringRefAddr("dataSourceURL", dataSourceURL)); if (null != dataSourceDescription) ref.add(new StringRefAddr("dataSourceDescription", dataSourceDescription)); return ref; } // Initialize this datasource from properties found inside the reference ref. // Called by SQLServerDataSourceObjectFactory to initialize new DataSource instance. void initializeFromReference(javax.naming.Reference ref) { // Enumerate all the StringRefAddr objects in the Reference and assign properties appropriately. Enumeration<?> e = ref.getAll(); while (e.hasMoreElements()) { StringRefAddr addr = (StringRefAddr) e.nextElement(); String propertyName = addr.getType(); String propertyValue = (String) addr.getContent(); // Special case dataSourceURL and dataSourceDescription. if (propertyName.equals("dataSourceURL")) { dataSourceURL = propertyValue; } else if (propertyName.equals("dataSourceDescription")) { dataSourceDescription = propertyValue; } else if (propertyName.equals("trustStorePasswordStripped")) { trustStorePasswordStripped = true; } // Just skip "class" StringRefAddr, it does not go into connectionProps else if (false == propertyName.equals("class")) { connectionProps.setProperty(propertyName, propertyValue); } } } public boolean isWrapperFor(Class<?> iface) throws SQLException { loggerExternal.entering(getClassNameLogging(), "isWrapperFor", iface); boolean f = iface.isInstance(this); loggerExternal.exiting(getClassNameLogging(), "isWrapperFor", Boolean.valueOf(f)); return f; } public <T> T unwrap(Class<T> iface) throws SQLException { loggerExternal.entering(getClassNameLogging(), "unwrap", iface); T t; try { t = iface.cast(this); } catch (ClassCastException e) { throw new SQLServerException(e.getMessage(), e); } loggerExternal.exiting(getClassNameLogging(), "unwrap", t); return t; } // Returns unique id for each DataSource instance. private static int nextDataSourceID() { return baseDataSourceID.incrementAndGet(); } private Object writeReplace() throws java.io.ObjectStreamException { return new SerializationProxy(this); } private void readObject(java.io.ObjectInputStream stream) throws java.io.InvalidObjectException { // For added security/robustness, the only way to rehydrate a serialized SQLServerDataSource // is to use a SerializationProxy. Direct use of readObject() is not supported. throw new java.io.InvalidObjectException(""); } // This code is duplicated in pooled and XA datasource classes. private static class SerializationProxy implements java.io.Serializable { private final Reference ref; private static final long serialVersionUID = 654661379542314226L; SerializationProxy(SQLServerDataSource ds) { // We do not need the class name so pass null, serialization mechanism // stores the class info. ref = ds.getReferenceInternal(null); } private Object readResolve() { SQLServerDataSource ds = new SQLServerDataSource(); ds.initializeFromReference(ref); return ds; } } }