Skip to content

Commit 0c45ff6

Browse files
committed
Resolving conflicts
2 parents 6cc49af + 49a04c3 commit 0c45ff6

36 files changed

+22254
-1453
lines changed

.coveragerc

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
[run]
22
omit =
3-
mssql_python/testing_ddbc_bindings.py
3+
main.py
4+
setup.py
5+
bcp_options.py
46
tests/*
57

68
[report]

.github/workflows/pr-code-coverage.yml

Lines changed: 491 additions & 0 deletions
Large diffs are not rendered by default.

.github/workflows/pr-format-check.yml

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,9 @@ jobs:
5757
// Extract the summary content
5858
const summaryContent = summaryMatch[1];
5959
60-
// Remove all HTML comments including the template placeholder
60+
// Remove all HTML comments including unclosed ones (template placeholders)
6161
const contentWithoutComments =
62-
summaryContent.replace(/<!--[\s\S]*?-->/g, '');
62+
summaryContent.replace(/<!--[\s\S]*?(?:-->|$)/g, '');
6363
6464
// Remove whitespace and check if there's actual text content
6565
const trimmedContent = contentWithoutComments.trim();
@@ -94,24 +94,35 @@ jobs:
9494
labelToAdd = 'pr-size: large';
9595
}
9696
97-
// Remove existing size labels if any
97+
// Get existing labels
9898
const existingLabels = pr.labels.map(l => l.name);
9999
const sizeLabels = ['pr-size: small', 'pr-size: medium', 'pr-size: large'];
100-
for (const label of existingLabels) {
101-
if (sizeLabels.includes(label)) {
100+
101+
// Find current size label (if any)
102+
const currentSizeLabel = existingLabels.find(label => sizeLabels.includes(label));
103+
104+
// Only make changes if the label needs to be updated
105+
if (currentSizeLabel !== labelToAdd) {
106+
console.log(`Current size label: ${currentSizeLabel || 'none'}`);
107+
console.log(`Required size label: ${labelToAdd} (Total changes: ${totalChanges})`);
108+
109+
// Remove existing size label if different from required
110+
if (currentSizeLabel) {
111+
console.log(`Removing outdated label: ${currentSizeLabel}`);
102112
await github.rest.issues.removeLabel({
103113
...context.repo,
104114
issue_number: pr.number,
105-
name: label,
115+
name: currentSizeLabel,
106116
});
107117
}
108-
}
109118
110-
// Add new size label
111-
await github.rest.issues.addLabels({
112-
...context.repo,
113-
issue_number: pr.number,
114-
labels: [labelToAdd],
115-
});
116-
117-
console.log(`Added label: ${labelToAdd} (Total changes: ${totalChanges})`);
119+
// Add new size label
120+
console.log(`Adding new label: ${labelToAdd}`);
121+
await github.rest.issues.addLabels({
122+
...context.repo,
123+
issue_number: pr.number,
124+
labels: [labelToAdd],
125+
});
126+
} else {
127+
console.log(`Label already correct: ${labelToAdd} (Total changes: ${totalChanges}) - no changes needed`);
128+
}

.gitignore

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
# Ignore all files in the pybind/build directory
2-
mssql_python/pybind/build/
3-
41
# Ignore pycache files and folders
52
__pycache__/
63
**/__pycache__/
@@ -23,6 +20,7 @@ test-*.xml
2320

2421
# Ignore the build & mssql_python.egg-info directories
2522
build/
23+
**/build/
2624
mssql_python.egg-info/
2725

2826
# Python bytecode
@@ -46,4 +44,19 @@ build/
4644
*.swp
4745

4846
# .DS_Store files
49-
.DS_Store
47+
.DS_Store
48+
49+
# wheel files
50+
*.whl
51+
*.tar.gz
52+
*.zip
53+
54+
# Dockerfiles and images (root only)
55+
/Dockerfile*
56+
/docker-compose.yml
57+
/docker-compose.override.yml
58+
/docker-compose.*.yml
59+
60+
# Virtual environments
61+
*venv*/
62+
**/*venv*/

PyPI_Description.md

Lines changed: 43 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,55 @@
11
# mssql-python
22

