Coder Social home page Coder Social logo

microsoft / mssql-jdbc Goto Github PK

View Code? Open in Web Editor NEW
1.0K 75.0 418.0 16.22 MB

The Microsoft JDBC Driver for SQL Server is a Type 4 JDBC driver that provides database connectivity with SQL Server through the standard JDBC application program interfaces (APIs).

License: MIT License

Java 100.00%

mssql-jdbc's Introduction

GitHub license Maven Central Javadocs Gitter

Microsoft JDBC Driver for SQL Server

Welcome to the Microsoft JDBC Driver for SQL Server project!

The Microsoft JDBC Driver for SQL Server is a Type 4 JDBC driver that provides database connectivity through the standard JDBC application program interfaces (APIs) available in the Java Platform, Enterprise Editions. The Driver provides access to Microsoft SQL Server and Azure SQL Database from any Java application, application server, or Java-enabled applet.

Releases can be found on the GitHub Releases page, in the Microsoft JDBC Documentation, or via Maven. Starting from preview release 12.1.0, each release contains two versions of the driver. One for use with Java 8 (jre8), and one for use with version Java 11 and above (jre11).

We hope you enjoy using the Microsoft JDBC Driver for SQL Server.

Microsoft JDBC driver for SQL Server Team

Take our survey

Let us know how you think we're doing.

Status of Most Recent Builds

Azure Pipelines (Windows) Azure Pipelines (Linux) Azure Pipelines (MacOS)
Build Status Build Status Build Status

Announcements

What's coming next? We will look into adding a more comprehensive set of tests, improving our javadocs, and start developing the next set of features.

Get Started

Getting started with SQL Server and Java

Build

Prerequisites

  • Java 11+
  • Maven 3.5.0+
  • An instance of SQL Server or Azure SQL Database that you can connect to.

Build the JAR files

Maven builds automatically trigger a set of verification tests to run. For these tests to pass, you will first need to add an environment variable in your system called mssql_jdbc_test_connection_properties to provide the correct connection properties for your SQL Server or Azure SQL Database instance.

To build the jar files, you must use minimum version of Java 11 with Maven. You may choose to build JDBC 4.3 compliant jar file (for use with JRE 11 or newer JRE versions) and/or a JDBC 4.2 compliant jar file (for use with JRE 8).

  • Maven:

    1. If you have not already done so, add the environment variable mssql_jdbc_test_connection_properties in your system with the connection properties for your SQL Server or SQL DB instance.
    2. Run one of the commands below to build a JRE 11 and newer versions compatible jar or JRE 8 compatible jar in the \target directory.
      • Run mvn install -Pjre22. This creates JRE 22 compatible jar in \target directory which is JDBC 4.3 compliant (Build with JDK 22).
      • Run mvn install -Pjre21. This creates JRE 21 compatible jar in \target directory which is JDBC 4.3 compliant (Build with JDK 21+).
      • Run mvn install -Pjre17. This creates JRE 17 compatible jar in \target directory which is JDBC 4.3 compliant (Build with JDK 17+).
      • Run mvn install -Pjre11. This creates JRE 11 compatible jar in \target directory which is JDBC 4.3 compliant (Build with JDK 11+).
      • Run mvn install -Pjre8. This creates JRE 8 compatible jar in \target directory which is JDBC 4.2 compliant (Build with JDK 11+).
  • Gradle:

    1. If you have not already done so, add the environment variable mssql_jdbc_test_connection_properties in your system with the connection properties for your SQL Server or SQL DB instance.
    2. Run one of the commands below to build a JRE 11 and newer versions compatible jar or JRE 8 compatible jar in the \build\libs directory.
      • Run gradle build -PbuildProfile=jre22. This creates JRE 22 compatible jar in \build\libs directory which is JDBC 4.3 compliant (Build with JDK 22).
      • Run gradle build -PbuildProfile=jre21. This creates JRE 21 compatible jar in \build\libs directory which is JDBC 4.3 compliant (Build with JDK 21+).
      • Run gradle build -PbuildProfile=jre17. This creates JRE 17 compatible jar in \build\libs directory which is JDBC 4.3 compliant (Build with JDK 17+).
      • Run gradle build -PbuildProfile=jre11. This creates JRE 11 compatible jar in \build\libs directory which is JDBC 4.3 compliant (Build with JDK 11+).
      • Run gradle build -PbuildProfile=jre8. This creates JRE 8 compatible jar in \build\libs directory which is JDBC 4.2 compliant (Build with JDK 11+).

Resources

Documentation

API reference documentation is available in Javadocs.

This driver is documented on Microsoft Docs.

Sample Code

For samples, please see the src\sample directory.

Download the DLLs

For some features (e.g. Integrated Authentication and Distributed Transactions), you may need to use the sqljdbc_xa and mssql-jdbc_auth-<version>.<arch> DLLs. They can be found in the package that can be downloaded from Microsoft. mssql-jdbc_auth-<version>.<arch> can also be downloaded from Maven.

Download the driver

Don't want to compile anything?

We're now on the Maven Central Repository. Add the following to your POM file to get the most stable release:

<dependency>
	<groupId>com.microsoft.sqlserver</groupId>
	<artifactId>mssql-jdbc</artifactId>
	<version>12.6.0.jre11</version>
</dependency>

The driver can be downloaded from Microsoft. For driver version 12.1.0 and greater, please use the jre11 version when using Java 11 or greater, and the jre8 version when using Java 8.

To get the latest version of the driver, add the following to your POM file:

<dependency>
	<groupId>com.microsoft.sqlserver</groupId>
	<artifactId>mssql-jdbc</artifactId>
	<version>12.6.0.jre11</version>
</dependency>

Using driver as Java Module

Starting from version 7.0.0, the driver Jars (jre10 and above) will expose 'Automatic-Module' as 'com.microsoft.sqlserver.jdbc'. The supporting Jar can now be added to ModulePath to access this module.

Dependencies

This project has following dependencies:

Compile Time:

  • com.azure:azure-security-keyvault-keys : Microsoft Azure Client Library For KeyVault Keys (optional)
  • com.azure:azure-identity : Microsoft Azure Client Library For Identity (optional)
  • org.bouncycastle:bcprov-jdk18on : Bouncy Castle Provider for Always Encrypted with secure enclaves feature with JAVA 8 only (optional)
  • com.google.code.gson:gson : Gson for Always Encrypted with secure enclaves feature (optional)

Test Time:

  • junit:jar : For Unit Test cases.

Dependency Tree

One can see all dependencies including Transitive Dependency by executing following command.

mvn dependency:tree

Azure Key Vault and Azure Active Directory Authentication Dependencies

Projects that require either of the two features need to explicitly declare the dependency in their pom file.

For Example: If you are using Azure Active Directory Authentication feature then you need to declare the azure-identity dependency in your project's POM file. Please see the following snippet:

<dependency>
	<groupId>com.microsoft.sqlserver</groupId>
	<artifactId>mssql-jdbc</artifactId>
	<version>12.6.0.jre11</version>
	<scope>compile</scope>
</dependency>

<dependency>
	<groupId>com.azure</groupId>
	<artifactId>azure-identity</artifactId>
	<version>1.3.3</version>
</dependency>

For Example: If you are using Azure Key Vault feature then you need to declare the azure-identity and azure-security-keyvault-keys dependencies in your project's POM file. Please see the following snippet:

<dependency>
	<groupId>com.microsoft.sqlserver</groupId>
	<artifactId>mssql-jdbc</artifactId>
	<version>12.6.0.jre11</version>
	<scope>compile</scope>
</dependency>

<dependency>
	<groupId>com.azure</groupId>
	<artifactId>azure-identity</artifactId>
	<version>1.3.3</version>
</dependency>

<dependency>
	<groupId>com.azure</groupId>
	<artifactId>azure-security-keyvault-keys</artifactId>
	<version>4.2.8</version>
</dependency>

Please note as of the v6.2.2, the way to construct a SQLServerColumnEncryptionAzureKeyVaultProvider object has changed. Please refer to this Wiki page for more information.

'useFmtOnly' connection property Dependencies

When setting 'useFmtOnly' property to 'true' for establishing a connection or creating a prepared statement, antlr-runtime dependency is required to be added in your project's POM file. Please see the following snippet:

<dependency>
	<groupId>com.microsoft.sqlserver</groupId>
	<artifactId>mssql-jdbc</artifactId>
	<version>12.6.0.jre11</version>
</dependency>

<dependency>
	<groupId>org.antlr</groupId>
	<artifactId>antlr4-runtime</artifactId>
	<version>4.9.2</version>
</dependency>

Guidelines for Creating Pull Requests

We love contributions from the community. To help improve the quality of our code, we encourage you to use the mssql-jdbc_formatter.xml formatter provided on all pull requests.

Thank you!

Guidelines for Reporting Issues

