1 | # -*- coding: utf-8 -*- |
---|
2 | |
---|
3 | # PyPyODBC is develped from RealPyODBC 0.1 beta released in 2004 by Michele Petrazzo. Thanks Michele. |
---|
4 | |
---|
5 | # The MIT License (MIT) |
---|
6 | # |
---|
7 | # Copyright (c) 2014 Henry Zhou <jiangwen365@gmail.com> and PyPyODBC contributors |
---|
8 | # Copyright (c) 2004 Michele Petrazzo |
---|
9 | |
---|
10 | # Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated |
---|
11 | # documentation files (the "Software"), to deal in the Software without restriction, including without limitation |
---|
12 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, |
---|
13 | # and to permit persons to whom the Software is furnished to do so, subject to the following conditions: |
---|
14 | # |
---|
15 | # The above copyright notice and this permission notice shall be included in all copies or substantial portions |
---|
16 | # of the Software. |
---|
17 | # |
---|
18 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO |
---|
19 | # THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
---|
20 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF |
---|
21 | # CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
---|
22 | # DEALINGS IN THE SOFTWARE. |
---|
23 | |
---|
24 | pooling = True |
---|
25 | apilevel = '2.0' |
---|
26 | paramstyle = 'qmark' |
---|
27 | threadsafety = 1 |
---|
28 | version = '1.3.3' |
---|
29 | lowercase=True |
---|
30 | |
---|
31 | DEBUG = 0 |
---|
32 | # Comment out all "if DEBUG:" statements like below for production |
---|
33 | #if DEBUG:print 'DEBUGGING' |
---|
34 | |
---|
35 | import sys, os, datetime, ctypes, threading |
---|
36 | from decimal import Decimal |
---|
37 | |
---|
38 | |
---|
39 | py_ver = sys.version[:3] |
---|
40 | py_v3 = py_ver >= '3.0' |
---|
41 | |
---|
42 | if py_v3: |
---|
43 | long = int |
---|
44 | unicode = str |
---|
45 | str_8b = bytes |
---|
46 | buffer = memoryview |
---|
47 | BYTE_1 = bytes('1','ascii') |
---|
48 | use_unicode = True |
---|
49 | else: |
---|
50 | str_8b = str |
---|
51 | BYTE_1 = '1' |
---|
52 | use_unicode = False |
---|
53 | if py_ver < '2.6': |
---|
54 | bytearray = str |
---|
55 | |
---|
56 | |
---|
57 | if not hasattr(ctypes, 'c_ssize_t'): |
---|
58 | if ctypes.sizeof(ctypes.c_uint) == ctypes.sizeof(ctypes.c_void_p): |
---|
59 | ctypes.c_ssize_t = ctypes.c_int |
---|
60 | elif ctypes.sizeof(ctypes.c_ulong) == ctypes.sizeof(ctypes.c_void_p): |
---|
61 | ctypes.c_ssize_t = ctypes.c_long |
---|
62 | elif ctypes.sizeof(ctypes.c_ulonglong) == ctypes.sizeof(ctypes.c_void_p): |
---|
63 | ctypes.c_ssize_t = ctypes.c_longlong |
---|
64 | |
---|
65 | |
---|
66 | lock = threading.Lock() |
---|
67 | shared_env_h = None |
---|
68 | SQLWCHAR_SIZE = ctypes.sizeof(ctypes.c_wchar) |
---|
69 | |
---|
70 | #determin the size of Py_UNICODE |
---|
71 | #sys.maxunicode > 65536 and 'UCS4' or 'UCS2' |
---|
72 | UNICODE_SIZE = sys.maxunicode > 65536 and 4 or 2 |
---|
73 | |
---|
74 | |
---|
75 | # Define ODBC constants. They are widly used in ODBC documents and programs |
---|
76 | # They are defined in cpp header files: sql.h sqlext.h sqltypes.h sqlucode.h |
---|
77 | # and you can get these files from the mingw32-runtime_3.13-1_all.deb package |
---|
78 | SQL_ATTR_ODBC_VERSION, SQL_OV_ODBC2, SQL_OV_ODBC3 = 200, 2, 3 |
---|
79 | SQL_DRIVER_NOPROMPT = 0 |
---|
80 | SQL_ATTR_CONNECTION_POOLING = 201; SQL_CP_ONE_PER_HENV = 2 |
---|
81 | |
---|
82 | SQL_FETCH_NEXT, SQL_FETCH_FIRST, SQL_FETCH_LAST = 0x01, 0x02, 0x04 |
---|
83 | SQL_NULL_HANDLE, SQL_HANDLE_ENV, SQL_HANDLE_DBC, SQL_HANDLE_STMT = 0, 1, 2, 3 |
---|
84 | SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR = 0, 1, -1 |
---|
85 | SQL_NO_DATA = 100; SQL_NO_TOTAL = -4 |
---|
86 | SQL_ATTR_ACCESS_MODE = SQL_ACCESS_MODE = 101 |
---|
87 | SQL_ATTR_AUTOCOMMIT = SQL_AUTOCOMMIT = 102 |
---|
88 | |
---|
89 | SQL_MODE_DEFAULT = SQL_MODE_READ_WRITE = 0; SQL_MODE_READ_ONLY = 1 |
---|
90 | SQL_AUTOCOMMIT_OFF, SQL_AUTOCOMMIT_ON = 0, 1 |
---|
91 | SQL_IS_UINTEGER = -5 |
---|
92 | SQL_ATTR_LOGIN_TIMEOUT = 103; SQL_ATTR_CONNECTION_TIMEOUT = 113;SQL_ATTR_QUERY_TIMEOUT = 0 |
---|
93 | SQL_COMMIT, SQL_ROLLBACK = 0, 1 |
---|
94 | |
---|
95 | SQL_INDEX_UNIQUE,SQL_INDEX_ALL = 0,1 |
---|
96 | SQL_QUICK,SQL_ENSURE = 0,1 |
---|
97 | SQL_FETCH_NEXT = 1 |
---|
98 | SQL_COLUMN_DISPLAY_SIZE = 6 |
---|
99 | SQL_INVALID_HANDLE = -2 |
---|
100 | SQL_NO_DATA_FOUND = 100; SQL_NULL_DATA = -1; SQL_NTS = -3 |
---|
101 | SQL_HANDLE_DESCR = 4 |
---|
102 | SQL_TABLE_NAMES = 3 |
---|
103 | SQL_PARAM_INPUT = 1; SQL_PARAM_INPUT_OUTPUT = 2 |
---|
104 | SQL_PARAM_TYPE_UNKNOWN = 0 |
---|
105 | SQL_RESULT_COL = 3 |
---|
106 | SQL_PARAM_OUTPUT = 4 |
---|
107 | SQL_RETURN_VALUE = 5 |
---|
108 | SQL_PARAM_TYPE_DEFAULT = SQL_PARAM_INPUT_OUTPUT |
---|
109 | |
---|
110 | SQL_RESET_PARAMS = 3 |
---|
111 | SQL_UNBIND = 2 |
---|
112 | SQL_CLOSE = 0 |
---|
113 | |
---|
114 | |
---|
115 | |
---|
116 | |
---|
117 | # Below defines The constants for sqlgetinfo method, and their coresponding return types |
---|
118 | SQL_QUALIFIER_LOCATION = 114 |
---|
119 | SQL_QUALIFIER_NAME_SEPARATOR = 41 |
---|
120 | SQL_QUALIFIER_TERM = 42 |
---|
121 | SQL_QUALIFIER_USAGE = 92 |
---|
122 | SQL_OWNER_TERM = 39 |
---|
123 | SQL_OWNER_USAGE = 91 |
---|
124 | SQL_ACCESSIBLE_PROCEDURES = 20 |
---|
125 | SQL_ACCESSIBLE_TABLES = 19 |
---|
126 | SQL_ACTIVE_ENVIRONMENTS = 116 |
---|
127 | SQL_AGGREGATE_FUNCTIONS = 169 |
---|
128 | SQL_ALTER_DOMAIN = 117 |
---|
129 | SQL_ALTER_TABLE = 86 |
---|
130 | SQL_ASYNC_MODE = 10021 |
---|
131 | SQL_BATCH_ROW_COUNT = 120 |
---|
132 | SQL_BATCH_SUPPORT = 121 |
---|
133 | SQL_BOOKMARK_PERSISTENCE = 82 |
---|
134 | SQL_CATALOG_LOCATION = SQL_QUALIFIER_LOCATION |
---|
135 | SQL_CATALOG_NAME = 10003 |
---|
136 | SQL_CATALOG_NAME_SEPARATOR = SQL_QUALIFIER_NAME_SEPARATOR |
---|
137 | SQL_CATALOG_TERM = SQL_QUALIFIER_TERM |
---|
138 | SQL_CATALOG_USAGE = SQL_QUALIFIER_USAGE |
---|
139 | SQL_COLLATION_SEQ = 10004 |
---|
140 | SQL_COLUMN_ALIAS = 87 |
---|
141 | SQL_CONCAT_NULL_BEHAVIOR = 22 |
---|
142 | SQL_CONVERT_FUNCTIONS = 48 |
---|
143 | SQL_CONVERT_VARCHAR = 70 |
---|
144 | SQL_CORRELATION_NAME = 74 |
---|
145 | SQL_CREATE_ASSERTION = 127 |
---|
146 | SQL_CREATE_CHARACTER_SET = 128 |
---|
147 | SQL_CREATE_COLLATION = 129 |
---|
148 | SQL_CREATE_DOMAIN = 130 |
---|
149 | SQL_CREATE_SCHEMA = 131 |
---|
150 | SQL_CREATE_TABLE = 132 |
---|
151 | SQL_CREATE_TRANSLATION = 133 |
---|
152 | SQL_CREATE_VIEW = 134 |
---|
153 | SQL_CURSOR_COMMIT_BEHAVIOR = 23 |
---|
154 | SQL_CURSOR_ROLLBACK_BEHAVIOR = 24 |
---|
155 | SQL_DATABASE_NAME = 16 |
---|
156 | SQL_DATA_SOURCE_NAME = 2 |
---|
157 | SQL_DATA_SOURCE_READ_ONLY = 25 |
---|
158 | SQL_DATETIME_LITERALS = 119 |
---|
159 | SQL_DBMS_NAME = 17 |
---|
160 | SQL_DBMS_VER = 18 |
---|
161 | SQL_DDL_INDEX = 170 |
---|
162 | SQL_DEFAULT_TXN_ISOLATION = 26 |
---|
163 | SQL_DESCRIBE_PARAMETER = 10002 |
---|
164 | SQL_DM_VER = 171 |
---|
165 | SQL_DRIVER_NAME = 6 |
---|
166 | SQL_DRIVER_ODBC_VER = 77 |
---|
167 | SQL_DRIVER_VER = 7 |
---|
168 | SQL_DROP_ASSERTION = 136 |
---|
169 | SQL_DROP_CHARACTER_SET = 137 |
---|
170 | SQL_DROP_COLLATION = 138 |
---|
171 | SQL_DROP_DOMAIN = 139 |
---|
172 | SQL_DROP_SCHEMA = 140 |
---|
173 | SQL_DROP_TABLE = 141 |
---|
174 | SQL_DROP_TRANSLATION = 142 |
---|
175 | SQL_DROP_VIEW = 143 |
---|
176 | SQL_DYNAMIC_CURSOR_ATTRIBUTES1 = 144 |
---|
177 | SQL_DYNAMIC_CURSOR_ATTRIBUTES2 = 145 |
---|
178 | SQL_EXPRESSIONS_IN_ORDERBY = 27 |
---|
179 | SQL_FILE_USAGE = 84 |
---|
180 | SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES1 = 146 |
---|
181 | SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2 = 147 |
---|
182 | SQL_GETDATA_EXTENSIONS = 81 |
---|
183 | SQL_GROUP_BY = 88 |
---|
184 | SQL_IDENTIFIER_CASE = 28 |
---|
185 | SQL_IDENTIFIER_QUOTE_CHAR = 29 |
---|
186 | SQL_INDEX_KEYWORDS = 148 |
---|
187 | SQL_INFO_SCHEMA_VIEWS = 149 |
---|
188 | SQL_INSERT_STATEMENT = 172 |
---|
189 | SQL_INTEGRITY = 73 |
---|
190 | SQL_KEYSET_CURSOR_ATTRIBUTES1 = 150 |
---|
191 | SQL_KEYSET_CURSOR_ATTRIBUTES2 = 151 |
---|
192 | SQL_KEYWORDS = 89 |
---|
193 | SQL_LIKE_ESCAPE_CLAUSE = 113 |
---|
194 | SQL_MAX_ASYNC_CONCURRENT_STATEMENTS = 10022 |
---|
195 | SQL_MAX_BINARY_LITERAL_LEN = 112 |
---|
196 | SQL_MAX_CATALOG_NAME_LEN = 34 |
---|
197 | SQL_MAX_CHAR_LITERAL_LEN = 108 |
---|
198 | SQL_MAX_COLUMNS_IN_GROUP_BY = 97 |
---|
199 | SQL_MAX_COLUMNS_IN_INDEX = 98 |
---|
200 | SQL_MAX_COLUMNS_IN_ORDER_BY = 99 |
---|
201 | SQL_MAX_COLUMNS_IN_SELECT = 100 |
---|
202 | SQL_MAX_COLUMNS_IN_TABLE = 101 |
---|
203 | SQL_MAX_COLUMN_NAME_LEN = 30 |
---|
204 | SQL_MAX_CONCURRENT_ACTIVITIES = 1 |
---|
205 | SQL_MAX_CURSOR_NAME_LEN = 31 |
---|
206 | SQL_MAX_DRIVER_CONNECTIONS = 0 |
---|
207 | SQL_MAX_IDENTIFIER_LEN = 10005 |
---|
208 | SQL_MAX_INDEX_SIZE = 102 |
---|
209 | SQL_MAX_PROCEDURE_NAME_LEN = 33 |
---|
210 | SQL_MAX_ROW_SIZE = 104 |
---|
211 | SQL_MAX_ROW_SIZE_INCLUDES_LONG = 103 |
---|
212 | SQL_MAX_SCHEMA_NAME_LEN = 32 |
---|
213 | SQL_MAX_STATEMENT_LEN = 105 |
---|
214 | SQL_MAX_TABLES_IN_SELECT = 106 |
---|
215 | SQL_MAX_TABLE_NAME_LEN = 35 |
---|
216 | SQL_MAX_USER_NAME_LEN = 107 |
---|
217 | SQL_MULTIPLE_ACTIVE_TXN = 37 |
---|
218 | SQL_MULT_RESULT_SETS = 36 |
---|
219 | SQL_NEED_LONG_DATA_LEN = 111 |
---|
220 | SQL_NON_NULLABLE_COLUMNS = 75 |
---|
221 | SQL_NULL_COLLATION = 85 |
---|
222 | SQL_NUMERIC_FUNCTIONS = 49 |
---|
223 | SQL_ODBC_INTERFACE_CONFORMANCE = 152 |
---|
224 | SQL_ODBC_VER = 10 |
---|
225 | SQL_OJ_CAPABILITIES = 65003 |
---|
226 | SQL_ORDER_BY_COLUMNS_IN_SELECT = 90 |
---|
227 | SQL_PARAM_ARRAY_ROW_COUNTS = 153 |
---|
228 | SQL_PARAM_ARRAY_SELECTS = 154 |
---|
229 | SQL_PROCEDURES = 21 |
---|
230 | SQL_PROCEDURE_TERM = 40 |
---|
231 | SQL_QUOTED_IDENTIFIER_CASE = 93 |
---|
232 | SQL_ROW_UPDATES = 11 |
---|
233 | SQL_SCHEMA_TERM = SQL_OWNER_TERM |
---|
234 | SQL_SCHEMA_USAGE = SQL_OWNER_USAGE |
---|
235 | SQL_SCROLL_OPTIONS = 44 |
---|
236 | SQL_SEARCH_PATTERN_ESCAPE = 14 |
---|
237 | SQL_SERVER_NAME = 13 |
---|
238 | SQL_SPECIAL_CHARACTERS = 94 |
---|
239 | SQL_SQL92_DATETIME_FUNCTIONS = 155 |
---|
240 | SQL_SQL92_FOREIGN_KEY_DELETE_RULE = 156 |
---|
241 | SQL_SQL92_FOREIGN_KEY_UPDATE_RULE = 157 |
---|
242 | SQL_SQL92_GRANT = 158 |
---|
243 | SQL_SQL92_NUMERIC_VALUE_FUNCTIONS = 159 |
---|
244 | SQL_SQL92_PREDICATES = 160 |
---|
245 | SQL_SQL92_RELATIONAL_JOIN_OPERATORS = 161 |
---|
246 | SQL_SQL92_REVOKE = 162 |
---|
247 | SQL_SQL92_ROW_VALUE_CONSTRUCTOR = 163 |
---|
248 | SQL_SQL92_STRING_FUNCTIONS = 164 |
---|
249 | SQL_SQL92_VALUE_EXPRESSIONS = 165 |
---|
250 | SQL_SQL_CONFORMANCE = 118 |
---|
251 | SQL_STANDARD_CLI_CONFORMANCE = 166 |
---|
252 | SQL_STATIC_CURSOR_ATTRIBUTES1 = 167 |
---|
253 | SQL_STATIC_CURSOR_ATTRIBUTES2 = 168 |
---|
254 | SQL_STRING_FUNCTIONS = 50 |
---|
255 | SQL_SUBQUERIES = 95 |
---|
256 | SQL_SYSTEM_FUNCTIONS = 51 |
---|
257 | SQL_TABLE_TERM = 45 |
---|
258 | SQL_TIMEDATE_ADD_INTERVALS = 109 |
---|
259 | SQL_TIMEDATE_DIFF_INTERVALS = 110 |
---|
260 | SQL_TIMEDATE_FUNCTIONS = 52 |
---|
261 | SQL_TXN_CAPABLE = 46 |
---|
262 | SQL_TXN_ISOLATION_OPTION = 72 |
---|
263 | SQL_UNION = 96 |
---|
264 | SQL_USER_NAME = 47 |
---|
265 | SQL_XOPEN_CLI_YEAR = 10000 |
---|
266 | |
---|
267 | |
---|
268 | aInfoTypes = { |
---|
269 | SQL_ACCESSIBLE_PROCEDURES : 'GI_YESNO',SQL_ACCESSIBLE_TABLES : 'GI_YESNO',SQL_ACTIVE_ENVIRONMENTS : 'GI_USMALLINT', |
---|
270 | SQL_AGGREGATE_FUNCTIONS : 'GI_UINTEGER',SQL_ALTER_DOMAIN : 'GI_UINTEGER', |
---|
271 | SQL_ALTER_TABLE : 'GI_UINTEGER',SQL_ASYNC_MODE : 'GI_UINTEGER',SQL_BATCH_ROW_COUNT : 'GI_UINTEGER', |
---|
272 | SQL_BATCH_SUPPORT : 'GI_UINTEGER',SQL_BOOKMARK_PERSISTENCE : 'GI_UINTEGER',SQL_CATALOG_LOCATION : 'GI_USMALLINT', |
---|
273 | SQL_CATALOG_NAME : 'GI_YESNO',SQL_CATALOG_NAME_SEPARATOR : 'GI_STRING',SQL_CATALOG_TERM : 'GI_STRING', |
---|
274 | SQL_CATALOG_USAGE : 'GI_UINTEGER',SQL_COLLATION_SEQ : 'GI_STRING',SQL_COLUMN_ALIAS : 'GI_YESNO', |
---|
275 | SQL_CONCAT_NULL_BEHAVIOR : 'GI_USMALLINT',SQL_CONVERT_FUNCTIONS : 'GI_UINTEGER',SQL_CONVERT_VARCHAR : 'GI_UINTEGER', |
---|
276 | SQL_CORRELATION_NAME : 'GI_USMALLINT',SQL_CREATE_ASSERTION : 'GI_UINTEGER',SQL_CREATE_CHARACTER_SET : 'GI_UINTEGER', |
---|
277 | SQL_CREATE_COLLATION : 'GI_UINTEGER',SQL_CREATE_DOMAIN : 'GI_UINTEGER',SQL_CREATE_SCHEMA : 'GI_UINTEGER', |
---|
278 | SQL_CREATE_TABLE : 'GI_UINTEGER',SQL_CREATE_TRANSLATION : 'GI_UINTEGER',SQL_CREATE_VIEW : 'GI_UINTEGER', |
---|
279 | SQL_CURSOR_COMMIT_BEHAVIOR : 'GI_USMALLINT',SQL_CURSOR_ROLLBACK_BEHAVIOR : 'GI_USMALLINT',SQL_DATABASE_NAME : 'GI_STRING', |
---|
280 | SQL_DATA_SOURCE_NAME : 'GI_STRING',SQL_DATA_SOURCE_READ_ONLY : 'GI_YESNO',SQL_DATETIME_LITERALS : 'GI_UINTEGER', |
---|
281 | SQL_DBMS_NAME : 'GI_STRING',SQL_DBMS_VER : 'GI_STRING',SQL_DDL_INDEX : 'GI_UINTEGER', |
---|
282 | SQL_DEFAULT_TXN_ISOLATION : 'GI_UINTEGER',SQL_DESCRIBE_PARAMETER : 'GI_YESNO',SQL_DM_VER : 'GI_STRING', |
---|
283 | SQL_DRIVER_NAME : 'GI_STRING',SQL_DRIVER_ODBC_VER : 'GI_STRING',SQL_DRIVER_VER : 'GI_STRING',SQL_DROP_ASSERTION : 'GI_UINTEGER', |
---|
284 | SQL_DROP_CHARACTER_SET : 'GI_UINTEGER', SQL_DROP_COLLATION : 'GI_UINTEGER',SQL_DROP_DOMAIN : 'GI_UINTEGER', |
---|
285 | SQL_DROP_SCHEMA : 'GI_UINTEGER',SQL_DROP_TABLE : 'GI_UINTEGER',SQL_DROP_TRANSLATION : 'GI_UINTEGER', |
---|
286 | SQL_DROP_VIEW : 'GI_UINTEGER',SQL_DYNAMIC_CURSOR_ATTRIBUTES1 : 'GI_UINTEGER',SQL_DYNAMIC_CURSOR_ATTRIBUTES2 : 'GI_UINTEGER', |
---|
287 | SQL_EXPRESSIONS_IN_ORDERBY : 'GI_YESNO',SQL_FILE_USAGE : 'GI_USMALLINT', |
---|
288 | SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES1 : 'GI_UINTEGER',SQL_FORWARD_ONLY_CURSOR_ATTRIBUTES2 : 'GI_UINTEGER', |
---|
289 | SQL_GETDATA_EXTENSIONS : 'GI_UINTEGER',SQL_GROUP_BY : 'GI_USMALLINT',SQL_IDENTIFIER_CASE : 'GI_USMALLINT', |
---|
290 | SQL_IDENTIFIER_QUOTE_CHAR : 'GI_STRING',SQL_INDEX_KEYWORDS : 'GI_UINTEGER',SQL_INFO_SCHEMA_VIEWS : 'GI_UINTEGER', |
---|
291 | SQL_INSERT_STATEMENT : 'GI_UINTEGER',SQL_INTEGRITY : 'GI_YESNO',SQL_KEYSET_CURSOR_ATTRIBUTES1 : 'GI_UINTEGER', |
---|
292 | SQL_KEYSET_CURSOR_ATTRIBUTES2 : 'GI_UINTEGER',SQL_KEYWORDS : 'GI_STRING', |
---|
293 | SQL_LIKE_ESCAPE_CLAUSE : 'GI_YESNO',SQL_MAX_ASYNC_CONCURRENT_STATEMENTS : 'GI_UINTEGER', |
---|
294 | SQL_MAX_BINARY_LITERAL_LEN : 'GI_UINTEGER',SQL_MAX_CATALOG_NAME_LEN : 'GI_USMALLINT', |
---|
295 | SQL_MAX_CHAR_LITERAL_LEN : 'GI_UINTEGER',SQL_MAX_COLUMNS_IN_GROUP_BY : 'GI_USMALLINT', |
---|
296 | SQL_MAX_COLUMNS_IN_INDEX : 'GI_USMALLINT',SQL_MAX_COLUMNS_IN_ORDER_BY : 'GI_USMALLINT', |
---|
297 | SQL_MAX_COLUMNS_IN_SELECT : 'GI_USMALLINT',SQL_MAX_COLUMNS_IN_TABLE : 'GI_USMALLINT', |
---|
298 | SQL_MAX_COLUMN_NAME_LEN : 'GI_USMALLINT',SQL_MAX_CONCURRENT_ACTIVITIES : 'GI_USMALLINT', |
---|
299 | SQL_MAX_CURSOR_NAME_LEN : 'GI_USMALLINT',SQL_MAX_DRIVER_CONNECTIONS : 'GI_USMALLINT', |
---|
300 | SQL_MAX_IDENTIFIER_LEN : 'GI_USMALLINT',SQL_MAX_INDEX_SIZE : 'GI_UINTEGER', |
---|
301 | SQL_MAX_PROCEDURE_NAME_LEN : 'GI_USMALLINT',SQL_MAX_ROW_SIZE : 'GI_UINTEGER', |
---|
302 | SQL_MAX_ROW_SIZE_INCLUDES_LONG : 'GI_YESNO',SQL_MAX_SCHEMA_NAME_LEN : 'GI_USMALLINT', |
---|
303 | SQL_MAX_STATEMENT_LEN : 'GI_UINTEGER',SQL_MAX_TABLES_IN_SELECT : 'GI_USMALLINT', |
---|
304 | SQL_MAX_TABLE_NAME_LEN : 'GI_USMALLINT',SQL_MAX_USER_NAME_LEN : 'GI_USMALLINT', |
---|
305 | SQL_MULTIPLE_ACTIVE_TXN : 'GI_YESNO',SQL_MULT_RESULT_SETS : 'GI_YESNO', |
---|
306 | SQL_NEED_LONG_DATA_LEN : 'GI_YESNO',SQL_NON_NULLABLE_COLUMNS : 'GI_USMALLINT', |
---|
307 | SQL_NULL_COLLATION : 'GI_USMALLINT',SQL_NUMERIC_FUNCTIONS : 'GI_UINTEGER', |
---|
308 | SQL_ODBC_INTERFACE_CONFORMANCE : 'GI_UINTEGER',SQL_ODBC_VER : 'GI_STRING',SQL_OJ_CAPABILITIES : 'GI_UINTEGER', |
---|
309 | SQL_ORDER_BY_COLUMNS_IN_SELECT : 'GI_YESNO',SQL_PARAM_ARRAY_ROW_COUNTS : 'GI_UINTEGER', |
---|
310 | SQL_PARAM_ARRAY_SELECTS : 'GI_UINTEGER',SQL_PROCEDURES : 'GI_YESNO',SQL_PROCEDURE_TERM : 'GI_STRING', |
---|
311 | SQL_QUOTED_IDENTIFIER_CASE : 'GI_USMALLINT',SQL_ROW_UPDATES : 'GI_YESNO',SQL_SCHEMA_TERM : 'GI_STRING', |
---|
312 | SQL_SCHEMA_USAGE : 'GI_UINTEGER',SQL_SCROLL_OPTIONS : 'GI_UINTEGER',SQL_SEARCH_PATTERN_ESCAPE : 'GI_STRING', |
---|
313 | SQL_SERVER_NAME : 'GI_STRING',SQL_SPECIAL_CHARACTERS : 'GI_STRING',SQL_SQL92_DATETIME_FUNCTIONS : 'GI_UINTEGER', |
---|
314 | SQL_SQL92_FOREIGN_KEY_DELETE_RULE : 'GI_UINTEGER',SQL_SQL92_FOREIGN_KEY_UPDATE_RULE : 'GI_UINTEGER', |
---|
315 | SQL_SQL92_GRANT : 'GI_UINTEGER',SQL_SQL92_NUMERIC_VALUE_FUNCTIONS : 'GI_UINTEGER', |
---|
316 | SQL_SQL92_PREDICATES : 'GI_UINTEGER',SQL_SQL92_RELATIONAL_JOIN_OPERATORS : 'GI_UINTEGER', |
---|
317 | SQL_SQL92_REVOKE : 'GI_UINTEGER',SQL_SQL92_ROW_VALUE_CONSTRUCTOR : 'GI_UINTEGER', |
---|
318 | SQL_SQL92_STRING_FUNCTIONS : 'GI_UINTEGER',SQL_SQL92_VALUE_EXPRESSIONS : 'GI_UINTEGER', |
---|
319 | SQL_SQL_CONFORMANCE : 'GI_UINTEGER',SQL_STANDARD_CLI_CONFORMANCE : 'GI_UINTEGER', |
---|
320 | SQL_STATIC_CURSOR_ATTRIBUTES1 : 'GI_UINTEGER',SQL_STATIC_CURSOR_ATTRIBUTES2 : 'GI_UINTEGER', |
---|
321 | SQL_STRING_FUNCTIONS : 'GI_UINTEGER',SQL_SUBQUERIES : 'GI_UINTEGER', |
---|
322 | SQL_SYSTEM_FUNCTIONS : 'GI_UINTEGER',SQL_TABLE_TERM : 'GI_STRING',SQL_TIMEDATE_ADD_INTERVALS : 'GI_UINTEGER', |
---|
323 | SQL_TIMEDATE_DIFF_INTERVALS : 'GI_UINTEGER',SQL_TIMEDATE_FUNCTIONS : 'GI_UINTEGER', |
---|
324 | SQL_TXN_CAPABLE : 'GI_USMALLINT',SQL_TXN_ISOLATION_OPTION : 'GI_UINTEGER', |
---|
325 | SQL_UNION : 'GI_UINTEGER',SQL_USER_NAME : 'GI_STRING',SQL_XOPEN_CLI_YEAR : 'GI_STRING', |
---|
326 | } |
---|
327 | |
---|
328 | #Definations for types |
---|
329 | BINARY = bytearray |
---|
330 | Binary = bytearray |
---|
331 | DATETIME = datetime.datetime |
---|
332 | Date = datetime.date |
---|
333 | Time = datetime.time |
---|
334 | Timestamp = datetime.datetime |
---|
335 | STRING = str |
---|
336 | NUMBER = float |
---|
337 | ROWID = int |
---|
338 | DateFromTicks = datetime.date.fromtimestamp |
---|
339 | TimeFromTicks = lambda x: datetime.datetime.fromtimestamp(x).time() |
---|
340 | TimestampFromTicks = datetime.datetime.fromtimestamp |
---|
341 | |
---|
342 | |
---|
343 | #Define exceptions |
---|
344 | class OdbcNoLibrary(Exception): |
---|
345 | def __init__(self, value): |
---|
346 | self.value = value |
---|
347 | def __str__(self): |
---|
348 | return repr(self.value) |
---|
349 | class OdbcLibraryError(Exception): |
---|
350 | def __init__(self, value): |
---|
351 | self.value = value |
---|
352 | def __str__(self): |
---|
353 | return repr(self.value) |
---|
354 | class OdbcInvalidHandle(Exception): |
---|
355 | def __init__(self, value): |
---|
356 | self.value = value |
---|
357 | def __str__(self): |
---|
358 | return repr(self.value) |
---|
359 | class OdbcGenericError(Exception): |
---|
360 | def __init__(self, value): |
---|
361 | self.value = value |
---|
362 | def __str__(self): |
---|
363 | return repr(self.value) |
---|
364 | class Warning(Exception): |
---|
365 | def __init__(self, error_code, error_desc): |
---|
366 | self.value = (error_code, error_desc) |
---|
367 | self.args = (error_code, error_desc) |
---|
368 | class Error(Exception): |
---|
369 | def __init__(self, error_code, error_desc): |
---|
370 | self.value = (error_code, error_desc) |
---|
371 | self.args = (error_code, error_desc) |
---|
372 | class InterfaceError(Error): |
---|
373 | def __init__(self, error_code, error_desc): |
---|
374 | self.value = (error_code, error_desc) |
---|
375 | self.args = (error_code, error_desc) |
---|
376 | class DatabaseError(Error): |
---|
377 | def __init__(self, error_code, error_desc): |
---|
378 | self.value = (error_code, error_desc) |
---|
379 | self.args = (error_code, error_desc) |
---|
380 | class InternalError(DatabaseError): |
---|
381 | def __init__(self, error_code, error_desc): |
---|
382 | self.value = (error_code, error_desc) |
---|
383 | self.args = (error_code, error_desc) |
---|
384 | class ProgrammingError(DatabaseError): |
---|
385 | def __init__(self, error_code, error_desc): |
---|
386 | self.value = (error_code, error_desc) |
---|
387 | self.args = (error_code, error_desc) |
---|
388 | class DataError(DatabaseError): |
---|
389 | def __init__(self, error_code, error_desc): |
---|
390 | self.value = (error_code, error_desc) |
---|
391 | self.args = (error_code, error_desc) |
---|
392 | class IntegrityError(DatabaseError): |
---|
393 | def __init__(self, error_code, error_desc): |
---|
394 | self.value = (error_code, error_desc) |
---|
395 | self.args = (error_code, error_desc) |
---|
396 | class NotSupportedError(Error): |
---|
397 | def __init__(self, error_code, error_desc): |
---|
398 | self.value = (error_code, error_desc) |
---|
399 | self.args = (error_code, error_desc) |
---|
400 | class OperationalError(DatabaseError): |
---|
401 | def __init__(self, error_code, error_desc): |
---|
402 | self.value = (error_code, error_desc) |
---|
403 | self.args = (error_code, error_desc) |
---|
404 | |
---|
405 | |
---|
406 | |
---|
407 | |
---|
408 | ############################################################################ |
---|
409 | # |
---|
410 | # Find the ODBC library on the platform and connect to it using ctypes |
---|
411 | # |
---|
412 | ############################################################################ |
---|
413 | # Get the References of the platform's ODBC functions via ctypes |
---|
414 | |
---|
415 | odbc_decoding = 'utf_16' |
---|
416 | odbc_encoding = 'utf_16_le' |
---|
417 | ucs_length = 2 |
---|
418 | |
---|
419 | if sys.platform in ('win32','cli'): |
---|
420 | ODBC_API = ctypes.windll.odbc32 |
---|
421 | # On Windows, the size of SQLWCHAR is hardcoded to 2-bytes. |
---|
422 | SQLWCHAR_SIZE = ctypes.sizeof(ctypes.c_ushort) |
---|
423 | else: |
---|
424 | # Set load the library on linux |
---|
425 | try: |
---|
426 | # First try direct loading libodbc.so |
---|
427 | ODBC_API = ctypes.cdll.LoadLibrary('libodbc.so') |
---|
428 | except: |
---|
429 | # If direct loading libodbc.so failed |
---|
430 | # We try finding the libodbc.so by using find_library |
---|
431 | from ctypes.util import find_library |
---|
432 | library = find_library('odbc') |
---|
433 | if library is None: |
---|
434 | # If find_library still can not find the library |
---|
435 | # we try finding it manually from where libodbc.so usually appears |
---|
436 | lib_paths = ("/usr/lib/libodbc.so","/usr/lib/i386-linux-gnu/libodbc.so","/usr/lib/x86_64-linux-gnu/libodbc.so","/usr/lib/libiodbc.dylib") |
---|
437 | lib_paths = [path for path in lib_paths if os.path.exists(path)] |
---|
438 | if len(lib_paths) == 0 : |
---|
439 | raise OdbcNoLibrary('ODBC Library is not found. Is LD_LIBRARY_PATH set?') |
---|
440 | else: |
---|
441 | library = lib_paths[0] |
---|
442 | |
---|
443 | # Then we try loading the found libodbc.so again |
---|
444 | try: |
---|
445 | ODBC_API = ctypes.cdll.LoadLibrary(library) |
---|
446 | except: |
---|
447 | # If still fail loading, abort. |
---|
448 | raise OdbcLibraryError('Error while loading ' + library) |
---|
449 | |
---|
450 | # only iODBC uses utf-32 / UCS4 encoding data, others normally use utf-16 / UCS2 |
---|
451 | # So we set those for handling. |
---|
452 | if 'libiodbc.dylib' in library: |
---|
453 | odbc_decoding = 'utf_32' |
---|
454 | odbc_encoding = 'utf_32_le' |
---|
455 | ucs_length = 4 |
---|
456 | |
---|
457 | |
---|
458 | # unixODBC defaults to 2-bytes SQLWCHAR, unless "-DSQL_WCHART_CONVERT" was |
---|
459 | # added to CFLAGS, in which case it will be the size of wchar_t. |
---|
460 | # Note that using 4-bytes SQLWCHAR will break most ODBC drivers, as driver |
---|
461 | # development mostly targets the Windows platform. |
---|
462 | if py_v3: |
---|
463 | from subprocess import getstatusoutput |
---|
464 | else: |
---|
465 | from commands import getstatusoutput |
---|
466 | |
---|
467 | status, output = getstatusoutput('odbc_config --cflags') |
---|
468 | if status == 0 and 'SQL_WCHART_CONVERT' in output: |
---|
469 | SQLWCHAR_SIZE = ctypes.sizeof(ctypes.c_wchar) |
---|
470 | else: |
---|
471 | SQLWCHAR_SIZE = ctypes.sizeof(ctypes.c_ushort) |
---|
472 | |
---|
473 | |
---|
474 | create_buffer_u = ctypes.create_unicode_buffer |
---|
475 | create_buffer = ctypes.create_string_buffer |
---|
476 | wchar_pointer = ctypes.c_wchar_p |
---|
477 | UCS_buf = lambda s: s |
---|
478 | def UCS_dec(buffer): |
---|
479 | i = 0 |
---|
480 | uchars = [] |
---|
481 | while True: |
---|
482 | uchar = buffer.raw[i:i + ucs_length].decode(odbc_decoding) |
---|
483 | if uchar == unicode('\x00'): |
---|
484 | break |
---|
485 | uchars.append(uchar) |
---|
486 | i += ucs_length |
---|
487 | return ''.join(uchars) |
---|
488 | from_buffer_u = lambda buffer: buffer.value |
---|
489 | |
---|
490 | # This is the common case on Linux, which uses wide Python build together with |
---|
491 | # the default unixODBC without the "-DSQL_WCHART_CONVERT" CFLAGS. |
---|
492 | if sys.platform not in ('win32','cli'): |
---|
493 | if UNICODE_SIZE >= SQLWCHAR_SIZE: |
---|
494 | # We can only use unicode buffer if the size of wchar_t (UNICODE_SIZE) is |
---|
495 | # the same as the size expected by the driver manager (SQLWCHAR_SIZE). |
---|
496 | create_buffer_u = create_buffer |
---|
497 | wchar_pointer = ctypes.c_char_p |
---|
498 | |
---|
499 | def UCS_buf(s): |
---|
500 | return s.encode(odbc_encoding) |
---|
501 | |
---|
502 | from_buffer_u = UCS_dec |
---|
503 | |
---|
504 | # Exoteric case, don't really care. |
---|
505 | elif UNICODE_SIZE < SQLWCHAR_SIZE: |
---|
506 | raise OdbcLibraryError('Using narrow Python build with ODBC library ' |
---|
507 | 'expecting wide unicode is not supported.') |
---|
508 | |
---|
509 | |
---|
510 | |
---|
511 | |
---|
512 | |
---|
513 | |
---|
514 | |
---|
515 | |
---|
516 | |
---|
517 | |
---|
518 | |
---|
519 | |
---|
520 | ############################################################ |
---|
521 | # Database value to Python data type mappings |
---|
522 | |
---|
523 | |
---|
524 | SQL_TYPE_NULL = 0 |
---|
525 | SQL_DECIMAL = 3 |
---|
526 | SQL_FLOAT = 6 |
---|
527 | SQL_DATE = 9 |
---|
528 | SQL_TIME = 10 |
---|
529 | SQL_TIMESTAMP = 11 |
---|
530 | SQL_VARCHAR = 12 |
---|
531 | SQL_LONGVARCHAR = -1 |
---|
532 | SQL_VARBINARY = -3 |
---|
533 | SQL_LONGVARBINARY = -4 |
---|
534 | SQL_BIGINT = -5 |
---|
535 | SQL_WVARCHAR = -9 |
---|
536 | SQL_WLONGVARCHAR = -10 |
---|
537 | SQL_ALL_TYPES = 0 |
---|
538 | SQL_SIGNED_OFFSET = -20 |
---|
539 | SQL_SS_VARIANT = -150 |
---|
540 | SQL_SS_UDT = -151 |
---|
541 | SQL_SS_XML = -152 |
---|
542 | SQL_SS_TIME2 = -154 |
---|
543 | |
---|
544 | SQL_C_CHAR = SQL_CHAR = 1 |
---|
545 | SQL_C_NUMERIC = SQL_NUMERIC = 2 |
---|
546 | SQL_C_LONG = SQL_INTEGER = 4 |
---|
547 | SQL_C_SLONG = SQL_C_LONG + SQL_SIGNED_OFFSET |
---|
548 | SQL_C_SHORT = SQL_SMALLINT = 5 |
---|
549 | SQL_C_FLOAT = SQL_REAL = 7 |
---|
550 | SQL_C_DOUBLE = SQL_DOUBLE = 8 |
---|
551 | SQL_C_TYPE_DATE = SQL_TYPE_DATE = 91 |
---|
552 | SQL_C_TYPE_TIME = SQL_TYPE_TIME = 92 |
---|
553 | SQL_C_BINARY = SQL_BINARY = -2 |
---|
554 | SQL_C_SBIGINT = SQL_BIGINT + SQL_SIGNED_OFFSET |
---|
555 | SQL_C_TINYINT = SQL_TINYINT = -6 |
---|
556 | SQL_C_BIT = SQL_BIT = -7 |
---|
557 | SQL_C_WCHAR = SQL_WCHAR = -8 |
---|
558 | SQL_C_GUID = SQL_GUID = -11 |
---|
559 | SQL_C_TYPE_TIMESTAMP = SQL_TYPE_TIMESTAMP = 93 |
---|
560 | SQL_C_DEFAULT = 99 |
---|
561 | |
---|
562 | SQL_DESC_DISPLAY_SIZE = SQL_COLUMN_DISPLAY_SIZE |
---|
563 | |
---|
564 | def dttm_cvt(x): |
---|
565 | if py_v3: |
---|
566 | x = x.decode('ascii') |
---|
567 | if x == '': return None |
---|
568 | x = x.ljust(26,'0') |
---|
569 | return datetime.datetime(int(x[0:4]),int(x[5:7]),int(x[8:10]),int(x[10:13]),int(x[14:16]),int(x[17:19]),int(x[20:26])) |
---|
570 | |
---|
571 | def tm_cvt(x): |
---|
572 | if py_v3: |
---|
573 | x = x.decode('ascii') |
---|
574 | if x == '': return None |
---|
575 | x = x.ljust(15,'0') |
---|
576 | return datetime.time(int(x[0:2]),int(x[3:5]),int(x[6:8]),int(x[9:15])) |
---|
577 | |
---|
578 | def dt_cvt(x): |
---|
579 | if py_v3: |
---|
580 | x = x.decode('ascii') |
---|
581 | if x == '': return None |
---|
582 | else:return datetime.date(int(x[0:4]),int(x[5:7]),int(x[8:10])) |
---|
583 | |
---|
584 | def Decimal_cvt(x): |
---|
585 | if py_v3: |
---|
586 | x = x.decode('ascii') |
---|
587 | return Decimal(x) |
---|
588 | |
---|
589 | bytearray_cvt = bytearray |
---|
590 | if sys.platform == 'cli': |
---|
591 | bytearray_cvt = lambda x: bytearray(buffer(x)) |
---|
592 | |
---|
593 | # Below Datatype mappings referenced the document at |
---|
594 | # http://infocenter.sybase.com/help/index.jsp?topic=/com.sybase.help.sdk_12.5.1.aseodbc/html/aseodbc/CACFDIGH.htm |
---|
595 | |
---|
596 | SQL_data_type_dict = { \ |
---|
597 | #SQL Data TYPE 0.Python Data Type 1.Default Output Converter 2.Buffer Type 3.Buffer Allocator 4.Default Size 5.Variable Length |
---|
598 | SQL_TYPE_NULL : (None, lambda x: None, SQL_C_CHAR, create_buffer, 2 , False ), |
---|
599 | SQL_CHAR : (str, lambda x: x, SQL_C_CHAR, create_buffer, 2048 , False ), |
---|
600 | SQL_NUMERIC : (Decimal, Decimal_cvt, SQL_C_CHAR, create_buffer, 150 , False ), |
---|
601 | SQL_DECIMAL : (Decimal, Decimal_cvt, SQL_C_CHAR, create_buffer, 150 , False ), |
---|
602 | SQL_INTEGER : (int, int, SQL_C_CHAR, create_buffer, 150 , False ), |
---|
603 | SQL_SMALLINT : (int, int, SQL_C_CHAR, create_buffer, 150 , False ), |
---|
604 | SQL_FLOAT : (float, float, SQL_C_CHAR, create_buffer, 150 , False ), |
---|
605 | SQL_REAL : (float, float, SQL_C_CHAR, create_buffer, 150 , False ), |
---|
606 | SQL_DOUBLE : (float, float, SQL_C_CHAR, create_buffer, 200 , False ), |
---|
607 | SQL_DATE : (datetime.date, dt_cvt, SQL_C_CHAR, create_buffer, 30 , False ), |
---|
608 | SQL_TIME : (datetime.time, tm_cvt, SQL_C_CHAR, create_buffer, 20 , False ), |
---|
609 | SQL_SS_TIME2 : (datetime.time, tm_cvt, SQL_C_CHAR, create_buffer, 20 , False ), |
---|
610 | SQL_TIMESTAMP : (datetime.datetime, dttm_cvt, SQL_C_CHAR, create_buffer, 30 , False ), |
---|
611 | SQL_VARCHAR : (str, lambda x: x, SQL_C_CHAR, create_buffer, 2048 , False ), |
---|
612 | SQL_LONGVARCHAR : (str, lambda x: x, SQL_C_CHAR, create_buffer, 20500 , True ), |
---|
613 | SQL_BINARY : (bytearray, bytearray_cvt, SQL_C_BINARY, create_buffer, 5120 , True ), |
---|
614 | SQL_VARBINARY : (bytearray, bytearray_cvt, SQL_C_BINARY, create_buffer, 5120 , True ), |
---|
615 | SQL_LONGVARBINARY : (bytearray, bytearray_cvt, SQL_C_BINARY, create_buffer, 20500 , True ), |
---|
616 | SQL_BIGINT : (long, long, SQL_C_CHAR, create_buffer, 150 , False ), |
---|
617 | SQL_TINYINT : (int, int, SQL_C_CHAR, create_buffer, 150 , False ), |
---|
618 | SQL_BIT : (bool, lambda x:x == BYTE_1, SQL_C_CHAR, create_buffer, 2 , False ), |
---|
619 | SQL_WCHAR : (unicode, lambda x: x, SQL_C_WCHAR, create_buffer_u, 2048 , False ), |
---|
620 | SQL_WVARCHAR : (unicode, lambda x: x, SQL_C_WCHAR, create_buffer_u, 2048 , False ), |
---|
621 | SQL_GUID : (str, str, SQL_C_CHAR, create_buffer, 2048 , False ), |
---|
622 | SQL_WLONGVARCHAR : (unicode, lambda x: x, SQL_C_WCHAR, create_buffer_u, 20500 , True ), |
---|
623 | SQL_TYPE_DATE : (datetime.date, dt_cvt, SQL_C_CHAR, create_buffer, 30 , False ), |
---|
624 | SQL_TYPE_TIME : (datetime.time, tm_cvt, SQL_C_CHAR, create_buffer, 20 , False ), |
---|
625 | SQL_TYPE_TIMESTAMP : (datetime.datetime, dttm_cvt, SQL_C_CHAR, create_buffer, 30 , False ), |
---|
626 | SQL_SS_VARIANT : (str, lambda x: x, SQL_C_CHAR, create_buffer, 2048 , True ), |
---|
627 | SQL_SS_XML : (unicode, lambda x: x, SQL_C_WCHAR, create_buffer_u, 20500 , True ), |
---|
628 | SQL_SS_UDT : (bytearray, bytearray_cvt, SQL_C_BINARY, create_buffer, 5120 , True ), |
---|
629 | } |
---|
630 | |
---|
631 | |
---|
632 | """ |
---|
633 | Types mapping, applicable for 32-bit and 64-bit Linux / Windows / Mac OS X. |
---|
634 | |
---|
635 | SQLPointer -> ctypes.c_void_p |
---|
636 | SQLCHAR * -> ctypes.c_char_p |
---|
637 | SQLWCHAR * -> ctypes.c_wchar_p on Windows, ctypes.c_char_p with unixODBC |
---|
638 | SQLINT -> ctypes.c_int |
---|
639 | SQLSMALLINT -> ctypes.c_short |
---|
640 | SQMUSMALLINT -> ctypes.c_ushort |
---|
641 | SQLLEN -> ctypes.c_ssize_t |
---|
642 | SQLULEN -> ctypes.c_size_t |
---|
643 | SQLRETURN -> ctypes.c_short |
---|
644 | """ |
---|
645 | |
---|
646 | # Define the python return type for ODBC functions with ret result. |
---|
647 | funcs_with_ret = [ |
---|
648 | "SQLAllocHandle", |
---|
649 | "SQLBindParameter", |
---|
650 | "SQLBindCol", |
---|
651 | "SQLCloseCursor", |
---|
652 | "SQLColAttribute", |
---|
653 | "SQLColumns", |
---|
654 | "SQLColumnsW", |
---|
655 | "SQLConnect", |
---|
656 | "SQLConnectW", |
---|
657 | "SQLDataSources", |
---|
658 | "SQLDataSourcesW", |
---|
659 | "SQLDescribeCol", |
---|
660 | "SQLDescribeColW", |
---|
661 | "SQLDescribeParam", |
---|
662 | "SQLDisconnect", |
---|
663 | "SQLDriverConnect", |
---|
664 | "SQLDriverConnectW", |
---|
665 | "SQLDrivers", |
---|
666 | "SQLDriversW", |
---|
667 | "SQLEndTran", |
---|
668 | "SQLExecDirect", |
---|
669 | "SQLExecDirectW", |
---|
670 | "SQLExecute", |
---|
671 | "SQLFetch", |
---|
672 | "SQLFetchScroll", |
---|
673 | "SQLForeignKeys", |
---|
674 | "SQLForeignKeysW", |
---|
675 | "SQLFreeHandle", |
---|
676 | "SQLFreeStmt", |
---|
677 | "SQLGetData", |
---|
678 | "SQLGetDiagRec", |
---|
679 | "SQLGetDiagRecW", |
---|
680 | "SQLGetInfo", |
---|
681 | "SQLGetInfoW", |
---|
682 | "SQLGetTypeInfo", |
---|
683 | "SQLMoreResults", |
---|
684 | "SQLNumParams", |
---|
685 | "SQLNumResultCols", |
---|
686 | "SQLPrepare", |
---|
687 | "SQLPrepareW", |
---|
688 | "SQLPrimaryKeys", |
---|
689 | "SQLPrimaryKeysW", |
---|
690 | "SQLProcedureColumns", |
---|
691 | "SQLProcedureColumnsW", |
---|
692 | "SQLProcedures", |
---|
693 | "SQLProceduresW", |
---|
694 | "SQLRowCount", |
---|
695 | "SQLSetConnectAttr", |
---|
696 | "SQLSetEnvAttr", |
---|
697 | "SQLStatistics", |
---|
698 | "SQLStatisticsW", |
---|
699 | "SQLTables", |
---|
700 | "SQLTablesW", |
---|
701 | "SQLSetStmtAttr" |
---|
702 | ] |
---|
703 | |
---|
704 | for func_name in funcs_with_ret: |
---|
705 | getattr(ODBC_API, func_name).restype = ctypes.c_short |
---|
706 | |
---|
707 | if sys.platform not in ('cli'): |
---|
708 | #Seems like the IronPython can not declare ctypes.POINTER type arguments |
---|
709 | ODBC_API.SQLAllocHandle.argtypes = [ |
---|
710 | ctypes.c_short, ctypes.c_void_p, ctypes.POINTER(ctypes.c_void_p), |
---|
711 | ] |
---|
712 | |
---|
713 | ODBC_API.SQLBindParameter.argtypes = [ |
---|
714 | ctypes.c_void_p, ctypes.c_ushort, ctypes.c_short, |
---|
715 | ctypes.c_short, ctypes.c_short, ctypes.c_size_t, |
---|
716 | ctypes.c_short, ctypes.c_void_p, ctypes.c_ssize_t, ctypes.POINTER(ctypes.c_ssize_t), |
---|
717 | ] |
---|
718 | |
---|
719 | ODBC_API.SQLColAttribute.argtypes = [ |
---|
720 | ctypes.c_void_p, ctypes.c_ushort, ctypes.c_ushort, |
---|
721 | ctypes.c_void_p, ctypes.c_short, ctypes.POINTER(ctypes.c_short), ctypes.POINTER(ctypes.c_ssize_t), |
---|
722 | ] |
---|
723 | |
---|
724 | ODBC_API.SQLDataSources.argtypes = [ |
---|
725 | ctypes.c_void_p, ctypes.c_ushort, ctypes.c_char_p, |
---|
726 | ctypes.c_short, ctypes.POINTER(ctypes.c_short), |
---|
727 | ctypes.c_char_p, ctypes.c_short, ctypes.POINTER(ctypes.c_short), |
---|
728 | ] |
---|
729 | |
---|
730 | ODBC_API.SQLDescribeCol.argtypes = [ |
---|
731 | ctypes.c_void_p, ctypes.c_ushort, ctypes.c_char_p, ctypes.c_short, |
---|
732 | ctypes.POINTER(ctypes.c_short), ctypes.POINTER(ctypes.c_short), |
---|
733 | ctypes.POINTER(ctypes.c_size_t), ctypes.POINTER(ctypes.c_short), ctypes.POINTER(ctypes.c_short), |
---|
734 | ] |
---|
735 | |
---|
736 | ODBC_API.SQLDescribeParam.argtypes = [ |
---|
737 | ctypes.c_void_p, ctypes.c_ushort, |
---|
738 | ctypes.POINTER(ctypes.c_short), ctypes.POINTER(ctypes.c_size_t), |
---|
739 | ctypes.POINTER(ctypes.c_short), ctypes.POINTER(ctypes.c_short), |
---|
740 | ] |
---|
741 | |
---|
742 | ODBC_API.SQLDriverConnect.argtypes = [ |
---|
743 | ctypes.c_void_p, ctypes.c_void_p, ctypes.c_char_p, |
---|
744 | ctypes.c_short, ctypes.c_char_p, ctypes.c_short, |
---|
745 | ctypes.POINTER(ctypes.c_short), ctypes.c_ushort, |
---|
746 | ] |
---|
747 | |
---|
748 | ODBC_API.SQLDrivers.argtypes = [ |
---|
749 | ctypes.c_void_p, ctypes.c_ushort, |
---|
750 | ctypes.c_char_p, ctypes.c_short, ctypes.POINTER(ctypes.c_short), |
---|
751 | ctypes.c_char_p, ctypes.c_short, ctypes.POINTER(ctypes.c_short), |
---|
752 | ] |
---|
753 | |
---|
754 | ODBC_API.SQLGetData.argtypes = [ |
---|
755 | ctypes.c_void_p, ctypes.c_ushort, ctypes.c_short, |
---|
756 | ctypes.c_void_p, ctypes.c_ssize_t, ctypes.POINTER(ctypes.c_ssize_t), |
---|
757 | ] |
---|
758 | |
---|
759 | ODBC_API.SQLGetDiagRec.argtypes = [ |
---|
760 | ctypes.c_short, ctypes.c_void_p, ctypes.c_short, |
---|
761 | ctypes.c_char_p, ctypes.POINTER(ctypes.c_int), |
---|
762 | ctypes.c_char_p, ctypes.c_short, ctypes.POINTER(ctypes.c_short), |
---|
763 | ] |
---|
764 | |
---|
765 | ODBC_API.SQLGetInfo.argtypes = [ |
---|
766 | ctypes.c_void_p, ctypes.c_ushort, ctypes.c_void_p, |
---|
767 | ctypes.c_short, ctypes.POINTER(ctypes.c_short), |
---|
768 | ] |
---|
769 | |
---|
770 | ODBC_API.SQLRowCount.argtypes = [ |
---|
771 | ctypes.c_void_p, ctypes.POINTER(ctypes.c_ssize_t), |
---|
772 | ] |
---|
773 | |
---|
774 | ODBC_API.SQLNumParams.argtypes = [ |
---|
775 | ctypes.c_void_p, ctypes.POINTER(ctypes.c_short), |
---|
776 | ] |
---|
777 | |
---|
778 | ODBC_API.SQLNumResultCols.argtypes = [ |
---|
779 | ctypes.c_void_p, ctypes.POINTER(ctypes.c_short), |
---|
780 | ] |
---|
781 | |
---|
782 | |
---|
783 | ODBC_API.SQLCloseCursor.argtypes = [ctypes.c_void_p] |
---|
784 | |
---|
785 | ODBC_API.SQLColumns.argtypes = [ |
---|
786 | ctypes.c_void_p, ctypes.c_char_p, ctypes.c_short, |
---|
787 | ctypes.c_char_p, ctypes.c_short, ctypes.c_char_p, |
---|
788 | ctypes.c_short, ctypes.c_char_p, ctypes.c_short, |
---|
789 | ] |
---|
790 | |
---|
791 | ODBC_API.SQLConnect.argtypes = [ |
---|
792 | ctypes.c_void_p, ctypes.c_char_p, ctypes.c_short, |
---|
793 | ctypes.c_char_p, ctypes.c_short, ctypes.c_char_p, ctypes.c_short, |
---|
794 | ] |
---|
795 | |
---|
796 | ODBC_API.SQLDisconnect.argtypes = [ctypes.c_void_p] |
---|
797 | |
---|
798 | ODBC_API.SQLEndTran.argtypes = [ |
---|
799 | ctypes.c_short, ctypes.c_void_p, ctypes.c_short, |
---|
800 | ] |
---|
801 | |
---|
802 | ODBC_API.SQLExecute.argtypes = [ctypes.c_void_p] |
---|
803 | |
---|
804 | ODBC_API.SQLExecDirect.argtypes = [ |
---|
805 | ctypes.c_void_p, ctypes.c_char_p, ctypes.c_int, |
---|
806 | ] |
---|
807 | |
---|
808 | ODBC_API.SQLFetch.argtypes = [ctypes.c_void_p] |
---|
809 | |
---|
810 | ODBC_API.SQLFetchScroll.argtypes = [ |
---|
811 | ctypes.c_void_p, ctypes.c_short, ctypes.c_ssize_t, |
---|
812 | ] |
---|
813 | |
---|
814 | ODBC_API.SQLForeignKeys.argtypes = [ |
---|
815 | ctypes.c_void_p, ctypes.c_char_p, ctypes.c_short, |
---|
816 | ctypes.c_char_p, ctypes.c_short, ctypes.c_char_p, |
---|
817 | ctypes.c_short, ctypes.c_char_p, ctypes.c_short, |
---|
818 | ctypes.c_char_p, ctypes.c_short, ctypes.c_char_p, ctypes.c_short, |
---|
819 | ] |
---|
820 | |
---|
821 | ODBC_API.SQLFreeHandle.argtypes = [ |
---|
822 | ctypes.c_short, ctypes.c_void_p, |
---|
823 | ] |
---|
824 | |
---|
825 | ODBC_API.SQLFreeStmt.argtypes = [ |
---|
826 | ctypes.c_void_p, ctypes.c_ushort, |
---|
827 | ] |
---|
828 | |
---|
829 | |
---|
830 | ODBC_API.SQLGetTypeInfo.argtypes = [ |
---|
831 | ctypes.c_void_p, ctypes.c_short, |
---|
832 | ] |
---|
833 | |
---|
834 | ODBC_API.SQLMoreResults.argtypes = [ctypes.c_void_p] |
---|
835 | |
---|
836 | |
---|
837 | ODBC_API.SQLPrepare.argtypes = [ |
---|
838 | ctypes.c_void_p, ctypes.c_char_p, ctypes.c_int, |
---|
839 | ] |
---|
840 | |
---|
841 | ODBC_API.SQLPrimaryKeys.argtypes = [ |
---|
842 | ctypes.c_void_p, ctypes.c_char_p, ctypes.c_short, |
---|
843 | ctypes.c_char_p, ctypes.c_short, ctypes.c_char_p, ctypes.c_short, |
---|
844 | ] |
---|
845 | |
---|
846 | ODBC_API.SQLProcedureColumns.argtypes = [ |
---|
847 | ctypes.c_void_p, ctypes.c_char_p, ctypes.c_short, |
---|
848 | ctypes.c_char_p, ctypes.c_short, ctypes.c_char_p, |
---|
849 | ctypes.c_short, ctypes.c_char_p, ctypes.c_short, |
---|
850 | ] |
---|
851 | |
---|
852 | ODBC_API.SQLProcedures.argtypes = [ |
---|
853 | ctypes.c_void_p, ctypes.c_char_p, ctypes.c_short, |
---|
854 | ctypes.c_char_p, ctypes.c_short, ctypes.c_char_p, ctypes.c_short, |
---|
855 | ] |
---|
856 | |
---|
857 | |
---|
858 | ODBC_API.SQLSetConnectAttr.argtypes = [ |
---|
859 | ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p, ctypes.c_int, |
---|
860 | ] |
---|
861 | |
---|
862 | ODBC_API.SQLSetEnvAttr.argtypes = [ |
---|
863 | ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p, ctypes.c_int, |
---|
864 | ] |
---|
865 | |
---|
866 | ODBC_API.SQLStatistics.argtypes = [ |
---|
867 | ctypes.c_void_p, ctypes.c_char_p, ctypes.c_short, |
---|
868 | ctypes.c_char_p, ctypes.c_short, ctypes.c_char_p, |
---|
869 | ctypes.c_short, ctypes.c_ushort, ctypes.c_ushort, |
---|
870 | ] |
---|
871 | |
---|
872 | ODBC_API.SQLTables.argtypes = [ |
---|
873 | ctypes.c_void_p, ctypes.c_char_p, ctypes.c_short, |
---|
874 | ctypes.c_char_p, ctypes.c_short, ctypes.c_char_p, |
---|
875 | ctypes.c_short, ctypes.c_char_p, ctypes.c_short, |
---|
876 | ] |
---|
877 | |
---|
878 | def to_wchar(argtypes): |
---|
879 | if argtypes: # Under IronPython some argtypes are not declared |
---|
880 | result = [] |
---|
881 | for x in argtypes: |
---|
882 | if x == ctypes.c_char_p: |
---|
883 | result.append(wchar_pointer) |
---|
884 | else: |
---|
885 | result.append(x) |
---|
886 | return result |
---|
887 | else: |
---|
888 | return argtypes |
---|
889 | |
---|
890 | ODBC_API.SQLColumnsW.argtypes = to_wchar(ODBC_API.SQLColumns.argtypes) |
---|
891 | ODBC_API.SQLConnectW.argtypes = to_wchar(ODBC_API.SQLConnect.argtypes) |
---|
892 | ODBC_API.SQLDataSourcesW.argtypes = to_wchar(ODBC_API.SQLDataSources.argtypes) |
---|
893 | ODBC_API.SQLDescribeColW.argtypes = to_wchar(ODBC_API.SQLDescribeCol.argtypes) |
---|
894 | ODBC_API.SQLDriverConnectW.argtypes = to_wchar(ODBC_API.SQLDriverConnect.argtypes) |
---|
895 | ODBC_API.SQLDriversW.argtypes = to_wchar(ODBC_API.SQLDrivers.argtypes) |
---|
896 | ODBC_API.SQLExecDirectW.argtypes = to_wchar(ODBC_API.SQLExecDirect.argtypes) |
---|
897 | ODBC_API.SQLForeignKeysW.argtypes = to_wchar(ODBC_API.SQLForeignKeys.argtypes) |
---|
898 | ODBC_API.SQLPrepareW.argtypes = to_wchar(ODBC_API.SQLPrepare.argtypes) |
---|
899 | ODBC_API.SQLPrimaryKeysW.argtypes = to_wchar(ODBC_API.SQLPrimaryKeys.argtypes) |
---|
900 | ODBC_API.SQLProcedureColumnsW.argtypes = to_wchar(ODBC_API.SQLProcedureColumns.argtypes) |
---|
901 | ODBC_API.SQLProceduresW.argtypes = to_wchar(ODBC_API.SQLProcedures.argtypes) |
---|
902 | ODBC_API.SQLStatisticsW.argtypes = to_wchar(ODBC_API.SQLStatistics.argtypes) |
---|
903 | ODBC_API.SQLTablesW.argtypes = to_wchar(ODBC_API.SQLTables.argtypes) |
---|
904 | ODBC_API.SQLGetDiagRecW.argtypes = to_wchar(ODBC_API.SQLGetDiagRec.argtypes) |
---|
905 | ODBC_API.SQLGetInfoW.argtypes = to_wchar(ODBC_API.SQLGetInfo.argtypes) |
---|
906 | |
---|
907 | # Set the alias for the ctypes functions for beter code readbility or performance. |
---|
908 | ADDR = ctypes.byref |
---|
909 | c_short = ctypes.c_short |
---|
910 | c_ssize_t = ctypes.c_ssize_t |
---|
911 | SQLFetch = ODBC_API.SQLFetch |
---|
912 | SQLExecute = ODBC_API.SQLExecute |
---|
913 | SQLBindParameter = ODBC_API.SQLBindParameter |
---|
914 | SQLGetData = ODBC_API.SQLGetData |
---|
915 | SQLRowCount = ODBC_API.SQLRowCount |
---|
916 | SQLNumResultCols = ODBC_API.SQLNumResultCols |
---|
917 | SQLEndTran = ODBC_API.SQLEndTran |
---|
918 | # Set alias for beter code readbility or performance. |
---|
919 | NO_FREE_STATEMENT = 0 |
---|
920 | FREE_STATEMENT = 1 |
---|
921 | BLANK_BYTE = str_8b() |
---|
922 | |
---|
923 | def ctrl_err(ht, h, val_ret, ansi): |
---|
924 | """Classify type of ODBC error from (type of handle, handle, return value) |
---|
925 | , and raise with a list""" |
---|
926 | |
---|
927 | if ansi: |
---|
928 | state = create_buffer(22) |
---|
929 | Message = create_buffer(1024*4) |
---|
930 | ODBC_func = ODBC_API.SQLGetDiagRec |
---|
931 | if py_v3: |
---|
932 | raw_s = lambda s: bytes(s,'ascii') |
---|
933 | else: |
---|
934 | raw_s = str_8b |
---|
935 | else: |
---|
936 | state = create_buffer_u(22) |
---|
937 | Message = create_buffer_u(1024*4) |
---|
938 | ODBC_func = ODBC_API.SQLGetDiagRecW |
---|
939 | raw_s = unicode |
---|
940 | NativeError = ctypes.c_int() |
---|
941 | Buffer_len = c_short() |
---|
942 | err_list = [] |
---|
943 | number_errors = 1 |
---|
944 | |
---|
945 | while 1: |
---|
946 | ret = ODBC_func(ht, h, number_errors, state, \ |
---|
947 | ADDR(NativeError), Message, 1024, ADDR(Buffer_len)) |
---|
948 | if ret == SQL_NO_DATA_FOUND: |
---|
949 | #No more data, I can raise |
---|
950 | #print(err_list[0][1]) |
---|
951 | state = err_list[0][0] |
---|
952 | err_text = raw_s('[')+state+raw_s('] ')+err_list[0][1] |
---|
953 | if state[:2] in (raw_s('24'),raw_s('25'),raw_s('42')): |
---|
954 | raise ProgrammingError(state,err_text) |
---|
955 | elif state[:2] in (raw_s('22')): |
---|
956 | raise DataError(state,err_text) |
---|
957 | elif state[:2] in (raw_s('23')) or state == raw_s('40002'): |
---|
958 | raise IntegrityError(state,err_text) |
---|
959 | elif state == raw_s('0A000'): |
---|
960 | raise NotSupportedError(state,err_text) |
---|
961 | elif state in (raw_s('HYT00'),raw_s('HYT01')): |
---|
962 | raise OperationalError(state,err_text) |
---|
963 | elif state[:2] in (raw_s('IM'),raw_s('HY')): |
---|
964 | raise Error(state,err_text) |
---|
965 | else: |
---|
966 | raise DatabaseError(state,err_text) |
---|
967 | break |
---|
968 | elif ret == SQL_INVALID_HANDLE: |
---|
969 | #The handle passed is an invalid handle |
---|
970 | raise ProgrammingError('', 'SQL_INVALID_HANDLE') |
---|
971 | elif ret == SQL_SUCCESS: |
---|
972 | if ansi: |
---|
973 | err_list.append((state.value, Message.value, NativeError.value)) |
---|
974 | else: |
---|
975 | err_list.append((from_buffer_u(state), from_buffer_u(Message), NativeError.value)) |
---|
976 | number_errors += 1 |
---|
977 | elif ret == SQL_ERROR: |
---|
978 | raise ProgrammingError('', 'SQL_ERROR') |
---|
979 | |
---|
980 | |
---|
981 | |
---|
982 | def check_success(ODBC_obj, ret): |
---|
983 | """ Validate return value, if not success, raise exceptions based on the handle """ |
---|
984 | if ret not in (SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_NO_DATA): |
---|
985 | if isinstance(ODBC_obj, Cursor): |
---|
986 | ctrl_err(SQL_HANDLE_STMT, ODBC_obj.stmt_h, ret, ODBC_obj.ansi) |
---|
987 | elif isinstance(ODBC_obj, Connection): |
---|
988 | ctrl_err(SQL_HANDLE_DBC, ODBC_obj.dbc_h, ret, ODBC_obj.ansi) |
---|
989 | else: |
---|
990 | ctrl_err(SQL_HANDLE_ENV, ODBC_obj, ret, False) |
---|
991 | |
---|
992 | |
---|
993 | def AllocateEnv(): |
---|
994 | if pooling: |
---|
995 | ret = ODBC_API.SQLSetEnvAttr(SQL_NULL_HANDLE, SQL_ATTR_CONNECTION_POOLING, SQL_CP_ONE_PER_HENV, SQL_IS_UINTEGER) |
---|
996 | check_success(SQL_NULL_HANDLE, ret) |
---|
997 | |
---|
998 | ''' |
---|
999 | Allocate an ODBC environment by initializing the handle shared_env_h |
---|
1000 | ODBC enviroment needed to be created, so connections can be created under it |
---|
1001 | connections pooling can be shared under one environment |
---|
1002 | ''' |
---|
1003 | global shared_env_h |
---|
1004 | shared_env_h = ctypes.c_void_p() |
---|
1005 | ret = ODBC_API.SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, ADDR(shared_env_h)) |
---|
1006 | check_success(shared_env_h, ret) |
---|
1007 | |
---|
1008 | # Set the ODBC environment's compatibil leve to ODBC 3.0 |
---|
1009 | ret = ODBC_API.SQLSetEnvAttr(shared_env_h, SQL_ATTR_ODBC_VERSION, SQL_OV_ODBC3, 0) |
---|
1010 | check_success(shared_env_h, ret) |
---|
1011 | |
---|
1012 | |
---|
1013 | """ |
---|
1014 | Here, we have a few callables that determine how a result row is returned. |
---|
1015 | |
---|
1016 | A new one can be added by creating a callable that: |
---|
1017 | - accepts a cursor as its parameter. |
---|
1018 | - returns a callable that accepts an iterable containing the row values. |
---|
1019 | """ |
---|
1020 | |
---|
1021 | def TupleRow(cursor): |
---|
1022 | """Normal tuple with added attribute `cursor_description`, as in pyodbc. |
---|
1023 | |
---|
1024 | This is the default. |
---|
1025 | """ |
---|
1026 | class Row(tuple): |
---|
1027 | cursor_description = cursor.description |
---|
1028 | |
---|
1029 | def get(self, field): |
---|
1030 | if not hasattr(self, 'field_dict'): |
---|
1031 | self.field_dict = {} |
---|
1032 | for i,item in enumerate(self): |
---|
1033 | self.field_dict[self.cursor_description[i][0]] = item |
---|
1034 | return self.field_dict.get(field) |
---|
1035 | |
---|
1036 | def __getitem__(self, field): |
---|
1037 | if isinstance(field, (unicode,str)): |
---|
1038 | return self.get(field) |
---|
1039 | else: |
---|
1040 | return tuple.__getitem__(self,field) |
---|
1041 | |
---|
1042 | return Row |
---|
1043 | |
---|
1044 | |
---|
1045 | def NamedTupleRow(cursor): |
---|
1046 | """Named tuple to allow attribute lookup by name. |
---|
1047 | |
---|
1048 | Requires py2.6 or above. |
---|
1049 | """ |
---|
1050 | from collections import namedtuple |
---|
1051 | |
---|
1052 | attr_names = [x[0] for x in cursor._ColBufferList] |
---|
1053 | |
---|
1054 | class Row(namedtuple('Row', attr_names, rename=True)): |
---|
1055 | cursor_description = cursor.description |
---|
1056 | |
---|
1057 | def __new__(cls, iterable): |
---|
1058 | return super(Row, cls).__new__(cls, *iterable) |
---|
1059 | |
---|
1060 | return Row |
---|
1061 | |
---|
1062 | |
---|
1063 | def MutableNamedTupleRow(cursor): |
---|
1064 | """Mutable named tuple to allow attribute to be replaced. This should be |
---|
1065 | compatible with pyodbc's Row type. |
---|
1066 | |
---|
1067 | Requires 3rd-party library "recordtype". |
---|
1068 | """ |
---|
1069 | from recordtype import recordtype |
---|
1070 | |
---|
1071 | attr_names = [x[0] for x in cursor._ColBufferList] |
---|
1072 | |
---|
1073 | class Row(recordtype('Row', attr_names, rename=True)): |
---|
1074 | cursor_description = cursor.description |
---|
1075 | |
---|
1076 | def __init__(self, iterable): |
---|
1077 | super(Row, self).__init__(*iterable) |
---|
1078 | |
---|
1079 | def __iter__(self): |
---|
1080 | for field_name in self.__slots__: |
---|
1081 | yield getattr(self, field_name) |
---|
1082 | |
---|
1083 | def __getitem__(self, index): |
---|
1084 | if isinstance(index, slice): |
---|
1085 | return tuple(getattr(self, x) for x in self.__slots__[index]) |
---|
1086 | return getattr(self, self.__slots__[index]) |
---|
1087 | |
---|
1088 | def __setitem__(self, index, value): |
---|
1089 | setattr(self, self.__slots__[index], value) |
---|
1090 | |
---|
1091 | return Row |
---|
1092 | |
---|
1093 | # When Null is used in a binary parameter, database usually would not |
---|
1094 | # accept the None for a binary field, so the work around is to use a |
---|
1095 | # Specical None that the pypyodbc moudle would know this NULL is for |
---|
1096 | # a binary field. |
---|
1097 | class BinaryNullType(): pass |
---|
1098 | BinaryNull = BinaryNullType() |
---|
1099 | |
---|
1100 | # The get_type function is used to determine if parameters need to be re-binded |
---|
1101 | # against the changed parameter types |
---|
1102 | # 'b' for bool, 'U' for long unicode string, 'u' for short unicode string |
---|
1103 | # 'S' for long 8 bit string, 's' for short 8 bit string, 'l' for big integer, 'i' for normal integer |
---|
1104 | # 'f' for float, 'D' for Decimal, 't' for datetime.time, 'd' for datetime.datetime, 'dt' for datetime.datetime |
---|
1105 | # 'bi' for binary |
---|
1106 | def get_type(v): |
---|
1107 | |
---|
1108 | if isinstance(v, bool): |
---|
1109 | return ('b',) |
---|
1110 | elif isinstance(v, unicode): |
---|
1111 | if len(v) >= 255: |
---|
1112 | return ('U',(len(v)//1000+1)*1000) |
---|
1113 | else: |
---|
1114 | return ('u',) |
---|
1115 | elif isinstance(v, (str_8b,str)): |
---|
1116 | if len(v) >= 255: |
---|
1117 | return ('S',(len(v)//1000+1)*1000) |
---|
1118 | else: |
---|
1119 | return ('s',) |
---|
1120 | elif isinstance(v, (int, long)): |
---|
1121 | #SQL_BIGINT defination: http://msdn.microsoft.com/en-us/library/ms187745.aspx |
---|
1122 | if v > 2147483647 or v < -2147483648: |
---|
1123 | return ('l',) |
---|
1124 | else: |
---|
1125 | return ('i',) |
---|
1126 | elif isinstance(v, float): |
---|
1127 | return ('f',) |
---|
1128 | elif isinstance(v, BinaryNullType): |
---|
1129 | return ('BN',) |
---|
1130 | elif v is None: |
---|
1131 | return ('N',) |
---|
1132 | elif isinstance(v, Decimal): |
---|
1133 | t = v.as_tuple() #1.23 -> (1,2,3),-2 , 1.23*E7 -> (1,2,3),5 |
---|
1134 | return ('D',(len(t[1]),0 - t[2])) # number of digits, and number of decimal digits |
---|
1135 | |
---|
1136 | |
---|
1137 | elif isinstance (v, datetime.datetime): |
---|
1138 | return ('dt',) |
---|
1139 | elif isinstance (v, datetime.date): |
---|
1140 | return ('d',) |
---|
1141 | elif isinstance(v, datetime.time): |
---|
1142 | return ('t',) |
---|
1143 | elif isinstance (v, (bytearray, buffer)): |
---|
1144 | return ('bi',(len(v)//1000+1)*1000) |
---|
1145 | |
---|
1146 | return type(v) |
---|
1147 | |
---|
1148 | |
---|
1149 | # The Cursor Class. |
---|
1150 | class Cursor: |
---|
1151 | def __init__(self, conx, row_type_callable=None): |
---|
1152 | """ Initialize self.stmt_h, which is the handle of a statement |
---|
1153 | A statement is actually the basis of a python"cursor" object |
---|
1154 | """ |
---|
1155 | self.stmt_h = ctypes.c_void_p() |
---|
1156 | self.connection = conx |
---|
1157 | self.ansi = conx.ansi |
---|
1158 | self.row_type_callable = row_type_callable or TupleRow |
---|
1159 | self.statement = None |
---|
1160 | self._last_param_types = None |
---|
1161 | self._ParamBufferList = [] |
---|
1162 | self._ColBufferList = [] |
---|
1163 | self._row_type = None |
---|
1164 | self._buf_cvt_func = [] |
---|
1165 | self.rowcount = -1 |
---|
1166 | self.description = None |
---|
1167 | self.autocommit = None |
---|
1168 | self._ColTypeCodeList = [] |
---|
1169 | self._outputsize = {} |
---|
1170 | self._inputsizers = [] |
---|
1171 | self.arraysize = 1 |
---|
1172 | ret = ODBC_API.SQLAllocHandle(SQL_HANDLE_STMT, self.connection.dbc_h, ADDR(self.stmt_h)) |
---|
1173 | check_success(self, ret) |
---|
1174 | |
---|
1175 | self.timeout = conx.timeout |
---|
1176 | if self.timeout != 0: |
---|
1177 | self.set_timeout(self.timeout) |
---|
1178 | |
---|
1179 | self._PARAM_SQL_TYPE_LIST = [] |
---|
1180 | self.closed = False |
---|
1181 | |
---|
1182 | def set_timeout(self, timeout): |
---|
1183 | self.timeout = timeout |
---|
1184 | ret = ODBC_API.SQLSetStmtAttr(self.stmt_h, SQL_ATTR_QUERY_TIMEOUT, self.timeout, 0) |
---|
1185 | check_success(self, ret) |
---|
1186 | |
---|
1187 | def prepare(self, query_string): |
---|
1188 | """prepare a query""" |
---|
1189 | |
---|
1190 | #self._free_results(FREE_STATEMENT) |
---|
1191 | if not self.connection: |
---|
1192 | self.close() |
---|
1193 | |
---|
1194 | if type(query_string) == unicode: |
---|
1195 | c_query_string = wchar_pointer(UCS_buf(query_string)) |
---|
1196 | ret = ODBC_API.SQLPrepareW(self.stmt_h, c_query_string, len(query_string)) |
---|
1197 | else: |
---|
1198 | c_query_string = ctypes.c_char_p(query_string) |
---|
1199 | ret = ODBC_API.SQLPrepare(self.stmt_h, c_query_string, len(query_string)) |
---|
1200 | if ret != SQL_SUCCESS: |
---|
1201 | check_success(self, ret) |
---|
1202 | |
---|
1203 | |
---|
1204 | self._PARAM_SQL_TYPE_LIST = [] |
---|
1205 | |
---|
1206 | if self.connection.support_SQLDescribeParam: |
---|
1207 | # SQLServer's SQLDescribeParam only supports DML SQL, so avoid the SELECT statement |
---|
1208 | if True:# 'SELECT' not in query_string.upper(): |
---|
1209 | #self._free_results(NO_FREE_STATEMENT) |
---|
1210 | NumParams = c_short() |
---|
1211 | ret = ODBC_API.SQLNumParams(self.stmt_h, ADDR(NumParams)) |
---|
1212 | if ret != SQL_SUCCESS: |
---|
1213 | check_success(self, ret) |
---|
1214 | |
---|
1215 | for col_num in range(NumParams.value): |
---|
1216 | ParameterNumber = ctypes.c_ushort(col_num + 1) |
---|
1217 | DataType = c_short() |
---|
1218 | ParameterSize = ctypes.c_size_t() |
---|
1219 | DecimalDigits = c_short() |
---|
1220 | Nullable = c_short() |
---|
1221 | ret = ODBC_API.SQLDescribeParam( |
---|
1222 | self.stmt_h, |
---|
1223 | ParameterNumber, |
---|
1224 | ADDR(DataType), |
---|
1225 | ADDR(ParameterSize), |
---|
1226 | ADDR(DecimalDigits), |
---|
1227 | ADDR(Nullable), |
---|
1228 | ) |
---|
1229 | if ret != SQL_SUCCESS: |
---|
1230 | try: |
---|
1231 | check_success(self, ret) |
---|
1232 | except DatabaseError: |
---|
1233 | if sys.exc_info()[1].value[0] == '07009': |
---|
1234 | self._PARAM_SQL_TYPE_LIST = [] |
---|
1235 | break |
---|
1236 | else: |
---|
1237 | raise sys.exc_info()[1] |
---|
1238 | except: |
---|
1239 | raise sys.exc_info()[1] |
---|
1240 | |
---|
1241 | self._PARAM_SQL_TYPE_LIST.append((DataType.value,DecimalDigits.value)) |
---|
1242 | |
---|
1243 | self.statement = query_string |
---|
1244 | |
---|
1245 | |
---|
1246 | def _BindParams(self, param_types, pram_io_list = []): |
---|
1247 | """Create parameter buffers based on param types, and bind them to the statement""" |
---|
1248 | # Clear the old Parameters |
---|
1249 | if not self.connection: |
---|
1250 | self.close() |
---|
1251 | #self._free_results(NO_FREE_STATEMENT) |
---|
1252 | |
---|
1253 | # Get the number of query parameters judged by database. |
---|
1254 | NumParams = c_short() |
---|
1255 | ret = ODBC_API.SQLNumParams(self.stmt_h, ADDR(NumParams)) |
---|
1256 | if ret != SQL_SUCCESS: |
---|
1257 | check_success(self, ret) |
---|
1258 | |
---|
1259 | if len(param_types) != NumParams.value: |
---|
1260 | # In case number of parameters provided do not same as number required |
---|
1261 | error_desc = "The SQL contains %d parameter markers, but %d parameters were supplied" \ |
---|
1262 | %(NumParams.value,len(param_types)) |
---|
1263 | raise ProgrammingError('HY000',error_desc) |
---|
1264 | |
---|
1265 | |
---|
1266 | # Every parameter needs to be binded to a buffer |
---|
1267 | ParamBufferList = [] |
---|
1268 | # Temporary holder since we can only call SQLDescribeParam before |
---|
1269 | # calling SQLBindParam. |
---|
1270 | temp_holder = [] |
---|
1271 | for col_num in range(NumParams.value): |
---|
1272 | dec_num = 0 |
---|
1273 | buf_size = 512 |
---|
1274 | |
---|
1275 | if param_types[col_num][0] == 'u': |
---|
1276 | sql_c_type = SQL_C_WCHAR |
---|
1277 | sql_type = SQL_WVARCHAR |
---|
1278 | buf_size = 255 |
---|
1279 | ParameterBuffer = create_buffer_u(buf_size) |
---|
1280 | |
---|
1281 | elif param_types[col_num][0] == 's': |
---|
1282 | sql_c_type = SQL_C_CHAR |
---|
1283 | sql_type = SQL_VARCHAR |
---|
1284 | buf_size = 255 |
---|
1285 | ParameterBuffer = create_buffer(buf_size) |
---|
1286 | |
---|
1287 | |
---|
1288 | elif param_types[col_num][0] == 'U': |
---|
1289 | sql_c_type = SQL_C_WCHAR |
---|
1290 | sql_type = SQL_WLONGVARCHAR |
---|
1291 | buf_size = param_types[col_num][1]#len(self._inputsizers)>col_num and self._inputsizers[col_num] or 20500 |
---|
1292 | ParameterBuffer = create_buffer_u(buf_size) |
---|
1293 | |
---|
1294 | elif param_types[col_num][0] == 'S': |
---|
1295 | sql_c_type = SQL_C_CHAR |
---|
1296 | sql_type = SQL_LONGVARCHAR |
---|
1297 | buf_size = param_types[col_num][1]#len(self._inputsizers)>col_num and self._inputsizers[col_num] or 20500 |
---|
1298 | ParameterBuffer = create_buffer(buf_size) |
---|
1299 | |
---|
1300 | # bool subclasses int, thus has to go first |
---|
1301 | elif param_types[col_num][0] == 'b': |
---|
1302 | sql_c_type = SQL_C_CHAR |
---|
1303 | sql_type = SQL_BIT |
---|
1304 | buf_size = SQL_data_type_dict[sql_type][4] |
---|
1305 | ParameterBuffer = create_buffer(buf_size) |
---|
1306 | |
---|
1307 | elif param_types[col_num][0] == 'i': |
---|
1308 | sql_c_type = SQL_C_CHAR |
---|
1309 | sql_type = SQL_INTEGER |
---|
1310 | buf_size = SQL_data_type_dict[sql_type][4] |
---|
1311 | ParameterBuffer = create_buffer(buf_size) |
---|
1312 | |
---|
1313 | elif param_types[col_num][0] == 'l': |
---|
1314 | sql_c_type = SQL_C_CHAR |
---|
1315 | sql_type = SQL_BIGINT |
---|
1316 | buf_size = SQL_data_type_dict[sql_type][4] |
---|
1317 | ParameterBuffer = create_buffer(buf_size) |
---|
1318 | |
---|
1319 | |
---|
1320 | elif param_types[col_num][0] == 'D': #Decimal |
---|
1321 | sql_c_type = SQL_C_CHAR |
---|
1322 | sql_type = SQL_NUMERIC |
---|
1323 | digit_num, dec_num = param_types[col_num][1] |
---|
1324 | if dec_num > 0: |
---|
1325 | # has decimal |
---|
1326 | buf_size = digit_num |
---|
1327 | dec_num = dec_num |
---|
1328 | else: |
---|
1329 | # no decimal |
---|
1330 | buf_size = digit_num - dec_num |
---|
1331 | dec_num = 0 |
---|
1332 | |
---|
1333 | ParameterBuffer = create_buffer(buf_size + 4)# add extra length for sign and dot |
---|
1334 | |
---|
1335 | |
---|
1336 | elif param_types[col_num][0] == 'f': |
---|
1337 | sql_c_type = SQL_C_CHAR |
---|
1338 | sql_type = SQL_DOUBLE |
---|
1339 | buf_size = SQL_data_type_dict[sql_type][4] |
---|
1340 | ParameterBuffer = create_buffer(buf_size) |
---|
1341 | |
---|
1342 | |
---|
1343 | # datetime subclasses date, thus has to go first |
---|
1344 | elif param_types[col_num][0] == 'dt': |
---|
1345 | sql_c_type = SQL_C_CHAR |
---|
1346 | sql_type = SQL_TYPE_TIMESTAMP |
---|
1347 | buf_size = self.connection.type_size_dic[SQL_TYPE_TIMESTAMP][0] |
---|
1348 | ParameterBuffer = create_buffer(buf_size) |
---|
1349 | dec_num = self.connection.type_size_dic[SQL_TYPE_TIMESTAMP][1] |
---|
1350 | |
---|
1351 | |
---|
1352 | elif param_types[col_num][0] == 'd': |
---|
1353 | sql_c_type = SQL_C_CHAR |
---|
1354 | if SQL_TYPE_DATE in self.connection.type_size_dic: |
---|
1355 | #if DEBUG:print('conx.type_size_dic.has_key(SQL_TYPE_DATE)') |
---|
1356 | sql_type = SQL_TYPE_DATE |
---|
1357 | buf_size = self.connection.type_size_dic[SQL_TYPE_DATE][0] |
---|
1358 | |
---|
1359 | ParameterBuffer = create_buffer(buf_size) |
---|
1360 | dec_num = self.connection.type_size_dic[SQL_TYPE_DATE][1] |
---|
1361 | |
---|
1362 | else: |
---|
1363 | # SQL Sever <2008 doesn't have a DATE type. |
---|
1364 | sql_type = SQL_TYPE_TIMESTAMP |
---|
1365 | buf_size = 10 |
---|
1366 | ParameterBuffer = create_buffer(buf_size) |
---|
1367 | |
---|
1368 | |
---|
1369 | elif param_types[col_num][0] == 't': |
---|
1370 | sql_c_type = SQL_C_CHAR |
---|
1371 | if SQL_TYPE_TIME in self.connection.type_size_dic: |
---|
1372 | sql_type = SQL_TYPE_TIME |
---|
1373 | buf_size = self.connection.type_size_dic[SQL_TYPE_TIME][0] |
---|
1374 | ParameterBuffer = create_buffer(buf_size) |
---|
1375 | dec_num = self.connection.type_size_dic[SQL_TYPE_TIME][1] |
---|
1376 | elif SQL_SS_TIME2 in self.connection.type_size_dic: |
---|
1377 | # TIME type added in SQL Server 2008 |
---|
1378 | sql_type = SQL_SS_TIME2 |
---|
1379 | buf_size = self.connection.type_size_dic[SQL_SS_TIME2][0] |
---|
1380 | ParameterBuffer = create_buffer(buf_size) |
---|
1381 | dec_num = self.connection.type_size_dic[SQL_SS_TIME2][1] |
---|
1382 | else: |
---|
1383 | # SQL Sever <2008 doesn't have a TIME type. |
---|
1384 | sql_type = SQL_TYPE_TIMESTAMP |
---|
1385 | buf_size = self.connection.type_size_dic[SQL_TYPE_TIMESTAMP][0] |
---|
1386 | ParameterBuffer = create_buffer(buf_size) |
---|
1387 | dec_num = 3 |
---|
1388 | |
---|
1389 | elif param_types[col_num][0] == 'BN': |
---|
1390 | sql_c_type = SQL_C_BINARY |
---|
1391 | sql_type = SQL_VARBINARY |
---|
1392 | buf_size = 1 |
---|
1393 | ParameterBuffer = create_buffer(buf_size) |
---|
1394 | |
---|
1395 | elif param_types[col_num][0] == 'N': |
---|
1396 | if len(self._PARAM_SQL_TYPE_LIST) > 0: |
---|
1397 | sql_c_type = SQL_C_DEFAULT |
---|
1398 | sql_type = self._PARAM_SQL_TYPE_LIST[col_num][0] |
---|
1399 | buf_size = 1 |
---|
1400 | ParameterBuffer = create_buffer(buf_size) |
---|
1401 | else: |
---|
1402 | sql_c_type = SQL_C_CHAR |
---|
1403 | sql_type = SQL_CHAR |
---|
1404 | buf_size = 1 |
---|
1405 | ParameterBuffer = create_buffer(buf_size) |
---|
1406 | elif param_types[col_num][0] == 'bi': |
---|
1407 | sql_c_type = SQL_C_BINARY |
---|
1408 | sql_type = SQL_LONGVARBINARY |
---|
1409 | buf_size = param_types[col_num][1]#len(self._inputsizers)>col_num and self._inputsizers[col_num] or 20500 |
---|
1410 | ParameterBuffer = create_buffer(buf_size) |
---|
1411 | |
---|
1412 | |
---|
1413 | else: |
---|
1414 | sql_c_type = SQL_C_CHAR |
---|
1415 | sql_type = SQL_LONGVARCHAR |
---|
1416 | buf_size = len(self._inputsizers)>col_num and self._inputsizers[col_num] or 20500 |
---|
1417 | ParameterBuffer = create_buffer(buf_size) |
---|
1418 | |
---|
1419 | temp_holder.append((sql_c_type, sql_type, buf_size, dec_num, ParameterBuffer)) |
---|
1420 | |
---|
1421 | for col_num, (sql_c_type, sql_type, buf_size, dec_num, ParameterBuffer) in enumerate(temp_holder): |
---|
1422 | BufferLen = c_ssize_t(buf_size) |
---|
1423 | LenOrIndBuf = c_ssize_t() |
---|
1424 | |
---|
1425 | |
---|
1426 | InputOutputType = SQL_PARAM_INPUT |
---|
1427 | if len(pram_io_list) > col_num: |
---|
1428 | InputOutputType = pram_io_list[col_num] |
---|
1429 | |
---|
1430 | ret = SQLBindParameter(self.stmt_h, col_num + 1, InputOutputType, sql_c_type, sql_type, buf_size,\ |
---|
1431 | dec_num, ADDR(ParameterBuffer), BufferLen,ADDR(LenOrIndBuf)) |
---|
1432 | if ret != SQL_SUCCESS: |
---|
1433 | check_success(self, ret) |
---|
1434 | # Append the value buffer and the length buffer to the array |
---|
1435 | ParamBufferList.append((ParameterBuffer,LenOrIndBuf,sql_type)) |
---|
1436 | |
---|
1437 | self._last_param_types = param_types |
---|
1438 | self._ParamBufferList = ParamBufferList |
---|
1439 | |
---|
1440 | |
---|
1441 | def execute(self, query_string, params=None, many_mode=False, call_mode=False): |
---|
1442 | """ Execute the query string, with optional parameters. |
---|
1443 | If parameters are provided, the query would first be prepared, then executed with parameters; |
---|
1444 | If parameters are not provided, only th query sting, it would be executed directly |
---|
1445 | """ |
---|
1446 | if not self.connection: |
---|
1447 | self.close() |
---|
1448 | |
---|
1449 | self._free_stmt(SQL_CLOSE) |
---|
1450 | if params: |
---|
1451 | # If parameters exist, first prepare the query then executed with parameters |
---|
1452 | |
---|
1453 | if not isinstance(params, (tuple, list)): |
---|
1454 | raise TypeError("Params must be in a list, tuple, or Row") |
---|
1455 | |
---|
1456 | |
---|
1457 | if query_string != self.statement: |
---|
1458 | # if the query is not same as last query, then it is not prepared |
---|
1459 | self.prepare(query_string) |
---|
1460 | |
---|
1461 | |
---|
1462 | param_types = list(map(get_type, params)) |
---|
1463 | |
---|
1464 | if call_mode: |
---|
1465 | self._free_stmt(SQL_RESET_PARAMS) |
---|
1466 | self._BindParams(param_types, self._pram_io_list) |
---|
1467 | else: |
---|
1468 | if self._last_param_types is None: |
---|
1469 | self._free_stmt(SQL_RESET_PARAMS) |
---|
1470 | self._BindParams(param_types) |
---|
1471 | elif len(param_types) != len(self._last_param_types): |
---|
1472 | self._free_stmt(SQL_RESET_PARAMS) |
---|
1473 | self._BindParams(param_types) |
---|
1474 | elif sum([p_type[0] != 'N' and p_type != self._last_param_types[i] for i,p_type in enumerate(param_types)]) > 0: |
---|
1475 | self._free_stmt(SQL_RESET_PARAMS) |
---|
1476 | self._BindParams(param_types) |
---|
1477 | |
---|
1478 | |
---|
1479 | # With query prepared, now put parameters into buffers |
---|
1480 | col_num = 0 |
---|
1481 | for param_buffer, param_buffer_len, sql_type in self._ParamBufferList: |
---|
1482 | c_char_buf, c_buf_len = '', 0 |
---|
1483 | param_val = params[col_num] |
---|
1484 | if param_types[col_num][0] in ('N','BN'): |
---|
1485 | param_buffer_len.value = SQL_NULL_DATA |
---|
1486 | col_num += 1 |
---|
1487 | continue |
---|
1488 | elif param_types[col_num][0] in ('i','l','f'): |
---|
1489 | if py_v3: |
---|
1490 | c_char_buf = bytes(str(param_val),'ascii') |
---|
1491 | else: |
---|
1492 | c_char_buf = str(param_val) |
---|
1493 | c_buf_len = len(c_char_buf) |
---|
1494 | |
---|
1495 | elif param_types[col_num][0] in ('s','S'): |
---|
1496 | c_char_buf = param_val |
---|
1497 | c_buf_len = len(c_char_buf) |
---|
1498 | elif param_types[col_num][0] in ('u','U'): |
---|
1499 | c_char_buf = UCS_buf(param_val) |
---|
1500 | c_buf_len = len(c_char_buf) |
---|
1501 | |
---|
1502 | elif param_types[col_num][0] == 'dt': |
---|
1503 | max_len = self.connection.type_size_dic[SQL_TYPE_TIMESTAMP][0] |
---|
1504 | datetime_str = param_val.strftime('%Y-%m-%d %H:%M:%S.%f') |
---|
1505 | c_char_buf = datetime_str[:max_len] |
---|
1506 | if py_v3: |
---|
1507 | c_char_buf = bytes(c_char_buf,'ascii') |
---|
1508 | |
---|
1509 | c_buf_len = len(c_char_buf) |
---|
1510 | # print c_buf_len, c_char_buf |
---|
1511 | |
---|
1512 | elif param_types[col_num][0] == 'd': |
---|
1513 | if SQL_TYPE_DATE in self.connection.type_size_dic: |
---|
1514 | max_len = self.connection.type_size_dic[SQL_TYPE_DATE][0] |
---|
1515 | else: |
---|
1516 | max_len = 10 |
---|
1517 | c_char_buf = param_val.isoformat()[:max_len] |
---|
1518 | if py_v3: |
---|
1519 | c_char_buf = bytes(c_char_buf,'ascii') |
---|
1520 | c_buf_len = len(c_char_buf) |
---|
1521 | #print c_char_buf |
---|
1522 | |
---|
1523 | elif param_types[col_num][0] == 't': |
---|
1524 | if SQL_TYPE_TIME in self.connection.type_size_dic: |
---|
1525 | max_len = self.connection.type_size_dic[SQL_TYPE_TIME][0] |
---|
1526 | c_char_buf = param_val.isoformat()[:max_len] |
---|
1527 | c_buf_len = len(c_char_buf) |
---|
1528 | elif SQL_SS_TIME2 in self.connection.type_size_dic: |
---|
1529 | max_len = self.connection.type_size_dic[SQL_SS_TIME2][0] |
---|
1530 | c_char_buf = param_val.isoformat()[:max_len] |
---|
1531 | c_buf_len = len(c_char_buf) |
---|
1532 | else: |
---|
1533 | c_buf_len = self.connection.type_size_dic[SQL_TYPE_TIMESTAMP][0] |
---|
1534 | time_str = param_val.isoformat() |
---|
1535 | if len(time_str) == 8: |
---|
1536 | time_str += '.000' |
---|
1537 | c_char_buf = '1900-01-01 '+time_str[0:c_buf_len - 11] |
---|
1538 | if py_v3: |
---|
1539 | c_char_buf = bytes(c_char_buf,'ascii') |
---|
1540 | #print c_buf_len, c_char_buf |
---|
1541 | |
---|
1542 | elif param_types[col_num][0] == 'b': |
---|
1543 | if param_val == True: |
---|
1544 | c_char_buf = '1' |
---|
1545 | else: |
---|
1546 | c_char_buf = '0' |
---|
1547 | if py_v3: |
---|
1548 | c_char_buf = bytes(c_char_buf,'ascii') |
---|
1549 | c_buf_len = 1 |
---|
1550 | |
---|
1551 | elif param_types[col_num][0] == 'D': #Decimal |
---|
1552 | sign = param_val.as_tuple()[0] == 0 and '+' or '-' |
---|
1553 | digit_string = ''.join([str(x) for x in param_val.as_tuple()[1]]) |
---|
1554 | digit_num, dec_num = param_types[col_num][1] |
---|
1555 | if dec_num > 0: |
---|
1556 | # has decimal |
---|
1557 | left_part = digit_string[:digit_num - dec_num] |
---|
1558 | right_part = digit_string[0-dec_num:] |
---|
1559 | else: |
---|
1560 | # no decimal |
---|
1561 | left_part = digit_string + '0'*(0-dec_num) |
---|
1562 | right_part = '' |
---|
1563 | v = ''.join((sign, left_part,'.', right_part)) |
---|
1564 | |
---|
1565 | if py_v3: |
---|
1566 | c_char_buf = bytes(v,'ascii') |
---|
1567 | else: |
---|
1568 | c_char_buf = v |
---|
1569 | c_buf_len = len(c_char_buf) |
---|
1570 | |
---|
1571 | elif param_types[col_num][0] == 'bi': |
---|
1572 | c_char_buf = str_8b(param_val) |
---|
1573 | c_buf_len = len(c_char_buf) |
---|
1574 | |
---|
1575 | else: |
---|
1576 | c_char_buf = param_val |
---|
1577 | |
---|
1578 | |
---|
1579 | if param_types[col_num][0] == 'bi': |
---|
1580 | param_buffer.raw = str_8b(param_val) |
---|
1581 | |
---|
1582 | else: |
---|
1583 | #print (type(param_val),param_buffer, param_buffer.value) |
---|
1584 | param_buffer.value = c_char_buf |
---|
1585 | |
---|
1586 | if param_types[col_num][0] in ('U','u','S','s'): |
---|
1587 | #ODBC driver will find NUL in unicode and string to determine their length |
---|
1588 | param_buffer_len.value = SQL_NTS |
---|
1589 | else: |
---|
1590 | param_buffer_len.value = c_buf_len |
---|
1591 | |
---|
1592 | col_num += 1 |
---|
1593 | ret = SQLExecute(self.stmt_h) |
---|
1594 | if ret != SQL_SUCCESS: |
---|
1595 | #print param_valparam_buffer, param_buffer.value |
---|
1596 | check_success(self, ret) |
---|
1597 | |
---|
1598 | |
---|
1599 | if not many_mode: |
---|
1600 | self._NumOfRows() |
---|
1601 | self._UpdateDesc() |
---|
1602 | #self._BindCols() |
---|
1603 | |
---|
1604 | else: |
---|
1605 | self.execdirect(query_string) |
---|
1606 | return self |
---|
1607 | |
---|
1608 | |
---|
1609 | def _SQLExecute(self): |
---|
1610 | if not self.connection: |
---|
1611 | self.close() |
---|
1612 | ret = SQLExecute(self.stmt_h) |
---|
1613 | if ret != SQL_SUCCESS: |
---|
1614 | check_success(self, ret) |
---|
1615 | |
---|
1616 | |
---|
1617 | def execdirect(self, query_string): |
---|
1618 | """Execute a query directly""" |
---|
1619 | if not self.connection: |
---|
1620 | self.close() |
---|
1621 | |
---|
1622 | self._free_stmt() |
---|
1623 | self._last_param_types = None |
---|
1624 | self.statement = None |
---|
1625 | if type(query_string) == unicode: |
---|
1626 | c_query_string = wchar_pointer(UCS_buf(query_string)) |
---|
1627 | ret = ODBC_API.SQLExecDirectW(self.stmt_h, c_query_string, len(query_string)) |
---|
1628 | else: |
---|
1629 | c_query_string = ctypes.c_char_p(query_string) |
---|
1630 | ret = ODBC_API.SQLExecDirect(self.stmt_h, c_query_string, len(query_string)) |
---|
1631 | check_success(self, ret) |
---|
1632 | self._NumOfRows() |
---|
1633 | self._UpdateDesc() |
---|
1634 | #self._BindCols() |
---|
1635 | return self |
---|
1636 | |
---|
1637 | |
---|
1638 | def callproc(self, procname, args): |
---|
1639 | if not self.connection: |
---|
1640 | self.close() |
---|
1641 | raise Warning('', 'Still not fully implemented') |
---|
1642 | self._pram_io_list = [row[4] for row in self.procedurecolumns(procedure = procname).fetchall() if row[4] not in (SQL_RESULT_COL, SQL_RETURN_VALUE)] |
---|
1643 | |
---|
1644 | print('pram_io_list: '+str(self._pram_io_list)) |
---|
1645 | |
---|
1646 | |
---|
1647 | |
---|
1648 | call_escape = '{CALL '+procname |
---|
1649 | if args: |
---|
1650 | call_escape += '(' + ','.join(['?' for params in args]) + ')' |
---|
1651 | call_escape += '}' |
---|
1652 | |
---|
1653 | self.execute(call_escape, args, call_mode = True) |
---|
1654 | |
---|
1655 | result = [] |
---|
1656 | |
---|
1657 | for buf, buf_len, sql_type in self._ParamBufferList: |
---|
1658 | if buf_len.value == -1: |
---|
1659 | result.append(None) |
---|
1660 | else: |
---|
1661 | result.append(self.connection.output_converter[sql_type](buf.value)) |
---|
1662 | return result |
---|
1663 | |
---|
1664 | |
---|
1665 | |
---|
1666 | def executemany(self, query_string, params_list = [None]): |
---|
1667 | if not self.connection: |
---|
1668 | self.close() |
---|
1669 | |
---|
1670 | for params in params_list: |
---|
1671 | self.execute(query_string, params, many_mode = True) |
---|
1672 | self._NumOfRows() |
---|
1673 | self.rowcount = -1 |
---|
1674 | self._UpdateDesc() |
---|
1675 | #self._BindCols() |
---|
1676 | |
---|
1677 | |
---|
1678 | |
---|
1679 | def _CreateColBuf(self): |
---|
1680 | if not self.connection: |
---|
1681 | self.close() |
---|
1682 | self._free_stmt(SQL_UNBIND) |
---|
1683 | NOC = self._NumOfCols() |
---|
1684 | self._ColBufferList = [] |
---|
1685 | bind_data = True |
---|
1686 | for col_num in range(NOC): |
---|
1687 | col_name = self.description[col_num][0] |
---|
1688 | col_size = self.description[col_num][2] |
---|
1689 | col_sql_data_type = self._ColTypeCodeList[col_num] |
---|
1690 | |
---|
1691 | target_type = SQL_data_type_dict[col_sql_data_type][2] |
---|
1692 | dynamic_length = SQL_data_type_dict[col_sql_data_type][5] |
---|
1693 | # set default size base on the column's sql data type |
---|
1694 | total_buf_len = SQL_data_type_dict[col_sql_data_type][4] |
---|
1695 | |
---|
1696 | # over-write if there's pre-set size value for "large columns" |
---|
1697 | if total_buf_len > 20500: |
---|
1698 | total_buf_len = self._outputsize.get(None,total_buf_len) |
---|
1699 | # over-write if there's pre-set size value for the "col_num" column |
---|
1700 | total_buf_len = self._outputsize.get(col_num, total_buf_len) |
---|
1701 | |
---|
1702 | # if the size of the buffer is very long, do not bind |
---|
1703 | # because a large buffer decrease performance, and sometimes you only get a NULL value. |
---|
1704 | # in that case use sqlgetdata instead. |
---|
1705 | if col_size >= 1024: |
---|
1706 | dynamic_length = True |
---|
1707 | |
---|
1708 | alloc_buffer = SQL_data_type_dict[col_sql_data_type][3](total_buf_len) |
---|
1709 | |
---|
1710 | used_buf_len = c_ssize_t() |
---|
1711 | |
---|
1712 | force_unicode = self.connection.unicode_results |
---|
1713 | |
---|
1714 | if force_unicode and col_sql_data_type in (SQL_CHAR,SQL_VARCHAR,SQL_LONGVARCHAR): |
---|
1715 | target_type = SQL_C_WCHAR |
---|
1716 | alloc_buffer = create_buffer_u(total_buf_len) |
---|
1717 | |
---|
1718 | buf_cvt_func = self.connection.output_converter[self._ColTypeCodeList[col_num]] |
---|
1719 | |
---|
1720 | if bind_data: |
---|
1721 | if dynamic_length: |
---|
1722 | bind_data = False |
---|
1723 | self._ColBufferList.append([col_name, target_type, used_buf_len, ADDR(used_buf_len), alloc_buffer, ADDR(alloc_buffer), total_buf_len, buf_cvt_func, bind_data]) |
---|
1724 | |
---|
1725 | if bind_data: |
---|
1726 | ret = ODBC_API.SQLBindCol(self.stmt_h, col_num + 1, target_type, ADDR(alloc_buffer), total_buf_len, ADDR(used_buf_len)) |
---|
1727 | if ret != SQL_SUCCESS: |
---|
1728 | check_success(self, ret) |
---|
1729 | |
---|
1730 | def _UpdateDesc(self): |
---|
1731 | "Get the information of (name, type_code, display_size, internal_size, col_precision, scale, null_ok)" |
---|
1732 | if not self.connection: |
---|
1733 | self.close() |
---|
1734 | |
---|
1735 | force_unicode = self.connection.unicode_results |
---|
1736 | if force_unicode: |
---|
1737 | Cname = create_buffer_u(1024) |
---|
1738 | else: |
---|
1739 | Cname = create_buffer(1024) |
---|
1740 | |
---|
1741 | Cname_ptr = c_short() |
---|
1742 | Ctype_code = c_short() |
---|
1743 | Csize = ctypes.c_size_t() |
---|
1744 | Cdisp_size = c_ssize_t(0) |
---|
1745 | CDecimalDigits = c_short() |
---|
1746 | Cnull_ok = c_short() |
---|
1747 | ColDescr = [] |
---|
1748 | self._ColTypeCodeList = [] |
---|
1749 | NOC = self._NumOfCols() |
---|
1750 | for col in range(1, NOC+1): |
---|
1751 | |
---|
1752 | ret = ODBC_API.SQLColAttribute(self.stmt_h, col, SQL_DESC_DISPLAY_SIZE, ADDR(create_buffer(10)), |
---|
1753 | 10, ADDR(c_short()),ADDR(Cdisp_size)) |
---|
1754 | if ret != SQL_SUCCESS: |
---|
1755 | check_success(self, ret) |
---|
1756 | |
---|
1757 | if force_unicode: |
---|
1758 | |
---|
1759 | ret = ODBC_API.SQLDescribeColW(self.stmt_h, col, Cname, len(Cname), ADDR(Cname_ptr),\ |
---|
1760 | ADDR(Ctype_code),ADDR(Csize),ADDR(CDecimalDigits), ADDR(Cnull_ok)) |
---|
1761 | if ret != SQL_SUCCESS: |
---|
1762 | check_success(self, ret) |
---|
1763 | else: |
---|
1764 | |
---|
1765 | ret = ODBC_API.SQLDescribeCol(self.stmt_h, col, Cname, len(Cname), ADDR(Cname_ptr),\ |
---|
1766 | ADDR(Ctype_code),ADDR(Csize),ADDR(CDecimalDigits), ADDR(Cnull_ok)) |
---|
1767 | if ret != SQL_SUCCESS: |
---|
1768 | check_success(self, ret) |
---|
1769 | |
---|
1770 | col_name = Cname.value |
---|
1771 | if lowercase: |
---|
1772 | col_name = col_name.lower() |
---|
1773 | #(name, type_code, display_size, |
---|
1774 | |
---|
1775 | ColDescr.append((col_name, SQL_data_type_dict.get(Ctype_code.value,(Ctype_code.value,))[0],Cdisp_size.value,\ |
---|
1776 | Csize.value, Csize.value,CDecimalDigits.value,Cnull_ok.value == 1 and True or False)) |
---|
1777 | self._ColTypeCodeList.append(Ctype_code.value) |
---|
1778 | |
---|
1779 | if len(ColDescr) > 0: |
---|
1780 | self.description = ColDescr |
---|
1781 | # Create the row type before fetching. |
---|
1782 | self._row_type = self.row_type_callable(self) |
---|
1783 | else: |
---|
1784 | self.description = None |
---|
1785 | self._CreateColBuf() |
---|
1786 | |
---|
1787 | |
---|
1788 | def _NumOfRows(self): |
---|
1789 | """Get the number of rows""" |
---|
1790 | if not self.connection: |
---|
1791 | self.close() |
---|
1792 | |
---|
1793 | NOR = c_ssize_t() |
---|
1794 | ret = SQLRowCount(self.stmt_h, ADDR(NOR)) |
---|
1795 | if ret != SQL_SUCCESS: |
---|
1796 | check_success(self, ret) |
---|
1797 | self.rowcount = NOR.value |
---|
1798 | return self.rowcount |
---|
1799 | |
---|
1800 | |
---|
1801 | def _NumOfCols(self): |
---|
1802 | """Get the number of cols""" |
---|
1803 | if not self.connection: |
---|
1804 | self.close() |
---|
1805 | |
---|
1806 | NOC = c_short() |
---|
1807 | ret = SQLNumResultCols(self.stmt_h, ADDR(NOC)) |
---|
1808 | if ret != SQL_SUCCESS: |
---|
1809 | check_success(self, ret) |
---|
1810 | return NOC.value |
---|
1811 | |
---|
1812 | |
---|
1813 | def fetchall(self): |
---|
1814 | if not self.connection: |
---|
1815 | self.close() |
---|
1816 | |
---|
1817 | rows = [] |
---|
1818 | while True: |
---|
1819 | row = self.fetchone() |
---|
1820 | if row is None: |
---|
1821 | break |
---|
1822 | rows.append(row) |
---|
1823 | return rows |
---|
1824 | |
---|
1825 | |
---|
1826 | def fetchmany(self, num = None): |
---|
1827 | if not self.connection: |
---|
1828 | self.close() |
---|
1829 | |
---|
1830 | if num is None: |
---|
1831 | num = self.arraysize |
---|
1832 | rows = [] |
---|
1833 | |
---|
1834 | while len(rows) < num: |
---|
1835 | row = self.fetchone() |
---|
1836 | if row is None: |
---|
1837 | break |
---|
1838 | rows.append(row) |
---|
1839 | return rows |
---|
1840 | |
---|
1841 | |
---|
1842 | def fetchone(self): |
---|
1843 | if not self.connection: |
---|
1844 | self.close() |
---|
1845 | |
---|
1846 | ret = SQLFetch(self.stmt_h) |
---|
1847 | |
---|
1848 | if ret in (SQL_SUCCESS,SQL_SUCCESS_WITH_INFO): |
---|
1849 | '''Bind buffers for the record set columns''' |
---|
1850 | |
---|
1851 | value_list = [] |
---|
1852 | col_num = 1 |
---|
1853 | for col_name, target_type, used_buf_len, ADDR_used_buf_len, alloc_buffer, ADDR_alloc_buffer, total_buf_len, buf_cvt_func, bind_data in self._ColBufferList: |
---|
1854 | raw_data_parts = [] |
---|
1855 | while 1: |
---|
1856 | if bind_data: |
---|
1857 | ret = SQL_SUCCESS |
---|
1858 | else: |
---|
1859 | ret = SQLGetData(self.stmt_h, col_num, target_type, ADDR_alloc_buffer, total_buf_len, ADDR_used_buf_len) |
---|
1860 | if ret == SQL_SUCCESS: |
---|
1861 | if used_buf_len.value == SQL_NULL_DATA: |
---|
1862 | value_list.append(None) |
---|
1863 | else: |
---|
1864 | if raw_data_parts == []: |
---|
1865 | # Means no previous data, no need to combine |
---|
1866 | if target_type == SQL_C_BINARY: |
---|
1867 | value_list.append(buf_cvt_func(alloc_buffer.raw[:used_buf_len.value])) |
---|
1868 | elif target_type == SQL_C_WCHAR: |
---|
1869 | value_list.append(buf_cvt_func(from_buffer_u(alloc_buffer))) |
---|
1870 | else: |
---|
1871 | value_list.append(buf_cvt_func(alloc_buffer.value)) |
---|
1872 | else: |
---|
1873 | # There are previous fetched raw data to combine |
---|
1874 | if target_type == SQL_C_BINARY: |
---|
1875 | raw_data_parts.append(alloc_buffer.raw[:used_buf_len.value]) |
---|
1876 | elif target_type == SQL_C_WCHAR: |
---|
1877 | raw_data_parts.append(from_buffer_u(alloc_buffer)) |
---|
1878 | else: |
---|
1879 | raw_data_parts.append(alloc_buffer.value) |
---|
1880 | break |
---|
1881 | |
---|
1882 | elif ret == SQL_SUCCESS_WITH_INFO: |
---|
1883 | # Means the data is only partial |
---|
1884 | if target_type == SQL_C_BINARY: |
---|
1885 | raw_data_parts.append(alloc_buffer.raw) |
---|
1886 | else: |
---|
1887 | raw_data_parts.append(alloc_buffer.value) |
---|
1888 | |
---|
1889 | elif ret == SQL_NO_DATA: |
---|
1890 | # Means all data has been transmitted |
---|
1891 | break |
---|
1892 | else: |
---|
1893 | check_success(self, ret) |
---|
1894 | |
---|
1895 | if raw_data_parts != []: |
---|
1896 | if py_v3: |
---|
1897 | if target_type != SQL_C_BINARY: |
---|
1898 | raw_value = ''.join(raw_data_parts) |
---|
1899 | else: |
---|
1900 | raw_value = BLANK_BYTE.join(raw_data_parts) |
---|
1901 | else: |
---|
1902 | raw_value = ''.join(raw_data_parts) |
---|
1903 | |
---|
1904 | value_list.append(buf_cvt_func(raw_value)) |
---|
1905 | col_num += 1 |
---|
1906 | |
---|
1907 | return self._row_type(value_list) |
---|
1908 | |
---|
1909 | else: |
---|
1910 | if ret == SQL_NO_DATA_FOUND: |
---|
1911 | |
---|
1912 | return None |
---|
1913 | else: |
---|
1914 | check_success(self, ret) |
---|
1915 | |
---|
1916 | def __next__(self): |
---|
1917 | return self.next() |
---|
1918 | |
---|
1919 | def next(self): |
---|
1920 | row = self.fetchone() |
---|
1921 | if row is None: |
---|
1922 | raise(StopIteration) |
---|
1923 | return row |
---|
1924 | |
---|
1925 | def __iter__(self): |
---|
1926 | return self |
---|
1927 | |
---|
1928 | |
---|
1929 | def skip(self, count = 0): |
---|
1930 | if not self.connection: |
---|
1931 | self.close() |
---|
1932 | |
---|
1933 | for i in range(count): |
---|
1934 | ret = ODBC_API.SQLFetchScroll(self.stmt_h, SQL_FETCH_NEXT, 0) |
---|
1935 | if ret != SQL_SUCCESS: |
---|
1936 | check_success(self, ret) |
---|
1937 | return None |
---|
1938 | |
---|
1939 | |
---|
1940 | |
---|
1941 | def nextset(self): |
---|
1942 | if not self.connection: |
---|
1943 | self.close() |
---|
1944 | |
---|
1945 | ret = ODBC_API.SQLMoreResults(self.stmt_h) |
---|
1946 | if ret not in (SQL_SUCCESS, SQL_NO_DATA): |
---|
1947 | check_success(self, ret) |
---|
1948 | |
---|
1949 | if ret == SQL_NO_DATA: |
---|
1950 | self._free_stmt() |
---|
1951 | return False |
---|
1952 | else: |
---|
1953 | self._NumOfRows() |
---|
1954 | self._UpdateDesc() |
---|
1955 | #self._BindCols() |
---|
1956 | return True |
---|
1957 | |
---|
1958 | |
---|
1959 | def _free_stmt(self, free_type = None): |
---|
1960 | if not self.connection: |
---|
1961 | self.close() |
---|
1962 | |
---|
1963 | if not self.connection.connected: |
---|
1964 | raise ProgrammingError('HY000','Attempt to use a closed connection.') |
---|
1965 | |
---|
1966 | #self.description = None |
---|
1967 | #self.rowcount = -1 |
---|
1968 | if free_type in (SQL_CLOSE, None): |
---|
1969 | ret = ODBC_API.SQLFreeStmt(self.stmt_h, SQL_CLOSE) |
---|
1970 | if ret != SQL_SUCCESS: |
---|
1971 | check_success(self, ret) |
---|
1972 | if free_type in (SQL_UNBIND, None): |
---|
1973 | ret = ODBC_API.SQLFreeStmt(self.stmt_h, SQL_UNBIND) |
---|
1974 | if ret != SQL_SUCCESS: |
---|
1975 | check_success(self, ret) |
---|
1976 | if free_type in (SQL_RESET_PARAMS, None): |
---|
1977 | ret = ODBC_API.SQLFreeStmt(self.stmt_h, SQL_RESET_PARAMS) |
---|
1978 | if ret != SQL_SUCCESS: |
---|
1979 | check_success(self, ret) |
---|
1980 | |
---|
1981 | |
---|
1982 | |
---|
1983 | def getTypeInfo(self, sqlType = None): |
---|
1984 | if not self.connection: |
---|
1985 | self.close() |
---|
1986 | |
---|
1987 | if sqlType is None: |
---|
1988 | type = SQL_ALL_TYPES |
---|
1989 | else: |
---|
1990 | type = sqlType |
---|
1991 | ret = ODBC_API.SQLGetTypeInfo(self.stmt_h, type) |
---|
1992 | if ret in (SQL_SUCCESS, SQL_SUCCESS_WITH_INFO): |
---|
1993 | self._NumOfRows() |
---|
1994 | self._UpdateDesc() |
---|
1995 | #self._BindCols() |
---|
1996 | return self.fetchone() |
---|
1997 | |
---|
1998 | |
---|
1999 | def tables(self, table=None, catalog=None, schema=None, tableType=None): |
---|
2000 | """Return a list with all tables""" |
---|
2001 | if not self.connection: |
---|
2002 | self.close() |
---|
2003 | |
---|
2004 | l_catalog = l_schema = l_table = l_tableType = 0 |
---|
2005 | |
---|
2006 | if unicode in [type(x) for x in (table, catalog, schema,tableType)]: |
---|
2007 | string_p = lambda x:wchar_pointer(UCS_buf(x)) |
---|
2008 | API_f = ODBC_API.SQLTablesW |
---|
2009 | else: |
---|
2010 | string_p = ctypes.c_char_p |
---|
2011 | API_f = ODBC_API.SQLTables |
---|
2012 | |
---|
2013 | |
---|
2014 | |
---|
2015 | if catalog is not None: |
---|
2016 | l_catalog = len(catalog) |
---|
2017 | catalog = string_p(catalog) |
---|
2018 | |
---|
2019 | if schema is not None: |
---|
2020 | l_schema = len(schema) |
---|
2021 | schema = string_p(schema) |
---|
2022 | |
---|
2023 | if table is not None: |
---|
2024 | l_table = len(table) |
---|
2025 | table = string_p(table) |
---|
2026 | |
---|
2027 | if tableType is not None: |
---|
2028 | l_tableType = len(tableType) |
---|
2029 | tableType = string_p(tableType) |
---|
2030 | |
---|
2031 | self._free_stmt() |
---|
2032 | self._last_param_types = None |
---|
2033 | self.statement = None |
---|
2034 | ret = API_f(self.stmt_h, |
---|
2035 | catalog, l_catalog, |
---|
2036 | schema, l_schema, |
---|
2037 | table, l_table, |
---|
2038 | tableType, l_tableType) |
---|
2039 | check_success(self, ret) |
---|
2040 | |
---|
2041 | self._NumOfRows() |
---|
2042 | self._UpdateDesc() |
---|
2043 | #self._BindCols() |
---|
2044 | return self |
---|
2045 | |
---|
2046 | |
---|
2047 | def columns(self, table=None, catalog=None, schema=None, column=None): |
---|
2048 | """Return a list with all columns""" |
---|
2049 | if not self.connection: |
---|
2050 | self.close() |
---|
2051 | |
---|
2052 | l_catalog = l_schema = l_table = l_column = 0 |
---|
2053 | |
---|
2054 | if unicode in [type(x) for x in (table, catalog, schema,column)]: |
---|
2055 | string_p = lambda x:wchar_pointer(UCS_buf(x)) |
---|
2056 | API_f = ODBC_API.SQLColumnsW |
---|
2057 | else: |
---|
2058 | string_p = ctypes.c_char_p |
---|
2059 | API_f = ODBC_API.SQLColumns |
---|
2060 | |
---|
2061 | |
---|
2062 | |
---|
2063 | if catalog is not None: |
---|
2064 | l_catalog = len(catalog) |
---|
2065 | catalog = string_p(catalog) |
---|
2066 | if schema is not None: |
---|
2067 | l_schema = len(schema) |
---|
2068 | schema = string_p(schema) |
---|
2069 | if table is not None: |
---|
2070 | l_table = len(table) |
---|
2071 | table = string_p(table) |
---|
2072 | if column is not None: |
---|
2073 | l_column = len(column) |
---|
2074 | column = string_p(column) |
---|
2075 | |
---|
2076 | self._free_stmt() |
---|
2077 | self._last_param_types = None |
---|
2078 | self.statement = None |
---|
2079 | |
---|
2080 | ret = API_f(self.stmt_h, |
---|
2081 | catalog, l_catalog, |
---|
2082 | schema, l_schema, |
---|
2083 | table, l_table, |
---|
2084 | column, l_column) |
---|
2085 | check_success(self, ret) |
---|
2086 | |
---|
2087 | self._NumOfRows() |
---|
2088 | self._UpdateDesc() |
---|
2089 | #self._BindCols() |
---|
2090 | return self |
---|
2091 | |
---|
2092 | |
---|
2093 | def primaryKeys(self, table=None, catalog=None, schema=None): |
---|
2094 | if not self.connection: |
---|
2095 | self.close() |
---|
2096 | |
---|
2097 | l_catalog = l_schema = l_table = 0 |
---|
2098 | |
---|
2099 | if unicode in [type(x) for x in (table, catalog, schema)]: |
---|
2100 | string_p = lambda x:wchar_pointer(UCS_buf(x)) |
---|
2101 | API_f = ODBC_API.SQLPrimaryKeysW |
---|
2102 | else: |
---|
2103 | string_p = ctypes.c_char_p |
---|
2104 | API_f = ODBC_API.SQLPrimaryKeys |
---|
2105 | |
---|
2106 | |
---|
2107 | |
---|
2108 | if catalog is not None: |
---|
2109 | l_catalog = len(catalog) |
---|
2110 | catalog = string_p(catalog) |
---|
2111 | |
---|
2112 | if schema is not None: |
---|
2113 | l_schema = len(schema) |
---|
2114 | schema = string_p(schema) |
---|
2115 | |
---|
2116 | if table is not None: |
---|
2117 | l_table = len(table) |
---|
2118 | table = string_p(table) |
---|
2119 | |
---|
2120 | self._free_stmt() |
---|
2121 | self._last_param_types = None |
---|
2122 | self.statement = None |
---|
2123 | |
---|
2124 | ret = API_f(self.stmt_h, |
---|
2125 | catalog, l_catalog, |
---|
2126 | schema, l_schema, |
---|
2127 | table, l_table) |
---|
2128 | check_success(self, ret) |
---|
2129 | |
---|
2130 | self._NumOfRows() |
---|
2131 | self._UpdateDesc() |
---|
2132 | #self._BindCols() |
---|
2133 | return self |
---|
2134 | |
---|
2135 | |
---|
2136 | def foreignKeys(self, table=None, catalog=None, schema=None, foreignTable=None, foreignCatalog=None, foreignSchema=None): |
---|
2137 | if not self.connection: |
---|
2138 | self.close() |
---|
2139 | |
---|
2140 | l_catalog = l_schema = l_table = l_foreignTable = l_foreignCatalog = l_foreignSchema = 0 |
---|
2141 | |
---|
2142 | if unicode in [type(x) for x in (table, catalog, schema,foreignTable,foreignCatalog,foreignSchema)]: |
---|
2143 | string_p = lambda x:wchar_pointer(UCS_buf(x)) |
---|
2144 | API_f = ODBC_API.SQLForeignKeysW |
---|
2145 | else: |
---|
2146 | string_p = ctypes.c_char_p |
---|
2147 | API_f = ODBC_API.SQLForeignKeys |
---|
2148 | |
---|
2149 | if catalog is not None: |
---|
2150 | l_catalog = len(catalog) |
---|
2151 | catalog = string_p(catalog) |
---|
2152 | if schema is not None: |
---|
2153 | l_schema = len(schema) |
---|
2154 | schema = string_p(schema) |
---|
2155 | if table is not None: |
---|
2156 | l_table = len(table) |
---|
2157 | table = string_p(table) |
---|
2158 | if foreignTable is not None: |
---|
2159 | l_foreignTable = len(foreignTable) |
---|
2160 | foreignTable = string_p(foreignTable) |
---|
2161 | if foreignCatalog is not None: |
---|
2162 | l_foreignCatalog = len(foreignCatalog) |
---|
2163 | foreignCatalog = string_p(foreignCatalog) |
---|
2164 | if foreignSchema is not None: |
---|
2165 | l_foreignSchema = len(foreignSchema) |
---|
2166 | foreignSchema = string_p(foreignSchema) |
---|
2167 | |
---|
2168 | self._free_stmt() |
---|
2169 | self._last_param_types = None |
---|
2170 | self.statement = None |
---|
2171 | |
---|
2172 | ret = API_f(self.stmt_h, |
---|
2173 | catalog, l_catalog, |
---|
2174 | schema, l_schema, |
---|
2175 | table, l_table, |
---|
2176 | foreignCatalog, l_foreignCatalog, |
---|
2177 | foreignSchema, l_foreignSchema, |
---|
2178 | foreignTable, l_foreignTable) |
---|
2179 | check_success(self, ret) |
---|
2180 | |
---|
2181 | self._NumOfRows() |
---|
2182 | self._UpdateDesc() |
---|
2183 | #self._BindCols() |
---|
2184 | return self |
---|
2185 | |
---|
2186 | |
---|
2187 | def procedurecolumns(self, procedure=None, catalog=None, schema=None, column=None): |
---|
2188 | if not self.connection: |
---|
2189 | self.close() |
---|
2190 | |
---|
2191 | l_catalog = l_schema = l_procedure = l_column = 0 |
---|
2192 | if unicode in [type(x) for x in (procedure, catalog, schema,column)]: |
---|
2193 | string_p = lambda x:wchar_pointer(UCS_buf(x)) |
---|
2194 | API_f = ODBC_API.SQLProcedureColumnsW |
---|
2195 | else: |
---|
2196 | string_p = ctypes.c_char_p |
---|
2197 | API_f = ODBC_API.SQLProcedureColumns |
---|
2198 | |
---|
2199 | |
---|
2200 | if catalog is not None: |
---|
2201 | l_catalog = len(catalog) |
---|
2202 | catalog = string_p(catalog) |
---|
2203 | if schema is not None: |
---|
2204 | l_schema = len(schema) |
---|
2205 | schema = string_p(schema) |
---|
2206 | if procedure is not None: |
---|
2207 | l_procedure = len(procedure) |
---|
2208 | procedure = string_p(procedure) |
---|
2209 | if column is not None: |
---|
2210 | l_column = len(column) |
---|
2211 | column = string_p(column) |
---|
2212 | |
---|
2213 | |
---|
2214 | self._free_stmt() |
---|
2215 | self._last_param_types = None |
---|
2216 | self.statement = None |
---|
2217 | |
---|
2218 | ret = API_f(self.stmt_h, |
---|
2219 | catalog, l_catalog, |
---|
2220 | schema, l_schema, |
---|
2221 | procedure, l_procedure, |
---|
2222 | column, l_column) |
---|
2223 | check_success(self, ret) |
---|
2224 | |
---|
2225 | self._NumOfRows() |
---|
2226 | self._UpdateDesc() |
---|
2227 | return self |
---|
2228 | |
---|
2229 | |
---|
2230 | def procedures(self, procedure=None, catalog=None, schema=None): |
---|
2231 | if not self.connection: |
---|
2232 | self.close() |
---|
2233 | |
---|
2234 | l_catalog = l_schema = l_procedure = 0 |
---|
2235 | |
---|
2236 | if unicode in [type(x) for x in (procedure, catalog, schema)]: |
---|
2237 | string_p = lambda x:wchar_pointer(UCS_buf(x)) |
---|
2238 | API_f = ODBC_API.SQLProceduresW |
---|
2239 | else: |
---|
2240 | string_p = ctypes.c_char_p |
---|
2241 | API_f = ODBC_API.SQLProcedures |
---|
2242 | |
---|
2243 | |
---|
2244 | |
---|
2245 | if catalog is not None: |
---|
2246 | l_catalog = len(catalog) |
---|
2247 | catalog = string_p(catalog) |
---|
2248 | if schema is not None: |
---|
2249 | l_schema = len(schema) |
---|
2250 | schema = string_p(schema) |
---|
2251 | if procedure is not None: |
---|
2252 | l_procedure = len(procedure) |
---|
2253 | procedure = string_p(procedure) |
---|
2254 | |
---|
2255 | |
---|
2256 | self._free_stmt() |
---|
2257 | self._last_param_types = None |
---|
2258 | self.statement = None |
---|
2259 | |
---|
2260 | ret = API_f(self.stmt_h, |
---|
2261 | catalog, l_catalog, |
---|
2262 | schema, l_schema, |
---|
2263 | procedure, l_procedure) |
---|
2264 | check_success(self, ret) |
---|
2265 | |
---|
2266 | self._NumOfRows() |
---|
2267 | self._UpdateDesc() |
---|
2268 | return self |
---|
2269 | |
---|
2270 | |
---|
2271 | def statistics(self, table, catalog=None, schema=None, unique=False, quick=True): |
---|
2272 | if not self.connection: |
---|
2273 | self.close() |
---|
2274 | |
---|
2275 | l_table = l_catalog = l_schema = 0 |
---|
2276 | |
---|
2277 | if unicode in [type(x) for x in (table, catalog, schema)]: |
---|
2278 | string_p = lambda x:wchar_pointer(UCS_buf(x)) |
---|
2279 | API_f = ODBC_API.SQLStatisticsW |
---|
2280 | else: |
---|
2281 | string_p = ctypes.c_char_p |
---|
2282 | API_f = ODBC_API.SQLStatistics |
---|
2283 | |
---|
2284 | |
---|
2285 | if catalog is not None: |
---|
2286 | l_catalog = len(catalog) |
---|
2287 | catalog = string_p(catalog) |
---|
2288 | if schema is not None: |
---|
2289 | l_schema = len(schema) |
---|
2290 | schema = string_p(schema) |
---|
2291 | if table is not None: |
---|
2292 | l_table = len(table) |
---|
2293 | table = string_p(table) |
---|
2294 | |
---|
2295 | if unique: |
---|
2296 | Unique = SQL_INDEX_UNIQUE |
---|
2297 | else: |
---|
2298 | Unique = SQL_INDEX_ALL |
---|
2299 | if quick: |
---|
2300 | Reserved = SQL_QUICK |
---|
2301 | else: |
---|
2302 | Reserved = SQL_ENSURE |
---|
2303 | |
---|
2304 | self._free_stmt() |
---|
2305 | self._last_param_types = None |
---|
2306 | self.statement = None |
---|
2307 | |
---|
2308 | ret = API_f(self.stmt_h, |
---|
2309 | catalog, l_catalog, |
---|
2310 | schema, l_schema, |
---|
2311 | table, l_table, |
---|
2312 | Unique, Reserved) |
---|
2313 | check_success(self, ret) |
---|
2314 | |
---|
2315 | self._NumOfRows() |
---|
2316 | self._UpdateDesc() |
---|
2317 | #self._BindCols() |
---|
2318 | return self |
---|
2319 | |
---|
2320 | |
---|
2321 | def commit(self): |
---|
2322 | if not self.connection: |
---|
2323 | self.close() |
---|
2324 | self.connection.commit() |
---|
2325 | |
---|
2326 | def rollback(self): |
---|
2327 | if not self.connection: |
---|
2328 | self.close() |
---|
2329 | self.connection.rollback() |
---|
2330 | |
---|
2331 | def setoutputsize(self, size, column = None): |
---|
2332 | if not self.connection: |
---|
2333 | self.close() |
---|
2334 | self._outputsize[column] = size |
---|
2335 | |
---|
2336 | def setinputsizes(self, sizes): |
---|
2337 | if not self.connection: |
---|
2338 | self.close() |
---|
2339 | self._inputsizers = [size for size in sizes] |
---|
2340 | |
---|
2341 | |
---|
2342 | def close(self): |
---|
2343 | """ Call SQLCloseCursor API to free the statement handle""" |
---|
2344 | # ret = ODBC_API.SQLCloseCursor(self.stmt_h) |
---|
2345 | # check_success(self, ret) |
---|
2346 | # |
---|
2347 | if self.connection.connected: |
---|
2348 | ret = ODBC_API.SQLFreeStmt(self.stmt_h, SQL_CLOSE) |
---|
2349 | check_success(self, ret) |
---|
2350 | |
---|
2351 | ret = ODBC_API.SQLFreeStmt(self.stmt_h, SQL_UNBIND) |
---|
2352 | check_success(self, ret) |
---|
2353 | |
---|
2354 | ret = ODBC_API.SQLFreeStmt(self.stmt_h, SQL_RESET_PARAMS) |
---|
2355 | check_success(self, ret) |
---|
2356 | |
---|
2357 | ret = ODBC_API.SQLFreeHandle(SQL_HANDLE_STMT, self.stmt_h) |
---|
2358 | check_success(self, ret) |
---|
2359 | |
---|
2360 | |
---|
2361 | self.closed = True |
---|
2362 | |
---|
2363 | |
---|
2364 | def __del__(self): |
---|
2365 | if not self.closed: |
---|
2366 | self.close() |
---|
2367 | |
---|
2368 | def __exit__(self, type, value, traceback): |
---|
2369 | if not self.connection: |
---|
2370 | self.close() |
---|
2371 | |
---|
2372 | if value: |
---|
2373 | self.rollback() |
---|
2374 | else: |
---|
2375 | self.commit() |
---|
2376 | |
---|
2377 | self.close() |
---|
2378 | |
---|
2379 | |
---|
2380 | def __enter__(self): |
---|
2381 | return self |
---|
2382 | |
---|
2383 | |
---|
2384 | |
---|
2385 | |
---|
2386 | |
---|
2387 | |
---|
2388 | # This class implement a odbc connection. |
---|
2389 | # |
---|
2390 | # |
---|
2391 | connection_timeout = 0 |
---|
2392 | |
---|
2393 | class Connection: |
---|
2394 | def __init__(self, connectString = '', autocommit = False, ansi = False, timeout = 0, unicode_results = use_unicode, readonly = False, **kargs): |
---|
2395 | """Init variables and connect to the engine""" |
---|
2396 | self.connected = 0 |
---|
2397 | self.type_size_dic = {} |
---|
2398 | self.ansi = False |
---|
2399 | self.unicode_results = False |
---|
2400 | self.dbc_h = ctypes.c_void_p() |
---|
2401 | self.autocommit = autocommit |
---|
2402 | self.readonly = False |
---|
2403 | # the query timeout value |
---|
2404 | self.timeout = 0 |
---|
2405 | # self._cursors = [] |
---|
2406 | for key, value in list(kargs.items()): |
---|
2407 | connectString = connectString + key + '=' + value + ';' |
---|
2408 | self.connectString = connectString |
---|
2409 | |
---|
2410 | |
---|
2411 | self.clear_output_converters() |
---|
2412 | |
---|
2413 | try: |
---|
2414 | lock.acquire() |
---|
2415 | if shared_env_h is None: |
---|
2416 | #Initialize an enviroment if it is not created. |
---|
2417 | AllocateEnv() |
---|
2418 | finally: |
---|
2419 | lock.release() |
---|
2420 | |
---|
2421 | # Allocate an DBC handle self.dbc_h under the environment shared_env_h |
---|
2422 | # This DBC handle is actually the basis of a "connection" |
---|
2423 | # The handle of self.dbc_h will be used to connect to a certain source |
---|
2424 | # in the self.connect and self.ConnectByDSN method |
---|
2425 | |
---|
2426 | ret = ODBC_API.SQLAllocHandle(SQL_HANDLE_DBC, shared_env_h, ADDR(self.dbc_h)) |
---|
2427 | check_success(self, ret) |
---|
2428 | |
---|
2429 | self.connection_timeout = connection_timeout |
---|
2430 | if self.connection_timeout != 0: |
---|
2431 | self.set_connection_timeout(connection_timeout) |
---|
2432 | |
---|
2433 | |
---|
2434 | self.connect(connectString, autocommit, ansi, timeout, unicode_results, readonly) |
---|
2435 | |
---|
2436 | def set_connection_timeout(self,connection_timeout): |
---|
2437 | self.connection_timeout = connection_timeout |
---|
2438 | ret = ODBC_API.SQLSetConnectAttr(self.dbc_h, SQL_ATTR_CONNECTION_TIMEOUT, connection_timeout, SQL_IS_UINTEGER); |
---|
2439 | check_success(self, ret) |
---|
2440 | |
---|
2441 | def connect(self, connectString = '', autocommit = False, ansi = False, timeout = 0, unicode_results = use_unicode, readonly = False): |
---|
2442 | """Connect to odbc, using connect strings and set the connection's attributes like autocommit and timeout |
---|
2443 | by calling SQLSetConnectAttr |
---|
2444 | """ |
---|
2445 | |
---|
2446 | # Before we establish the connection by the connection string |
---|
2447 | # Set the connection's attribute of "timeout" (Actully LOGIN_TIMEOUT) |
---|
2448 | if timeout != 0: |
---|
2449 | ret = ODBC_API.SQLSetConnectAttr(self.dbc_h, SQL_ATTR_LOGIN_TIMEOUT, timeout, SQL_IS_UINTEGER); |
---|
2450 | check_success(self, ret) |
---|
2451 | # Create one connection with a connect string by calling SQLDriverConnect |
---|
2452 | # and make self.dbc_h the handle of this connection |
---|
2453 | |
---|
2454 | |
---|
2455 | # Convert the connetsytring to encoded string |
---|
2456 | # so it can be converted to a ctypes c_char array object |
---|
2457 | |
---|
2458 | |
---|
2459 | self.ansi = ansi |
---|
2460 | if not ansi: |
---|
2461 | c_connectString = wchar_pointer(UCS_buf(self.connectString)) |
---|
2462 | odbc_func = ODBC_API.SQLDriverConnectW |
---|
2463 | else: |
---|
2464 | c_connectString = ctypes.c_char_p(self.connectString) |
---|
2465 | odbc_func = ODBC_API.SQLDriverConnect |
---|
2466 | |
---|
2467 | # With unixODBC, SQLDriverConnect will intermittently fail with error: |
---|
2468 | # [01000] [unixODBC][Driver Manager]Can't open lib '/path/to/so' : file not found" |
---|
2469 | # or: |
---|
2470 | # [01000] [unixODBC][Driver Manager]Can't open lib '/path/to/so' : (null)" |
---|
2471 | # when called concurrently by more than one threads. So, we have to |
---|
2472 | # use a lock to serialize the calls. By the way, the error is much |
---|
2473 | # less likely to happen if ODBC Tracing is enabled, likely due to the |
---|
2474 | # implicit serialization caused by writing to trace file. |
---|
2475 | if ODBC_API._name != 'odbc32': |
---|
2476 | try: |
---|
2477 | lock.acquire() |
---|
2478 | ret = odbc_func(self.dbc_h, 0, c_connectString, len(self.connectString), None, 0, None, SQL_DRIVER_NOPROMPT) |
---|
2479 | finally: |
---|
2480 | lock.release() |
---|
2481 | else: |
---|
2482 | ret = odbc_func(self.dbc_h, 0, c_connectString, len(self.connectString), None, 0, None, SQL_DRIVER_NOPROMPT) |
---|
2483 | check_success(self, ret) |
---|
2484 | |
---|
2485 | |
---|
2486 | # Set the connection's attribute of "autocommit" |
---|
2487 | # |
---|
2488 | self.autocommit = autocommit |
---|
2489 | |
---|
2490 | if self.autocommit == True: |
---|
2491 | ret = ODBC_API.SQLSetConnectAttr(self.dbc_h, SQL_ATTR_AUTOCOMMIT, SQL_AUTOCOMMIT_ON, SQL_IS_UINTEGER) |
---|
2492 | else: |
---|
2493 | ret = ODBC_API.SQLSetConnectAttr(self.dbc_h, SQL_ATTR_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF, SQL_IS_UINTEGER) |
---|
2494 | check_success(self, ret) |
---|
2495 | |
---|
2496 | # Set the connection's attribute of "readonly" |
---|
2497 | # |
---|
2498 | self.readonly = readonly |
---|
2499 | if self.readonly == True: |
---|
2500 | ret = ODBC_API.SQLSetConnectAttr(self.dbc_h, SQL_ATTR_ACCESS_MODE, SQL_MODE_READ_ONLY, SQL_IS_UINTEGER) |
---|
2501 | check_success(self, ret) |
---|
2502 | |
---|
2503 | self.unicode_results = unicode_results |
---|
2504 | self.connected = 1 |
---|
2505 | self.update_db_special_info() |
---|
2506 | |
---|
2507 | def clear_output_converters(self): |
---|
2508 | self.output_converter = {} |
---|
2509 | for sqltype, profile in SQL_data_type_dict.items(): |
---|
2510 | self.output_converter[sqltype] = profile[1] |
---|
2511 | |
---|
2512 | |
---|
2513 | def add_output_converter(self, sqltype, func): |
---|
2514 | self.output_converter[sqltype] = func |
---|
2515 | |
---|
2516 | |
---|
2517 | |
---|
2518 | def ConnectByDSN(self, dsn, user, passwd = ''): |
---|
2519 | """Connect to odbc, we need dsn, user and optionally password""" |
---|
2520 | self.dsn = dsn |
---|
2521 | self.user = user |
---|
2522 | self.passwd = passwd |
---|
2523 | |
---|
2524 | sn = create_buffer(dsn) |
---|
2525 | un = create_buffer(user) |
---|
2526 | pw = create_buffer(passwd) |
---|
2527 | |
---|
2528 | ret = ODBC_API.SQLConnect(self.dbc_h, sn, len(sn), un, len(un), pw, len(pw)) |
---|
2529 | check_success(self, ret) |
---|
2530 | |
---|
2531 | self.update_db_special_info() |
---|
2532 | self.connected = 1 |
---|
2533 | |
---|
2534 | |
---|
2535 | def cursor(self, row_type_callable=None): |
---|
2536 | #self.settimeout(self.timeout) |
---|
2537 | if not self.connected: |
---|
2538 | raise ProgrammingError('HY000','Attempt to use a closed connection.') |
---|
2539 | cur = Cursor(self, row_type_callable=row_type_callable) |
---|
2540 | # self._cursors.append(cur) |
---|
2541 | return cur |
---|
2542 | |
---|
2543 | def update_db_special_info(self): |
---|
2544 | for sql_type in ( |
---|
2545 | SQL_TYPE_TIMESTAMP, |
---|
2546 | SQL_TYPE_DATE, |
---|
2547 | SQL_TYPE_TIME, |
---|
2548 | SQL_SS_TIME2, |
---|
2549 | ): |
---|
2550 | cur = Cursor(self) |
---|
2551 | |
---|
2552 | try: |
---|
2553 | info_tuple = cur.getTypeInfo(sql_type) |
---|
2554 | if info_tuple is not None: |
---|
2555 | self.type_size_dic[sql_type] = info_tuple[2], info_tuple[14] |
---|
2556 | except: |
---|
2557 | pass |
---|
2558 | cur.close() |
---|
2559 | |
---|
2560 | self.support_SQLDescribeParam = False |
---|
2561 | try: |
---|
2562 | driver_name = self.getinfo(SQL_DRIVER_NAME) |
---|
2563 | if any(x in driver_name for x in ('SQLSRV','ncli','libsqlncli')): |
---|
2564 | self.support_SQLDescribeParam = True |
---|
2565 | except: |
---|
2566 | pass |
---|
2567 | |
---|
2568 | def commit(self): |
---|
2569 | if not self.connected: |
---|
2570 | raise ProgrammingError('HY000','Attempt to use a closed connection.') |
---|
2571 | |
---|
2572 | ret = SQLEndTran(SQL_HANDLE_DBC, self.dbc_h, SQL_COMMIT) |
---|
2573 | if ret != SQL_SUCCESS: |
---|
2574 | check_success(self, ret) |
---|
2575 | |
---|
2576 | def rollback(self): |
---|
2577 | if not self.connected: |
---|
2578 | raise ProgrammingError('HY000','Attempt to use a closed connection.') |
---|
2579 | ret = SQLEndTran(SQL_HANDLE_DBC, self.dbc_h, SQL_ROLLBACK) |
---|
2580 | if ret != SQL_SUCCESS: |
---|
2581 | check_success(self, ret) |
---|
2582 | |
---|
2583 | |
---|
2584 | |
---|
2585 | def getinfo(self,infotype): |
---|
2586 | if infotype not in list(aInfoTypes.keys()): |
---|
2587 | raise ProgrammingError('HY000','Invalid getinfo value: '+str(infotype)) |
---|
2588 | |
---|
2589 | |
---|
2590 | if aInfoTypes[infotype] == 'GI_UINTEGER': |
---|
2591 | total_buf_len = 1000 |
---|
2592 | alloc_buffer = ctypes.c_ulong() |
---|
2593 | used_buf_len = c_short() |
---|
2594 | ret = ODBC_API.SQLGetInfo(self.dbc_h,infotype,ADDR(alloc_buffer), total_buf_len,\ |
---|
2595 | ADDR(used_buf_len)) |
---|
2596 | check_success(self, ret) |
---|
2597 | result = alloc_buffer.value |
---|
2598 | |
---|
2599 | elif aInfoTypes[infotype] == 'GI_USMALLINT': |
---|
2600 | total_buf_len = 1000 |
---|
2601 | alloc_buffer = ctypes.c_ushort() |
---|
2602 | used_buf_len = c_short() |
---|
2603 | ret = ODBC_API.SQLGetInfo(self.dbc_h,infotype,ADDR(alloc_buffer), total_buf_len,\ |
---|
2604 | ADDR(used_buf_len)) |
---|
2605 | check_success(self, ret) |
---|
2606 | result = alloc_buffer.value |
---|
2607 | |
---|
2608 | else: |
---|
2609 | total_buf_len = 1000 |
---|
2610 | alloc_buffer = create_buffer(total_buf_len) |
---|
2611 | used_buf_len = c_short() |
---|
2612 | if self.ansi: |
---|
2613 | API_f = ODBC_API.SQLGetInfo |
---|
2614 | else: |
---|
2615 | API_f = ODBC_API.SQLGetInfoW |
---|
2616 | ret = API_f(self.dbc_h,infotype,ADDR(alloc_buffer), total_buf_len,\ |
---|
2617 | ADDR(used_buf_len)) |
---|
2618 | check_success(self, ret) |
---|
2619 | if self.ansi: |
---|
2620 | result = alloc_buffer.value |
---|
2621 | else: |
---|
2622 | result = UCS_dec(alloc_buffer) |
---|
2623 | if aInfoTypes[infotype] == 'GI_YESNO': |
---|
2624 | if unicode(result[0]) == unicode('Y'): |
---|
2625 | result = True |
---|
2626 | else: |
---|
2627 | result = False |
---|
2628 | |
---|
2629 | return result |
---|
2630 | |
---|
2631 | def __exit__(self, type, value, traceback): |
---|
2632 | if value: |
---|
2633 | self.rollback() |
---|
2634 | else: |
---|
2635 | self.commit() |
---|
2636 | |
---|
2637 | if self.connected: |
---|
2638 | self.close() |
---|
2639 | |
---|
2640 | def __enter__(self): |
---|
2641 | return self |
---|
2642 | |
---|
2643 | def __del__(self): |
---|
2644 | if self.connected: |
---|
2645 | self.close() |
---|
2646 | |
---|
2647 | def close(self): |
---|
2648 | if not self.connected: |
---|
2649 | raise ProgrammingError('HY000','Attempt to close a closed connection.') |
---|
2650 | # for cur in self._cursors: |
---|
2651 | # if not cur is None: |
---|
2652 | # if not cur.closed: |
---|
2653 | # cur.close() |
---|
2654 | |
---|
2655 | if self.connected: |
---|
2656 | #if DEBUG:print 'disconnect' |
---|
2657 | if not self.autocommit: |
---|
2658 | self.rollback() |
---|
2659 | ret = ODBC_API.SQLDisconnect(self.dbc_h) |
---|
2660 | check_success(self, ret) |
---|
2661 | #if DEBUG:print 'free dbc' |
---|
2662 | ret = ODBC_API.SQLFreeHandle(SQL_HANDLE_DBC, self.dbc_h) |
---|
2663 | check_success(self, ret) |
---|
2664 | # if shared_env_h.value: |
---|
2665 | # #if DEBUG:print 'env' |
---|
2666 | # ret = ODBC_API.SQLFreeHandle(SQL_HANDLE_ENV, shared_env_h) |
---|
2667 | # check_success(shared_env_h, ret) |
---|
2668 | self.connected = 0 |
---|
2669 | |
---|
2670 | odbc = Connection |
---|
2671 | connect = odbc |
---|
2672 | ''' |
---|
2673 | def connect(connectString = '', autocommit = False, ansi = False, timeout = 0, unicode_results = False, readonly = False, **kargs): |
---|
2674 | return odbc(connectString, autocommit, ansi, timeout, unicode_results, readonly, kargs) |
---|
2675 | ''' |
---|
2676 | |
---|
2677 | def drivers(): |
---|
2678 | if sys.platform not in ('win32','cli'): |
---|
2679 | raise Exception('This function is available for use in Windows only.') |
---|
2680 | try: |
---|
2681 | lock.acquire() |
---|
2682 | if shared_env_h is None: |
---|
2683 | AllocateEnv() |
---|
2684 | finally: |
---|
2685 | lock.release() |
---|
2686 | |
---|
2687 | DriverDescription = create_buffer_u(1000) |
---|
2688 | BufferLength1 = c_short(1000) |
---|
2689 | DescriptionLength = c_short() |
---|
2690 | DriverAttributes = create_buffer_u(1000) |
---|
2691 | BufferLength2 = c_short(1000) |
---|
2692 | AttributesLength = c_short() |
---|
2693 | ret = SQL_SUCCESS |
---|
2694 | DriverList = [] |
---|
2695 | Direction = SQL_FETCH_FIRST |
---|
2696 | while ret != SQL_NO_DATA: |
---|
2697 | ret = ODBC_API.SQLDriversW(shared_env_h, Direction , DriverDescription , BufferLength1 |
---|
2698 | , ADDR(DescriptionLength), DriverAttributes, BufferLength2, ADDR(AttributesLength)) |
---|
2699 | check_success(shared_env_h, ret) |
---|
2700 | DriverList.append(DriverDescription.value) |
---|
2701 | if Direction == SQL_FETCH_FIRST: |
---|
2702 | Direction = SQL_FETCH_NEXT |
---|
2703 | return DriverList |
---|
2704 | |
---|
2705 | |
---|
2706 | |
---|
2707 | |
---|
2708 | def win_create_mdb(mdb_path, sort_order = "General\0\0"): |
---|
2709 | if sys.platform not in ('win32','cli'): |
---|
2710 | raise Exception('This function is available for use in Windows only.') |
---|
2711 | |
---|
2712 | mdb_driver = [d for d in drivers() if 'Microsoft Access Driver (*.mdb' in d] |
---|
2713 | if mdb_driver == []: |
---|
2714 | raise Exception('Access Driver is not found.') |
---|
2715 | else: |
---|
2716 | driver_name = mdb_driver[0].encode('mbcs') |
---|
2717 | |
---|
2718 | |
---|
2719 | #CREATE_DB=<path name> <sort order> |
---|
2720 | ctypes.windll.ODBCCP32.SQLConfigDataSource.argtypes = [ctypes.c_void_p,ctypes.c_ushort,ctypes.c_char_p,ctypes.c_char_p] |
---|
2721 | |
---|
2722 | if py_v3: |
---|
2723 | c_Path = bytes("CREATE_DB=" + mdb_path + " " + sort_order,'mbcs') |
---|
2724 | else: |
---|
2725 | c_Path = "CREATE_DB=" + mdb_path + " " + sort_order |
---|
2726 | ODBC_ADD_SYS_DSN = 1 |
---|
2727 | |
---|
2728 | |
---|
2729 | ret = ctypes.windll.ODBCCP32.SQLConfigDataSource(None,ODBC_ADD_SYS_DSN,driver_name, c_Path) |
---|
2730 | if not ret: |
---|
2731 | raise Exception('Failed to create Access mdb file - "%s". Please check file path, permission and Access driver readiness.' %mdb_path) |
---|
2732 | |
---|
2733 | |
---|
2734 | def win_connect_mdb(mdb_path): |
---|
2735 | if sys.platform not in ('win32','cli'): |
---|
2736 | raise Exception('This function is available for use in Windows only.') |
---|
2737 | |
---|
2738 | mdb_driver = [d for d in drivers() if 'Microsoft Access Driver (*.mdb' in d] |
---|
2739 | if mdb_driver == []: |
---|
2740 | raise Exception('Access Driver is not found.') |
---|
2741 | else: |
---|
2742 | driver_name = mdb_driver[0] |
---|
2743 | |
---|
2744 | return connect('Driver={'+driver_name+"};DBQ="+mdb_path, unicode_results = use_unicode, readonly = False) |
---|
2745 | |
---|
2746 | |
---|
2747 | |
---|
2748 | def win_compact_mdb(mdb_path, compacted_mdb_path, sort_order = "General\0\0"): |
---|
2749 | if sys.platform not in ('win32','cli'): |
---|
2750 | raise Exception('This function is available for use in Windows only.') |
---|
2751 | |
---|
2752 | |
---|
2753 | mdb_driver = [d for d in drivers() if 'Microsoft Access Driver (*.mdb' in d] |
---|
2754 | if mdb_driver == []: |
---|
2755 | raise Exception('Access Driver is not found.') |
---|
2756 | else: |
---|
2757 | driver_name = mdb_driver[0].encode('mbcs') |
---|
2758 | |
---|
2759 | #COMPACT_DB=<source path> <destination path> <sort order> |
---|
2760 | ctypes.windll.ODBCCP32.SQLConfigDataSource.argtypes = [ctypes.c_void_p,ctypes.c_ushort,ctypes.c_char_p,ctypes.c_char_p] |
---|
2761 | #driver_name = "Microsoft Access Driver (*.mdb)" |
---|
2762 | if py_v3: |
---|
2763 | c_Path = bytes("COMPACT_DB=" + mdb_path + " " + compacted_mdb_path + " " + sort_order,'mbcs') |
---|
2764 | #driver_name = bytes(driver_name,'mbcs') |
---|
2765 | else: |
---|
2766 | c_Path = "COMPACT_DB=" + mdb_path + " " + compacted_mdb_path + " " + sort_order |
---|
2767 | |
---|
2768 | ODBC_ADD_SYS_DSN = 1 |
---|
2769 | ret = ctypes.windll.ODBCCP32.SQLConfigDataSource(None,ODBC_ADD_SYS_DSN,driver_name, c_Path) |
---|
2770 | if not ret: |
---|
2771 | raise Exception('Failed to compact Access mdb file - "%s". Please check file path, permission and Access driver readiness.' %compacted_mdb_path) |
---|
2772 | |
---|
2773 | |
---|
2774 | def dataSources(): |
---|
2775 | """Return a list with [name, descrition]""" |
---|
2776 | dsn = create_buffer(1024) |
---|
2777 | desc = create_buffer(1024) |
---|
2778 | dsn_len = c_short() |
---|
2779 | desc_len = c_short() |
---|
2780 | dsn_list = {} |
---|
2781 | try: |
---|
2782 | lock.acquire() |
---|
2783 | if shared_env_h is None: |
---|
2784 | AllocateEnv() |
---|
2785 | finally: |
---|
2786 | lock.release() |
---|
2787 | while 1: |
---|
2788 | ret = ODBC_API.SQLDataSources(shared_env_h, SQL_FETCH_NEXT, \ |
---|
2789 | dsn, len(dsn), ADDR(dsn_len), desc, len(desc), ADDR(desc_len)) |
---|
2790 | if ret == SQL_NO_DATA_FOUND: |
---|
2791 | break |
---|
2792 | elif not ret in (SQL_SUCCESS, SQL_SUCCESS_WITH_INFO): |
---|
2793 | ctrl_err(SQL_HANDLE_ENV, shared_env_h, ret) |
---|
2794 | else: |
---|
2795 | dsn_list[dsn.value] = desc.value |
---|
2796 | return dsn_list |
---|
2797 | |
---|
2798 | |
---|
2799 | def monkey_patch_for_gevent(): |
---|
2800 | import functools, gevent |
---|
2801 | apply_e = gevent.get_hub().threadpool.apply_e |
---|
2802 | def monkey_patch(func): |
---|
2803 | @functools.wraps(func) |
---|
2804 | def wrap(*args, **kwargs): |
---|
2805 | #if DEBUG:print('%s called with %s %s' % (func, args, kwargs)) |
---|
2806 | return apply_e(Exception, func, args, kwargs) |
---|
2807 | return wrap |
---|
2808 | for attr in dir(ODBC_API): |
---|
2809 | if attr.startswith('SQL') and hasattr(getattr(ODBC_API, attr), 'argtypes'): |
---|
2810 | setattr(ODBC_API, attr, monkey_patch(getattr(ODBC_API, attr))) |
---|