diff --git a/CHANGELOG.md b/CHANGELOG.md index 081cb8281e..4e736de77b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,21 +3,6 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) -## [7.1.3] Preview Release -### Added -- Added a new SQLServerMetaData constructor for string values of length greater than 4000 [#876](https://github.com/Microsoft/mssql-jdbc/pull/876) - -### Fixed Issues -- Fixed an issue with Geography.point() having coordinates reversed [#853](https://github.com/Microsoft/mssql-jdbc/pull/853) -- Fixed intermittent test failures [#854](https://github.com/Microsoft/mssql-jdbc/pull/854) [#862](https://github.com/Microsoft/mssql-jdbc/pull/862) [#888](https://github.com/Microsoft/mssql-jdbc/pull/888) -- Fixed an issue with setAutoCommit() leaving a transaction open when running against Azure SQL Data Warehouse [#881](https://github.com/Microsoft/mssql-jdbc/pull/881) - -### Changed -- Changed query timeout logic to use a single thread [#842](https://github.com/Microsoft/mssql-jdbc/pull/842) -- Code cleanup [#857](https://github.com/Microsoft/mssql-jdbc/pull/857) [#873](https://github.com/Microsoft/mssql-jdbc/pull/873) -- Removed populating Lobs when calling ResultSet.wasNull() [#875](https://github.com/Microsoft/mssql-jdbc/pull/875) -- Improved retry logic for intermittent TLS1.2 issue when establishing a connection [#882](https://github.com/Microsoft/mssql-jdbc/pull/882) - ## [7.1.2] Preview Release ### Added - Added support for JDK 11 [#824](https://github.com/Microsoft/mssql-jdbc/pull/824) [#837](https://github.com/Microsoft/mssql-jdbc/pull/837) [#807](https://github.com/Microsoft/mssql-jdbc/pull/807) @@ -72,7 +57,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) - Added new test for validation of supported public APIs in request boundary declaration APIs [#746](https://github.com/Microsoft/mssql-jdbc/pull/746) ### Fixed Issues -- Fixed policheck issue with a keyword [#745](https://github.com/Microsoft/mssql-jdbc/pull/745) +- Fixed policheck issue with 'Country' keyword [#745](https://github.com/Microsoft/mssql-jdbc/pull/745) - Fixed issues reported by static analysis tools (SonarQube, Fortify) [#747](https://github.com/Microsoft/mssql-jdbc/pull/747) ### Changed diff --git a/README.md b/README.md index 8fb19d3f95..51c931dd59 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ SQL Server Team Let us know how you think we're doing. - + ## Status of Most Recent Builds | AppVeyor (Windows) | Travis CI (Linux) | @@ -90,7 +90,7 @@ To get the latest preview version of the driver, add the following to your POM f com.microsoft.sqlserver mssql-jdbc - 7.1.3.jre11-preview + 7.1.2.jre11-preview ``` @@ -123,7 +123,7 @@ Projects that require either of the two features need to explicitly declare the com.microsoft.sqlserver mssql-jdbc - 7.1.3.jre11-preview + 7.1.2.jre11-preview compile @@ -140,7 +140,7 @@ Projects that require either of the two features need to explicitly declare the com.microsoft.sqlserver mssql-jdbc - 7.1.3.jre11-preview + 7.1.2.jre11-preview compile diff --git a/appveyor.yml b/appveyor.yml index 4f1c4577fd..3e70b718ba 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -4,7 +4,7 @@ init: - cmd: net start MSSQL$%SQL_Instance% environment: - JAVA_HOME: C:\Program Files\Java\jdk11 + JAVA_HOME: C:\Program Files\Java\jdk10 mssql_jdbc_test_connection_properties: jdbc:sqlserver://localhost:1433;instanceName=%SQL_Instance%;databaseName=master;username=sa;password=Password12!; matrix: - SQL_Instance: SQL2008R2SP2 @@ -31,9 +31,9 @@ cache: build_script: - keytool -importkeystore -srckeystore cert.pfx -srcstoretype pkcs12 -destkeystore clientcert.jks -deststoretype JKS -srcstorepass password -deststorepass password - keytool -list -v -keystore clientcert.jks -storepass "password" > JavaKeyStore.txt - - cd.. - - mvn install -DskipTests=true -Dmaven.javadoc.skip=true -B -V -Pbuild43 - - mvn install -DskipTests=true -Dmaven.javadoc.skip=true -B -V -Pbuild42 -test_script: - - mvn test -B -Pbuild43 - - mvn test -B -Pbuild42 +# - cd.. +# - mvn install -DskipTests=true -Dmaven.javadoc.skip=true -B -V -Pbuild43 +# - mvn install -DskipTests=true -Dmaven.javadoc.skip=true -B -V -Pbuild42 +# test_script: +# - mvn test -B -Pbuild43 +# - mvn test -B -Pbuild42 diff --git a/build.gradle b/build.gradle index d084185a8c..0688b4aedf 100644 --- a/build.gradle +++ b/build.gradle @@ -10,7 +10,7 @@ apply plugin: 'java' -version = '7.1.3' +version = '7.1.2' def jreVersion = "" def testOutputDir = file("build/classes/java/test") def archivesBaseName = 'mssql-jdbc' diff --git a/pom.xml b/pom.xml index 7b8e944adc..9505b50557 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.microsoft.sqlserver mssql-jdbc - 7.1.3 + 7.1.2 jar Microsoft JDBC Driver for SQL Server diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/Column.java b/src/main/java/com/microsoft/sqlserver/jdbc/Column.java index fdd71facbf..20453b2b7a 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/Column.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/Column.java @@ -214,7 +214,7 @@ void updateValue(JDBCType jdbcType, Object value, JavaType javaType, StreamSette if (JDBCType.TINYINT == cryptoMetadata.getBaseTypeInfo().getSSType().getJDBCType() && javaType == JavaType.SHORT) { if (value instanceof Boolean) { - if ((boolean) value) { + if (true == ((boolean) value)) { value = 1; } else { value = 0; @@ -251,7 +251,7 @@ else if (jdbcType.isBinary()) { } if (Util.shouldHonorAEForParameters(stmtColumnEncriptionSetting, con)) { - if ((null == cryptoMetadata) && forceEncrypt) { + if ((null == cryptoMetadata) && true == forceEncrypt) { MessageFormat form = new MessageFormat( SQLServerException.getErrString("R_ForceEncryptionTrue_HonorAETrue_UnencryptedColumnRS")); Object[] msgArgs = {parameterIndex}; @@ -273,7 +273,7 @@ else if (jdbcType.isBinary()) { } } } else { - if (forceEncrypt) { + if (true == forceEncrypt) { MessageFormat form = new MessageFormat( SQLServerException.getErrString("R_ForceEncryptionTrue_HonorAEFalseRS")); Object[] msgArgs = {parameterIndex}; diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/DDC.java b/src/main/java/com/microsoft/sqlserver/jdbc/DDC.java index 7e18aec104..845fe5b900 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/DDC.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/DDC.java @@ -596,14 +596,8 @@ static final Object convertStreamToObject(BaseInputStream stream, TypeInfo typeI if (JDBCType.GUID == jdbcType) { return Util.readGUID(byteValue); } else if (JDBCType.GEOMETRY == jdbcType) { - if (!typeInfo.getSSTypeName().equalsIgnoreCase(jdbcType.toString())) { - DataTypes.throwConversionError(typeInfo.getSSTypeName().toUpperCase(), jdbcType.toString()); - } return Geometry.STGeomFromWKB(byteValue); } else if (JDBCType.GEOGRAPHY == jdbcType) { - if (!typeInfo.getSSTypeName().equalsIgnoreCase(jdbcType.toString())) { - DataTypes.throwConversionError(typeInfo.getSSTypeName().toUpperCase(), jdbcType.toString()); - } return Geography.STGeomFromWKB(byteValue); } else { String hexString = Util.bytesToHexString(byteValue, byteValue.length); diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/DataTypes.java b/src/main/java/com/microsoft/sqlserver/jdbc/DataTypes.java index a5970e6dce..66f71bac98 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/DataTypes.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/DataTypes.java @@ -606,7 +606,7 @@ else if (!sendStringParametersAsUnicode && fromJavaType == JavaType.BYTEARRAY return false; return setterConversionAEMap.get(fromJavaType).contains(toJDBCType); } - } + }; } @@ -799,7 +799,7 @@ private SetterConversion(JDBCType.Category from, EnumSet to) static boolean converts(JDBCType fromJDBCType, JDBCType toJDBCType) { return conversionMap.get(fromJDBCType.category).contains(toJDBCType.category); } - } + }; boolean convertsTo(JDBCType jdbcType) { return SetterConversion.converts(this, jdbcType); @@ -898,7 +898,7 @@ private UpdaterConversion(JDBCType.Category from, EnumSet to) { static boolean converts(JDBCType fromJDBCType, SSType toSSType) { return conversionMap.get(fromJDBCType.category).contains(toSSType.category); } - } + }; boolean convertsTo(SSType ssType) { return UpdaterConversion.converts(this, ssType); @@ -1076,7 +1076,7 @@ private NormalizationAE(JDBCType from, EnumSet to) { static boolean converts(JDBCType fromJDBCType, SSType toSSType) { return normalizationMapAE.get(fromJDBCType).contains(toSSType); } - } + }; boolean normalizationCheck(SSType ssType) { return NormalizationAE.converts(this, ssType); diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/FailOverMapSingleton.java b/src/main/java/com/microsoft/sqlserver/jdbc/FailOverMapSingleton.java index c87beb042e..c0936b09c0 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/FailOverMapSingleton.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/FailOverMapSingleton.java @@ -31,7 +31,7 @@ private static String concatPrimaryDatabase(String primary, String instance, Str static FailoverInfo getFailoverInfo(SQLServerConnection connection, String primaryServer, String instance, String database) { synchronized (FailoverMapSingleton.class) { - if (failoverMap.isEmpty()) { + if (true == failoverMap.isEmpty()) { return null; } else { String mapKey = concatPrimaryDatabase(primaryServer, instance, database); diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/Geography.java b/src/main/java/com/microsoft/sqlserver/jdbc/Geography.java index c572ad70bd..d8dd00929f 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/Geography.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/Geography.java @@ -140,7 +140,7 @@ public static Geography parse(String wkt) throws SQLServerException { * if an exception occurs */ public static Geography point(double lat, double lon, int srid) throws SQLServerException { - return new Geography("POINT (" + lon + " " + lat + ")", srid); + return new Geography("POINT (" + lat + " " + lon + ")", srid); } /** @@ -212,8 +212,8 @@ public boolean hasZ() { * @return double value that represents the latitude. */ public Double getLatitude() { - if (null != internalType && internalType == InternalSpatialDatatype.POINT && yValues.length == 1) { - return yValues[0]; + if (null != internalType && internalType == InternalSpatialDatatype.POINT && xValues.length == 1) { + return xValues[0]; } return null; } @@ -224,8 +224,8 @@ public Double getLatitude() { * @return double value that represents the longitude. */ public Double getLongitude() { - if (null != internalType && internalType == InternalSpatialDatatype.POINT && xValues.length == 1) { - return xValues[0]; + if (null != internalType && internalType == InternalSpatialDatatype.POINT && yValues.length == 1) { + return yValues[0]; } return null; } diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java b/src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java index 056cf721ff..0cabb29360 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java @@ -52,10 +52,15 @@ import java.util.Set; import java.util.SimpleTimeZone; import java.util.TimeZone; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; import java.util.concurrent.SynchronousQueue; +import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; import java.util.logging.Level; import java.util.logging.Logger; @@ -1362,7 +1367,7 @@ private final class HostNameOverrideX509TrustManager implements X509TrustManager this.logContext = tdsChannel.toString() + " (HostNameOverrideX509TrustManager):"; defaultTrustManager = tm; // canonical name is in lower case so convert this to lowercase too. - this.hostName = hostName.toLowerCase(Locale.ENGLISH); + this.hostName = hostName.toLowerCase(Locale.ENGLISH);; } // Parse name in RFC 2253 format @@ -1537,7 +1542,7 @@ enum SSLHandhsakeState { SSL_HANDHSAKE_NOT_STARTED, SSL_HANDHSAKE_STARTED, SSL_HANDHSAKE_COMPLETE - } + }; /** * Enables SSL Handshake. @@ -1794,40 +1799,31 @@ else if (con.getTrustManagerClass() != null) { + tmfDefaultAlgorithm + "\n") : "") + ((null != ksProvider) ? ("KeyStore provider info: " + ksProvider.getInfo() + "\n") : "") + "java.ext.dirs: " + System.getProperty("java.ext.dirs")); - // Retrieve the localized error message if possible. - String localizedMessage = e.getLocalizedMessage(); - String errMsg = (localizedMessage != null) ? localizedMessage : e.getMessage(); - /* - * Retrieve the error message of the cause too because actual error message can be wrapped into a different - * message when re-thrown from underlying InputStream. - */ - String causeErrMsg = null; - Throwable cause = e.getCause(); - if (cause != null) { - String causeLocalizedMessage = cause.getLocalizedMessage(); - causeErrMsg = (causeLocalizedMessage != null) ? causeLocalizedMessage : cause.getMessage(); - } MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_sslFailed")); - Object[] msgArgs = {errMsg}; - - /* - * The error message may have a connection id appended to it. Extract the message only for comparison. This - * client connection id is appended in method checkAndAppendClientConnId(). - */ - if (errMsg != null && errMsg.contains(SQLServerException.LOG_CLIENT_CONNECTION_ID_PREFIX)) { - errMsg = errMsg.substring(0, errMsg.indexOf(SQLServerException.LOG_CLIENT_CONNECTION_ID_PREFIX)); + Object[] msgArgs = {e.getMessage()}; + + // It is important to get the localized message here, otherwise error messages won't match for different + // locales. + String errMsg = e.getLocalizedMessage(); + // If the message is null replace it with the non-localized message or a dummy string. This can happen if a + // custom + // TrustManager implementation is specified that does not provide localized messages. + if (errMsg == null) { + errMsg = e.getMessage(); } - - if (causeErrMsg != null && causeErrMsg.contains(SQLServerException.LOG_CLIENT_CONNECTION_ID_PREFIX)) { - causeErrMsg = causeErrMsg.substring(0, - causeErrMsg.indexOf(SQLServerException.LOG_CLIENT_CONNECTION_ID_PREFIX)); + if (errMsg == null) { + errMsg = ""; + } + // The error message may have a connection id appended to it. Extract the message only for comparison. + // This client connection id is appended in method checkAndAppendClientConnId(). + if (errMsg.contains(SQLServerException.LOG_CLIENT_CONNECTION_ID_PREFIX)) { + errMsg = errMsg.substring(0, errMsg.indexOf(SQLServerException.LOG_CLIENT_CONNECTION_ID_PREFIX)); } // Isolate the TLS1.2 intermittent connection error. if (e instanceof IOException && (SSLHandhsakeState.SSL_HANDHSAKE_STARTED == handshakeState) - && (SQLServerException.getErrString("R_truncatedServerResponse").equals(errMsg) - || SQLServerException.getErrString("R_truncatedServerResponse").equals(causeErrMsg))) { + && (errMsg.equals(SQLServerException.getErrString("R_truncatedServerResponse")))) { con.terminate(SQLServerException.DRIVER_ERROR_INTERMITTENT_TLS_FAILED, form.format(msgArgs), e); } else { con.terminate(SQLServerException.DRIVER_ERROR_SSL_FAILED, form.format(msgArgs), e); @@ -2112,8 +2108,8 @@ final void close() { // // Note: the log formatter itself timestamps what we write so we don't have // to do it again here. - logMsg.append(tcpSocket.getLocalAddress().toString()).append(":").append(tcpSocket.getLocalPort()) - .append(" SPID:").append(spid).append(" ").append(messageDetail).append("\r\n"); + logMsg.append(tcpSocket.getLocalAddress().toString() + ":" + tcpSocket.getLocalPort() + " SPID:" + spid + " " + + messageDetail + "\r\n"); // Fill in the body of the log message, line by line, 16 bytes per line. int nBytesLogged = 0; @@ -2299,7 +2295,7 @@ Socket findSocket(String hostName, int portNumber, int timeoutInMilliSeconds, bo loggingString.append(". They are: "); for (InetAddress inetAddr : inetAddrs) { - loggingString.append(inetAddr.toString()).append(";"); + loggingString.append(inetAddr.toString() + ";"); } logger.finer(loggingString.toString()); @@ -2477,7 +2473,7 @@ private void findSocketUsingJavaNIO(InetAddress[] inetAddrs, int portNumber, // ch.finishConnect should either return true or throw an exception // as we have subscribed for OP_CONNECT. - assert connected : "finishConnect on channel:" + ch + " cannot be false"; + assert connected == true : "finishConnect on channel:" + ch + " cannot be false"; selectedChannel = ch; @@ -6167,7 +6163,7 @@ final public String toString() { final boolean isEOM() { return TDS.STATUS_BIT_EOM == (header[TDS.PACKET_HEADER_MESSAGE_STATUS] & TDS.STATUS_BIT_EOM); } -} +}; /** @@ -6196,7 +6192,7 @@ final class TDSReaderMark { final class TDSReader { private final static Logger logger = Logger.getLogger("com.microsoft.sqlserver.jdbc.internals.TDS.Reader"); final private String traceID; - private TimeoutCommand timeoutCommand; + private TimeoutTimer tcpKeepAliveTimeoutTimer; final public String toString() { return traceID; @@ -6240,6 +6236,17 @@ private static int nextReaderID() { this.tdsChannel = tdsChannel; this.con = con; this.command = command; // may be null + if (null != command) { + // if cancelQueryTimeout is set, we should wait for the total amount of queryTimeout + cancelQueryTimeout to + // terminate the connection. + this.tcpKeepAliveTimeoutTimer = (command.getCancelQueryTimeoutSeconds() > 0 + && command.getQueryTimeoutSeconds() > 0) + ? (new TimeoutTimer( + command.getCancelQueryTimeoutSeconds() + + command.getQueryTimeoutSeconds(), + null, con)) + : null; + } // if the logging level is not detailed than fine or more we will not have proper reader IDs. if (logger.isLoggable(Level.FINE)) traceID = "TDSReader@" + nextReaderID() + " (" + con.toString() + ")"; @@ -6344,16 +6351,11 @@ synchronized final boolean readPacket() throws SQLServerException { + " should be less than numMsgsSent:" + tdsChannel.numMsgsSent; TDSPacket newPacket = new TDSPacket(con.getTDSPacketSize()); - if (null != command) { - // if cancelQueryTimeout is set, we should wait for the total amount of - // queryTimeout + cancelQueryTimeout to - // terminate the connection. - if ((command.getCancelQueryTimeoutSeconds() > 0 && command.getQueryTimeoutSeconds() > 0)) { - // if a timeout is configured with this object, add it to the timeout poller - int timeout = command.getCancelQueryTimeoutSeconds() + command.getQueryTimeoutSeconds(); - this.timeoutCommand = new TdsTimeoutCommand(timeout, this.command, this.con); - TimeoutPoller.getTimeoutPoller().addTimeoutCommand(this.timeoutCommand); + if (null != tcpKeepAliveTimeoutTimer) { + if (logger.isLoggable(Level.FINEST)) { + logger.finest(this.toString() + ": starting timer..."); } + tcpKeepAliveTimeoutTimer.start(); } // First, read the packet header. for (int headerBytesRead = 0; headerBytesRead < TDS.PACKET_HEADER_SIZE;) { @@ -6373,8 +6375,11 @@ synchronized final boolean readPacket() throws SQLServerException { } // if execution was subject to timeout then stop timing - if (this.timeoutCommand != null) { - TimeoutPoller.getTimeoutPoller().remove(this.timeoutCommand); + if (null != tcpKeepAliveTimeoutTimer) { + if (logger.isLoggable(Level.FINEST)) { + logger.finest(this.toString() + ":stopping timer..."); + } + tcpKeepAliveTimeoutTimer.stop(); } // Header size is a 2 byte unsigned short integer in big-endian order. int packetLength = Util.readUnsignedShortBigEndian(newPacket.header, TDS.PACKET_HEADER_MESSAGE_LENGTH); @@ -6964,25 +6969,82 @@ final void trySetSensitivityClassification(SensitivityClassification sensitivity /** - * The tds default implementation of a timeout command + * Timer for use with Commands that support a timeout. + * + * Once started, the timer runs for the prescribed number of seconds unless stopped. If the timer runs out, it + * interrupts its associated Command with a reason like "timed out". */ -class TdsTimeoutCommand extends TimeoutCommand { - public TdsTimeoutCommand(int timeout, TDSCommand command, SQLServerConnection sqlServerConnection) { - super(timeout, command, sqlServerConnection); +final class TimeoutTimer implements Runnable { + private static final String threadGroupName = "mssql-jdbc-TimeoutTimer"; + private final int timeoutSeconds; + private final TDSCommand command; + private volatile Future task; + private final SQLServerConnection con; + + private static final ExecutorService executor = Executors.newCachedThreadPool(new ThreadFactory() { + private final AtomicReference tgr = new AtomicReference<>(); + private final AtomicInteger threadNumber = new AtomicInteger(0); + + @Override + public Thread newThread(Runnable r) { + ThreadGroup tg = tgr.get(); + + if (tg == null || tg.isDestroyed()) { + tg = new ThreadGroup(threadGroupName); + tgr.set(tg); + } + + Thread t = new Thread(tg, r, tg.getName() + "-" + threadNumber.incrementAndGet()); + t.setDaemon(true); + return t; + } + }); + + private volatile boolean canceled = false; + + TimeoutTimer(int timeoutSeconds, TDSCommand command, SQLServerConnection con) { + assert timeoutSeconds > 0; + + this.timeoutSeconds = timeoutSeconds; + this.command = command; + this.con = con; } - public void interrupt() { - TDSCommand command = getCommand(); - SQLServerConnection sqlServerConnection = getSqlServerConnection(); + final void start() { + task = executor.submit(this); + } + + final void stop() { + task.cancel(true); + canceled = true; + } + + public void run() { + int secondsRemaining = timeoutSeconds; try { - // If TCP Connection to server is silently dropped, exceeding the query timeout - // on the same connection does + // Poll every second while time is left on the timer. + // Return if/when the timer is canceled. + do { + if (canceled) + return; + + Thread.sleep(1000); + } while (--secondsRemaining > 0); + } catch (InterruptedException e) { + // re-interrupt the current thread, in order to restore the thread's interrupt status. + Thread.currentThread().interrupt(); + return; + } + + // If the timer wasn't canceled before it ran out of + // time then interrupt the registered command. + try { + // If TCP Connection to server is silently dropped, exceeding the query timeout on the same connection does // not throw SQLTimeoutException - // The application stops responding instead until SocketTimeoutException is - // thrown. In this case, we must + // The application stops responding instead until SocketTimeoutException is thrown. In this case, we must // manually terminate the connection. - if (null == command && null != sqlServerConnection) { - sqlServerConnection.terminate(SQLServerException.DRIVER_ERROR_IO_FAILED, + if (null == command && null != con) { + con.terminate(SQLServerException.DRIVER_ERROR_IO_FAILED, SQLServerException.getErrString("R_connectionIsClosed")); } else { // If the timer wasn't canceled before it ran out of @@ -6999,6 +7061,7 @@ public void interrupt() { } } + /** * TDSCommand encapsulates an interruptable TDS conversation. * @@ -7032,6 +7095,10 @@ final void log(Level level, String message) { logger.log(level, toString() + ": " + message); } + // Optional timer that is set if the command was created with a non-zero timeout period. + // When the timer expires, the command is interrupted. + private final TimeoutTimer timeoutTimer; + // TDS channel accessors // These are set/reset at command execution time. // Volatile ensures visibility to execution thread and interrupt thread @@ -7120,7 +7187,6 @@ protected void setProcessedResponse(boolean processedResponse) { private volatile boolean readingResponse; private int queryTimeoutSeconds; private int cancelQueryTimeoutSeconds; - private TdsTimeoutCommand timeoutCommand; protected int getQueryTimeoutSeconds() { return this.queryTimeoutSeconds; @@ -7147,6 +7213,7 @@ final boolean readingResponse() { this.logContext = logContext; this.queryTimeoutSeconds = queryTimeoutSeconds; this.cancelQueryTimeoutSeconds = cancelQueryTimeoutSeconds; + this.timeoutTimer = (queryTimeoutSeconds > 0) ? (new TimeoutTimer(queryTimeoutSeconds, this, null)) : null; } /** @@ -7535,9 +7602,11 @@ final TDSReader startResponse(boolean isAdaptive) throws SQLServerException { // If command execution is subject to timeout then start timing until // the server returns the first response packet. - if (queryTimeoutSeconds > 0) { - this.timeoutCommand = new TdsTimeoutCommand(queryTimeoutSeconds, this, null); - TimeoutPoller.getTimeoutPoller().addTimeoutCommand(this.timeoutCommand); + if (null != timeoutTimer) { + if (logger.isLoggable(Level.FINEST)) + logger.finest(this.toString() + ": Starting timer..."); + + timeoutTimer.start(); } if (logger.isLoggable(Level.FINEST)) @@ -7560,8 +7629,11 @@ final TDSReader startResponse(boolean isAdaptive) throws SQLServerException { } finally { // If command execution was subject to timeout then stop timing as soon // as the server returns the first response packet or errors out. - if (this.timeoutCommand != null) { - TimeoutPoller.getTimeoutPoller().remove(this.timeoutCommand); + if (null != timeoutTimer) { + if (logger.isLoggable(Level.FINEST)) + logger.finest(this.toString() + ": Stopping timer..."); + + timeoutTimer.stop(); } } diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/Parameter.java b/src/main/java/com/microsoft/sqlserver/jdbc/Parameter.java index 7e94fe9e4c..6e8e0a2daa 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/Parameter.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/Parameter.java @@ -296,7 +296,7 @@ void setValue(JDBCType jdbcType, Object value, JavaType javaType, StreamSetterAr } // forceEncryption is true, shouldhonorae is false - if (forceEncrypt && !Util.shouldHonorAEForParameters(stmtColumnEncriptionSetting, con)) { + if ((true == forceEncrypt) && (false == Util.shouldHonorAEForParameters(stmtColumnEncriptionSetting, con))) { MessageFormat form = new MessageFormat( SQLServerException.getErrString("R_ForceEncryptionTrue_HonorAEFalse")); @@ -603,9 +603,10 @@ private void setTypeDefinition(DTV dtv) { */ if (userProvidesScale) { - param.typeDefinition = SSType.TIME.toString() + "(" + outScale + ")"; + param.typeDefinition = (SSType.TIME.toString() + "(" + outScale + ")"); } else { - param.typeDefinition = SSType.TIME.toString() + "(" + valueLength + ")"; + param.typeDefinition = param.typeDefinition = SSType.TIME.toString() + "(" + valueLength + + ")"; } } else { param.typeDefinition = con.getSendTimeAsDatetime() ? SSType.DATETIME.toString() diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLJdbcVersion.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLJdbcVersion.java index 05c10cbe1a..de354b40e4 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLJdbcVersion.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLJdbcVersion.java @@ -8,6 +8,6 @@ final class SQLJdbcVersion { static final int major = 7; static final int minor = 1; - static final int patch = 3; + static final int patch = 2; static final int build = 0; } diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCopy.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCopy.java index 2df1e090a5..068e400117 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCopy.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCopy.java @@ -224,7 +224,7 @@ class BulkColumnMetaData { this.jdbcType = bulkColumnMetaData.jdbcType; this.cryptoMeta = cryptoMeta; } - } + }; /** * A map to store the metadata information for the destination table. @@ -247,16 +247,56 @@ class BulkColumnMetaData { private int srcColumnCount; /** - * Timeout for the bulk copy command + * Timer for the bulk copy operation. The other timeout timers in the TDS layer only measure the response of the + * first packet from SQL Server. */ - private final class BulkTimeoutCommand extends TimeoutCommand { - public BulkTimeoutCommand(int timeout, TDSCommand command, SQLServerConnection sqlServerConnection) { - super(timeout, command, sqlServerConnection); + private final class BulkTimeoutTimer implements Runnable { + private final int timeoutSeconds; + private int secondsRemaining; + private final TDSCommand command; + private Thread timerThread; + private volatile boolean canceled = false; + + BulkTimeoutTimer(int timeoutSeconds, TDSCommand command) { + assert timeoutSeconds > 0; + assert null != command; + + this.timeoutSeconds = timeoutSeconds; + this.secondsRemaining = timeoutSeconds; + this.command = command; + } + + final void start() { + timerThread = new Thread(this); + timerThread.setDaemon(true); + timerThread.start(); + } + + final void stop() { + canceled = true; + timerThread.interrupt(); } - @Override - public void interrupt() { - TDSCommand command = getCommand(); + final boolean expired() { + return (secondsRemaining <= 0); + } + + public void run() { + try { + // Poll every second while time is left on the timer. + // Return if/when the timer is canceled. + do { + if (canceled) + return; + + Thread.sleep(1000); + } while (--secondsRemaining > 0); + } catch (InterruptedException e) { + // re-interrupt the current thread, in order to restore the thread's interrupt status. + Thread.currentThread().interrupt(); + return; + } + // If the timer wasn't canceled before it ran out of // time then interrupt the registered command. try { @@ -270,7 +310,7 @@ public void interrupt() { } } - private BulkTimeoutCommand timeoutCommand; + private BulkTimeoutTimer timeoutTimer = null; /** * The maximum temporal precision we can send when using varchar(precision) in bulkcommand, to send a @@ -647,15 +687,15 @@ final class InsertBulk extends TDSCommand { InsertBulk() { super("InsertBulk", 0, 0); int timeoutSeconds = copyOptions.getBulkCopyTimeout(); - timeoutCommand = timeoutSeconds > 0 ? new BulkTimeoutCommand(timeoutSeconds, this, null) : null; + timeoutTimer = (timeoutSeconds > 0) ? (new BulkTimeoutTimer(timeoutSeconds, this)) : null; } final boolean doExecute() throws SQLServerException { - if (null != timeoutCommand) { + if (null != timeoutTimer) { if (logger.isLoggable(Level.FINEST)) logger.finest(this.toString() + ": Starting bulk timer..."); - TimeoutPoller.getTimeoutPoller().addTimeoutCommand(timeoutCommand); + timeoutTimer.start(); } // doInsertBulk inserts the rows in one batch. It returns true if there are more rows in @@ -672,18 +712,18 @@ final boolean doExecute() throws SQLServerException { // Check whether it is a timeout exception. if (rootCause instanceof SQLException) { - checkForTimeoutException((SQLException) rootCause, timeoutCommand); + checkForTimeoutException((SQLException) rootCause, timeoutTimer); } // It is not a timeout exception. Re-throw. throw topLevelException; } - if (null != timeoutCommand) { + if (null != timeoutTimer) { if (logger.isLoggable(Level.FINEST)) logger.finest(this.toString() + ": Stopping bulk timer..."); - TimeoutPoller.getTimeoutPoller().remove(timeoutCommand); + timeoutTimer.stop(); } return true; @@ -730,7 +770,7 @@ private void writeColumnMetaDataColumnData(TDSWriter tdsWriter, int idx) throws // the driver will not sent AE information, so, we need to set Encryption bit flag to 0. if (null == srcColumnMetadata.get(srcColumnIndex).cryptoMeta && null == destColumnMetadata.get(destColumnIndex).cryptoMeta - && copyOptions.isAllowEncryptedValueModifications()) { + && true == copyOptions.isAllowEncryptedValueModifications()) { // flags[1]>>3 & 0x01 is the encryption bit flag. // it is the 4th least significant bit in this byte, so minus 8 to set it to 0. @@ -1148,9 +1188,9 @@ private void writeColumnMetaData(TDSWriter tdsWriter) throws SQLServerException /** * Helper method that throws a timeout exception if the cause of the exception was that the query was cancelled */ - private void checkForTimeoutException(SQLException e, BulkTimeoutCommand timeoutCommand) throws SQLServerException { + private void checkForTimeoutException(SQLException e, BulkTimeoutTimer timeoutTimer) throws SQLServerException { if ((null != e.getSQLState()) && (e.getSQLState().equals(SQLState.STATEMENT_CANCELED.getSQLStateCode())) - && timeoutCommand.canTimeout()) { + && timeoutTimer.expired()) { // If SQLServerBulkCopy is managing the transaction, a rollback is needed. if (copyOptions.isUseInternalTransaction()) { connection.rollback(); @@ -1410,7 +1450,7 @@ private String createInsertBulkCommand(TDSWriter tdsWriter) throws SQLServerExce StringBuilder bulkCmd = new StringBuilder(); List bulkOptions = new ArrayList<>(); String endColumn = " , "; - bulkCmd.append("INSERT BULK ").append(destinationTableName).append(" ("); + bulkCmd.append("INSERT BULK " + destinationTableName + " ("); for (int i = 0; i < (columnMappings.size()); ++i) { if (i == columnMappings.size() - 1) { @@ -1431,23 +1471,21 @@ private String createInsertBulkCommand(TDSWriter tdsWriter) throws SQLServerExce } if (colMapping.destinationColumnName.contains("]")) { String escapedColumnName = colMapping.destinationColumnName.replaceAll("]", "]]"); - bulkCmd.append("[").append(escapedColumnName).append("] ").append(destType).append(addCollate) - .append(endColumn); + bulkCmd.append("[" + escapedColumnName + "] " + destType + addCollate + endColumn); } else { - bulkCmd.append("[").append(colMapping.destinationColumnName).append("] ").append(destType) - .append(addCollate).append(endColumn); + bulkCmd.append("[" + colMapping.destinationColumnName + "] " + destType + addCollate + endColumn); } } - if (copyOptions.isCheckConstraints()) { + if (true == copyOptions.isCheckConstraints()) { bulkOptions.add("CHECK_CONSTRAINTS"); } - if (copyOptions.isFireTriggers()) { + if (true == copyOptions.isFireTriggers()) { bulkOptions.add("FIRE_TRIGGERS"); } - if (copyOptions.isKeepNulls()) { + if (true == copyOptions.isKeepNulls()) { bulkOptions.add("KEEP_NULLS"); } @@ -1455,11 +1493,11 @@ private String createInsertBulkCommand(TDSWriter tdsWriter) throws SQLServerExce bulkOptions.add("ROWS_PER_BATCH = " + copyOptions.getBatchSize()); } - if (copyOptions.isTableLock()) { + if (true == copyOptions.isTableLock()) { bulkOptions.add("TABLOCK"); } - if (copyOptions.isAllowEncryptedValueModifications()) { + if (true == copyOptions.isAllowEncryptedValueModifications()) { bulkOptions.add("ALLOW_ENCRYPTED_VALUE_MODIFICATIONS"); } diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java index 92355d90fe..0ba3f48d30 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java @@ -1324,7 +1324,7 @@ Connection connectInternal(Properties propsIn, } trustedServerNameAE = sPropValue; - if (serverNameAsACE) { + if (true == serverNameAsACE) { try { sPropValue = java.net.IDN.toASCII(sPropValue); } catch (IllegalArgumentException ex) { @@ -1529,8 +1529,8 @@ Connection connectInternal(Properties propsIn, } authenticationString = SqlAuthentication.valueOfString(sPropValue).toString(); - if (integratedSecurity - && !authenticationString.equalsIgnoreCase(SqlAuthentication.NotSpecified.toString())) { + if ((true == integratedSecurity) + && (!authenticationString.equalsIgnoreCase(SqlAuthentication.NotSpecified.toString()))) { if (connectionlogger.isLoggable(Level.SEVERE)) { connectionlogger.severe(toString() + " " + SQLServerException.getErrString("R_SetAuthenticationWhenIntegratedSecurityTrue")); @@ -1591,7 +1591,7 @@ Connection connectInternal(Properties propsIn, throw new SQLServerException(SQLServerException.getErrString("R_AccessTokenCannotBeEmpty"), null); } - if (integratedSecurity && (null != accessTokenInByte)) { + if ((true == integratedSecurity) && (null != accessTokenInByte)) { if (connectionlogger.isLoggable(Level.SEVERE)) { connectionlogger.severe(toString() + " " + SQLServerException.getErrString("R_SetAccesstokenWhenIntegratedSecurityTrue")); @@ -2983,7 +2983,7 @@ String sqlStatementToSetTransactionIsolationLevel() throws SQLServerException { * @return the required syntax */ static String sqlStatementToSetCommit(boolean autoCommit) { - return autoCommit ? "set implicit_transactions off " : "set implicit_transactions on "; + return (true == autoCommit) ? "set implicit_transactions off " : "set implicit_transactions on "; } @Override @@ -3033,7 +3033,7 @@ public void setAutoCommit(boolean newAutoCommitMode) throws SQLServerException { // When changing to auto-commit from inside an existing transaction, // commit that transaction first. - if (newAutoCommitMode) + if (newAutoCommitMode == true) commitPendingTransaction = "IF @@TRANCOUNT > 0 COMMIT TRAN "; if (connectionlogger.isLoggable(Level.FINER)) { @@ -3042,7 +3042,7 @@ public void setAutoCommit(boolean newAutoCommitMode) throws SQLServerException { } rolledBackTransaction = false; - connectionCommand(sqlStatementToSetCommit(newAutoCommitMode) + commitPendingTransaction, "setAutoCommit"); + connectionCommand(commitPendingTransaction + sqlStatementToSetCommit(newAutoCommitMode), "setAutoCommit"); databaseAutoCommitMode = newAutoCommitMode; loggerExternal.exiting(getClassNameLogging(), "setAutoCommit"); } @@ -3457,11 +3457,11 @@ int writeFedAuthFeatureRequest(boolean write, TDSWriter tdsWriter, // set upper 7 bits of options to indicate fed auth library type switch (fedAuthFeatureExtensionData.libraryType) { case TDS.TDS_FEDAUTH_LIBRARY_ADAL: - assert federatedAuthenticationInfoRequested; + assert federatedAuthenticationInfoRequested == true; options |= TDS.TDS_FEDAUTH_LIBRARY_ADAL << 1; break; case TDS.TDS_FEDAUTH_LIBRARY_SECURITYTOKEN: - assert federatedAuthenticationRequested; + assert federatedAuthenticationRequested == true; options |= TDS.TDS_FEDAUTH_LIBRARY_SECURITYTOKEN << 1; break; default: @@ -3469,7 +3469,7 @@ int writeFedAuthFeatureRequest(boolean write, TDSWriter tdsWriter, break; } - options |= (byte) (fedAuthFeatureExtensionData.fedAuthRequiredPreLoginResponse ? 0x01 : 0x00); + options |= (byte) (fedAuthFeatureExtensionData.fedAuthRequiredPreLoginResponse == true ? 0x01 : 0x00); // write FeatureDataLen tdsWriter.writeInt(dataLen); @@ -4279,7 +4279,7 @@ private void onFeatureExtAck(byte featureId, byte[] data) throws SQLServerExcept } byte enabled = data[1]; - serverSupportsDataClassification = enabled != 0; + serverSupportsDataClassification = (enabled == 0) ? false : true; } case TDS.TDS_FEATURE_EXT_UTF8SUPPORT: { if (connectionlogger.isLoggable(Level.FINER)) { @@ -4977,7 +4977,7 @@ public void releaseSavepoint(Savepoint savepoint) throws SQLException { } final private Savepoint setNamedSavepoint(String sName) throws SQLServerException { - if (databaseAutoCommitMode) { + if (true == databaseAutoCommitMode) { SQLServerException.makeFromDriverError(this, this, SQLServerException.getErrString("R_cantSetSavepoint"), null, false); } @@ -5028,7 +5028,7 @@ public void rollback(Savepoint s) throws SQLServerException { loggerExternal.finer(toString() + " ActivityId: " + ActivityCorrelator.getNext().toString()); } checkClosed(); - if (databaseAutoCommitMode) { + if (true == databaseAutoCommitMode) { SQLServerException.makeFromDriverError(this, this, SQLServerException.getErrString("R_cantInvokeRollback"), null, false); } @@ -5971,7 +5971,7 @@ public void onEviction(CityHash128Key key, PreparedStatementHandle handle) { boolean isAzureDW() throws SQLServerException, SQLException { if (null == isAzureDW) { try (Statement stmt = this.createStatement(); - ResultSet rs = stmt.executeQuery("SELECT CAST(SERVERPROPERTY('EngineEdition') as INT)")) { + ResultSet rs = stmt.executeQuery("SELECT CAST(SERVERPROPERTY('EngineEdition') as INT)");) { // SERVERPROPERTY('EngineEdition') can be used to determine whether the db server is SQL Azure. // It should return 6 for SQL Azure DW. This is more reliable than @@version or // serverproperty('edition'). @@ -5988,7 +5988,7 @@ boolean isAzureDW() throws SQLServerException, SQLException { // Base data type: int final int ENGINE_EDITION_FOR_SQL_AZURE_DW = 6; rs.next(); - isAzureDW = rs.getInt(1) == ENGINE_EDITION_FOR_SQL_AZURE_DW; + isAzureDW = (rs.getInt(1) == ENGINE_EDITION_FOR_SQL_AZURE_DW) ? true : false; } return isAzureDW; } else { diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataSource.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataSource.java index e20b0a8e87..a0b32b32e8 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataSource.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataSource.java @@ -1090,7 +1090,7 @@ Reference getReferenceInternal(String dataSourceClassString) { if (propertyName.equals(SQLServerDriverStringProperty.TRUST_STORE_PASSWORD.toString())) { // The property set and the variable set at the same time is not // possible - assert !trustStorePasswordStripped; + assert trustStorePasswordStripped == false; ref.add(new StringRefAddr("trustStorePasswordStripped", "true")); } else { // do not add passwords to the collection. we have normal diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDatabaseMetaData.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDatabaseMetaData.java index 51132018f7..91592c78b5 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDatabaseMetaData.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDatabaseMetaData.java @@ -521,16 +521,17 @@ public java.sql.ResultSet getTables(String catalog, String schema, String table, arguments[1] = schema; arguments[2] = catalog; + String tableTypes = null; if (types != null) { - final StringBuilder tableTypes = new StringBuilder("'"); + tableTypes = "'"; for (int i = 0; i < types.length; i++) { if (i > 0) - tableTypes.append(","); - tableTypes.append("''").append(types[i]).append("''"); + tableTypes += ","; + tableTypes += "''" + types[i] + "''"; } - tableTypes.append("'"); - arguments[3] = tableTypes.toString(); + tableTypes += "'"; } + arguments[3] = tableTypes; return getResultSetWithProvidedColumnNames(catalog, CallableHandles.SP_TABLES, arguments, getTablesColumnNames); } diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerException.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerException.java index bdea428d6d..be19694f5e 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerException.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerException.java @@ -118,7 +118,7 @@ private void logException(Object o, String errText, boolean bStack) { sb.append(aSt.toString()); Throwable t = this.getCause(); if (t != null) { - sb.append("\n caused by ").append(t).append("\n"); + sb.append("\n caused by " + t + "\n"); StackTraceElement tst[] = t.getStackTrace(); for (StackTraceElement aTst : tst) sb.append(aTst.toString()); diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerMetaData.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerMetaData.java index dfb43f7568..da9db54b7e 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerMetaData.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerMetaData.java @@ -60,23 +60,6 @@ public SQLServerMetaData(String columnName, int sqlType, int precision, int scal this.scale = scale; } - /** - * Constructs a SQLServerMetaData with the column name, SQL type, and length (for String data). - * The length is used to differentiate large strings from strings with length less than 4000 characters. - * - * @param columnName - * the name of the column - * @param sqlType - * the SQL type of the column - * @param length - * the length of the string type - */ - public SQLServerMetaData(String columnName, int sqlType, int length) { - this.columnName = columnName; - this.javaSqlType = sqlType; - this.precision = length; - } - /** * Constructs a SQLServerMetaData. * diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerParameterMetaData.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerParameterMetaData.java index c2bea2755e..8ce79e106b 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerParameterMetaData.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerParameterMetaData.java @@ -645,7 +645,7 @@ private void checkClosed() throws SQLServerException { StringBuilder sbColumns = new StringBuilder(); for (MetaInfo mi : metaInfoList) { - sbColumns = sbColumns.append(mi.fields).append(","); + sbColumns = sbColumns.append(mi.fields + ","); } sbColumns.deleteCharAt(sbColumns.length() - 1); @@ -660,10 +660,9 @@ private void checkClosed() throws SQLServerException { && metaInfoList.get(i).fields.equals(metaInfoList.get(i - 1).fields)) { continue; } - sbTablesAndJoins = sbTablesAndJoins.append(" LEFT JOIN ").append(metaInfoList.get(i).table) - .append(" ON ").append(metaInfoList.get(i - 1).table).append(".") - .append(metaInfoList.get(i - 1).fields).append("=") - .append(metaInfoList.get(i).table).append(".").append(metaInfoList.get(i).fields); + sbTablesAndJoins = sbTablesAndJoins.append(" LEFT JOIN " + metaInfoList.get(i).table + + " ON " + metaInfoList.get(i - 1).table + "." + metaInfoList.get(i - 1).fields + + "=" + metaInfoList.get(i).table + "." + metaInfoList.get(i).fields); } } diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerPreparedStatement.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerPreparedStatement.java index fea6c22e36..41844f8134 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerPreparedStatement.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerPreparedStatement.java @@ -925,7 +925,7 @@ private void getParameterEncryptionMetadata(Parameter[] params) throws SQLServer // Decrypt the symmetric key.(This will also validate and throw if needed). SQLServerSecurityUtility.decryptSymmetricKey(params[paramIndex].cryptoMeta, connection); } else { - if (params[paramIndex].getForceEncryption()) { + if (true == params[paramIndex].getForceEncryption()) { MessageFormat form = new MessageFormat( SQLServerException.getErrString("R_ForceEncryptionTrue_HonorAETrue_UnencryptedColumn")); Object[] msgArgs = {userSQL, paramIndex + 1}; @@ -1081,7 +1081,7 @@ private ResultSet buildExecuteMetaData() throws SQLServerException { internalStmt = (SQLServerStatement) connection.createStatement(); emptyResultSet = internalStmt.executeQueryInternal("set fmtonly on " + fmtSQL + "\nset fmtonly off"); } catch (SQLException sqle) { - if (!sqle.getMessage().equals(SQLServerException.getErrString("R_noResultset"))) { + if (false == sqle.getMessage().equals(SQLServerException.getErrString("R_noResultset"))) { // if the error is not no resultset then throw a processings error. MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_processingError")); Object[] msgArgs = {sqle.getMessage()}; @@ -1972,7 +1972,7 @@ public int[] executeBatch() throws SQLServerException, BatchUpdateException, SQL stmtColumnEncriptionSetting); SQLServerResultSet rs = stmt .executeQueryInternal("sp_executesql N'SET FMTONLY ON SELECT * FROM " - + Util.escapeSingleQuotes(tableName) + " '")) { + + Util.escapeSingleQuotes(tableName) + " '");) { if (null != columnList && columnList.size() > 0) { if (columnList.size() != valueList.size()) { throw new IllegalArgumentException( @@ -2129,7 +2129,7 @@ public long[] executeLargeBatch() throws SQLServerException, BatchUpdateExceptio stmtColumnEncriptionSetting); SQLServerResultSet rs = stmt .executeQueryInternal("sp_executesql N'SET FMTONLY ON SELECT * FROM " - + Util.escapeSingleQuotes(tableName) + " '")) { + + Util.escapeSingleQuotes(tableName) + " '");) { if (null != columnList && columnList.size() > 0) { if (columnList.size() != valueList.size()) { throw new IllegalArgumentException( diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResultSet.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResultSet.java index 8a6e3391c9..e163219e80 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResultSet.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResultSet.java @@ -1072,6 +1072,7 @@ public boolean next() throws SQLServerException { public boolean wasNull() throws SQLServerException { loggerExternal.entering(getClassNameLogging(), "wasNull"); checkClosed(); + fillLOBs(); loggerExternal.exiting(getClassNameLogging(), "wasNull", lastValueWasNull); return lastValueWasNull; } diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerStatement.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerStatement.java index 7f166b0723..d0ae5e25b5 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerStatement.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerStatement.java @@ -1012,28 +1012,29 @@ static String replaceParameterWithString(String str, char marker, String replace */ static String replaceMarkerWithNull(String sql) { if (!sql.contains("'")) { - return replaceParameterWithString(sql, '?', "null"); + String retStr = replaceParameterWithString(sql, '?', "null"); + return retStr; } else { StringTokenizer st = new StringTokenizer(sql, "'", true); boolean beforeColon = true; - final StringBuilder retSql = new StringBuilder(); + String retSql = ""; while (st.hasMoreTokens()) { String str = st.nextToken(); if (str.equals("'")) { - retSql.append("'"); + retSql += "'"; beforeColon = !beforeColon; continue; } if (beforeColon) { String repStr = replaceParameterWithString(str, '?', "null"); - retSql.append(repStr); + retSql += repStr; continue; } else { - retSql.append(str); + retSql += str; continue; } } - return retSql.toString(); + return retSql; } } @@ -2411,7 +2412,7 @@ enum State { OFFSET, QUOTE, PROCESS - } + }; // This pattern matches the LIMIT syntax with an OFFSET clause. The driver does not support OFFSET expression in the // LIMIT clause. diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerSymmetricKeyCache.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerSymmetricKeyCache.java index bebb43e98b..80eb9a03ae 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerSymmetricKeyCache.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerSymmetricKeyCache.java @@ -14,7 +14,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadFactory;; class CacheClear implements Runnable { diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SimpleInputStream.java b/src/main/java/com/microsoft/sqlserver/jdbc/SimpleInputStream.java index 4586ef3895..fa22c96ca4 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SimpleInputStream.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SimpleInputStream.java @@ -37,7 +37,7 @@ private static int nextLoggingID() { } static final java.util.logging.Logger logger = java.util.logging.Logger - .getLogger("com.microsoft.sqlserver.jdbc.internals.InputStream"); + .getLogger("com.microsoft.sqlserver.jdbc.internals.InputStream");; private String traceID; final public String toString() { diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/TVP.java b/src/main/java/com/microsoft/sqlserver/jdbc/TVP.java index abe9fe097e..92bf03d6c1 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/TVP.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/TVP.java @@ -63,7 +63,7 @@ enum MPIState { MPI_LookForNextCharOrSeparator, MPI_ParseQuote, MPI_RightQuote, - } + }; void initTVP(TVPType type, String tvpPartName) throws SQLServerException { tvpType = type; diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/TimeoutCommand.java b/src/main/java/com/microsoft/sqlserver/jdbc/TimeoutCommand.java deleted file mode 100644 index 65b1f68b26..0000000000 --- a/src/main/java/com/microsoft/sqlserver/jdbc/TimeoutCommand.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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; - -/** - * Abstract implementation of a command that can be timed out using the {@link TimeoutPoller} - */ -abstract class TimeoutCommand { - private final long startTime; - private final int timeout; - private final T command; - private final SQLServerConnection sqlServerConnection; - - TimeoutCommand(int timeout, T command, SQLServerConnection sqlServerConnection) { - this.timeout = timeout; - this.command = command; - this.sqlServerConnection = sqlServerConnection; - this.startTime = System.currentTimeMillis(); - } - - public boolean canTimeout() { - long currentTime = System.currentTimeMillis(); - return ((currentTime - startTime) / 1000) >= timeout; - } - - public T getCommand() { - return command; - } - - public SQLServerConnection getSqlServerConnection() { - return sqlServerConnection; - } - - /** - * The implementation for interrupting this timeout command - */ - public abstract void interrupt(); -} diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/TimeoutPoller.java b/src/main/java/com/microsoft/sqlserver/jdbc/TimeoutPoller.java deleted file mode 100644 index 6c53d4d744..0000000000 --- a/src/main/java/com/microsoft/sqlserver/jdbc/TimeoutPoller.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * 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.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - - -/** - * Thread that runs in the background while the mssql driver is used that can timeout TDSCommands Checks all registered - * commands every second to see if they can be interrupted - */ -final class TimeoutPoller implements Runnable { - private List> timeoutCommands = new ArrayList<>(); - final static Logger logger = Logger.getLogger("com.microsoft.sqlserver.jdbc.TimeoutPoller"); - private static volatile TimeoutPoller timeoutPoller = null; - - static TimeoutPoller getTimeoutPoller() { - if (timeoutPoller == null) { - synchronized (TimeoutPoller.class) { - if (timeoutPoller == null) { - // initialize the timeout poller thread once - timeoutPoller = new TimeoutPoller(); - // start the timeout polling thread - Thread pollerThread = new Thread(timeoutPoller, "mssql-jdbc-TimeoutPoller"); - pollerThread.setDaemon(true); - pollerThread.start(); - } - } - } - return timeoutPoller; - } - - void addTimeoutCommand(TimeoutCommand timeoutCommand) { - synchronized (timeoutCommands) { - timeoutCommands.add(timeoutCommand); - } - } - - void remove(TimeoutCommand timeoutCommand) { - synchronized (timeoutCommands) { - timeoutCommands.remove(timeoutCommand); - } - } - - private TimeoutPoller() {} - - public void run() { - try { - // Poll every second checking for commands that have timed out and need - // interruption - while (true) { - synchronized (timeoutCommands) { - Iterator> timeoutCommandIterator = timeoutCommands.iterator(); - while (timeoutCommandIterator.hasNext()) { - TimeoutCommand timeoutCommand = timeoutCommandIterator.next(); - try { - if (timeoutCommand.canTimeout()) { - try { - timeoutCommand.interrupt(); - } finally { - timeoutCommandIterator.remove(); - } - } - } catch (Exception e) { - logger.log(Level.WARNING, "Could not timeout command", e); - } - } - } - Thread.sleep(1000); - } - } catch (Exception e) { - logger.log(Level.SEVERE, "Error processing timeout commands", e); - } - } -} diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/Util.java b/src/main/java/com/microsoft/sqlserver/jdbc/Util.java index 76617d31a0..087c2408b6 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/Util.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/Util.java @@ -380,7 +380,7 @@ else if (ch == ':') name = SQLServerDriver.getNormalizedPropertyName(name, logger); if (null != name) { if (logger.isLoggable(Level.FINE)) { - if (!name.equals(SQLServerDriverStringProperty.USER.toString())) { + if (false == name.equals(SQLServerDriverStringProperty.USER.toString())) { if (!name.toLowerCase(Locale.ENGLISH).contains("password") && !name.toLowerCase(Locale.ENGLISH).contains("keystoresecret")) { logger.fine("Property:" + name + " Value:" + value); @@ -417,8 +417,8 @@ else if (ch == ':') name = SQLServerDriver.getNormalizedPropertyName(name, logger); if (null != name) { if (logger.isLoggable(Level.FINE)) { - if (!name.equals(SQLServerDriverStringProperty.USER.toString()) - && !name.equals(SQLServerDriverStringProperty.PASSWORD.toString())) + if ((false == name.equals(SQLServerDriverStringProperty.USER.toString())) + && (false == name.equals(SQLServerDriverStringProperty.PASSWORD.toString()))) logger.fine("Property:" + name + " Value:" + value); } p.put(name, value); @@ -487,9 +487,9 @@ else if (ch == ':') name = SQLServerDriver.getNormalizedPropertyName(name, logger); if (null != name) { if (logger.isLoggable(Level.FINE)) { - if (!name.equals(SQLServerDriverStringProperty.USER.toString()) - && !name.equals(SQLServerDriverStringProperty.PASSWORD.toString()) - && !name.equals(SQLServerDriverStringProperty.KEY_STORE_SECRET.toString())) + if ((false == name.equals(SQLServerDriverStringProperty.USER.toString())) + && (false == name.equals(SQLServerDriverStringProperty.PASSWORD.toString())) + && (false == name.equals(SQLServerDriverStringProperty.KEY_STORE_SECRET.toString()))) logger.fine("Property:" + name + " Value:" + value); } p.put(name, value); @@ -1044,19 +1044,19 @@ final String asEscapedString() { StringBuilder fullName = new StringBuilder(256); if (serverName.length() > 0) - fullName.append("[").append(serverName).append("]."); + fullName.append("[" + serverName + "]."); if (databaseName.length() > 0) - fullName.append("[").append(databaseName).append("]."); + fullName.append("[" + databaseName + "]."); else assert 0 == serverName.length(); if (schemaName.length() > 0) - fullName.append("[").append(schemaName).append("]."); + fullName.append("[" + schemaName + "]."); else if (databaseName.length() > 0) fullName.append('.'); - fullName.append("[").append(objectName).append("]"); + fullName.append("[" + objectName + "]"); return fullName.toString(); } diff --git a/src/samples/datatypes/src/main/java/SpatialDataTypes.java b/src/samples/datatypes/src/main/java/SpatialDataTypes.java index 8a3d145fea..6a7aae6dc1 100644 --- a/src/samples/datatypes/src/main/java/SpatialDataTypes.java +++ b/src/samples/datatypes/src/main/java/SpatialDataTypes.java @@ -58,6 +58,7 @@ public static void main(String[] args) { try (Connection con = ds.getConnection(); Statement stmt = con.createStatement();) { dropAndCreateTable(stmt); + // TODO: Implement Sample code String geoWKT = "POINT(3 40 5 6)"; Geometry geomWKT = Geometry.STGeomFromText(geoWKT, 0); Geography geogWKT = Geography.STGeomFromText(geoWKT, 4326); diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyColumnMappingTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyColumnMappingTest.java index e6b96f1833..0da47193c0 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyColumnMappingTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyColumnMappingTest.java @@ -5,7 +5,6 @@ package com.microsoft.sqlserver.jdbc.bulkCopy; import static org.junit.jupiter.api.Assertions.fail; -import static org.junit.jupiter.api.Assertions.assertTrue; import java.sql.ResultSet; import java.sql.ResultSetMetaData; @@ -22,7 +21,6 @@ import com.microsoft.sqlserver.jdbc.ComparisonUtil; import com.microsoft.sqlserver.jdbc.TestResource; -import com.microsoft.sqlserver.jdbc.TestUtils; import com.microsoft.sqlserver.testframework.DBConnection; import com.microsoft.sqlserver.testframework.DBResultSet; import com.microsoft.sqlserver.testframework.DBStatement; @@ -387,10 +385,10 @@ private void validateValuesRepetitiveCM(DBConnection con, DBTable sourceTable, int totalColumns = sourceMeta.getColumnCount(); // verify data from sourceType and resultSet - int numRows = 0; while (srcResultSet.next() && dstResultSet.next()) { - numRows++; for (int i = 1; i <= totalColumns; i++) { + // TODO: check row and column count in both the tables + Object srcValue, dstValue; srcValue = srcResultSet.getObject(i); dstValue = dstResultSet.getObject(i); @@ -405,11 +403,6 @@ private void validateValuesRepetitiveCM(DBConnection con, DBTable sourceTable, } } } - - // verify number of rows and columns - assertTrue(((ResultSet) dstResultSet.product()).getMetaData().getColumnCount() == totalColumns + 1); - assertTrue(sourceTable.getTotalRows() == numRows); - assertTrue(destinationTable.getTotalRows() == numRows); } } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyResultSetCursorTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyResultSetCursorTest.java index 3ed177217e..3ce050a65e 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyResultSetCursorTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyResultSetCursorTest.java @@ -70,7 +70,7 @@ private void serverCursorsTest(int resultSetType, int resultSetConcurrency) thro try (Statement stmt2 = conn.createStatement(resultSetType, resultSetConcurrency); ResultSet rs = stmt2 - .executeQuery("select * from " + AbstractSQLGenerator.escapeIdentifier(srcTable) + " ORDER BY id ASC"); + .executeQuery("select * from " + AbstractSQLGenerator.escapeIdentifier(srcTable)); SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(conn)) { bulkCopy.setDestinationTableName(AbstractSQLGenerator.escapeIdentifier(desTable)); bulkCopy.writeToServer(rs); @@ -96,7 +96,7 @@ public void testSelectMethodSetToCursor() throws SQLException { createTables(stmt); populateSourceTable(); - try (ResultSet rs = stmt.executeQuery("select * from " + AbstractSQLGenerator.escapeIdentifier(srcTable) + " ORDER BY id ASC"); + try (ResultSet rs = stmt.executeQuery("select * from " + AbstractSQLGenerator.escapeIdentifier(srcTable)); SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(conn)) { bulkCopy.setDestinationTableName(AbstractSQLGenerator.escapeIdentifier(desTable)); @@ -122,7 +122,7 @@ public void testMultiplePreparedStatementAndResultSet() throws SQLException { try (Statement stmt1 = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); ResultSet rs = stmt1 - .executeQuery("select * from " + AbstractSQLGenerator.escapeIdentifier(srcTable) + " ORDER BY id ASC")) { + .executeQuery("select * from " + AbstractSQLGenerator.escapeIdentifier(srcTable))) { try (SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(conn)) { bulkCopy.setDestinationTableName(AbstractSQLGenerator.escapeIdentifier(desTable)); bulkCopy.writeToServer(rs); @@ -158,7 +158,7 @@ public void testMultiplePreparedStatementAndResultSet() throws SQLException { try (Statement stmt2 = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); ResultSet rs2 = stmt2 - .executeQuery("select * from " + AbstractSQLGenerator.escapeIdentifier(srcTable) + " ORDER BY id ASC"); + .executeQuery("select * from " + AbstractSQLGenerator.escapeIdentifier(srcTable)); SQLServerBulkCopy bulkCopy3 = new SQLServerBulkCopy(conn)) { bulkCopy3.setDestinationTableName(AbstractSQLGenerator.escapeIdentifier(desTable)); bulkCopy3.writeToServer(rs2); @@ -170,20 +170,20 @@ public void testMultiplePreparedStatementAndResultSet() throws SQLException { private static void verifyDestinationTableData(int expectedNumberOfRows) throws SQLException { try (Connection conn = DriverManager.getConnection(connectionString); ResultSet rs = conn.createStatement() - .executeQuery("select * from " + AbstractSQLGenerator.escapeIdentifier(desTable) + " ORDER BY id ASC")) { + .executeQuery("select * from " + AbstractSQLGenerator.escapeIdentifier(desTable))) { int expectedArrayLength = expectedBigDecimals.length; int i = 0; while (rs.next()) { - assertTrue(rs.getString(2).equals(expectedBigDecimalStrings[i % expectedArrayLength]), "Expected Value:" - + expectedBigDecimalStrings[i % expectedArrayLength] + ", Actual Value: " + rs.getString(2)); - assertTrue(rs.getString(3).trim().equals(expectedStrings[i % expectedArrayLength]), "Expected Value:" - + expectedStrings[i % expectedArrayLength] + ", Actual Value: " + rs.getString(3)); - assertTrue(rs.getString(4).equals(expectedTimestampStrings[i % expectedArrayLength]), "Expected Value:" - + expectedTimestampStrings[i % expectedArrayLength] + ", Actual Value: " + rs.getString(4)); - assertTrue(rs.getString(5).trim().equals(expectedStrings[i % expectedArrayLength]), "Expected Value:" - + expectedStrings[i % expectedArrayLength] + ", Actual Value: " + rs.getString(5)); + assertTrue(rs.getString(1).equals(expectedBigDecimalStrings[i % expectedArrayLength]), "Expected Value:" + + expectedBigDecimalStrings[i % expectedArrayLength] + ", Actual Value: " + rs.getString(1)); + assertTrue(rs.getString(2).trim().equals(expectedStrings[i % expectedArrayLength]), "Expected Value:" + + expectedStrings[i % expectedArrayLength] + ", Actual Value: " + rs.getString(2)); + assertTrue(rs.getString(3).equals(expectedTimestampStrings[i % expectedArrayLength]), "Expected Value:" + + expectedTimestampStrings[i % expectedArrayLength] + ", Actual Value: " + rs.getString(3)); + assertTrue(rs.getString(4).trim().equals(expectedStrings[i % expectedArrayLength]), "Expected Value:" + + expectedStrings[i % expectedArrayLength] + ", Actual Value: " + rs.getString(4)); i++; } @@ -196,7 +196,8 @@ private static void populateSourceTable() throws SQLException { Calendar calGMT = Calendar.getInstance(TimeZone.getTimeZone("GMT")); try (Connection conn = DriverManager.getConnection(connectionString); - SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) conn.prepareStatement(sql)) { + SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) conn.prepareStatement(sql)) { + for (int i = 0; i < expectedBigDecimals.length; i++) { pstmt.setBigDecimal(1, expectedBigDecimals[i]); pstmt.setString(2, expectedStrings[i]); @@ -218,10 +219,10 @@ private static void dropTables(Statement stmt) throws SQLException { private static void createTables(Statement stmt) throws SQLException { String sql = "create table " + AbstractSQLGenerator.escapeIdentifier(srcTable) - + " (id INT NOT NULL IDENTITY PRIMARY KEY, c1 decimal(10,5) null, c2 nchar(50) null, c3 datetime2(7) null, c4 char(7000));"; + + " (c1 decimal(10,5) null, c2 nchar(50) null, c3 datetime2(7) null, c4 char(7000));"; stmt.execute(sql); sql = "create table " + AbstractSQLGenerator.escapeIdentifier(desTable) - + " (id INT NOT NULL IDENTITY PRIMARY KEY, c1 decimal(10,5) null, c2 nchar(50) null, c3 datetime2(7) null, c4 char(7000));"; + + " (c1 decimal(10,5) null, c2 nchar(50) null, c3 datetime2(7) null, c4 char(7000));"; stmt.execute(sql); } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyTestUtil.java b/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyTestUtil.java index 8a942a64ac..73e77c885f 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyTestUtil.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyTestUtil.java @@ -4,7 +4,6 @@ */ package com.microsoft.sqlserver.jdbc.bulkCopy; -import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; import java.sql.Connection; @@ -281,10 +280,10 @@ static void validateValues(DBConnection con, DBTable sourceTable, DBTable destin int totalColumns = destMeta.getColumnCount(); // verify data from sourceType and resultSet - int numRows = 0; while (srcResultSet.next() && dstResultSet.next()) { - numRows++; for (int i = 1; i <= totalColumns; i++) { + // TODO: check row and column count in both the tables + Object srcValue, dstValue; srcValue = srcResultSet.getObject(i); dstValue = dstResultSet.getObject(i); @@ -292,14 +291,6 @@ static void validateValues(DBConnection con, DBTable sourceTable, DBTable destin ComparisonUtil.compareExpectedAndActual(destMeta.getColumnType(i), srcValue, dstValue); } } - - // verify number of rows and columns - assertTrue(((ResultSet) srcResultSet.product()).getMetaData().getColumnCount() == totalColumns); - - if (numRows > 0) { - assertTrue(sourceTable.getTotalRows() == numRows); - assertTrue(destinationTable.getTotalRows() == numRows); - } } } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyTimeoutTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyTimeoutTest.java index 76688ca9e0..c3497adf8f 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyTimeoutTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyTimeoutTest.java @@ -47,13 +47,13 @@ public void testZeroTimeOut() throws SQLException { */ @Test @DisplayName("BulkCopy:test negative timeout") - public void testNegativeTimeOut() { + public void testNegativeTimeOut() throws SQLException { assertThrows(SQLException.class, new org.junit.jupiter.api.function.Executable() { @Override public void execute() throws SQLException { testBulkCopyWithTimeout(-1); } - }, "The timeout argument cannot be negative."); + }); } private void testBulkCopyWithTimeout(int timeout) throws SQLException { diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/databasemetadata/DatabaseMetaDataTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/databasemetadata/DatabaseMetaDataTest.java index 3a4a054e28..07485bb8aa 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/databasemetadata/DatabaseMetaDataTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/databasemetadata/DatabaseMetaDataTest.java @@ -419,7 +419,9 @@ public void testGetColumnPrivileges() throws SQLException { } /** - * Testing {@link SQLServerDatabaseMetaData#getFunctions(String, String, String)} with sending wrong catalog. + * TODO: Check JDBC Specs: Can we have any tables/functions without category? + * + * Testing {@link SQLServerDatabaseMetaData#getFunctions(String, String, String)} with sending wrong category. * * @throws SQLException */ @@ -428,7 +430,9 @@ public void testGetFunctionsWithWrongParams() throws SQLException { try (Connection conn = DriverManager.getConnection(connectionString)) { conn.getMetaData().getFunctions("", null, "xp_%"); assertTrue(false, TestResource.getResource("R_noSchemaShouldFail")); - } catch (Exception ae) {} + } catch (Exception ae) { + + } } /** diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/datatypes/BulkCopyWithSqlVariantTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/datatypes/BulkCopyWithSqlVariantTest.java index b6345e4381..6814627153 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/datatypes/BulkCopyWithSqlVariantTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/datatypes/BulkCopyWithSqlVariantTest.java @@ -609,7 +609,7 @@ public void bulkCopyTestVarbinary8000() throws SQLException { * * @throws SQLException */ - @Test + @Test // TODO: check bitnull public void bulkCopyTestBitNull() throws SQLException { try (Connection con = DriverManager.getConnection(connectionString); Statement stmt = con.createStatement()) { diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/datatypes/SQLServerSpatialDatatypeTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/datatypes/SQLServerSpatialDatatypeTest.java index cce188515e..6a95f29c9e 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/datatypes/SQLServerSpatialDatatypeTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/datatypes/SQLServerSpatialDatatypeTest.java @@ -4,7 +4,6 @@ */ package com.microsoft.sqlserver.jdbc.datatypes; -import static org.junit.Assert.fail; import static org.junit.jupiter.api.Assertions.assertEquals; import java.io.IOException; @@ -813,7 +812,7 @@ public void testPoint() throws SQLException { String geoWKT = "POINT(1 2)"; Geometry geomWKT = Geometry.point(1, 2, 0); - Geography geogWKT = Geography.point(2, 1, 4326); + Geography geogWKT = Geography.point(1, 2, 4326); try (Connection con = (SQLServerConnection) DriverManager.getConnection(connectionString); Statement stmt = con.createStatement()) { @@ -969,8 +968,8 @@ public void testGetXGetY() throws SQLException { x = geog.getLatitude(); y = geog.getLongitude(); - assertEquals(x, 2); - assertEquals(y, 1); + assertEquals(x, 1); + assertEquals(y, 2); } @Test @@ -1042,48 +1041,6 @@ public void testNull() throws SQLException { } } } - - @Test - public void testWrongtype() throws SQLException { - beforeEachSetup(); - - Geometry geomWKT = Geometry.point(1, 2, 0); - Geography geogWKT = Geography.point(2, 1, 4326); - - try (Connection con = (SQLServerConnection) DriverManager.getConnection(connectionString); - Statement stmt = con.createStatement()) { - - try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) con.prepareStatement( - "insert into " + AbstractSQLGenerator.escapeIdentifier(geomTableName) + " values (?)");) { - pstmt.setGeometry(1, geomWKT); - pstmt.execute(); - - try { - SQLServerResultSet rs = (SQLServerResultSet) stmt.executeQuery("select * from " + AbstractSQLGenerator.escapeIdentifier(geomTableName)); - rs.next(); - rs.getGeography(1); // should fail - fail(); - } catch (SQLServerException e) { - assertEquals(e.getMessage(), "The conversion from GEOMETRY to GEOGRAPHY is unsupported."); - } - } - - try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) con.prepareStatement( - "insert into " + AbstractSQLGenerator.escapeIdentifier(geogTableName) + " values (?)");) { - pstmt.setGeography(1, geogWKT); - pstmt.execute(); - - try { - SQLServerResultSet rs = (SQLServerResultSet) stmt.executeQuery("select * from " + AbstractSQLGenerator.escapeIdentifier(geogTableName)); - rs.next(); - rs.getGeometry(1); // should fail - fail(); - } catch (SQLServerException e) { - assertEquals(e.getMessage(), "The conversion from GEOGRAPHY to GEOMETRY is unsupported."); - } - } - } - } private void beforeEachSetup() throws SQLException { try (Connection con = (SQLServerConnection) DriverManager.getConnection(connectionString); diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/datatypes/TVPWithSqlVariantTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/datatypes/TVPWithSqlVariantTest.java index 307bbdcdf9..d58c5dd15a 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/datatypes/TVPWithSqlVariantTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/datatypes/TVPWithSqlVariantTest.java @@ -353,10 +353,8 @@ public void testDateTime() throws SQLException { * * @throws SQLException * @throws SQLTimeoutException - * https://msdn.microsoft.com/en-ca/library/dd303302.aspx?f=255&MSPPError=-2147217396 - * Data types cannot be NULL when inside a sql_variant */ - @Test + @Test // TODO We need to check this later. Right now sending null with TVP is not supported public void testNull() throws SQLException { tvp = new SQLServerDataTable(); tvp.addColumnMetadata("c1", microsoft.sql.Types.SQL_VARIANT); diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/fips/FipsEnvTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/fips/FipsEnvTest.java index 32e40b5077..46b593730a 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/fips/FipsEnvTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/fips/FipsEnvTest.java @@ -55,13 +55,16 @@ public static void populateProperties() { currentJVM = IBM_JVM; } + // TODO: Need to check this. if (p.getProperty("java.vendor").startsWith("SAP")) { currentJVM = SAP_JVM; } } /** - * Test FIPS in Oracle Env. + * After stabilizing parameterized test case TODO: Enable FIPS can be done in two ways. + *
  • JVM Level - Done. + *
  • Program Level - Not Done. We need to test both on different environments. * * @since 6.1.2 */ @@ -88,7 +91,7 @@ public void testFIPSOnOracle() throws Exception { } /** - * Test FIPS in IBM Env. If JVM is not IBM test will not fail. It will simply skipped. + * It will test FIPS on IBM Env. If JVM is not IBM test will not fail. It will simply skipped. * * @since 6.1.2 */ diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/timeouts/TimeoutTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/timeouts/TimeoutTest.java deleted file mode 100644 index a61e097b17..0000000000 --- a/src/test/java/com/microsoft/sqlserver/jdbc/timeouts/TimeoutTest.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * 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.timeouts; - -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.PreparedStatement; -import java.sql.SQLException; -import java.sql.SQLTimeoutException; - -import org.junit.Assert; -import org.junit.jupiter.api.Test; -import org.junit.platform.runner.JUnitPlatform; -import org.junit.runner.RunWith; - -import com.microsoft.sqlserver.testframework.AbstractTest; - - -@RunWith(JUnitPlatform.class) -public class TimeoutTest extends AbstractTest { - @Test - public void testBasicQueryTimeout() { - boolean exceptionThrown = false; - try { - // wait 1 minute and timeout after 10 seconds - Assert.assertTrue("Select succeeded", runQuery("WAITFOR DELAY '00:01'", 10)); - } catch (SQLException e) { - exceptionThrown = true; - Assert.assertTrue("Timeout exception not thrown", e.getClass().equals(SQLTimeoutException.class)); - } - Assert.assertTrue("A SQLTimeoutException was expected", exceptionThrown); - } - - @Test - public void testQueryTimeoutValid() { - boolean exceptionThrown = false; - int timeoutInSeconds = 10; - long start = System.currentTimeMillis(); - try { - // wait 1 minute and timeout after 10 seconds - Assert.assertTrue("Select succeeded", runQuery("WAITFOR DELAY '00:01'", timeoutInSeconds)); - } catch (SQLException e) { - int secondsElapsed = (int) ((System.currentTimeMillis() - start) / 1000); - Assert.assertTrue("Query did not timeout expected, elapsedTime=" + secondsElapsed, - secondsElapsed >= timeoutInSeconds); - exceptionThrown = true; - Assert.assertTrue("Timeout exception not thrown", e.getClass().equals(SQLTimeoutException.class)); - } - Assert.assertTrue("A SQLTimeoutException was expected", exceptionThrown); - } - - private boolean runQuery(String query, int timeout) throws SQLException { - try (Connection con = DriverManager.getConnection(connectionString); - PreparedStatement preparedStatement = con.prepareStatement(query)) { - // set provided timeout - preparedStatement.setQueryTimeout(timeout); - return preparedStatement.execute(); - } - } -} diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/tvp/TVPAllTypesTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/tvp/TVPAllTypesTest.java index d5c7e2f9cf..22408852f0 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/tvp/TVPAllTypesTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/tvp/TVPAllTypesTest.java @@ -33,9 +33,12 @@ @RunWith(JUnitPlatform.class) public class TVPAllTypesTest extends AbstractTest { + private static Connection conn = null; + static Statement stmt = null; private static String tvpName; private static String procedureName; + private static DBTable tableSrc = null; private static DBTable tableDest = null; @@ -56,36 +59,18 @@ public void testTVPResultSet() throws SQLException { private void testTVPResultSet(boolean setSelectMethod, Integer resultSetType, Integer resultSetConcurrency) throws SQLException { - - String connString; - Statement stmt = null; - - if (setSelectMethod) { - connString = connectionString + ";selectMethod=cursor;"; - } else { - connString = connectionString; - } - - try (Connection conn = DriverManager.getConnection(connString)) { - if (null != resultSetType && null != resultSetConcurrency) { - stmt = conn.createStatement(resultSetType, resultSetConcurrency); - } else { - stmt = conn.createStatement(); - } - - setupVariation(setSelectMethod, stmt); - try (ResultSet rs = stmt.executeQuery("select * from " + tableSrc.getEscapedTableName()); - SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) conn.prepareStatement( - "INSERT INTO " + tableDest.getEscapedTableName() + " select * from ? ;")) { - pstmt.setStructured(1, tvpName, rs); - pstmt.execute(); - ComparisonUtil.compareSrcTableAndDestTableIgnoreRowOrder(new DBConnection(connectionString), tableSrc, - tableDest); - } catch (Exception e) { - fail(TestResource.getResource("R_unexpectedErrorMessage") + e.toString()); - } finally { - stmt.close(); - } + setupVariation(setSelectMethod, resultSetType, resultSetConcurrency); + + try (ResultSet rs = stmt.executeQuery("select * from " + tableSrc.getEscapedTableName()); + SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) conn + .prepareStatement("INSERT INTO " + tableDest.getEscapedTableName() + " select * from ? ;")) { + pstmt.setStructured(1, tvpName, rs); + pstmt.execute(); + + ComparisonUtil.compareSrcTableAndDestTableIgnoreRowOrder(new DBConnection(connectionString), tableSrc, + tableDest); + } catch (Exception e) { + fail(TestResource.getResource("R_unexpectedErrorMessage") + e.toString()); } finally { terminateVariation(); } @@ -108,33 +93,15 @@ public void testTVPStoredProcedureResultSet() throws SQLException { private void testTVPStoredProcedureResultSet(boolean setSelectMethod, Integer resultSetType, Integer resultSetConcurrency) throws SQLException { - String connString; - Statement stmt = null; - - if (setSelectMethod) { - connString = connectionString + ";selectMethod=cursor;"; - } else { - connString = connectionString; - } - - try (Connection conn = DriverManager.getConnection(connString)) { - if (null != resultSetType && null != resultSetConcurrency) { - stmt = conn.createStatement(resultSetType, resultSetConcurrency); - } else { - stmt = conn.createStatement(); - } - - setupVariation(setSelectMethod, stmt); - try (ResultSet rs = stmt.executeQuery("select * from " + tableSrc.getEscapedTableName()); - SQLServerCallableStatement Cstmt = (SQLServerCallableStatement) conn - .prepareCall("{call " + AbstractSQLGenerator.escapeIdentifier(procedureName) + "(?)}")) { - Cstmt.setStructured(1, tvpName, rs); - Cstmt.execute(); - ComparisonUtil.compareSrcTableAndDestTableIgnoreRowOrder(new DBConnection(connectionString), tableSrc, - tableDest); - } finally { - stmt.close(); - } + setupVariation(setSelectMethod, resultSetType, resultSetConcurrency); + try (ResultSet rs = stmt.executeQuery("select * from " + tableSrc.getEscapedTableName()); + SQLServerCallableStatement Cstmt = (SQLServerCallableStatement) conn + .prepareCall("{call " + AbstractSQLGenerator.escapeIdentifier(procedureName) + "(?)}")) { + Cstmt.setStructured(1, tvpName, rs); + Cstmt.execute(); + + ComparisonUtil.compareSrcTableAndDestTableIgnoreRowOrder(new DBConnection(connectionString), tableSrc, + tableDest); } finally { terminateVariation(); } @@ -147,35 +114,33 @@ private void testTVPStoredProcedureResultSet(boolean setSelectMethod, Integer re */ @Test public void testTVPDataTable() throws SQLException { + setupVariation(false, null, null); + + SQLServerDataTable dt = new SQLServerDataTable(); + + int numberOfColumns = tableDest.getColumns().size(); + Object[] values = new Object[numberOfColumns]; + for (int i = 0; i < numberOfColumns; i++) { + SqlType sqlType = tableDest.getColumns().get(i).getSqlType(); + dt.addColumnMetadata(tableDest.getColumnName(i), sqlType.getJdbctype().getVendorTypeNumber()); + values[i] = sqlType.createdata(); + } - try (Connection conn = DriverManager.getConnection(connectionString); Statement stmt = conn.createStatement()) { - setupVariation(false, stmt); - SQLServerDataTable dt = new SQLServerDataTable(); - int numberOfColumns = tableDest.getColumns().size(); - Object[] values = new Object[numberOfColumns]; - - for (int i = 0; i < numberOfColumns; i++) { - SqlType sqlType = tableDest.getColumns().get(i).getSqlType(); - dt.addColumnMetadata(tableDest.getColumnName(i), sqlType.getJdbctype().getVendorTypeNumber()); - values[i] = sqlType.createdata(); - } - - int numberOfRows = 10; - for (int i = 0; i < numberOfRows; i++) { - dt.addRow(values); - } - - try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) conn - .prepareStatement("INSERT INTO " + tableDest.getEscapedTableName() + " select * from ? ;")) { - pstmt.setStructured(1, tvpName, dt); - pstmt.execute(); - } + int numberOfRows = 10; + for (int i = 0; i < numberOfRows; i++) { + dt.addRow(values); + } + + try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) connection + .prepareStatement("INSERT INTO " + tableDest.getEscapedTableName() + " select * from ? ;")) { + pstmt.setStructured(1, tvpName, dt); + pstmt.execute(); } finally { terminateVariation(); } } - private static void createProcedure(String procedureName, String destTable, Statement stmt) throws SQLException { + private static void createPreocedure(String procedureName, String destTable) throws SQLException { String sql = "CREATE PROCEDURE " + AbstractSQLGenerator.escapeIdentifier(procedureName) + " @InputData " + AbstractSQLGenerator.escapeIdentifier(tvpName) + " READONLY " + " AS " + " BEGIN " + " INSERT INTO " + destTable + " SELECT * FROM @InputData" + " END"; @@ -183,17 +148,30 @@ private static void createProcedure(String procedureName, String destTable, Stat stmt.execute(sql); } - private static void createTVPS(String tvpName, String TVPDefinition, Statement stmt) throws SQLException { + private static void createTVPS(String tvpName, String TVPDefinition) throws SQLException { String TVPCreateCmd = "CREATE TYPE " + AbstractSQLGenerator.escapeIdentifier(tvpName) + " as table (" + TVPDefinition + ");"; stmt.executeUpdate(TVPCreateCmd); } - private void setupVariation(boolean setSelectMethod, Statement stmt) throws SQLException { + private void setupVariation(boolean setSelectMethod, Integer resultSetType, + Integer resultSetConcurrency) throws SQLException { tvpName = RandomUtil.getIdentifier("TVP"); procedureName = RandomUtil.getIdentifier("TVP"); + if (setSelectMethod) { + conn = DriverManager.getConnection(connectionString + ";selectMethod=cursor;"); + } else { + conn = DriverManager.getConnection(connectionString); + } + + if (null != resultSetType || null != resultSetConcurrency) { + stmt = conn.createStatement(resultSetType, resultSetConcurrency); + } else { + stmt = conn.createStatement(); + } + TestUtils.dropProcedureIfExists(AbstractSQLGenerator.escapeIdentifier(procedureName), stmt); TestUtils.dropTableIfExists(AbstractSQLGenerator.escapeIdentifier(tvpName), stmt); @@ -206,19 +184,24 @@ private void setupVariation(boolean setSelectMethod, Statement stmt) throws SQLE dbStmt.createTable(tableSrc); dbStmt.createTable(tableDest); - createTVPS(tvpName, tableSrc.getDefinitionOfColumns(), stmt); - createProcedure(procedureName, tableDest.getEscapedTableName(), stmt); + createTVPS(tvpName, tableSrc.getDefinitionOfColumns()); + createPreocedure(procedureName, tableDest.getEscapedTableName()); dbStmt.populateTable(tableSrc); } } private void terminateVariation() throws SQLException { - try (Connection conn = DriverManager.getConnection(connectionString); Statement stmt = conn.createStatement()) { - TestUtils.dropProcedureIfExists(AbstractSQLGenerator.escapeIdentifier(procedureName), stmt); - TestUtils.dropTableIfExists(tableSrc.getEscapedTableName(), stmt); - TestUtils.dropTableIfExists(tableDest.getEscapedTableName(), stmt); - TestUtils.dropTableIfExists(AbstractSQLGenerator.escapeIdentifier(tvpName), stmt); + TestUtils.dropProcedureIfExists(AbstractSQLGenerator.escapeIdentifier(procedureName), stmt); + TestUtils.dropTableIfExists(tableSrc.getEscapedTableName(), stmt); + TestUtils.dropTableIfExists(tableDest.getEscapedTableName(), stmt); + TestUtils.dropTableIfExists(AbstractSQLGenerator.escapeIdentifier(tvpName), stmt); + + if (null != stmt) { + stmt.close(); + } + if (null != conn) { + conn.close(); } } } diff --git a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlFloat.java b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlFloat.java index cdf227dfd7..f1881406f2 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlFloat.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlFloat.java @@ -27,9 +27,10 @@ public SqlFloat() { public Object createdata() { // for float in SQL Server, any precision <=24 is considered as real so the value must be within // SqlTypeValue.REAL.minValue/maxValue - if (precision > 24) { - return ThreadLocalRandom.current().nextDouble(((Double) minvalue), ((Double) maxvalue)); - } else { + if (precision > 24) + return Double.longBitsToDouble(ThreadLocalRandom.current().nextLong(((Double) minvalue).longValue(), + ((Double) maxvalue).longValue())); + else { return ThreadLocalRandom.current().nextDouble((Float) SqlTypeValue.REAL.minValue, (Float) SqlTypeValue.REAL.maxValue); }