fastmssql 0.3.0__cp310-cp310-win_amd64.whl → 0.3.3__cp310-cp310-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of fastmssql might be problematic. Click here for more details.
- fastmssql/__init__.py +261 -0
- fastmssql/fastmssql.cp310-win_amd64.pyd +0 -0
- fastmssql-0.3.3.dist-info/METADATA +393 -0
- fastmssql-0.3.3.dist-info/RECORD +6 -0
- fastmssql-0.3.0.dist-info/METADATA +0 -803
- fastmssql-0.3.0.dist-info/RECORD +0 -6
- {fastmssql-0.3.0.dist-info → fastmssql-0.3.3.dist-info}/WHEEL +0 -0
- {fastmssql-0.3.0.dist-info → fastmssql-0.3.3.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,803 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: fastmssql
|
|
3
|
-
Version: 0.3.0
|
|
4
|
-
Classifier: Development Status :: 4 - Beta
|
|
5
|
-
Classifier: Intended Audience :: Developers
|
|
6
|
-
Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
|
|
7
|
-
Classifier: Programming Language :: Python :: 3
|
|
8
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
9
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
10
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
11
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
-
Classifier: Programming Language :: Python :: 3.13
|
|
14
|
-
Classifier: Programming Language :: Rust
|
|
15
|
-
Classifier: Topic :: Database
|
|
16
|
-
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
17
|
-
Requires-Dist: pytest>=7.0 ; extra == 'dev'
|
|
18
|
-
Requires-Dist: pytest-asyncio>=0.21 ; extra == 'dev'
|
|
19
|
-
Requires-Dist: psutil>=5.9.0 ; extra == 'dev'
|
|
20
|
-
Provides-Extra: dev
|
|
21
|
-
License-File: LICENSE
|
|
22
|
-
Summary: A high-performance Python library for Microsoft SQL Server using Rust and Tiberius
|
|
23
|
-
Author-email: Riveranda <riverb514@gmail.com>
|
|
24
|
-
License: GPL-3.0-or-later OR Commercial
|
|
25
|
-
Requires-Python: >=3.8
|
|
26
|
-
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
27
|
-
Project-URL: Homepage, https://github.com/Rivendael/pymssql-rs
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
# Fastmssql ⚡
|
|
31
|
-
|
|
32
|
-
A Python library for Microsoft SQL Server built with Rust using the [Tiberius](https://github.com/prisma/tiberius) driver, [PyO3](https://github.com/PyO3/pyo3), and [bb8](https://github.com/djc/bb8) connection pooling.
|
|
33
|
-
|
|
34
|
-
[](https://github.com/Rivendael/pymssql-rs)
|
|
35
|
-
[](https://github.com/Rivendael/pymssql-rs)
|
|
36
|
-
[](https://github.com/Rivendael/pymssql-rs)
|
|
37
|
-
|
|
38
|
-
## Features
|
|
39
|
-
|
|
40
|
-
- **High Performance**: Exceptional throughput with 17,800+ RPS capability
|
|
41
|
-
- **Rust-Powered Backend**: Built with Rust for memory safety and reliability
|
|
42
|
-
- **No ODBC Required**: Direct native SQL Server connection without ODBC drivers
|
|
43
|
-
- **Connection Pooling**: Intelligent bb8-based connection pooling (default: 75 max, 25 min idle)
|
|
44
|
-
- **Async-Only Design**: Built on Tokio with clean async/await API
|
|
45
|
-
- **Context Managers**: Automatic resource management with `async with`
|
|
46
|
-
- **Type Safety**: Strong typing with automatic Python type conversion
|
|
47
|
-
- **Thread Safety**: Support for concurrent operations
|
|
48
|
-
- **Cross-Platform**: Works on Windows, macOS, and Linux
|
|
49
|
-
- **Simple API**: Clean, intuitive async-only interface with separate `query()` and `execute()` methods
|
|
50
|
-
|
|
51
|
-
## Key API Methods
|
|
52
|
-
|
|
53
|
-
FastMSSQL provides two distinct methods for database operations:
|
|
54
|
-
|
|
55
|
-
- **`query()`** - For SELECT statements that return rows
|
|
56
|
-
- **`execute()`** - For INSERT/UPDATE/DELETE statements that return affected row count
|
|
57
|
-
|
|
58
|
-
```python
|
|
59
|
-
# Use query() for SELECT statements
|
|
60
|
-
result = await conn.query("SELECT * FROM users WHERE age > @P1", [25])
|
|
61
|
-
rows = result.rows()
|
|
62
|
-
|
|
63
|
-
# Use execute() for data modification
|
|
64
|
-
affected = await conn.execute("INSERT INTO users (name) VALUES (@P1)", ["John"])
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
## Performance Highlights
|
|
68
|
-
|
|
69
|
-
Fastmssql delivers exceptional database performance through Rust-powered architecture:
|
|
70
|
-
|
|
71
|
-
- **Outstanding Throughput**: Up to **17,800+ RPS** with multiple connection pattern
|
|
72
|
-
- **High Performance**: **5,000+ RPS** with single connection (default usage)
|
|
73
|
-
- **Low Latency**: ~2ms average query latency under high load
|
|
74
|
-
- **Scalable Architecture**: Linear scaling with multiple connection objects
|
|
75
|
-
- **Production Ready**: Stable API with comprehensive error handling
|
|
76
|
-
- **Connection Pooling**: Efficient resource management with configurable pools
|
|
77
|
-
- **Type Conversion**: Automatic conversion between SQL Server and Python types
|
|
78
|
-
- **SSL/TLS Support**: Secure connections with flexible encryption options
|
|
79
|
-
|
|
80
|
-
### Performance Benchmarks
|
|
81
|
-
|
|
82
|
-
| Pattern | RPS | Configuration | Use Case |
|
|
83
|
-
|---------|-----|---------------|----------|
|
|
84
|
-
| Single Connection (Default) | **5,000+** | Default pool (75/25) | Standard applications |
|
|
85
|
-
| Multiple Connections | **17,800+** | 50 workers, high_throughput() | High-concurrency scenarios |
|
|
86
|
-
| Conservative Load | 3,500+ | Shared connection | Traditional pooling |
|
|
87
|
-
|
|
88
|
-
**Benchmark Environment:**
|
|
89
|
-
- Database: SQL Server (local instance)
|
|
90
|
-
- Query: `SELECT 1` (minimal overhead)
|
|
91
|
-
- Test Duration: 15-30 seconds per test
|
|
92
|
-
- Hardware: Modern development machine
|
|
93
|
-
|
|
94
|
-
**Key Performance Insights:**
|
|
95
|
-
1. **Multiple Connection Objects**: Creating separate `Connection()` objects eliminates serialization bottlenecks
|
|
96
|
-
2. **Pool Configuration**: Use `PoolConfig.high_throughput()` for demanding workloads
|
|
97
|
-
3. **Optimal Worker Count**: 30-50 concurrent workers provides best throughput
|
|
98
|
-
4. **Tokio Optimization**: Aggressive threading configuration maximizes async performance
|
|
99
|
-
|
|
100
|
-
## Installation
|
|
101
|
-
|
|
102
|
-
### From PyPI (Recommended)
|
|
103
|
-
|
|
104
|
-
Install fastmssql using pip:
|
|
105
|
-
|
|
106
|
-
```bash
|
|
107
|
-
pip install fastmssql
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
### Prerequisites
|
|
111
|
-
|
|
112
|
-
- Python 3.8 to 3.13
|
|
113
|
-
- Microsoft SQL Server (any recent version)
|
|
114
|
-
|
|
115
|
-
### From Source (Development)
|
|
116
|
-
Ensure you have Docker, Rust, and Python installed.
|
|
117
|
-
If you want to build from source or contribute to development:
|
|
118
|
-
|
|
119
|
-
1. Clone the repository:
|
|
120
|
-
```bash
|
|
121
|
-
git clone <your-repo-url>
|
|
122
|
-
cd mssql-python-rust
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
2. Run the setup script
|
|
126
|
-
```
|
|
127
|
-
./setup.sh
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
## Quick Start
|
|
131
|
-
|
|
132
|
-
### Basic Async Usage (Recommended)
|
|
133
|
-
|
|
134
|
-
```python
|
|
135
|
-
import asyncio
|
|
136
|
-
from fastmssql import Connection
|
|
137
|
-
|
|
138
|
-
async def main():
|
|
139
|
-
# Connect to SQL Server using async context manager
|
|
140
|
-
connection_string = "Server=localhost;Database=master;User Id=myuser;Password=mypass"
|
|
141
|
-
|
|
142
|
-
# Automatic connection pool management
|
|
143
|
-
async with Connection(connection_string) as conn:
|
|
144
|
-
# Use query() for SELECT statements that return rows
|
|
145
|
-
result = await conn.query("SELECT @@VERSION as version")
|
|
146
|
-
rows = result.rows()
|
|
147
|
-
for row in rows:
|
|
148
|
-
print(row['version'])
|
|
149
|
-
|
|
150
|
-
# Pool statistics
|
|
151
|
-
stats = conn.pool_stats()
|
|
152
|
-
print(f"Pool: {stats['active_connections']}/{stats['connections']} connections active")
|
|
153
|
-
|
|
154
|
-
asyncio.run(main())
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
### Connection Methods
|
|
158
|
-
|
|
159
|
-
The library supports two ways to connect to SQL Server:
|
|
160
|
-
|
|
161
|
-
#### 1. Connection String (Traditional)
|
|
162
|
-
|
|
163
|
-
```python
|
|
164
|
-
import asyncio
|
|
165
|
-
from fastmssql import Connection
|
|
166
|
-
|
|
167
|
-
async def main():
|
|
168
|
-
# Traditional connection string approach
|
|
169
|
-
connection_string = "Server=localhost;Database=master;User Id=myuser;Password=mypass"
|
|
170
|
-
|
|
171
|
-
async with Connection(connection_string=connection_string) as conn:
|
|
172
|
-
# Use query() for SELECT statements that return rows
|
|
173
|
-
result = await conn.query("SELECT @@VERSION as version")
|
|
174
|
-
rows = result.rows()
|
|
175
|
-
for row in rows:
|
|
176
|
-
print(row['version'])
|
|
177
|
-
|
|
178
|
-
asyncio.run(main())
|
|
179
|
-
```
|
|
180
|
-
|
|
181
|
-
#### 2. Individual Parameters
|
|
182
|
-
|
|
183
|
-
```python
|
|
184
|
-
import asyncio
|
|
185
|
-
from fastmssql import Connection
|
|
186
|
-
|
|
187
|
-
async def main():
|
|
188
|
-
# Using individual connection parameters
|
|
189
|
-
|
|
190
|
-
# SQL Server Authentication
|
|
191
|
-
async with Connection(
|
|
192
|
-
server="localhost",
|
|
193
|
-
database="master",
|
|
194
|
-
username="myuser",
|
|
195
|
-
password="mypassword"
|
|
196
|
-
) as conn:
|
|
197
|
-
# Use query() for SELECT statements that return rows
|
|
198
|
-
result = await conn.query("SELECT SUSER_NAME() as login")
|
|
199
|
-
rows = result.rows()
|
|
200
|
-
for row in rows:
|
|
201
|
-
print(f"Logged in as: {row['login']}")
|
|
202
|
-
|
|
203
|
-
asyncio.run(main())
|
|
204
|
-
```
|
|
205
|
-
|
|
206
|
-
### Performance Patterns
|
|
207
|
-
|
|
208
|
-
For maximum performance in high-concurrency scenarios, create multiple Connection objects:
|
|
209
|
-
|
|
210
|
-
```python
|
|
211
|
-
import asyncio
|
|
212
|
-
from fastmssql import Connection, PoolConfig
|
|
213
|
-
|
|
214
|
-
async def high_performance_pattern():
|
|
215
|
-
"""Optimal pattern for maximum throughput."""
|
|
216
|
-
connection_string = "Server=localhost;Database=master;User Id=myuser;Password=mypass"
|
|
217
|
-
config = PoolConfig.high_throughput() # Optimized settings
|
|
218
|
-
|
|
219
|
-
async def worker():
|
|
220
|
-
# Each worker gets its own Connection object for maximum throughput
|
|
221
|
-
async with Connection(connection_string, pool_config=config) as conn:
|
|
222
|
-
for _ in range(1000):
|
|
223
|
-
# Use query() for SELECT statements that return rows
|
|
224
|
-
result = await conn.query("SELECT data FROM my_table WHERE id = @P1", [123])
|
|
225
|
-
rows = result.rows()
|
|
226
|
-
# Process results...
|
|
227
|
-
|
|
228
|
-
# Launch multiple workers - each with their own connection
|
|
229
|
-
workers = [asyncio.create_task(worker()) for _ in range(50)]
|
|
230
|
-
await asyncio.gather(*workers)
|
|
231
|
-
|
|
232
|
-
# This pattern can achieve 17,800+ RPS
|
|
233
|
-
|
|
234
|
-
asyncio.run(high_performance_pattern())
|
|
235
|
-
```
|
|
236
|
-
|
|
237
|
-
**Key Performance Insight**: While a single Connection object provides excellent performance (5,000+ RPS),
|
|
238
|
-
creating multiple Connection objects eliminates serialization bottlenecks and can achieve 17,800+ RPS
|
|
239
|
-
for maximum throughput scenarios.
|
|
240
|
-
|
|
241
|
-
### Connection Pool Configuration
|
|
242
|
-
|
|
243
|
-
Configure the connection pool for your specific needs:
|
|
244
|
-
|
|
245
|
-
```python
|
|
246
|
-
import asyncio
|
|
247
|
-
from fastmssql import Connection, PoolConfig
|
|
248
|
-
|
|
249
|
-
async def main():
|
|
250
|
-
# Custom pool configuration
|
|
251
|
-
pool_config = PoolConfig(
|
|
252
|
-
max_size=20, # Maximum connections in pool
|
|
253
|
-
min_idle=5, # Minimum idle connections
|
|
254
|
-
max_lifetime_secs=3600, # Connection max lifetime (1 hour)
|
|
255
|
-
idle_timeout_secs=600, # Idle connection timeout (10 min)
|
|
256
|
-
connection_timeout_secs=30 # Max wait time for connection
|
|
257
|
-
)
|
|
258
|
-
|
|
259
|
-
async with Connection(connection_string, pool_config) as conn:
|
|
260
|
-
# Use query() for SELECT statements that return rows
|
|
261
|
-
result = await conn.query("SELECT * FROM users")
|
|
262
|
-
rows = result.rows()
|
|
263
|
-
for row in rows:
|
|
264
|
-
print(f"User: {row['name']}")
|
|
265
|
-
|
|
266
|
-
# Predefined configurations for different scenarios
|
|
267
|
-
high_throughput_config = PoolConfig.high_throughput() # 100 connections, optimized for high RPS
|
|
268
|
-
maximum_performance = PoolConfig.maximum_performance() # 150 connections, optimized for peak load
|
|
269
|
-
low_resource_config = PoolConfig.low_resource() # 3 connections, minimal resources
|
|
270
|
-
dev_config = PoolConfig.development() # 5 connections, shorter timeouts
|
|
271
|
-
|
|
272
|
-
# Default configuration is optimized for high performance
|
|
273
|
-
# Default: max_size=75, min_idle=25 - ready for production workloads
|
|
274
|
-
|
|
275
|
-
# For maximum throughput, use multiple Connection objects:
|
|
276
|
-
async def high_perf_worker():
|
|
277
|
-
async with Connection(connection_string, maximum_performance) as conn:
|
|
278
|
-
# Use query() for SELECT statements that return rows
|
|
279
|
-
result = await conn.query("SELECT * FROM fast_table")
|
|
280
|
-
return result.rows()
|
|
281
|
-
|
|
282
|
-
# Each worker gets its own connection for optimal performance
|
|
283
|
-
tasks = [asyncio.create_task(high_perf_worker()) for _ in range(50)]
|
|
284
|
-
results = await asyncio.gather(*tasks)
|
|
285
|
-
|
|
286
|
-
asyncio.run(main())
|
|
287
|
-
```
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
### Connection Strings
|
|
292
|
-
|
|
293
|
-
The library supports standard SQL Server connection string formats:
|
|
294
|
-
|
|
295
|
-
```python
|
|
296
|
-
# SQL Server Authentication
|
|
297
|
-
conn_str = "Server=localhost;Database=MyDB;User Id=sa;Password=MyPassword"
|
|
298
|
-
|
|
299
|
-
# With specific port
|
|
300
|
-
conn_str = "Server=localhost,1433;Database=MyDB;User Id=myuser;Password=mypass"
|
|
301
|
-
|
|
302
|
-
# Azure SQL Database
|
|
303
|
-
conn_str = "Server=tcp:myserver.database.windows.net,1433;Database=MyDB;User Id=myuser;Password=mypass;Encrypt=true"
|
|
304
|
-
```
|
|
305
|
-
|
|
306
|
-
### Working with Data
|
|
307
|
-
|
|
308
|
-
```python
|
|
309
|
-
import asyncio
|
|
310
|
-
from fastmssql import Connection
|
|
311
|
-
|
|
312
|
-
async def main():
|
|
313
|
-
async with Connection(connection_string) as conn:
|
|
314
|
-
# === SELECT QUERIES - Use query() method (returns rows) ===
|
|
315
|
-
result = await conn.query("SELECT id, name, email FROM users WHERE active = 1")
|
|
316
|
-
rows = result.rows()
|
|
317
|
-
|
|
318
|
-
# Iterate through results
|
|
319
|
-
for row in rows:
|
|
320
|
-
print(f"User {row['id']}: {row['name']} ({row['email']})")
|
|
321
|
-
|
|
322
|
-
# === DATA MODIFICATION - Use execute() method (returns affected row count) ===
|
|
323
|
-
# INSERT operation
|
|
324
|
-
rows_affected = await conn.execute(
|
|
325
|
-
"INSERT INTO users (name, email, active) VALUES (@P1, @P2, @P3)",
|
|
326
|
-
["John Doe", "john@example.com", 1]
|
|
327
|
-
)
|
|
328
|
-
print(f"Inserted {rows_affected} row(s)")
|
|
329
|
-
|
|
330
|
-
# UPDATE operation
|
|
331
|
-
rows_affected = await conn.execute(
|
|
332
|
-
"UPDATE users SET last_login = GETDATE() WHERE id = @P1",
|
|
333
|
-
[123]
|
|
334
|
-
)
|
|
335
|
-
print(f"Updated {rows_affected} row(s)")
|
|
336
|
-
|
|
337
|
-
# DELETE operation
|
|
338
|
-
rows_affected = await conn.execute(
|
|
339
|
-
"DELETE FROM users WHERE active = 0 AND last_login < DATEADD(year, -1, GETDATE())"
|
|
340
|
-
)
|
|
341
|
-
print(f"Deleted {rows_affected} inactive users")
|
|
342
|
-
|
|
343
|
-
# === WORKING WITH DIFFERENT DATA TYPES ===
|
|
344
|
-
result = await conn.query("""
|
|
345
|
-
SELECT
|
|
346
|
-
42 as int_value,
|
|
347
|
-
3.14159 as float_value,
|
|
348
|
-
'Hello World' as string_value,
|
|
349
|
-
GETDATE() as datetime_value,
|
|
350
|
-
CAST(1 as BIT) as bool_value,
|
|
351
|
-
NULL as null_value
|
|
352
|
-
""")
|
|
353
|
-
|
|
354
|
-
rows = result.rows()
|
|
355
|
-
if rows:
|
|
356
|
-
row = rows[0]
|
|
357
|
-
for column_name, value in row.items():
|
|
358
|
-
print(f"{column_name}: {value} (type: {type(value).__name__})")
|
|
359
|
-
|
|
360
|
-
asyncio.run(main())
|
|
361
|
-
```
|
|
362
|
-
|
|
363
|
-
## Usage
|
|
364
|
-
|
|
365
|
-
### Asynchronous Usage with Connection Pooling
|
|
366
|
-
|
|
367
|
-
Full async/await support with automatic connection pool management:
|
|
368
|
-
|
|
369
|
-
```python
|
|
370
|
-
import asyncio
|
|
371
|
-
from fastmssql import Connection
|
|
372
|
-
|
|
373
|
-
async def main():
|
|
374
|
-
connection_string = "Server=localhost;Database=test;Integrated Security=true"
|
|
375
|
-
|
|
376
|
-
# Async context manager with automatic pool management
|
|
377
|
-
async with Connection(connection_string) as conn:
|
|
378
|
-
# Use query() for SELECT statements that return rows
|
|
379
|
-
result = await conn.query("SELECT name FROM sys.databases")
|
|
380
|
-
rows = result.rows()
|
|
381
|
-
for row in rows:
|
|
382
|
-
print(row['name'])
|
|
383
|
-
|
|
384
|
-
# Pool statistics
|
|
385
|
-
stats = conn.pool_stats()
|
|
386
|
-
print(f"Pool: {stats['active_connections']}/{stats['connections']} connections active")
|
|
387
|
-
|
|
388
|
-
# High-performance concurrent operations
|
|
389
|
-
async def fetch_user_data(user_id):
|
|
390
|
-
async with Connection(connection_string) as conn:
|
|
391
|
-
# Use query() for SELECT statements that return rows
|
|
392
|
-
result = await conn.query(f"SELECT * FROM users WHERE id = {user_id}")
|
|
393
|
-
return result.rows()
|
|
394
|
-
|
|
395
|
-
# Execute multiple queries concurrently using the connection pool
|
|
396
|
-
user_ids = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
|
397
|
-
tasks = [fetch_user_data(uid) for uid in user_ids]
|
|
398
|
-
results = await asyncio.gather(*tasks) # bb8 pool handles concurrent connections efficiently
|
|
399
|
-
|
|
400
|
-
for user_data in results:
|
|
401
|
-
if user_data:
|
|
402
|
-
print(f"User: {user_data[0]['name']}")
|
|
403
|
-
|
|
404
|
-
asyncio.run(main())
|
|
405
|
-
```
|
|
406
|
-
|
|
407
|
-
## Development
|
|
408
|
-
|
|
409
|
-
### Building from Source
|
|
410
|
-
|
|
411
|
-
```bash
|
|
412
|
-
# Install development dependencies
|
|
413
|
-
pip install maturin pytest pytest-asyncio black ruff
|
|
414
|
-
|
|
415
|
-
# Build in development mode
|
|
416
|
-
maturin develop
|
|
417
|
-
|
|
418
|
-
# Run tests
|
|
419
|
-
python -m pytest tests/
|
|
420
|
-
|
|
421
|
-
# Format code
|
|
422
|
-
black python/
|
|
423
|
-
ruff check python/
|
|
424
|
-
```
|
|
425
|
-
|
|
426
|
-
### Project Structure
|
|
427
|
-
|
|
428
|
-
```
|
|
429
|
-
mssql-python-rust/
|
|
430
|
-
├── src/ # Rust source code
|
|
431
|
-
│ ├── lib.rs # Main library entry point
|
|
432
|
-
│ ├── connection.rs # Connection handling
|
|
433
|
-
│ ├── query.rs # Query execution
|
|
434
|
-
│ └── types.rs # Type definitions
|
|
435
|
-
├── python/ # Python source code
|
|
436
|
-
│ ├── __init__.py # Main Python module
|
|
437
|
-
│ ├── mssql.py # High-level API
|
|
438
|
-
│ └── types.py # Python type definitions
|
|
439
|
-
├── examples/ # Usage examples
|
|
440
|
-
├── tests/ # Test files
|
|
441
|
-
├── Cargo.toml # Rust dependencies
|
|
442
|
-
├── pyproject.toml # Python project configuration
|
|
443
|
-
└── README.md # This file
|
|
444
|
-
```
|
|
445
|
-
|
|
446
|
-
### Testing
|
|
447
|
-
|
|
448
|
-
Run the examples to test your installation:
|
|
449
|
-
|
|
450
|
-
```bash
|
|
451
|
-
# Basic functionality
|
|
452
|
-
python examples/basic_usage.py
|
|
453
|
-
|
|
454
|
-
# Advanced features
|
|
455
|
-
python examples/advanced_usage.py
|
|
456
|
-
```
|
|
457
|
-
|
|
458
|
-
## API Reference
|
|
459
|
-
|
|
460
|
-
### Query vs Execute Methods
|
|
461
|
-
|
|
462
|
-
FastMSSQL provides two distinct methods for database operations:
|
|
463
|
-
|
|
464
|
-
- **`query()`** - For SELECT statements that return rows
|
|
465
|
-
- Returns a `QueryResult` object with a `rows()` method
|
|
466
|
-
- Use for retrieving data from the database
|
|
467
|
-
|
|
468
|
-
- **`execute()`** - For INSERT, UPDATE, DELETE statements
|
|
469
|
-
- Returns the number of affected rows as an integer
|
|
470
|
-
- Use for modifying data in the database
|
|
471
|
-
|
|
472
|
-
**SQL Server Parameter Syntax**: Use positional parameters `@P1`, `@P2`, `@P3`, etc.
|
|
473
|
-
|
|
474
|
-
```python
|
|
475
|
-
# SELECT queries - use query()
|
|
476
|
-
result = await conn.query("SELECT * FROM users WHERE age > @P1 AND city = @P2", [25, "New York"])
|
|
477
|
-
rows = result.rows()
|
|
478
|
-
|
|
479
|
-
# INSERT/UPDATE/DELETE - use execute()
|
|
480
|
-
affected = await conn.execute("INSERT INTO users (name, email) VALUES (@P1, @P2)", ["John", "john@example.com"])
|
|
481
|
-
```
|
|
482
|
-
|
|
483
|
-
### Core Classes
|
|
484
|
-
|
|
485
|
-
#### `Connection`
|
|
486
|
-
Main connection class with bb8 connection pool management.
|
|
487
|
-
|
|
488
|
-
**Constructor:**
|
|
489
|
-
```python
|
|
490
|
-
Connection(connection_string: str, pool_config: Optional[PoolConfig] = None)
|
|
491
|
-
```
|
|
492
|
-
|
|
493
|
-
**Context Manager Support:**
|
|
494
|
-
```python
|
|
495
|
-
# Asynchronous (recommended)
|
|
496
|
-
async with Connection(conn_str) as conn:
|
|
497
|
-
# Use query() for SELECT statements
|
|
498
|
-
result = await conn.query("SELECT * FROM table")
|
|
499
|
-
rows = result.rows()
|
|
500
|
-
|
|
501
|
-
# Use execute() for INSERT/UPDATE/DELETE statements
|
|
502
|
-
affected = await conn.execute("INSERT INTO table (col) VALUES (@P1)", ["value"])
|
|
503
|
-
```
|
|
504
|
-
```
|
|
505
|
-
|
|
506
|
-
**Methods:**
|
|
507
|
-
- `query(sql: str, params: Optional[List] = None) -> QueryResult` - Execute SELECT queries that return rows
|
|
508
|
-
- `execute(sql: str, params: Optional[List] = None) -> int` - Execute INSERT/UPDATE/DELETE statements, returns affected row count
|
|
509
|
-
- `pool_stats() -> dict` - Get connection pool statistics
|
|
510
|
-
- `disconnect()` - Close the connection pool
|
|
511
|
-
- `is_connected() -> bool` - Check if pool is active
|
|
512
|
-
|
|
513
|
-
**Method Details:**
|
|
514
|
-
|
|
515
|
-
`query()` - For SELECT statements that return data:
|
|
516
|
-
```python
|
|
517
|
-
# Returns a QueryResult object with rows() method
|
|
518
|
-
result = await conn.query("SELECT * FROM users WHERE age > @P1", [21])
|
|
519
|
-
rows = result.rows()
|
|
520
|
-
for row in rows:
|
|
521
|
-
print(row['name'])
|
|
522
|
-
```
|
|
523
|
-
|
|
524
|
-
`execute()` - For INSERT/UPDATE/DELETE statements:
|
|
525
|
-
```python
|
|
526
|
-
# Returns the number of affected rows
|
|
527
|
-
affected = await conn.execute("INSERT INTO users (name) VALUES (@P1)", ["John"])
|
|
528
|
-
print(f"Inserted {affected} row(s)")
|
|
529
|
-
|
|
530
|
-
affected = await conn.execute("UPDATE users SET age = @P1 WHERE name = @P2", [25, "John"])
|
|
531
|
-
print(f"Updated {affected} row(s)")
|
|
532
|
-
```
|
|
533
|
-
|
|
534
|
-
**Pool Statistics:**
|
|
535
|
-
```python
|
|
536
|
-
stats = conn.pool_stats()
|
|
537
|
-
# Returns: {
|
|
538
|
-
# 'connections': 10, # Total connections in pool
|
|
539
|
-
# 'active_connections': 3, # Currently active connections
|
|
540
|
-
# 'idle_connections': 7 # Available idle connections
|
|
541
|
-
# }
|
|
542
|
-
```
|
|
543
|
-
|
|
544
|
-
#### `PoolConfig`
|
|
545
|
-
Configuration class for bb8 connection pool settings.
|
|
546
|
-
|
|
547
|
-
**Constructor:**
|
|
548
|
-
```python
|
|
549
|
-
PoolConfig(
|
|
550
|
-
max_size: int = 10, # Maximum connections in pool
|
|
551
|
-
min_idle: int = 0, # Minimum idle connections
|
|
552
|
-
max_lifetime_secs: Optional[int] = None, # Connection max lifetime
|
|
553
|
-
idle_timeout_secs: Optional[int] = None, # Idle connection timeout
|
|
554
|
-
connection_timeout_secs: int = 30 # Max wait time for connection
|
|
555
|
-
)
|
|
556
|
-
```
|
|
557
|
-
|
|
558
|
-
**Predefined Configurations:**
|
|
559
|
-
```python
|
|
560
|
-
# High throughput applications (web servers, APIs)
|
|
561
|
-
config = PoolConfig.high_throughput() # 20 connections, optimized settings
|
|
562
|
-
|
|
563
|
-
# Low resource environments (embedded, containers)
|
|
564
|
-
config = PoolConfig.low_resource() # 3 connections, minimal overhead
|
|
565
|
-
|
|
566
|
-
# Development environments
|
|
567
|
-
config = PoolConfig.development() # 5 connections, shorter timeouts
|
|
568
|
-
```
|
|
569
|
-
|
|
570
|
-
#### `Row`
|
|
571
|
-
Represents a database row with column access.
|
|
572
|
-
|
|
573
|
-
**Methods:**
|
|
574
|
-
- `get(column: str) -> Value` - Get value by column name
|
|
575
|
-
- `get_by_index(index: int) -> Value` - Get value by column index
|
|
576
|
-
- `columns() -> List[str]` - Get column names
|
|
577
|
-
- `values() -> List[Value]` - Get all values
|
|
578
|
-
- `to_dict() -> dict` - Convert to dictionary
|
|
579
|
-
|
|
580
|
-
### Module Functions
|
|
581
|
-
|
|
582
|
-
#### Connection Management
|
|
583
|
-
```python
|
|
584
|
-
# Create connection with connection pooling
|
|
585
|
-
Connection(connection_string: str, pool_config: Optional[PoolConfig] = None) -> Connection
|
|
586
|
-
|
|
587
|
-
# Usage with async context manager (recommended)
|
|
588
|
-
async with Connection(connection_string) as conn:
|
|
589
|
-
# Use query() for SELECT statements that return rows
|
|
590
|
-
result = await conn.query("SELECT * FROM users")
|
|
591
|
-
rows = result.rows()
|
|
592
|
-
|
|
593
|
-
# Use execute() for INSERT/UPDATE/DELETE statements that return affected count
|
|
594
|
-
affected = await conn.execute("INSERT INTO users (name) VALUES (@P1)", ["John"])
|
|
595
|
-
```
|
|
596
|
-
|
|
597
|
-
#### Utility Functions
|
|
598
|
-
```python
|
|
599
|
-
version() -> str # Get library version
|
|
600
|
-
```
|
|
601
|
-
|
|
602
|
-
### Connection Pool Architecture
|
|
603
|
-
|
|
604
|
-
The library uses the bb8 connection pool for efficient resource management:
|
|
605
|
-
|
|
606
|
-
1. **Pool Initialization**: Creates a pool of reusable connections on first use
|
|
607
|
-
2. **Connection Reuse**: Automatically reuses idle connections for new requests
|
|
608
|
-
3. **Load Balancing**: Distributes connections across concurrent operations
|
|
609
|
-
4. **Automatic Cleanup**: Closes idle connections based on timeout settings
|
|
610
|
-
5. **Thread Safety**: Safe for use across multiple threads and async tasks
|
|
611
|
-
|
|
612
|
-
### Error Handling
|
|
613
|
-
|
|
614
|
-
```python
|
|
615
|
-
try:
|
|
616
|
-
async with mssql.connect_async(connection_string) as conn:
|
|
617
|
-
result = await conn.query("SELECT * FROM invalid_table")
|
|
618
|
-
rows = result.rows()
|
|
619
|
-
except Exception as e:
|
|
620
|
-
print(f"Database error: {e}")
|
|
621
|
-
# Connection automatically returned to pool even on error
|
|
622
|
-
```
|
|
623
|
-
|
|
624
|
-
## Migration to Async-Only Architecture
|
|
625
|
-
|
|
626
|
-
This library has been upgraded to use async-only operations with the bb8 connection pool for improved performance and reliability.
|
|
627
|
-
|
|
628
|
-
**Async-Only API:**
|
|
629
|
-
```python
|
|
630
|
-
# Async-only with automatic connection pooling
|
|
631
|
-
async with mssql.connect_async(conn_str) as conn:
|
|
632
|
-
result = await conn.query("SELECT * FROM table")
|
|
633
|
-
rows = result.rows()
|
|
634
|
-
|
|
635
|
-
# Pool statistics
|
|
636
|
-
stats = conn.pool_stats()
|
|
637
|
-
print(f"Pool utilization: {stats['active_connections']}/{stats['connections']}")
|
|
638
|
-
```
|
|
639
|
-
|
|
640
|
-
## Advanced Usage Patterns
|
|
641
|
-
|
|
642
|
-
### Custom Pool Configuration for Different Scenarios
|
|
643
|
-
|
|
644
|
-
```python
|
|
645
|
-
from fastmssql import Connection, PoolConfig
|
|
646
|
-
|
|
647
|
-
# High-load web application
|
|
648
|
-
web_config = PoolConfig(
|
|
649
|
-
max_size=50, # Handle many concurrent requests
|
|
650
|
-
min_idle=10, # Keep connections ready
|
|
651
|
-
max_lifetime_secs=1800, # 30 min connection lifetime
|
|
652
|
-
idle_timeout_secs=300, # 5 min idle timeout
|
|
653
|
-
connection_timeout_secs=10 # Fast timeout for web responses
|
|
654
|
-
)
|
|
655
|
-
|
|
656
|
-
# Batch processing application
|
|
657
|
-
batch_config = PoolConfig(
|
|
658
|
-
max_size=5, # Fewer connections
|
|
659
|
-
min_idle=2, # Always keep some ready
|
|
660
|
-
max_lifetime_secs=7200, # 2 hour lifetime for long operations
|
|
661
|
-
idle_timeout_secs=1800, # 30 min idle timeout
|
|
662
|
-
connection_timeout_secs=60 # Longer timeout for batch work
|
|
663
|
-
)
|
|
664
|
-
|
|
665
|
-
# Microservice with limited resources
|
|
666
|
-
micro_config = PoolConfig(
|
|
667
|
-
max_size=3, # Minimal connections
|
|
668
|
-
min_idle=1, # One always ready
|
|
669
|
-
max_lifetime_secs=3600, # 1 hour lifetime
|
|
670
|
-
idle_timeout_secs=600, # 10 min idle timeout
|
|
671
|
-
connection_timeout_secs=15 # Quick timeout
|
|
672
|
-
)
|
|
673
|
-
```
|
|
674
|
-
|
|
675
|
-
### Monitoring Pool Health
|
|
676
|
-
|
|
677
|
-
```python
|
|
678
|
-
async def monitor_database_pool():
|
|
679
|
-
"""Monitor connection pool health and performance"""
|
|
680
|
-
|
|
681
|
-
async with mssql.connect_async(connection_string) as conn:
|
|
682
|
-
while True:
|
|
683
|
-
stats = conn.pool_stats()
|
|
684
|
-
utilization = stats['active_connections'] / stats['connections'] * 100
|
|
685
|
-
|
|
686
|
-
print(f"Pool Utilization: {utilization:.1f}%")
|
|
687
|
-
print(f"Active: {stats['active_connections']}, Idle: {stats['idle_connections']}")
|
|
688
|
-
|
|
689
|
-
# Alert if pool utilization is too high
|
|
690
|
-
if utilization > 90:
|
|
691
|
-
print("WARNING: High pool utilization detected!")
|
|
692
|
-
|
|
693
|
-
await asyncio.sleep(30) # Check every 30 seconds
|
|
694
|
-
```
|
|
695
|
-
|
|
696
|
-
### Optimizing for Different Database Workloads
|
|
697
|
-
|
|
698
|
-
```python
|
|
699
|
-
# OLTP (Online Transaction Processing) - Many small, fast queries
|
|
700
|
-
oltp_config = PoolConfig.high_throughput()
|
|
701
|
-
async def oltp_operations():
|
|
702
|
-
async with mssql.connect_async(conn_str, oltp_config) as conn:
|
|
703
|
-
# Fast, concurrent transactions
|
|
704
|
-
tasks = [
|
|
705
|
-
conn.query("SELECT * FROM users WHERE id = @P1", [user_id])
|
|
706
|
-
for user_id in range(1, 101)
|
|
707
|
-
]
|
|
708
|
-
results = await asyncio.gather(*tasks)
|
|
709
|
-
|
|
710
|
-
# OLAP (Online Analytical Processing) - Fewer, longer-running queries
|
|
711
|
-
olap_config = PoolConfig.low_resource()
|
|
712
|
-
async def olap_operations():
|
|
713
|
-
async with mssql.connect_async(conn_str, olap_config) as conn:
|
|
714
|
-
# Long-running analytical queries
|
|
715
|
-
result = await conn.query("""
|
|
716
|
-
SELECT
|
|
717
|
-
DATE_TRUNC('quarter', order_date) as quarter,
|
|
718
|
-
SUM(total_amount) as total_revenue,
|
|
719
|
-
COUNT(*) as order_count
|
|
720
|
-
FROM orders
|
|
721
|
-
WHERE order_date >= '2024-01-01'
|
|
722
|
-
GROUP BY DATE_TRUNC('quarter', order_date)
|
|
723
|
-
ORDER BY quarter
|
|
724
|
-
""")
|
|
725
|
-
return result.rows()
|
|
726
|
-
```
|
|
727
|
-
|
|
728
|
-
## API Reference
|
|
729
|
-
|
|
730
|
-
### Common Issues
|
|
731
|
-
|
|
732
|
-
1. **Import Error**: Make sure you've built the extension with `maturin develop`
|
|
733
|
-
2. **Connection Fails**: Check your connection string and SQL Server configuration. Note that Windows authentication is not supported - use SQL Server authentication with username and password.
|
|
734
|
-
3. **Build Errors**: Ensure you have the Rust toolchain installed
|
|
735
|
-
4. **Build Issues**: Make sure you have the Microsoft Visual C++ Build Tools on Windows
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
## Contributing
|
|
739
|
-
|
|
740
|
-
Contributions are welcome! Please open an issue or submit a pull request for any enhancements or bug fixes.
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
## License
|
|
744
|
-
|
|
745
|
-
FastMSSQL is available under your choice of two licenses:
|
|
746
|
-
|
|
747
|
-
### Option 1: GNU General Public License v3.0 (GPL-3.0)
|
|
748
|
-
|
|
749
|
-
**Free for open source projects.** If you distribute your application, you must make your entire application open source under GPL-3.0.
|
|
750
|
-
|
|
751
|
-
### Option 2: Commercial License
|
|
752
|
-
|
|
753
|
-
**Paid license for proprietary applications.** Allows you to keep your application closed source. Contact riverb514@gmail.com for commercial licensing.
|
|
754
|
-
|
|
755
|
-
See the [LICENSE](LICENSE) file for full GPL-3.0 terms and commercial licensing details.
|
|
756
|
-
|
|
757
|
-
### Examples and Benchmarks
|
|
758
|
-
|
|
759
|
-
- **Examples Directory**: All files in the `examples/` directory are licensed under the MIT License. See `examples/LICENSE` for full terms.
|
|
760
|
-
- **Benchmarks Directory**: All files in the `benchmarks/` directory are licensed under the MIT License. See `licenses/MIT_LICENSE.txt` for full terms.
|
|
761
|
-
|
|
762
|
-
## Third-Party Attributions
|
|
763
|
-
|
|
764
|
-
This project includes and depends on third-party libraries licensed under the Apache License 2.0 and MIT License, as well as other open source licenses.
|
|
765
|
-
|
|
766
|
-
**Note:** Additional third-party libraries and their license information are listed in `licenses/NOTICE.txt`.
|
|
767
|
-
|
|
768
|
-
- [Tiberius](https://github.com/prisma/tiberius) (Apache License 2.0)
|
|
769
|
-
- [PyO3](https://github.com/PyO3/pyo3) (Apache License 2.0)
|
|
770
|
-
- [pyo3-asyncio](https://github.com/PyO3/pyo3-asyncio) (Apache License 2.0)
|
|
771
|
-
- [bb8](https://github.com/djc/bb8) (MIT or Apache License 2.0)
|
|
772
|
-
- [bb8-tiberius](https://github.com/prisma/tiberius) (Apache License 2.0)
|
|
773
|
-
- [tokio](https://github.com/tokio-rs/tokio) (MIT or Apache License 2.0)
|
|
774
|
-
- [tokio-util](https://github.com/tokio-rs/tokio) (MIT or Apache License 2.0)
|
|
775
|
-
- [futures](https://github.com/rust-lang/futures-rs) (MIT or Apache License 2.0)
|
|
776
|
-
- [serde](https://github.com/serde-rs/serde) (MIT or Apache License 2.0)
|
|
777
|
-
- [serde_json](https://github.com/serde-rs/json) (MIT or Apache License 2.0)
|
|
778
|
-
- [anyhow](https://github.com/dtolnay/anyhow) (MIT or Apache License 2.0)
|
|
779
|
-
- [chrono](https://github.com/chronotope/chrono) (MIT or Apache License 2.0)
|
|
780
|
-
- [uuid](https://github.com/uuid-rs/uuid) (MIT or Apache License 2.0)
|
|
781
|
-
- [tempfile](https://github.com/Stebalien/tempfile) (MIT or Apache License 2.0)
|
|
782
|
-
- [pytest](https://github.com/pytest-dev/pytest) (MIT License)
|
|
783
|
-
- [pytest-asyncio](https://github.com/pytest-dev/pytest-asyncio) (MIT License)
|
|
784
|
-
- [black](https://github.com/psf/black) (MIT License)
|
|
785
|
-
- [ruff](https://github.com/astral-sh/ruff) (MIT License)
|
|
786
|
-
- [maturin](https://github.com/PyO3/maturin) (Apache License 2.0 or MIT License)
|
|
787
|
-
- [Python](https://www.python.org/) and [asyncio](https://docs.python.org/3/library/asyncio.html) (Python Software Foundation License)
|
|
788
|
-
|
|
789
|
-
See the `licenses/NOTICE.txt` file for full attribution and copyright information.
|
|
790
|
-
The full text of the Apache License 2.0 is provided in the `licenses/APACHE_LICENSE_2.0.txt` file.
|
|
791
|
-
The full text of the MIT License is provided in the `licenses/MIT_LICENSE.txt` file.
|
|
792
|
-
|
|
793
|
-
## Acknowledgments
|
|
794
|
-
|
|
795
|
-
- [Tiberius](https://github.com/prisma/tiberius) - Rust SQL Server driver (Apache License 2.0)
|
|
796
|
-
- [PyO3](https://github.com/PyO3/pyo3) - Python bindings for Rust (Apache License 2.0)
|
|
797
|
-
- [pyo3-asyncio](https://github.com/PyO3/pyo3-asyncio) - Async bridge for PyO3 (Apache License 2.0)
|
|
798
|
-
- [pytest](https://github.com/pytest-dev/pytest) - Python testing framework (MIT License)
|
|
799
|
-
- [pytest-asyncio](https://github.com/pytest-dev/pytest-asyncio) - Async test support for pytest (MIT License)
|
|
800
|
-
- [black](https://github.com/psf/black) - Python code formatter (MIT License)
|
|
801
|
-
- [ruff](https://github.com/astral-sh/ruff) - Python linter (MIT License)
|
|
802
|
-
- [Python](https://www.python.org/) and [asyncio](https://docs.python.org/3/library/asyncio.html) - Python standard library (Python Software Foundation License)
|
|
803
|
-
- [Maturin](https://github.com/PyO3/maturin) - Build tool for Python extensions in Rust
|