Skip to content

Commit 39fa6f3

Browse files
authored
Merge branch 'main' into saumya/datetimeoffset
2 parents 08d967b + d94b518 commit 39fa6f3

File tree

13 files changed

+5392
-213
lines changed

13 files changed

+5392
-213
lines changed

PyPI_Description.md

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -39,20 +39,15 @@ PyBind11 provides:
3939

4040
We are currently in **Public Preview**.
4141

42-
## What's new in v0.10.0
43-
44-
- **SUSE Linux Support:** Added full support for SUSE and openSUSE distributions alongside existing other Linux distros support, broadening enterprise Linux compatibility.
45-
- **Context Manager Support:** Implemented Python `with` statement support for Connection and Cursor classes with automatic transaction management and resource cleanup.
46-
- **Large Text Streaming:** Added Data At Execution (DAE) support for streaming large text parameters (`NVARCHAR(MAX)`, `VARCHAR(MAX)`), eliminating memory constraints for bulk text `execute()` operations.
47-
- `VARBINARY(MAX)` support to follow alongwith streaming support for fetch operations.
48-
- **Enhanced Unicode Handling:** Improved emoji and international character support with robust UTF-16 encoding for reliable multilingual data processing.
49-
- **PyODBC Compatibility:** Enhanced API compatibility with pyodbc including:
50-
- DB-API 2.0 exception classes: `Warning`, `Error`, `InterfaceError`, `DatabaseError`, `DataError`, `OperationalError`, `IntegrityError`, `InternalError`, `ProgrammingError`, `NotSupportedError`
51-
- Context manager support with `with` statements for Connection and Cursor
52-
- Encoding configuration APIs: `setencoding()`, `getencoding()`, `setdecoding()`, `getdecoding()`
53-
- Cursor navigation APIs: `next()`, `__iter__()`, `scroll()`, `skip()`, `fetchval()`
54-
- Cursor attributes: `rownumber`, `messages`
55-
- Additional methods: `cursor.commit()`, `cursor.rollback()`, `table()`
42+
## What's new in v0.11.0
43+
44+
- **Database Metadata & Introspection:** Added comprehensive `getInfo()` method and extensive catalog APIs (`SQLGetTypeInfo`, `SQLProcedures`, `SQLForeignKeys`, `SQLColumns`) for complete database schema discovery and introspection capabilities.
45+
- **Advanced Parameter Management:** Implemented `setinputsizes()` with SQL type constants and enhanced parameter validation through the `SQLTypes` class for precise type control in parameterized queries.
46+
- **Large Data Streaming Enhancements:** Extended streaming support to VARBINARY(MAX) and VARCHAR(MAX) across all fetch operations (`fetchone`, `fetchmany`, `fetchall`) with improved chunked retrieval for efficient memory usage.
47+
- **Output Data Conversion System:** Introduced flexible output converter framework with `add_output_converter()`, `remove_output_converter()`, and related methods for customizable data transformations during result fetching.
48+
- **Connection-Level Execute:** Added direct `execute()` method to Connection class for streamlined query execution without explicit cursor management.
49+
- **Financial Data Type Support:** Comprehensive support for SQL Server MONEY and SMALLMONEY types with proper boundary value handling and decimal precision.
50+
- **Enhanced Configuration APIs:** Added connection timeout control, decimal separator configuration (`getDecimalSeperator()`, `setDecimalSeperator()`), and improved global variable management.
5651

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

mssql_python/__init__.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,3 +180,28 @@ def _custom_setattr(name, value):
180180

