fastmssql 0.2.7__cp310-cp310-win_amd64.whl → 0.3.2__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 +139 -104
- fastmssql/fastmssql.cp310-win_amd64.pyd +0 -0
- fastmssql-0.3.2.dist-info/METADATA +346 -0
- fastmssql-0.3.2.dist-info/RECORD +6 -0
- fastmssql-0.3.2.dist-info/licenses/LICENSE +675 -0
- fastmssql-0.2.7.dist-info/METADATA +0 -687
- fastmssql-0.2.7.dist-info/RECORD +0 -6
- fastmssql-0.2.7.dist-info/licenses/LICENSE +0 -139
- {fastmssql-0.2.7.dist-info → fastmssql-0.3.2.dist-info}/WHEEL +0 -0
fastmssql/__init__.py
CHANGED
|
@@ -23,18 +23,25 @@ Basic Usage (Async):
|
|
|
23
23
|
>>>
|
|
24
24
|
>>> async def main():
|
|
25
25
|
... async with Connection("Server=localhost;Database=test;Trusted_Connection=yes") as conn:
|
|
26
|
-
... #
|
|
27
|
-
... result = await conn.
|
|
26
|
+
... # SELECT queries - use query() method
|
|
27
|
+
... result = await conn.query("SELECT * FROM users")
|
|
28
28
|
... async for row in result:
|
|
29
29
|
... print(f"User: {row['name']}, Age: {row['age']}")
|
|
30
30
|
...
|
|
31
|
-
... # Parameterized query
|
|
32
|
-
... result = await conn.
|
|
31
|
+
... # Parameterized SELECT query
|
|
32
|
+
... result = await conn.query(
|
|
33
33
|
... "SELECT * FROM users WHERE age > @P1 AND city = @P2",
|
|
34
34
|
... [18, "New York"]
|
|
35
35
|
... )
|
|
36
36
|
... rows = await result.fetchall()
|
|
37
37
|
... print(f"Found {len(rows)} users")
|
|
38
|
+
...
|
|
39
|
+
... # INSERT/UPDATE/DELETE - use execute() method
|
|
40
|
+
... affected = await conn.execute(
|
|
41
|
+
... "INSERT INTO users (name, email, age) VALUES (@P1, @P2, @P3)",
|
|
42
|
+
... ["John Doe", "john@example.com", 30]
|
|
43
|
+
... )
|
|
44
|
+
... print(f"Inserted {affected} rows")
|
|
38
45
|
>>>
|
|
39
46
|
>>> asyncio.run(main())
|
|
40
47
|
|
|
@@ -42,11 +49,9 @@ Basic Usage (Sync):
|
|
|
42
49
|
>>> from fastmssql import Connection
|
|
43
50
|
>>>
|
|
44
51
|
>>> with Connection("Server=localhost;Database=test;Trusted_Connection=yes") as conn:
|
|
45
|
-
...
|
|
46
|
-
...
|
|
47
|
-
...
|
|
48
|
-
... )
|
|
49
|
-
... print(f"Active users: {result[0]['count']}")
|
|
52
|
+
... # For SELECT queries, you would typically use the async API
|
|
53
|
+
... # Sync usage is primarily for simple operations
|
|
54
|
+
... pass # Connection established and will be closed on exit
|
|
50
55
|
|
|
51
56
|
Advanced Configuration:
|
|
52
57
|
>>> from fastmssql import Connection, PoolConfig, SslConfig, EncryptionLevel
|
|
@@ -232,13 +237,19 @@ class Connection:
|
|
|
232
237
|
trusted_connection=trusted_connection
|
|
233
238
|
)
|
|
234
239
|
|
|
235
|
-
async def
|
|
240
|
+
async def query(self, query, parameters=None):
|
|
236
241
|
"""
|
|
237
|
-
Execute a SQL query
|
|
242
|
+
Execute a SQL query that returns rows (SELECT statements) asynchronously.
|
|
238
243
|
|
|
239
|
-
This method
|
|
240
|
-
|
|
241
|
-
|
|
244
|
+
This method is specifically designed for SELECT queries and other statements
|
|
245
|
+
that return result sets. It uses the optimized query() method internally
|
|
246
|
+
for maximum performance when fetching data.
|
|
247
|
+
|
|
248
|
+
Use this method for:
|
|
249
|
+
- SELECT statements
|
|
250
|
+
- Stored procedures that return result sets
|
|
251
|
+
- SHOW commands
|
|
252
|
+
- Any query that returns tabular data
|
|
242
253
|
|
|
243
254
|
Parameter Binding:
|
|
244
255
|
Parameters are bound using positional placeholders (@P1, @P2, etc.) in the
|
|
@@ -258,7 +269,7 @@ class Connection:
|
|
|
258
269
|
- uuid.UUID (uniqueidentifier)
|
|
259
270
|
|
|
260
271
|
Args:
|
|
261
|
-
query (str): SQL query to execute. Use @P1, @P2, etc. for parameters.
|
|
272
|
+
query (str): SQL SELECT query to execute. Use @P1, @P2, etc. for parameters.
|
|
262
273
|
Example: "SELECT * FROM users WHERE age > @P1 AND city = @P2"
|
|
263
274
|
|
|
264
275
|
parameters (list, optional): List of parameter values in order.
|
|
@@ -280,143 +291,167 @@ class Connection:
|
|
|
280
291
|
|
|
281
292
|
Examples:
|
|
282
293
|
# Simple SELECT query
|
|
283
|
-
>>> result = await conn.
|
|
294
|
+
>>> result = await conn.query("SELECT * FROM users")
|
|
284
295
|
>>> async for row in result:
|
|
285
296
|
... print(f"User ID: {row['id']}, Name: {row['name']}")
|
|
286
297
|
|
|
287
298
|
# Parameterized query
|
|
288
|
-
>>> result = await conn.
|
|
299
|
+
>>> result = await conn.query(
|
|
289
300
|
... "SELECT * FROM orders WHERE created_date > @P1 AND amount > @P2",
|
|
290
301
|
... [datetime(2023, 1, 1), 100.0]
|
|
291
302
|
... )
|
|
292
303
|
>>> rows = await result.fetchall()
|
|
293
304
|
>>> print(f"Found {len(rows)} orders")
|
|
294
305
|
|
|
295
|
-
#
|
|
296
|
-
>>> result = await conn.
|
|
297
|
-
... "
|
|
298
|
-
...
|
|
306
|
+
# Complex SELECT with joins
|
|
307
|
+
>>> result = await conn.query(
|
|
308
|
+
... \"\"\"SELECT u.name, u.email, COUNT(o.id) as order_count
|
|
309
|
+
... FROM users u
|
|
310
|
+
... LEFT JOIN orders o ON u.id = o.user_id
|
|
311
|
+
... WHERE u.created_date > @P1
|
|
312
|
+
... GROUP BY u.id, u.name, u.email
|
|
313
|
+
... ORDER BY order_count DESC\"\"\",
|
|
314
|
+
... [datetime(2023, 1, 1)]
|
|
299
315
|
... )
|
|
300
|
-
>>>
|
|
316
|
+
>>> async for row in result:
|
|
317
|
+
... print(f"{row['name']}: {row['order_count']} orders")
|
|
301
318
|
|
|
302
|
-
# Stored procedure
|
|
303
|
-
>>> result = await conn.
|
|
319
|
+
# Stored procedure that returns data
|
|
320
|
+
>>> result = await conn.query(
|
|
304
321
|
... "EXEC GetUsersByDepartment @P1, @P2",
|
|
305
322
|
... ["Engineering", True] # department, active_only
|
|
306
323
|
... )
|
|
307
324
|
>>> users = await result.fetchall()
|
|
308
|
-
|
|
309
|
-
# Complex query with multiple data types
|
|
310
|
-
>>> from decimal import Decimal
|
|
311
|
-
>>> from datetime import datetime
|
|
312
|
-
>>> import uuid
|
|
313
|
-
>>>
|
|
314
|
-
>>> result = await conn.execute(
|
|
315
|
-
... \"\"\"UPDATE products
|
|
316
|
-
... SET price = @P1, updated_date = @P2, active = @P3
|
|
317
|
-
... WHERE product_id = @P4\"\"\",
|
|
318
|
-
... [Decimal('29.99'), datetime.now(), True, uuid.uuid4()]
|
|
319
|
-
... )
|
|
320
325
|
|
|
321
326
|
Performance Tips:
|
|
322
|
-
- Use
|
|
327
|
+
- Use this method instead of execute() for SELECT queries for better performance
|
|
323
328
|
- For large result sets, iterate asynchronously rather than calling fetchall()
|
|
324
329
|
- Reuse Connection instances to benefit from connection pooling
|
|
325
|
-
-
|
|
326
|
-
|
|
327
|
-
Security Notes:
|
|
328
|
-
- Always use parameterized queries to prevent SQL injection attacks
|
|
329
|
-
- Parameter values are automatically escaped and type-checked
|
|
330
|
-
- Never concatenate user input directly into SQL query strings
|
|
330
|
+
- Use appropriate indexes on filtered columns
|
|
331
331
|
"""
|
|
332
|
-
|
|
333
|
-
return await self._conn.execute(query, parameters)
|
|
332
|
+
return await self._conn.query(query, parameters)
|
|
334
333
|
|
|
335
|
-
def
|
|
334
|
+
async def execute(self, query, parameters=None):
|
|
336
335
|
"""
|
|
337
|
-
Execute a SQL
|
|
336
|
+
Execute a SQL command that doesn't return rows (INSERT/UPDATE/DELETE/DDL) asynchronously.
|
|
337
|
+
|
|
338
|
+
This method is specifically designed for SQL commands that modify data or database
|
|
339
|
+
structure but don't return result sets. It uses the optimized execute() method
|
|
340
|
+
internally for maximum performance when performing data modifications.
|
|
338
341
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
342
|
+
Use this method for:
|
|
343
|
+
- INSERT statements
|
|
344
|
+
- UPDATE statements
|
|
345
|
+
- DELETE statements
|
|
346
|
+
- DDL commands (CREATE, ALTER, DROP)
|
|
347
|
+
- Stored procedures that don't return result sets
|
|
348
|
+
- MERGE statements
|
|
343
349
|
|
|
344
350
|
Parameter Binding:
|
|
345
|
-
|
|
346
|
-
provided as a list in the same order
|
|
351
|
+
Parameters are bound using positional placeholders (@P1, @P2, etc.) in the
|
|
352
|
+
query string. The parameter values are provided as a list in the same order.
|
|
347
353
|
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
354
|
+
Supported Parameter Types:
|
|
355
|
+
- None (NULL)
|
|
356
|
+
- bool
|
|
357
|
+
- int (32-bit and 64-bit)
|
|
358
|
+
- float (32-bit and 64-bit)
|
|
359
|
+
- str (varchar, nvarchar, text)
|
|
360
|
+
- bytes (varbinary, image)
|
|
361
|
+
- datetime.datetime (datetime, datetime2)
|
|
362
|
+
- datetime.date (date)
|
|
363
|
+
- datetime.time (time)
|
|
364
|
+
- decimal.Decimal (decimal, money)
|
|
365
|
+
- uuid.UUID (uniqueidentifier)
|
|
351
366
|
|
|
352
367
|
Args:
|
|
353
|
-
query (str): SQL
|
|
354
|
-
Example: "
|
|
368
|
+
query (str): SQL command to execute. Use @P1, @P2, etc. for parameters.
|
|
369
|
+
Example: "INSERT INTO users (name, email, age) VALUES (@P1, @P2, @P3)"
|
|
355
370
|
|
|
356
|
-
|
|
371
|
+
parameters (list, optional): List of parameter values in order.
|
|
357
372
|
Values are automatically converted to appropriate SQL types.
|
|
358
|
-
Example: [
|
|
373
|
+
Example: ["John Doe", "john@example.com", 30]
|
|
359
374
|
|
|
360
375
|
Returns:
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
For
|
|
376
|
+
int: Number of rows affected by the command.
|
|
377
|
+
- For INSERT: Number of rows inserted
|
|
378
|
+
- For UPDATE: Number of rows updated
|
|
379
|
+
- For DELETE: Number of rows deleted
|
|
380
|
+
- For DDL: Usually 0 (structure changes don't affect rows)
|
|
364
381
|
|
|
365
382
|
Raises:
|
|
366
|
-
SqlError: If the SQL
|
|
367
|
-
ConnectionError: If the database connection is
|
|
383
|
+
SqlError: If the SQL command contains syntax errors or constraint violations.
|
|
384
|
+
ConnectionError: If the database connection is lost during execution.
|
|
385
|
+
TimeoutError: If the command execution exceeds configured timeouts.
|
|
368
386
|
ParameterError: If parameter types cannot be converted or are invalid.
|
|
369
387
|
|
|
370
388
|
Examples:
|
|
371
|
-
#
|
|
372
|
-
>>>
|
|
373
|
-
... "
|
|
374
|
-
... [
|
|
389
|
+
# INSERT with parameters
|
|
390
|
+
>>> affected = await conn.execute(
|
|
391
|
+
... "INSERT INTO users (name, email, age) VALUES (@P1, @P2, @P3)",
|
|
392
|
+
... ["John Doe", "john@example.com", 30]
|
|
375
393
|
... )
|
|
376
|
-
>>>
|
|
377
|
-
... print(f"User: {row['name']} ({row['email']})")
|
|
394
|
+
>>> print(f"Inserted {affected} row(s)")
|
|
378
395
|
|
|
379
|
-
#
|
|
380
|
-
>>> conn.
|
|
381
|
-
... "
|
|
382
|
-
... [
|
|
396
|
+
# UPDATE with conditions
|
|
397
|
+
>>> affected = await conn.execute(
|
|
398
|
+
... "UPDATE users SET age = @P1, updated_date = @P2 WHERE id = @P3",
|
|
399
|
+
... [31, datetime.now(), 123]
|
|
383
400
|
... )
|
|
401
|
+
>>> print(f"Updated {affected} user(s)")
|
|
384
402
|
|
|
385
|
-
#
|
|
386
|
-
>>> conn.
|
|
387
|
-
... "
|
|
388
|
-
... [datetime
|
|
403
|
+
# DELETE with parameters
|
|
404
|
+
>>> affected = await conn.execute(
|
|
405
|
+
... "DELETE FROM users WHERE age < @P1 AND last_login < @P2",
|
|
406
|
+
... [18, datetime(2020, 1, 1)]
|
|
389
407
|
... )
|
|
408
|
+
>>> print(f"Deleted {affected} inactive users")
|
|
390
409
|
|
|
391
|
-
#
|
|
392
|
-
>>>
|
|
393
|
-
|
|
394
|
-
...
|
|
395
|
-
...
|
|
396
|
-
...
|
|
397
|
-
...
|
|
398
|
-
... [Decimal('10.00'), Decimal('100.00'), False]
|
|
410
|
+
# DDL commands
|
|
411
|
+
>>> affected = await conn.execute(
|
|
412
|
+
... \"\"\"CREATE TABLE temp_data (
|
|
413
|
+
... id INT IDENTITY(1,1) PRIMARY KEY,
|
|
414
|
+
... name NVARCHAR(100) NOT NULL,
|
|
415
|
+
... created_date DATETIME2 DEFAULT GETDATE()
|
|
416
|
+
... )\"\"\"
|
|
399
417
|
... )
|
|
400
|
-
|
|
401
|
-
Migration from DB-API 2.0:
|
|
402
|
-
This method is designed to be compatible with Python's DB-API 2.0
|
|
403
|
-
specification, making it easier to migrate from libraries like pyodbc
|
|
404
|
-
or pymssql with minimal code changes.
|
|
418
|
+
>>> print(f"Table created (affected rows: {affected})")
|
|
405
419
|
|
|
406
|
-
#
|
|
407
|
-
|
|
408
|
-
|
|
420
|
+
# Stored procedure that modifies data
|
|
421
|
+
>>> affected = await conn.execute(
|
|
422
|
+
... "EXEC UpdateUserPreferences @P1, @P2",
|
|
423
|
+
... [user_id, json.dumps(preferences)]
|
|
424
|
+
... )
|
|
425
|
+
>>> print(f"Updated preferences for {affected} user(s)")
|
|
409
426
|
|
|
410
|
-
#
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
427
|
+
# Batch operations
|
|
428
|
+
>>> users_to_insert = [
|
|
429
|
+
... ["Alice Johnson", "alice@example.com", 28],
|
|
430
|
+
... ["Bob Smith", "bob@example.com", 32],
|
|
431
|
+
... ["Carol Davis", "carol@example.com", 25]
|
|
432
|
+
... ]
|
|
433
|
+
>>> total_affected = 0
|
|
434
|
+
>>> for user_data in users_to_insert:
|
|
435
|
+
... affected = await conn.execute(
|
|
436
|
+
... "INSERT INTO users (name, email, age) VALUES (@P1, @P2, @P3)",
|
|
437
|
+
... user_data
|
|
438
|
+
... )
|
|
439
|
+
... total_affected += affected
|
|
440
|
+
>>> print(f"Inserted {total_affected} users total")
|
|
441
|
+
|
|
442
|
+
Performance Tips:
|
|
443
|
+
- Use this method instead of query() for data modification commands
|
|
444
|
+
- For bulk operations, consider using batch processing or table-valued parameters
|
|
445
|
+
- Use transactions for multiple related operations
|
|
446
|
+
- Monitor the returned affected row count for validation
|
|
447
|
+
|
|
448
|
+
Security Notes:
|
|
449
|
+
- Always use parameterized queries to prevent SQL injection attacks
|
|
450
|
+
- Validate affected row counts match expectations
|
|
451
|
+
- Consider using transactions for data consistency
|
|
418
452
|
"""
|
|
419
|
-
return self._conn.
|
|
453
|
+
return await self._conn.execute(query, parameters)
|
|
454
|
+
|
|
420
455
|
|
|
421
456
|
async def is_connected(self):
|
|
422
457
|
"""
|
|
Binary file
|