We appreciate you taking the time to test the driver, provide feedback and report any issues. It would be extremely helpful if you:

  • Report each issue as a new issue (but check first if it's already been reported)
  • Try to be detailed in your report. Useful information for good bug reports include:
    • What you are seeing and what the expected behavior is
    • Which jar file?
    • Environment details: e.g. Java version, client operating system?
    • Table schema (for some issues the data types make a big difference!)
    • Any other relevant information you want to share
  • Try to include a Java sample demonstrating the isolated problem.

Thank you!

Reporting security issues and security bugs

Security issues and bugs should be reported privately, via email, to the Microsoft Security Response Center (MSRC) [email protected]. You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Further information, including the MSRC PGP key, can be found in the Security TechCenter.

Release roadmap and standards

Our goal is to release regular updates which improve the driver and bring new features to users. Stable, production quality releases happen twice a year, targeting the first and third quarters of the calendar year. They are tested against a comprehensive matrix of supported operating systems, Java versions, and SQL Server versions. Stable releases are accompanied by additional localized packages, which are available on the Microsoft website.

Preview releases happen approximately monthly between stable releases. This gives users an opportunity to try out new features and provide feedback on them before they go into stable releases. Preview releases also include frequent bug fixes for customers to verify without having to wait for a stable release. Preview releases are only available in English. While they are tested, preview releases do not necessarily go through the same rigorous, full test matrix and review process as stable releases.

You can see what is going into a future release by monitoring Milestones in the repository.

Version conventions

Starting with 6.0, stable versions have an even minor version. For example, 6.0, 6.2, 6.4, 7.0, 7.2, 7.4, 8.2, 8.4, 9.2, 9.4, 10.2, 11.2, 12.2, 12.4, 12.6. Preview versions have an odd minor version. For example, 6.1, 6.3, 6.5, 7.1, 7.3, 8.1, 9.1, 10.1, 11.1, 12.1, 12.3, 12.5, and so on.

Contributors

Special thanks to everyone who has contributed to the project.

Up-to-date list of contributors: https://github.com/Microsoft/mssql-jdbc/graphs/contributors

Here are our Top 15 contributors from the community:

  • pierresouchay (Pierre Souchay)
  • marschall (Philippe Marschall)
  • JamieMagee (Jamie Magee)
  • sehrope (Sehrope Sarkuni)
  • gordthompson (Gord Thompson)
  • simon04 (Simon Legner)
  • gstojsic
  • cosmofrit
  • mmimica (Milan Mimica)
  • harawata (Iwao AVE!)
  • rPraml (Roland Praml)
  • laeubi (Christoph Laubrich)
  • worldtiki (Daniel Albuquerque)
  • shayaantx
  • mnhubspot

License

The Microsoft JDBC Driver for SQL Server is licensed under the MIT license. See the LICENSE file for more details.

Code of conduct

This project has adopted the Microsoft Open Source Code of Conduct. For more information see the Code of Conduct FAQ or contact [email protected] with any additional questions or comments.

mssql-jdbc's People

Contributors

afsanehr-zz avatar ajlam avatar cheenamalhotra avatar cosmofrit avatar david-engel avatar dependabot[bot] avatar gordthompson avatar gstojsic avatar harawata avatar jamiemagee avatar jeffery-wasty avatar karinazhou avatar lilgreenbird avatar marschall avatar mmimica avatar nsidhaye avatar peterbae avatar pierresouchay avatar rene-ye avatar rpraml avatar sehrope avatar shayaantx avatar simon04 avatar tkyc avatar tobiassql avatar tonytamwk avatar ulvii avatar v-nisidh avatar veryveryspicy avatar xiangyushawn avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

mssql-jdbc's Issues

Query Cancellation Hangs When Using Multi Subnet Failover

Normally we use the standard Statement.cancel() method to cancel running queries. If it's called on a connection made with multiSubnetFailover=true, it has no effect and both the original Thread executing the Statement and the Thread issuing the cancel() will hang until the statement completes.

This issue been tested and confirmed on the latest stable SQL Server JDBC driver as well as a number of older drivers (prior to the 6.x branch).

See below for a self-contained example of this. Replace the JDBC url with any recent version of SQL Server and flip the boolean multiSubnetFailover property between true/false to see the impact. The sample code issues a dummy WAITFOR statement to simulate a slow query and then tries to cancel it in a separate thread. If multiSubnetFailover is enabled, the cancellation never occurs as the canceler thread blocks waiting to write to the nio Channel (probably trying to write the ATTENTION cancellation packet).

Stack trace for thread: stmt-canceller

java.nio.channels.Channels.writeFully(Channels.java:96)
java.nio.channels.Channels.access$000(Channels.java:61)
java.nio.channels.Channels$1.write(Channels.java:174)
com.microsoft.sqlserver.jdbc.TDSChannel$ProxyOutputStream.writeInternal(IOBuffer.java:1059)
com.microsoft.sqlserver.jdbc.TDSChannel$ProxyOutputStream.write(IOBuffer.java:1051)
sun.security.ssl.OutputRecord.writeBuffer(OutputRecord.java:431)
sun.security.ssl.OutputRecord.write(OutputRecord.java:417)
sun.security.ssl.SSLSocketImpl.writeRecordInternal(SSLSocketImpl.java:876)
sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:847)
sun.security.ssl.AppOutputStream.write(AppOutputStream.java:123)
com.microsoft.sqlserver.jdbc.TDSChannel.write(IOBuffer.java:1887)
com.microsoft.sqlserver.jdbc.TDSWriter.flush(IOBuffer.java:4285)
com.microsoft.sqlserver.jdbc.TDSWriter.writePacket(IOBuffer.java:4186)
com.microsoft.sqlserver.jdbc.TDSWriter.endMessage(IOBuffer.java:3192)
com.microsoft.sqlserver.jdbc.TDSWriter.sendAttention(IOBuffer.java:4164)
com.microsoft.sqlserver.jdbc.TDSCommand.interrupt(IOBuffer.java:7647)
com.microsoft.sqlserver.jdbc.SQLServerStatement.cancel(SQLServerStatement.java:1193)
Main$2.run(Main.java:64)

Stack trace for thread: main

sun.nio.ch.FileDispatcherImpl.read0(Native Method)
sun.nio.ch.SocketDispatcher.read(SocketDispatcher.java:39)
sun.nio.ch.IOUtil.readIntoNativeBuffer(IOUtil.java:223)
sun.nio.ch.IOUtil.read(IOUtil.java:197)
sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:380)
sun.nio.ch.SocketAdaptor$SocketInputStream.read(SocketAdaptor.java:192)
sun.nio.ch.ChannelInputStream.read(ChannelInputStream.java:103)
com.microsoft.sqlserver.jdbc.TDSChannel$ProxyInputStream.readInternal(IOBuffer.java:949)
com.microsoft.sqlserver.jdbc.TDSChannel$ProxyInputStream.read(IOBuffer.java:937)
sun.security.ssl.InputRecord.readFully(InputRecord.java:465)
sun.security.ssl.InputRecord.read(InputRecord.java:503)
sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:973)
sun.security.ssl.SSLSocketImpl.readDataRecord(SSLSocketImpl.java:930)
sun.security.ssl.AppInputStream.read(AppInputStream.java:105)
com.microsoft.sqlserver.jdbc.TDSChannel.read(IOBuffer.java:1871)
com.microsoft.sqlserver.jdbc.TDSReader.readPacket(IOBuffer.java:6602)
com.microsoft.sqlserver.jdbc.TDSCommand.startResponse(IOBuffer.java:7919)
com.microsoft.sqlserver.jdbc.SQLServerStatement.doExecuteStatement(SQLServerStatement.java:879)
com.microsoft.sqlserver.jdbc.SQLServerStatement$StmtExecCmd.doExecute(SQLServerStatement.java:778)
com.microsoft.sqlserver.jdbc.TDSCommand.execute(IOBuffer.java:7465)
com.microsoft.sqlserver.jdbc.SQLServerConnection.executeCommand(SQLServerConnection.java:2271)
com.microsoft.sqlserver.jdbc.SQLServerStatement.executeCommand(SQLServerStatement.java:191)
com.microsoft.sqlserver.jdbc.SQLServerStatement.executeStatement(SQLServerStatement.java:166)
com.microsoft.sqlserver.jdbc.SQLServerStatement.execute(SQLServerStatement.java:751)
Main.main(Main.java:77)

Stepping through a debugger and comparing the stacks with multiSubnetFailover enabled/disabled, we noticed that the underlying SocketInputStream is a different class. When the feature is disabled, it's a java.net.SocketInputStream. When it's enabled it's a SocketAdaptor.SocketInputStream.

If I had to guess, I'd say that whatever the JDK is doing to spoof a Socket interface atop a Channel isn't as concurrent as a true Socket. It's a probably a shared lock acquired by a reader on the channel blocking the writer. These two lines look suspicious as they're both synchronizing on the same object:

https://github.com/openjdk-mirror/jdk/blob/jdk8u/jdk8u/master/src/share/classes/sun/nio/ch/SocketAdaptor.java#L188

https://github.com/openjdk-mirror/jdk/blob/jdk8u/jdk8u/master/src/share/classes/java/nio/channels/Channels.java#L95

While this could be a bug in the JDK, I'm not sure that non-blocking between readers/writers is part of the API contract for Sockets or at least Sockets derived from Channels. As such, this might be something you'd need to have the driver handle. The answer might be to switch to using real Sockets rather than Channels even when multiSubnetFailover is enabled.