3-
This is a new Python driver for Microsoft SQL Server currently in Alpha phase.
3+
mssql-python is a new first-party SQL Server driver for Python that has all of the benefits of a fresh start while preserving a familiar experience for developers.
4+
5+
## What makes mssql-python different?
6+
7+
### Powered by DDBC – Direct Database Connectivity
8+
9+
Most Python SQL Server drivers, including pyodbc, route calls through the Driver Manager, which has slightly different implementations across Windows, macOS, and Linux. This results in inconsistent behavior and capabilities across platforms. Additionally, the Driver Manager must be installed separately, creating friction for both new developers and when deploying applications to servers.
10+
11+
At the heart of the driver is DDBC (Direct Database Connectivity) — a lightweight, high-performance C++ layer that replaces the platform’s Driver Manager.
12+
13+
Key Advantages:
14+
15+
- Provides a consistent, cross-platform backend that handles connections, statements, and memory directly.
16+
- Interfaces directly with the native SQL Server drivers.
17+
- Integrates with the same TDS core library that powers the ODBC driver.
18+
19+
### Why is this architecture important?
20+
21+
By simplifying the architecture, DDBC delivers:
22+
23+
- Consistency across platforms
24+
- Lower function call overhead
25+
- Zero external dependencies on Windows (`pip install mssql-python` is all you need)
26+
- Full control over connections, memory, and statement handling
27+
28+
### Built with PyBind11 + Modern C++ for Performance and Safety
29+
30+
To expose the DDBC engine to Python, mssql-python uses PyBind11 – a modern C++ binding library, instead of ctypes. With ctypes, every call between Python and the ODBC driver involved costly type conversions, manual pointer management, resulting in slow and potentially unsafe code.
31+
32+
PyBind11 provides:
33+
34+
- Native-speed execution with automatic type conversions
35+
- Memory-safe bindings
36+
- Clean and Pythonic API, while performance-critical logic remains in robust, maintainable C++.
437

538
## Public Preview Release
639

7-
We are making progress - The Public Preview of our driver is now available! This marks a significant milestone in our development journey. While we saw a few early adopters of our alpha release, we are introducing the following functionalities to support your applications in a more robust and reliable manner.
40+
We are currently in **Public Preview**.
841

9-
### What's Included:
42+
## What's new in v0.13.0
1043

11-
- Everything from previous releases
12-
- **Alpine Linux Support:** Added full support for Alpine Linux distribution (musllinux) with specialized driver handling and fixes for musl libc compatibility.
13-
- **Connection Management Improvements:** Fixed autocommit to be False by default and added automatic rollback on connection close for better transaction control.
14-
- **PyODBC Compatibility:** Enhanced type objects and constructor compatibility with pyodbc for seamless migration and interoperability.
44+
- **Enhanced Batch Operations:** Complete support for UNIQUEIDENTIFIER and DATETIMEOFFSET in `executemany()` operations with automatic type inference, enabling efficient bulk inserts of complex data types including UUIDs and timezone-aware datetimes.
45+
- **Streaming Large Values:** Robust handling of large objects (NVARCHAR/VARCHAR/VARBINARY(MAX)) in `executemany()` with automatic Data-At-Execution detection and fallback, supporting streaming inserts and fetches for massive datasets.
46+
- **Improved Cursor Reliability:** Enhanced `cursor.rowcount` accuracy across all fetch operations, including proper handling of empty result sets and consistent behavior for SELECT, INSERT, and UPDATE operations.
47+
- **Critical Stability Fixes:** Resolved memory leaks with secure token buffer handling, fixed resource cleanup to prevent segmentation faults during Python shutdown, and corrected type inference bugs in batch operations.
1548

1649
For more information, please visit the project link on Github: https://github.com/microsoft/mssql-python
1750

18-
### What's Next:
19-
20-
As we continue to develop and refine the driver, you can expect regular updates that will introduce new features, optimizations, and bug fixes. We encourage you to contribute, provide feedback and report any issues you encounter, as this will help us improve the driver for the final release.
51+
If you have any feedback, questions or need support please mail us at mssql-python@microsoft.com.
2152

22-
### Stay Tuned:
53+
## What's Next
2354

24-
We appreciate your interest and support in this project. Stay tuned for more updates and enhancements as we work towards delivering a robust and fully-featured driver in coming months.
25-
Thank you for being a part of our journey!
55+
As we continue to develop and refine the driver, you can expect regular updates that will introduce new features, optimizations, and bug fixes. We encourage you to contribute, provide feedback and report any issues you encounter, as this will help us improve the driver ahead of General Availability.

