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
12 changes: 10 additions & 2 deletions .github/workflows/pr-validation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
strategy:
matrix:
go: ['1.24']
sqlImage: ['2019-latest','2022-latest']
sqlImage: ['2017-latest','2019-latest','2022-latest','2025-latest']
steps:
- uses: actions/checkout@v2
- name: Setup go
Expand All @@ -26,7 +26,15 @@ jobs:
export SQLUSER=sa
export SQLPASSWORD=$SQLCMDPASSWORD
export DATABASE=master
export HOST=.
export HOST=localhost
# Build connection string - SQL 2017 requires trusting its self-signed certificate
if [ "${{ matrix.sqlImage }}" = "2017-latest" ]; then
export SQLSERVER_DSN="sqlserver://${SQLUSER}:${SQLPASSWORD}@localhost:1433?database=${DATABASE}&trustServerCertificate=true"
# SQL 2017's certificate has a negative serial number which Go 1.23+ rejects by default
export GODEBUG=x509negativeserial=1
else
export SQLSERVER_DSN="sqlserver://${SQLUSER}:${SQLPASSWORD}@localhost:1433?database=${DATABASE}"
fi
docker run -m 2GB -e ACCEPT_EULA=1 -d --name sqlserver -p:1433:1433 -e SA_PASSWORD=$SQLCMDPASSWORD mcr.microsoft.com/mssql/server:${{ matrix.sqlImage }}
sleep 10
go test -v ./...
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@
# Changelog

## Unreleased

### Features

* Add `mssql.JSON` and `mssql.NullJSON` types for working with JSON data
- Uses native JSON type (0xF4) on SQL Server 2025+ and Azure SQL Database
- Automatically falls back to `nvarchar(max)` on SQL Server 2016-2022 for seamless compatibility
- Works with SQL Server's built-in JSON functions (JSON_VALUE, JSON_QUERY, ISJSON, etc.) on all supported SQL Server versions (2016+)

## 1.9.3

### Bug fixes
Expand Down
40 changes: 40 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,8 @@ are supported:

* string -> nvarchar
* mssql.VarChar -> varchar
* mssql.JSON -> json (SQL Server 2025+) or nvarchar(max) (older versions)
* mssql.NullJSON -> json (nullable, SQL Server 2025+) or nvarchar(max) (older versions)
* time.Time -> datetimeoffset or datetime (TDS version dependent)
* mssql.DateTime1 -> datetime
* mssql.DateTimeOffset -> datetimeoffset
Expand All @@ -454,6 +456,41 @@ db.QueryContext(ctx, `select * from t2 where user_name = @p1;`, mssql.VarChar(na
// Note: Mismatched data types on table and parameter may cause long running queries
```

### JSON Type

The driver provides `mssql.JSON` and `mssql.NullJSON` types for working with JSON data. These types work seamlessly across all supported SQL Server versions with automatic fallback behavior.

**Server Compatibility:**
- **SQL Server 2025+ / Azure SQL Database**: Uses the native JSON data type (type ID 0xF4) for optimal performance and type safety
- **SQL Server 2016-2022**: Automatically falls back to `nvarchar(max)` parameter declaration, allowing JSON data to work with the built-in JSON functions (JSON_VALUE, JSON_QUERY, ISJSON, etc.)

The driver automatically detects server capabilities during connection and chooses the appropriate behavior. You can use the same `mssql.JSON` and `mssql.NullJSON` types regardless of the SQL Server version - no code changes required.

**Note:** Native JSON *columns* (using the JSON data type in CREATE TABLE) require SQL Server 2025+ or Azure SQL Database. On older versions, store JSON in `nvarchar(max)` columns.

```go
// Insert JSON data
jsonData := json.RawMessage(`{"name":"John","age":30,"active":true}`)
_, err := db.ExecContext(ctx, "INSERT INTO users (profile) VALUES (@p1)", mssql.JSON(jsonData))

// Insert nullable JSON
nullableJSON := mssql.NullJSON{JSON: json.RawMessage(`{"key":"value"}`), Valid: true}
_, err = db.ExecContext(ctx, "INSERT INTO users (metadata) VALUES (@p1)", nullableJSON)

// Insert NULL JSON value
nullJSON := mssql.NullJSON{Valid: false}
_, err = db.ExecContext(ctx, "INSERT INTO users (metadata) VALUES (@p1)", nullJSON)

// Read JSON data
var result mssql.NullJSON
err = db.QueryRowContext(ctx, "SELECT metadata FROM users WHERE id = @p1", 1).Scan(&result)
if result.Valid {
fmt.Println("JSON data:", result.JSON)
} else {
fmt.Println("JSON is NULL")
}
```

## Using Always Encrypted

The protocol and cryptography details for AE are [detailed elsewhere](https://learn.microsoft.com/sql/relational-databases/security/encryption/always-encrypted-database-engine?view=sql-server-ver16).
Expand Down Expand Up @@ -529,6 +566,7 @@ Constrain the provider to an allowed list of key vaults by appending vault host
* Can be used with Microsoft Azure SQL Database
* Can be used on all go supported platforms (e.g. Linux, Mac OS X and Windows)
* Supports new date/time types: date, time, datetime2, datetimeoffset
* Supports JSON data with automatic fallback (SQL Server 2016+, native JSON type in 2025+)
* Supports string parameters longer than 8000 characters
* Supports encryption using SSL/TLS
* Supports SQL Server and Windows Authentication
Expand Down Expand Up @@ -586,6 +624,8 @@ More information: <http://support.microsoft.com/kb/2653857>

* Bulk copy does not yet support encrypting column values using Always Encrypted. Tracked in [#127](https://github.com/microsoft/go-mssqldb/issues/127)

* The JSON data type is not supported with Always Encrypted. This is a SQL Server limitation - the JSON type is not included in the list of [supported data types for Always Encrypted](https://learn.microsoft.com/en-us/sql/relational-databases/security/encryption/always-encrypted-cryptography).

# Contributing
This project is a fork of [https://github.com/denisenkom/go-mssqldb](https://github.com/denisenkom/go-mssqldb) and welcomes new and previous contributors. For more informaton on contributing to this project, please see [Contributing](./CONTRIBUTING.md).

Expand Down
3 changes: 2 additions & 1 deletion integratedauth/winsspi/provider.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//go:build windows
// +build windows

package winsspi
Expand All @@ -12,4 +13,4 @@ func init() {
if err != nil {
panic(err)
}
}
}
1 change: 1 addition & 0 deletions integratedauth/winsspi/winsspi.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//go:build windows
// +build windows

package winsspi
Expand Down
Loading