Skip to content

Commit 47cdbd5

Browse files
authored
Merge pull request #66 from iamvirul/feature/mssql-support
feat(mssql): Add full MSSQL/SQL Server support
2 parents 8f32315 + 9270bb7 commit 47cdbd5

30 files changed

Lines changed: 2210 additions & 126 deletions

.github/workflows/build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ jobs:
1717
- name: Set up Go
1818
uses: actions/setup-go@v5
1919
with:
20-
go-version: '1.23'
20+
go-version: '1.25'
2121
cache-dependency-path: go.sum
2222

2323
- name: Download dependencies

.github/workflows/ci.yml

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ jobs:
1212
runs-on: ubuntu-latest
1313
strategy:
1414
matrix:
15-
go-version: ['1.23', '1.24']
15+
go-version: ['1.24', '1.25']
1616

1717
steps:
1818
- name: Checkout code
@@ -41,15 +41,15 @@ jobs:
4141
continue-on-error: false
4242

4343
- name: Merge coverage files
44-
if: matrix.go-version == '1.24'
44+
if: matrix.go-version == '1.25'
4545
run: |
4646
# Merge coverage files using go tool cover
4747
echo "mode: atomic" > coverage.txt
4848
grep -h -v "^mode:" coverage-unit.txt coverage-integration-basic.txt >> coverage.txt || true
4949
continue-on-error: false
5050

5151
- name: Verify coverage file exists
52-
if: matrix.go-version == '1.24'
52+
if: matrix.go-version == '1.25'
5353
run: |
5454
if [ ! -f coverage.txt ]; then
5555
echo "Error: coverage.txt not found"
@@ -59,7 +59,7 @@ jobs:
5959
head -5 coverage.txt
6060
6161
- name: Upload coverage artifact for merging
62-
if: matrix.go-version == '1.24'
62+
if: matrix.go-version == '1.25'
6363
uses: actions/upload-artifact@v4
6464
with:
6565
name: coverage-unit-${{ github.run_id }}
@@ -78,7 +78,7 @@ jobs:
7878
- name: Set up Go
7979
uses: actions/setup-go@v5
8080
with:
81-
go-version: '1.24'
81+
go-version: '1.25'
8282
cache-dependency-path: go.sum
8383

8484
- name: Verify dependencies
@@ -89,7 +89,7 @@ jobs:
8989

9090
- name: Run testcontainers integration tests
9191
run: |
92-
go test -v -timeout=20m -coverprofile=coverage-integration.txt -covermode=atomic -coverpkg=./internal/...,./pkg/... ./tests -run 'TestIntegration_MySQL_FullWorkflow|TestIntegration_PostgreSQL_FullWorkflow|TestIntegration_AllReportsGenerated'
92+
go test -v -timeout=30m -coverprofile=coverage-integration.txt -covermode=atomic -coverpkg=./internal/...,./pkg/... ./tests -run 'TestIntegration_MySQL_FullWorkflow|TestIntegration_PostgreSQL_FullWorkflow|TestIntegration_MSSQL_FullWorkflow|TestIntegration_AllReportsGenerated'
9393
continue-on-error: false
9494

9595
- name: Verify integration coverage file exists
@@ -130,7 +130,7 @@ jobs:
130130
- name: Set up Go
131131
uses: actions/setup-go@v5
132132
with:
133-
go-version: '1.24'
133+
go-version: '1.25'
134134
cache-dependency-path: go.sum
135135

136136
- name: Download unit test coverage artifact
@@ -173,13 +173,14 @@ jobs:
173173
- name: Set up Go
174174
uses: actions/setup-go@v5
175175
with:
176-
go-version: '1.24'
176+
go-version: '1.25'
177177
cache-dependency-path: go.sum
178178

179179
- name: Run linter
180-
uses: golangci/golangci-lint-action@v4
180+
uses: golangci/golangci-lint-action@v6
181181
with:
182-
version: latest
182+
version: v1.64.8
183+
install-mode: goinstall
183184
args: --timeout=5m --out-format=colored-line-number
184185

