sqlalchemy-iris 0.5.0b3__py3-none-any.whl → 0.6.0b1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- intersystems_iris/_BufferReader.py +10 -0
- intersystems_iris/_BufferWriter.py +32 -0
- intersystems_iris/_ConnectionInformation.py +54 -0
- intersystems_iris/_ConnectionParameters.py +18 -0
- intersystems_iris/_Constant.py +38 -0
- intersystems_iris/_DBList.py +499 -0
- intersystems_iris/_Device.py +69 -0
- intersystems_iris/_GatewayContext.py +25 -0
- intersystems_iris/_GatewayException.py +4 -0
- intersystems_iris/_GatewayUtility.py +74 -0
- intersystems_iris/_IRIS.py +1294 -0
- intersystems_iris/_IRISConnection.py +516 -0
- intersystems_iris/_IRISEmbedded.py +85 -0
- intersystems_iris/_IRISGlobalNode.py +273 -0
- intersystems_iris/_IRISGlobalNodeView.py +25 -0
- intersystems_iris/_IRISIterator.py +143 -0
- intersystems_iris/_IRISList.py +360 -0
- intersystems_iris/_IRISNative.py +208 -0
- intersystems_iris/_IRISOREF.py +4 -0
- intersystems_iris/_IRISObject.py +424 -0
- intersystems_iris/_IRISReference.py +133 -0
- intersystems_iris/_InStream.py +149 -0
- intersystems_iris/_LegacyIterator.py +135 -0
- intersystems_iris/_ListItem.py +15 -0
- intersystems_iris/_ListReader.py +84 -0
- intersystems_iris/_ListWriter.py +157 -0
- intersystems_iris/_LogFileStream.py +115 -0
- intersystems_iris/_MessageHeader.py +51 -0
- intersystems_iris/_OutStream.py +25 -0
- intersystems_iris/_PrintStream.py +65 -0
- intersystems_iris/_PythonGateway.py +850 -0
- intersystems_iris/_SharedMemorySocket.py +87 -0
- intersystems_iris/__init__.py +79 -0
- intersystems_iris/__main__.py +7 -0
- intersystems_iris/dbapi/_Column.py +56 -0
- intersystems_iris/dbapi/_DBAPI.py +2295 -0
- intersystems_iris/dbapi/_Descriptor.py +46 -0
- intersystems_iris/dbapi/_IRISStream.py +63 -0
- intersystems_iris/dbapi/_Message.py +158 -0
- intersystems_iris/dbapi/_Parameter.py +138 -0
- intersystems_iris/dbapi/_ParameterCollection.py +133 -0
- intersystems_iris/dbapi/_ResultSetRow.py +314 -0
- intersystems_iris/dbapi/_SQLType.py +32 -0
- intersystems_iris/dbapi/__init__.py +0 -0
- intersystems_iris/dbapi/preparser/_PreParser.py +1658 -0
- intersystems_iris/dbapi/preparser/_Scanner.py +391 -0
- intersystems_iris/dbapi/preparser/_Token.py +81 -0
- intersystems_iris/dbapi/preparser/_TokenList.py +251 -0
- intersystems_iris/dbapi/preparser/__init__.py +0 -0
- intersystems_iris/pex/_BusinessHost.py +101 -0
- intersystems_iris/pex/_BusinessOperation.py +105 -0
- intersystems_iris/pex/_BusinessProcess.py +214 -0
- intersystems_iris/pex/_BusinessService.py +95 -0
- intersystems_iris/pex/_Common.py +228 -0
- intersystems_iris/pex/_Director.py +24 -0
- intersystems_iris/pex/_IRISBusinessOperation.py +5 -0
- intersystems_iris/pex/_IRISBusinessService.py +18 -0
- intersystems_iris/pex/_IRISInboundAdapter.py +5 -0
- intersystems_iris/pex/_IRISOutboundAdapter.py +17 -0
- intersystems_iris/pex/_InboundAdapter.py +57 -0
- intersystems_iris/pex/_Message.py +6 -0
- intersystems_iris/pex/_OutboundAdapter.py +46 -0
- intersystems_iris/pex/__init__.py +25 -0
- iris/__init__.py +25 -0
- iris/iris_site.py +13 -0
- iris/irisbuiltins.py +97 -0
- iris/irisloader.py +199 -0
- irisnative/_IRISNative.py +9 -0
- irisnative/__init__.py +10 -0
- {sqlalchemy_iris-0.5.0b3.dist-info → sqlalchemy_iris-0.6.0b1.dist-info}/METADATA +1 -1
- sqlalchemy_iris-0.6.0b1.dist-info/RECORD +83 -0
- sqlalchemy_iris-0.6.0b1.dist-info/top_level.txt +4 -0
- sqlalchemy_iris-0.5.0b3.dist-info/RECORD +0 -14
- sqlalchemy_iris-0.5.0b3.dist-info/top_level.txt +0 -1
- {sqlalchemy_iris-0.5.0b3.dist-info → sqlalchemy_iris-0.6.0b1.dist-info}/LICENSE +0 -0
- {sqlalchemy_iris-0.5.0b3.dist-info → sqlalchemy_iris-0.6.0b1.dist-info}/WHEEL +0 -0
- {sqlalchemy_iris-0.5.0b3.dist-info → sqlalchemy_iris-0.6.0b1.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,2295 @@
|
|
1
|
+
import enum
|
2
|
+
import copy
|
3
|
+
import decimal
|
4
|
+
import intersystems_iris
|
5
|
+
from collections import namedtuple
|
6
|
+
from . import _Message
|
7
|
+
import intersystems_iris.dbapi._Parameter
|
8
|
+
import intersystems_iris.dbapi._Column
|
9
|
+
from ._ResultSetRow import _ResultSetRow
|
10
|
+
import intersystems_iris.dbapi._ParameterCollection
|
11
|
+
import intersystems_iris.dbapi.preparser._PreParser
|
12
|
+
from intersystems_iris.dbapi._Parameter import ParameterMode
|
13
|
+
from intersystems_iris.dbapi.preparser._PreParser import StatementType
|
14
|
+
from intersystems_iris._IRISConnection import Feature
|
15
|
+
from intersystems_iris._InStream import _InStream
|
16
|
+
from intersystems_iris.dbapi._IRISStream import (IRISStream, IRISBinaryStream, )
|
17
|
+
from ._SQLType import SQLType
|
18
|
+
|
19
|
+
from .._IRISNative import connect as native_connect
|
20
|
+
from .._IRISEmbedded import _IRISEmbedded
|
21
|
+
|
22
|
+
def NotImplementedErrorDBAPI(msg=None):
|
23
|
+
import traceback
|
24
|
+
if msg is None:
|
25
|
+
traceback.print_stack()
|
26
|
+
msg = "Coming soon to an IRIS DB API near you!"
|
27
|
+
return NotImplementedError(msg)
|
28
|
+
|
29
|
+
def embedded_connect(*args, hostname = None, port = None, namespace = None, username = None, password = None, **kw):
|
30
|
+
connection = _IRISEmbedded()
|
31
|
+
connection.connect(hostname, port, namespace, username, password, **kw)
|
32
|
+
return connection
|
33
|
+
|
34
|
+
def connect(*args, embedded=False, hostname = None, port = None, namespace = None, username = None, password = None, **kw):
|
35
|
+
if not embedded:
|
36
|
+
return native_connect(*args, hostname=hostname, port=port, namespace=namespace, username=username, password=password, **kw)
|
37
|
+
else:
|
38
|
+
return embedded_connect(*args, hostname=hostname, port=port, namespace=namespace, username=username, password=password, **kw)
|
39
|
+
|
40
|
+
|
41
|
+
class ServerReturnType(enum.IntEnum):
|
42
|
+
NO_RETURN_VALUE = 0
|
43
|
+
IGNORE_RETURN_VALUE = 1
|
44
|
+
HAS_RETURN_VALUE = 2
|
45
|
+
NULL_RETURN_VALUE = 3
|
46
|
+
|
47
|
+
class CursorType(enum.IntEnum):
|
48
|
+
DEFAULT = 0
|
49
|
+
PREPARED = 1
|
50
|
+
CALLABLE = 2
|
51
|
+
|
52
|
+
# api globals, methods, classes, etc.
|
53
|
+
# globals
|
54
|
+
apilevel = "2.0"
|
55
|
+
threadsafety = 0
|
56
|
+
paramstyle = "qmark"
|
57
|
+
|
58
|
+
class _BaseCursor:
|
59
|
+
embedded = False
|
60
|
+
def __init__(self, connection):
|
61
|
+
self._connection = connection
|
62
|
+
|
63
|
+
self._columns = None
|
64
|
+
self._rowcount = -1
|
65
|
+
self.arraysize = 1
|
66
|
+
|
67
|
+
self._result_set = None
|
68
|
+
|
69
|
+
self._rsrow = None
|
70
|
+
self._rownumber = 0
|
71
|
+
self._cursor_ptr = 0
|
72
|
+
self._scroll_flag = False
|
73
|
+
|
74
|
+
self.maxRowItemCount = 0
|
75
|
+
|
76
|
+
self._is_batch_update = False
|
77
|
+
|
78
|
+
self._exec_params = None
|
79
|
+
self._params = intersystems_iris.dbapi._ParameterCollection._ParameterCollection()
|
80
|
+
self._multiple_result_sets = False
|
81
|
+
self._mrs_done = False
|
82
|
+
self._has_return_value = 0
|
83
|
+
self._cursor_type = 0
|
84
|
+
self._parameter_list_mismatch_exception = False
|
85
|
+
self._fetch_done = False
|
86
|
+
self._output_parameter_list = None
|
87
|
+
|
88
|
+
self._sqlcode = None
|
89
|
+
self._lastrowid = None
|
90
|
+
|
91
|
+
self._closed = False
|
92
|
+
|
93
|
+
def __enter__(self):
|
94
|
+
return self
|
95
|
+
|
96
|
+
def __exit__(self, type, value, traceback):
|
97
|
+
self._connection.rollback()
|
98
|
+
self.close()
|
99
|
+
|
100
|
+
def __iter__(self):
|
101
|
+
if self._result_set == None:
|
102
|
+
raise InterfaceError("Either execute has not yet been called, or the previous call of execute did not return a result set")
|
103
|
+
return self
|
104
|
+
|
105
|
+
def __next__(self):
|
106
|
+
row = self.fetchone()
|
107
|
+
if row:
|
108
|
+
return row
|
109
|
+
raise StopIteration
|
110
|
+
|
111
|
+
# non-api methods and classes
|
112
|
+
def isClosed(self):
|
113
|
+
return self._closed
|
114
|
+
|
115
|
+
def setinputsizes(self, sizes):
|
116
|
+
raise NotImplementedErrorDBAPI()
|
117
|
+
|
118
|
+
def setoutputsize(size, column = None):
|
119
|
+
raise NotImplementedErrorDBAPI()
|
120
|
+
|
121
|
+
@property
|
122
|
+
def sqlcode(self):
|
123
|
+
if self._closed:
|
124
|
+
raise InterfaceError("Cursor is closed")
|
125
|
+
return 0 if self._sqlcode is None else self._sqlcode
|
126
|
+
|
127
|
+
def close(self):
|
128
|
+
if self._closed:
|
129
|
+
return
|
130
|
+
self._columns = None
|
131
|
+
self._rowcount = -1
|
132
|
+
self.arraysize = 0
|
133
|
+
|
134
|
+
self._connection = None
|
135
|
+
self._in_message = None
|
136
|
+
self._out_message = None
|
137
|
+
|
138
|
+
self._result_set = None
|
139
|
+
|
140
|
+
if self._rsrow != None:
|
141
|
+
self._rsrow = None
|
142
|
+
self._cursor_ptr = 0
|
143
|
+
self._scroll_flag = False
|
144
|
+
self._warehouse = []
|
145
|
+
self._warehouse_dict = {}
|
146
|
+
self._last_row_in_warehouse_dict = -1
|
147
|
+
self._warehouse_dict_keys = []
|
148
|
+
|
149
|
+
self._params = None
|
150
|
+
self._parsed_statement = None
|
151
|
+
self._cursor_type = CursorType.DEFAULT
|
152
|
+
self._statementType = StatementType.UPDATE # default
|
153
|
+
self._paramInfo = None
|
154
|
+
self.statement = None
|
155
|
+
self.statementFeatureOption = Feature.optionNone
|
156
|
+
self._statement_id = None
|
157
|
+
self._sqlcode = None
|
158
|
+
self._current_wire = None
|
159
|
+
self._result_set = []
|
160
|
+
self._rs_index = -1
|
161
|
+
|
162
|
+
self._parameter_sets = 0
|
163
|
+
self._exec_params = None
|
164
|
+
self._is_batch_update = False
|
165
|
+
self._multiple_result_sets = False
|
166
|
+
self._mrs_done = False
|
167
|
+
self._fetch_done = False
|
168
|
+
self._parameter_list_mismatch_exception = False
|
169
|
+
if self._output_parameter_list != None:
|
170
|
+
self._output_parameter_list._clear_list()
|
171
|
+
|
172
|
+
self._closed = True
|
173
|
+
|
174
|
+
def _cleanup(self):
|
175
|
+
if self._rsrow != None:
|
176
|
+
self._rsrow = None
|
177
|
+
if self._params != None:
|
178
|
+
self._params._clear()
|
179
|
+
self._multiple_result_sets = False
|
180
|
+
self._mrs_done = False
|
181
|
+
self._fetch_done = False
|
182
|
+
self._parameter_list_mismatch_exception = False
|
183
|
+
self._parameter_sets = 0
|
184
|
+
self._rowcount = -1
|
185
|
+
self._exec_params = None
|
186
|
+
self._statementType = StatementType.UPDATE
|
187
|
+
self.statementFeatureOption = 0
|
188
|
+
self.maxRowItemCount = 0
|
189
|
+
self._is_batch_update = False
|
190
|
+
|
191
|
+
def direct_execute(self, operation, *params):
|
192
|
+
self.statement = operation
|
193
|
+
if len(params) == 1 and (isinstance(params[0], tuple) or isinstance(params[0], list)):
|
194
|
+
self.params = params[0]
|
195
|
+
else:
|
196
|
+
self.params = params
|
197
|
+
self._params.set_input_params(self.params)
|
198
|
+
|
199
|
+
self._cursor_type = CursorType.DEFAULT
|
200
|
+
self._cleanup()
|
201
|
+
self._preparse()
|
202
|
+
|
203
|
+
self._execute()
|
204
|
+
return self._rowcount
|
205
|
+
|
206
|
+
def execute(self, operation, params=()):
|
207
|
+
self.statement = operation
|
208
|
+
if params and not isinstance(params, list) and not isinstance(params, tuple):
|
209
|
+
params = (params, )
|
210
|
+
self.params = params if params is not None else ()
|
211
|
+
self._params.set_input_params(self.params)
|
212
|
+
|
213
|
+
self._cleanup()
|
214
|
+
self._preparse()
|
215
|
+
|
216
|
+
if self._statementType == StatementType.UPDATE:
|
217
|
+
self._cursor_type = CursorType.PREPARED
|
218
|
+
self._prepare()
|
219
|
+
else:
|
220
|
+
self._cursor_type = CursorType.DEFAULT
|
221
|
+
|
222
|
+
self._execute()
|
223
|
+
return self._rowcount
|
224
|
+
|
225
|
+
def add_batch(self):
|
226
|
+
if self._closed:
|
227
|
+
raise InterfaceError("Cursor is closed")
|
228
|
+
|
229
|
+
if self._params._array_bound:
|
230
|
+
if len(self._params._params_list) > 0:
|
231
|
+
cnt = 0
|
232
|
+
first = True
|
233
|
+
for i in range(self._params._user_parameters_size):
|
234
|
+
i = i + 1
|
235
|
+
cnt = len(self._params._get_user_param(i)._values)
|
236
|
+
if cnt > 1:
|
237
|
+
if first:
|
238
|
+
self._parameter_sets = cnt
|
239
|
+
first = False
|
240
|
+
elif self._parameter_sets != cnt:
|
241
|
+
raise Exception("Unmatched columnwise parameter values: " + str(self._parameter_sets)
|
242
|
+
+ " rows expected, but found only " + str(cnt) +" in " + str(i) + " parameter!")
|
243
|
+
if self._parameter_sets > 1:
|
244
|
+
return
|
245
|
+
self._parameter_sets = self._parameter_sets + 1
|
246
|
+
|
247
|
+
for param in self._params._params_list:
|
248
|
+
if param.mode != ParameterMode.REPLACED_LITERAL:
|
249
|
+
if len(param._values) != self._parameter_sets:
|
250
|
+
if self._parameter_sets != 1:
|
251
|
+
if len(param._values) + 1 == self._parameter_sets:
|
252
|
+
param._values.append(param._values[len(param._values) - 1])
|
253
|
+
continue
|
254
|
+
|
255
|
+
def executemany(self, operation, seq_of_params):
|
256
|
+
self._rowcount = 0
|
257
|
+
if self._closed:
|
258
|
+
raise InterfaceError("Cursor is closed")
|
259
|
+
if self._connection == None or self._connection.isClosed():
|
260
|
+
raise InterfaceError("Connection not open")
|
261
|
+
|
262
|
+
self.statement = operation
|
263
|
+
self.params = seq_of_params
|
264
|
+
self._params.set_input_params(self.params)
|
265
|
+
|
266
|
+
self._cursor_type = CursorType.PREPARED
|
267
|
+
self._cleanup()
|
268
|
+
self._is_batch_update = True
|
269
|
+
|
270
|
+
self._preparse()
|
271
|
+
self._prepare()
|
272
|
+
|
273
|
+
for row_num, param_row in enumerate(seq_of_params):
|
274
|
+
self.add_batch()
|
275
|
+
|
276
|
+
if self._parameter_sets == 0:
|
277
|
+
for param in self._params._params_list:
|
278
|
+
if param.value == '?':
|
279
|
+
raise ValueError("Missing value")
|
280
|
+
self._prepared_update_execute() # similar to executing a statement w/ literals
|
281
|
+
return
|
282
|
+
|
283
|
+
for param in self._params._params_list:
|
284
|
+
mode = param.mode
|
285
|
+
if mode == ParameterMode.INPUT_OUTPUT or mode == ParameterMode.OUTPUT:
|
286
|
+
raise ValueError("INOUT/OUT parameters not permitted")
|
287
|
+
|
288
|
+
self._prepared_update_execute()
|
289
|
+
|
290
|
+
return self._rowcount
|
291
|
+
|
292
|
+
def _preparse(self):
|
293
|
+
csql = self._connection._pre_preparse_cache.get(self.statement)
|
294
|
+
if csql != None:
|
295
|
+
self._has_return_value = csql._has_return_value
|
296
|
+
self._params = copy.deepcopy(csql._params)
|
297
|
+
self._params.set_input_params(self.params)
|
298
|
+
self._parsed_statement = csql._parsed_statement
|
299
|
+
self._statementType = csql._statementType
|
300
|
+
self._paramInfo = csql._paramInfo
|
301
|
+
return
|
302
|
+
|
303
|
+
count = 0
|
304
|
+
for i, item in enumerate(self.params):
|
305
|
+
if isinstance(item, list) or isinstance(item, tuple):
|
306
|
+
if not self._is_batch_update:
|
307
|
+
raise TypeError("Unsupported argument type: " + str(type(item)))
|
308
|
+
for ele in item:
|
309
|
+
if intersystems_iris._DBList._DBList._set_switcher.get(type(ele), None) == None:
|
310
|
+
raise TypeError("Unsupported argument type: " + str(type(ele)))
|
311
|
+
elif intersystems_iris._DBList._DBList._set_switcher.get(type(item), None) is None:
|
312
|
+
raise TypeError("Unsupported argument type: " + str(type(item)))
|
313
|
+
if i == 0:
|
314
|
+
count = len(item) if isinstance(item, list) or isinstance(item, tuple) else 1
|
315
|
+
else:
|
316
|
+
curr_count = len(item) if isinstance(item, list) or isinstance(item, tuple) else 1
|
317
|
+
if count != curr_count:
|
318
|
+
raise Exception("Parameter count does not match")
|
319
|
+
|
320
|
+
parser = intersystems_iris.dbapi.preparser._PreParser._PreParser(self._connection._connection_info._delimited_ids, embedded=self.embedded)
|
321
|
+
try:
|
322
|
+
pOut = parser.PreParse(self.statement, self._params)
|
323
|
+
except Exception as e:
|
324
|
+
raise InterfaceError("Error parsing statement '" + self.statement + "':\n" + str(e))
|
325
|
+
|
326
|
+
if len(self.params) > 0:
|
327
|
+
item = self.params[0]
|
328
|
+
if (isinstance(item, list) or isinstance(item, tuple)) and not self._is_batch_update:
|
329
|
+
raise TypeError("Unsupported argument type: " + str(type(item)))
|
330
|
+
|
331
|
+
self._parsed_statement = pOut.sResult
|
332
|
+
self._statementType = pOut.p_eStmtType
|
333
|
+
self._paramInfo = parser.m_ParamInfo
|
334
|
+
|
335
|
+
if self._statementType == StatementType.CALL:
|
336
|
+
self._has_return_value = ServerReturnType.NO_RETURN_VALUE
|
337
|
+
elif self._statementType == StatementType.CALLWITHRESULT:
|
338
|
+
self._has_return_value = ServerReturnType.HAS_RETURN_VALUE
|
339
|
+
|
340
|
+
self._update_parameters()
|
341
|
+
self._connection._add_pre_preparse_cache(self.statement, self)
|
342
|
+
|
343
|
+
def _prepare(self):
|
344
|
+
notDDL = bool(self._statementType != StatementType.DDL_ALTER_DROP
|
345
|
+
and self._statementType != StatementType.DDL_OTHER)
|
346
|
+
|
347
|
+
if notDDL and self._get_cached_info():
|
348
|
+
return
|
349
|
+
else:
|
350
|
+
self._prepare_new()
|
351
|
+
|
352
|
+
def _update_parameters(self):
|
353
|
+
count = self._paramInfo._list_data[0] # self._paramInfo.count()
|
354
|
+
if count == 0:
|
355
|
+
return
|
356
|
+
|
357
|
+
temp_list_data = self._paramInfo._list_data[1:]
|
358
|
+
param_info_count = int(len(temp_list_data)/2)
|
359
|
+
if self._is_batch_update:
|
360
|
+
unknown_count = replaced_count = 0
|
361
|
+
for item in temp_list_data:
|
362
|
+
if item == 'c':
|
363
|
+
replaced_count = replaced_count + 1
|
364
|
+
elif item == '?':
|
365
|
+
unknown_count = unknown_count + 1
|
366
|
+
|
367
|
+
if len(self.params) > 0:
|
368
|
+
item = self.params[0]
|
369
|
+
param_count = len(item) if isinstance(item, list) or isinstance(item, tuple) else len(self.params)
|
370
|
+
if param_count != unknown_count:
|
371
|
+
raise Exception("Parameter mismatch")
|
372
|
+
else:
|
373
|
+
if self._cursor_type == CursorType.CALLABLE:
|
374
|
+
i = 0
|
375
|
+
for param in self._params._params_list:
|
376
|
+
if param.mode == ParameterMode.RETURN_VALUE:
|
377
|
+
continue
|
378
|
+
else:
|
379
|
+
if len(self._params._params_list) == len(self.params) and self.params[i] == None:
|
380
|
+
param.mode = ParameterMode.OUTPUT
|
381
|
+
if len(self._params._params_list) > len(self.params):
|
382
|
+
if i >= len(self.params):
|
383
|
+
param.mode = ParameterMode.OUTPUT
|
384
|
+
else:
|
385
|
+
if self.params[i] == None:
|
386
|
+
param.mode = ParameterMode.OUTPUT
|
387
|
+
i += 1
|
388
|
+
return
|
389
|
+
|
390
|
+
if len(temp_list_data) > 0:
|
391
|
+
if count != param_info_count:
|
392
|
+
raise Exception("Parameter mismatch")
|
393
|
+
|
394
|
+
unknown_count = replaced_count = 0
|
395
|
+
for item in temp_list_data:
|
396
|
+
if item == 'c':
|
397
|
+
replaced_count = replaced_count + 1
|
398
|
+
elif item == '?':
|
399
|
+
unknown_count = unknown_count + 1
|
400
|
+
|
401
|
+
if unknown_count != len(self.params):
|
402
|
+
raise Exception("Incorrect number of parameters")
|
403
|
+
|
404
|
+
def _is_not_default_or_replaced(self, param):
|
405
|
+
mode = param.mode
|
406
|
+
if mode != ParameterMode.REPLACED_LITERAL and mode != ParameterMode.DEFAULT_PARAMETER and mode != ParameterMode.INPUT:
|
407
|
+
raise Exception("Parameters not allowed in Cursor class")
|
408
|
+
|
409
|
+
def _validate_parameters(self):
|
410
|
+
if self._parameter_list_mismatch_exception and not self._params._has_bound_by_param_name:
|
411
|
+
raise Exception("Parameter list mismatch")
|
412
|
+
for param in self._params._params_list:
|
413
|
+
self._is_not_default_or_replaced(param)
|
414
|
+
|
415
|
+
def _validate_prepared_parameters(self):
|
416
|
+
if self._parameter_list_mismatch_exception and not self._params._has_bound_by_param_name:
|
417
|
+
raise Exception("Parameter list mismatch")
|
418
|
+
i = 0
|
419
|
+
if self._has_return_value == ServerReturnType.IGNORE_RETURN_VALUE or self._has_return_value == ServerReturnType.NULL_RETURN_VALUE:
|
420
|
+
i = 1
|
421
|
+
for param in self._params._params_list:
|
422
|
+
if i == 1:
|
423
|
+
i = 0
|
424
|
+
continue
|
425
|
+
if param.mode == ParameterMode.UNKNOWN:
|
426
|
+
if self._params._has_named_parameters():
|
427
|
+
param.mode = ParameterMode.DEFAULT_PARAMETER
|
428
|
+
else:
|
429
|
+
raise Exception("Not all parameters bound/registered")
|
430
|
+
|
431
|
+
def _execute(self):
|
432
|
+
if self._closed:
|
433
|
+
raise InterfaceError("Cursor is closed")
|
434
|
+
if self._connection == None or self._connection.isClosed():
|
435
|
+
raise InterfaceError("Connection not open")
|
436
|
+
|
437
|
+
exec_switcher = {
|
438
|
+
StatementType.QUERY: self._execute_query,
|
439
|
+
StatementType.CALL: self._execute_update,
|
440
|
+
StatementType.UPDATE: self._execute_update,
|
441
|
+
StatementType.DDL_OTHER: self._execute_update,
|
442
|
+
StatementType.DDL_ALTER_DROP: self._execute_update
|
443
|
+
}
|
444
|
+
exec_func = exec_switcher.get(self._statementType, None)
|
445
|
+
if exec_func is None:
|
446
|
+
raise NotImplementedErrorDBAPI(f'StatementType {self._statementType.name} not implemented')
|
447
|
+
else:
|
448
|
+
return exec_func()
|
449
|
+
|
450
|
+
def _prepare_stored_procedure(self):
|
451
|
+
if self._get_cached_info():
|
452
|
+
self._prepared_stored_procedure_execute()
|
453
|
+
pass
|
454
|
+
|
455
|
+
def _execute_stored_procedure(self):
|
456
|
+
if self._cursor_type == CursorType.DEFAULT:
|
457
|
+
if self._get_cached_info():
|
458
|
+
# found in client side cache - send SQ message
|
459
|
+
self._stored_procedure_update()
|
460
|
+
else:
|
461
|
+
# not found in client side cache - send DS message
|
462
|
+
self._send_direct_stored_procedure_request()
|
463
|
+
else:
|
464
|
+
self._stored_procedure_update()
|
465
|
+
|
466
|
+
def _execute_query(self):
|
467
|
+
self._fetch_done = False
|
468
|
+
if self._cursor_type == CursorType.DEFAULT:
|
469
|
+
if self._statementType not in [StatementType.QUERY, StatementType.CALL, StatementType.CALLWITHRESULT]:
|
470
|
+
raise Exception("Not a query")
|
471
|
+
|
472
|
+
if self._exec_params != None:
|
473
|
+
self._prepare_stored_procedure()
|
474
|
+
self._bind_exec_params()
|
475
|
+
if self._statementType in [StatementType.DIRECT_CALL_UPDATE, StatementType.PREPARED_CALL_UPDATE]:
|
476
|
+
raise Exception("Not a query")
|
477
|
+
elif self._statementType in [StatementType.DIRECT_CALL_QUERY, StatementType.PREPARED_CALL_QUERY]:
|
478
|
+
self._stored_procedure_query()
|
479
|
+
return
|
480
|
+
|
481
|
+
self._validate_parameters()
|
482
|
+
|
483
|
+
if self._statementType in [StatementType.CALL, StatementType.CALLWITHRESULT]:
|
484
|
+
self._execute_stored_procedure()
|
485
|
+
if not (self._statementType in [StatementType.DIRECT_CALL_QUERY, StatementType.PREPARED_CALL_QUERY]):
|
486
|
+
raise Exception("Not a query")
|
487
|
+
return
|
488
|
+
|
489
|
+
if self._get_cached_info():
|
490
|
+
# found in client side cache - send PQ message
|
491
|
+
self._prepared_query_execute()
|
492
|
+
else:
|
493
|
+
# not found in client side cache - send DQ message
|
494
|
+
self._send_direct_query_request()
|
495
|
+
else:
|
496
|
+
if (self._statementType != StatementType.QUERY and
|
497
|
+
self._statementType != StatementType.PREPARED_CALL_QUERY and
|
498
|
+
self._statementType != StatementType.DIRECT_CALL_QUERY):
|
499
|
+
raise Exception("Not a query")
|
500
|
+
|
501
|
+
if self._exec_params != None:
|
502
|
+
self._bind_exec_params()
|
503
|
+
self._validate_prepared_parameters()
|
504
|
+
|
505
|
+
if self.statementFeatureOption & Feature.optionFastSelect == Feature.optionFastSelect:
|
506
|
+
self._rsrow = _ResultSetRow(self._connection, self._columns, self.maxRowItemCount)
|
507
|
+
else:
|
508
|
+
self._rsrow = _ResultSetRow(self._connection, self._columns, 0)
|
509
|
+
|
510
|
+
if self._cursor_type == CursorType.CALLABLE or self._statementType == StatementType.PREPARED_CALL_QUERY:
|
511
|
+
self._stored_procedure_query()
|
512
|
+
return
|
513
|
+
self._prepared_query_execute()
|
514
|
+
|
515
|
+
def _execute_update(self):
|
516
|
+
if self._cursor_type == CursorType.DEFAULT:
|
517
|
+
if self._statementType == StatementType.QUERY:
|
518
|
+
raise Exception("Not an update")
|
519
|
+
|
520
|
+
if self._exec_params != None:
|
521
|
+
self._prepare_stored_procedure()
|
522
|
+
self._bind_exec_params()
|
523
|
+
if self._statementType in [StatementType.DIRECT_CALL_UPDATE, StatementType.PREPARED_CALL_UPDATE]:
|
524
|
+
self._stored_procedure_query()
|
525
|
+
elif self._statementType in [StatementType.DIRECT_CALL_QUERY, StatementType.PREPARED_CALL_QUERY]:
|
526
|
+
raise Exception("Not an update")
|
527
|
+
return
|
528
|
+
|
529
|
+
self._validate_parameters()
|
530
|
+
|
531
|
+
if self._statementType == StatementType.CALL:
|
532
|
+
self._execute_stored_procedure()
|
533
|
+
if self._statementType == StatementType.DIRECT_CALL_QUERY:
|
534
|
+
raise Exception("Not an update")
|
535
|
+
return
|
536
|
+
|
537
|
+
notDDL = bool(self._statementType != StatementType.DDL_ALTER_DROP
|
538
|
+
and self._statementType != StatementType.DDL_OTHER)
|
539
|
+
|
540
|
+
if notDDL and self._get_cached_info():
|
541
|
+
# found in client side cache - send PU message
|
542
|
+
self._prepared_update_execute()
|
543
|
+
else:
|
544
|
+
# not found in client side cache - send DU message
|
545
|
+
self._send_direct_update_request()
|
546
|
+
else:
|
547
|
+
if self._statementType == StatementType.QUERY or self._statementType == StatementType.PREPARED_CALL_QUERY:
|
548
|
+
raise Exception("Not an update")
|
549
|
+
|
550
|
+
if self._exec_params != None:
|
551
|
+
self._bind_exec_params()
|
552
|
+
self._validate_prepared_parameters()
|
553
|
+
|
554
|
+
if (self._cursor_type == CursorType.CALLABLE or
|
555
|
+
self._statementType == StatementType.PREPARED_CALL_UPDATE or
|
556
|
+
self._statementType == StatementType.DIRECT_CALL_UPDATE):
|
557
|
+
self._stored_procedure_update()
|
558
|
+
return
|
559
|
+
|
560
|
+
self._prepared_update_execute()
|
561
|
+
|
562
|
+
def _query404(self):
|
563
|
+
with self._connection._lock:
|
564
|
+
self._validate_parameters()
|
565
|
+
self._send_direct_query_request()
|
566
|
+
|
567
|
+
def _update404(self):
|
568
|
+
with self._connection._lock:
|
569
|
+
self._validate_parameters()
|
570
|
+
self._send_direct_update_request()
|
571
|
+
|
572
|
+
# api properties and methods
|
573
|
+
@property
|
574
|
+
def description(self):
|
575
|
+
if self._columns == None:
|
576
|
+
return None
|
577
|
+
|
578
|
+
Column = namedtuple("Column", [
|
579
|
+
'name',
|
580
|
+
'type_code',
|
581
|
+
'display_size',
|
582
|
+
'internal_size',
|
583
|
+
'precision',
|
584
|
+
'scale',
|
585
|
+
'null_ok',
|
586
|
+
])
|
587
|
+
|
588
|
+
sequence = []
|
589
|
+
for column in self._columns: sequence.append(Column(
|
590
|
+
column.name,
|
591
|
+
column.type,
|
592
|
+
None,
|
593
|
+
None,
|
594
|
+
column.precision,
|
595
|
+
column.scale,
|
596
|
+
column.nullable,
|
597
|
+
))
|
598
|
+
return tuple(sequence)
|
599
|
+
|
600
|
+
# currently doesn't work for queries
|
601
|
+
@property
|
602
|
+
def rowcount(self):
|
603
|
+
return self._rowcount
|
604
|
+
|
605
|
+
# Cursor class
|
606
|
+
class Cursor(_BaseCursor):
|
607
|
+
def __init__(self, connection):
|
608
|
+
super().__init__(connection)
|
609
|
+
|
610
|
+
self._columns = None
|
611
|
+
self._rowcount = -1
|
612
|
+
self.arraysize = 1
|
613
|
+
|
614
|
+
self._in_message = intersystems_iris._InStream._InStream(connection)
|
615
|
+
self._out_message = intersystems_iris._OutStream._OutStream(connection)
|
616
|
+
self.statementFeatureOption = 0
|
617
|
+
|
618
|
+
self._result_set = None
|
619
|
+
|
620
|
+
self._rsrow = None
|
621
|
+
self._rownumber = 0
|
622
|
+
self._cursor_ptr = 0
|
623
|
+
self._scroll_flag = False
|
624
|
+
self._warehouse = list()
|
625
|
+
|
626
|
+
self._warehouse_dict = dict()
|
627
|
+
self._last_row_in_warehouse_dict = -1
|
628
|
+
self._warehouse_dict_keys = list()
|
629
|
+
|
630
|
+
self.maxRowItemCount = 0
|
631
|
+
|
632
|
+
self._parameter_sets = 0
|
633
|
+
self._exec_params = None
|
634
|
+
self._params = intersystems_iris.dbapi._ParameterCollection._ParameterCollection()
|
635
|
+
self._is_batch_update = False
|
636
|
+
|
637
|
+
self._exec_params = None
|
638
|
+
self._multiple_result_sets = False
|
639
|
+
self._mrs_done = False
|
640
|
+
self._has_return_value = 0
|
641
|
+
self._cursor_type = 0
|
642
|
+
self._parameter_list_mismatch_exception = False
|
643
|
+
self._fetch_done = False
|
644
|
+
self._output_parameter_list = None
|
645
|
+
|
646
|
+
self._lastrowid = None
|
647
|
+
|
648
|
+
self._closed = False
|
649
|
+
|
650
|
+
def _get_cached_info(self):
|
651
|
+
if not self._connection._preparedCache or not hasattr(self._connection._preparedCache, '__iter__'):
|
652
|
+
return False
|
653
|
+
if self._parsed_statement in self._connection._preparedCache:
|
654
|
+
self._prepare_cached(self._connection._preparedCache[self._parsed_statement])
|
655
|
+
return True
|
656
|
+
else:
|
657
|
+
return False
|
658
|
+
|
659
|
+
def _prepare_cached(self, cached_statement):
|
660
|
+
self._statement_id = cached_statement.statement_id
|
661
|
+
|
662
|
+
if self._statementType == StatementType.CALL or self._statementType == StatementType.CALLWITHRESULT:
|
663
|
+
if len(self._params._params_list) != len(cached_statement._params._params_list):
|
664
|
+
if (self._statementType == StatementType.CALL and
|
665
|
+
self._has_return_value == 0 and
|
666
|
+
cached_statement._has_return_value == 1 and
|
667
|
+
len(self._params._params_list) + 1 == len(cached_statement._params._params_list)):
|
668
|
+
self._params._params_list.insert(0, intersystems_iris.dbapi._Parameter._Parameter(None, ParameterMode.OUTPUT, 'c'))
|
669
|
+
else:
|
670
|
+
if len(self._params._params_list) == 0 or len(self._params._params_list) == 1:
|
671
|
+
self._params._clear()
|
672
|
+
else:
|
673
|
+
return False
|
674
|
+
|
675
|
+
if cached_statement._statementType == StatementType.QUERY:
|
676
|
+
self._statementType = StatementType.PREPARED_CALL_QUERY
|
677
|
+
else:
|
678
|
+
if cached_statement._statementType == StatementType.UPDATE:
|
679
|
+
self._statementType = StatementType.PREPARED_CALL_UPDATE
|
680
|
+
else:
|
681
|
+
self._statementType = cached_statement._statementType
|
682
|
+
|
683
|
+
self._has_return_value = cached_statement._has_return_value
|
684
|
+
self._multiple_result_sets = cached_statement.multiple_result_sets
|
685
|
+
self._mrs_done = False
|
686
|
+
|
687
|
+
if (not self._multiple_result_sets and
|
688
|
+
(self._statementType in [StatementType.QUERY, StatementType.PREPARED_CALL_QUERY, StatementType.DIRECT_CALL_QUERY])):
|
689
|
+
self._columns = []
|
690
|
+
for column in cached_statement.columns:
|
691
|
+
self._columns.append(column.Clone())
|
692
|
+
|
693
|
+
if self.statementFeatureOption & Feature.optionFastSelect == Feature.optionFastSelect:
|
694
|
+
self._rsrow = _ResultSetRow(self._connection, self._columns, cached_statement.maxRowItemCount)
|
695
|
+
else:
|
696
|
+
self._rsrow = _ResultSetRow(self._connection, self._columns, 0)
|
697
|
+
|
698
|
+
else:
|
699
|
+
if self._statementType == StatementType.QUERY:
|
700
|
+
self._columns = []
|
701
|
+
for column in cached_statement.columns:
|
702
|
+
self._columns.append(column.Clone())
|
703
|
+
|
704
|
+
if self.statementFeatureOption & Feature.optionFastSelect == Feature.optionFastSelect:
|
705
|
+
self._rsrow = _ResultSetRow(self._connection, self._columns, cached_statement.maxRowItemCount)
|
706
|
+
else:
|
707
|
+
self._rsrow = _ResultSetRow(self._connection, self._columns, 0)
|
708
|
+
|
709
|
+
if hasattr(cached_statement, "statementFeatureOption"):
|
710
|
+
self.statementFeatureOption = cached_statement.statementFeatureOption
|
711
|
+
if hasattr(cached_statement, "maxRowItemCount"):
|
712
|
+
self.maxRowItemCount = cached_statement.maxRowItemCount
|
713
|
+
if hasattr(cached_statement, "_params"):
|
714
|
+
self._params._update_param_info(cached_statement._params)
|
715
|
+
|
716
|
+
def _prepare_new(self):
|
717
|
+
# send PP message
|
718
|
+
with self._connection._lock:
|
719
|
+
# message header
|
720
|
+
self._statement_id = self._connection._get_new_statement_id()
|
721
|
+
self._out_message.wire._write_header(_Message.PREPARE)
|
722
|
+
intersystems_iris._MessageHeader._MessageHeader._set_statement_id(self._out_message.wire.buffer, self._statement_id)
|
723
|
+
|
724
|
+
# message body
|
725
|
+
self._out_message.wire._set(1) # number of statement chunks
|
726
|
+
self._out_message.wire._set(self._parsed_statement) # statement itself
|
727
|
+
self._out_message.wire._set_raw_bytes(self._paramInfo.getBuffer()) # paramInfo (from _PreParser)
|
728
|
+
|
729
|
+
# send message
|
730
|
+
sequence_number = self._connection._get_new_sequence_number()
|
731
|
+
self._out_message._send(sequence_number)
|
732
|
+
|
733
|
+
# retrieve response
|
734
|
+
self._in_message._read_message_sql(sequence_number, self._statement_id, 0, [0])
|
735
|
+
sqlcode = self._in_message.wire.header._get_function_code()
|
736
|
+
if sqlcode not in [0, 100]:
|
737
|
+
raise InterfaceError(self._get_error_info(sqlcode))
|
738
|
+
|
739
|
+
# process metadata
|
740
|
+
try:
|
741
|
+
if self._connection._isFastOption():
|
742
|
+
self._check_statement_feature(self._in_message.wire)
|
743
|
+
else:
|
744
|
+
self.statementFeatureOption = Feature.optionNone
|
745
|
+
|
746
|
+
if self._statementType == StatementType.QUERY:
|
747
|
+
self._get_column_info(self._in_message.wire)
|
748
|
+
else:
|
749
|
+
self._columns = None
|
750
|
+
|
751
|
+
addToCache = self._get_parameter_info(self._in_message.wire)
|
752
|
+
if addToCache:
|
753
|
+
self._cache_prepared_statement()
|
754
|
+
except IndexError:
|
755
|
+
raise DatabaseError("Server response message terminated prematurely")
|
756
|
+
except TypeError:
|
757
|
+
raise DatabaseError("Unexpected server response message format")
|
758
|
+
|
759
|
+
def _get_error_info(self, sqlcode):
|
760
|
+
with self._connection._lock:
|
761
|
+
self._out_message.wire._write_header(_Message.GET_SERVER_ERROR)
|
762
|
+
self._out_message.wire._set(sqlcode)
|
763
|
+
|
764
|
+
sequence_number = self._connection._get_new_sequence_number()
|
765
|
+
self._out_message._send(sequence_number)
|
766
|
+
|
767
|
+
self._in_message._read_message_sql(sequence_number)
|
768
|
+
return self._in_message.wire._get()
|
769
|
+
|
770
|
+
def _check_statement_feature(self, wire):
|
771
|
+
self.statementFeatureOption = wire._get()
|
772
|
+
if self.statementFeatureOption == Feature.optionFastSelect or self.statementFeatureOption == Feature.optionFastInsert:
|
773
|
+
self.maxRowItemCount = wire._get()
|
774
|
+
else:
|
775
|
+
self.maxRowItemCount = 0
|
776
|
+
|
777
|
+
def _get_column_info(self, wire):
|
778
|
+
self._columns = []
|
779
|
+
count = wire._get()
|
780
|
+
for i in range(count):
|
781
|
+
name = wire._get()
|
782
|
+
type = wire._get()
|
783
|
+
precision = wire._get()
|
784
|
+
scale = wire._get()
|
785
|
+
nullable = wire._get()
|
786
|
+
label = wire._get()
|
787
|
+
tableName = wire._get()
|
788
|
+
schema = wire._get()
|
789
|
+
catalog = wire._get()
|
790
|
+
if catalog == 0:
|
791
|
+
catalog = None
|
792
|
+
additionalData = wire._get().encode()
|
793
|
+
slotPosition = wire._get() if self.statementFeatureOption & Feature.optionFastSelect == Feature.optionFastSelect else i + 1
|
794
|
+
self._columns.append(intersystems_iris.dbapi._Column._Column(name, type, precision, scale, nullable, label, tableName, schema, catalog, additionalData, slotPosition))
|
795
|
+
|
796
|
+
def _get_parameter_info(self, wire):
|
797
|
+
count = wire._get()
|
798
|
+
if count != len(self._params._params_list):
|
799
|
+
raise Exception("Invalid number of parameters")
|
800
|
+
self._read_parameter_data(wire, count, False)
|
801
|
+
|
802
|
+
addToCache = bool(wire._get())
|
803
|
+
return addToCache
|
804
|
+
|
805
|
+
def _read_parameter_data(self, wire, count, is_stored_procedure):
|
806
|
+
if count != len(self._params._params_list):
|
807
|
+
raise Exception("Invalid number of parameters")
|
808
|
+
with self._connection._lock:
|
809
|
+
r = 0
|
810
|
+
user_param_count = 0
|
811
|
+
if self._has_return_value == ServerReturnType.NULL_RETURN_VALUE:
|
812
|
+
r += 1
|
813
|
+
if self._has_return_value == ServerReturnType.IGNORE_RETURN_VALUE:
|
814
|
+
user_param_count -= 1
|
815
|
+
|
816
|
+
for i in range(count):
|
817
|
+
param = self._params._params_list[i + r]
|
818
|
+
param.type = wire._get()
|
819
|
+
param.precision = wire._get()
|
820
|
+
param.scale = wire._get()
|
821
|
+
param.nullable = wire._get()
|
822
|
+
|
823
|
+
if self.statementFeatureOption & Feature.optionFastInsert == Feature.optionFastInsert:
|
824
|
+
param.slotPosition = wire._get()
|
825
|
+
self.rowOfDefaultValues = wire._get() # needs to be processed
|
826
|
+
else:
|
827
|
+
param.slotPosition = i + r
|
828
|
+
|
829
|
+
if is_stored_procedure:
|
830
|
+
param.name = wire._get()
|
831
|
+
wire._get()
|
832
|
+
|
833
|
+
if is_stored_procedure:
|
834
|
+
self._params._update_names()
|
835
|
+
|
836
|
+
def _execute_update(self):
|
837
|
+
super()._execute_update()
|
838
|
+
|
839
|
+
if self._parameter_sets == 0 and not self._multiple_result_sets:
|
840
|
+
self._rowcount = self._in_message.wire._get()
|
841
|
+
|
842
|
+
|
843
|
+
class prepared_statement(intersystems_iris._IRISConnection.CachedSQL):
|
844
|
+
def __init__(self, cursor):
|
845
|
+
if not isinstance(cursor, Cursor):
|
846
|
+
raise TypeError("cursor must be a Cursor")
|
847
|
+
|
848
|
+
super().__init__(cursor)
|
849
|
+
self.statement = cursor._parsed_statement
|
850
|
+
self.statement_id = cursor._statement_id
|
851
|
+
|
852
|
+
if cursor._columns != None:
|
853
|
+
self.columns = []
|
854
|
+
for column in cursor._columns:
|
855
|
+
self.columns.append(column.Clone())
|
856
|
+
|
857
|
+
if hasattr(cursor, "statementFeatureOption"):
|
858
|
+
self.statementFeatureOption = cursor.statementFeatureOption
|
859
|
+
if hasattr(cursor, "maxRowItemCount"):
|
860
|
+
self.maxRowItemCount = cursor.maxRowItemCount
|
861
|
+
|
862
|
+
self.multiple_result_sets = cursor._multiple_result_sets
|
863
|
+
|
864
|
+
def _cache_prepared_statement(self):
|
865
|
+
self._connection._cache_prepared_statement(self.prepared_statement(self))
|
866
|
+
|
867
|
+
def _write_parameters(self):
|
868
|
+
sets = self._parameter_sets or 1
|
869
|
+
|
870
|
+
self._out_message.wire._set(sets) # nParamSets
|
871
|
+
self._out_message.wire._set(len(self._params._params_list)) # nParams
|
872
|
+
for i in range(sets):
|
873
|
+
param_index = 0
|
874
|
+
param_counter = i
|
875
|
+
for param in self._params._params_list:
|
876
|
+
mode = param.mode
|
877
|
+
if mode == ParameterMode.REPLACED_LITERAL:
|
878
|
+
self._out_message.wire._set_parameter(param)
|
879
|
+
elif not mode == ParameterMode.INPUT:
|
880
|
+
temp_param = intersystems_iris.dbapi._Parameter._Parameter(param._values[i])
|
881
|
+
self._out_message.wire._set_parameter(temp_param)
|
882
|
+
elif len(self.params) > 0:
|
883
|
+
item = self.params[param_counter]
|
884
|
+
if isinstance(item, list) or isinstance(item, tuple):
|
885
|
+
value = item[param_index]
|
886
|
+
param_index = param_index + 1
|
887
|
+
else:
|
888
|
+
value = item
|
889
|
+
param_counter = param_counter + 1
|
890
|
+
temp_param = intersystems_iris.dbapi._Parameter._Parameter(value)
|
891
|
+
self._out_message.wire._set_parameter(temp_param)
|
892
|
+
else:
|
893
|
+
raise Exception("Missing value")
|
894
|
+
|
895
|
+
def _prepared_query_execute(self):
|
896
|
+
# send PQ message
|
897
|
+
with self._connection._lock:
|
898
|
+
# message header
|
899
|
+
self._out_message.wire._write_header(_Message.PREPARED_QUERY_EXECUTE)
|
900
|
+
intersystems_iris._MessageHeader._MessageHeader._set_statement_id(self._out_message.wire.buffer, self._statement_id)
|
901
|
+
|
902
|
+
# message body
|
903
|
+
self._write_parameters()
|
904
|
+
self._out_message.wire._set(0) # query timeout
|
905
|
+
self._out_message.wire._set(0) # maxRows (0 = all rows)
|
906
|
+
|
907
|
+
# send
|
908
|
+
sequence_number = self._connection._get_new_sequence_number()
|
909
|
+
self._out_message._send(sequence_number)
|
910
|
+
|
911
|
+
# retrieve response
|
912
|
+
self._in_message._read_message_sql(sequence_number, self._statement_id, _InStream.FETCH_DATA, [404, 100])
|
913
|
+
self._sqlcode = self._in_message.wire.header._get_function_code()
|
914
|
+
self._handle_error_504(self._sqlcode)
|
915
|
+
if self._sqlcode == 404:
|
916
|
+
return
|
917
|
+
if self._sqlcode not in [0, 100]:
|
918
|
+
raise InterfaceError(self._get_error_info(self._sqlcode))
|
919
|
+
|
920
|
+
self._current_wire = self._in_message.wire
|
921
|
+
self._result_set = [self._current_wire]
|
922
|
+
self._rs_index = 0
|
923
|
+
|
924
|
+
self._rowcount = -1
|
925
|
+
|
926
|
+
def _send_direct_stored_procedure_request(self):
|
927
|
+
# self._has_return_value = ServerReturnType.NO_RETURN_VALUE
|
928
|
+
# send DS message
|
929
|
+
with self._connection._lock:
|
930
|
+
# message header
|
931
|
+
self._statement_id = self._connection._get_new_statement_id()
|
932
|
+
self._out_message.wire._write_header(_Message.DIRECT_STORED_PROCEDURE)
|
933
|
+
intersystems_iris._MessageHeader._MessageHeader._set_statement_id(self._out_message.wire.buffer, self._statement_id)
|
934
|
+
|
935
|
+
# message body
|
936
|
+
self._out_message.wire._set(self._parsed_statement) # statement itself
|
937
|
+
self._out_message.wire._set(0) # resultSetType != ResultSet.TYPE_SCROLL_INSENSITIVE
|
938
|
+
self._out_message.wire._set(0) # query timeout
|
939
|
+
self._out_message.wire._set(0) # maxRows (0 = all rows)
|
940
|
+
self._write_stored_procedure_parameters()
|
941
|
+
|
942
|
+
# send
|
943
|
+
sequence_number = self._connection._get_new_sequence_number()
|
944
|
+
self._out_message._send(sequence_number)
|
945
|
+
|
946
|
+
try:
|
947
|
+
# retrieve metadata
|
948
|
+
self._in_message._read_message_sql(sequence_number, self._statement_id, 0, [100])
|
949
|
+
sqlcode = self._in_message.wire.header._get_function_code()
|
950
|
+
if sqlcode not in [0, 100]:
|
951
|
+
raise InterfaceError(self._get_error_info(sqlcode))
|
952
|
+
|
953
|
+
self._process_stored_procedure_metadata(self._in_message.wire, True)
|
954
|
+
if self._multiple_result_sets:
|
955
|
+
# todo
|
956
|
+
return
|
957
|
+
|
958
|
+
self._cache_prepared_statement()
|
959
|
+
|
960
|
+
if self._statementType in [StatementType.UPDATE, StatementType.DIRECT_CALL_UPDATE, StatementType.PREPARED_CALL_UPDATE]:
|
961
|
+
return False
|
962
|
+
|
963
|
+
except IndexError:
|
964
|
+
raise DatabaseError("Server response message terminated prematurely")
|
965
|
+
except TypeError:
|
966
|
+
raise DatabaseError("Unexpected server response message format")
|
967
|
+
|
968
|
+
def _prepared_stored_procedure_execute(self):
|
969
|
+
# send SU message
|
970
|
+
with self._connection._lock:
|
971
|
+
# message header
|
972
|
+
self._out_message.wire._write_header(_Message.PREPARED_UPDATE_EXECUTE)
|
973
|
+
intersystems_iris._MessageHeader._MessageHeader._set_statement_id(self._out_message.wire.buffer, self._statement_id)
|
974
|
+
|
975
|
+
|
976
|
+
def _send_direct_query_request(self):
|
977
|
+
# send DQ message
|
978
|
+
with self._connection._lock:
|
979
|
+
# message header
|
980
|
+
self._statement_id = self._connection._get_new_statement_id()
|
981
|
+
self._out_message.wire._write_header(_Message.DIRECT_QUERY)
|
982
|
+
intersystems_iris._MessageHeader._MessageHeader._set_statement_id(self._out_message.wire.buffer, self._statement_id)
|
983
|
+
|
984
|
+
# message body
|
985
|
+
self._out_message.wire._set(1) # number of statement chunks
|
986
|
+
self._out_message.wire._set(self._parsed_statement) # statement itself
|
987
|
+
self._out_message.wire._set_raw_bytes(self._paramInfo.getBuffer()) # paramInfo (from _PreParser)
|
988
|
+
self._write_parameters()
|
989
|
+
self._out_message.wire._set(0) # query timeout
|
990
|
+
self._out_message.wire._set(0) # maxRows (0 = all rows)
|
991
|
+
|
992
|
+
# send
|
993
|
+
sequence_number = self._connection._get_new_sequence_number()
|
994
|
+
self._out_message._send(sequence_number)
|
995
|
+
|
996
|
+
try:
|
997
|
+
# retrieve metadata
|
998
|
+
self._in_message._read_message_sql(sequence_number, self._statement_id, 0, [100])
|
999
|
+
sqlcode = self._in_message.wire.header._get_function_code()
|
1000
|
+
if sqlcode not in [0, 100]:
|
1001
|
+
raise InterfaceError(self._get_error_info(sqlcode))
|
1002
|
+
|
1003
|
+
if self._connection._isFastOption():
|
1004
|
+
self._check_statement_feature(self._in_message.wire)
|
1005
|
+
else:
|
1006
|
+
self.statementFeatureOption = Feature.optionNone
|
1007
|
+
self._get_column_info(self._in_message.wire)
|
1008
|
+
self._get_parameter_info(self._in_message.wire)
|
1009
|
+
self._cache_prepared_statement()
|
1010
|
+
|
1011
|
+
# retrieve data
|
1012
|
+
self._in_message._read_message_sql(sequence_number, self._statement_id, _InStream.FETCH_DATA, [100])
|
1013
|
+
self._sqlcode = self._in_message.wire.header._get_function_code()
|
1014
|
+
if self._sqlcode not in [0, 100]:
|
1015
|
+
raise InterfaceError(self._get_error_info(self._sqlcode))
|
1016
|
+
|
1017
|
+
except IndexError:
|
1018
|
+
raise DatabaseError("Server response message terminated prematurely")
|
1019
|
+
except TypeError:
|
1020
|
+
raise DatabaseError("Unexpected server response message format")
|
1021
|
+
|
1022
|
+
self._current_wire = self._in_message.wire
|
1023
|
+
self._result_set = [self._current_wire]
|
1024
|
+
self._rs_index = 0
|
1025
|
+
|
1026
|
+
self._rowcount = -1
|
1027
|
+
if self.statementFeatureOption & Feature.optionFastSelect == Feature.optionFastSelect:
|
1028
|
+
self._rsrow = _ResultSetRow(self._connection, self._columns, self.maxRowItemCount)
|
1029
|
+
else:
|
1030
|
+
self._rsrow = _ResultSetRow(self._connection, self._columns, 0)
|
1031
|
+
|
1032
|
+
def _prepared_update_execute(self):
|
1033
|
+
# send PU message
|
1034
|
+
with self._connection._lock:
|
1035
|
+
# message header
|
1036
|
+
self._out_message.wire._write_header(_Message.PREPARED_UPDATE_EXECUTE)
|
1037
|
+
intersystems_iris._MessageHeader._MessageHeader._set_statement_id(self._out_message.wire.buffer, self._statement_id)
|
1038
|
+
|
1039
|
+
# message body
|
1040
|
+
self._lastrowid = None
|
1041
|
+
self._out_message.wire._set(-1) # autoGeneratedKeyColumn
|
1042
|
+
self._out_message.wire._set(0) # statement timeout always 0 for non-queries
|
1043
|
+
self._write_parameters()
|
1044
|
+
|
1045
|
+
# send
|
1046
|
+
sequence_number = self._connection._get_new_sequence_number()
|
1047
|
+
self._out_message._send(sequence_number)
|
1048
|
+
|
1049
|
+
# retrieve response
|
1050
|
+
self._in_message._read_message_sql(sequence_number, self._statement_id, 0, [404, 100])
|
1051
|
+
sqlcode = self._in_message.wire.header._get_function_code()
|
1052
|
+
if sqlcode == 404:
|
1053
|
+
self._update404()
|
1054
|
+
return
|
1055
|
+
if sqlcode == 119:
|
1056
|
+
raise IntegrityError(self._get_error_info(sqlcode))
|
1057
|
+
if sqlcode not in [0, 100]:
|
1058
|
+
raise InterfaceError(self._get_error_info(sqlcode))
|
1059
|
+
|
1060
|
+
def _send_direct_update_request(self):
|
1061
|
+
# send DU message
|
1062
|
+
with self._connection._lock:
|
1063
|
+
self._statement_id = self._connection._get_new_statement_id()
|
1064
|
+
# message header
|
1065
|
+
self._out_message.wire._write_header(_Message.DIRECT_UPDATE)
|
1066
|
+
intersystems_iris._MessageHeader._MessageHeader._set_statement_id(self._out_message.wire.buffer, self._statement_id)
|
1067
|
+
|
1068
|
+
# message body
|
1069
|
+
self._lastrowid = None
|
1070
|
+
self._out_message.wire._set(1) # number of statement chunks
|
1071
|
+
self._out_message.wire._set(self._parsed_statement) # statement itself
|
1072
|
+
self._out_message.wire._set_raw_bytes(self._paramInfo.getBuffer()) # paramInfo (from _PreParser)
|
1073
|
+
self._out_message.wire._set(-1) # autoGeneratedKeyColumn
|
1074
|
+
self._out_message.wire._set(0) # statement timeout always 0 for non-queries
|
1075
|
+
self._write_parameters()
|
1076
|
+
|
1077
|
+
# send
|
1078
|
+
sequence_number = self._connection._get_new_sequence_number()
|
1079
|
+
self._out_message._send(sequence_number)
|
1080
|
+
|
1081
|
+
try:
|
1082
|
+
# retrieve response
|
1083
|
+
self._in_message._read_message_sql(sequence_number, self._statement_id, 0, [100])
|
1084
|
+
self._sqlcode = self._in_message.wire.header._get_function_code()
|
1085
|
+
if self._sqlcode not in [0, 100]:
|
1086
|
+
raise InterfaceError(self._get_error_info(self._sqlcode))
|
1087
|
+
|
1088
|
+
addToCache = self._get_parameter_info(self._in_message.wire)
|
1089
|
+
|
1090
|
+
notDDL = bool(self._statementType != StatementType.DDL_ALTER_DROP
|
1091
|
+
and self._statementType != StatementType.DDL_OTHER)
|
1092
|
+
if notDDL and addToCache:
|
1093
|
+
self._cache_prepared_statement()
|
1094
|
+
|
1095
|
+
except IndexError:
|
1096
|
+
raise DatabaseError("Server response message terminated prematurely")
|
1097
|
+
except TypeError:
|
1098
|
+
raise DatabaseError("Unexpected server response message format")
|
1099
|
+
|
1100
|
+
def _prepare_stored_procedure(self):
|
1101
|
+
with self._connection._lock:
|
1102
|
+
# message header
|
1103
|
+
self._statement_id = self._connection._get_new_statement_id()
|
1104
|
+
self._out_message.wire._write_header(_Message.PREPARE_STORED_PROCEDURE)
|
1105
|
+
intersystems_iris._MessageHeader._MessageHeader._set_statement_id(self._out_message.wire.buffer, self._statement_id)
|
1106
|
+
|
1107
|
+
# message body
|
1108
|
+
#self._out_message.wire._set(1) # number of statement chunks
|
1109
|
+
self._out_message.wire._set(self._parsed_statement) # statement itself
|
1110
|
+
|
1111
|
+
# send message
|
1112
|
+
sequence_number = self._connection._get_new_sequence_number()
|
1113
|
+
self._out_message._send(sequence_number)
|
1114
|
+
|
1115
|
+
# retrieve response
|
1116
|
+
self._in_message._read_message_sql(sequence_number, self._statement_id, 0, [0])
|
1117
|
+
self._sqlcode = self._in_message.wire.header._get_function_code()
|
1118
|
+
if self._sqlcode not in [0, 100]:
|
1119
|
+
raise InterfaceError(self._get_error_info(self._sqlcode))
|
1120
|
+
|
1121
|
+
self._process_stored_procedure_metadata(self._in_message.wire, False)
|
1122
|
+
if self._multiple_result_sets:
|
1123
|
+
return
|
1124
|
+
self._cache_prepared_statement()
|
1125
|
+
return
|
1126
|
+
|
1127
|
+
def _process_stored_procedure_metadata(self, wire, direct_execute):
|
1128
|
+
ret_stmt_type = wire._get()
|
1129
|
+
if ret_stmt_type < 0:
|
1130
|
+
if ret_stmt_type == -1:
|
1131
|
+
self._multiple_result_sets_metadata(wire, False, direct_execute)
|
1132
|
+
else:
|
1133
|
+
self._multiple_result_sets_metadata(wire, True, direct_execute)
|
1134
|
+
return
|
1135
|
+
if ret_stmt_type % 2 == StatementType.QUERY.value:
|
1136
|
+
self._get_column_info(wire)
|
1137
|
+
if not self._stored_procedure_parameter_info(wire, ret_stmt_type > 1, direct_execute):
|
1138
|
+
if direct_execute and ret_stmt_type % 2 == StatementType.QUERY.value:
|
1139
|
+
# result set type check
|
1140
|
+
self._in_message.wire._move_to_end()
|
1141
|
+
if direct_execute:
|
1142
|
+
raise Exception("Parameter list mismatch")
|
1143
|
+
if direct_execute and self._parameter_list_mismatch_exception:
|
1144
|
+
raise Exception("Parameter list mismatch")
|
1145
|
+
if self._cursor_type == CursorType.CALLABLE:
|
1146
|
+
self._statementType = StatementType(ret_stmt_type % 2)
|
1147
|
+
return
|
1148
|
+
if self._cursor_type == CursorType.PREPARED:
|
1149
|
+
if ret_stmt_type % 2 == StatementType.QUERY.value:
|
1150
|
+
self._statementType = StatementType.PREPARED_CALL_QUERY
|
1151
|
+
else:
|
1152
|
+
self._statementType = StatementType.PREPARED_CALL_UPDATE
|
1153
|
+
return
|
1154
|
+
if ret_stmt_type % 2 == StatementType.QUERY.value:
|
1155
|
+
self._statementType = StatementType.DIRECT_CALL_QUERY
|
1156
|
+
else:
|
1157
|
+
self._statementType = StatementType.DIRECT_CALL_UPDATE
|
1158
|
+
return
|
1159
|
+
|
1160
|
+
def _multiple_result_sets_metadata(self, wire, server_has_return, direct_execute):
|
1161
|
+
self._multiple_result_sets = True
|
1162
|
+
self._mrs_done = False
|
1163
|
+
if not self._stored_procedure_parameter_info(wire, server_has_return, direct_execute):
|
1164
|
+
raise Exception("Parameter list mismatch")
|
1165
|
+
|
1166
|
+
if self._cursor_type == CursorType.CALLABLE:
|
1167
|
+
self._statementType = StatementType.QUERY
|
1168
|
+
elif self._cursor_type == CursorType.PREPARED:
|
1169
|
+
self._statementType = StatementType.PREPARED_CALL_QUERY
|
1170
|
+
else:
|
1171
|
+
self._statementType = StatementType.DIRECT_CALL_QUERY
|
1172
|
+
|
1173
|
+
def _stored_procedure_parameter_info(self, wire, server_has_return, direct_execute):
|
1174
|
+
count = wire._get()
|
1175
|
+
size = len(self._params._params_list)
|
1176
|
+
if self._cursor_type != CursorType.CALLABLE and self._has_return_value == 1:
|
1177
|
+
wire._move_to_end()
|
1178
|
+
return False
|
1179
|
+
if self._exec_params != None:
|
1180
|
+
while size < count:
|
1181
|
+
self._params._params_list.insert(0, intersystems_iris.dbapi._Parameter._Parameter())
|
1182
|
+
size = size + 1
|
1183
|
+
if server_has_return:
|
1184
|
+
self._has_return_value = ServerReturnType.IGNORE_RETURN_VALUE
|
1185
|
+
elif size == count:
|
1186
|
+
if server_has_return and self._has_return_value == ServerReturnType.HAS_RETURN_VALUE:
|
1187
|
+
self._has_return_value = ServerReturnType.HAS_RETURN_VALUE
|
1188
|
+
elif not server_has_return and self._has_return_value == ServerReturnType.NO_RETURN_VALUE:
|
1189
|
+
self._has_return_value = ServerReturnType.NO_RETURN_VALUE
|
1190
|
+
elif (size == 1 and count == 1
|
1191
|
+
and (self._params._params_list[0].mode == ParameterMode.DEFAULT_PARAMETER
|
1192
|
+
and self._has_return_value == ServerReturnType.NO_RETURN_VALUE and server_has_return)
|
1193
|
+
or (self._params._params_list[0].mode == ParameterMode.UNKNOWN
|
1194
|
+
and self._has_return_value == ServerReturnType.IGNORE_RETURN_VALUE and server_has_return)):
|
1195
|
+
self._params._params_list.pop(0)
|
1196
|
+
self._params._params_list.insert(0, intersystems_iris.dbapi._Parameter._Parameter())
|
1197
|
+
self._has_return_value = ServerReturnType.IGNORE_RETURN_VALUE
|
1198
|
+
else:
|
1199
|
+
wire._move_to_end()
|
1200
|
+
return False
|
1201
|
+
elif size == count + 1:
|
1202
|
+
if not server_has_return and self._has_return_value == ServerReturnType.HAS_RETURN_VALUE:
|
1203
|
+
self._has_return_value = ServerReturnType.NULL_RETURN_VALUE
|
1204
|
+
elif (size == 2 and count == 1) or (size == 1 and count == 0):
|
1205
|
+
if self._params._params_list[-1].mode == ParameterMode.DEFAULT_PARAMETER:
|
1206
|
+
if server_has_return and self._has_return_value == ServerReturnType.HAS_RETURN_VALUE:
|
1207
|
+
self._params._params_list.pop(-1)
|
1208
|
+
self._has_return_value = ServerReturnType.HAS_RETURN_VALUE
|
1209
|
+
elif not server_has_return and self._has_return_value == ServerReturnType.NO_RETURN_VALUE:
|
1210
|
+
self._params._params_list.pop(-1)
|
1211
|
+
self._has_return_value = ServerReturnType.NO_RETURN_VALUE
|
1212
|
+
else:
|
1213
|
+
wire._move_to_end()
|
1214
|
+
return False
|
1215
|
+
else:
|
1216
|
+
wire._move_to_end()
|
1217
|
+
return False
|
1218
|
+
else:
|
1219
|
+
wire._move_to_end()
|
1220
|
+
return False
|
1221
|
+
elif size == count - 1:
|
1222
|
+
if server_has_return and self._has_return_value == ServerReturnType.NO_RETURN_VALUE:
|
1223
|
+
self._params._params_list.insert(0, intersystems_iris.dbapi._Parameter._Parameter())
|
1224
|
+
self._has_return_value = ServerReturnType.IGNORE_RETURN_VALUE
|
1225
|
+
else:
|
1226
|
+
self._params._params_list.append(intersystems_iris.dbapi._Parameter._Parameter(ParameterMode.DEFAULT_PARAMETER, 'c'))
|
1227
|
+
else:
|
1228
|
+
self._parameter_list_mismatch_exception = True
|
1229
|
+
if server_has_return and self._has_return_value == ServerReturnType.NO_RETURN_VALUE:
|
1230
|
+
self._has_return_value = ServerReturnType.IGNORE_RETURN_VALUE
|
1231
|
+
param = intersystems_iris.dbapi._Parameter._Parameter()
|
1232
|
+
param.mode = ParameterMode.OUTPUT
|
1233
|
+
self._params._params_list.insert(0, param)
|
1234
|
+
size = size + 1
|
1235
|
+
while size < count:
|
1236
|
+
self._params._params_list.append(intersystems_iris.dbapi._Parameter._Parameter(ParameterMode.DEFAULT_PARAMETER, 'c'))
|
1237
|
+
size = size + 1
|
1238
|
+
self._read_parameter_data(wire, count, True)
|
1239
|
+
return True
|
1240
|
+
|
1241
|
+
def _bind_exec_params(self):
|
1242
|
+
for param in self._params._params_list:
|
1243
|
+
exec_param = self._get_exec_param_by_name(param.name)
|
1244
|
+
if exec_param != None:
|
1245
|
+
if exec_param.mode == ParameterMode.UNKNOWN:
|
1246
|
+
continue
|
1247
|
+
param.mode = exec_param.mode
|
1248
|
+
if exec_param.mode != ParameterMode.OUTPUT:
|
1249
|
+
if isinstance(exec_param.value, list):
|
1250
|
+
self._params._array_bound = True
|
1251
|
+
param._bind(exec_param.value, self._parameter_sets)
|
1252
|
+
else:
|
1253
|
+
param.__bound = exec_param.bound
|
1254
|
+
if exec_param.scale != -1:
|
1255
|
+
param.scale = exec_param.scale
|
1256
|
+
else:
|
1257
|
+
if param.mode == ParameterMode.UNKNOWN:
|
1258
|
+
param.mode = ParameterMode.DEFAULT_PARAMETER
|
1259
|
+
|
1260
|
+
def _get_exec_param_by_name(self, name):
|
1261
|
+
self._exec_params._has_bound_by_param_name = True
|
1262
|
+
return self._exec_params._params_list[self._exec_params._param_names.get(name.upper())]
|
1263
|
+
|
1264
|
+
def _stored_procedure_update(self):
|
1265
|
+
with self._connection._lock:
|
1266
|
+
# message header
|
1267
|
+
self._out_message.wire._write_header(_Message.STORED_PROCEDURE_UPDATE_EXECUTE)
|
1268
|
+
intersystems_iris._MessageHeader._MessageHeader._set_statement_id(self._out_message.wire.buffer, self._statement_id)
|
1269
|
+
|
1270
|
+
# message body
|
1271
|
+
self._out_message.wire._set(0) # isStatic should always be 0 for non-queries
|
1272
|
+
self._out_message.wire._set(0) # query timeout
|
1273
|
+
self._out_message.wire._set(0) # maxRows (0 = all rows)
|
1274
|
+
self._write_stored_procedure_parameters()
|
1275
|
+
|
1276
|
+
# send
|
1277
|
+
sequence_number = self._connection._get_new_sequence_number()
|
1278
|
+
self._out_message._send(sequence_number)
|
1279
|
+
|
1280
|
+
# retrieve response
|
1281
|
+
self._in_message._read_message_sql(sequence_number, self._statement_id, 0, [404, 100])
|
1282
|
+
self._sqlcode = self._in_message.wire.header._get_function_code()
|
1283
|
+
if self._sqlcode not in [0, 100,]:
|
1284
|
+
raise InterfaceError(self._get_error_info(self._sqlcode))
|
1285
|
+
if self._sqlcode == 404:
|
1286
|
+
self._update404(404)
|
1287
|
+
else:
|
1288
|
+
self._get_output_parameters(self._in_message.wire)
|
1289
|
+
return
|
1290
|
+
|
1291
|
+
def _stored_procedure_query(self):
|
1292
|
+
if self._multiple_result_sets:
|
1293
|
+
self._execute_multiple_result_sets(False)
|
1294
|
+
return
|
1295
|
+
with self._connection._lock:
|
1296
|
+
# message header
|
1297
|
+
self._out_message.wire._write_header(_Message.STORED_PROCEDURE_QUERY_EXECUTE)
|
1298
|
+
intersystems_iris._MessageHeader._MessageHeader._set_statement_id(self._out_message.wire.buffer, self._statement_id)
|
1299
|
+
|
1300
|
+
# message body
|
1301
|
+
self._out_message.wire._set(0) # ResultSet.TYPE_SCROLL_INSENSITIVE
|
1302
|
+
self._out_message.wire._set(0) # query timeout
|
1303
|
+
self._out_message.wire._set(0) # maxRows (0 = all rows)
|
1304
|
+
self._write_stored_procedure_parameters()
|
1305
|
+
|
1306
|
+
# send
|
1307
|
+
sequence_number = self._connection._get_new_sequence_number()
|
1308
|
+
self._out_message._send(sequence_number)
|
1309
|
+
|
1310
|
+
# retrieve response
|
1311
|
+
self._in_message._read_message_sql(sequence_number, self._statement_id, 0, [404, 100])
|
1312
|
+
self._sqlcode = self._in_message.wire.header._get_function_code()
|
1313
|
+
if self._sqlcode == 404:
|
1314
|
+
self._handle_error_504(404)
|
1315
|
+
return
|
1316
|
+
elif self._sqlcode == 100:
|
1317
|
+
self._handle_error_100(100)
|
1318
|
+
return
|
1319
|
+
self._get_output_parameters(self._in_message.wire)
|
1320
|
+
self._in_message._read_message_sql(sequence_number, self._statement_id, _InStream.FETCH_DATA, [100])
|
1321
|
+
self._sqlcode = self._in_message.wire.header._get_function_code()
|
1322
|
+
if self._sqlcode == 100:
|
1323
|
+
self._handle_error_100(100)
|
1324
|
+
|
1325
|
+
self._current_wire = self._in_message.wire
|
1326
|
+
self._result_set = [self._current_wire]
|
1327
|
+
self._rs_index = 0
|
1328
|
+
|
1329
|
+
def _execute_multiple_result_sets(self, validate):
|
1330
|
+
self._fetch_done = False
|
1331
|
+
if validate:
|
1332
|
+
self._validate_parameters()
|
1333
|
+
with self._connection._lock:
|
1334
|
+
self._out_message.wire._write_header(_Message.EXECUTE_MULTIPLE_RESULT_SETS)
|
1335
|
+
self._out_message.wire._set(0) # resultSetType != ResultSet.TYPE_SCROLL_INSENSITIVE
|
1336
|
+
self._out_message.wire._set(0) # query timeout
|
1337
|
+
self._write_stored_procedure_parameters()
|
1338
|
+
|
1339
|
+
# send
|
1340
|
+
sequence_number = self._connection._get_new_sequence_number()
|
1341
|
+
self._out_message._send(sequence_number)
|
1342
|
+
|
1343
|
+
if self.statementFeatureOption & Feature.optionFastSelect == Feature.optionFastSelect:
|
1344
|
+
self._rsrow = _ResultSetRow(self._connection, self._columns, self.maxRowItemCount)
|
1345
|
+
else:
|
1346
|
+
self._rsrow = _ResultSetRow(self._connection, self._columns, 0)
|
1347
|
+
|
1348
|
+
self._in_message._read_message_sql(sequence_number, self._statement_id, _InStream.FETCH_DATA, [100])
|
1349
|
+
self._sqlcode = self._in_message.wire.header._get_function_code()
|
1350
|
+
if self._sqlcode == 100:
|
1351
|
+
self._fetch_done = True
|
1352
|
+
self._get_output_parameters(self._in_message.wire)
|
1353
|
+
|
1354
|
+
self._current_wire = self._in_message.wire
|
1355
|
+
self._result_set = [self._current_wire]
|
1356
|
+
self._rs_index = 0
|
1357
|
+
|
1358
|
+
results = self._in_message.wire._get()
|
1359
|
+
if results >= 0 :
|
1360
|
+
self._update_cnt = results
|
1361
|
+
return False
|
1362
|
+
elif results == -1:
|
1363
|
+
return True
|
1364
|
+
elif results == -2:
|
1365
|
+
self._update_cnt = -1
|
1366
|
+
self._mrs_done = True
|
1367
|
+
#self._rsrow._is_after_last = True
|
1368
|
+
return False
|
1369
|
+
else:
|
1370
|
+
raise Exception("Invalid result type value")
|
1371
|
+
|
1372
|
+
def _write_stored_procedure_parameters(self):
|
1373
|
+
i = 0
|
1374
|
+
if self._parameter_sets != 0:
|
1375
|
+
self._out_message.wire._set(self._parameter_sets)
|
1376
|
+
self._out_message.wire._set(len(self._params._params_list))
|
1377
|
+
for j in range(self._parameter_sets):
|
1378
|
+
for i, param in enumerate(self._params._params_list):
|
1379
|
+
self._out_message.wire._set_parameter(param._values[j])
|
1380
|
+
return
|
1381
|
+
self._out_message.wire._set(1)
|
1382
|
+
if self._has_return_value != ServerReturnType.NO_RETURN_VALUE:
|
1383
|
+
i = 1
|
1384
|
+
self._out_message.wire._set(len(self._params._params_list) - i)
|
1385
|
+
param_index = 0
|
1386
|
+
param_counter = 0
|
1387
|
+
for param in self._params._params_list:
|
1388
|
+
if i == 1:
|
1389
|
+
i = 0
|
1390
|
+
continue
|
1391
|
+
if param.mode == ParameterMode.OUTPUT or param.mode == ParameterMode.DEFAULT_PARAMETER:
|
1392
|
+
self._out_message.wire._set_undefined()
|
1393
|
+
elif not (param.mode == ParameterMode.INPUT or param.mode == ParameterMode.INPUT_OUTPUT):
|
1394
|
+
self._out_message.wire._set_parameter_type(param.type, param.value)
|
1395
|
+
elif len(self.params) > 0:
|
1396
|
+
item = self.params[param_counter]
|
1397
|
+
if isinstance(item, list) or isinstance(item, tuple):
|
1398
|
+
value = item[param_index]
|
1399
|
+
param_index = param_index + 1
|
1400
|
+
else:
|
1401
|
+
value = item
|
1402
|
+
param_counter = param_counter + 1
|
1403
|
+
self._out_message.wire._set_parameter_type(param.type, value)
|
1404
|
+
else:
|
1405
|
+
raise Exception("Missing value")
|
1406
|
+
|
1407
|
+
def _get_output_parameters(self, wire):
|
1408
|
+
beg = wire._get_offset()
|
1409
|
+
i = 0
|
1410
|
+
if self._has_return_value == ServerReturnType.NULL_RETURN_VALUE:
|
1411
|
+
i += 1
|
1412
|
+
for param in self._params._params_list:
|
1413
|
+
if i == 1:
|
1414
|
+
i = 0
|
1415
|
+
continue
|
1416
|
+
if param.mode == ParameterMode.INPUT_OUTPUT or param.mode == ParameterMode.OUTPUT or param.mode == ParameterMode.RETURN_VALUE:
|
1417
|
+
wire._next_unless_undefined()
|
1418
|
+
else:
|
1419
|
+
wire._next()
|
1420
|
+
if self._has_return_value == ServerReturnType.NULL_RETURN_VALUE:
|
1421
|
+
self._output_parameter_list = wire._get_output_parameter_list(beg, True)
|
1422
|
+
self._has_return_value = ServerReturnType.HAS_RETURN_VALUE
|
1423
|
+
else:
|
1424
|
+
self._output_parameter_list = wire._get_output_parameter_list(beg, False)
|
1425
|
+
if self._statementType not in [StatementType.DIRECT_CALL_UPDATE]:
|
1426
|
+
self._params._prep_list_index(False, self._output_parameter_list) # fast select not supported for stored procedures
|
1427
|
+
return
|
1428
|
+
|
1429
|
+
def _handle_error_504(self, error):
|
1430
|
+
if error == 404:
|
1431
|
+
self._query404()
|
1432
|
+
return
|
1433
|
+
self._handle_error_100(error)
|
1434
|
+
|
1435
|
+
def _handle_error_100(self, error):
|
1436
|
+
if error == 100:
|
1437
|
+
self._fetch_done = True
|
1438
|
+
pass
|
1439
|
+
else:
|
1440
|
+
pass
|
1441
|
+
|
1442
|
+
def stored_results(self):
|
1443
|
+
if self._closed:
|
1444
|
+
raise InterfaceError("Cursor is closed")
|
1445
|
+
if self._statementType not in [StatementType.QUERY, StatementType.DIRECT_CALL_QUERY, StatementType.PREPARED_CALL_QUERY]:
|
1446
|
+
return None
|
1447
|
+
# getResultSet()
|
1448
|
+
if self._multiple_result_sets:
|
1449
|
+
if self._rsrow == None and self._rowcount == -1:
|
1450
|
+
return None
|
1451
|
+
if self._mrs_done:
|
1452
|
+
return None
|
1453
|
+
self._get_column_info(self._in_message.wire)
|
1454
|
+
self.nextset()
|
1455
|
+
return iter(self._stored_results)
|
1456
|
+
|
1457
|
+
def nextset(self):
|
1458
|
+
if len(self._stored_results) == 0:
|
1459
|
+
# getResultSet()
|
1460
|
+
if self.statementFeatureOption & Feature.optionFastSelect == Feature.optionFastSelect:
|
1461
|
+
self._rsrow = _ResultSetRow(self._connection, self._columns, self.maxRowItemCount)
|
1462
|
+
else:
|
1463
|
+
self._rsrow = _ResultSetRow(self._connection, self._columns, 0)
|
1464
|
+
self._rsrow.indexRow(self._in_message.wire.list_item)
|
1465
|
+
self._stored_results.append(self._rsrow._offsets)
|
1466
|
+
return True
|
1467
|
+
else:
|
1468
|
+
# getMoreResults()
|
1469
|
+
if self._closed:
|
1470
|
+
raise InterfaceError("Cursor is closed")
|
1471
|
+
if self._connection == None or self._connection.isClosed():
|
1472
|
+
raise InterfaceError("Connection not open")
|
1473
|
+
if (self._mrs_done or not self._multiple_result_sets or
|
1474
|
+
(self._statementType != StatementType.PREPARED_CALL_QUERY and
|
1475
|
+
self._statementType != StatementType.DIRECT_CALL_QUERY and
|
1476
|
+
self._statementType != StatementType.CALL and
|
1477
|
+
self._statementType != StatementType.CALLWITHRESULT and
|
1478
|
+
not (self._statementType == StatementType.QUERY and self._cursor_type == CursorType.CALLABLE))):
|
1479
|
+
return False
|
1480
|
+
with self._connection._lock:
|
1481
|
+
self._out_message.wire._write_header(_Message.GET_MORE_RESULTS)
|
1482
|
+
self._out_message.wire._set(1) # current = CLOSE_CURRENT_RESULT
|
1483
|
+
|
1484
|
+
# send
|
1485
|
+
sequence_number = self._connection._get_new_sequence_number()
|
1486
|
+
self._out_message._send(sequence_number)
|
1487
|
+
|
1488
|
+
self._in_message._read_message_sql(sequence_number, self._statement_id, 0, [100])
|
1489
|
+
sqlcode = self._in_message.wire.header._get_function_code()
|
1490
|
+
|
1491
|
+
self._current_wire = self._in_message.wire
|
1492
|
+
self._result_set = [self._current_wire]
|
1493
|
+
self._rs_index = 0
|
1494
|
+
|
1495
|
+
results = self._in_message.wire._get()
|
1496
|
+
if results >= 0 :
|
1497
|
+
self._update_cnt = results
|
1498
|
+
return False
|
1499
|
+
elif results == -1:
|
1500
|
+
self._rsrow = None
|
1501
|
+
self._get_column_info(self._in_message.wire)
|
1502
|
+
if self.statementFeatureOption & Feature.optionFastSelect == Feature.optionFastSelect:
|
1503
|
+
self._rsrow = _ResultSetRow(self._connection, self._columns, self.maxRowItemCount)
|
1504
|
+
else:
|
1505
|
+
self._rsrow = _ResultSetRow(self._connection, self._columns, 0)
|
1506
|
+
self._rsrow.indexRow(self._in_message.wire.list_item)
|
1507
|
+
self._stored_results.append(self._rsrow._offsets)
|
1508
|
+
if sqlcode == 100:
|
1509
|
+
self._fetch_done = True
|
1510
|
+
else:
|
1511
|
+
self._fetch_done = False
|
1512
|
+
return True
|
1513
|
+
elif results == -2:
|
1514
|
+
self._update_cnt = -1
|
1515
|
+
self._mrs_done = True
|
1516
|
+
return False
|
1517
|
+
else:
|
1518
|
+
raise Exception("Invalid result type value")
|
1519
|
+
return
|
1520
|
+
|
1521
|
+
def _get_result_set(self, oref):
|
1522
|
+
if oref == None:
|
1523
|
+
return None
|
1524
|
+
|
1525
|
+
with self._connection._lock:
|
1526
|
+
self._out_message.wire._write_header(_Message.GET_RESULT_SET_OBJECT)
|
1527
|
+
self._out_message.wire._set(oref)
|
1528
|
+
self._out_message.wire._set(0) # IRISResultSet.GET_RESULT_SET_OBJECT_INIT
|
1529
|
+
|
1530
|
+
# send
|
1531
|
+
sequence_number = self._connection._get_new_sequence_number()
|
1532
|
+
self._out_message._send(sequence_number)
|
1533
|
+
|
1534
|
+
# retrieve response
|
1535
|
+
error = self._in_message._read_message_sql(sequence_number, self._statement_id, 0, [100])
|
1536
|
+
if error == 100:
|
1537
|
+
self._fetch_done = True
|
1538
|
+
self._get_column_info(self._in_message.wire)
|
1539
|
+
return
|
1540
|
+
|
1541
|
+
def callproc(self, procname, *params):
|
1542
|
+
if self._closed:
|
1543
|
+
raise InterfaceError("Cursor is closed")
|
1544
|
+
if self._connection == None or self._connection.isClosed():
|
1545
|
+
raise InterfaceError("Connection not open")
|
1546
|
+
|
1547
|
+
self.statement = procname
|
1548
|
+
if len(params) == 1 and (isinstance(params[0], tuple) or isinstance(params[0], list)):
|
1549
|
+
self.params = self.params[0]
|
1550
|
+
else:
|
1551
|
+
self.params = params
|
1552
|
+
|
1553
|
+
self._params.set_input_params(self.params)
|
1554
|
+
|
1555
|
+
self._cursor_type = CursorType.CALLABLE
|
1556
|
+
self._cleanup()
|
1557
|
+
self._preparse()
|
1558
|
+
self._stored_results = []
|
1559
|
+
|
1560
|
+
if not self._get_cached_info():
|
1561
|
+
self._prepare_stored_procedure()
|
1562
|
+
|
1563
|
+
#execute() in IrisPreparedStatement
|
1564
|
+
if self._multiple_result_sets:
|
1565
|
+
return self._execute_multiple_result_sets(True)
|
1566
|
+
if self._statementType == StatementType.QUERY or self._statementType == StatementType.PREPARED_CALL_QUERY:
|
1567
|
+
self._execute_query()
|
1568
|
+
self._rowcount = -1
|
1569
|
+
if self._fetch_done and self._in_message.wire.header._get_message_length() == 0:
|
1570
|
+
return
|
1571
|
+
return self._process_return_values()
|
1572
|
+
self._execute_update()
|
1573
|
+
if self._parameter_sets == 0 and not self._multiple_result_sets:
|
1574
|
+
self._rowcount = self._in_message.wire._get()
|
1575
|
+
|
1576
|
+
return self._process_return_values()
|
1577
|
+
|
1578
|
+
def _process_return_values(self):
|
1579
|
+
return_args = []
|
1580
|
+
for i, param in enumerate(self._params._params_list):
|
1581
|
+
if param.mode in [ParameterMode.RETURN_VALUE, ParameterMode.OUTPUT, ParameterMode.INPUT]:
|
1582
|
+
offset = self._params._get_user_list_offset(i + 1)
|
1583
|
+
val = self._output_parameter_list._get_at_offset(offset)
|
1584
|
+
if param.type == -51: # RESULT_SET_TYPE
|
1585
|
+
self._get_result_set(val)
|
1586
|
+
self.nextset()
|
1587
|
+
return_args.append(self._stored_results[0])
|
1588
|
+
else:
|
1589
|
+
if val == '\x01': # Either represents the number 1 or a null/None value
|
1590
|
+
# maybe move this to _grab_ascii_string in DBList?
|
1591
|
+
off = self._output_parameter_list.list_item.data_offset
|
1592
|
+
buf = self._output_parameter_list.list_item.buffer
|
1593
|
+
if buf[off] == 1 and buf[off - 1] == 1 and buf[off - 2] == 3:
|
1594
|
+
return_args.append(None)
|
1595
|
+
else:
|
1596
|
+
return_args.append(val)
|
1597
|
+
if len(return_args) > 0:
|
1598
|
+
if any(i != None for i in return_args):
|
1599
|
+
return return_args
|
1600
|
+
else:
|
1601
|
+
return
|
1602
|
+
else:
|
1603
|
+
return
|
1604
|
+
|
1605
|
+
@property
|
1606
|
+
def lastrowid(self):
|
1607
|
+
if self._lastrowid is not None:
|
1608
|
+
return self._lastrowid
|
1609
|
+
|
1610
|
+
if self._closed:
|
1611
|
+
return None
|
1612
|
+
if self._connection == None or self._connection.isClosed():
|
1613
|
+
return None
|
1614
|
+
|
1615
|
+
if self._statementType is not StatementType.UPDATE:
|
1616
|
+
return None
|
1617
|
+
|
1618
|
+
# In multivalue inserts it returns the first inserted value, not the last one
|
1619
|
+
# with self._connection._lock:
|
1620
|
+
# self._out_message.wire._write_header(_Message.GET_AUTO_GENERATED_KEYS)
|
1621
|
+
# sequence_number = self._connection._get_new_sequence_number()
|
1622
|
+
# self._out_message._send(sequence_number)
|
1623
|
+
# self._in_message._read_message_sql(sequence_number)
|
1624
|
+
# self._sqlcode = self._in_message.wire.header._get_function_code()
|
1625
|
+
# if self._sqlcode != 100:
|
1626
|
+
# raise InterfaceError(self._get_error_info(self._sqlcode))
|
1627
|
+
# self._get_column_info(self._in_message.wire)
|
1628
|
+
# self._lastrowid = self._in_message.wire._get()
|
1629
|
+
|
1630
|
+
self.execute('SELECT LAST_IDENTITY()')
|
1631
|
+
self._lastrowid = self.fetchone()[0]
|
1632
|
+
return self._lastrowid
|
1633
|
+
|
1634
|
+
def _cleanup(self):
|
1635
|
+
super()._cleanup()
|
1636
|
+
if self._rsrow != None:
|
1637
|
+
self._rsrow = None
|
1638
|
+
if self._params != None:
|
1639
|
+
self._params._clear()
|
1640
|
+
self._multiple_result_sets = False
|
1641
|
+
self._mrs_done = False
|
1642
|
+
self._fetch_done = False
|
1643
|
+
self._parameter_list_mismatch_exception = False
|
1644
|
+
self._parameter_sets = 0
|
1645
|
+
self._rowcount = -1
|
1646
|
+
self._exec_params = None
|
1647
|
+
self._statementType = StatementType.UPDATE
|
1648
|
+
self.statementFeatureOption = 0
|
1649
|
+
self.maxRowItemCount = 0
|
1650
|
+
self._is_batch_update = False
|
1651
|
+
|
1652
|
+
def close(self):
|
1653
|
+
if self._closed:
|
1654
|
+
return
|
1655
|
+
self._columns = None
|
1656
|
+
self._rowcount = -1
|
1657
|
+
self.arraysize = 0
|
1658
|
+
|
1659
|
+
self._connection = None
|
1660
|
+
self._in_message = None
|
1661
|
+
self._out_message = None
|
1662
|
+
|
1663
|
+
self._result_set = None
|
1664
|
+
|
1665
|
+
if self._rsrow != None:
|
1666
|
+
self._rsrow = None
|
1667
|
+
self._cursor_ptr = 0
|
1668
|
+
self._scroll_flag = False
|
1669
|
+
self._warehouse = []
|
1670
|
+
self._warehouse_dict = {}
|
1671
|
+
self._last_row_in_warehouse_dict = -1
|
1672
|
+
self._warehouse_dict_keys = []
|
1673
|
+
|
1674
|
+
self._params = None
|
1675
|
+
self._parsed_statement = None
|
1676
|
+
self._cursor_type = CursorType.DEFAULT
|
1677
|
+
self._statementType = StatementType.UPDATE # default
|
1678
|
+
self._paramInfo = None
|
1679
|
+
self.statement = None
|
1680
|
+
self.statementFeatureOption = Feature.optionNone
|
1681
|
+
self._statement_id = None
|
1682
|
+
self._sqlcode = None
|
1683
|
+
self._current_wire = None
|
1684
|
+
self._result_set = []
|
1685
|
+
self._rs_index = -1
|
1686
|
+
|
1687
|
+
self._parameter_sets = 0
|
1688
|
+
self._exec_params = None
|
1689
|
+
self._is_batch_update = False
|
1690
|
+
self._multiple_result_sets = False
|
1691
|
+
self._mrs_done = False
|
1692
|
+
self._fetch_done = False
|
1693
|
+
self._parameter_list_mismatch_exception = False
|
1694
|
+
if self._output_parameter_list != None:
|
1695
|
+
self._output_parameter_list._clear_list()
|
1696
|
+
|
1697
|
+
self._closed = True
|
1698
|
+
|
1699
|
+
def executemany(self, operation, seq_of_params):
|
1700
|
+
super().executemany(operation, seq_of_params)
|
1701
|
+
self._rowcount = 0
|
1702
|
+
for i in range(len(self.params)):
|
1703
|
+
self._rowcount += self._in_message.wire._get()
|
1704
|
+
return self._rowcount
|
1705
|
+
|
1706
|
+
def scroll(self, value, mode):
|
1707
|
+
if mode == None or mode == '':
|
1708
|
+
mode = 'relative'
|
1709
|
+
mode = mode.lower()
|
1710
|
+
if mode != 'absolute' and mode != 'relative':
|
1711
|
+
raise ValueError("This mode is not supported - use 'relative' or 'absolute'.")
|
1712
|
+
|
1713
|
+
# Backward Scrolling
|
1714
|
+
if value < 0:
|
1715
|
+
if mode == 'relative':
|
1716
|
+
self._rownumber = self._cursor_ptr + value - 1
|
1717
|
+
else:
|
1718
|
+
raise ValueError("Negative values with absolute scrolling are not allowed.")
|
1719
|
+
self._cursor_ptr = self._rownumber + 1
|
1720
|
+
if self._rs_index == 0:
|
1721
|
+
return self._warehouse[self._rownumber]
|
1722
|
+
else:
|
1723
|
+
if self._rownumber <= self._last_row_in_warehouse_dict:
|
1724
|
+
return self._retrieve_from_warehouse(self._rownumber)
|
1725
|
+
else:
|
1726
|
+
if self._current_wire == None:
|
1727
|
+
rows_available = self._last_row_in_warehouse_dict
|
1728
|
+
else:
|
1729
|
+
rows_available = self._last_row_in_warehouse_dict + len(self._warehouse)
|
1730
|
+
if self._rownumber <= rows_available:
|
1731
|
+
return self._warehouse[self._rownumber - self._last_row_in_warehouse_dict - 1]
|
1732
|
+
# Forward Scrolling
|
1733
|
+
else:
|
1734
|
+
if mode == 'absolute':
|
1735
|
+
self._cursor_ptr = 0
|
1736
|
+
self._scroll_flag = True
|
1737
|
+
self._rownumber = self._cursor_ptr + value - 1
|
1738
|
+
if self._rs_index == 0:
|
1739
|
+
if self._rownumber >= len(self._warehouse):
|
1740
|
+
if mode == 'absolute':
|
1741
|
+
self._cursor_ptr = len(self._warehouse)
|
1742
|
+
return self.fetchone()
|
1743
|
+
else:
|
1744
|
+
self._scroll_flag = False
|
1745
|
+
self._cursor_ptr = self._rownumber + 1
|
1746
|
+
return self._warehouse[self._rownumber]
|
1747
|
+
else:
|
1748
|
+
if self._rownumber <= self._last_row_in_warehouse_dict:
|
1749
|
+
self._scroll_flag = False
|
1750
|
+
self._cursor_ptr = self._rownumber + 1
|
1751
|
+
return self._retrieve_from_warehouse(self._rownumber)
|
1752
|
+
else:
|
1753
|
+
if self._current_wire == None:
|
1754
|
+
rows_available = self._last_row_in_warehouse_dict
|
1755
|
+
else:
|
1756
|
+
rows_available = self._last_row_in_warehouse_dict + len(self._warehouse)
|
1757
|
+
if self._rownumber <= rows_available:
|
1758
|
+
self._scroll_flag = False
|
1759
|
+
self._cursor_ptr = self._rownumber + 1
|
1760
|
+
return self._warehouse[self._rownumber - self._last_row_in_warehouse_dict - 1]
|
1761
|
+
else:
|
1762
|
+
if mode == 'absolute':
|
1763
|
+
self._cursor_ptr = rows_available + 1
|
1764
|
+
return self.fetchone()
|
1765
|
+
|
1766
|
+
def _retrieve_from_warehouse(self, value):
|
1767
|
+
for idx, (key, val) in enumerate(self._warehouse_dict.items()):
|
1768
|
+
if value <= key:
|
1769
|
+
if idx != 0:
|
1770
|
+
prev_key = self._warehouse_dict_keys[idx - 1]
|
1771
|
+
return val[value - prev_key - 1]
|
1772
|
+
return val[value]
|
1773
|
+
|
1774
|
+
def _switch_buffer(self):
|
1775
|
+
if self._sqlcode == 0:
|
1776
|
+
with self._connection._lock:
|
1777
|
+
self._out_message.wire._write_header(_Message.FETCH_DATA)
|
1778
|
+
intersystems_iris._MessageHeader._MessageHeader._set_statement_id(self._out_message.wire.buffer, self._statement_id)
|
1779
|
+
|
1780
|
+
sequence_number = self._connection._get_new_sequence_number()
|
1781
|
+
self._out_message._send(sequence_number)
|
1782
|
+
|
1783
|
+
self._in_message._read_message_sql(sequence_number, self._statement_id, 0, [100])
|
1784
|
+
self._sqlcode = self._in_message.wire.header._get_function_code()
|
1785
|
+
if self._sqlcode not in [0, 100]:
|
1786
|
+
raise InterfaceError(self._get_error_info(self._sqlcode))
|
1787
|
+
self._result_set.append(self._in_message.wire)
|
1788
|
+
|
1789
|
+
if self._sqlcode == 404:
|
1790
|
+
self._query404()
|
1791
|
+
return
|
1792
|
+
|
1793
|
+
if self._rs_index + 1 == len(self._result_set):
|
1794
|
+
self._warehouse_dict[self._cursor_ptr] = self._warehouse
|
1795
|
+
self._warehouse_dict_keys = sorted(self._warehouse_dict.keys())
|
1796
|
+
self._last_row_in_warehouse_dict = self._warehouse_dict_keys[-1]
|
1797
|
+
self._current_wire = None
|
1798
|
+
else:
|
1799
|
+
self._warehouse_dict[self._cursor_ptr] = self._warehouse
|
1800
|
+
self._warehouse_dict_keys = sorted(self._warehouse_dict.keys())
|
1801
|
+
self._last_row_in_warehouse_dict = self._warehouse_dict_keys[-1]
|
1802
|
+
self._warehouse = []
|
1803
|
+
self._rsrow._new_buffer = True
|
1804
|
+
self._rs_index += 1
|
1805
|
+
self._current_wire = self._result_set[self._rs_index]
|
1806
|
+
|
1807
|
+
def fetchone_helper(self):
|
1808
|
+
row_indexing = True
|
1809
|
+
if self.statementFeatureOption & Feature.optionFastSelect == Feature.optionFastSelect:
|
1810
|
+
list_item = self._current_wire.list_item
|
1811
|
+
buffer = list_item.buffer
|
1812
|
+
length = list_item.list_buffer_end
|
1813
|
+
|
1814
|
+
if self._rsrow._new_buffer:
|
1815
|
+
prev_offset = list_item.next_offset
|
1816
|
+
self._rsrow._new_buffer = False
|
1817
|
+
else:
|
1818
|
+
prev_offset = self._rsrow._offsets._length
|
1819
|
+
|
1820
|
+
if prev_offset < length:
|
1821
|
+
if self._rsrow._fast_first_iter:
|
1822
|
+
self._rsrow._fast_first_iter = False
|
1823
|
+
else:
|
1824
|
+
if self._rsrow._new_buffer:
|
1825
|
+
list_item.buffer = buffer
|
1826
|
+
list_item.next_offset = prev_offset
|
1827
|
+
intersystems_iris._DBList._DBList._get_list_element(list_item)
|
1828
|
+
length = list_item.next_offset
|
1829
|
+
prev_offset = list_item.data_offset
|
1830
|
+
if list_item.data_length == 0: #
|
1831
|
+
for j in range(self._rsrow.colCount):
|
1832
|
+
rowItems[j] = -1
|
1833
|
+
self._rsrow._offsets = self._rsrow.update(rowItems) # ???
|
1834
|
+
return True
|
1835
|
+
else:
|
1836
|
+
if self._rsrow.rowItems != None:
|
1837
|
+
self._rsrow.rowItems[-1] = 0
|
1838
|
+
return False
|
1839
|
+
|
1840
|
+
self._rsrow._last_list_item = list_item
|
1841
|
+
self._rsrow._offsets = self._rsrow.DataRowFastSelect(self._rsrow, prev_offset, length, buffer)
|
1842
|
+
self._warehouse.append(self._rsrow._offsets)
|
1843
|
+
|
1844
|
+
if self._current_wire._is_end():
|
1845
|
+
self._switch_buffer()
|
1846
|
+
|
1847
|
+
else:
|
1848
|
+
row_indexing = self._rsrow.indexRow(self._current_wire.list_item)
|
1849
|
+
if row_indexing:
|
1850
|
+
self._warehouse.append(self._rsrow._offsets)
|
1851
|
+
|
1852
|
+
if self._rsrow.rowItems == None:
|
1853
|
+
return
|
1854
|
+
|
1855
|
+
if self._rsrow.rowItems[-1] >= self._current_wire.list_item.list_buffer_end:
|
1856
|
+
self._switch_buffer()
|
1857
|
+
|
1858
|
+
self._cursor_ptr += 1
|
1859
|
+
return row_indexing
|
1860
|
+
|
1861
|
+
def fetchone(self):
|
1862
|
+
if self._result_set == None:
|
1863
|
+
raise InterfaceError("Either execute has not yet been called, or the previous call of execute did not return a result set")
|
1864
|
+
|
1865
|
+
if self._current_wire == None and self._cursor_ptr > self._last_row_in_warehouse_dict:
|
1866
|
+
return None
|
1867
|
+
|
1868
|
+
retval = None
|
1869
|
+
if self._rs_index == 0:
|
1870
|
+
if self._cursor_ptr < len(self._warehouse):
|
1871
|
+
self._cursor_ptr += 1
|
1872
|
+
retval = self._warehouse[self._cursor_ptr - 1]
|
1873
|
+
else:
|
1874
|
+
rownumber = self._cursor_ptr
|
1875
|
+
if rownumber <= self._last_row_in_warehouse_dict:
|
1876
|
+
self._cursor_ptr += 1
|
1877
|
+
retval = self._retrieve_from_warehouse(rownumber)
|
1878
|
+
else:
|
1879
|
+
if self._current_wire == None:
|
1880
|
+
rows_available = self._last_row_in_warehouse_dict
|
1881
|
+
else:
|
1882
|
+
rows_available = self._last_row_in_warehouse_dict + len(self._warehouse)
|
1883
|
+
if rownumber <= rows_available:
|
1884
|
+
self._cursor_ptr += 1
|
1885
|
+
retval = self._warehouse[rownumber - self._last_row_in_warehouse_dict - 1]
|
1886
|
+
|
1887
|
+
if retval is None:
|
1888
|
+
if self._scroll_flag:
|
1889
|
+
while self._cursor_ptr <= self._rownumber:
|
1890
|
+
if self.fetchone_helper():
|
1891
|
+
retval = self._rsrow._offsets
|
1892
|
+
self._scroll_flag = False
|
1893
|
+
else:
|
1894
|
+
if self.fetchone_helper():
|
1895
|
+
retval = self._rsrow._offsets
|
1896
|
+
|
1897
|
+
if retval is None:
|
1898
|
+
return retval
|
1899
|
+
return retval[:]
|
1900
|
+
|
1901
|
+
def fetchmany(self, size = None):
|
1902
|
+
if self._result_set == None:
|
1903
|
+
raise InterfaceError("Either execute has not yet been called, or the previous call of execute did not return a result set")
|
1904
|
+
|
1905
|
+
if self._current_wire == None:
|
1906
|
+
if self._cursor_ptr > self._last_row_in_warehouse_dict:
|
1907
|
+
return None
|
1908
|
+
if size is None:
|
1909
|
+
size = self.arraysize
|
1910
|
+
if self._rs_index == 0:
|
1911
|
+
if self._cursor_ptr < len(self._warehouse):
|
1912
|
+
rows = []
|
1913
|
+
for i in range(size):
|
1914
|
+
row = self._warehouse[self._cursor_ptr]
|
1915
|
+
rows.append(row[:])
|
1916
|
+
if self._cursor_ptr + 1 >= len(self._warehouse):
|
1917
|
+
self._cursor_ptr += 1
|
1918
|
+
break
|
1919
|
+
self._cursor_ptr += 1
|
1920
|
+
return rows
|
1921
|
+
else:
|
1922
|
+
rows = []
|
1923
|
+
for i in range(size):
|
1924
|
+
row = self._retrieve_from_warehouse(self._cursor_ptr)
|
1925
|
+
rows.append(row[:])
|
1926
|
+
if self._cursor_ptr + 1 > self._last_row_in_warehouse_dict:
|
1927
|
+
self._cursor_ptr += 1
|
1928
|
+
break
|
1929
|
+
self._cursor_ptr += 1
|
1930
|
+
return rows
|
1931
|
+
|
1932
|
+
if size is None:
|
1933
|
+
size = self.arraysize
|
1934
|
+
|
1935
|
+
rows = []
|
1936
|
+
for i in range(size):
|
1937
|
+
row = self.fetchone()
|
1938
|
+
if row is None:
|
1939
|
+
break
|
1940
|
+
rows.append(row[:])
|
1941
|
+
return rows
|
1942
|
+
|
1943
|
+
def fetchall(self):
|
1944
|
+
if self._result_set == None:
|
1945
|
+
raise InterfaceError("Either execute has not yet been called, or the previous call of execute did not return a result set")
|
1946
|
+
|
1947
|
+
if self._current_wire == None:
|
1948
|
+
if self._cursor_ptr > self._last_row_in_warehouse_dict:
|
1949
|
+
return None
|
1950
|
+
if self._rs_index == 0:
|
1951
|
+
if self._cursor_ptr < len(self._warehouse):
|
1952
|
+
rows = []
|
1953
|
+
while 1:
|
1954
|
+
row = self._warehouse[self._cursor_ptr]
|
1955
|
+
rows.append(row[:])
|
1956
|
+
if self._cursor_ptr + 1 >= len(self._warehouse):
|
1957
|
+
self._cursor_ptr += 1
|
1958
|
+
break
|
1959
|
+
self._cursor_ptr += 1
|
1960
|
+
return rows
|
1961
|
+
else:
|
1962
|
+
rows = []
|
1963
|
+
while 1:
|
1964
|
+
row = self._retrieve_from_warehouse(self._cursor_ptr)
|
1965
|
+
rows.append(row[:])
|
1966
|
+
if self._cursor_ptr + 1 > self._last_row_in_warehouse_dict:
|
1967
|
+
self._cursor_ptr += 1
|
1968
|
+
break
|
1969
|
+
self._cursor_ptr += 1
|
1970
|
+
return rows
|
1971
|
+
|
1972
|
+
rows = []
|
1973
|
+
while self._current_wire is not None:
|
1974
|
+
row = self.fetchone()
|
1975
|
+
if not row: break
|
1976
|
+
rows.append(row[:])
|
1977
|
+
return rows
|
1978
|
+
|
1979
|
+
class EmbdeddedCursor(_BaseCursor):
|
1980
|
+
embedded = True
|
1981
|
+
_result_set = None
|
1982
|
+
|
1983
|
+
def __init__(self, connection: _IRISEmbedded) -> None:
|
1984
|
+
super().__init__(connection)
|
1985
|
+
self._sql = connection.iris.sql
|
1986
|
+
self._iris = connection.iris
|
1987
|
+
self._closed = False
|
1988
|
+
|
1989
|
+
# $System.SQL.SetSelectMode(1 /* ODBC */)
|
1990
|
+
# $System.SQL.Util.SetOption("SelectMode", 1 /* ODBC */)
|
1991
|
+
connection.iris.system.SQL.SetSelectMode(1)
|
1992
|
+
|
1993
|
+
def _get_cached_info(self):
|
1994
|
+
return False
|
1995
|
+
|
1996
|
+
def _get_parameters(self, params_set = 0):
|
1997
|
+
params = self._params.collect(params_set)
|
1998
|
+
# None = '', '' = b'\x00'
|
1999
|
+
_conv = {
|
2000
|
+
type(None): lambda v: '',
|
2001
|
+
str: lambda v: v or b'\x00',
|
2002
|
+
decimal.Decimal: lambda v: float(v),
|
2003
|
+
}
|
2004
|
+
params = [_conv[type(v)](v) if type(v) in _conv else v for v in params]
|
2005
|
+
return params
|
2006
|
+
|
2007
|
+
def _get_column_info(self):
|
2008
|
+
self._columns = []
|
2009
|
+
if self._result_set is None:
|
2010
|
+
return
|
2011
|
+
|
2012
|
+
metadata = self._result_set.ResultSet._GetMetadata()
|
2013
|
+
count = metadata.columnCount if metadata != '' and metadata is not None else 0
|
2014
|
+
for i in range(count):
|
2015
|
+
slotPosition = i + 1
|
2016
|
+
_column_info = metadata.columns.GetAt(slotPosition)
|
2017
|
+
name = _column_info.colName
|
2018
|
+
odbctype = _column_info.ODBCType
|
2019
|
+
if _column_info.scale in SQLType.__members__:
|
2020
|
+
# There is a bug on IRIS side, when it may return incorrectly when it passed that way NUMERIC(?, ?)
|
2021
|
+
precision = 15
|
2022
|
+
scale = 15
|
2023
|
+
else:
|
2024
|
+
precision = _column_info.precision or None
|
2025
|
+
scale = _column_info.scale or None
|
2026
|
+
nullable = _column_info.isNullable
|
2027
|
+
label = _column_info.label
|
2028
|
+
tableName = _column_info.tableName
|
2029
|
+
schema = _column_info.schemaName
|
2030
|
+
catalog = None
|
2031
|
+
additionalData = [
|
2032
|
+
_column_info.isAutoIncrement,
|
2033
|
+
_column_info.isCaseSensitive,
|
2034
|
+
_column_info.isCurrency,
|
2035
|
+
_column_info.isReadOnly,
|
2036
|
+
_column_info.isRowVersion,
|
2037
|
+
_column_info.isUnique,
|
2038
|
+
_column_info.isAliased,
|
2039
|
+
_column_info.isExpression,
|
2040
|
+
_column_info.isHidden,
|
2041
|
+
_column_info.isIdentity,
|
2042
|
+
_column_info.isKeyColumn,
|
2043
|
+
_column_info.isRowId,
|
2044
|
+
]
|
2045
|
+
self._columns.append(intersystems_iris.dbapi._Column._Column(name, odbctype, precision, scale, nullable, label, tableName, schema, catalog, additionalData, slotPosition))
|
2046
|
+
|
2047
|
+
def _process_sqlcode(self, sqlcode, message):
|
2048
|
+
if sqlcode == -119:
|
2049
|
+
raise IntegrityError(message)
|
2050
|
+
if sqlcode not in [0, 100]:
|
2051
|
+
raise InterfaceError(message)
|
2052
|
+
|
2053
|
+
@property
|
2054
|
+
def lastrowid(self):
|
2055
|
+
return self._lastrowid
|
2056
|
+
|
2057
|
+
def _prepare_new(self):
|
2058
|
+
statement = self._parsed_statement
|
2059
|
+
sqlcode = 0
|
2060
|
+
message = None
|
2061
|
+
try:
|
2062
|
+
self._statement = self._sql.prepare(statement)
|
2063
|
+
except Exception as ex:
|
2064
|
+
sqlcode = ex.sqlcode
|
2065
|
+
message = ex.message
|
2066
|
+
self._process_sqlcode(sqlcode, message)
|
2067
|
+
|
2068
|
+
def _prepared_query_execute(self):
|
2069
|
+
self._rowcount = 0
|
2070
|
+
params = self._get_parameters()
|
2071
|
+
sqlcode = 0
|
2072
|
+
message = None
|
2073
|
+
try:
|
2074
|
+
self._result_set = self._statement.execute(*params)
|
2075
|
+
self._get_column_info()
|
2076
|
+
self._rowcount += self._result_set.ResultSet._ROWCOUNT
|
2077
|
+
except Exception as ex:
|
2078
|
+
sqlcode = ex.sqlcode
|
2079
|
+
message = ex.message
|
2080
|
+
|
2081
|
+
self._process_sqlcode(sqlcode, message)
|
2082
|
+
|
2083
|
+
def _send_direct_update_request(self):
|
2084
|
+
self._rowcount = 0
|
2085
|
+
self._lastrowid = None
|
2086
|
+
statement = self._parsed_statement
|
2087
|
+
|
2088
|
+
sets = self._parameter_sets or 1
|
2089
|
+
for i in range(sets):
|
2090
|
+
params = self._get_parameters(i)
|
2091
|
+
|
2092
|
+
sqlcode = 0
|
2093
|
+
message = None
|
2094
|
+
try:
|
2095
|
+
_result_set = self._sql.exec(statement, *params)
|
2096
|
+
self._rowcount += _result_set.ResultSet._ROWCOUNT
|
2097
|
+
self._lastrowid = _result_set.ResultSet._ROWID
|
2098
|
+
except Exception as ex:
|
2099
|
+
sqlcode = ex.sqlcode
|
2100
|
+
message = ex.message
|
2101
|
+
|
2102
|
+
self._process_sqlcode(sqlcode, message)
|
2103
|
+
|
2104
|
+
def _send_direct_query_request(self):
|
2105
|
+
self._rowcount = 0
|
2106
|
+
statement = self._parsed_statement
|
2107
|
+
|
2108
|
+
params = self._get_parameters()
|
2109
|
+
sqlcode = 0
|
2110
|
+
message = None
|
2111
|
+
try:
|
2112
|
+
self._result_set = self._sql.exec(statement, *params)
|
2113
|
+
self._rowcount = self._result_set.ResultSet._ROWCOUNT
|
2114
|
+
self._get_column_info()
|
2115
|
+
except Exception as ex:
|
2116
|
+
sqlcode = ex.sqlcode
|
2117
|
+
message = ex.message
|
2118
|
+
self._process_sqlcode(sqlcode, message)
|
2119
|
+
|
2120
|
+
def _prepared_update_execute(self):
|
2121
|
+
self._rowcount = 0
|
2122
|
+
self._lastrowid = None
|
2123
|
+
sets = self._parameter_sets or 1
|
2124
|
+
for i in range(sets):
|
2125
|
+
params = self._get_parameters(i)
|
2126
|
+
sqlcode = 0
|
2127
|
+
message = None
|
2128
|
+
try:
|
2129
|
+
_result_set = self._statement.execute(*params)
|
2130
|
+
self._rowcount += _result_set.ResultSet._ROWCOUNT
|
2131
|
+
self._lastrowid = _result_set.ResultSet._ROWID
|
2132
|
+
except Exception as ex:
|
2133
|
+
sqlcode = ex.sqlcode
|
2134
|
+
message = ex.message
|
2135
|
+
self._process_sqlcode(sqlcode, message)
|
2136
|
+
|
2137
|
+
def _send_direct_stored_procedure_request(self):
|
2138
|
+
sqlproc = self._parsed_statement
|
2139
|
+
self._rowcount = 0
|
2140
|
+
params = self._get_parameters()
|
2141
|
+
params_marks = ', '.join(['?'] * len(params))
|
2142
|
+
statement = f'CALL {sqlproc} ({params_marks})'
|
2143
|
+
|
2144
|
+
sqlcode = 0
|
2145
|
+
message = None
|
2146
|
+
try:
|
2147
|
+
self._result_set = self._sql.exec(statement, *params)
|
2148
|
+
self._rowcount = self._result_set.ResultSet._ROWCOUNT
|
2149
|
+
self._get_column_info()
|
2150
|
+
except Exception as ex:
|
2151
|
+
sqlcode = ex.sqlcode
|
2152
|
+
message = ex.message
|
2153
|
+
self._process_sqlcode(sqlcode, message)
|
2154
|
+
|
2155
|
+
@property
|
2156
|
+
def rowcount(self):
|
2157
|
+
return self._rowcount
|
2158
|
+
|
2159
|
+
def fetchone(self):
|
2160
|
+
if self._result_set == None:
|
2161
|
+
raise InterfaceError("Either execute has not yet been called, or the previous call of execute did not return a result set")
|
2162
|
+
|
2163
|
+
try:
|
2164
|
+
row = self._result_set.__next__()
|
2165
|
+
except:
|
2166
|
+
return None
|
2167
|
+
|
2168
|
+
row = [None if v == '' else '' if v == '\x00' else v for v in row]
|
2169
|
+
|
2170
|
+
_types = {
|
2171
|
+
SQLType.BIGINT: int,
|
2172
|
+
SQLType.BINARY: bytes,
|
2173
|
+
SQLType.BIT: bool,
|
2174
|
+
SQLType.INTEGER: int,
|
2175
|
+
SQLType.VARCHAR: str,
|
2176
|
+
SQLType.LONGVARBINARY: IRISBinaryStream,
|
2177
|
+
SQLType.LONGVARCHAR: IRISStream,
|
2178
|
+
}
|
2179
|
+
|
2180
|
+
if self._columns:
|
2181
|
+
for _column in self._columns:
|
2182
|
+
value = row[_column.slotPosition - 1]
|
2183
|
+
|
2184
|
+
ctype = _column.type
|
2185
|
+
value_type = _types[ctype] if ctype in _types else None
|
2186
|
+
try:
|
2187
|
+
if type(value) == float:
|
2188
|
+
value = decimal.Decimal(str(value))
|
2189
|
+
elif not _column.tableName and not _column.schema:
|
2190
|
+
pass
|
2191
|
+
elif value is None or value_type is None:
|
2192
|
+
pass
|
2193
|
+
elif issubclass(value_type, IRISStream):
|
2194
|
+
stream = value_type(self._connection, value, embedded=True)
|
2195
|
+
value = stream.fetch()
|
2196
|
+
elif not isinstance(value, value_type):
|
2197
|
+
value = value_type(value)
|
2198
|
+
except Exception as ex:
|
2199
|
+
raise ex
|
2200
|
+
pass
|
2201
|
+
row[_column.slotPosition - 1] = value
|
2202
|
+
return row
|
2203
|
+
|
2204
|
+
def fetchall(self):
|
2205
|
+
if self._result_set == None:
|
2206
|
+
raise InterfaceError("Either execute has not yet been called, or the previous call of execute did not return a result set")
|
2207
|
+
|
2208
|
+
rows = []
|
2209
|
+
while True:
|
2210
|
+
row = self.fetchone()
|
2211
|
+
if not row: break
|
2212
|
+
rows.append(row)
|
2213
|
+
return rows
|
2214
|
+
|
2215
|
+
def fetchmany(self, size = None):
|
2216
|
+
if self._result_set == None:
|
2217
|
+
raise InterfaceError("Either execute has not yet been called, or the previous call of execute did not return a result set")
|
2218
|
+
|
2219
|
+
if size is None:
|
2220
|
+
size = self.arraysize
|
2221
|
+
|
2222
|
+
rows = []
|
2223
|
+
for i in range(size):
|
2224
|
+
row = self.fetchone()
|
2225
|
+
if row is None:
|
2226
|
+
break
|
2227
|
+
rows.append(row)
|
2228
|
+
return rows
|
2229
|
+
|
2230
|
+
def nextset(self):
|
2231
|
+
raise NotImplementedErrorDBAPI()
|
2232
|
+
|
2233
|
+
|
2234
|
+
# Type Objects
|
2235
|
+
def Date(year, month, day):
|
2236
|
+
raise NotImplementedErrorDBAPI()
|
2237
|
+
|
2238
|
+
def Time(hour, minutes, second):
|
2239
|
+
raise NotImplementedErrorDBAPI()
|
2240
|
+
|
2241
|
+
def Timestamp(year, month, day, hour, minute, second):
|
2242
|
+
raise NotImplementedErrorDBAPI()
|
2243
|
+
|
2244
|
+
def DateFromTicks(ticks):
|
2245
|
+
raise NotImplementedErrorDBAPI()
|
2246
|
+
|
2247
|
+
def TimeFromTicks(ticks):
|
2248
|
+
raise NotImplementedErrorDBAPI()
|
2249
|
+
|
2250
|
+
def TimestampFromTicks(ticks):
|
2251
|
+
raise NotImplementedErrorDBAPI()
|
2252
|
+
|
2253
|
+
# def Binary(string):
|
2254
|
+
# return string
|
2255
|
+
|
2256
|
+
# Type definitions.
|
2257
|
+
Binary = bytes
|
2258
|
+
|
2259
|
+
STRING = str
|
2260
|
+
BINARY = bytes
|
2261
|
+
NUMBER = float
|
2262
|
+
ROWID = str
|
2263
|
+
|
2264
|
+
# still needs type singletons (?)
|
2265
|
+
|
2266
|
+
# Exception architecture
|
2267
|
+
class Error(Exception):
|
2268
|
+
pass
|
2269
|
+
|
2270
|
+
class Warning(Exception):
|
2271
|
+
pass
|
2272
|
+
|
2273
|
+
class InterfaceError(Error):
|
2274
|
+
pass
|
2275
|
+
|
2276
|
+
class DatabaseError(Error):
|
2277
|
+
pass
|
2278
|
+
|
2279
|
+
class InternalError(DatabaseError):
|
2280
|
+
pass
|
2281
|
+
|
2282
|
+
class OperationalError(DatabaseError):
|
2283
|
+
pass
|
2284
|
+
|
2285
|
+
class ProgrammingError(DatabaseError):
|
2286
|
+
pass
|
2287
|
+
|
2288
|
+
class IntegrityError(DatabaseError):
|
2289
|
+
pass
|
2290
|
+
|
2291
|
+
class DataError(DatabaseError):
|
2292
|
+
pass
|
2293
|
+
|
2294
|
+
class NotSupportedError(DatabaseError):
|
2295
|
+
pass
|