181181
# Replace the module's __setattr__ with our custom version
182182
sys.modules[__name__].__setattr__ = _custom_setattr
183+
184+
185+
# Export SQL constants at module level
186+
SQL_CHAR = ConstantsDDBC.SQL_CHAR.value
187+
SQL_VARCHAR = ConstantsDDBC.SQL_VARCHAR.value
188+
SQL_LONGVARCHAR = ConstantsDDBC.SQL_LONGVARCHAR.value
189+
SQL_WCHAR = ConstantsDDBC.SQL_WCHAR.value
190+
SQL_WVARCHAR = ConstantsDDBC.SQL_WVARCHAR.value
191+
SQL_WLONGVARCHAR = ConstantsDDBC.SQL_WLONGVARCHAR.value
192+
SQL_DECIMAL = ConstantsDDBC.SQL_DECIMAL.value
193+
SQL_NUMERIC = ConstantsDDBC.SQL_NUMERIC.value
194+
SQL_BIT = ConstantsDDBC.SQL_BIT.value
195+
SQL_TINYINT = ConstantsDDBC.SQL_TINYINT.value
196+
SQL_SMALLINT = ConstantsDDBC.SQL_SMALLINT.value
197+
SQL_INTEGER = ConstantsDDBC.SQL_INTEGER.value
198+
SQL_BIGINT = ConstantsDDBC.SQL_BIGINT.value
199+
SQL_REAL = ConstantsDDBC.SQL_REAL.value
200+
SQL_FLOAT = ConstantsDDBC.SQL_FLOAT.value
201+
SQL_DOUBLE = ConstantsDDBC.SQL_DOUBLE.value
202+
SQL_BINARY = ConstantsDDBC.SQL_BINARY.value
203+
SQL_VARBINARY = ConstantsDDBC.SQL_VARBINARY.value
204+
SQL_LONGVARBINARY = ConstantsDDBC.SQL_LONGVARBINARY.value
205+
SQL_DATE = ConstantsDDBC.SQL_DATE.value
206+
SQL_TIME = ConstantsDDBC.SQL_TIME.value
207+
SQL_TIMESTAMP = ConstantsDDBC.SQL_TIMESTAMP.value

mssql_python/connection.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ def _validate_encoding(encoding: str) -> bool:
6666
ProgrammingError,
6767
NotSupportedError,
6868
)
69+
from mssql_python.constants import GetInfoConstants
6970

7071

7172
class Connection:
@@ -544,6 +545,30 @@ def getdecoding(self, sqltype):
544545

545546
return self._decoding_settings[sqltype].copy()
546547

548+
@property
549+
def searchescape(self):
550+
"""
551+
The ODBC search pattern escape character, as returned by
552+
SQLGetInfo(SQL_SEARCH_PATTERN_ESCAPE), used to escape special characters
553+
such as '%' and '_' in LIKE clauses. These are driver specific.
554+
555+
Returns:
556+
str: The search pattern escape character (usually '\' or another character)
557+
"""
558+
if not hasattr(self, '_searchescape'):
559+
try:
560+
escape_char = self.getinfo(GetInfoConstants.SQL_SEARCH_PATTERN_ESCAPE.value)
561+
# Some drivers might return this as an integer memory address
562+
# or other non-string format, so ensure we have a string
563+
if not isinstance(escape_char, str):
564+
escape_char = '\\' # Default to backslash if not a string
565+
self._searchescape = escape_char
566+
except Exception as e:
567+
# Log the exception for debugging, but do not expose sensitive info
568+
log('warning', f"Failed to retrieve search escape character, using default '\\'. Exception: {type(e).__name__}")
569+
self._searchescape = '\\'
570+
return self._searchescape
571+
547572
def cursor(self) -> Cursor:
548573
"""
549574
Return a new Cursor object using the connection.
@@ -824,6 +849,30 @@ def batch_execute(self, statements, params=None, reuse_cursor=None, auto_close=F
824849
log('debug', "Automatically closed cursor after batch execution")
825850

826851
return results, cursor
852+
853+
def getinfo(self, info_type):
854+
"""
855+
Return general information about the driver and data source.
856+
857+
Args:
858+
info_type (int): The type of information to return. See the ODBC
859+
SQLGetInfo documentation for the supported values.
860+
861+
Returns:
862+
The requested information. The type of the returned value depends
863+
on the information requested. It will be a string, integer, or boolean.
864+
865+
Raises:
866+
DatabaseError: If there is an error retrieving the information.
867+
InterfaceError: If the connection is closed.
868+
"""
869+
if self._closed:
870+
raise InterfaceError(
871+
driver_error="Cannot get info on closed connection",
872+
ddbc_error="Cannot get info on closed connection",
873+
)
874+
875+
return self._conn.get_info(info_type)
827876

828877
def commit(self) -> None:
829878
"""