185186
build:
@@ -194,7 +195,7 @@ jobs:
194195
- name: Set up Go
195196
uses: actions/setup-go@v5
196197
with:
197-
go-version: '1.24'
198+
go-version: '1.25'
198199
cache-dependency-path: go.sum
199200

200201
- name: Download dependencies

.github/workflows/release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ jobs:
3939
- name: Set up Go
4040
uses: actions/setup-go@v5
4141
with:
42-
go-version: '1.23'
42+
go-version: '1.25'
4343
cache-dependency-path: go.sum
4444

4545
- name: Download dependencies

.golangci.yml

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
run:
2+
# golangci-lint is compiled from source via install-mode: goinstall in CI
3+
# using Go 1.25, so it can type-check modules that declare go 1.25.x.
4+
timeout: 5m
5+
6+
linters:
7+
enable-all: false
8+
# Use golangci-lint's default linter set; explicitly disable linters that
9+
# produce excessive noise or require Go 1.25-specific analysis.
10+
disable:
11+
- depguard
12+
- exhaustruct
13+
- gochecknoglobals
14+
- nlreturn
15+
- wsl
16+
- paralleltest
17+
- testpackage
18+
- godox
19+
20+
linters-settings:
21+
errcheck:
22+
# Type assertions in this codebase use the &holder SQL scan pattern where
23+
# the assertion is guaranteed to succeed. Enabling this produces false
24+
# positives on every sql.Rows.Scan destination dereference.
25+
check-type-assertions: false
26+
check-blank: false
27+
govet:
28+
enable-all: false
29+
# shadow: disabled — flags every `if err := ...; err != nil` block which is
30+
# idiomatic Go. Produces 40+ false positives across the codebase with zero
31+
# real bugs caught.
32+
gofmt:
33+
simplify: true
34+
35+
issues:
36+
exclude-rules:
37+
# Test files get relaxed rules
38+
- path: "_test\\.go"
39+
linters:
40+
- errcheck
41+
- gosec
42+
- gocritic
43+
# Seed/tooling binaries get relaxed rules
44+
- path: "cmd/"
45+
linters:
46+
- forbidigo
47+
# Don't fail on warnings from generated or vendor code
48+
exclude-dirs:
49+
- vendor