Sample Program Reproduce Issue - QueryCancelTest.java

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.time.LocalDateTime;
import java.util.Properties;

public class QueryCancelTest {
  private static final long CANCEL_WAIT_MILLIS = 2000;

  private static void log(String format, Object... args) {
    String timestamp = LocalDateTime.now().toString();
    String threadName = Thread.currentThread().getName();
    System.out.printf(timestamp + " [" + threadName + "] - " + format + "\n", args);
  }

  private static void dumpStackTrace(Thread thread) {
    StringBuilder sb = new StringBuilder();
    sb.append("Stack trace for thread: " + thread.getName() + "\n");
    for (StackTraceElement elem : thread.getStackTrace()) {
      sb.append("    " + elem.toString() + "\n");
    }
    System.err.println(sb.toString());
  }

  private static void sleepQuietly(long millis) {
    try {
      Thread.sleep(millis);
    } catch (InterruptedException e) {
      throw new RuntimeException(e);
    }
  }

  private static void delayPrintStackTrace(final Thread thread) {
    new Thread() {
      public void run() {
        sleepQuietly(2000);
        dumpStackTrace(thread);
      }
    }.start();
  }

  public static void main(String args[]) {
    String host = "db.example.com";
    int port = 1433;
    String databaseName = "test";
    String user = "myuser";
    String password = "mypass";
    boolean multiSubnetFailover = true;

    String url = "jdbc:sqlserver://" + host + ":" + port;
    Properties props = new Properties();
    props.put("databaseName", databaseName);
    props.put("user", user);
    props.put("password", password);
    if (multiSubnetFailover) {
      props.put("multiSubnetFailover", "true");
    }

    try {
      try (Connection conn = DriverManager.getConnection(url, props)) {
        log("Created Connection");
        try (final Statement stmt = conn.createStatement()) {
          log("Created Statement");

          final Thread mainThread = Thread.currentThread();
          final Thread cancellationThread = new Thread() {
            public void run() {
              log("Started");
              try {
                log("Waiting for %s ms for statement to begin", CANCEL_WAIT_MILLIS);
                Thread.sleep(CANCEL_WAIT_MILLIS);
                log("Finished waiting, will attempt to cancel statement");
                delayPrintStackTrace(this);
                delayPrintStackTrace(mainThread);
                log("Before stmt.cancel()");
                stmt.cancel();
                log("After stmt.cancel()");
              } catch (Exception e) {
                e.printStackTrace();
              }
              log("Finished");
            }
          };
          cancellationThread.setName("stmt-canceller");
          cancellationThread.start();

          try {
            log("Before stmt.execute(...)");
            boolean hasResultSet = stmt.execute("WAITFOR DELAY '00:00:15'");
            log("After stmt.execute(...) hasResultSet=%s", hasResultSet);
          } catch (SQLException e) {
            e.printStackTrace();
          }
        }
      }
      log("Finished successfully");
    } catch (Exception e) {
      e.printStackTrace();
      System.exit(1);
    }
    System.exit(0);
  }
}

Reduce driver package footprint?

These are the dependencies I get by including the driver in my project: close to 10Mb of additional bytes:
{{{
[INFO] +- com.microsoft.sqlserver:mssql-jdbc:jar:6.1.0.jre8:compile
[INFO] | - com.microsoft.azure:azure-keyvault:jar:0.9.3:compile
[INFO] | +- com.microsoft.azure:azure-core:jar:0.9.3:compile
[INFO] | | +- com.sun.jersey:jersey-client:jar:1.13:compile
[INFO] | | | - com.sun.jersey:jersey-core:jar:1.13:compile
[INFO] | | - com.sun.jersey:jersey-json:jar:1.13:compile
[INFO] | | +- org.codehaus.jettison:jettison:jar:1.1:compile
[INFO] | | | - stax:stax-api:jar:1.0.1:compile
[INFO] | | +- com.sun.xml.bind:jaxb-impl:jar:2.2.3-1:compile
[INFO] | | | - javax.xml.bind:jaxb-api:jar:2.2.2:compile
[INFO] | | | - javax.xml.stream:stax-api:jar:1.0-2:compile
[INFO] | | +- org.codehaus.jackson:jackson-core-asl:jar:1.9.2:compile
[INFO] | | +- org.codehaus.jackson:jackson-mapper-asl:jar:1.9.2:compile
[INFO] | | +- org.codehaus.jackson:jackson-jaxrs:jar:1.9.2:compile
[INFO] | | - org.codehaus.jackson:jackson-xc:jar:1.9.2:compile
[INFO] | +- org.apache.httpcomponents:httpclient:jar:4.5.2:compile
[INFO] | | - org.apache.httpcomponents:httpcore:jar:4.4.6:compile
[INFO] | +- javax.inject:javax.inject:jar:1:compile
[INFO] | - com.microsoft.azure:adal4j:jar:1.0.0:compile
[INFO] | +- com.nimbusds:oauth2-oidc-sdk:jar:4.5:compile
[INFO] | | +- net.jcip:jcip-annotations:jar:1.0:compile
[INFO] | | +- org.apache.commons:commons-lang3:jar:3.3.1:compile
[INFO] | | +- com.nimbusds:lang-tag:jar:1.4:compile
[INFO] | | - com.nimbusds:nimbus-jose-jwt:jar:3.1.2:compile
[INFO] | | - org.bouncycastle:bcprov-jdk15on:jar:1.51:compile
[INFO] | - com.google.code.gson:gson:jar:2.8.0:compile
}}}

Is there a way to make the azure-keyvault an optional dependency considering that the mssql-jdbc.jar is only 766093 bytes and we are not going to use it with azure keyvault?

Implement PreparedStatement caching for performance

To support modern versions of Hibernate, we need a JDBC 4 driver and we are looking to switch from our existing jtds driver http://jtds.sourceforge.net/ to Microsoftโ€™s JDBC driver. Performance problems prevent us from switching.

When we run a load test simulating our toughest workload, Solarwinds DPA is recording 7 times the cpu/memory wait time, big spikes on SQL compiles / sec and an overall doubling of cpu usage overall. The performance problems occur because the MS driver does not support statement pooling and does not reuse PreparedStatements.

A older comment on your jdbcteam blog summarizes this need very well, I will copy/paste it here:

Brett.Wooldridge
December 1, 2015 at 4:47 pm
Hello JDBC Team,
I am the principal developer of HikariCP (https://github.com/brettwooldridge/HikariCP), the fastest growing connection pool for Java.
We frequently are asked to implement PreparedStatement caching within the pool, but our stance has always been and continues to be that caching belongs in the driver. On behalf of our MS SQL Server users, I would like to request the implementation of PreparedStatement caching.
A survey of the Top 5 databases (https://dzone.com/articles/10-most-popular-db-engines-sql) leaves only SQL Server out without prepared statement caching.
Ironically, SQL Server's JDBC driver has a property, disableStatementPooling, which defaults to *true. Only true is supported currently (setting to false will throw an exception).
It was literally HikariCP's stand against placing responsibility of caching in the pool that prompted PostgreSQL to implement their very excellent solution (pgjdbc/pgjdbc#308).
The PostgreSQL implementation took one developer 3 days from start to finish.
In this new Satya Nadella era, isn't this the time for Microsoft to prove that it can be just as agile as the open source databases? The 6.0 Preview is the perfect chance to introduce this long needed feature.
Regards,
Brett Wooldridge

More from Brett regarding Statement Caching and why it is needed at the driver is on the HikariCP site:
https://github.com/brettwooldridge/HikariCP

Statement Cache
Many connection pools, including Apache DBCP, Vibur, c3p0 and others offer PreparedStatement caching. HikariCP does not. Why?
At the connection pool layer PreparedStatements can only be cached per connection. If your application has 250 commonly executed queries and a pool of 20 connections you are asking your database to hold on to 5000 query execution plans -- and similarly the pool must cache this many PreparedStatements and their related graph of objects.
Most major database JDBC drivers already have a Statement cache that can be configured, including PostgreSQL, Oracle, Derby, MySQL, DB2, and many others. JDBC drivers are in a unique position to exploit database specific features, and nearly all of the caching implementations are capable of sharing execution plans across connections. This means that instead of 5000 statements in memory and associated execution plans, your 250 commonly executed queries result in exactly 250 execution plans in the database. Clever implementations do not even retain PreparedStatement objects in memory at the driver-level but instead merely attach new instances to existing plan IDs.
Using a statement cache at the pooling layer is an anti-pattern, and will negatively impact your application performance compared to driver-provided caches.

I wrote simple PreparedStatement test programs that execute a simple select PreparedStatement on AdventureWorks2014 10k times on a SQL 2016 instance. Jtds completed in 19 seconds, the ms driver in 35 seconds and there was significantly more load placed onto the SQL Server instance. You can see why in a SQL Profiler trace.

Microsoft:

image

The MS driver is constantly preparing and unpreparing a statement on every execution. I used mssql-jdbc-6.1.4.jre7-preview.

jTDS:

image

Jtds prepares things once and then reuses the PreparedStatement.

The source of those tester programs are attached if they are of value to anyone. The postgres driver implemented statement caching a couple years ago and it could be used if you want ideas on how to implement it: pgjdbc/pgjdbc#319

jdbc.zip

Set the jre8 version as default

Currently issuing the command:
mvn clean install
for which most java developers expect that it should build something, issues an ugly build error. This is because a profile must be set in order for the build to succeed. Currently there are two profiles, one for jre8 and one for jre7. Consider making the jre8 default so that the above command builds the jre8 version by default.

Add IOException as a cause of SQLServerException

Hi,
I have one comment for error handling in case of IOException. Is it possible to add the exception (SocketTimeoutException for example) to SQLServerException as a cause? We want to separate database timeouts from the rest of errors from SQL Server i.e. we need cause of SQLServerException. I will be very appreciated if you could implement this.
Thanks,
Andrei

Problem connecting from macOS to SQL Azure

Hello,

When connecting to a SQL Azure database from mac I am getting the error below running the connectURL example.

mvn -q exec:java -Dexec.mainClass=com.sqlsamples.App -P connectURL

Output

com.microsoft.sqlserver.jdbc.SQLServerException: SQL Server did not return a response. The connection has been closed. ClientConnectionId:8de59301-094c-4f5e-bad9-83142d15c249
	at com.microsoft.sqlserver.jdbc.SQLServerConnection.terminate(SQLServerConnection.java:2392)
	at com.microsoft.sqlserver.jdbc.SQLServerConnection.terminate(SQLServerConnection.java:2376)
	at com.microsoft.sqlserver.jdbc.TDSReader.readPacket(IOBuffer.java:6680)
	at com.microsoft.sqlserver.jdbc.TDSCommand.startResponse(IOBuffer.java:7993)
	at com.microsoft.sqlserver.jdbc.TDSCommand.startResponse(IOBuffer.java:7945)
	at com.microsoft.sqlserver.jdbc.SQLServerConnection.sendLogon(SQLServerConnection.java:4375)
	at com.microsoft.sqlserver.jdbc.SQLServerConnection.logon(SQLServerConnection.java:3188)
	at com.microsoft.sqlserver.jdbc.SQLServerConnection.access$100(SQLServerConnection.java:61)
	at com.microsoft.sqlserver.jdbc.SQLServerConnection$LogonCommand.doExecute(SQLServerConnection.java:3151)
	at com.microsoft.sqlserver.jdbc.TDSCommand.execute(IOBuffer.java:7535)
	at com.microsoft.sqlserver.jdbc.SQLServerConnection.executeCommand(SQLServerConnection.java:2438)
	at com.microsoft.sqlserver.jdbc.SQLServerConnection.connectHelper(SQLServerConnection.java:1973)
	at com.microsoft.sqlserver.jdbc.SQLServerConnection.login(SQLServerConnection.java:1616)
	at com.microsoft.sqlserver.jdbc.SQLServerConnection.connectInternal(SQLServerConnection.java:1447)
	at com.microsoft.sqlserver.jdbc.SQLServerConnection.connect(SQLServerConnection.java:788)
	at com.microsoft.sqlserver.jdbc.SQLServerDriver.connect(SQLServerDriver.java:1187)
	at java.sql.DriverManager.getConnection(DriverManager.java:664)
	at java.sql.DriverManager.getConnection(DriverManager.java:270)
	at connectURL.main(connectURL.java:63)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.codehaus.mojo.exec.ExecJavaMojo$1.run(ExecJavaMojo.java:297)
	at java.lang.Thread.run(Thread.java:745)

I am using macOS 10.12.3, JDK 8 Update 121. Same example from Windows is working fine and I can connect with no problems.

I also tried a connection string different with the following format

jdbc:sqlserver://server.database.windows.net;databaseName=database-name;encrypt=true;trustServerCertificate=false;hostNameInCertificate=*.database.windows.net;loginTimeout=30;

I also tried the parameters in different combinations
-Djsse.enableCBCProtection=false
-Djdk.tls.client.protocols=TLSv1

Attached you can find the output when debugging SSL as suggested in a couple of places, but I could not figure out the root of the problem

output.txt

If I try to connect to a SQL Server deployed in the RDS service of AWS everything works as expected

Any help will be appreciated

BigDecimal in TVP can incorrectly cause SQLServerException related to invalid precision or scale

I pulled together some tests which reproduce the behavior I'm encountering. I've been testing using java build 1.8.0_101-b13, mssql-jdbc driver version 6.1.0.jre8 and Microsoft SQL Server 2016 (RTM) - 13.0.1601.5 (X64).

I suspect the issue might be caused by the driver code incorrectly assuming that the precision and scale values of BigDecimal mirror those of the decimal data type in SQL Server, namely the code found here.

Let me know if any additional details would be helpful.

Remove obsolete methods from DriverJDBCVersion

If I understand correctly the current codebase supports jdbc 4.1 and jdbc 4.2 specs. This means that there is no need to check if the driver supports jdbc 4.1 and lower since 4.1 is the earliest jdbc version implemented by the driver. Therefore I believe that the methods in DriverJDBCVersion:
checkSupportsJDBC4
and
checkSupportsJDBC41
are obsolete and can safely be removed. There are just under 200 references in the code for the two methods and removing them would make the code much cleaner. The methods are no-ops and are probably removed by the compiler anyway.

Use static factory methods for wrapper types

The driver currently instantiates wrapper types (Integer, Long, โ€ฆ) by directly calling the constructor using new rather than by calling the static valueOf factory methods. This is discouraged and deprecated in Java 9. To quote from the Integer constructor

It is rarely appropriate to use this constructor. The static factory valueOf(int) is generally a better choice, as it is likely to yield significantly better space and time performance.

Log parameter name that is causing the exception

If a parameter of the wrong type the driver throws an error with a message like Error converting data type nvarchar to decimal. It would be very helpful to see the name of the parameter that is causing this.

NullPointerException in case of SocketTimeout occurred

Hi! I've tried newest preview version "6.1.2-preview" and faced the following issue. When I set too small socket timeout like 30ms or less I have NullPointerException. I believe SocketTimeoutException should be instead. Please find full stacktrace below and let me know if you need more details.

java.lang.NullPointerException
at java.lang.StringBuilder.(StringBuilder.java:112)
at com.microsoft.sqlserver.jdbc.SQLServerException.checkAndAppendClientConnId(SQLServerException.java:348)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.terminate(SQLServerConnection.java:2507)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.terminate(SQLServerConnection.java:2491)
at com.microsoft.sqlserver.jdbc.TDSChannel.read(IOBuffer.java:2013)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.Prelogin(SQLServerConnection.java:2244)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.connectHelper(SQLServerConnection.java:2080)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.login(SQLServerConnection.java:1731)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.connectInternal(SQLServerConnection.java:1562)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.connect(SQLServerConnection.java:855)
at com.microsoft.sqlserver.jdbc.SQLServerDataSource.getConnectionInternal(SQLServerDataSource.java:842)
at com.microsoft.sqlserver.jdbc.SQLServerDataSource.getConnection(SQLServerDataSource.java:83)
at com.test.SoTimeoutTest.testSoTimeout(SoTimeoutTest.java:61)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:69)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:48)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
at org.junit.runners.ParentRunner.run(ParentRunner.java:292)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:678)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)

Add constrained delegation support

I am able to obtain a service ticket for SQL Server using an impersonated credential with Java 8 but when I try to use this with the driver I am getting the next error:

KrbException: The ticket isn't for us (35)

It seems that the problem is in the KerbAuthentication class inside the method intAuthInit(). In this class a context is created for the authentication and this context requests that the initiator's credentials be delegated to the acceptor during context establishment. This behavior is not possible within a constrained delegation scenario.

The service ticket obtained using the impersonated credential is not a forwardable ticket and is not usable for the driver. Changing the next set to false makes the authentication works.

peerContext.requestCredDeleg(true);

I understand this is not the right change since the SQL Server can need to use a delegated credential in order to connect to other SQL Server instances using open delegation, but a change is necessary to set this property to false in a constrained delegation scenery.

Connection gets closed because the "variant" data type is not supported

When I execute SELECT * FROM INFORMATION_SCHEMA.SEQUENCES, the connection gets closed, with an exception indicating that the "variant" data type is not supported. Consider throwing SQLServerException with a state other than com.microsoft.sqlserver.jdbc.SQLServerException.EXCEPTION_XOPEN_CONNECTION_FAILURE, and not closing the database connection.

Please let me know if you need more information.

Cant build with master's current head

current ref: cd2f4c87403aa6a41cbe8b3dda3106392dc6ee0b
Os: Ubuntu 16.04

mvn version

Apache Maven 3.3.9
Maven home: /usr/share/maven
Java version: 1.8.0_111, vendor: Oracle Corporation
Java home: /usr/lib/jvm/java-8-openjdk-amd64/jre
Default locale: en_US, platform encoding: UTF-8
OS name: "linux", version: "4.4.0-47-generic", arch: "amd64", family: "unix" 

java version