mssql_python/constants.py

Lines changed: 193 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,9 +126,201 @@ class ConstantsDDBC(Enum):
126126
SQL_FETCH_BOOKMARK = 8
127127
SQL_DATETIMEOFFSET = -155
128128
SQL_C_SS_TIMESTAMPOFFSET = 0x4001
129+
SQL_SCOPE_CURROW = 0
130+
SQL_BEST_ROWID = 1
131+
SQL_ROWVER = 2
132+
SQL_NO_NULLS = 0
133+
SQL_NULLABLE_UNKNOWN = 2
134+
SQL_INDEX_UNIQUE = 0
135+
SQL_INDEX_ALL = 1
136+
SQL_QUICK = 0
137+
SQL_ENSURE = 1
138+
139+
class GetInfoConstants(Enum):
140+
"""
141+
These constants are used with various methods like getinfo().
142+
"""
143+
144+
# Driver and database information
145+
SQL_DRIVER_NAME = 6
146+
SQL_DRIVER_VER = 7
147+
SQL_DRIVER_ODBC_VER = 77
148+
SQL_DRIVER_HLIB = 76
149+
SQL_DRIVER_HENV = 75
150+
SQL_DRIVER_HDBC = 74
151+
SQL_DATA_SOURCE_NAME = 2
152+
SQL_DATABASE_NAME = 16
153+
SQL_SERVER_NAME = 13
154+
SQL_USER_NAME = 47
155+
156+
# SQL conformance and support
157+
SQL_SQL_CONFORMANCE = 118
158+
SQL_KEYWORDS = 89
159+
SQL_IDENTIFIER_CASE = 28
160+
SQL_IDENTIFIER_QUOTE_CHAR = 29
161+
SQL_SPECIAL_CHARACTERS = 94
162+
SQL_SQL92_ENTRY_SQL = 127
163+
SQL_SQL92_INTERMEDIATE_SQL = 128
164+
SQL_SQL92_FULL_SQL = 129
165+
SQL_SUBQUERIES = 95
166+
SQL_EXPRESSIONS_IN_ORDERBY = 27
167+
SQL_CORRELATION_NAME = 74
168+
SQL_SEARCH_PATTERN_ESCAPE = 14
169+
170+
# Catalog and schema support
171+
SQL_CATALOG_TERM = 42
172+
SQL_CATALOG_NAME_SEPARATOR = 41
173+
SQL_SCHEMA_TERM = 39
174+
SQL_TABLE_TERM = 45
175+
SQL_PROCEDURES = 21
176+
SQL_ACCESSIBLE_TABLES = 19
177+
SQL_ACCESSIBLE_PROCEDURES = 20
178+
SQL_CATALOG_NAME = 10002
179+
SQL_CATALOG_USAGE = 92
180+
SQL_SCHEMA_USAGE = 91
181+
SQL_COLUMN_ALIAS = 87
182+
SQL_DESCRIBE_PARAMETER = 10003
183+
184+
# Transaction support
185+
SQL_TXN_CAPABLE = 46
186+
SQL_TXN_ISOLATION_OPTION = 72
187+
SQL_DEFAULT_TXN_ISOLATION = 26
188+
SQL_MULTIPLE_ACTIVE_TXN = 37
189+
SQL_TXN_ISOLATION_LEVEL = 108
190+
191+
# Data type support
192+
SQL_NUMERIC_FUNCTIONS = 49
193+
SQL_STRING_FUNCTIONS = 50
194+
SQL_DATETIME_FUNCTIONS = 51
195+
SQL_SYSTEM_FUNCTIONS = 58
196+
SQL_CONVERT_FUNCTIONS = 48
197+
SQL_LIKE_ESCAPE_CLAUSE = 113
198+
199+
# Numeric limits
200+
SQL_MAX_COLUMN_NAME_LEN = 30
201+
SQL_MAX_TABLE_NAME_LEN = 35
202+
SQL_MAX_SCHEMA_NAME_LEN = 32
203+
SQL_MAX_CATALOG_NAME_LEN = 34
204+
SQL_MAX_IDENTIFIER_LEN = 10005
205+
SQL_MAX_STATEMENT_LEN = 105
206+
SQL_MAX_CHAR_LITERAL_LEN = 108
207+
SQL_MAX_BINARY_LITERAL_LEN = 112
208+
SQL_MAX_COLUMNS_IN_TABLE = 101
209+
SQL_MAX_COLUMNS_IN_SELECT = 100
210+
SQL_MAX_COLUMNS_IN_GROUP_BY = 97
211+
SQL_MAX_COLUMNS_IN_ORDER_BY = 99
212+
SQL_MAX_COLUMNS_IN_INDEX = 98
213+
SQL_MAX_TABLES_IN_SELECT = 106
214+
SQL_MAX_CONCURRENT_ACTIVITIES = 1
215+
SQL_MAX_DRIVER_CONNECTIONS = 0
216+
SQL_MAX_ROW_SIZE = 104
217+
SQL_MAX_USER_NAME_LEN = 107
218+
219+
# Connection attributes
220+
SQL_ACTIVE_CONNECTIONS = 0
221+
SQL_ACTIVE_STATEMENTS = 1
222+
SQL_DATA_SOURCE_READ_ONLY = 25
223+
SQL_NEED_LONG_DATA_LEN = 111
224+
SQL_GETDATA_EXTENSIONS = 81
225+
226+
# Result set and cursor attributes
227+
SQL_CURSOR_COMMIT_BEHAVIOR = 23
228+
SQL_CURSOR_ROLLBACK_BEHAVIOR = 24
229+
SQL_CURSOR_SENSITIVITY = 10001
230+
SQL_BOOKMARK_PERSISTENCE = 82
231+
SQL_DYNAMIC_CURSOR_ATTRIBUTES1 = 144
232+
SQL_DYNAMIC_CURSOR_ATTRIBUTES2 = 145
233+
SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES1 = 146
234+
SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2 = 147
235+
SQL_STATIC_CURSOR_ATTRIBUTES1 = 150
236+
SQL_STATIC_CURSOR_ATTRIBUTES2 = 151
237+
SQL_KEYSET_CURSOR_ATTRIBUTES1 = 148
238+
SQL_KEYSET_CURSOR_ATTRIBUTES2 = 149
239+
SQL_SCROLL_OPTIONS = 44
240+
SQL_SCROLL_CONCURRENCY = 43
241+
SQL_FETCH_DIRECTION = 8
242+
SQL_ROWSET_SIZE = 9
243+
SQL_CONCURRENCY = 7
244+
SQL_ROW_NUMBER = 14
245+
SQL_STATIC_SENSITIVITY = 83
246+
SQL_BATCH_SUPPORT = 121
247+
SQL_BATCH_ROW_COUNT = 120
248+
SQL_PARAM_ARRAY_ROW_COUNTS = 153
249+
SQL_PARAM_ARRAY_SELECTS = 154
250+
251+
# Positioned statement support
252+
SQL_POSITIONED_STATEMENTS = 80
253+
254+
# Other constants
255+
SQL_GROUP_BY = 88
256+
SQL_OJ_CAPABILITIES = 65
257+
SQL_ORDER_BY_COLUMNS_IN_SELECT = 90
258+
SQL_OUTER_JOINS = 38
259+
SQL_QUOTED_IDENTIFIER_CASE = 93
260+
SQL_CONCAT_NULL_BEHAVIOR = 22
261+
SQL_NULL_COLLATION = 85
262+
SQL_ALTER_TABLE = 86
263+
SQL_UNION = 96
264+
SQL_DDL_INDEX = 170
265+
SQL_MULT_RESULT_SETS = 36
266+
SQL_OWNER_USAGE = 91
267+
SQL_QUALIFIER_USAGE = 92
268+
SQL_TIMEDATE_ADD_INTERVALS = 109
269+
SQL_TIMEDATE_DIFF_INTERVALS = 110
270+
271+
# Return values for some getinfo functions
272+
SQL_IC_UPPER = 1
273+
SQL_IC_LOWER = 2
274+
SQL_IC_SENSITIVE = 3
275+
SQL_IC_MIXED = 4
129276

