|
9 | 9 | import threading |
10 | 10 | import types |
11 | 11 | import weakref |
12 | | -from typing import Dict |
13 | 12 |
|
14 | | -# Import settings from helpers to avoid circular imports |
| 13 | +# Import settings from helpers module |
15 | 14 | from .helpers import Settings, get_settings, _settings, _settings_lock |
16 | 15 |
|
17 | 16 | # Driver version |
|
61 | 60 | # Cursor Objects |
62 | 61 | from .cursor import Cursor |
63 | 62 |
|
| 63 | +# Row Objects |
| 64 | +from .row import Row |
| 65 | + |
64 | 66 | # Logging Configuration (Simplified single-level DEBUG system) |
65 | 67 | from .logging import logger, setup_logging, driver_logger |
66 | 68 |
|
67 | 69 | # Constants |
68 | | -from .constants import ConstantsDDBC, GetInfoConstants |
| 70 | +from .constants import ConstantsDDBC, GetInfoConstants, get_info_constants |
69 | 71 |
|
70 | 72 | # Pooling |
71 | 73 | from .pooling import PoolingManager |
@@ -119,97 +121,177 @@ def _cleanup_connections(): |
119 | 121 | paramstyle: str = "pyformat" |
120 | 122 | threadsafety: int = 1 |
121 | 123 |
|
122 | | -# Set the initial decimal separator in C++ |
123 | | -try: |
124 | | - from .ddbc_bindings import DDBCSetDecimalSeparator |
125 | | - |
126 | | - DDBCSetDecimalSeparator(_settings.decimal_separator) |
127 | | -except ImportError: |
128 | | - # Handle case where ddbc_bindings is not available |
129 | | - DDBCSetDecimalSeparator = None |
130 | | - |
131 | | - |
132 | | -# New functions for decimal separator control |
133 | | -def setDecimalSeparator(separator: str) -> None: |
134 | | - """ |
135 | | - Sets the decimal separator character used when parsing NUMERIC/DECIMAL values |
136 | | - from the database, e.g. the "." in "1,234.56". |
137 | | -
|
138 | | - The default is to use the current locale's "decimal_point" value when the module |
139 | | - was first imported, or "." if the locale is not available. This function overrides |
140 | | - the default. |
141 | | -
|
142 | | - Args: |
143 | | - separator (str): The character to use as decimal separator |
144 | | -
|
145 | | - Raises: |
146 | | - ValueError: If the separator is not a single character string |
147 | | - """ |
148 | | - # Type validation |
149 | | - if not isinstance(separator, str): |
150 | | - raise ValueError("Decimal separator must be a string") |
151 | | - |
152 | | - # Length validation |
153 | | - if len(separator) == 0: |
154 | | - raise ValueError("Decimal separator cannot be empty") |
155 | | - |
156 | | - if len(separator) > 1: |
157 | | - raise ValueError("Decimal separator must be a single character") |
158 | | - |
159 | | - # Character validation |
160 | | - if separator.isspace(): |
161 | | - raise ValueError("Whitespace characters are not allowed as decimal separators") |
162 | | - |
163 | | - # Check for specific disallowed characters |
164 | | - if separator in ["\t", "\n", "\r", "\v", "\f"]: |
165 | | - raise ValueError( |
166 | | - f"Control character '{repr(separator)}' is not allowed as a decimal separator" |
167 | | - ) |
168 | | - |
169 | | - # Set in Python side settings |
170 | | - _settings.decimal_separator = separator |
171 | | - |
172 | | - # Update the C++ side |
173 | | - if DDBCSetDecimalSeparator is not None: |
174 | | - DDBCSetDecimalSeparator(separator) |
175 | | - |
176 | | - |
177 | | -def getDecimalSeparator() -> str: |
178 | | - """ |
179 | | - Returns the decimal separator character used when parsing NUMERIC/DECIMAL values |
180 | | - from the database. |
181 | | -
|
182 | | - Returns: |
183 | | - str: The current decimal separator character |
184 | | - """ |
185 | | - return _settings.decimal_separator |
186 | | - |
187 | | - |
188 | | -# Export specific constants for setencoding() |
189 | | -SQL_CHAR: int = ConstantsDDBC.SQL_CHAR.value |
190 | | -SQL_WCHAR: int = ConstantsDDBC.SQL_WCHAR.value |
191 | | -SQL_WMETADATA: int = -99 |
192 | | - |
193 | | -# Export connection attribute constants for set_attr() |
194 | | -# Only include driver-level attributes that the SQL Server ODBC driver can handle directly |
195 | | - |
196 | | -# Core driver-level attributes |
197 | | -SQL_ATTR_ACCESS_MODE: int = ConstantsDDBC.SQL_ATTR_ACCESS_MODE.value |
198 | | -SQL_ATTR_CONNECTION_TIMEOUT: int = ConstantsDDBC.SQL_ATTR_CONNECTION_TIMEOUT.value |
199 | | -SQL_ATTR_CURRENT_CATALOG: int = ConstantsDDBC.SQL_ATTR_CURRENT_CATALOG.value |
200 | | -SQL_ATTR_LOGIN_TIMEOUT: int = ConstantsDDBC.SQL_ATTR_LOGIN_TIMEOUT.value |
201 | | -SQL_ATTR_PACKET_SIZE: int = ConstantsDDBC.SQL_ATTR_PACKET_SIZE.value |
202 | | -SQL_ATTR_TXN_ISOLATION: int = ConstantsDDBC.SQL_ATTR_TXN_ISOLATION.value |
203 | | - |
204 | | -# Transaction Isolation Level Constants |
205 | | -SQL_TXN_READ_UNCOMMITTED: int = ConstantsDDBC.SQL_TXN_READ_UNCOMMITTED.value |
206 | | -SQL_TXN_READ_COMMITTED: int = ConstantsDDBC.SQL_TXN_READ_COMMITTED.value |
207 | | -SQL_TXN_REPEATABLE_READ: int = ConstantsDDBC.SQL_TXN_REPEATABLE_READ.value |
208 | | -SQL_TXN_SERIALIZABLE: int = ConstantsDDBC.SQL_TXN_SERIALIZABLE.value |
209 | | - |
210 | | -# Access Mode Constants |
211 | | -SQL_MODE_READ_WRITE: int = ConstantsDDBC.SQL_MODE_READ_WRITE.value |
212 | | -SQL_MODE_READ_ONLY: int = ConstantsDDBC.SQL_MODE_READ_ONLY.value |
| 124 | +# Create decimal separator control functions bound to our settings |
| 125 | +from .decimal_config import create_decimal_separator_functions |
| 126 | + |
| 127 | +setDecimalSeparator, getDecimalSeparator = create_decimal_separator_functions(_settings) |
| 128 | + |
| 129 | +# Import module-level constants from constants module |
| 130 | +from .constants import ( # noqa: F401 |
| 131 | + # Enum classes |
| 132 | + AuthType, |
| 133 | + SQLTypes, |
| 134 | + # Helper function |
| 135 | + get_info_constants, |
| 136 | + # SQL Type constants (from ConstantsDDBC) |
| 137 | + SQL_CHAR, |
| 138 | + SQL_VARCHAR, |
| 139 | + SQL_LONGVARCHAR, |
| 140 | + SQL_WCHAR, |
| 141 | + SQL_WVARCHAR, |
| 142 | + SQL_WLONGVARCHAR, |
| 143 | + SQL_DECIMAL, |
| 144 | + SQL_NUMERIC, |
| 145 | + SQL_BIT, |
| 146 | + SQL_TINYINT, |
| 147 | + SQL_SMALLINT, |
| 148 | + SQL_INTEGER, |
| 149 | + SQL_BIGINT, |
| 150 | + SQL_REAL, |
| 151 | + SQL_FLOAT, |
| 152 | + SQL_DOUBLE, |
| 153 | + SQL_BINARY, |
| 154 | + SQL_VARBINARY, |
| 155 | + SQL_LONGVARBINARY, |
| 156 | + SQL_DATE, |
| 157 | + SQL_TIME, |
| 158 | + SQL_TIMESTAMP, |
| 159 | + SQL_TYPE_DATE, |
| 160 | + SQL_TYPE_TIME, |
| 161 | + SQL_TYPE_TIMESTAMP, |
| 162 | + SQL_GUID, |
| 163 | + SQL_XML, |
| 164 | + # Connection attribute constants |
| 165 | + SQL_ATTR_ACCESS_MODE, |
| 166 | + SQL_ATTR_CONNECTION_TIMEOUT, |
| 167 | + SQL_ATTR_CURRENT_CATALOG, |
| 168 | + SQL_ATTR_LOGIN_TIMEOUT, |
| 169 | + SQL_ATTR_PACKET_SIZE, |
| 170 | + SQL_ATTR_TXN_ISOLATION, |
| 171 | + # Transaction isolation levels |
| 172 | + SQL_TXN_READ_UNCOMMITTED, |
| 173 | + SQL_TXN_READ_COMMITTED, |
| 174 | + SQL_TXN_REPEATABLE_READ, |
| 175 | + SQL_TXN_SERIALIZABLE, |
| 176 | + # Access modes |
| 177 | + SQL_MODE_READ_WRITE, |
| 178 | + SQL_MODE_READ_ONLY, |
| 179 | + # Special constants |
| 180 | + SQL_WMETADATA, |
| 181 | + # GetInfoConstants (all exported as module-level constants) |
| 182 | + SQL_DRIVER_NAME, |
| 183 | + SQL_DRIVER_VER, |
| 184 | + SQL_DRIVER_ODBC_VER, |
| 185 | + SQL_DRIVER_HLIB, |
| 186 | + SQL_DRIVER_HENV, |
| 187 | + SQL_DRIVER_HDBC, |
| 188 | + SQL_DATA_SOURCE_NAME, |
| 189 | + SQL_DATABASE_NAME, |
| 190 | + SQL_SERVER_NAME, |
| 191 | + SQL_USER_NAME, |
| 192 | + SQL_SQL_CONFORMANCE, |
| 193 | + SQL_KEYWORDS, |
| 194 | + SQL_IDENTIFIER_CASE, |
| 195 | + SQL_IDENTIFIER_QUOTE_CHAR, |
| 196 | + SQL_SPECIAL_CHARACTERS, |
| 197 | + SQL_SQL92_ENTRY_SQL, |
| 198 | + SQL_SQL92_INTERMEDIATE_SQL, |
| 199 | + SQL_SQL92_FULL_SQL, |
| 200 | + SQL_SUBQUERIES, |
| 201 | + SQL_EXPRESSIONS_IN_ORDERBY, |
| 202 | + SQL_CORRELATION_NAME, |
| 203 | + SQL_SEARCH_PATTERN_ESCAPE, |
| 204 | + SQL_CATALOG_TERM, |
| 205 | + SQL_CATALOG_NAME_SEPARATOR, |
| 206 | + SQL_SCHEMA_TERM, |
| 207 | + SQL_TABLE_TERM, |
| 208 | + SQL_PROCEDURES, |
| 209 | + SQL_ACCESSIBLE_TABLES, |
| 210 | + SQL_ACCESSIBLE_PROCEDURES, |
| 211 | + SQL_CATALOG_NAME, |
| 212 | + SQL_CATALOG_USAGE, |
| 213 | + SQL_SCHEMA_USAGE, |
| 214 | + SQL_COLUMN_ALIAS, |
| 215 | + SQL_DESCRIBE_PARAMETER, |
| 216 | + SQL_TXN_CAPABLE, |
| 217 | + SQL_TXN_ISOLATION_OPTION, |
| 218 | + SQL_DEFAULT_TXN_ISOLATION, |
| 219 | + SQL_MULTIPLE_ACTIVE_TXN, |
| 220 | + SQL_TXN_ISOLATION_LEVEL, |
| 221 | + SQL_NUMERIC_FUNCTIONS, |
| 222 | + SQL_STRING_FUNCTIONS, |
| 223 | + SQL_DATETIME_FUNCTIONS, |
| 224 | + SQL_SYSTEM_FUNCTIONS, |
| 225 | + SQL_CONVERT_FUNCTIONS, |
| 226 | + SQL_LIKE_ESCAPE_CLAUSE, |
| 227 | + SQL_MAX_COLUMN_NAME_LEN, |
| 228 | + SQL_MAX_TABLE_NAME_LEN, |
| 229 | + SQL_MAX_SCHEMA_NAME_LEN, |
| 230 | + SQL_MAX_CATALOG_NAME_LEN, |
| 231 | + SQL_MAX_IDENTIFIER_LEN, |
| 232 | + SQL_MAX_STATEMENT_LEN, |
| 233 | + SQL_MAX_CHAR_LITERAL_LEN, |
| 234 | + SQL_MAX_BINARY_LITERAL_LEN, |
| 235 | + SQL_MAX_COLUMNS_IN_TABLE, |
| 236 | + SQL_MAX_COLUMNS_IN_SELECT, |
| 237 | + SQL_MAX_COLUMNS_IN_GROUP_BY, |
| 238 | + SQL_MAX_COLUMNS_IN_ORDER_BY, |
| 239 | + SQL_MAX_COLUMNS_IN_INDEX, |
| 240 | + SQL_MAX_TABLES_IN_SELECT, |
| 241 | + SQL_MAX_CONCURRENT_ACTIVITIES, |
| 242 | + SQL_MAX_DRIVER_CONNECTIONS, |
| 243 | + SQL_MAX_ROW_SIZE, |
| 244 | + SQL_MAX_USER_NAME_LEN, |
| 245 | + SQL_ACTIVE_CONNECTIONS, |
| 246 | + SQL_ACTIVE_STATEMENTS, |
| 247 | + SQL_DATA_SOURCE_READ_ONLY, |
| 248 | + SQL_NEED_LONG_DATA_LEN, |
| 249 | + SQL_GETDATA_EXTENSIONS, |
| 250 | + SQL_CURSOR_COMMIT_BEHAVIOR, |
| 251 | + SQL_CURSOR_ROLLBACK_BEHAVIOR, |
| 252 | + SQL_CURSOR_SENSITIVITY, |
| 253 | + SQL_BOOKMARK_PERSISTENCE, |
| 254 | + SQL_DYNAMIC_CURSOR_ATTRIBUTES1, |
| 255 | + SQL_DYNAMIC_CURSOR_ATTRIBUTES2, |
| 256 | + SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES1, |
| 257 | + SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2, |
| 258 | + SQL_STATIC_CURSOR_ATTRIBUTES1, |
| 259 | + SQL_STATIC_CURSOR_ATTRIBUTES2, |
| 260 | + SQL_KEYSET_CURSOR_ATTRIBUTES1, |
| 261 | + SQL_KEYSET_CURSOR_ATTRIBUTES2, |
| 262 | + SQL_SCROLL_OPTIONS, |
| 263 | + SQL_SCROLL_CONCURRENCY, |
| 264 | + SQL_FETCH_DIRECTION, |
| 265 | + SQL_ROWSET_SIZE, |
| 266 | + SQL_CONCURRENCY, |
| 267 | + SQL_ROW_NUMBER, |
| 268 | + SQL_STATIC_SENSITIVITY, |
| 269 | + SQL_BATCH_SUPPORT, |
| 270 | + SQL_BATCH_ROW_COUNT, |
| 271 | + SQL_PARAM_ARRAY_ROW_COUNTS, |
| 272 | + SQL_PARAM_ARRAY_SELECTS, |
| 273 | + SQL_PROCEDURE_TERM, |
| 274 | + SQL_POSITIONED_STATEMENTS, |
| 275 | + SQL_GROUP_BY, |
| 276 | + SQL_OJ_CAPABILITIES, |
| 277 | + SQL_ORDER_BY_COLUMNS_IN_SELECT, |
| 278 | + SQL_OUTER_JOINS, |
| 279 | + SQL_QUOTED_IDENTIFIER_CASE, |
| 280 | + SQL_CONCAT_NULL_BEHAVIOR, |
| 281 | + SQL_NULL_COLLATION, |
| 282 | + SQL_ALTER_TABLE, |
| 283 | + SQL_UNION, |
| 284 | + SQL_DDL_INDEX, |
| 285 | + SQL_MULT_RESULT_SETS, |
| 286 | + SQL_OWNER_USAGE, |
| 287 | + SQL_QUALIFIER_USAGE, |
| 288 | + SQL_TIMEDATE_ADD_INTERVALS, |
| 289 | + SQL_TIMEDATE_DIFF_INTERVALS, |
| 290 | + SQL_IC_UPPER, |
| 291 | + SQL_IC_LOWER, |
| 292 | + SQL_IC_SENSITIVE, |
| 293 | + SQL_IC_MIXED, |
| 294 | +) |
213 | 295 |
|
214 | 296 |
|
215 | 297 | def pooling(max_size: int = 100, idle_timeout: int = 600, enabled: bool = True) -> None: |
@@ -249,81 +331,6 @@ def _custom_setattr(name, value): |
249 | 331 | sys.modules[__name__].__setattr__ = _custom_setattr |
250 | 332 |
|
251 | 333 |
|
252 | | -# Export SQL constants at module level |
253 | | -SQL_VARCHAR: int = ConstantsDDBC.SQL_VARCHAR.value |
254 | | -SQL_LONGVARCHAR: int = ConstantsDDBC.SQL_LONGVARCHAR.value |
255 | | -SQL_WVARCHAR: int = ConstantsDDBC.SQL_WVARCHAR.value |
256 | | -SQL_WLONGVARCHAR: int = ConstantsDDBC.SQL_WLONGVARCHAR.value |
257 | | -SQL_DECIMAL: int = ConstantsDDBC.SQL_DECIMAL.value |
258 | | -SQL_NUMERIC: int = ConstantsDDBC.SQL_NUMERIC.value |
259 | | -SQL_BIT: int = ConstantsDDBC.SQL_BIT.value |
260 | | -SQL_TINYINT: int = ConstantsDDBC.SQL_TINYINT.value |
261 | | -SQL_SMALLINT: int = ConstantsDDBC.SQL_SMALLINT.value |
262 | | -SQL_INTEGER: int = ConstantsDDBC.SQL_INTEGER.value |
263 | | -SQL_BIGINT: int = ConstantsDDBC.SQL_BIGINT.value |
264 | | -SQL_REAL: int = ConstantsDDBC.SQL_REAL.value |
265 | | -SQL_FLOAT: int = ConstantsDDBC.SQL_FLOAT.value |
266 | | -SQL_DOUBLE: int = ConstantsDDBC.SQL_DOUBLE.value |
267 | | -SQL_BINARY: int = ConstantsDDBC.SQL_BINARY.value |
268 | | -SQL_VARBINARY: int = ConstantsDDBC.SQL_VARBINARY.value |
269 | | -SQL_LONGVARBINARY: int = ConstantsDDBC.SQL_LONGVARBINARY.value |
270 | | -SQL_DATE: int = ConstantsDDBC.SQL_DATE.value |
271 | | -SQL_TIME: int = ConstantsDDBC.SQL_TIME.value |
272 | | -SQL_TIMESTAMP: int = ConstantsDDBC.SQL_TIMESTAMP.value |
273 | | - |
274 | | -# Export GetInfo constants at module level |
275 | | -# Driver and database information |
276 | | -SQL_DRIVER_NAME: int = GetInfoConstants.SQL_DRIVER_NAME.value |
277 | | -SQL_DRIVER_VER: int = GetInfoConstants.SQL_DRIVER_VER.value |
278 | | -SQL_DRIVER_ODBC_VER: int = GetInfoConstants.SQL_DRIVER_ODBC_VER.value |
279 | | -SQL_DATA_SOURCE_NAME: int = GetInfoConstants.SQL_DATA_SOURCE_NAME.value |
280 | | -SQL_DATABASE_NAME: int = GetInfoConstants.SQL_DATABASE_NAME.value |
281 | | -SQL_SERVER_NAME: int = GetInfoConstants.SQL_SERVER_NAME.value |
282 | | -SQL_USER_NAME: int = GetInfoConstants.SQL_USER_NAME.value |
283 | | - |
284 | | -# SQL conformance and support |
285 | | -SQL_SQL_CONFORMANCE: int = GetInfoConstants.SQL_SQL_CONFORMANCE.value |
286 | | -SQL_KEYWORDS: int = GetInfoConstants.SQL_KEYWORDS.value |
287 | | -SQL_IDENTIFIER_QUOTE_CHAR: int = GetInfoConstants.SQL_IDENTIFIER_QUOTE_CHAR.value |
288 | | -SQL_SEARCH_PATTERN_ESCAPE: int = GetInfoConstants.SQL_SEARCH_PATTERN_ESCAPE.value |
289 | | - |
290 | | -# Catalog and schema support |
291 | | -SQL_CATALOG_TERM: int = GetInfoConstants.SQL_CATALOG_TERM.value |
292 | | -SQL_SCHEMA_TERM: int = GetInfoConstants.SQL_SCHEMA_TERM.value |
293 | | -SQL_TABLE_TERM: int = GetInfoConstants.SQL_TABLE_TERM.value |
294 | | -SQL_PROCEDURE_TERM: int = GetInfoConstants.SQL_PROCEDURE_TERM.value |
295 | | - |
296 | | -# Transaction support |
297 | | -SQL_TXN_CAPABLE: int = GetInfoConstants.SQL_TXN_CAPABLE.value |
298 | | -SQL_DEFAULT_TXN_ISOLATION: int = GetInfoConstants.SQL_DEFAULT_TXN_ISOLATION.value |
299 | | - |
300 | | -# Data type support |
301 | | -SQL_NUMERIC_FUNCTIONS: int = GetInfoConstants.SQL_NUMERIC_FUNCTIONS.value |
302 | | -SQL_STRING_FUNCTIONS: int = GetInfoConstants.SQL_STRING_FUNCTIONS.value |
303 | | -SQL_DATETIME_FUNCTIONS: int = GetInfoConstants.SQL_DATETIME_FUNCTIONS.value |
304 | | - |
305 | | -# Limits |
306 | | -SQL_MAX_COLUMN_NAME_LEN: int = GetInfoConstants.SQL_MAX_COLUMN_NAME_LEN.value |
307 | | -SQL_MAX_TABLE_NAME_LEN: int = GetInfoConstants.SQL_MAX_TABLE_NAME_LEN.value |
308 | | -SQL_MAX_SCHEMA_NAME_LEN: int = GetInfoConstants.SQL_MAX_SCHEMA_NAME_LEN.value |
309 | | -SQL_MAX_CATALOG_NAME_LEN: int = GetInfoConstants.SQL_MAX_CATALOG_NAME_LEN.value |
310 | | -SQL_MAX_IDENTIFIER_LEN: int = GetInfoConstants.SQL_MAX_IDENTIFIER_LEN.value |
311 | | - |
312 | | - |
313 | | -# Also provide a function to get all constants |
314 | | -def get_info_constants() -> Dict[str, int]: |
315 | | - """ |
316 | | - Returns a dictionary of all available GetInfo constants. |
317 | | -
|
318 | | - This provides all SQLGetInfo constants that can be used with the Connection.getinfo() method |
319 | | - to retrieve metadata about the database server and driver. |
320 | | -
|
321 | | - Returns: |
322 | | - dict: Dictionary mapping constant names to their integer values |
323 | | - """ |
324 | | - return {name: member.value for name, member in GetInfoConstants.__members__.items()} |
325 | | - |
326 | | - |
327 | 334 | # Create a custom module class that uses properties instead of __setattr__ |
328 | 335 | class _MSSQLModule(types.ModuleType): |
329 | 336 | @property |
|
0 commit comments