mssql-python 0.1.6__cp311-cp311-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 mssql-python might be problematic. Click here for more details.

@@ -0,0 +1,55 @@
1
+ """
2
+ Copyright (c) Microsoft Corporation.
3
+ Licensed under the MIT license.
4
+ This module initializes the mssql_python package.
5
+ """
6
+
7
+ # Exceptions
8
+ # https://www.python.org/dev/peps/pep-0249/#exceptions
9
+ from .exceptions import (
10
+ Warning,
11
+ Error,
12
+ InterfaceError,
13
+ DatabaseError,
14
+ DataError,
15
+ OperationalError,
16
+ IntegrityError,
17
+ InternalError,
18
+ ProgrammingError,
19
+ NotSupportedError,
20
+ )
21
+
22
+ # Type Objects
23
+ from .type import (
24
+ Date,
25
+ Time,
26
+ Timestamp,
27
+ DateFromTicks,
28
+ TimeFromTicks,
29
+ TimestampFromTicks,
30
+ Binary,
31
+ STRING,
32
+ BINARY,
33
+ NUMBER,
34
+ DATETIME,
35
+ ROWID,
36
+ )
37
+
38
+ # Connection Objects
39
+ from .connection import Connection
40
+ from .db_connection import connect
41
+
42
+ # Cursor Objects
43
+ from .cursor import Cursor
44
+
45
+ # Logging Configuration
46
+ from .logging_config import setup_logging, get_logger
47
+
48
+ # Constants
49
+ from .constants import ConstantsDDBC
50
+
51
+ # GLOBALS
52
+ # Read-Only
53
+ apilevel = "2.0"
54
+ paramstyle = "qmark"
55
+ threadsafety = 1
@@ -0,0 +1,424 @@
1
+ """
2
+ Copyright (c) Microsoft Corporation.
3
+ Licensed under the MIT license.
4
+ This module defines the Connection class, which is used to manage a connection to a database.
5
+ The class provides methods to establish a connection, create cursors, commit transactions,
6
+ roll back transactions, and close the connection.
7
+ """
8
+ import ctypes
9
+ from mssql_python.cursor import Cursor
10
+ from mssql_python.logging_config import get_logger, ENABLE_LOGGING
11
+ from mssql_python.constants import ConstantsDDBC as ddbc_sql_const
12
+ from mssql_python.helpers import add_driver_to_connection_str, check_error
13
+ from mssql_python import ddbc_bindings
14
+
15
+ logger = get_logger()
16
+
17
+
18
+ class Connection:
19
+ """
20
+ A class to manage a connection to a database, compliant with DB-API 2.0 specifications.
21
+
22
+ This class provides methods to establish a connection to a database, create cursors,
23
+ commit transactions, roll back transactions, and close the connection. It is designed
24
+ to be used in a context where database operations are required, such as executing queries
25
+ and fetching results.
26
+
27
+ Methods:
28
+ __init__(database: str) -> None:
29
+ connect_to_db() -> None:
30
+ cursor() -> Cursor:
31
+ commit() -> None:
32
+ rollback() -> None:
33
+ close() -> None:
34
+ """
35
+
36
+ def __init__(self, connection_str: str = "", autocommit: bool = False, attrs_before: dict = None, **kwargs) -> None:
37
+ """
38
+ Initialize the connection object with the specified connection string and parameters.
39
+
40
+ Args:
41
+ - connection_str (str): The connection string to connect to.
42
+ - autocommit (bool): If True, causes a commit to be performed after each SQL statement.
43
+ **kwargs: Additional key/value pairs for the connection string.
44
+ Not including below properties since we are driver doesn't support this:
45
+
46
+ Returns:
47
+ None
48
+
49
+ Raises:
50
+ ValueError: If the connection string is invalid or connection fails.
51
+
52
+ This method sets up the initial state for the connection object,
53
+ preparing it for further operations such as connecting to the
54
+ database, executing queries, etc.
55
+ """
56
+ self.henv = None
57
+ self.hdbc = None
58
+ self.connection_str = self._construct_connection_string(
59
+ connection_str, **kwargs
60
+ )
61
+ self._attrs_before = attrs_before
62
+ self._autocommit = autocommit # Initialize _autocommit before calling _initializer
63
+ self._initializer()
64
+ self.setautocommit(autocommit)
65
+
66
+ def _construct_connection_string(self, connection_str: str = "", **kwargs) -> str:
67
+ """
68
+ Construct the connection string by concatenating the connection string
69
+ with key/value pairs from kwargs.
70
+
71
+ Args:
72
+ connection_str (str): The base connection string.
73
+ **kwargs: Additional key/value pairs for the connection string.
74
+
75
+ Returns:
76
+ str: The constructed connection string.
77
+ """
78
+ # Add the driver attribute to the connection string
79
+ conn_str = add_driver_to_connection_str(connection_str)
80
+
81
+ # Add additional key-value pairs to the connection string
82
+ for key, value in kwargs.items():
83
+ if key.lower() == "host" or key.lower() == "server":
84
+ key = "Server"
85
+ elif key.lower() == "user" or key.lower() == "uid":
86
+ key = "Uid"
87
+ elif key.lower() == "password" or key.lower() == "pwd":
88
+ key = "Pwd"
89
+ elif key.lower() == "database":
90
+ key = "Database"
91
+ elif key.lower() == "encrypt":
92
+ key = "Encrypt"
93
+ elif key.lower() == "trust_server_certificate":
94
+ key = "TrustServerCertificate"
95
+ else:
96
+ continue
97
+ conn_str += f"{key}={value};"
98
+
99
+ if ENABLE_LOGGING:
100
+ logger.info("Final connection string: %s", conn_str)
101
+
102
+ return conn_str
103
+
104
+ def _is_closed(self) -> bool:
105
+ """
106
+ Check if the connection is closed.
107
+
108
+ Returns:
109
+ bool: True if the connection is closed, False otherwise.
110
+ """
111
+ return self.hdbc is None
112
+
113
+ def _initializer(self) -> None:
114
+ """
115
+ Initialize the environment and connection handles.
116
+
117
+ This method is responsible for setting up the environment and connection
118
+ handles, allocating memory for them, and setting the necessary attributes.
119
+ It should be called before establishing a connection to the database.
120
+ """
121
+ self._allocate_environment_handle()
122
+ self._set_environment_attributes()
123
+ self._allocate_connection_handle()
124
+ if self._attrs_before != {}:
125
+ self._apply_attrs_before() # Apply pre-connection attributes
126
+ if self._autocommit:
127
+ self._set_connection_attributes(
128
+ ddbc_sql_const.SQL_ATTR_AUTOCOMMIT.value,
129
+ ddbc_sql_const.SQL_AUTOCOMMIT_ON.value,
130
+ )
131
+ self._connect_to_db()
132
+
133
+ def _apply_attrs_before(self):
134
+ """
135
+ Apply specific pre-connection attributes.
136
+ Currently, this method only processes an attribute with key 1256 (e.g., SQL_COPT_SS_ACCESS_TOKEN)
137
+ if present in `self._attrs_before`. Other attributes are ignored.
138
+
139
+ Returns:
140
+ bool: True.
141
+ """
142
+
143
+ if ENABLE_LOGGING:
144
+ logger.info("Attempting to apply pre-connection attributes (attrs_before): %s", self._attrs_before)
145
+
146
+ if not isinstance(self._attrs_before, dict):
147
+ if self._attrs_before is not None and ENABLE_LOGGING:
148
+ logger.warning(
149
+ f"_attrs_before is of type {type(self._attrs_before).__name__}, "
150
+ f"expected dict. Skipping attribute application."
151
+ )
152
+ elif self._attrs_before is None and ENABLE_LOGGING:
153
+ logger.debug("_attrs_before is None. No pre-connection attributes to apply.")
154
+ return True # Exit if _attrs_before is not a dictionary or is None
155
+
156
+ for key, value in self._attrs_before.items():
157
+ ikey = None
158
+ if isinstance(key, int):
159
+ ikey = key
160
+ elif isinstance(key, str) and key.isdigit():
161
+ try:
162
+ ikey = int(key)
163
+ except ValueError:
164
+ if ENABLE_LOGGING:
165
+ logger.debug(
166
+ f"Skipping attribute with key '{key}' in attrs_before: "
167
+ f"could not convert string to int."
168
+ )
169
+ continue # Skip if string key is not a valid integer
170
+ else:
171
+ if ENABLE_LOGGING:
172
+ logger.debug(
173
+ f"Skipping attribute with key '{key}' in attrs_before due to "
174
+ f"unsupported key type: {type(key).__name__}. Expected int or string representation of an int."
175
+ )
176
+ continue # Skip keys that are not int or string representation of an int
177
+
178
+ if ikey == ddbc_sql_const.SQL_COPT_SS_ACCESS_TOKEN.value:
179
+ if ENABLE_LOGGING:
180
+ logger.info(
181
+ f"Found attribute {ddbc_sql_const.SQL_COPT_SS_ACCESS_TOKEN.value}. Attempting to set it."
182
+ )
183
+ self._set_connection_attributes(ikey, value)
184
+ if ENABLE_LOGGING:
185
+ logger.info(
186
+ f"Call to set attribute {ddbc_sql_const.SQL_COPT_SS_ACCESS_TOKEN.value} with value '{value}' completed."
187
+ )
188
+ # If you expect only one such key, you could add 'break' here.
189
+ else:
190
+ if ENABLE_LOGGING:
191
+ logger.debug(
192
+ f"Ignoring attribute with key '{key}' (resolved to {ikey}) in attrs_before "
193
+ f"as it is not the target attribute ({ddbc_sql_const.SQL_COPT_SS_ACCESS_TOKEN.value})."
194
+ )
195
+ return True
196
+
197
+ def _allocate_environment_handle(self):
198
+ """
199
+ Allocate the environment handle.
200
+ """
201
+ ret, handle = ddbc_bindings.DDBCSQLAllocHandle(
202
+ ddbc_sql_const.SQL_HANDLE_ENV.value, # SQL environment handle type
203
+ None
204
+ )
205
+ check_error(ddbc_sql_const.SQL_HANDLE_ENV.value, handle, ret)
206
+ self.henv = handle
207
+
208
+ def _set_environment_attributes(self):
209
+ """
210
+ Set the environment attributes.
211
+ """
212
+ ret = ddbc_bindings.DDBCSQLSetEnvAttr(
213
+ self.henv, # Use the wrapper class
214
+ ddbc_sql_const.SQL_ATTR_DDBC_VERSION.value, # Attribute
215
+ ddbc_sql_const.SQL_OV_DDBC3_80.value, # String Length
216
+ 0, # Null-terminated string
217
+ )
218
+ check_error(ddbc_sql_const.SQL_HANDLE_ENV.value, self.henv, ret)
219
+
220
+ def _allocate_connection_handle(self):
221
+ """
222
+ Allocate the connection handle.
223
+ """
224
+ ret, handle = ddbc_bindings.DDBCSQLAllocHandle(
225
+ ddbc_sql_const.SQL_HANDLE_DBC.value, # SQL connection handle type
226
+ self.henv
227
+ )
228
+ check_error(ddbc_sql_const.SQL_HANDLE_DBC.value, handle, ret)
229
+ self.hdbc = handle
230
+
231
+ def _set_connection_attributes(self, ikey: int, ivalue: any) -> None:
232
+ """
233
+ Set the connection attributes before connecting.
234
+
235
+ Args:
236
+ ikey (int): The attribute key to set.
237
+ ivalue (Any): The value to set for the attribute. Can be bytes, bytearray, int, or unicode.
238
+ vallen (int): The length of the value.
239
+
240
+ Raises:
241
+ DatabaseError: If there is an error while setting the connection attribute.
242
+ """
243
+
244
+ ret = ddbc_bindings.DDBCSQLSetConnectAttr(
245
+ self.hdbc, # Connection handle
246
+ ikey, # Attribute
247
+ ivalue, # Value
248
+ )
249
+ check_error(ddbc_sql_const.SQL_HANDLE_DBC.value, self.hdbc, ret)
250
+
251
+ def _connect_to_db(self) -> None:
252
+ """
253
+ Establish a connection to the database.
254
+
255
+ This method is responsible for creating a connection to the specified database.
256
+ It does not take any arguments and does not return any value. The connection
257
+ details such as database name, user credentials, host, and port should be
258
+ configured within the class or passed during the class instantiation.
259
+
260
+ Raises:
261
+ DatabaseError: If there is an error while trying to connect to the database.
262
+ InterfaceError: If there is an error related to the database interface.
263
+ """
264
+ if ENABLE_LOGGING:
265
+ logger.info("Connecting to the database")
266
+ ret = ddbc_bindings.DDBCSQLDriverConnect(
267
+ self.hdbc, # Connection handle (wrapper)
268
+ 0, # Window handle
269
+ self.connection_str, # Connection string
270
+ )
271
+ check_error(ddbc_sql_const.SQL_HANDLE_DBC.value, self.hdbc, ret)
272
+ if ENABLE_LOGGING:
273
+ logger.info("Connection established successfully.")
274
+
275
+ @property
276
+ def autocommit(self) -> bool:
277
+ """
278
+ Return the current autocommit mode of the connection.
279
+ Returns:
280
+ bool: True if autocommit is enabled, False otherwise.
281
+ """
282
+ autocommit_mode = ddbc_bindings.DDBCSQLGetConnectionAttr(
283
+ self.hdbc, # Connection handle (wrapper)
284
+ ddbc_sql_const.SQL_ATTR_AUTOCOMMIT.value, # Attribute
285
+ )
286
+ check_error(
287
+ ddbc_sql_const.SQL_HANDLE_DBC.value, self.hdbc, autocommit_mode
288
+ )
289
+ return autocommit_mode == ddbc_sql_const.SQL_AUTOCOMMIT_ON.value
290
+
291
+ @autocommit.setter
292
+ def autocommit(self, value: bool) -> None:
293
+ """
294
+ Set the autocommit mode of the connection.
295
+ Args:
296
+ value (bool): True to enable autocommit, False to disable it.
297
+ Returns:
298
+ None
299
+ Raises:
300
+ DatabaseError: If there is an error while setting the autocommit mode.
301
+ """
302
+ ret = ddbc_bindings.DDBCSQLSetConnectAttr(
303
+ self.hdbc, # Connection handle
304
+ ddbc_sql_const.SQL_ATTR_AUTOCOMMIT.value, # Attribute
305
+ (
306
+ ddbc_sql_const.SQL_AUTOCOMMIT_ON.value
307
+ if value
308
+ else ddbc_sql_const.SQL_AUTOCOMMIT_OFF.value
309
+ ), # Value
310
+ )
311
+ check_error(ddbc_sql_const.SQL_HANDLE_DBC.value, self.hdbc, ret)
312
+ self._autocommit = value
313
+ if ENABLE_LOGGING:
314
+ logger.info("Autocommit mode set to %s.", value)
315
+
316
+ def setautocommit(self, value: bool = True) -> None:
317
+ """
318
+ Set the autocommit mode of the connection.
319
+ Args:
320
+ value (bool): True to enable autocommit, False to disable it.
321
+ Returns:
322
+ None
323
+ Raises:
324
+ DatabaseError: If there is an error while setting the autocommit mode.
325
+ """
326
+ self.autocommit = value
327
+
328
+ def cursor(self) -> Cursor:
329
+ """
330
+ Return a new Cursor object using the connection.
331
+
332
+ This method creates and returns a new cursor object that can be used to
333
+ execute SQL queries and fetch results. The cursor is associated with the
334
+ current connection and allows interaction with the database.
335
+
336
+ Returns:
337
+ Cursor: A new cursor object for executing SQL queries.
338
+
339
+ Raises:
340
+ DatabaseError: If there is an error while creating the cursor.
341
+ InterfaceError: If there is an error related to the database interface.
342
+ """
343
+ if self._is_closed():
344
+ # Cannot create a cursor if the connection is closed
345
+ raise Exception("Connection is closed. Cannot create cursor.")
346
+ return Cursor(self)
347
+
348
+ def commit(self) -> None:
349
+ """
350
+ Commit the current transaction.
351
+
352
+ This method commits the current transaction to the database, making all
353
+ changes made during the transaction permanent. It should be called after
354
+ executing a series of SQL statements that modify the database to ensure
355
+ that the changes are saved.
356
+
357
+ Raises:
358
+ DatabaseError: If there is an error while committing the transaction.
359
+ """
360
+ if self._is_closed():
361
+ # Cannot commit if the connection is closed
362
+ raise Exception("Connection is closed. Cannot commit.")
363
+
364
+ # Commit the current transaction
365
+ ret = ddbc_bindings.DDBCSQLEndTran(
366
+ ddbc_sql_const.SQL_HANDLE_DBC.value, # Handle type
367
+ self.hdbc, # Connection handle (wrapper)
368
+ ddbc_sql_const.SQL_COMMIT.value, # Commit the transaction
369
+ )
370
+ check_error(ddbc_sql_const.SQL_HANDLE_DBC.value, self.hdbc, ret)
371
+ if ENABLE_LOGGING:
372
+ logger.info("Transaction committed successfully.")
373
+
374
+ def rollback(self) -> None:
375
+ """
376
+ Roll back the current transaction.
377
+
378
+ This method rolls back the current transaction, undoing all changes made
379
+ during the transaction. It should be called if an error occurs during the
380
+ transaction or if the changes should not be saved.
381
+
382
+ Raises:
383
+ DatabaseError: If there is an error while rolling back the transaction.
384
+ """
385
+ if self._is_closed():
386
+ # Cannot roll back if the connection is closed
387
+ raise Exception("Connection is closed. Cannot roll back.")
388
+
389
+ # Roll back the current transaction
390
+ ret = ddbc_bindings.DDBCSQLEndTran(
391
+ ddbc_sql_const.SQL_HANDLE_DBC.value, # Handle type
392
+ self.hdbc, # Connection handle (wrapper)
393
+ ddbc_sql_const.SQL_ROLLBACK.value, # Roll back the transaction
394
+ )
395
+ check_error(ddbc_sql_const.SQL_HANDLE_DBC.value, self.hdbc, ret)
396
+ if ENABLE_LOGGING:
397
+ logger.info("Transaction rolled back successfully.")
398
+
399
+ def close(self) -> None:
400
+ """
401
+ Close the connection now (rather than whenever .__del__() is called).
402
+
403
+ This method closes the connection to the database, releasing any resources
404
+ associated with it. After calling this method, the connection object should
405
+ not be used for any further operations. The same applies to all cursor objects
406
+ trying to use the connection. Note that closing a connection without committing
407
+ the changes first will cause an implicit rollback to be performed.
408
+
409
+ Raises:
410
+ DatabaseError: If there is an error while closing the connection.
411
+ """
412
+ if self._is_closed():
413
+ # Connection is already closed
414
+ return
415
+ # Disconnect from the database
416
+ ret = ddbc_bindings.DDBCSQLDisconnect(self.hdbc)
417
+ check_error(ddbc_sql_const.SQL_HANDLE_DBC.value, self.hdbc, ret)
418
+
419
+ # Set the reference to None to trigger destructor
420
+ self.hdbc.free()
421
+ self.hdbc = None
422
+
423
+ if ENABLE_LOGGING:
424
+ logger.info("Connection closed successfully.")
@@ -0,0 +1,120 @@
1
+ """
2
+ Copyright (c) Microsoft Corporation.
3
+ Licensed under the MIT license.
4
+ This module contains the constants used in the DDBC module.
5
+ """
6
+
7
+ from enum import Enum
8
+
9
+
10
+ class ConstantsDDBC(Enum):
11
+ """
12
+ Constants used in the DDBC module.
13
+ """
14
+ SQL_HANDLE_ENV = 1
15
+ SQL_HANDLE_DBC = 2
16
+ SQL_HANDLE_STMT = 3
17
+ SQL_SUCCESS = 0
18
+ SQL_SUCCESS_WITH_INFO = 1
19
+ SQL_NO_DATA = 100
20
+ SQL_STILL_EXECUTING = 2
21
+ SQL_NTS = -3
22
+ SQL_DRIVER_NOPROMPT = 0
23
+ SQL_ATTR_ASYNC_DBC_EVENT = 119
24
+ SQL_IS_INTEGER = -6
25
+ SQL_ATTR_ASYNC_DBC_FUNCTIONS_ENABLE = 117
26
+ SQL_OV_DDBC3_80 = 380
27
+ SQL_ATTR_DDBC_VERSION = 200
28
+ SQL_ATTR_ASYNC_ENABLE = 4
29
+ SQL_ATTR_ASYNC_STMT_EVENT = 29
30
+ SQL_ERROR = -1
31
+ SQL_INVALID_HANDLE = -2
32
+ SQL_NULL_HANDLE = 0
33
+ SQL_OV_DDBC3 = 3
34
+ SQL_COMMIT = 0
35
+ SQL_ROLLBACK = 1
36
+ SQL_ATTR_AUTOCOMMIT = 102
37
+ SQL_SMALLINT = 5
38
+ SQL_CHAR = 1
39
+ SQL_WCHAR = -8
40
+ SQL_WVARCHAR = -9
41
+ SQL_BIT = -7
42
+ SQL_TINYINT = -6
43
+ SQL_BIGINT = -5
44
+ SQL_BINARY = -2
45
+ SQL_VARBINARY = -3
46
+ SQL_LONGVARBINARY = -4
47
+ SQL_LONGVARCHAR = -1
48
+ SQL_UNKNOWN_TYPE = 0
49
+ SQL_NUMERIC = 2
50
+ SQL_DECIMAL = 3
51
+ SQL_INTEGER = 4
52
+ SQL_FLOAT = 6
53
+ SQL_REAL = 7
54
+ SQL_DOUBLE = 8
55
+ SQL_DATETIME = 9
56
+ SQL_INTERVAL = 10
57
+ SQL_TIMESTAMP = 11
58
+ SQL_DATE = 9
59
+ SQL_TIME = 10
60
+ SQL_VARCHAR = 12
61
+ SQL_TYPE_DATE = 91
62
+ SQL_TYPE_TIME = 92
63
+ SQL_TYPE_TIMESTAMP = 93
64
+ SQL_TYPE_TIMESTAMP_WITH_TIMEZONE = 95
65
+ SQL_GUID = -11
66
+ SQL_XML = 241
67
+ SQL_SMALLDATETIME = 58
68
+ SQL_TIMESTAMPOFFSET = 43
69
+ SQL_DATETIME2 = 42
70
+ SQL_SMALLMONEY = 122
71
+ SQL_MONEY = 60
72
+ SQL_WLONGVARCHAR = -10
73
+ SQL_C_BIT = -7
74
+ SQL_C_TINYINT = -6
75
+ SQL_C_SBIGINT = -25
76
+ SQL_C_BINARY = -2
77
+ SQL_AUTOCOMMIT_ON = 1
78
+ SQL_AUTOCOMMIT_OFF = 0
79
+ SQL_C_VARBINARY = -3
80
+ SQL_C_LONGVARBINARY = -4
81
+ SQL_C_LONGVARCHAR = -1
82
+ SQL_C_CHAR = -8
83
+ SQL_C_NUMERIC = 2
84
+ SQL_C_DECIMAL = 3
85
+ SQL_C_LONG = 4
86
+ SQL_C_SHORT = 5
87
+ SQL_C_FLOAT = 7
88
+ SQL_C_DOUBLE = 8
89
+ SQL_C_TYPE_DATE = 91
90
+ SQL_C_TYPE_TIME = 92
91
+ SQL_C_TYPE_TIMESTAMP = 93
92
+ SQL_C_TYPE_TIMESTAMP_WITH_TIMEZONE = 95
93
+ SQL_C_GUID = -11
94
+ SQL_DESC_TYPE = 2
95
+ SQL_DESC_LENGTH = 3
96
+ SQL_DESC_NAME = 4
97
+ SQL_ATTR_ROW_ARRAY_SIZE = 27
98
+ SQL_ATTR_ROWS_FETCHED_PTR = 26
99
+ SQL_ATTR_ROW_STATUS_PTR = 25
100
+ SQL_FETCH_NEXT = 1
101
+ SQL_ROW_SUCCESS = 0
102
+ SQL_ROW_SUCCESS_WITH_INFO = 1
103
+ SQL_ROW_NOROW = 100
104
+ SQL_ATTR_CURSOR_TYPE = 6
105
+ SQL_CURSOR_FORWARD_ONLY = 0
106
+ SQL_CURSOR_STATIC = 3
107
+ SQL_CURSOR_KEYSET_DRIVEN = 2
108
+ SQL_CURSOR_DYNAMIC = 3
109
+ SQL_NULL_DATA = -1
110
+ SQL_C_DEFAULT = 99
111
+ SQL_ATTR_ROW_BIND_TYPE = 5
112
+ SQL_BIND_BY_COLUMN = 0
113
+ SQL_PARAM_INPUT = 1
114
+ SQL_PARAM_OUTPUT = 2
115
+ SQL_PARAM_INPUT_OUTPUT = 3
116
+ SQL_C_WCHAR = -8
117
+ SQL_NULLABLE = 1
118
+ SQL_MAX_NUMERIC_LEN = 16
119
+ SQL_IS_POINTER = -4
120
+ SQL_COPT_SS_ACCESS_TOKEN = 1256