CHANGELOG.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,33 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
## [0.8] - 2026-03-14
11+
12+
### Added
13+
- **Microsoft SQL Server Support** (issue #13)
14+
- New driver: `driver: "mssql"` in `deepdiffdb.config.yaml`; maps to `github.com/microsoft/go-mssqldb` (`sqlserver://` DSN)
15+
- Schema introspection via `INFORMATION_SCHEMA.COLUMNS`, `sys.indexes`, `sys.index_columns`, `INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS`, and `sys.key_constraints`
16+
- Square-bracket identifier quoting: `[table]`, `[column]`, with `]]` escaping for literal `]`
17+
- `OFFSET 0 ROWS FETCH NEXT n ROWS ONLY` pagination (MSSQL has no `LIMIT` clause)
18+
- MSSQL-compatible `ALTER TABLE` generation: `ADD` (no `COLUMN` keyword), `ALTER COLUMN`, `DROP CONSTRAINT`, `DROP INDEX … ON …`
19+
- FK control during pack application via `sp_msforeachtable`: `NOCHECK CONSTRAINT ALL` / `WITH CHECK CHECK CONSTRAINT ALL`
20+
- Full type reconstruction: `varchar(max)`, `decimal(10,2)`, `nvarchar(255)` with `nchar`/`nvarchar` half-length correction (MSSQL stores byte-length)
21+
- `CheckPrimaryKeys` extended with MSSQL case querying `sys.tables` / `sys.key_constraints`
22+
- Port is optional for MSSQL (defaults to SQL Server standard 1433)
23+
- Integration test `TestIntegration_MSSQL_FullWorkflow` using testcontainers + `mcr.microsoft.com/mssql/server:2022-latest`
24+
- **Sample 15: MSSQL Support** (`samples/15-mssql-support/`)
25+
- Docker Compose with two SQL Server 2022 Express containers (prod on 1433, dev on 1434)
26+
- Init SQL scripts with deliberate schema drift: new columns, nullability changes, new indexes, FK relationships
27+
- Seed data with deliberate data drift: price updates, status changes, new rows
28+
- Makefile targets: `up`, `seed`, `diff`, `diff-schema`, `diff-content`, `gen-pack`, `down`, `clean`
29+
30+
### Changed
31+
- `pkg/config/config.go`: `mssql` added to valid driver list; port validation skipped for MSSQL (optional)
32+
- `internal/drivers/drivers.go`: MSSQL DSN builder added (`sqlserver://user:pass@host:port?database=db`)
33+
- `internal/content/hash.go` / `cursor.go`: MSSQL identifier quoting and `OFFSET/FETCH` pagination
34+
- `internal/content/pack.go`: MSSQL FK disable/enable, column type introspection, `ALTER TABLE ADD` syntax
35+
- `deepdiffdb.config.yaml.example`: Commented MSSQL connection example added
36+
1037
## [0.7] - 2026-03-14
1138

1239
### Added

README.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ DeepDiff DB makes the entire process deterministic, reviewable, and safe by:
2424

2525
- **Fast Go-based diff engine** - Optimized for performance with efficient memory usage
2626
- **Single static binary** - Zero dependencies after download, works on any compatible system
27-
- **Multi-database support** - MySQL, PostgreSQL, and SQLite
27+
- **Multi-database support** - MySQL, PostgreSQL, SQLite, and Microsoft SQL Server
2828
- **Schema drift detection** - Identifies structural differences between databases
2929
- **Row-level comparison** - SHA-256 hashing for accurate change detection
3030
- **Conflict detection** - Identifies rows that exist in both databases but differ
@@ -172,7 +172,7 @@ Create a `deepdiffdb.config.yaml` file:
172172

173173
```yaml
174174
prod:
175-
driver: "mysql" # mysql, postgres, postgresql, or sqlite
175+
driver: "mysql" # mysql, postgres, postgresql, sqlite, or mssql
176176
host: "localhost"
177177
port: 3306
178178
user: "root"
@@ -218,9 +218,9 @@ conflict_resolution:
218218
### Configuration Options
219219
220220
**Database Configuration:**
221-
- `driver`: Database driver (`mysql`, `postgres`, `postgresql`, or `sqlite`)
221+
- `driver`: Database driver (`mysql`, `postgres`, `postgresql`, `sqlite`, or `mssql`)
222222
- `host`: Database hostname or IP address
223-
- `port`: Database port number (not required for SQLite)
223+
- `port`: Database port number (not required for SQLite; defaults to 1433 for MSSQL)
224224
- `user`: Database username
225225
- `password`: Database password
226226
- `database`: Database name
@@ -306,7 +306,7 @@ deepdiffdb schema-migrate --config deepdiffdb.config.yaml
306306
- `schema_migration.sql` - Transaction-wrapped SQL migration script
307307

308308
**Features:**
309-
- Driver-specific SQL syntax (MySQL, PostgreSQL, SQLite)
309+
- Driver-specific SQL syntax (MySQL, PostgreSQL, SQLite, MSSQL)
310310
- Safe defaults (destructive operations commented out by default)
311311
- Proper dependency ordering for foreign keys and constraints
312312
- Transaction-wrapped for atomic execution
@@ -613,7 +613,7 @@ deepdiffdb gen-pack --config deepdiffdb.config.yaml --resume
613613

614614
Current limitations and known constraints:
615615

616-
- **Database Support** - MSSQL and Oracle are not yet supported (planned for future releases)
616+
- **Database Support** - Oracle is not yet supported (planned for future releases)
617617
- **Schema Auto-merge** - Schema differences must be resolved manually
618618
- **Primary Key Requirement** - All tables must have primary keys (unless explicitly ignored)
619619
- **Large Database Performance** - Very large tables are handled with keyset-paginated batching (v0.7+); diff output files may still be large for tables with many changed rows
@@ -640,7 +640,7 @@ go test ./tests/drivers
640640
go test ./tests -run TestIntegration -v
641641
```
642642

643-
Integration tests use testcontainers and automatically spin up MySQL and PostgreSQL containers for full workflow validation.
643+
Integration tests use testcontainers and automatically spin up MySQL, PostgreSQL, and MSSQL containers for full workflow validation.
644644

645645
## Contributing
646646

ROADMAP.md

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,15 @@ We release a new version every **Saturday**. Each release includes one or more f
88

99
---
1010

11-
## Current Status: v0.7
11+
## Current Status: v0.8
1212

1313
**Last Release:** 2026-03-14
1414

1515
**Current Features:**
1616
- Schema drift detection and standalone schema migration (`schema-migrate`)
1717
- Row-level data comparison with SHA-256 hashing
1818
- Migration pack generation and transactional apply mode
19-
- MySQL, PostgreSQL, and SQLite support
19+
- MySQL, PostgreSQL, SQLite, and **Microsoft SQL Server** support
2020
- Conflict detection with `ours`/`theirs`/`manual` resolution strategies
2121
- Interactive `resolve-conflicts` command with `--auto` and `--resume` flags
2222
- Per-table conflict resolution strategies with `resolutions.json` persistence
@@ -119,17 +119,18 @@ We release a new version every **Saturday**. Each release includes one or more f
119119

120120
---
121121

122-
### v0.8: MSSQL Support
123-
**Target Date:** Next Saturday
122+
### ~~v0.8: MSSQL Support~~ ✅ Released 2026-03-14
124123

125-
**Features:**
126-
- Microsoft SQL Server driver support
127-
- MSSQL-specific schema introspection
128-
- MSSQL-specific SQL generation
129-
- Transaction handling for MSSQL
130-
- Testing with MSSQL 2019+ versions
124+
**Features delivered:**
125+
- Microsoft SQL Server driver (`github.com/microsoft/go-mssqldb`)
126+
- Schema introspection via `INFORMATION_SCHEMA` + `sys.*` catalog views
127+
- MSSQL-compatible SQL generation (square-bracket quoting, `ALTER COLUMN`, `DROP INDEX … ON …`)
128+
- FK control via `sp_msforeachtable` in pack application
129+
- `OFFSET/FETCH` pagination (no `LIMIT`)
130+
- Integration tests with SQL Server 2022 (testcontainers)
131+
- Sample 15: MSSQL Support
131132

132-
**Impact:** Expands database support to enterprise SQL Server users
133+
**Impact:** Enterprise SQL Server users can now use DeepDiff DB in production
133134

134135
---
135136

@@ -213,11 +214,9 @@ We release a new version every **Saturday**. Each release includes one or more f
213214
- ~~HTML Report Viewer~~ (v0.5)
214215
- ~~Enhanced Error Handling & Logging~~ (v0.6)
215216
- ~~Streaming Support for Large Datasets~~ (v0.7)
217+
- ~~MSSQL Support~~ (v0.8)
216218
- Documentation & Production Readiness
217219

218-
### Medium Priority (Should Have)
219-
- MSSQL Support
220-
221220
### Low Priority (Nice to Have)
222221
- Oracle Support (can be post-v1.0)
223222
- Advanced features (post-v1.0)

deepdiffdb.config.yaml.example

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
prod:
2-
driver: "postgres"
2+
driver: "postgres" # Supported: mysql | postgres | postgresql | sqlite | mssql
33
host: "127.0.0.1"
44
port: 5432
55
user: "postgres"
@@ -14,6 +14,27 @@ dev:
1414
password: "password"
1515
database: "dev_db"
1616

17+
# ─────────────────────────────────────────────────────────
18+
# Microsoft SQL Server example (driver: mssql)
19+
# Requires SQL Server 2017+ (or Azure SQL Database)
20+
# Port is optional — defaults to 1433 when omitted.
21+
# ─────────────────────────────────────────────────────────
22+
# prod:
23+
# driver: "mssql"
24+
# host: "127.0.0.1"
25+
# port: 1433 # optional; omit to use default 1433
26+
# user: "sa"
27+
# password: "StrongP@ss1word!"
28+
# database: "prod_db"
29+
#
30+
# dev:
31+
# driver: "mssql"
32+
# host: "127.0.0.1"
33+
# port: 1434
34+
# user: "sa"
35+
# password: "StrongP@ss1word!"
36+
# database: "dev_db"
37+
1738
ignore:
1839
tables:
1940
- "logs"

0 commit comments

Comments
 (0)