Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,42 @@
All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](http://keepachangelog.com/)
## [13.1.1] Preview Release

### Added

- **JSON datatype support** [#2558](https://github.com/microsoft/mssql-jdbc/pull/2558)
**What was added**: Support for reading and writing JSON columns in SQL Server.
**Who benefits**: Developers working with semi-structured data in SQL Server.
**Impact**: Enhances application flexibility by natively handling JSON content, reducing need for manual parsing.

- **Add order hints for Bulk Copy operations** [#2701](https://github.com/microsoft/mssql-jdbc/pull/2701)
**What was added**: Support for specifying order hints during Bulk Copy.
**Who benefits**: Data engineers and DBAs managing large data migrations or ETL jobs.
**Impact**: Improves bulk data load performance.

- **Coding best practices and review process** [#2666](https://github.com/microsoft/mssql-jdbc/pull/2666)
**What was added**: Introduced contributor guidelines, coding best practices, and review processes.
**Who benefits**: Open-source contributors and maintainers of the mssql-jdbc project.
**Impact**: Improves code quality, consistency, and onboarding experience for new contributors.

- **Add new trusted AKV URLs for FR and DE** [#2708](https://github.com/microsoft/mssql-jdbc/pull/2708)
**What was added**: Registered four new Azure Key Vault and Managed HSM endpoints for France and Germany.
**Who benefits**: Customers in regulated regions (France, Germany) using AKV for encryption.
**Impact**: Enables secure key operations via region-specific trusted endpoints.

### Fixed issues

- **Fix for null handling in temporal types with bulk copy** [#2702](https://github.com/microsoft/mssql-jdbc/pull/2702)
**What was fixed**: Properly handle null values for temporal types when sendTemporalDataTypesAsStringForBulkCopy=false.
**Who benefits**: Developers using batch insert with native temporal types in bulk copy.
**Impact**: Prevents failures during bulk inserts, improving reliability of time-sensitive data ingestion.

- **Fix string insertion with bulk copy API when sendStringParametersAsUnicode=false** [#2704](https://github.com/microsoft/mssql-jdbc/pull/2704)
**What was fixed**: Resolved issue where strings were inserted as byte arrays in batch bulk copy mode when sendStringParametersAsUnicode is set to false.
**Who benefits**: Developers using non-Unicode string inserts in performance-sensitive batch operations.
**Impact**: Ensures string integrity during batch inserts, eliminating silent data corruption.


## [13.1.0] Preview Release

Expand Down
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ We're now on the Maven Central Repository. Add the following to your POM file to
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>13.1.0.jre11-preview</version>
<version>13.1.1.jre11-preview</version>
</dependency>
```
The driver can be downloaded from [Microsoft](https://aka.ms/downloadmssqljdbc). 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.
Expand All @@ -94,7 +94,7 @@ 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>13.1.0.jre11-preview</version>
<version>13.1.1.jre11-preview</version>
</dependency>
```

Expand Down Expand Up @@ -129,7 +129,7 @@ Projects that require either of the two features need to explicitly declare the
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>13.1.0.jre11-preview</version>
<version>13.1.1.jre11-preview</version>
<scope>compile</scope>
</dependency>

Expand All @@ -147,7 +147,7 @@ Projects that require either of the two features need to explicitly declare the
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>13.1.0.jre11-preview</version>
<version>13.1.1.jre11-preview</version>
<scope>compile</scope>
</dependency>

Expand All @@ -174,7 +174,7 @@ When setting 'useFmtOnly' property to 'true' for establishing a connection or cr
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>13.1.0.jre11-preview</version>
<version>13.1.1.jre11-preview</version>
</dependency>

<dependency>
Expand Down
14 changes: 7 additions & 7 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

apply plugin: 'java'

version = '13.1.0'
version = '13.1.1'
def releaseExt = '-preview'
def jreVersion = ""
def testOutputDir = file("build/classes/java/test")
Expand All @@ -29,7 +29,7 @@ allprojects {

test {
useJUnitPlatform {
excludeTags (hasProperty('excludedGroups') ? excludedGroups : 'xSQLv15','xGradle','reqExternalSetup','NTLM','MSI','clientCertAuth','fedAuth','kerberos','vectorTest')
excludeTags (hasProperty('excludedGroups') ? excludedGroups : 'xSQLv15','xGradle','reqExternalSetup','NTLM','MSI','clientCertAuth','fedAuth','kerberos','vectorTest','JSONTest')
}
}

Expand All @@ -46,7 +46,7 @@ if (!hasProperty('buildProfile') || (hasProperty('buildProfile') && buildProfile
targetCompatibility = 23
test {
useJUnitPlatform {
excludeTags(hasProperty('excludedGroups') ? excludedGroups : 'vectorTest')
excludeTags(hasProperty('excludedGroups') ? excludedGroups : 'vectorTest','JSONTest')
}
}
}
Expand All @@ -64,7 +64,7 @@ if (hasProperty('buildProfile') && buildProfile == "jre21") {
targetCompatibility = 21
test {
useJUnitPlatform {
excludeTags(hasProperty('excludedGroups') ? excludedGroups : 'vectorTest')
excludeTags(hasProperty('excludedGroups') ? excludedGroups : 'vectorTest','JSONTest')
}
}
}
Expand All @@ -82,7 +82,7 @@ if (hasProperty('buildProfile') && buildProfile == "jre17") {
targetCompatibility = 17
test {
useJUnitPlatform {
excludeTags(hasProperty('excludedGroups') ? excludedGroups : 'vectorTest')
excludeTags(hasProperty('excludedGroups') ? excludedGroups : 'vectorTest','JSONTest')
}
}
}
Expand All @@ -100,7 +100,7 @@ if (hasProperty('buildProfile') && buildProfile == "jre11") {
targetCompatibility = 11
test {
useJUnitPlatform {
excludeTags(hasProperty('excludedGroups') ? excludedGroups : 'vectorTest')
excludeTags(hasProperty('excludedGroups') ? excludedGroups : 'vectorTest','JSONTest')
}
}
}
Expand All @@ -114,7 +114,7 @@ if(hasProperty('buildProfile') && buildProfile == "jre8") {
targetCompatibility = 1.8
test {
useJUnitPlatform {
excludeTags (hasProperty('excludedGroups') ? excludedGroups : 'xSQLv15','xGradle','NTLM','reqExternalSetup','MSI','clientCertAuth','fedAuth','xJDBC42','vectorTest')
excludeTags (hasProperty('excludedGroups') ? excludedGroups : 'xSQLv15','xGradle','NTLM','reqExternalSetup','MSI','clientCertAuth','fedAuth','xJDBC42','vectorTest','JSONTest')
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion mssql-jdbc_auth_LICENSE
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
MICROSOFT SOFTWARE LICENSE TERMS
MICROSOFT JDBC DRIVER 13.1.0 FOR SQL SERVER
MICROSOFT JDBC DRIVER 13.1.1 FOR SQL SERVER

These license terms are an agreement between you and Microsoft Corporation (or one of its affiliates). They apply to the software named above and any Microsoft services or software updates (except to the extent such services or updates are accompanied by new or additional terms, in which case those different terms apply prospectively and do not alter your or Microsoft’s rights relating to pre-updated software or services). IF YOU COMPLY WITH THESE LICENSE TERMS, YOU HAVE THE RIGHTS BELOW. BY USING THE SOFTWARE, YOU ACCEPT THESE TERMS.

Expand Down
5 changes: 3 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>13.1.0</version>
<version>13.1.1</version>
<packaging>jar</packaging>
<name>Microsoft JDBC Driver for SQL Server</name>
<description>
Expand Down Expand Up @@ -47,10 +47,11 @@
reqExternalSetup - For tests requiring external setup (excluded by default)
clientCertAuth - - For tests requiring client certificate authentication
vectorTest - - For tests using vector data types (excluded by default)
JSONTest - For tests using JSON data type
setup (excluded by default) - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Default testing enabled with SQL Server 2019 (SQLv15) -->
<excludedGroups>xSQLv12,xSQLv15,NTLM,MSI,reqExternalSetup,clientCertAuth,fedAuth,kerberos,vectorTest</excludedGroups>
<excludedGroups>xSQLv12,xSQLv15,NTLM,MSI,reqExternalSetup,clientCertAuth,fedAuth,kerberos,vectorTest,JSONTest</excludedGroups>
<!-- Use -preview for preview release, leave empty for official release. -->
<releaseExt>-preview</releaseExt>
<!-- Driver Dependencies -->
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/microsoft/sqlserver/jdbc/Column.java
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,7 @@ else if (jdbcType.isBinary()) {

// Update of Unicode SSType from textual JDBCType: Use Unicode.
if ((SSType.NCHAR == ssType || SSType.NVARCHAR == ssType || SSType.NVARCHARMAX == ssType
|| SSType.NTEXT == ssType || SSType.XML == ssType) &&
|| SSType.NTEXT == ssType || SSType.XML == ssType || SSType.JSON == ssType) &&

(JDBCType.CHAR == jdbcType || JDBCType.VARCHAR == jdbcType || JDBCType.LONGVARCHAR == jdbcType
|| JDBCType.CLOB == jdbcType)) {
Expand Down
37 changes: 26 additions & 11 deletions src/main/java/com/microsoft/sqlserver/jdbc/DataTypes.java
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ enum TDSType {
UDT(0xF0), // -16
XML(0xF1), // -15
VECTOR(0xF5), // 245
JSON(0xF4), // -12

// LONGLEN types
SQL_VARIANT(0x62); // 98
Expand Down Expand Up @@ -151,7 +152,8 @@ enum SSType {
TIMESTAMP(Category.TIMESTAMP, "timestamp", JDBCType.BINARY),
GEOMETRY(Category.UDT, "geometry", JDBCType.GEOMETRY),
GEOGRAPHY(Category.UDT, "geography", JDBCType.GEOGRAPHY),
VECTOR(Category.VECTOR, "vector", JDBCType.VECTOR);
VECTOR(Category.VECTOR, "vector", JDBCType.VECTOR),
JSON(Category.JSON, "json", JDBCType.JSON);

final Category category;
private final String name;
Expand Down Expand Up @@ -208,7 +210,8 @@ enum Category {
UDT,
SQL_VARIANT,
XML,
VECTOR;
VECTOR,
JSON;

private static final Category[] VALUES = values();
}
Expand Down Expand Up @@ -272,7 +275,11 @@ enum GetterConversion {
JDBCType.Category.NUMERIC, JDBCType.Category.DATE, JDBCType.Category.TIME, JDBCType.Category.BINARY,
JDBCType.Category.TIMESTAMP, JDBCType.Category.NCHARACTER, JDBCType.Category.GUID)),

VECTOR(SSType.Category.VECTOR, EnumSet.of(JDBCType.Category.VECTOR));
VECTOR(SSType.Category.VECTOR, EnumSet.of(JDBCType.Category.VECTOR)),
JSON(SSType.Category.JSON, EnumSet.of(JDBCType.Category.CHARACTER, JDBCType.Category.LONG_CHARACTER,
JDBCType.Category.CLOB, JDBCType.Category.NCHARACTER, JDBCType.Category.LONG_NCHARACTER,
JDBCType.Category.NCLOB, JDBCType.Category.BINARY, JDBCType.Category.LONG_BINARY,
JDBCType.Category.BLOB, JDBCType.Category.JSON));

private final SSType.Category from;
private final EnumSet<JDBCType.Category> to;
Expand Down Expand Up @@ -462,6 +469,9 @@ JDBCType getJDBCType(SSType ssType, JDBCType jdbcTypeFromApp) {
case VECTOR:
jdbcType = JDBCType.VECTOR;
break;
case JSON:
jdbcType = JDBCType.JSON;
break;
case XML:
default:
jdbcType = JDBCType.LONGVARBINARY;
Expand Down Expand Up @@ -686,8 +696,9 @@ enum JDBCType {
GEOMETRY(Category.GEOMETRY, microsoft.sql.Types.GEOMETRY, Object.class.getName()),
GEOGRAPHY(Category.GEOGRAPHY, microsoft.sql.Types.GEOGRAPHY, Object.class.getName()),
LOCALDATETIME(Category.TIMESTAMP, java.sql.Types.TIMESTAMP, LocalDateTime.class.getName()),
VECTOR(Category.VECTOR, microsoft.sql.Types.VECTOR, microsoft.sql.Vector.class.getName());

VECTOR(Category.VECTOR, microsoft.sql.Types.VECTOR, microsoft.sql.Vector.class.getName()),
JSON(Category.JSON, microsoft.sql.Types.JSON, Object.class.getName());

final Category category;
private final int intValue;
private final String className;
Expand Down Expand Up @@ -736,7 +747,8 @@ enum Category {
SQL_VARIANT,
GEOMETRY,
GEOGRAPHY,
VECTOR;
VECTOR,
JSON;

private static final Category[] VALUES = values();
}
Expand All @@ -747,7 +759,7 @@ enum SetterConversion {
JDBCType.Category.TIME, JDBCType.Category.TIMESTAMP, JDBCType.Category.DATETIMEOFFSET,
JDBCType.Category.CHARACTER, JDBCType.Category.LONG_CHARACTER, JDBCType.Category.NCHARACTER,
JDBCType.Category.LONG_NCHARACTER, JDBCType.Category.BINARY, JDBCType.Category.LONG_BINARY,
JDBCType.Category.GUID, JDBCType.Category.SQL_VARIANT)),
JDBCType.Category.GUID, JDBCType.Category.SQL_VARIANT, JDBCType.Category.JSON)),

LONG_CHARACTER(JDBCType.Category.LONG_CHARACTER, EnumSet.of(JDBCType.Category.CHARACTER,
JDBCType.Category.LONG_CHARACTER, JDBCType.Category.NCHARACTER, JDBCType.Category.LONG_NCHARACTER,
Expand Down Expand Up @@ -811,7 +823,8 @@ enum SetterConversion {

GEOGRAPHY(JDBCType.Category.GEOGRAPHY, EnumSet.of(JDBCType.Category.GEOGRAPHY)),

VECTOR(JDBCType.Category.VECTOR, EnumSet.of(JDBCType.Category.VECTOR));
VECTOR(JDBCType.Category.VECTOR, EnumSet.of(JDBCType.Category.VECTOR)),
JSON(JDBCType.Category.JSON, EnumSet.of(JDBCType.Category.JSON));

private final JDBCType.Category from;
private final EnumSet<JDBCType.Category> to;
Expand Down Expand Up @@ -848,7 +861,7 @@ enum UpdaterConversion {
SSType.Category.DATETIMEOFFSET, SSType.Category.CHARACTER, SSType.Category.LONG_CHARACTER,
SSType.Category.NCHARACTER, SSType.Category.LONG_NCHARACTER, SSType.Category.XML,
SSType.Category.BINARY, SSType.Category.LONG_BINARY, SSType.Category.UDT, SSType.Category.GUID,
SSType.Category.TIMESTAMP, SSType.Category.SQL_VARIANT, SSType.Category.VECTOR)),
SSType.Category.TIMESTAMP, SSType.Category.SQL_VARIANT, SSType.Category.VECTOR, SSType.Category.JSON)),

LONG_CHARACTER(JDBCType.Category.LONG_CHARACTER, EnumSet.of(SSType.Category.CHARACTER,
SSType.Category.LONG_CHARACTER, SSType.Category.NCHARACTER, SSType.Category.LONG_NCHARACTER,
Expand Down Expand Up @@ -914,7 +927,8 @@ enum UpdaterConversion {
SQL_VARIANT(JDBCType.Category.SQL_VARIANT, EnumSet.of(SSType.Category.SQL_VARIANT)),

VECTOR(JDBCType.Category.VECTOR, EnumSet.of(SSType.Category.CHARACTER, SSType.Category.LONG_CHARACTER,
SSType.Category.VECTOR));
SSType.Category.VECTOR)),
JSON(JDBCType.Category.JSON, EnumSet.of(SSType.Category.JSON));

private final JDBCType.Category from;
private final EnumSet<SSType.Category> to;
Expand Down Expand Up @@ -989,7 +1003,7 @@ boolean isBinary() {
* @return true if the JDBC type is textual
*/
private final static EnumSet<Category> textualCategories = EnumSet.of(Category.CHARACTER, Category.LONG_CHARACTER,
Category.CLOB, Category.NCHARACTER, Category.LONG_NCHARACTER, Category.NCLOB);
Category.CLOB, Category.NCHARACTER, Category.LONG_NCHARACTER, Category.NCLOB);

boolean isTextual() {
return textualCategories.contains(category);
Expand All @@ -1016,6 +1030,7 @@ int asJavaSqlType() {
return java.sql.Types.CHAR;
case NVARCHAR:
case SQLXML:
case JSON:
return java.sql.Types.VARCHAR;
case VECTOR:
return microsoft.sql.Types.VECTOR;
Expand Down
29 changes: 29 additions & 0 deletions src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,10 @@ final class TDS {
static final byte TDS_FEATURE_EXT_VECTORSUPPORT = 0x0E;
static final byte VECTORSUPPORT_NOT_SUPPORTED = 0x00;
static final byte MAX_VECTORSUPPORT_VERSION = 0x01;
// JSON support
static final byte TDS_FEATURE_EXT_JSONSUPPORT = 0x0D;
static final byte JSONSUPPORT_NOT_SUPPORTED = 0x00;
static final byte MAX_JSONSUPPORT_VERSION = 0x01;

static final int TDS_TVP = 0xF3;
static final int TVP_ROW = 0x01;
Expand Down Expand Up @@ -245,6 +249,9 @@ static final String getTokenName(int tdsTokenType) {
return "TDS_FEATURE_EXT_SESSIONRECOVERY (0x01)";
case TDS_FEATURE_EXT_VECTORSUPPORT:
return "TDS_FEATURE_EXT_VECTORSUPPORT (0x0E)";
case TDS_FEATURE_EXT_JSONSUPPORT:
return "TDS_FEATURE_EXT_JSONSUPPORT (0x0D)";

default:
return "unknown token (0x" + Integer.toHexString(tdsTokenType).toUpperCase() + ")";
}
Expand Down Expand Up @@ -4864,6 +4871,26 @@ void writeRPCStringUnicode(String sValue) throws SQLServerException {
writeRPCStringUnicode(null, sValue, false, null);
}

void writeRPCJson(String sName, String sValue, boolean bOut) throws SQLServerException {
boolean bValueNull = (sValue == null);
int nValueLen = bValueNull ? 0 : (2 * sValue.length());

writeRPCNameValType(sName, bOut, TDSType.JSON);

// PLP encoding is used for JSON values.
writeVMaxHeader(nValueLen, bValueNull, /* collation = */ null);

if (!bValueNull) {
if (nValueLen > 0) {
writeInt(nValueLen);
writeString(sValue);
}

// PLP terminator
writeInt(0);
}
}

/**
* Writes a string value as Unicode for RPC
*
Expand Down Expand Up @@ -5249,6 +5276,7 @@ private void writeInternalTVPRowValues(JDBCType jdbcType, String currentColumnSt
case LONGVARCHAR:
case LONGNVARCHAR:
case SQLXML:
case JSON:
isShortValue = (2L * columnPair.getValue().precision) <= DataTypes.SHORT_VARTYPE_MAX_BYTES;
isNull = (null == currentColumnStringValue);
dataLength = isNull ? 0 : currentColumnStringValue.length() * 2;
Expand Down Expand Up @@ -5493,6 +5521,7 @@ void writeTVPColumnMetaData(TVP value) throws SQLServerException {
case LONGVARCHAR:
case LONGNVARCHAR:
case SQLXML:
case JSON:
writeByte(TDSType.NVARCHAR.byteValue());
isShortValue = (2L * pair.getValue().precision) <= DataTypes.SHORT_VARTYPE_MAX_BYTES;
// Use PLP encoding on Yukon and later with long values
Expand Down
4 changes: 3 additions & 1 deletion src/main/java/com/microsoft/sqlserver/jdbc/Parameter.java
Original file line number Diff line number Diff line change
Expand Up @@ -907,7 +907,9 @@ private void setTypeDefinition(DTV dtv) {
case SQLXML:
param.typeDefinition = SSType.XML.toString();
break;

case JSON:
param.typeDefinition = SSType.JSON.toString();
break;
case TVP:
// definition should contain the TVP name and the keyword READONLY
String schema = param.schemaName;
Expand Down
Loading