130277
class AuthType(Enum):
131278
"""Constants for authentication types"""
132279
INTERACTIVE = "activedirectoryinteractive"
133280
DEVICE_CODE = "activedirectorydevicecode"
134-
DEFAULT = "activedirectorydefault"
281+
DEFAULT = "activedirectorydefault"
282+
283+
class SQLTypes:
284+
"""Constants for valid SQL data types to use with setinputsizes"""
285+
286+
@classmethod
287+
def get_valid_types(cls) -> set:
288+
"""Returns a set of all valid SQL type constants"""
289+
290+
return {
291+
ConstantsDDBC.SQL_CHAR.value, ConstantsDDBC.SQL_VARCHAR.value,
292+
ConstantsDDBC.SQL_LONGVARCHAR.value, ConstantsDDBC.SQL_WCHAR.value,
293+
ConstantsDDBC.SQL_WVARCHAR.value, ConstantsDDBC.SQL_WLONGVARCHAR.value,
294+
ConstantsDDBC.SQL_DECIMAL.value, ConstantsDDBC.SQL_NUMERIC.value,
295+
ConstantsDDBC.SQL_BIT.value, ConstantsDDBC.SQL_TINYINT.value,
296+
ConstantsDDBC.SQL_SMALLINT.value, ConstantsDDBC.SQL_INTEGER.value,
297+
ConstantsDDBC.SQL_BIGINT.value, ConstantsDDBC.SQL_REAL.value,
298+
ConstantsDDBC.SQL_FLOAT.value, ConstantsDDBC.SQL_DOUBLE.value,
299+
ConstantsDDBC.SQL_BINARY.value, ConstantsDDBC.SQL_VARBINARY.value,
300+
ConstantsDDBC.SQL_LONGVARBINARY.value, ConstantsDDBC.SQL_DATE.value,
301+
ConstantsDDBC.SQL_TIME.value, ConstantsDDBC.SQL_TIMESTAMP.value,
302+
ConstantsDDBC.SQL_GUID.value
303+
}
304+
305+
# Could also add category methods for convenience
306+
@classmethod
307+
def get_string_types(cls) -> set:
308+
"""Returns a set of string SQL type constants"""
309+
310+
return {
311+
ConstantsDDBC.SQL_CHAR.value, ConstantsDDBC.SQL_VARCHAR.value,
312+
ConstantsDDBC.SQL_LONGVARCHAR.value, ConstantsDDBC.SQL_WCHAR.value,
313+
ConstantsDDBC.SQL_WVARCHAR.value, ConstantsDDBC.SQL_WLONGVARCHAR.value
314+
}
315+
316+
@classmethod
317+
def get_numeric_types(cls) -> set:
318+
"""Returns a set of numeric SQL type constants"""
319+
320+
return {
321+
ConstantsDDBC.SQL_DECIMAL.value, ConstantsDDBC.SQL_NUMERIC.value,
322+
ConstantsDDBC.SQL_BIT.value, ConstantsDDBC.SQL_TINYINT.value,
323+
ConstantsDDBC.SQL_SMALLINT.value, ConstantsDDBC.SQL_INTEGER.value,
324+
ConstantsDDBC.SQL_BIGINT.value, ConstantsDDBC.SQL_REAL.value,
325+
ConstantsDDBC.SQL_FLOAT.value, ConstantsDDBC.SQL_DOUBLE.value
326+
}

0 commit comments

Comments
 (0)