openjdk version "1.8.0_111"
OpenJDK Runtime Environment (build 1.8.0_111-8u111-b14-2ubuntu0.16.04.2-b14)
OpenJDK 64-Bit Server VM (build 25.111-b14, mixed mode)
xargs: clp: No such file or directory

I've attached the error text. Apparently the compile plugin defualts to 1.5 for some reason.
I'll try to fix this and submit a PR if I get a fix before anybody else.

error.txt

Exception thrown if comments are in SQL string

Running any query with a comment (using either -- or /**/) will throw an exception. We tend to read more complex SQL from a file on the classpath so having the ability to run queries with comments is very beneficial.

Example query: "/* test */ top 100 user_id from users" will throw the following:
"java.sql.SQLException: com.microsoft.sqlserver.jdbc.SQLServerException: Unable to identify the table /* test */"

exception SQL Server instance in use does not support column encryption

I have solution which tries to connect to Azure SQL database, database contains one table with few columns, one of columns has enabled column encryption (Always Encrypted with Azure KeyVault provider).
application is not able to connect to Azure SQL on Linux machine.
Finally I prepared docker image based on standard dockerhub java image (linux based). When I am running this image on my Windows 10 OS (but internally it still uses Linux docker in docker for windows) connection is successful, but when I upload my image to ubuntu linux VM in Azure it fails with exception:

com.microsoft.sqlserver.jdbc.SQLServerException: SQL Server instance in use does not support column encryption.
at com.microsoft.sqlserver.jdbc.TDSReader.TryProcessFeatureExtAck(IOBuffer.java:7346)
at com.microsoft.sqlserver.jdbc.TDSParser.parse(tdsparser.java:123)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.sendLogon(SQLServerConnection.java:4376)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.logon(SQLServerConnection.java:3188)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.access$100(SQLServerConnection.java:61)
at com.microsoft.sqlserver.jdbc.SQLServerConnection$LogonCommand.doExecute(SQLServerConnection.java:3151)
at com.microsoft.sqlserver.jdbc.TDSCommand.execute(IOBuffer.java:7535)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.executeCommand(SQLServerConnection.java:2438)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.connectHelper(SQLServerConnection.java:1973)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.login(SQLServerConnection.java:1616)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.connectInternal(SQLServerConnection.java:1447)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.connect(SQLServerConnection.java:788)
at com.microsoft.sqlserver.jdbc.SQLServerDriver.connect(SQLServerDriver.java:1187)
at java.sql.DriverManager.getConnection(DriverManager.java:664)
at java.sql.DriverManager.getConnection(DriverManager.java:270)
at Main.main(Main.java:81)

If I change connection string to use standard sql connection without columnEncryptionSetting than it works on both platforms.

included source codes and also trace logs from both scenario - docker on ubuntu linux and same docker image on windows10 docker.

Valdemar
project.zip
docker-on-ubuntu-1604.txt
docker-on-windows10.txt

Support cursor out parameters

It is my understanding that stored procedure with a cursor can not be called from JDBC. An example would be this

CREATE PROCEDURE simpleCursor
    @OutputCursor CURSOR VARYING OUTPUT
AS
BEGIN
    SET @OutputCursor = CURSOR
    FORWARD_ONLY STATIC FOR
    SELECT 'hello' UNION ALL SELECT 'world';

    OPEN @OutputCursor;
    return;
END;

which you should be able to call using this code

try (CallableStatement call = connection.prepareCall("{ call simpleCursor(?)}")) {
    call.registerOutParameter(1, Types.REF_CURSOR);
    call.execute();
    try (ResultSet resultSet = call.getObject(1, ResultSet.class)) {
        while (resultSet.next()) {
            System.out.println(resultSet.getObject(1, String.class));
        }
    }
}

This does not work because ref cursor support is not implemented in the driver. Instead the procedure has to be rewritten into this

CREATE PROCEDURE simpleCursor
AS
BEGIN
    SELECT 'hello' UNION ALL SELECT 'world'
END;

and the Java code has to be changed to

try (CallableStatement call = connection.prepareCall("{ call simpleCursor()}")) {
    call.execute();
    try (ResultSet resultSet = call.getResultSet) {
        while (resultSet.next()) {
            System.out.println(resultSet.getString(1));
        }
    }
}

