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.
Files changed (77) hide show
  1. intersystems_iris/_BufferReader.py +10 -0
  2. intersystems_iris/_BufferWriter.py +32 -0
  3. intersystems_iris/_ConnectionInformation.py +54 -0
  4. intersystems_iris/_ConnectionParameters.py +18 -0
  5. intersystems_iris/_Constant.py +38 -0
  6. intersystems_iris/_DBList.py +499 -0
  7. intersystems_iris/_Device.py +69 -0
  8. intersystems_iris/_GatewayContext.py +25 -0
  9. intersystems_iris/_GatewayException.py +4 -0
  10. intersystems_iris/_GatewayUtility.py +74 -0
  11. intersystems_iris/_IRIS.py +1294 -0
  12. intersystems_iris/_IRISConnection.py +516 -0
  13. intersystems_iris/_IRISEmbedded.py +85 -0
  14. intersystems_iris/_IRISGlobalNode.py +273 -0
  15. intersystems_iris/_IRISGlobalNodeView.py +25 -0
  16. intersystems_iris/_IRISIterator.py +143 -0
  17. intersystems_iris/_IRISList.py +360 -0
  18. intersystems_iris/_IRISNative.py +208 -0
  19. intersystems_iris/_IRISOREF.py +4 -0
  20. intersystems_iris/_IRISObject.py +424 -0
  21. intersystems_iris/_IRISReference.py +133 -0
  22. intersystems_iris/_InStream.py +149 -0
  23. intersystems_iris/_LegacyIterator.py +135 -0
  24. intersystems_iris/_ListItem.py +15 -0
  25. intersystems_iris/_ListReader.py +84 -0
  26. intersystems_iris/_ListWriter.py +157 -0
  27. intersystems_iris/_LogFileStream.py +115 -0
  28. intersystems_iris/_MessageHeader.py +51 -0
  29. intersystems_iris/_OutStream.py +25 -0
  30. intersystems_iris/_PrintStream.py +65 -0
  31. intersystems_iris/_PythonGateway.py +850 -0
  32. intersystems_iris/_SharedMemorySocket.py +87 -0
  33. intersystems_iris/__init__.py +79 -0
  34. intersystems_iris/__main__.py +7 -0
  35. intersystems_iris/dbapi/_Column.py +56 -0
  36. intersystems_iris/dbapi/_DBAPI.py +2295 -0
  37. intersystems_iris/dbapi/_Descriptor.py +46 -0
  38. intersystems_iris/dbapi/_IRISStream.py +63 -0
  39. intersystems_iris/dbapi/_Message.py +158 -0
  40. intersystems_iris/dbapi/_Parameter.py +138 -0
  41. intersystems_iris/dbapi/_ParameterCollection.py +133 -0
  42. intersystems_iris/dbapi/_ResultSetRow.py +314 -0
  43. intersystems_iris/dbapi/_SQLType.py +32 -0
  44. intersystems_iris/dbapi/__init__.py +0 -0
  45. intersystems_iris/dbapi/preparser/_PreParser.py +1658 -0
  46. intersystems_iris/dbapi/preparser/_Scanner.py +391 -0
  47. intersystems_iris/dbapi/preparser/_Token.py +81 -0
  48. intersystems_iris/dbapi/preparser/_TokenList.py +251 -0
  49. intersystems_iris/dbapi/preparser/__init__.py +0 -0
  50. intersystems_iris/pex/_BusinessHost.py +101 -0
  51. intersystems_iris/pex/_BusinessOperation.py +105 -0
  52. intersystems_iris/pex/_BusinessProcess.py +214 -0
  53. intersystems_iris/pex/_BusinessService.py +95 -0
  54. intersystems_iris/pex/_Common.py +228 -0
  55. intersystems_iris/pex/_Director.py +24 -0
  56. intersystems_iris/pex/_IRISBusinessOperation.py +5 -0
  57. intersystems_iris/pex/_IRISBusinessService.py +18 -0
  58. intersystems_iris/pex/_IRISInboundAdapter.py +5 -0
  59. intersystems_iris/pex/_IRISOutboundAdapter.py +17 -0
  60. intersystems_iris/pex/_InboundAdapter.py +57 -0
  61. intersystems_iris/pex/_Message.py +6 -0
  62. intersystems_iris/pex/_OutboundAdapter.py +46 -0
  63. intersystems_iris/pex/__init__.py +25 -0
  64. iris/__init__.py +25 -0
  65. iris/iris_site.py +13 -0
  66. iris/irisbuiltins.py +97 -0
  67. iris/irisloader.py +199 -0
  68. irisnative/_IRISNative.py +9 -0
  69. irisnative/__init__.py +10 -0
  70. {sqlalchemy_iris-0.5.0b3.dist-info → sqlalchemy_iris-0.6.0b1.dist-info}/METADATA +1 -1
  71. sqlalchemy_iris-0.6.0b1.dist-info/RECORD +83 -0
  72. sqlalchemy_iris-0.6.0b1.dist-info/top_level.txt +4 -0
  73. sqlalchemy_iris-0.5.0b3.dist-info/RECORD +0 -14
  74. sqlalchemy_iris-0.5.0b3.dist-info/top_level.txt +0 -1
  75. {sqlalchemy_iris-0.5.0b3.dist-info → sqlalchemy_iris-0.6.0b1.dist-info}/LICENSE +0 -0
  76. {sqlalchemy_iris-0.5.0b3.dist-info → sqlalchemy_iris-0.6.0b1.dist-info}/WHEEL +0 -0
  77. {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