README.md

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,25 +24,30 @@ pip install mssql-python
2424
**Linux:** mssql-python can be installed with [pip](http://pypi.python.org/pypi/pip)
2525
```bash
2626
# For Alpine
27-
apk add libtool krb5-libs
27+
apk add libtool krb5-libs krb5-dev
2828

29-
# For Debian/Ubuntu
30-
apt-get install -y libltdl7
29+
# For Debian/Ubuntu
30+
apt-get install -y libltdl7 libkrb5-3 libgssapi-krb5-2
3131

3232
# For RHEL
33-
dnf install -y libtool-ltdl
33+
dnf install -y libtool-ltdl krb5-libs
34+
35+
# For SUSE
36+
zypper install -y libltdl7 libkrb5-3 libgssapi-krb5-2
37+
38+
# For SUSE/openSUSE
39+
zypper install -y libltdl7
3440

3541
pip install mssql-python
3642
```
3743

3844
## Key Features
3945
### Supported Platforms
4046

41-
Windows, MacOS and Linux (manylinux - Debian, Ubuntu, RHEL & musllinux - Alpine)
47+
Windows, MacOS and Linux (manylinux - Debian, Ubuntu, RHEL, SUSE (x64 only) & musllinux - Alpine)
4248

4349
> **Note:**
44-
> Support for additional Linux OSs (SUSE Linux) will come soon
45-
>
50+
> SUSE Linux ARM64 is not supported by Microsoft ODBC Driver. Use x64 architecture for SUSE deployments.
4651
4752
### DBAPI v2.0 Compliance
4853

eng/pipelines/build-whl-pipeline.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,9 @@ jobs:
258258
# Install CMake on macOS
259259
- script: |
260260
brew update
261+
# Uninstall existing CMake to avoid tap conflicts
262+
brew uninstall cmake --ignore-dependencies || echo "CMake not installed or already removed"
263+
# Install CMake from homebrew/core
261264
brew install cmake
262265
displayName: 'Install CMake'
263266
@@ -337,7 +340,7 @@ jobs:
337340
python -m pytest -v
338341
displayName: 'Run Pytest to validate bindings'
339342
env:
340-
DB_CONNECTION_STRING: 'Driver=ODBC Driver 18 for SQL Server;Server=localhost;Database=master;Uid=SA;Pwd=$(DB_PASSWORD);TrustServerCertificate=yes'
343+
DB_CONNECTION_STRING: 'Driver=ODBC Driver 18 for SQL Server;Server=tcp:127.0.0.1,1433;Database=master;Uid=SA;Pwd=$(DB_PASSWORD);TrustServerCertificate=yes'
341344
342345
# Build wheel package for universal2
343346
- script: |

eng/pipelines/pr-validation-pipeline.yml

Lines changed: 123 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,44 @@ trigger:
77
- main
88

99
jobs:
10+
- job: CodeQLAnalysis
11+
displayName: 'CodeQL Security Analysis'
12+
pool:
13+
vmImage: 'ubuntu-latest'
14+
15+
steps:
16+
- script: |
17+
sudo apt-get update
18+
sudo apt-get install -y build-essential cmake curl git python3 python3-pip python3-dev python3-venv unixodbc-dev
19+
displayName: 'Install build dependencies for CodeQL'
20+
21+
- task: UsePythonVersion@0
22+
inputs:
23+
versionSpec: '3.13'
24+
addToPath: true
25+
displayName: 'Use Python 3.13 for CodeQL'
26+
27+
- script: |
28+
python -m pip install --upgrade pip
29+
pip install -r requirements.txt
30+
displayName: 'Install Python dependencies for CodeQL'
31+
32+
- task: CodeQL3000Init@0
33+
inputs:
34+
Enabled: true
35+
displayName: 'Initialize CodeQL'
36+
37+
# Build the C++ extension for CodeQL analysis
38+
- script: |
39+
cd mssql_python/pybind
40+
chmod +x build.sh
41+
./build.sh
42+
displayName: 'Build C++ extension for CodeQL analysis'
43+
44+
- task: CodeQL3000Finalize@0
45+
condition: always()
46+
displayName: 'Finalize CodeQL'
47+
1048
- job: PytestOnWindows
1149
displayName: 'Windows x64'
1250
pool:
@@ -72,11 +110,11 @@ jobs:
72110
testResultsFiles: '**/test-results.xml'
73111
testRunTitle: 'Publish test results'
74112

75-
- task: PublishCodeCoverageResults@1
76-
inputs:
77-
codeCoverageTool: 'Cobertura'
78-
summaryFileLocation: 'coverage.xml'
79-
displayName: 'Publish code coverage results'
113+
# - task: PublishCodeCoverageResults@1
114+
# inputs:
115+
# codeCoverageTool: 'Cobertura'
116+
# summaryFileLocation: 'coverage.xml'
117+
# displayName: 'Publish code coverage results'
80118

81119
- job: PytestOnMacOS
82120
displayName: 'macOS x86_64'
@@ -92,6 +130,9 @@ jobs:
92130

93131
- script: |
94132
brew update
133+
# Uninstall existing CMake to avoid tap conflicts
134+
brew uninstall cmake --ignore-dependencies || echo "CMake not installed or already removed"
135+
# Install CMake from homebrew/core
95136
brew install cmake
96137
displayName: 'Install CMake'
97138
@@ -149,7 +190,7 @@ jobs:
149190
python -m pytest -v --junitxml=test-results.xml --cov=. --cov-report=xml --capture=tee-sys --cache-clear
150191
displayName: 'Run pytest with coverage'
151192
env:
152-
DB_CONNECTION_STRING: 'Driver=ODBC Driver 18 for SQL Server;Server=localhost;Database=master;Uid=SA;Pwd=$(DB_PASSWORD);TrustServerCertificate=yes'
193+
DB_CONNECTION_STRING: 'Driver=ODBC Driver 18 for SQL Server;Server=tcp:127.0.0.1,1433;Database=master;Uid=SA;Pwd=$(DB_PASSWORD);TrustServerCertificate=yes'
153194
DB_PASSWORD: $(DB_PASSWORD)
154195
155196
- task: PublishTestResults@2
@@ -1474,3 +1515,79 @@ jobs:
14741515
inputs:
14751516
testResultsFiles: '**/test-results-alpine-arm64.xml'
14761517
testRunTitle: 'Publish pytest results on Alpine ARM64'
1518+
1519+
- job: CodeCoverageReport
1520+
displayName: 'Full Code Coverage Report in Ubuntu x86_64'
1521+
pool:
1522+
vmImage: 'ubuntu-latest'
1523+
1524+
steps:
1525+
- script: |
1526+
# Install build dependencies
1527+
sudo apt-get update
1528+
sudo apt-get install -y cmake gcc g++ lcov unixodbc-dev llvm clang
1529+
displayName: 'Install build dependencies'
1530+
1531+
- script: |
1532+
# Start SQL Server container
1533+
docker pull mcr.microsoft.com/mssql/server:2022-latest
1534+
docker run \
1535+
--name sqlserver \
1536+
-e ACCEPT_EULA=Y \
1537+
-e MSSQL_SA_PASSWORD="$(DB_PASSWORD)" \
1538+
-p 1433:1433 \
1539+
-d mcr.microsoft.com/mssql/server:2022-latest
1540+
1541+
# Wait until SQL Server is ready
1542+
for i in {1..30}; do
1543+
docker exec sqlserver \
1544+
/opt/mssql-tools18/bin/sqlcmd \
1545+
-S localhost \
1546+
-U SA \
1547+
-P "$(DB_PASSWORD)" \
1548+
-C -Q "SELECT 1" && break
1549+
sleep 2
1550+
done
1551+
displayName: 'Start SQL Server container'
1552+
env:
1553+
DB_PASSWORD: $(DB_PASSWORD)
1554+
1555+
- script: |
1556+
# Install Python dependencies
1557+
python -m pip install --upgrade pip
1558+
pip install -r requirements.txt
1559+
pip install coverage-lcov lcov-cobertura
1560+
displayName: 'Install Python dependencies'
1561+
1562+
- script: |
1563+
# Build pybind bindings with coverage instrumentation
1564+
cd mssql_python/pybind
1565+
./build.sh codecov
1566+
displayName: 'Build pybind bindings with coverage'
1567+
1568+
- script: |
1569+
# Generate unified coverage (Python + C++)
1570+
chmod +x ./generate_codecov.sh
1571+
./generate_codecov.sh
1572+
1573+
# Convert unified LCOV to Cobertura XML for ADO reporting
1574+
lcov_cobertura total.info --output unified-coverage/coverage.xml
1575+
displayName: 'Generate unified coverage (Python + C++)'
1576+
env:
1577+
DB_CONNECTION_STRING: 'Driver=ODBC Driver 18 for SQL Server;Server=tcp:127.0.0.1,1433;Database=master;Uid=SA;Pwd=$(DB_PASSWORD);TrustServerCertificate=yes'
1578+
DB_PASSWORD: $(DB_PASSWORD)
1579+
1580+
- task: PublishTestResults@2
1581+
condition: succeededOrFailed()
1582+
inputs:
1583+
testResultsFiles: '**/test-results.xml'
1584+
testRunTitle: 'Publish pytest results with unified coverage'
1585+
1586+
- task: PublishCodeCoverageResults@2
1587+
condition: succeededOrFailed()
1588+
inputs:
1589+
codeCoverageTool: Cobertura
1590+
summaryFileLocation: 'unified-coverage/coverage.xml'
1591+
reportDirectory: 'unified-coverage'
1592+
failIfCoverageEmpty: true
1593+
displayName: 'Publish unified code coverage results'

0 commit comments

Comments
 (0)