azure-keyvault (mssql-jdbc's dependencies)

Not sure if this is alright, but I needed to exclude azure-keyvault since I do not use it, and this dependency was adding a lot more of its own deps to my final build.

Can you clarify those dependencies ? Maybe add this to the project README ? Thanks !

<dependency>
    <groupId>com.microsoft.sqlserver</groupId>
    <artifactId>mssql-jdbc</artifactId>
    <version>6.1.0.jre8</version>
    <exclusions>
        <exclusion>
            <groupId>com.microsoft.azure</groupId>
            <artifactId>azure-keyvault</artifactId>
        </exclusion>
    </exclusions>
</dependency>

Dependency tree report:

[INFO] | +- com.microsoft.sqlserver:mssql-jdbc:jar:6.1.0.jre8:compile
[INFO] |  \- com.microsoft.azure:azure-keyvault:jar:0.9.3:compile
[INFO] |     +- com.microsoft.azure:azure-core:jar:0.9.3:compile
[INFO] |     |  +- commons-codec:commons-codec:jar:1.10:compile
[INFO] |     |  +- commons-lang:commons-lang:jar:2.6:compile
[INFO] |     |  +- javax.mail:mail:jar:1.4.5:compile
[INFO] |     |  |  \- javax.activation:activation:jar:1.1:compile
[INFO] |     |  +- com.sun.jersey:jersey-client:jar:1.13:compile
[INFO] |     |  |  \- com.sun.jersey:jersey-core:jar:1.13:compile
[INFO] |     |  \- com.sun.jersey:jersey-json:jar:1.13:compile
[INFO] |     |     +- org.codehaus.jettison:jettison:jar:1.1:compile
[INFO] |     |     |  \- stax:stax-api:jar:1.0.1:compile
[INFO] |     |     +- com.sun.xml.bind:jaxb-impl:jar:2.2.3-1:compile
[INFO] |     |     |  \- javax.xml.bind:jaxb-api:jar:2.2.2:compile
[INFO] |     |     |     \- javax.xml.stream:stax-api:jar:1.0-2:compile
[INFO] |     |     +- org.codehaus.jackson:jackson-core-asl:jar:1.9.2:compile
[INFO] |     |     +- org.codehaus.jackson:jackson-mapper-asl:jar:1.9.2:compile
[INFO] |     |     +- org.codehaus.jackson:jackson-jaxrs:jar:1.9.2:compile
[INFO] |     |     \- org.codehaus.jackson:jackson-xc:jar:1.9.2:compile
[INFO] |     +- org.apache.httpcomponents:httpclient:jar:4.3.6:compile
[INFO] |     |  +- org.apache.httpcomponents:httpcore:jar:4.3.3:compile
[INFO] |     |  \- commons-logging:commons-logging:jar:1.1.3:compile
[INFO] |     +- javax.inject:javax.inject:jar:1:compile
[INFO] |     \- com.microsoft.azure:adal4j:jar:1.0.0:compile
[INFO] |        +- com.nimbusds:oauth2-oidc-sdk:jar:4.5:compile
[INFO] |        |  +- net.jcip:jcip-annotations:jar:1.0:compile
[INFO] |        |  +- org.apache.commons:commons-lang3:jar:3.3.1:compile
[INFO] |        |  +- net.minidev:json-smart:jar:1.1.1:compile
[INFO] |        |  +- com.nimbusds:lang-tag:jar:1.4:compile
[INFO] |        |  \- com.nimbusds:nimbus-jose-jwt:jar:3.1.2:compile
[INFO] |        +- com.google.code.gson:gson:jar:2.2.4:compile
[INFO] |        \- org.slf4j:slf4j-api:jar:1.7.5:compile

Socket Timeout support for jdbc connection

Hi,
Please correct me if I'm wrong but there is no possibility to configure socket (or read) timeout for MS SQL Server JDBC driver. I've found the following threads about this

https://social.msdn.microsoft.com/Forums/sqlserver/en-US/95755534-bbef-4c2c-afa4-b80ca2a2c333/how-can-i-set-sotimeout-on-the-sockets-used-by-the-jdbc-2005-driver?forum=sqldataaccess

https://social.msdn.microsoft.com/Forums/sqlserver/en-US/3373d40a-2a0b-4fe4-b6e8-46f2988debf8/any-plans-to-add-socket-timeout-option-in-jdbc-driver?forum=sqldataaccess

From my perspective it is a must have feature as network issues can cause thread hanging if there is no configured timeout. I will be very appreciate if you could support socket level timeout.

Thank you in advance!

Incorrect syntax near '@P0'

I'm using MS SQL 2016 (express), with a Java-based application using the following mvn reference to this library:

<dependency> <groupId>com.microsoft.sqlserver</groupId> <artifactId>mssql-jdbc</artifactId> <version>6.1.0.jre8</version> </dependency>

And I'm using the following MS-specific Hibernate settings:

String connectionUrl = "jdbc:sqlserver://localhost:1433;databaseName=fhir;user=fhir;password=xxx";
retVal.setDriver(new com.microsoft.sqlserver.jdbc.SQLServerDriver());
retVal.setUrl(connectionUrl);
retVal.setUsername("fhir");
retVal.setPassword("xxx");
...
//extraProperties.put("hibernate.dialect", org.hibernate.dialect.SQLServer2012Dialect.class.getName());
extraProperties.put("hibernate.dialect", org.hibernate.dialect.SQLServerDialect.class.getName());

I'm using 5.1.0.Final Hibernate.

The server I'm using is HAPI-FHIR (but I'm guessing that doesn't really matter, as it works towards many other database types. When 'downgrading' my db server to 2012-compatibility and using the 2012 dialect (as commented out above) in my Java code, everything works. But when I use 2016 or 2014 MS SQL together with dialect = org.hibernate.dialect.SQLServerDialect, I get the error below. Any idea what could be wrong??? The code with the 2012-mods is available on https://bitbucket.org/ehelse/hapi-v2

I'm getting the following exception:

62 [scheduledExecutorService-2] WARN o.h.e.jdbc.spi.SqlExceptionHelper [SqlExceptionHelper.java:129] SQL Error: 102, SQLState: S0001
2016-12-01 13:22:47.363 [scheduledExecutorService-2] ERROR o.h.e.jdbc.spi.SqlExceptionHelper [SqlExceptionHelper.java:131] Incorrect syntax near '@p0'.
2016-12-01 13:22:47.367 [scheduledExecutorService-2] ERROR o.s.s.s.TaskUtils$LoggingErrorHandler [TaskUtils.java:95] Unexpected error occurred in scheduled task.
javax.persistence.PersistenceException: org.hibernate.exception.SQLGrammarException: could not extract ResultSet
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1692)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1602)
at org.hibernate.jpa.internal.QueryImpl.getResultList(QueryImpl.java:492)
at ca.uhn.fhir.jpa.dao.BaseHapiFhirSystemDao$1.doInTransaction(BaseHapiFhirSystemDao.java:105)
at ca.uhn.fhir.jpa.dao.BaseHapiFhirSystemDao$1.doInTransaction(BaseHapiFhirSystemDao.java:93)
at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:133)
at ca.uhn.fhir.jpa.dao.BaseHapiFhirSystemDao.doPerformReindexingPassForResources(BaseHapiFhirSystemDao.java:93)
at ca.uhn.fhir.jpa.dao.BaseHapiFhirSystemDao.doPerformReindexingPass(BaseHapiFhirSystemDao.java:88)
at ca.uhn.fhir.jpa.dao.BaseHapiFhirSystemDao.performReindexingPass(BaseHapiFhirSystemDao.java:273)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:333)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:281)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
at com.sun.proxy.$Proxy121.performReindexingPass(Unknown Source)
at ca.uhn.fhir.jpa.dao.FhirResourceDaoSearchParameterDstu2.performReindexingPass(FhirResourceDaoSearchParameterDstu2.java:49)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:65)
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Caused by: org.hibernate.exception.SQLGrammarException: could not extract ResultSet
at org.hibernate.exception.internal.SQLStateConversionDelegate.convert(SQLStateConversionDelegate.java:106)
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:111)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:97)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:79)
at org.hibernate.loader.Loader.getResultSet(Loader.java:2115)
at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1898)
at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1874)
at org.hibernate.loader.Loader.doQuery(Loader.java:919)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:336)
at org.hibernate.loader.Loader.doList(Loader.java:2610)
at org.hibernate.loader.Loader.doList(Loader.java:2593)
at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2422)
at org.hibernate.loader.Loader.list(Loader.java:2417)
at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:501)
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:371)
at org.hibernate.engine.query.spi.HQLQueryPlan.performList(HQLQueryPlan.java:216)
at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1339)
at org.hibernate.internal.QueryImpl.list(QueryImpl.java:87)
at org.hibernate.jpa.internal.QueryImpl.list(QueryImpl.java:606)
at org.hibernate.jpa.internal.QueryImpl.getResultList(QueryImpl.java:483)
... 33 common frames omitted
Caused by: com.microsoft.sqlserver.jdbc.SQLServerException: Incorrect syntax near '@p0'.
at com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDatabaseError(SQLServerException.java:232)
at com.microsoft.sqlserver.jdbc.SQLServerStatement.getNextResult(SQLServerStatement.java:1672)
at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.doExecutePreparedStatement(SQLServerPreparedStatement.java:460)
at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement$PrepStmtExecCmd.doExecute(SQLServerPreparedStatement.java:405)
at com.microsoft.sqlserver.jdbc.TDSCommand.execute(IOBuffer.java:7535)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.executeCommand(SQLServerConnection.java:2438)
at com.microsoft.sqlserver.jdbc.SQLServerStatement.executeCommand(SQLServerStatement.java:208)
at com.microsoft.sqlserver.jdbc.SQLServerStatement.executeStatement(SQLServerStatement.java:183)
at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.executeQuery(SQLServerPreparedStatement.java:317)
at org.apache.commons.dbcp2.DelegatingPreparedStatement.executeQuery(DelegatingPreparedStatement.java:83)
at org.apache.commons.dbcp2.DelegatingPreparedStatement.executeQuery(DelegatingPreparedStatement.java:83)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:70)
... 49 common frames omitted

Here is some SQL-logging that I think may be related:

Hibernate:
select
subscripti0_.PID as col_0_0_
from
HFJ_SUBSCRIPTION subscripti0_
where
subscripti0_.SUBSCRIPTION_STATUS=?
and subscripti0_.NEXT_CHECK<=?
Hibernate:
select
search0_.PID as PID1_6_,
search0_.CREATED as CREATED2_6_,
search0_.LAST_UPDATED_HIGH as LAST_UPD3_6_,
search0_.LAST_UPDATED_LOW as LAST_UPD4_6_,
search0_.PREFERRED_PAGE_SIZE as PREFERRE5_6_,
search0_.RESOURCE_ID as RESOURCE6_6_,
search0_.RESOURCE_TYPE as RESOURCE7_6_,
search0_.SEARCH_TYPE as SEARCH_T8_6_,
search0_.TOTAL_COUNT as TOTAL_CO9_6_,
search0_.SEARCH_UUID as SEARCH_10_6_
from
HFJ_SEARCH search0_
where
search0_.CREATED<?
Hibernate:
select
count(termconcep0_.PID) as col_0_0_
from
TRM_CONCEPT termconcep0_
where
termconcep0_.INDEX_STATUS is null

Please tag releases

Please tag releases via git tag so it's easier to follow changes on GitHub.
Thank you!

JDBC Driver for SQL Server - Pulse Survey

We are continuing to improve the JDBC Driver for SQL Server by fixing issues reported on GitHub and adding new features. We've been releasing new preview releases every 3-4 weeks.

To help us drive our priorities going forward, can you please take this survey to help us learn more about your Java and SQL Server configuration?

Thanks,
Andrea Lam (on behalf of the JDBC team)

No longer possible to use JDBC driver as single jar

Previously a MS SQL Server JDBC driver was just a single jar. Now the version published to Maven Central brings tons of external dependencies.

Here is my sample Gradle build:

apply plugin: 'java'

repositories {
    jcenter()
}

dependencies {
    compileOnly 'com.microsoft.sqlserver:mssql-jdbc:6.1.0.jre8'
}

And if I run gradle dependencies I get the following picture:

