-
Notifications
You must be signed in to change notification settings - Fork 24
Connection
The connect()
function simplifies creating a connection to SQL Server by returning a Connection object. Internally, it initializes and configures connection handle, processes the provided connection string, and attempts to establish a session with the target database.
The Connection Class itself supports fundamental DB-API 2.0 features, you can create cursors to run SQL statements, control transactional behavior via methods like commit
and rollback
, and close the connection once you’re done. By default, autocommit
mode is set to True
, meaning all statements are committed immediately—if you need explicit transactional control, simply set setautocommit(False)
and invoke commit
or rollback
as needed.
The connection string traditionally indicates the database server, the specific database to connect to, driver settings, and security details (e.g., Trusted Connection). You can include a port number in server port
syntax. If only a server name is included, port 1433 is assumed.
Following are the methods and attributes exposed through Connection Class
:
Creates a new Connection object.
from mssql_python import connect
conn_str = "Server=<your_server_name>,<port>;Database=<your_db_name>;Trusted_Connection=yes;"
conn = connect(conn_str)
Creates and returns a cursor object for executing SQL commands.
cursor = conn.cursor()
cursor.execute("SELECT * FROM T1")
rows = cursor.fetchall()
Commits the current transaction. Only necessary if autocommit
is off.
conn.commit()
Rolls back the current transaction. Only necessary if autocommit is off.
conn.rollback()
Closes the connection, freeing any resources. No further operations can be performed afterward.
conn.close()
conn.setencoding(encoding=None, ctype=None)
Sets the text encoding for SQL statements and text parameters.
Parameters:
-
encoding
: Python encoding used to convert text to bytes before sending to the database. Default: "utf-16le" for Unicode text. -
ctype
: C data type for text values:mssql_python.SQL_CHAR
-
mssql_python.SQL_WCHAR
(default for UTF-16 encodings)
Example:
# Use UTF-8 for all text communication
conn.setencoding(encoding='utf-8')
Defaults:
Type | Encoding | CType |
---|---|---|
str | utf-16le | SQL_WCHAR |
conn.setdecoding(sqltype, encoding=None, ctype=None)
Sets the text decoding when reading SQL_CHAR
or SQL_WCHAR
data from the database.
Parameters:
-
sqltype
: One ofmssql_python.SQL_CHAR
mssql_python.SQL_WCHAR
-
mssql_python.SQL_WMETADATA
(for column name metadata)
-
encoding
: Python encoding to decode database text into Python str -
ctype
: C data type forSQLGetData
.
Example:
# Decode all CHAR/WCHAR data using UTF-8
conn.setdecoding(mssql_python.SQL_CHAR, encoding='utf-8')
conn.setdecoding(mssql_python.SQL_WCHAR, encoding='utf-8')
Defaults:
SQL Type | Encoding | CType |
---|---|---|
SQL_CHAR | utf-8 | SQL_CHAR |
SQL_WCHAR | utf-16le | SQL_WCHAR |
SQL_WMETADATA | utf-16le | SQL_WCHAR |
This function is not part of the Python DB API.
Creates a new Cursor object, executes the given SQL statement, and returns the cursor. This method is intended for convenient one-off queries where explicit cursor management is unnecessary.
Cursors created by execute are tracked internally and automatically cleaned up when they go out of scope, but for long-running applications or loops it is recommended to explicitly call cursor.close()
to release resources promptly.
Example:
import mssql_python
conn = mssql_python.connect(connection_string)
# One-off query with automatic cleanup
row = conn.execute("SELECT name FROM users WHERE id = ?", 123).fetchone()
print("User name:", row[0])
# Explicit resource management for large result sets
cursor = conn.execute("SELECT * FROM large_table")
try:
rows = cursor.fetchall()
for row in rows:
print(row)
finally:
cursor.close() # Explicitly close the cursor
Performance & Resource Management Notes
- Each call to execute creates a new cursor. For workloads involving many queries, this may add unnecessary overhead.
- Prefer execute for quick, single queries (like fetching one row).
- For batch operations or repeated queries in loops, use an explicitly managed cursor or
batch_execute
.
This function is not part of the Python DB API.
Executes multiple SQL statements efficiently using a single cursor. It supports parameterized queries, optional cursor reuse, and automatic cursor cleanup.
This is useful for:
- Executing a sequence of statements without repeatedly creating/destroying cursors
- Batch inserts, updates, or deletes
- Combining multiple queries in a single operation
Arguments:
- statements (list[str]) – SQL statements to execute.
- params (list, optional) – Parameter sets corresponding to each statement. Must be the same length as statements.
- reuse_cursor (Cursor, optional) – Use an existing cursor instead of creating a new one.
- auto_close (bool) – Whether to automatically close the cursor after execution (only applies if a new cursor was created).
Returns:
- A tuple (results, cursor) where:
- results is a list of execution results (rowcount for non-SELECT, or fetched rows for queries returning data).
- cursor is the cursor used (can be reused if needed).
Example – multiple statements:
import mssql_python as mssql
conn = mssql.connect("connection_string")
# Execute multiple statements with parameters
results, _ = conn.batch_execute(
[
"INSERT INTO users VALUES (?, ?)",
"UPDATE stats SET count = count + 1",
"SELECT * FROM users"
],
[
(1, "user1"), # Parameters for INSERT
None, # No parameters for UPDATE
None # No parameters for SELECT
]
)
print("Inserted rowcount:", results[0]) # e.g. 1
print("Updated rowcount:", results[1]) # e.g. 1
print("Users:", results[2]) # List of rows from SELECT
Example – cursor reuse:
# Reuse the same cursor for multiple batches
my_cursor = conn.cursor()
results, _ = conn.batch_execute(
["SELECT * FROM table1", "SELECT * FROM table2"],
reuse_cursor=my_cursor
)
# Cursor remains open
my_cursor.execute("SELECT * FROM table3")
Performance & Resource Management Notes
- batch_execute is more efficient than calling execute multiple times, since it avoids creating a new cursor for each statement.
- Use
reuse_cursor=True
to keep the cursor alive across batches when executing multiple groups of queries.- Use
auto_close=True
for fire-and-forget workloads where you don’t need to reuse the cursor.- For heavy transactional workloads (e.g., inserting thousands of rows), consider combining batch_execute with parameterized queries for maximum efficiency.
These functions are not part of the official Python DB API. They allow you to customize how values returned from SQL Server are converted into Python objects.
When you fetch results from a query, values are usually returned in default Python types (e.g., str, int, bytes). With output converters, you can intercept values of specific SQL types and transform them into more useful Python representations.
⚠️ Warning: Registering an output converter will cause the supplied Python function to be executed on every matching database value. Do not register converters from untrusted sources, as this can result in arbitrary code execution and security vulnerabilities.
Registers a converter function for a given SQL type. Whenever a column of this SQL type is read from the database, the function will be invoked to transform its raw value.
Parameters
-
sqltype: The integer value representing the SQL type. You can use standard constants (e.g.,
SQL_VARCHAR
,SQL_BINARY
) or SQL Server–specific codes. - func: A callable that accepts a single parameter (the raw database value).
If the value is NULL
, the parameter will be None.
Otherwise, the parameter will be a bytes object.
The function must return the converted Python object.
Example
import mssql_python
def to_str(value: bytes):
return value.decode('utf-8') if value is not None else None
conn = mssql_python.connect(conn_str)
conn.add_output_converter(mssql_python.SQL_VARCHAR, to_str)
cursor = conn.cursor()
cursor.execute("SELECT CAST('hello' AS VARCHAR(10))")
print(cursor.fetchone()[0]) # Output: 'hello'
Returns the currently registered converter function for a given SQL type. If no converter is registered, returns None.
Example
prev_converter = conn.get_output_converter(mssql_python.SQL_VARCHAR)
print(prev_converter) # <function to_str at 0x...>
# Temporarily replace with a new converter
conn.add_output_converter(mssql_python.SQL_VARCHAR, lambda v: v.upper().decode('utf-8'))
Unregisters a converter function for a specific SQL type. Subsequent reads for this type will use the default conversion.
Example
conn.remove_output_converter(mssql_python.SQL_VARCHAR)
cursor.execute("SELECT CAST('world' AS VARCHAR(10))")
print(cursor.fetchone()[0]) # Default behavior: returns b'world'
Removes all registered output converters from the connection. Useful if you want to reset behavior and start fresh.
Example
conn.clear_output_converters()
# All converters removed → values returned in their default form
cursor.execute("SELECT CAST('reset' AS VARCHAR(10))")
print(cursor.fetchone()[0]) # b'reset'
The autocommit
is a read_only attribute which determines whether SQL statements are committed to the database automatically or only when explicitly requested. By default, autocommit
is set to True, meaning any changes made (such as INSERT, UPDATE, or DELETE commands) are immediately committed and cannot be rolled back.
The setautocommit()
function enables or disables autocommit mode for the current connection.
Behavior:
- When
autocommit
is True, each DML statement (INSERT, UPDATE, DELETE) completes as soon as it is executed. - When
autocommit
is False, all changes remain in a temporary state until commit is called. If an error occurs, you can roll back pending changes. - You can switch autocommit mode at any time by calling
setautocommit(True)
orsetautocommit(False)
. - You can check the current mode via the autocommit property; it returns True if autocommit is enabled or False if disabled.
from mssql_python import connect
# By default, autocommit is True
conn = connect("Server=<your_server_name>,<port>;Database=<your_db_name>;Trusted_Connection=yes;")
# Prints True since autocommit is enabled
print("Autocommit:", conn.autocommit)
# Disable autocommit
conn.setautocommit(False)
cursor = conn.cursor()
cursor.execute("INSERT INTO T1 (col_1) VALUES (?)", "1234")
# Changes remain uncommitted until explicitly committed
conn.commit()
This property is not part of the Python DB API.
Returns the ODBC search pattern escape character as provided by SQLGetInfo(SQL_SEARCH_PATTERN_ESCAPE)
.
The escape character is used to treat special pattern characters (such as %
and _
) literally when writing LIKE
queries.
Different drivers may use different escape characters (commonly \
).
Example – escaping %:
import mssql_python
conn = mssql_python.connect(connection_string)
escape = conn.searchescape
cursor = conn.cursor()
cursor.execute("CREATE TABLE #test (id INT, text VARCHAR(50))")
cursor.execute("INSERT INTO #test VALUES (1, 'abc%def'), (2, 'abcdef')")
# Use ESCAPE to treat '%' literally
query = f"SELECT * FROM #test WHERE text LIKE 'abc{escape}%def' ESCAPE '{escape}'"
cursor.execute(query)
rows = cursor.fetchall()
print(rows) # Only matches 'abc%def'
Notes
- The value is driver-specific and may not always be a string.
- Cached at the connection level for efficiency — repeated calls return the same value.
- Useful when querying text data that contains wildcard characters.
This property is not part of the Python DB API.
Specifies the timeout (in seconds) for SQL query execution.
The default is 0, which disables query timeouts.
Unlike connection timeouts (set during connect()), this applies only to SQL queries run on cursors created from this connection.
If a query exceeds the timeout, the driver will raise an OperationalError
(usually with SQLSTATE HYT00
or HYT01
).
Example – setting timeout:
import mssql_python
# Set timeout in connection constructor
conn = mssql_python.connect("connection_string", timeout=30)
print(conn.timeout) # 30
# Change timeout dynamically
conn.timeout = 10
cursor = conn.cursor()
try:
# Query that might run longer than 10 seconds
cursor.execute("WAITFOR DELAY '00:00:15'")
cursor.fetchall()
except mssql.OperationalError as e:
print("Query timed out:", e)
Notes
- Setting
timeout = 0
disables query timeouts (default). - Affects all cursors created from the connection (cannot be set per cursor).
- Values must be non-negative integers:
- Raises
ValueError
if negative. - Raises
TypeError
if non-integer. - For connection timeouts, use the timeout argument in
mssql_python.connect()
.
Connection objects now support the Python context manager syntax (with statement).
Using with
on a Connection object ensures:
- Automatic commit if everything succeeds.
- Automatic rollback if an exception occurs.
- The connection is always closed when leaving the block.
from mssql_python import connect
with connect(connection_string) as conn:
cursor = conn.cursor()
cursor.execute("INSERT INTO users (name) VALUES ('Alice')")
# If no exception → commit happens automatically
# If exception → rollback happens automatically
# Connection is closed automatically here
This is roughly equivalent to:
conn= connect(connection_string)
try:
cursor = conn.cursor()
cursor.execute("INSERT INTO users (name) VALUES ('Alice')")
if not conn.autocommit:
conn.commit()
except:
if not conn.autocommit:
conn.rollback()
raise
finally:
conn.close()
How It Behaves
- Entering the block
- A connection is opened and assigned to conn.
- Any operations inside the block run using this connection.
- When the block exits:
- No Exception:
- If
autocommit = False
, all transactions since the last commit are automatically committed. - If
autocommit = True
, no commit happens because every statement is already committed automatically.
- If
- Exception Raised:
- If
autocommit = False
, all uncommitted changes are rolled back automatically. - The exception propagates upward unless you handle it.
- If
- Connection Cleanup:
- The connection is always closed after the block exits — even if an error occurs.
- This prevents resource leaks (open connections that aren’t properly closed).
This makes transaction handling simpler and reduces boilerplate code.
The DB-API 2.0 standard defines a set of exception classes—such as Error
, ProgrammingError
, DatabaseError
, OperationalError
, and more—that are essential for robust database error handling.
You can now catch exceptions using a connection instance, Example:
try:
conn.cursor().execute("…")
except conn.ProgrammingError:
# handle programming error
...
All the standard DB-API 2.0 exceptions are exposed on the connection, including:
Warning
Error
InterfaceError
DatabaseError
DataError
OperationalError
IntegrityError
InternalError
ProgrammingError
NotSupportedError
Connecting to a database server typically consists of several time-consuming steps. A physical channel such as a socket or a named pipe must be established, the initial handshake with the server must occur, the connection string information must be parsed, the connection must be authenticated by the server, checks must be run for enlisting in the current transaction, and so on.
In practice, most applications use only one or a few different configurations for connections. This means that during application execution, many identical connections will be repeatedly opened and closed. To minimize the cost of opening connections, mssql_python
uses an optimization technique called connection pooling
.
Now, mssql_python
driver provides built-in support for connection pooling
, which helps improve performance and scalability by reusing active database connections instead of creating a new connection for every request.
This document describes how you can configure and use it effectively.
Connection pooling is enabled by default
when the first connection is created. It uses the following default configuration:
max_size = 100
-
idle_timeout = 600 seconds
(10 minutes)
You can explicitly enable or disable pooling using the pooling()
API before any connections are created.
import mssql_python
# Enabling pooling here with a maximum of 50 connections
# and idle timeout of 300 seconds (5 minutes)
mssql_python.pooling(max_size=50, idle_timeout=300)
To disable pooling explicitly:
import mssql_python
mssql_python.pooling(enabled=False)
- If
enabled=False
is passed, no pooling will be used — connections will always be created and destroyed per use. - Pooling must be enabled before establishing a connection. It has no effect if called after connections are already created.
-
max_size (int)
– Maximum number of pooled connections per unique connection string. -
idle_timeout (int)
– Time (in seconds) after which idle connections are evicted from the pool. -
enabled (bool)
– Whether to enable or disable pooling. Defaults to True.
- Faster performance for applications making frequent connections.
- Reduced load on the database server.
- Transparent and compatible with the standard DBAPI interface.
Note: Connection pooling in mssql_python works consistently across all SQL Server-based environments, including Azure SQL Database, Azure SQL Managed Instance, and SQL Server (on-premises or in virtual machines (VMs)). The pooling mechanism is entirely client-side and functions identically across these platforms. However, service-specific factors can influence pooling efficiency: Azure SQL Database enforces connection limits based on the selected service tier (e.g., Basic, Standard, Premium), while Azure SQL Managed Instance ties connection limits to the instance's allocated resources, such as vCores and memory. In contrast, SQL Server on VMs has no enforced limits beyond hardware and licensing constraints, offering the most flexibility