compileClasspath - Compile classpath for source set 'main'.
\--- com.microsoft.sqlserver:mssql-jdbc:6.1.0.jre8
     \--- com.microsoft.azure:azure-keyvault:0.9.3
          +--- com.microsoft.azure:azure-core:0.9.3
          |    +--- org.apache.httpcomponents:httpclient:4.3.6
          |    |    +--- org.apache.httpcomponents:httpcore:4.3.3
          |    |    +--- commons-logging:commons-logging:1.1.3
          |    |    \--- commons-codec:commons-codec:1.6 -> 1.10
          |    +--- commons-codec:commons-codec:1.10
          |    +--- commons-lang:commons-lang:2.6
          |    +--- javax.mail:mail:1.4.5 -> 1.4.7
          |    |    \--- javax.activation:activation:1.1
          |    +--- javax.inject:javax.inject:1
          |    +--- com.sun.jersey:jersey-client:1.13
          |    |    \--- com.sun.jersey:jersey-core:1.13
          |    \--- com.sun.jersey:jersey-json:1.13
          |         +--- org.codehaus.jettison:jettison:1.1
          |         |    \--- stax:stax-api:1.0.1
          |         +--- com.sun.xml.bind:jaxb-impl:2.2.3-1
          |         |    \--- javax.xml.bind:jaxb-api:2.2.2
          |         |         +--- javax.xml.stream:stax-api:1.0-2
          |         |         \--- javax.activation:activation:1.1
          |         +--- org.codehaus.jackson:jackson-core-asl:1.9.2
          |         +--- org.codehaus.jackson:jackson-mapper-asl:1.9.2
          |         |    \--- org.codehaus.jackson:jackson-core-asl:1.9.2
          |         +--- org.codehaus.jackson:jackson-jaxrs:1.9.2
          |         |    +--- org.codehaus.jackson:jackson-core-asl:1.9.2
          |         |    \--- org.codehaus.jackson:jackson-mapper-asl:1.9.2 (*)
          |         +--- org.codehaus.jackson:jackson-xc:1.9.2
          |         |    +--- org.codehaus.jackson:jackson-core-asl:1.9.2
          |         |    \--- org.codehaus.jackson:jackson-mapper-asl:1.9.2 (*)
          |         \--- com.sun.jersey:jersey-core:1.13
          +--- org.apache.httpcomponents:httpclient:4.3.6 (*)
          +--- javax.inject:javax.inject:1
          \--- com.microsoft.azure:adal4j:1.0.0
               +--- com.nimbusds:oauth2-oidc-sdk:4.5
               |    +--- javax.mail:mail:1.4.7 (*)
               |    +--- net.jcip:jcip-annotations:1.0
               |    +--- org.apache.commons:commons-lang3:3.3.1
               |    +--- commons-codec:commons-codec:1.9 -> 1.10
               |    +--- net.minidev:json-smart:1.1.1
               |    +--- com.nimbusds:lang-tag:1.4
               |    |    \--- net.minidev:json-smart:1.1.1
               |    \--- com.nimbusds:nimbus-jose-jwt:3.1.2
               |         +--- net.jcip:jcip-annotations:1.0
               |         +--- net.minidev:json-smart:1.1.1
               |         \--- org.bouncycastle:bcprov-jdk15on:1.51
               +--- com.google.code.gson:gson:2.2.4
               +--- org.slf4j:slf4j-api:1.7.5
               \--- commons-codec:commons-codec:[1.10,) -> 1.10

Basically all of the external dependencies are due to com.microsoft.azure:azure-keyvault:0.9.3. Why is this dependency required? Can't it be made optional?

Handle sql_variant types as null (skip over them)

Currently if a ResultSet includes a sql_variant type then the driver will throw an exception during the column metadata parse phase of the response. This is because the driver does not yet handle sql_variant column types (presumably because sql_variant is complicated and parsing it would require handling many different types). Unfortunately this means that any SQL command that returns a sql_variant cannot be executed even if that particular column will not be processed.

Until it's fully supported one of the two following options would be nice:

  1. A connection option to interpret sql_variant columns as null. If set, then calling any getXYZ(...) method on a sql_variant column would always return null.
  2. Skipping over sql_variant columns in ResultSets as long as the getXYZ(...) methods are not invoked on them. The current "sql_variant is not supported..." exception could be thrown if one of those methods is invoked. The difference between this and the current driver would be that a user program could look at the ResultSetMetaData to determine which columns need to be skipped over (right now you can't do that as the metadata parsing phase throws the exception).

Issue while building

When I try to build on Mac OS X, I get the following message:

WARNING: ConnectionID:2 ClientConnectionId: 1c5a0f8d-3638-4189-b360-5c7d9be1760f Prelogin error: host localhost port 3306 Unexpected response type:74

I have set a local DB's config in src/test/serverConfig.cfg.
How do I build the project?

Temporal data types are forced as Varchar for "BulkRecord"

I tried to implement my own "ISQLServerBulkRecord" based on a "List" type, everything was fine until I discovered I have to convert the Date value to String because of:

SQLServerBulkCopy.java#L2364

case java.sql.Types.DATE:
    /*
     * If encrypted, varbinary will be returned before. The code will come here only if unencrypted. For unencrypted bulk copy if the
     * source is CSV, we send the data as varchar and SQL Server will do the conversion. if the source is ResultSet, we send the data as
     * the corresponding temporal type.
     */
    if (null != sourceBulkRecord) {
        return "varchar(" + ((0 == bulkPrecision) ? destPrecision : bulkPrecision) + ")";
    }
    else {
        return "date";
    }

Why are we assuming BulkRecord is "CSV" file? I have the date already, I shouldn't need to format it to string and let sql server on the other side to interpret it back to date right?

Statement property maxRows incorrectly affects count(*) on table valued functions.

Setting statement property maxRows results in faulty row count on table valued functions.
Below is the output from the supplied test program. The two functions numbers_tf and numbers_itf both return 10 rows. The former is table-valued function while the latter is an inlined version instead.

maxRows(0): select count(*) from dbo.numbers_itf() => 10  OK!
maxRows(5): select count(*) from dbo.numbers_itf() => 10  OK!
maxRows(0): select count(*) from dbo.numbers_tf() => 10  OK!
maxRows(5): select count(*) from dbo.numbers_tf() => 5  FAILED!

As can be seen setting maxRows to 5 changes the count to 5 instead of the expected 10. Clearly this is a bug. MaxRows should only affect the number of rows that the result set returns.

import java.math.BigInteger;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.concurrent.ThreadLocalRandom;

public class Main {
    public static void main(String[] args) throws SQLException {
        String url = "jdbc:sqlserver://localhost:1433";
        String user = "sa";
        String password = "Test1234!";
        String database = randomName("test_");
        try (
                Connection c = DriverManager.getConnection(url, user, password);
        ) {
            try {
                executeUpdate(c, "create database " + database);
                executeUpdate(c, "use " + database);


                executeUpdate(c, "create function dbo.numbers_itf()\n" +
                        "returns table\n" +
                        "as return\n" +
                        "    select * from (values (1), (2), (3), (4), (5), (6), (7), (8), (9), (10)) t(num)\n" +
                        "\n");

                executeUpdate(c, "create function dbo.numbers_tf()\n" +
                        "  returns @result table (\n" +
                        "    num int\n" +
                        "  )\n" +
                        "  as\n" +
                        "  begin\n" +
                        "    insert into @result\n" +
                        "    select * from (values (1), (2), (3), (4), (5), (6), (7), (8), (9), (10)) t(num)\n" +
                        "    return\n" +
                        "  end\n" +
                        "\n");


                executeTest(c, 0, "select count(*) from dbo.numbers_itf()", 10);
                executeTest(c, 5, "select count(*) from dbo.numbers_itf()", 10);
                executeTest(c, 0, "select count(*) from dbo.numbers_tf()", 10);
                executeTest(c, 5, "select count(*) from dbo.numbers_tf()", 10);

            } finally {
                executeUpdate(c,"use master");
                executeUpdate(c, "drop database " + database);
            }
        }
    }

    private static int executeUpdate(Connection c, String sql) throws SQLException {
        try (Statement s = c.createStatement()) {
            return s.executeUpdate(sql);
        }
    }

    private static void executeTest(Connection c, int maxRows, String sql, int expected) throws SQLException {
        try (Statement s = c.createStatement()) {
            s.setMaxRows(maxRows);
            s.execute(sql);
            try (ResultSet r = s.getResultSet()) {
                r.next();
                int actual = r.getInt(1);
                System.out.format("maxRows(%d): %s => %d  %s%n", s.getMaxRows(), sql, actual, (actual != expected ? "FAILED!" : "OK!"));
            }
        }
    }

    private static String randomName(String prefix) {
        return prefix + (new BigInteger(40, ThreadLocalRandom.current())).toString(32);
    }

}

Optional Dependency with Gradle

According to PR #148, the AKV and ADAL4J dependency are optional dependencies with Maven. It reduces dependency tree for any project that replies on mssql-jdbc. However, we couldn't find any equivalent option with Gradle. The most similar option may be compileOnly, but still, optional and compileOnly are different.

According to this Issue on Gradle, it seems like there is no optional with Gradle.

Any suggestions? Thanks.

Pick a build automation system

A short survey (by no means statistically valid) of the top java projects on github, such as guava, mockito, junit, hadoop, etc. shows that these projects use one, or in rarer cases two build automation systems. Currently in the dev branch there are config files for three: maven, gradle and ant. I believe this will be very hard to maintain so one build system should be picked and the others removed.

LOBs are fully materialised

BLOBs, CLOBs and NCLOBs are fully materialised into a single byte[]/String. In the case of large content (imagine a file stored in a BLOB) this puts quite a lot of pressure on both the allocator and the heap. It also defeats the point of streaming. Consider the following use case:

try (InputStream stream = resultSet.getBlob("column_name").getBinaryStream()) {
    // stream content
}

Exception thrown when using java.sql.Types.OTHER

Hi,
I am trying to write a method with dynamic data access, and I am getting exception
com.microsoft.sqlserver.jdbc.SQLServerException: The conversion from BIGINT to OTHER is unsupported.
here is my sample method to reproduce it:

	public List<MyData> read() {
		try {
			Connection connection = this.dataSource.getConnection();
			PreparedStatement ps = connection.prepareStatement("select * from TABLE_NAME where NAME = ?");
                     //ps.setObject(1,new String("test"),java.sql.Types.OTHER);
			ps.setObject(1,5,java.sql.Types.OTHER);
			ResultSet rs = ps.executeQuery();
			while (rs.next()) {
	            String s = rs.getString("NAME");
	            System.out.println(s);
	        }
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return null;
	}

This code works with JTDS 1.3.1 and once we tried migrating it to MS JDBC we got this error.

Add OSGi support to mssql-jdbc

OSGi support basically means adding OSGI specific headers to MANIFEST.MF done automatically by maven-bundle-plugin from Apache Felix or bnd-maven-plugin from Bndtools, so that the driver could be loaded in OSGi environmental.

One thing I see as problematic is the dependency to Microsoft Azure Keyvault, which is also not OSGI compatible and their plans do not promise any good: Azure/azure-sdk-for-java#471. Transitive Microsoft dependencies also seem to be non-OSGi compatible. Apache HTTPClient dependency should be ok as the jar is OSGi ready, although the HTTP client dependency seems to be only because of Azure connections.

TimeoutTimer starts a new Thread for all queries with a query-timeout

I think there is an opportunity to optimize the query-timeout function with relative ease.

In the TimeoutTimer class in IOBuffer I see on line 6800:

timerThread = new Thread(this);

If I read the code correctly, this would mean that a call to
SQLServerConnection.isValid(5)
would start a new thread to facilitate the 5 second timeout function.
A call to isValid is executed often by connection pool implementations (with a timeout) and should be relatively cheap.

Creating and starting a new thread is a relatively expensive operation.
This can be optimized using the ScheduledExecutorService. Below a little bit of code to demonstrate.
One thing that needs special attention is the shutdown of the ScheduledExecutorService:
this must be done properly and timely to ensure there are no memory leaks when, for example, re-deploying web applications (war-files). I known this can be a bit tricky as other JDBC drivers have failed to do this properly and required work-arounds.

package com.microsoft.sqlserver.jdbc;

import org.junit.Assert;
import org.junit.Test;

import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;

public class TimeoutTimerTest {

	@Test
	public void timeoutTest() {
		
		TdsTimeOutCommand cmd1 = new TdsTimeOutCommand("ttTest1");
		TimeoutTimerScheduled timer1 = new TimeoutTimerScheduled(1, cmd1);
		TdsTimeOutCommand cmd2 = new TdsTimeOutCommand("ttTest2");
		TimeoutTimerScheduled timer2 = new TimeoutTimerScheduled(2, cmd2);
		TimeoutTimerScheduled.prestart();
		try {
			timer1.start();
			timer2.start();
			// It appears it takes some time for timer-tasks to get scheduled:
			// this test will fail if sleep is set to 1001 milliseconds which, technically, should be enough.
			Thread.sleep(1500);
			Assert.assertNotNull("Command 1 interrupted.", cmd1.getInterruptReason());
			Assert.assertNull("Command 2 not interrupted.", cmd2.getInterruptReason());
			timer2.stop();
			Thread.sleep(1000);
			Assert.assertNull("Command 2 not interrupted after timer stopped.", cmd2.getInterruptReason());
		} catch (Exception e) {
			throw new AssertionError("Timeout test error.", e);
		} finally {
			TimeoutTimerScheduled.close();
		}
	}
	
	static class TdsTimeOutCommand extends TDSCommand {
		
		volatile String interruptReason;
		
		public TdsTimeOutCommand(String name) {
			super(name, 0);
		}

		@Override
		void interrupt(String reason) throws SQLServerException {
			interruptReason = reason;
			System.out.println(getLogContext() + " interrupted: " + reason);
		}

		@Override
		boolean doExecute() throws SQLServerException {
			return true;
		}
		
		public String getInterruptReason() {
			return interruptReason;
		}
		
	}
	
	// IOBuffer line 6800
	static class TimeoutTimerScheduled implements Runnable {
		
		private static final ScheduledThreadPoolExecutor tasks = new ScheduledThreadPoolExecutor(1);
		
		private final int timeoutSeconds;
		private final TDSCommand command;
		private volatile ScheduledFuture<?> task;
		
		TimeoutTimerScheduled(int timeoutSeconds,
				TDSCommand command) {
			assert timeoutSeconds > 0;
			assert null != command;

			this.timeoutSeconds = timeoutSeconds;
			this.command = command;
		}

		final void start() {
			
			task = tasks.schedule(this, timeoutSeconds, TimeUnit.SECONDS);
		}

		final void stop() {

			task.cancel(false);
		}

		@Override
		public void run() {
			
			// If the timer wasn't canceled before it ran out of
			// time then interrupt the registered command.
			try {
				command.interrupt(SQLServerException.getErrString("R_queryTimedOut"));
			}
			catch (SQLServerException e) {
				// Unfortunately, there's nothing we can do if we
				// fail to time out the request. There is no way
				// to report back what happened.
				command.log(Level.FINE, "Command could not be timed out. Reason: " + e.getMessage());
			}

		}

		public static void prestart() {
			tasks.prestartCoreThread();
		}

		public static void close() {
			tasks.shutdown();
		}
	}

}

TVP Handling is causing exception when calling SP with return value

When the SQLServerCallableStatement is called with prepareCall("{call SPNAME}") and Structured parameter is added to the statement, the call is successful.
However when the caller would need the return value from the call, that is prepareCall("{? = call SPNAME}") is used (with the first parameter placeholder for the return value) and also this is registered with registerOutParameter(1, Types.INTEGER), the execution of the statement fails because the SQLServerParameterMetaData class in the driver tries to get a nonexisting row from the sp_sproc_columns call result (to determine the TVP name from the database with this internal sp call).
The erroneus line is in the SQLServerParameterMetaData.verifyParameterPosition method, when calling the rsProcedureMeta.absolute(param+1). Here the +1 should be checked and added only if there is no return value parameter expected.

Request for jdbc 4.0

Recently I meet the SSL error due to the windows patch.
My application is running on JRE1.6, and can't update to 1.8 due to business reason.
I'm looking for the source code of version 4.0, and to overwrite it to avoid the SSL error.

Implement properly Cross Domain Kerberos using JavaKerberos

The Driver wrongly assumes the SPN to have the same value as the default_realm in krb5.conf.

Which means when connecting with principal [email protected] and connecting to to sqlserver:[email protected] the driver wrongly assumes the SPN is MSSQLSvc/sqlserver:[email protected] instead of the right MSSQLSvc/sqlserver:[email protected] even if DNS are correctly set up and domain to REALMS correctly described in krb5.conf file.

Using the default_realm is evil and should not be used at all.

Since the last driver (jdbc42, version 6.0), it is possible to override the Spn, but older drivers (compatible with Java 7) are not. Would it be possible to implement this feature?

java.lang.Character is "UNKNOWN"??

A parameter of type java.lang.Character is interpreted as javaType "OBJECT" and mapped to jdbcType "UNKNOWN" leading to an exception.

Of course this type should be mapped to JDBCType.CHAR.

Clarify depracted Lob public constructors

Both SQLServerClob and SQLServerBlob have deprecated public constructors. They are not used by the driver itself. I assume they are there to avoid breaking clients. I assume Connection#createClob and Connection#createBlob should be used instead. If that's true then it would be nice if this was documented in an @deprecated Javadoc tag and possibly in some kind of versioning policy on when the constructors will be removed.

Maven depends with old Jersey 1.x client

Trying to include MSSql support for our toolset. However, compiling into a modern Jersey 2.x project for Java 1.8 has conflicts with this driver since mssql-jdbc includes a dependency to Jersey client 1.x which isn't compatible and causes missing Map class errors due to the dual inclusion of both versions of the libs. Can this be updated or removed for the 6.1.0-JRE8 version?

This comes from this dependency chain:
azure-keyvault -> azure-core -> jersey-client v1.19 <<--- this is a 2 year old library...

java.lang.NoClassDefFoundError: com/microsoft/sqlserver/jdbc/StreamError

Using sqljdbc42.jar from package sqljdbc_6.0.7728.100_enu.tar, I'm getting the following exception from time to time:
config:
Linux CentOS 7 - 3.10.0-327.18.2.el7.x86_64
OpenJDK 64-Bit Server VM (build 25.111-b15, mixed mode)
Using HikariCP connection pool which wraps com.microsoft.sqlserver.jdbc.SQLServerDataSource

java.lang.NoClassDefFoundError: com/microsoft/sqlserver/jdbc/StreamError
        at com.microsoft.sqlserver.jdbc.TDSTokenHandler.onError(tdsparser.java:194)
        at com.microsoft.sqlserver.jdbc.TDSParser.parse(tdsparser.java:71)
        at com.microsoft.sqlserver.jdbc.SQLServerStatement.getNextResult(SQLServerStatement.java:1630)
        at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.doExecutePreparedStatement(SQLServerPreparedStatement.java:426)
        at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement$PrepStmtExecCmd.doExecute(SQLServerPreparedStatement.java:372)
        at com.microsoft.sqlserver.jdbc.TDSCommand.execute(IOBuffer.java:6276)
        at com.microsoft.sqlserver.jdbc.SQLServerConnection.executeCommand(SQLServerConnection.java:1793)
        at com.microsoft.sqlserver.jdbc.SQLServerStatement.executeCommand(SQLServerStatement.java:184)
        at com.microsoft.sqlserver.jdbc.SQLServerStatement.executeStatement(SQLServerStatement.java:159)
        at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.executeQuery(SQLServerPreparedStatement.java:284)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.