iris-pex-embedded-python 2.3.17__py3-none-any.whl → 2.3.18__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.

Potentially problematic release.


This version of iris-pex-embedded-python might be problematic. Click here for more details.

@@ -1,3 +1,5 @@
1
+ import struct
2
+ import copy
1
3
  import enum
2
4
  import copy
3
5
  import decimal
@@ -10,35 +12,47 @@ from ._ResultSetRow import _ResultSetRow
10
12
  import intersystems_iris.dbapi._ParameterCollection
11
13
  import intersystems_iris.dbapi.preparser._PreParser
12
14
  from intersystems_iris.dbapi._Parameter import ParameterMode
13
- from intersystems_iris.dbapi.preparser._PreParser import StatementType
15
+ from intersystems_iris.dbapi.preparser._PreParser import StatementType, MultiValuesInsert
14
16
  from intersystems_iris._IRISConnection import Feature
15
17
  from intersystems_iris._InStream import _InStream
16
- from intersystems_iris.dbapi._IRISStream import (IRISStream, IRISBinaryStream, )
18
+ from intersystems_iris.dbapi._IRISStream import (
19
+ IRISStream,
20
+ IRISBinaryStream,
21
+ )
17
22
  from ._SQLType import SQLType
18
23
 
19
24
  from .._IRISNative import connect as native_connect
20
25
  from .._IRISEmbedded import _IRISEmbedded
21
26
 
27
+
22
28
  def NotImplementedErrorDBAPI(msg=None):
23
29
  import traceback
30
+
24
31
  if msg is None:
25
32
  traceback.print_stack()
26
33
  msg = "Coming soon to an IRIS DB API near you!"
27
34
  return NotImplementedError(msg)
28
35
 
29
- def embedded_connect(*args, hostname = None, port = None, namespace = None, username = None, password = None, **kw):
36
+
37
+ def embedded_connect(*args, hostname=None, port=None, namespace=None, username=None, password=None, **kw):
30
38
  connection = _IRISEmbedded()
31
- connection.connect(hostname, port, namespace, username, password, **kw)
39
+ connection.connect(hostname, port, namespace, username, password, **kw)
32
40
  return connection
33
41
 
34
- def connect(*args, embedded=False, hostname = None, port = None, namespace = None, username = None, password = None, **kw):
42
+
43
+ def connect(*args, embedded=False, hostname=None, port=None, namespace=None, username=None, password=None, **kw):
35
44
  try:
36
45
  if not embedded:
37
- return native_connect(*args, hostname=hostname, port=port, namespace=namespace, username=username, password=password, **kw)
46
+ return native_connect(
47
+ *args, hostname=hostname, port=port, namespace=namespace, username=username, password=password, **kw
48
+ )
38
49
  else:
39
- return embedded_connect(*args, hostname=hostname, port=port, namespace=namespace, username=username, password=password, **kw)
50
+ return embedded_connect(
51
+ *args, hostname=hostname, port=port, namespace=namespace, username=username, password=password, **kw
52
+ )
40
53
  except Exception as e:
41
- raise DatabaseError(e)
54
+ raise OperationalError(e)
55
+
42
56
 
43
57
  class ServerReturnType(enum.IntEnum):
44
58
  NO_RETURN_VALUE = 0
@@ -46,25 +60,29 @@ class ServerReturnType(enum.IntEnum):
46
60
  HAS_RETURN_VALUE = 2
47
61
  NULL_RETURN_VALUE = 3
48
62
 
63
+
49
64
  class CursorType(enum.IntEnum):
50
65
  DEFAULT = 0
51
66
  PREPARED = 1
52
67
  CALLABLE = 2
53
68
 
69
+
54
70
  # api globals, methods, classes, etc.
55
71
  # globals
56
72
  apilevel = "2.0"
57
73
  threadsafety = 0
58
74
  paramstyle = "qmark"
59
75
 
76
+
60
77
  class _BaseCursor:
61
78
  embedded = False
79
+
62
80
  def __init__(self, connection):
63
81
  self._connection = connection
64
-
82
+
65
83
  self.statement = None
66
84
  self._parsed_statement = None
67
-
85
+
68
86
  self._columns = None
69
87
  self._rowcount = -1
70
88
  self.arraysize = 1
@@ -104,7 +122,9 @@ class _BaseCursor:
104
122
 
105
123
  def __iter__(self):
106
124
  if self._result_set == None:
107
- raise InterfaceError("Either execute has not yet been called, or the previous call of execute did not return a result set")
125
+ raise InterfaceError(
126
+ "Either execute has not yet been called, or the previous call of execute did not return a result set"
127
+ )
108
128
  return self
109
129
 
110
130
  def __next__(self):
@@ -112,17 +132,17 @@ class _BaseCursor:
112
132
  if row:
113
133
  return row
114
134
  raise StopIteration
115
-
135
+
116
136
  # non-api methods and classes
117
137
  def isClosed(self):
118
- return self._closed
138
+ return self._closed
119
139
 
120
140
  def setinputsizes(self, sizes):
121
141
  raise NotImplementedErrorDBAPI()
122
142
 
123
- def setoutputsize(size, column = None):
143
+ def setoutputsize(size, column=None):
124
144
  raise NotImplementedErrorDBAPI()
125
-
145
+
126
146
  @property
127
147
  def sqlcode(self):
128
148
  if self._closed:
@@ -154,7 +174,7 @@ class _BaseCursor:
154
174
  self._params = None
155
175
  self._parsed_statement = None
156
176
  self._cursor_type = CursorType.DEFAULT
157
- self._statementType = StatementType.UPDATE # default
177
+ self._statementType = StatementType.UPDATE # default
158
178
  self._paramInfo = None
159
179
  self.statement = None
160
180
  self.statementFeatureOption = Feature.optionNone
@@ -221,12 +241,21 @@ class _BaseCursor:
221
241
 
222
242
  self.statement = operation
223
243
  if params and not isinstance(params, list) and not isinstance(params, tuple):
224
- params = (params, )
244
+ params = (params,)
225
245
  self.params = params if params is not None else ()
226
246
  self._params.set_input_params(self.params)
227
247
 
228
248
  self._cleanup()
229
- self._preparse()
249
+ try:
250
+ self._preparse()
251
+ except MultiValuesInsert as ex:
252
+ # convert to executemany
253
+ params = params or ex.params
254
+ params_count = int(len(params) / ex.rows)
255
+ new_params = [params[i : i + params_count] for i in range(0, len(params), params_count)]
256
+ return self.executemany(ex.query, new_params)
257
+ except Exception:
258
+ raise
230
259
 
231
260
  if self._statementType == StatementType.UPDATE:
232
261
  self._cursor_type = CursorType.PREPARED
@@ -239,7 +268,7 @@ class _BaseCursor:
239
268
 
240
269
  def add_batch(self):
241
270
  self._is_alive()
242
-
271
+
243
272
  if self._params._array_bound:
244
273
  if len(self._params._params_list) > 0:
245
274
  cnt = 0
@@ -252,8 +281,15 @@ class _BaseCursor:
252
281
  self._parameter_sets = cnt
253
282
  first = False
254
283
  elif self._parameter_sets != cnt:
255
- raise Exception("Unmatched columnwise parameter values: " + str(self._parameter_sets)
256
- + " rows expected, but found only " + str(cnt) +" in " + str(i) + " parameter!")
284
+ raise Exception(
285
+ "Unmatched columnwise parameter values: "
286
+ + str(self._parameter_sets)
287
+ + " rows expected, but found only "
288
+ + str(cnt)
289
+ + " in "
290
+ + str(i)
291
+ + " parameter!"
292
+ )
257
293
  if self._parameter_sets > 1:
258
294
  return
259
295
  self._parameter_sets = self._parameter_sets + 1
@@ -274,7 +310,7 @@ class _BaseCursor:
274
310
  seq_of_params = tuple(seq_of_params)
275
311
 
276
312
  self.statement = operation
277
- self.params = seq_of_params
313
+ self.params = copy.deepcopy(seq_of_params)
278
314
  self._params.set_input_params(self.params)
279
315
 
280
316
  self._cursor_type = CursorType.PREPARED
@@ -286,12 +322,12 @@ class _BaseCursor:
286
322
 
287
323
  for row_num, param_row in enumerate(seq_of_params):
288
324
  self.add_batch()
289
-
325
+
290
326
  if self._parameter_sets == 0:
291
327
  for param in self._params._params_list:
292
- if param.value == '?':
328
+ if param.value == "?":
293
329
  raise ValueError("Missing value")
294
- self._prepared_update_execute() # similar to executing a statement w/ literals
330
+ self._prepared_update_execute() # similar to executing a statement w/ literals
295
331
  return
296
332
 
297
333
  for param in self._params._params_list:
@@ -300,7 +336,7 @@ class _BaseCursor:
300
336
  raise ValueError("INOUT/OUT parameters not permitted")
301
337
 
302
338
  self._prepared_update_execute()
303
-
339
+
304
340
  return self._rowcount
305
341
 
306
342
  def _process_sqlcode(self, sqlcode, message=None):
@@ -309,11 +345,13 @@ class _BaseCursor:
309
345
  return
310
346
  if abs(sqlcode) in [108, 119, 121, 122]:
311
347
  raise IntegrityError(message)
348
+ if abs(sqlcode) in [1, 12]:
349
+ raise OperationalError(message)
312
350
  raise DatabaseError(message)
313
351
 
314
352
  def _preparse(self):
315
353
  csql = self._connection._pre_preparse_cache.get(self.statement)
316
- if csql != None:
354
+ if csql is not None:
317
355
  self._has_return_value = csql._has_return_value
318
356
  self._params = copy.deepcopy(csql._params)
319
357
  self._params.set_input_params(self.params)
@@ -328,7 +366,8 @@ class _BaseCursor:
328
366
  if not self._is_batch_update:
329
367
  raise TypeError("Unsupported argument type: " + str(type(item)))
330
368
  for ele in item:
331
- if intersystems_iris._DBList._DBList._set_switcher.get(type(ele), None) == None:
369
+ if (not intersystems_iris._DBList._DBList._set_switcher.get(type(ele), None) and not issubclass(
370
+ type(ele), enum.Enum)):
332
371
  raise TypeError("Unsupported argument type: " + str(type(ele)))
333
372
  elif intersystems_iris._DBList._DBList._set_switcher.get(type(item), None) is None:
334
373
  item = str(item)
@@ -340,9 +379,13 @@ class _BaseCursor:
340
379
  if count != curr_count:
341
380
  raise Exception("Parameter count does not match")
342
381
 
343
- parser = intersystems_iris.dbapi.preparser._PreParser._PreParser(self._connection._connection_info._delimited_ids, embedded=self.embedded)
382
+ parser = intersystems_iris.dbapi.preparser._PreParser._PreParser(
383
+ self._connection._connection_info._delimited_ids, embedded=self.embedded
384
+ )
344
385
  try:
345
386
  pOut = parser.PreParse(self.statement, self._params)
387
+ except MultiValuesInsert:
388
+ raise
346
389
  except Exception as e:
347
390
  raise InterfaceError("Error parsing statement '" + self.statement + "':\n" + str(e))
348
391
 
@@ -350,22 +393,23 @@ class _BaseCursor:
350
393
  item = self.params[0]
351
394
  if (isinstance(item, list) or isinstance(item, tuple)) and not self._is_batch_update:
352
395
  raise TypeError("Unsupported argument type: " + str(type(item)))
353
-
396
+
354
397
  self._parsed_statement = pOut.sResult
355
398
  self._statementType = pOut.p_eStmtType
356
399
  self._paramInfo = parser.m_ParamInfo
357
400
 
358
- if self._statementType == StatementType.CALL:
401
+ if self._statementType == StatementType.CALL:
359
402
  self._has_return_value = ServerReturnType.NO_RETURN_VALUE
360
- elif self._statementType == StatementType.CALLWITHRESULT:
403
+ elif self._statementType == StatementType.CALLWITHRESULT:
361
404
  self._has_return_value = ServerReturnType.HAS_RETURN_VALUE
362
405
 
363
406
  self._update_parameters()
364
407
  self._connection._add_pre_preparse_cache(self.statement, self)
365
408
 
366
409
  def _prepare(self):
367
- notDDL = bool(self._statementType != StatementType.DDL_ALTER_DROP
368
- and self._statementType != StatementType.DDL_OTHER)
410
+ notDDL = bool(
411
+ self._statementType != StatementType.DDL_ALTER_DROP and self._statementType != StatementType.DDL_OTHER
412
+ )
369
413
 
370
414
  if notDDL and self._get_cached_info():
371
415
  return
@@ -373,18 +417,18 @@ class _BaseCursor:
373
417
  self._prepare_new()
374
418
 
375
419
  def _update_parameters(self):
376
- count = self._paramInfo._list_data[0] # self._paramInfo.count()
420
+ count = self._paramInfo._list_data[0] # self._paramInfo.count()
377
421
  if count == 0:
378
422
  return
379
-
423
+
380
424
  temp_list_data = self._paramInfo._list_data[1:]
381
- param_info_count = int(len(temp_list_data)/2)
425
+ param_info_count = int(len(temp_list_data) / 2)
382
426
  if self._is_batch_update:
383
427
  unknown_count = replaced_count = 0
384
428
  for item in temp_list_data:
385
- if item == 'c':
429
+ if item == "c":
386
430
  replaced_count = replaced_count + 1
387
- elif item == '?':
431
+ elif item == "?":
388
432
  unknown_count = unknown_count + 1
389
433
 
390
434
  if len(self.params) > 0:
@@ -409,24 +453,30 @@ class _BaseCursor:
409
453
  param.mode = ParameterMode.OUTPUT
410
454
  i += 1
411
455
  return
412
-
456
+
413
457
  if len(temp_list_data) > 0:
414
458
  if count != param_info_count:
415
459
  raise Exception("Parameter mismatch")
416
460
 
417
461
  unknown_count = replaced_count = 0
418
462
  for item in temp_list_data:
419
- if item == 'c':
463
+ if item == "c":
420
464
  replaced_count = replaced_count + 1
421
- elif item == '?':
465
+ elif item == "?":
422
466
  unknown_count = unknown_count + 1
423
467
 
424
468
  if unknown_count != len(self.params):
425
- raise Exception(f"Incorrect number of parameters: {unknown_count}/{replaced_count}/{len(self.params)}")
469
+ raise Exception(
470
+ f"Incorrect number of parameters: {unknown_count}/{replaced_count}/{len(self.params)}"
471
+ )
426
472
 
427
473
  def _is_not_default_or_replaced(self, param):
428
474
  mode = param.mode
429
- if mode != ParameterMode.REPLACED_LITERAL and mode != ParameterMode.DEFAULT_PARAMETER and mode != ParameterMode.INPUT:
475
+ if (
476
+ mode != ParameterMode.REPLACED_LITERAL
477
+ and mode != ParameterMode.DEFAULT_PARAMETER
478
+ and mode != ParameterMode.INPUT
479
+ ):
430
480
  raise Exception("Parameters not allowed in Cursor class")
431
481
 
432
482
  def _validate_parameters(self):
@@ -439,7 +489,10 @@ class _BaseCursor:
439
489
  if self._parameter_list_mismatch_exception and not self._params._has_bound_by_param_name:
440
490
  raise Exception("Parameter list mismatch")
441
491
  i = 0
442
- if self._has_return_value == ServerReturnType.IGNORE_RETURN_VALUE or self._has_return_value == ServerReturnType.NULL_RETURN_VALUE:
492
+ if (
493
+ self._has_return_value == ServerReturnType.IGNORE_RETURN_VALUE
494
+ or self._has_return_value == ServerReturnType.NULL_RETURN_VALUE
495
+ ):
443
496
  i = 1
444
497
  for param in self._params._params_list:
445
498
  if i == 1:
@@ -463,14 +516,14 @@ class _BaseCursor:
463
516
  StatementType.STMT_USE: self._execute_update,
464
517
  StatementType.UPDATE: self._execute_update,
465
518
  StatementType.DDL_OTHER: self._execute_update,
466
- StatementType.DDL_ALTER_DROP: self._execute_update
519
+ StatementType.DDL_ALTER_DROP: self._execute_update,
467
520
  }
468
521
  exec_func = exec_switcher.get(self._statementType, None)
469
522
  if exec_func is None:
470
- raise NotImplementedErrorDBAPI(f'StatementType {self._statementType.name} not implemented')
523
+ raise NotImplementedErrorDBAPI(f"StatementType {self._statementType.name} not implemented")
471
524
  else:
472
525
  return exec_func()
473
-
526
+
474
527
  def _prepare_stored_procedure(self):
475
528
  if self._get_cached_info():
476
529
  self._prepared_stored_procedure_execute()
@@ -517,20 +570,22 @@ class _BaseCursor:
517
570
  # not found in client side cache - send DQ message
518
571
  self._send_direct_query_request()
519
572
  else:
520
- if (self._statementType != StatementType.QUERY and
521
- self._statementType != StatementType.PREPARED_CALL_QUERY and
522
- self._statementType != StatementType.DIRECT_CALL_QUERY):
573
+ if (
574
+ self._statementType != StatementType.QUERY
575
+ and self._statementType != StatementType.PREPARED_CALL_QUERY
576
+ and self._statementType != StatementType.DIRECT_CALL_QUERY
577
+ ):
523
578
  raise Exception("Not a query")
524
-
579
+
525
580
  if self._exec_params != None:
526
581
  self._bind_exec_params()
527
582
  self._validate_prepared_parameters()
528
-
583
+
529
584
  if self.statementFeatureOption & Feature.optionFastSelect == Feature.optionFastSelect:
530
585
  self._rsrow = _ResultSetRow(self._connection, self._columns, self.maxRowItemCount)
531
586
  else:
532
587
  self._rsrow = _ResultSetRow(self._connection, self._columns, 0)
533
-
588
+
534
589
  if self._cursor_type == CursorType.CALLABLE or self._statementType == StatementType.PREPARED_CALL_QUERY:
535
590
  self._stored_procedure_query()
536
591
  return
@@ -558,8 +613,9 @@ class _BaseCursor:
558
613
  raise Exception("Not an update")
559
614
  return
560
615
 
561
- notDDL = bool(self._statementType != StatementType.DDL_ALTER_DROP
562
- and self._statementType != StatementType.DDL_OTHER)
616
+ notDDL = bool(
617
+ self._statementType != StatementType.DDL_ALTER_DROP and self._statementType != StatementType.DDL_OTHER
618
+ )
563
619
 
564
620
  if notDDL and self._get_cached_info():
565
621
  # found in client side cache - send PU message
@@ -570,19 +626,21 @@ class _BaseCursor:
570
626
  else:
571
627
  if self._statementType == StatementType.QUERY or self._statementType == StatementType.PREPARED_CALL_QUERY:
572
628
  raise Exception("Not an update")
573
-
629
+
574
630
  if self._exec_params != None:
575
631
  self._bind_exec_params()
576
632
  self._validate_prepared_parameters()
577
-
578
- if (self._cursor_type == CursorType.CALLABLE or
579
- self._statementType == StatementType.PREPARED_CALL_UPDATE or
580
- self._statementType == StatementType.DIRECT_CALL_UPDATE):
633
+
634
+ if (
635
+ self._cursor_type == CursorType.CALLABLE
636
+ or self._statementType == StatementType.PREPARED_CALL_UPDATE
637
+ or self._statementType == StatementType.DIRECT_CALL_UPDATE
638
+ ):
581
639
  self._stored_procedure_update()
582
640
  return
583
641
 
584
642
  self._prepared_update_execute()
585
-
643
+
586
644
  def _query404(self):
587
645
  with self._connection._lock:
588
646
  self._validate_parameters()
@@ -596,36 +654,46 @@ class _BaseCursor:
596
654
  # api properties and methods
597
655
  @property
598
656
  def description(self):
599
- if self._columns == None:
657
+ if self._statementType is StatementType.UPDATE:
658
+ return None
659
+
660
+ if self._columns is None:
600
661
  return None
601
662
 
602
- Column = namedtuple("Column", [
603
- 'name',
604
- 'type_code',
605
- 'display_size',
606
- 'internal_size',
607
- 'precision',
608
- 'scale',
609
- 'null_ok',
610
- ])
663
+ Column = namedtuple(
664
+ "Column",
665
+ [
666
+ "name",
667
+ "type_code",
668
+ "display_size",
669
+ "internal_size",
670
+ "precision",
671
+ "scale",
672
+ "null_ok",
673
+ ],
674
+ )
611
675
 
612
676
  sequence = []
613
- for column in self._columns: sequence.append(Column(
614
- column.name,
615
- column.type,
616
- None,
617
- None,
618
- column.precision,
619
- column.scale,
620
- column.nullable,
621
- ))
677
+ for column in self._columns:
678
+ sequence.append(
679
+ Column(
680
+ column.name,
681
+ column.type,
682
+ None,
683
+ None,
684
+ column.precision,
685
+ column.scale,
686
+ column.nullable,
687
+ )
688
+ )
622
689
  return tuple(sequence)
623
-
690
+
624
691
  # currently doesn't work for queries
625
692
  @property
626
693
  def rowcount(self):
627
694
  return self._rowcount
628
695
 
696
+
629
697
  # Cursor class
630
698
  class Cursor(_BaseCursor):
631
699
  def __init__(self, connection):
@@ -646,7 +714,7 @@ class Cursor(_BaseCursor):
646
714
  self._cursor_ptr = 0
647
715
  self._scroll_flag = False
648
716
  self._warehouse = list()
649
-
717
+
650
718
  self._warehouse_dict = dict()
651
719
  self._last_row_in_warehouse_dict = -1
652
720
  self._warehouse_dict_keys = list()
@@ -677,7 +745,7 @@ class Cursor(_BaseCursor):
677
745
  super()._process_sqlcode(sqlcode, self._get_error_info(sqlcode))
678
746
 
679
747
  def _get_cached_info(self):
680
- if not self._connection._preparedCache or not hasattr(self._connection._preparedCache, '__iter__'):
748
+ if not self._connection._preparedCache or not hasattr(self._connection._preparedCache, "__iter__"):
681
749
  return False
682
750
  if self._parsed_statement in self._connection._preparedCache:
683
751
  self._prepare_cached(self._connection._preparedCache[self._parsed_statement])
@@ -690,17 +758,21 @@ class Cursor(_BaseCursor):
690
758
 
691
759
  if self._statementType == StatementType.CALL or self._statementType == StatementType.CALLWITHRESULT:
692
760
  if len(self._params._params_list) != len(cached_statement._params._params_list):
693
- if (self._statementType == StatementType.CALL and
694
- self._has_return_value == 0 and
695
- cached_statement._has_return_value == 1 and
696
- len(self._params._params_list) + 1 == len(cached_statement._params._params_list)):
697
- self._params._params_list.insert(0, intersystems_iris.dbapi._Parameter._Parameter(None, ParameterMode.OUTPUT, 'c'))
761
+ if (
762
+ self._statementType == StatementType.CALL
763
+ and self._has_return_value == 0
764
+ and cached_statement._has_return_value == 1
765
+ and len(self._params._params_list) + 1 == len(cached_statement._params._params_list)
766
+ ):
767
+ self._params._params_list.insert(
768
+ 0, intersystems_iris.dbapi._Parameter._Parameter(None, ParameterMode.OUTPUT, "c")
769
+ )
698
770
  else:
699
771
  if len(self._params._params_list) == 0 or len(self._params._params_list) == 1:
700
772
  self._params._clear()
701
773
  else:
702
774
  return False
703
-
775
+
704
776
  if cached_statement._statementType == StatementType.QUERY:
705
777
  self._statementType = StatementType.PREPARED_CALL_QUERY
706
778
  else:
@@ -713,8 +785,10 @@ class Cursor(_BaseCursor):
713
785
  self._multiple_result_sets = cached_statement.multiple_result_sets
714
786
  self._mrs_done = False
715
787
 
716
- if (not self._multiple_result_sets and
717
- (self._statementType in [StatementType.QUERY, StatementType.PREPARED_CALL_QUERY, StatementType.DIRECT_CALL_QUERY])):
788
+ if not self._multiple_result_sets and (
789
+ self._statementType
790
+ in [StatementType.QUERY, StatementType.PREPARED_CALL_QUERY, StatementType.DIRECT_CALL_QUERY]
791
+ ):
718
792
  self._columns = []
719
793
  for column in cached_statement.columns:
720
794
  self._columns.append(column.Clone())
@@ -741,19 +815,21 @@ class Cursor(_BaseCursor):
741
815
  self.maxRowItemCount = cached_statement.maxRowItemCount
742
816
  if hasattr(cached_statement, "_params"):
743
817
  self._params._update_param_info(cached_statement._params)
744
-
818
+
745
819
  def _prepare_new(self):
746
820
  # send PP message
747
821
  with self._connection._lock:
748
822
  # message header
749
823
  self._statement_id = self._connection._get_new_statement_id()
750
824
  self._out_message.wire._write_header(_Message.PREPARE)
751
- intersystems_iris._MessageHeader._MessageHeader._set_statement_id(self._out_message.wire.buffer, self._statement_id)
825
+ intersystems_iris._MessageHeader._MessageHeader._set_statement_id(
826
+ self._out_message.wire.buffer, self._statement_id
827
+ )
752
828
 
753
829
  # message body
754
- self._out_message.wire._set(1) # number of statement chunks
755
- self._out_message.wire._set(self._parsed_statement) # statement itself
756
- self._out_message.wire._set_raw_bytes(self._paramInfo.getBuffer()) # paramInfo (from _PreParser)
830
+ self._out_message.wire._set(1) # number of statement chunks
831
+ self._out_message.wire._set(self._parsed_statement) # statement itself
832
+ self._out_message.wire._set_raw_bytes(self._paramInfo.getBuffer()) # paramInfo (from _PreParser)
757
833
 
758
834
  # send message
759
835
  sequence_number = self._connection._get_new_sequence_number()
@@ -789,7 +865,7 @@ class Cursor(_BaseCursor):
789
865
  with self._connection._lock:
790
866
  self._out_message.wire._write_header(_Message.GET_SERVER_ERROR)
791
867
  self._out_message.wire._set(sqlcode)
792
-
868
+
793
869
  sequence_number = self._connection._get_new_sequence_number()
794
870
  self._out_message._send(sequence_number)
795
871
 
@@ -798,7 +874,10 @@ class Cursor(_BaseCursor):
798
874
 
799
875
  def _check_statement_feature(self, wire):
800
876
  self.statementFeatureOption = wire._get()
801
- if self.statementFeatureOption == Feature.optionFastSelect or self.statementFeatureOption == Feature.optionFastInsert:
877
+ if (
878
+ self.statementFeatureOption == Feature.optionFastSelect
879
+ or self.statementFeatureOption == Feature.optionFastInsert
880
+ ):
802
881
  self.maxRowItemCount = wire._get()
803
882
  else:
804
883
  self.maxRowItemCount = 0
@@ -819,15 +898,33 @@ class Cursor(_BaseCursor):
819
898
  if catalog == 0:
820
899
  catalog = None
821
900
  additionalData = wire._get().encode()
822
- slotPosition = wire._get() if self.statementFeatureOption & Feature.optionFastSelect == Feature.optionFastSelect else i + 1
823
- self._columns.append(intersystems_iris.dbapi._Column._Column(name, type, precision, scale, nullable, label, tableName, schema, catalog, additionalData, slotPosition))
901
+ slotPosition = (
902
+ wire._get()
903
+ if self.statementFeatureOption & Feature.optionFastSelect == Feature.optionFastSelect
904
+ else i + 1
905
+ )
906
+ self._columns.append(
907
+ intersystems_iris.dbapi._Column._Column(
908
+ name,
909
+ type,
910
+ precision,
911
+ scale,
912
+ nullable,
913
+ label,
914
+ tableName,
915
+ schema,
916
+ catalog,
917
+ additionalData,
918
+ slotPosition,
919
+ )
920
+ )
824
921
 
825
922
  def _get_parameter_info(self, wire):
826
923
  count = wire._get()
827
924
  if count != len(self._params._params_list):
828
925
  raise Exception("Invalid number of parameters")
829
926
  self._read_parameter_data(wire, count, False)
830
-
927
+
831
928
  addToCache = bool(wire._get())
832
929
  return addToCache
833
930
 
@@ -851,7 +948,7 @@ class Cursor(_BaseCursor):
851
948
 
852
949
  if self.statementFeatureOption & Feature.optionFastInsert == Feature.optionFastInsert:
853
950
  param.slotPosition = wire._get()
854
- self.rowOfDefaultValues = wire._get() # needs to be processed
951
+ self.rowOfDefaultValues = wire._get() # needs to be processed
855
952
  else:
856
953
  param.slotPosition = i + r
857
954
 
@@ -868,7 +965,6 @@ class Cursor(_BaseCursor):
868
965
  if self._parameter_sets == 0 and not self._multiple_result_sets:
869
966
  self._rowcount = self._in_message.wire._get()
870
967
 
871
-
872
968
  class prepared_statement(intersystems_iris._IRISConnection.CachedSQL):
873
969
  def __init__(self, cursor):
874
970
  if not isinstance(cursor, Cursor):
@@ -896,8 +992,8 @@ class Cursor(_BaseCursor):
896
992
  def _write_parameters(self):
897
993
  sets = self._parameter_sets or 1
898
994
 
899
- self._out_message.wire._set(sets) # nParamSets
900
- self._out_message.wire._set(len(self._params._params_list)) # nParams
995
+ self._out_message.wire._set(sets) # nParamSets
996
+ self._out_message.wire._set(len(self._params._params_list)) # nParams
901
997
  for i in range(sets):
902
998
  param_index = 0
903
999
  param_counter = i
@@ -926,12 +1022,14 @@ class Cursor(_BaseCursor):
926
1022
  with self._connection._lock:
927
1023
  # message header
928
1024
  self._out_message.wire._write_header(_Message.PREPARED_QUERY_EXECUTE)
929
- intersystems_iris._MessageHeader._MessageHeader._set_statement_id(self._out_message.wire.buffer, self._statement_id)
1025
+ intersystems_iris._MessageHeader._MessageHeader._set_statement_id(
1026
+ self._out_message.wire.buffer, self._statement_id
1027
+ )
930
1028
 
931
1029
  # message body
932
1030
  self._write_parameters()
933
- self._out_message.wire._set(0) # query timeout
934
- self._out_message.wire._set(0) # maxRows (0 = all rows)
1031
+ self._out_message.wire._set(0) # query timeout
1032
+ self._out_message.wire._set(0) # maxRows (0 = all rows)
935
1033
 
936
1034
  # send
937
1035
  sequence_number = self._connection._get_new_sequence_number()
@@ -948,7 +1046,7 @@ class Cursor(_BaseCursor):
948
1046
  self._current_wire = self._in_message.wire
949
1047
  self._result_set = [self._current_wire]
950
1048
  self._rs_index = 0
951
-
1049
+
952
1050
  self._rowcount = -1
953
1051
 
954
1052
  def _send_direct_stored_procedure_request(self):
@@ -958,13 +1056,15 @@ class Cursor(_BaseCursor):
958
1056
  # message header
959
1057
  self._statement_id = self._connection._get_new_statement_id()
960
1058
  self._out_message.wire._write_header(_Message.DIRECT_STORED_PROCEDURE)
961
- intersystems_iris._MessageHeader._MessageHeader._set_statement_id(self._out_message.wire.buffer, self._statement_id)
1059
+ intersystems_iris._MessageHeader._MessageHeader._set_statement_id(
1060
+ self._out_message.wire.buffer, self._statement_id
1061
+ )
962
1062
 
963
1063
  # message body
964
- self._out_message.wire._set(self._parsed_statement) # statement itself
965
- self._out_message.wire._set(0) # resultSetType != ResultSet.TYPE_SCROLL_INSENSITIVE
966
- self._out_message.wire._set(0) # query timeout
967
- self._out_message.wire._set(0) # maxRows (0 = all rows)
1064
+ self._out_message.wire._set(self._parsed_statement) # statement itself
1065
+ self._out_message.wire._set(0) # resultSetType != ResultSet.TYPE_SCROLL_INSENSITIVE
1066
+ self._out_message.wire._set(0) # query timeout
1067
+ self._out_message.wire._set(0) # maxRows (0 = all rows)
968
1068
  self._write_stored_procedure_parameters()
969
1069
 
970
1070
  # send
@@ -985,21 +1085,26 @@ class Cursor(_BaseCursor):
985
1085
 
986
1086
  self._cache_prepared_statement()
987
1087
 
988
- if self._statementType in [StatementType.UPDATE, StatementType.DIRECT_CALL_UPDATE, StatementType.PREPARED_CALL_UPDATE]:
1088
+ if self._statementType in [
1089
+ StatementType.UPDATE,
1090
+ StatementType.DIRECT_CALL_UPDATE,
1091
+ StatementType.PREPARED_CALL_UPDATE,
1092
+ ]:
989
1093
  return False
990
1094
 
991
1095
  except IndexError:
992
1096
  raise DatabaseError("Server response message terminated prematurely")
993
1097
  except TypeError:
994
1098
  raise DatabaseError("Unexpected server response message format")
995
-
1099
+
996
1100
  def _prepared_stored_procedure_execute(self):
997
1101
  # send SU message
998
1102
  with self._connection._lock:
999
1103
  # message header
1000
1104
  self._out_message.wire._write_header(_Message.PREPARED_UPDATE_EXECUTE)
1001
- intersystems_iris._MessageHeader._MessageHeader._set_statement_id(self._out_message.wire.buffer, self._statement_id)
1002
-
1105
+ intersystems_iris._MessageHeader._MessageHeader._set_statement_id(
1106
+ self._out_message.wire.buffer, self._statement_id
1107
+ )
1003
1108
 
1004
1109
  def _send_direct_query_request(self):
1005
1110
  # send DQ message
@@ -1007,15 +1112,17 @@ class Cursor(_BaseCursor):
1007
1112
  # message header
1008
1113
  self._statement_id = self._connection._get_new_statement_id()
1009
1114
  self._out_message.wire._write_header(_Message.DIRECT_QUERY)
1010
- intersystems_iris._MessageHeader._MessageHeader._set_statement_id(self._out_message.wire.buffer, self._statement_id)
1115
+ intersystems_iris._MessageHeader._MessageHeader._set_statement_id(
1116
+ self._out_message.wire.buffer, self._statement_id
1117
+ )
1011
1118
 
1012
1119
  # message body
1013
- self._out_message.wire._set(1) # number of statement chunks
1014
- self._out_message.wire._set(self._parsed_statement) # statement itself
1015
- self._out_message.wire._set_raw_bytes(self._paramInfo.getBuffer()) # paramInfo (from _PreParser)
1120
+ self._out_message.wire._set(1) # number of statement chunks
1121
+ self._out_message.wire._set(self._parsed_statement) # statement itself
1122
+ self._out_message.wire._set_raw_bytes(self._paramInfo.getBuffer()) # paramInfo (from _PreParser)
1016
1123
  self._write_parameters()
1017
- self._out_message.wire._set(0) # query timeout
1018
- self._out_message.wire._set(0) # maxRows (0 = all rows)
1124
+ self._out_message.wire._set(0) # query timeout
1125
+ self._out_message.wire._set(0) # maxRows (0 = all rows)
1019
1126
 
1020
1127
  # send
1021
1128
  sequence_number = self._connection._get_new_sequence_number()
@@ -1049,24 +1156,83 @@ class Cursor(_BaseCursor):
1049
1156
  self._current_wire = self._in_message.wire
1050
1157
  self._result_set = [self._current_wire]
1051
1158
  self._rs_index = 0
1052
-
1159
+
1053
1160
  self._rowcount = -1
1054
1161
  if self.statementFeatureOption & Feature.optionFastSelect == Feature.optionFastSelect:
1055
1162
  self._rsrow = _ResultSetRow(self._connection, self._columns, self.maxRowItemCount)
1056
1163
  else:
1057
1164
  self._rsrow = _ResultSetRow(self._connection, self._columns, 0)
1165
+
1166
+ def _update_streams(self):
1167
+ sets = self._parameter_sets or 1
1168
+ self.params = list(self.params).copy()
1169
+ param_types = [param.type for param in self._params._params_list]
1058
1170
 
1171
+ for i in range(sets):
1172
+ params = self._params.collect(i)
1173
+ for pi, param in enumerate(params):
1174
+ if param_types[pi] in (SQLType.LONGVARBINARY, SQLType.LONGVARCHAR) and param is not None:
1175
+ stream_oref = self._send_stream(param_types[pi], param)
1176
+ if isinstance(self.params[i], tuple):
1177
+ self.params[i] = list(self.params[i])
1178
+ if isinstance(self.params[i], list):
1179
+ self.params[i][pi] = stream_oref
1180
+ else:
1181
+ self.params[pi] = stream_oref
1182
+
1183
+ def _send_stream(self, param_type, value):
1184
+ if not isinstance(value, str) and not isinstance(value, bytes):
1185
+ raise Exception(f"Invalid value type for stream, got {type(value).__name__}, expected str or bytes")
1186
+ stream_oref = None
1187
+ offset = 0
1188
+ full_size = len(value)
1189
+ with self._connection._lock:
1190
+ while True:
1191
+ size = full_size
1192
+ if size == 0:
1193
+ break
1194
+ size = 4096 if size > 4096 else size
1195
+ chunk = value[offset:offset + size]
1196
+ if not isinstance(chunk, bytes):
1197
+ chunk = bytes(chunk, "utf-8")
1198
+ offset += size
1199
+ full_size -= size
1200
+
1201
+ # message header
1202
+ code = _Message.STORE_BINARY_STREAM if param_type == SQLType.LONGVARBINARY else _Message.STORE_CHARACTER_STREAM
1203
+ self._out_message.wire._write_header(code)
1204
+ intersystems_iris._MessageHeader._MessageHeader._set_statement_id(
1205
+ self._out_message.wire.buffer, self._statement_id
1206
+ )
1207
+ # message body
1208
+ self._out_message.wire._set(stream_oref or "0")
1209
+ self._out_message.wire._set_raw_bytes(struct.pack("<i", size))
1210
+ self._out_message.wire._set_raw_bytes(chunk)
1211
+
1212
+ # send
1213
+ sequence_number = self._connection._get_new_sequence_number()
1214
+ self._out_message._send(sequence_number)
1215
+
1216
+ self._in_message._read_message_sql(sequence_number, self._statement_id, 0)
1217
+ stream_oref = self._sqlcode = self._in_message.wire._get()
1218
+
1219
+ return stream_oref
1220
+
1059
1221
  def _prepared_update_execute(self):
1222
+ self._update_streams()
1223
+
1060
1224
  # send PU message
1061
1225
  with self._connection._lock:
1062
1226
  # message header
1063
1227
  self._out_message.wire._write_header(_Message.PREPARED_UPDATE_EXECUTE)
1064
- intersystems_iris._MessageHeader._MessageHeader._set_statement_id(self._out_message.wire.buffer, self._statement_id)
1228
+ intersystems_iris._MessageHeader._MessageHeader._set_statement_id(
1229
+ self._out_message.wire.buffer, self._statement_id
1230
+ )
1065
1231
 
1066
1232
  # message body
1067
1233
  self._lastrowid = None
1068
- self._out_message.wire._set(-1) # autoGeneratedKeyColumn
1069
- self._out_message.wire._set(0) # statement timeout always 0 for non-queries
1234
+ self._out_message.wire._set(-1) # autoGeneratedKeyColumn
1235
+ self._out_message.wire._set(0) # statement timeout always 0 for non-queries
1070
1236
  self._write_parameters()
1071
1237
 
1072
1238
  # send
@@ -1087,15 +1253,17 @@ class Cursor(_BaseCursor):
1087
1253
  self._statement_id = self._connection._get_new_statement_id()
1088
1254
  # message header
1089
1255
  self._out_message.wire._write_header(_Message.DIRECT_UPDATE)
1090
- intersystems_iris._MessageHeader._MessageHeader._set_statement_id(self._out_message.wire.buffer, self._statement_id)
1256
+ intersystems_iris._MessageHeader._MessageHeader._set_statement_id(
1257
+ self._out_message.wire.buffer, self._statement_id
1258
+ )
1091
1259
 
1092
1260
  # message body
1093
1261
  self._lastrowid = None
1094
- self._out_message.wire._set(1) # number of statement chunks
1095
- self._out_message.wire._set(self._parsed_statement) # statement itself
1096
- self._out_message.wire._set_raw_bytes(self._paramInfo.getBuffer()) # paramInfo (from _PreParser)
1097
- self._out_message.wire._set(-1) # autoGeneratedKeyColumn
1098
- self._out_message.wire._set(0) # statement timeout always 0 for non-queries
1262
+ self._out_message.wire._set(1) # number of statement chunks
1263
+ self._out_message.wire._set(self._parsed_statement) # statement itself
1264
+ self._out_message.wire._set_raw_bytes(self._paramInfo.getBuffer()) # paramInfo (from _PreParser)
1265
+ self._out_message.wire._set(-1) # autoGeneratedKeyColumn
1266
+ self._out_message.wire._set(0) # statement timeout always 0 for non-queries
1099
1267
  self._write_parameters()
1100
1268
 
1101
1269
  # send
@@ -1109,9 +1277,11 @@ class Cursor(_BaseCursor):
1109
1277
  self._process_sqlcode(self._sqlcode)
1110
1278
 
1111
1279
  addToCache = self._get_parameter_info(self._in_message.wire)
1112
-
1113
- notDDL = bool(self._statementType != StatementType.DDL_ALTER_DROP
1114
- and self._statementType != StatementType.DDL_OTHER)
1280
+
1281
+ notDDL = bool(
1282
+ self._statementType != StatementType.DDL_ALTER_DROP
1283
+ and self._statementType != StatementType.DDL_OTHER
1284
+ )
1115
1285
  if notDDL and addToCache:
1116
1286
  self._cache_prepared_statement()
1117
1287
 
@@ -1125,12 +1295,14 @@ class Cursor(_BaseCursor):
1125
1295
  # message header
1126
1296
  self._statement_id = self._connection._get_new_statement_id()
1127
1297
  self._out_message.wire._write_header(_Message.PREPARE_STORED_PROCEDURE)
1128
- intersystems_iris._MessageHeader._MessageHeader._set_statement_id(self._out_message.wire.buffer, self._statement_id)
1298
+ intersystems_iris._MessageHeader._MessageHeader._set_statement_id(
1299
+ self._out_message.wire.buffer, self._statement_id
1300
+ )
1129
1301
 
1130
1302
  # message body
1131
- #self._out_message.wire._set(1) # number of statement chunks
1132
- self._out_message.wire._set(self._parsed_statement) # statement itself
1133
-
1303
+ # self._out_message.wire._set(1) # number of statement chunks
1304
+ self._out_message.wire._set(self._parsed_statement) # statement itself
1305
+
1134
1306
  # send message
1135
1307
  sequence_number = self._connection._get_new_sequence_number()
1136
1308
  self._out_message._send(sequence_number)
@@ -1209,11 +1381,20 @@ class Cursor(_BaseCursor):
1209
1381
  self._has_return_value = ServerReturnType.HAS_RETURN_VALUE
1210
1382
  elif not server_has_return and self._has_return_value == ServerReturnType.NO_RETURN_VALUE:
1211
1383
  self._has_return_value = ServerReturnType.NO_RETURN_VALUE
1212
- elif (size == 1 and count == 1
1213
- and (self._params._params_list[0].mode == ParameterMode.DEFAULT_PARAMETER
1214
- and self._has_return_value == ServerReturnType.NO_RETURN_VALUE and server_has_return)
1215
- or (self._params._params_list[0].mode == ParameterMode.UNKNOWN
1216
- and self._has_return_value == ServerReturnType.IGNORE_RETURN_VALUE and server_has_return)):
1384
+ elif (
1385
+ size == 1
1386
+ and count == 1
1387
+ and (
1388
+ self._params._params_list[0].mode == ParameterMode.DEFAULT_PARAMETER
1389
+ and self._has_return_value == ServerReturnType.NO_RETURN_VALUE
1390
+ and server_has_return
1391
+ )
1392
+ or (
1393
+ self._params._params_list[0].mode == ParameterMode.UNKNOWN
1394
+ and self._has_return_value == ServerReturnType.IGNORE_RETURN_VALUE
1395
+ and server_has_return
1396
+ )
1397
+ ):
1217
1398
  self._params._params_list.pop(0)
1218
1399
  self._params._params_list.insert(0, intersystems_iris.dbapi._Parameter._Parameter())
1219
1400
  self._has_return_value = ServerReturnType.IGNORE_RETURN_VALUE
@@ -1245,7 +1426,9 @@ class Cursor(_BaseCursor):
1245
1426
  self._params._params_list.insert(0, intersystems_iris.dbapi._Parameter._Parameter())
1246
1427
  self._has_return_value = ServerReturnType.IGNORE_RETURN_VALUE
1247
1428
  else:
1248
- self._params._params_list.append(intersystems_iris.dbapi._Parameter._Parameter(ParameterMode.DEFAULT_PARAMETER, 'c'))
1429
+ self._params._params_list.append(
1430
+ intersystems_iris.dbapi._Parameter._Parameter(ParameterMode.DEFAULT_PARAMETER, "c")
1431
+ )
1249
1432
  else:
1250
1433
  self._parameter_list_mismatch_exception = True
1251
1434
  if server_has_return and self._has_return_value == ServerReturnType.NO_RETURN_VALUE:
@@ -1255,7 +1438,9 @@ class Cursor(_BaseCursor):
1255
1438
  self._params._params_list.insert(0, param)
1256
1439
  size = size + 1
1257
1440
  while size < count:
1258
- self._params._params_list.append(intersystems_iris.dbapi._Parameter._Parameter(ParameterMode.DEFAULT_PARAMETER, 'c'))
1441
+ self._params._params_list.append(
1442
+ intersystems_iris.dbapi._Parameter._Parameter(ParameterMode.DEFAULT_PARAMETER, "c")
1443
+ )
1259
1444
  size = size + 1
1260
1445
  self._read_parameter_data(wire, count, True)
1261
1446
  return True
@@ -1287,12 +1472,14 @@ class Cursor(_BaseCursor):
1287
1472
  with self._connection._lock:
1288
1473
  # message header
1289
1474
  self._out_message.wire._write_header(_Message.STORED_PROCEDURE_UPDATE_EXECUTE)
1290
- intersystems_iris._MessageHeader._MessageHeader._set_statement_id(self._out_message.wire.buffer, self._statement_id)
1475
+ intersystems_iris._MessageHeader._MessageHeader._set_statement_id(
1476
+ self._out_message.wire.buffer, self._statement_id
1477
+ )
1291
1478
 
1292
1479
  # message body
1293
- self._out_message.wire._set(0) # isStatic should always be 0 for non-queries
1294
- self._out_message.wire._set(0) # query timeout
1295
- self._out_message.wire._set(0) # maxRows (0 = all rows)
1480
+ self._out_message.wire._set(0) # isStatic should always be 0 for non-queries
1481
+ self._out_message.wire._set(0) # query timeout
1482
+ self._out_message.wire._set(0) # maxRows (0 = all rows)
1296
1483
  self._write_stored_procedure_parameters()
1297
1484
 
1298
1485
  # send
@@ -1316,12 +1503,14 @@ class Cursor(_BaseCursor):
1316
1503
  with self._connection._lock:
1317
1504
  # message header
1318
1505
  self._out_message.wire._write_header(_Message.STORED_PROCEDURE_QUERY_EXECUTE)
1319
- intersystems_iris._MessageHeader._MessageHeader._set_statement_id(self._out_message.wire.buffer, self._statement_id)
1506
+ intersystems_iris._MessageHeader._MessageHeader._set_statement_id(
1507
+ self._out_message.wire.buffer, self._statement_id
1508
+ )
1320
1509
 
1321
1510
  # message body
1322
- self._out_message.wire._set(0) # ResultSet.TYPE_SCROLL_INSENSITIVE
1323
- self._out_message.wire._set(0) # query timeout
1324
- self._out_message.wire._set(0) # maxRows (0 = all rows)
1511
+ self._out_message.wire._set(0) # ResultSet.TYPE_SCROLL_INSENSITIVE
1512
+ self._out_message.wire._set(0) # query timeout
1513
+ self._out_message.wire._set(0) # maxRows (0 = all rows)
1325
1514
  self._write_stored_procedure_parameters()
1326
1515
 
1327
1516
  # send
@@ -1354,8 +1543,8 @@ class Cursor(_BaseCursor):
1354
1543
  self._validate_parameters()
1355
1544
  with self._connection._lock:
1356
1545
  self._out_message.wire._write_header(_Message.EXECUTE_MULTIPLE_RESULT_SETS)
1357
- self._out_message.wire._set(0) # resultSetType != ResultSet.TYPE_SCROLL_INSENSITIVE
1358
- self._out_message.wire._set(0) # query timeout
1546
+ self._out_message.wire._set(0) # resultSetType != ResultSet.TYPE_SCROLL_INSENSITIVE
1547
+ self._out_message.wire._set(0) # query timeout
1359
1548
  self._write_stored_procedure_parameters()
1360
1549
 
1361
1550
  # send
@@ -1378,7 +1567,7 @@ class Cursor(_BaseCursor):
1378
1567
  self._rs_index = 0
1379
1568
 
1380
1569
  results = self._in_message.wire._get()
1381
- if results >= 0 :
1570
+ if results >= 0:
1382
1571
  self._update_cnt = results
1383
1572
  return False
1384
1573
  elif results == -1:
@@ -1386,7 +1575,7 @@ class Cursor(_BaseCursor):
1386
1575
  elif results == -2:
1387
1576
  self._update_cnt = -1
1388
1577
  self._mrs_done = True
1389
- #self._rsrow._is_after_last = True
1578
+ # self._rsrow._is_after_last = True
1390
1579
  return False
1391
1580
  else:
1392
1581
  raise Exception("Invalid result type value")
@@ -1435,7 +1624,11 @@ class Cursor(_BaseCursor):
1435
1624
  if i == 1:
1436
1625
  i = 0
1437
1626
  continue
1438
- if param.mode == ParameterMode.INPUT_OUTPUT or param.mode == ParameterMode.OUTPUT or param.mode == ParameterMode.RETURN_VALUE:
1627
+ if (
1628
+ param.mode == ParameterMode.INPUT_OUTPUT
1629
+ or param.mode == ParameterMode.OUTPUT
1630
+ or param.mode == ParameterMode.RETURN_VALUE
1631
+ ):
1439
1632
  wire._next_unless_undefined()
1440
1633
  else:
1441
1634
  wire._next()
@@ -1445,7 +1638,9 @@ class Cursor(_BaseCursor):
1445
1638
  else:
1446
1639
  self._output_parameter_list = wire._get_output_parameter_list(beg, False)
1447
1640
  if self._statementType not in [StatementType.DIRECT_CALL_UPDATE]:
1448
- self._params._prep_list_index(False, self._output_parameter_list) # fast select not supported for stored procedures
1641
+ self._params._prep_list_index(
1642
+ False, self._output_parameter_list
1643
+ ) # fast select not supported for stored procedures
1449
1644
  return
1450
1645
 
1451
1646
  def _handle_error_504(self, error):
@@ -1464,7 +1659,11 @@ class Cursor(_BaseCursor):
1464
1659
  def stored_results(self):
1465
1660
  if self._closed:
1466
1661
  raise InterfaceError("Cursor is closed")
1467
- if self._statementType not in [StatementType.QUERY, StatementType.DIRECT_CALL_QUERY, StatementType.PREPARED_CALL_QUERY]:
1662
+ if self._statementType not in [
1663
+ StatementType.QUERY,
1664
+ StatementType.DIRECT_CALL_QUERY,
1665
+ StatementType.PREPARED_CALL_QUERY,
1666
+ ]:
1468
1667
  return None
1469
1668
  # getResultSet()
1470
1669
  if self._multiple_result_sets:
@@ -1492,16 +1691,21 @@ class Cursor(_BaseCursor):
1492
1691
  raise InterfaceError("Cursor is closed")
1493
1692
  if self._connection == None or self._connection.isClosed():
1494
1693
  raise InterfaceError("Connection not open")
1495
- if (self._mrs_done or not self._multiple_result_sets or
1496
- (self._statementType != StatementType.PREPARED_CALL_QUERY and
1497
- self._statementType != StatementType.DIRECT_CALL_QUERY and
1498
- self._statementType != StatementType.CALL and
1499
- self._statementType != StatementType.CALLWITHRESULT and
1500
- not (self._statementType == StatementType.QUERY and self._cursor_type == CursorType.CALLABLE))):
1694
+ if (
1695
+ self._mrs_done
1696
+ or not self._multiple_result_sets
1697
+ or (
1698
+ self._statementType != StatementType.PREPARED_CALL_QUERY
1699
+ and self._statementType != StatementType.DIRECT_CALL_QUERY
1700
+ and self._statementType != StatementType.CALL
1701
+ and self._statementType != StatementType.CALLWITHRESULT
1702
+ and not (self._statementType == StatementType.QUERY and self._cursor_type == CursorType.CALLABLE)
1703
+ )
1704
+ ):
1501
1705
  return False
1502
1706
  with self._connection._lock:
1503
1707
  self._out_message.wire._write_header(_Message.GET_MORE_RESULTS)
1504
- self._out_message.wire._set(1) # current = CLOSE_CURRENT_RESULT
1708
+ self._out_message.wire._set(1) # current = CLOSE_CURRENT_RESULT
1505
1709
 
1506
1710
  # send
1507
1711
  sequence_number = self._connection._get_new_sequence_number()
@@ -1515,7 +1719,7 @@ class Cursor(_BaseCursor):
1515
1719
  self._rs_index = 0
1516
1720
 
1517
1721
  results = self._in_message.wire._get()
1518
- if results >= 0 :
1722
+ if results >= 0:
1519
1723
  self._update_cnt = results
1520
1724
  return False
1521
1725
  elif results == -1:
@@ -1543,11 +1747,11 @@ class Cursor(_BaseCursor):
1543
1747
  def _get_result_set(self, oref):
1544
1748
  if oref == None:
1545
1749
  return None
1546
-
1750
+
1547
1751
  with self._connection._lock:
1548
1752
  self._out_message.wire._write_header(_Message.GET_RESULT_SET_OBJECT)
1549
1753
  self._out_message.wire._set(oref)
1550
- self._out_message.wire._set(0) # IRISResultSet.GET_RESULT_SET_OBJECT_INIT
1754
+ self._out_message.wire._set(0) # IRISResultSet.GET_RESULT_SET_OBJECT_INIT
1551
1755
 
1552
1756
  # send
1553
1757
  sequence_number = self._connection._get_new_sequence_number()
@@ -1573,16 +1777,16 @@ class Cursor(_BaseCursor):
1573
1777
  self.params = params
1574
1778
 
1575
1779
  self._params.set_input_params(self.params)
1576
-
1780
+
1577
1781
  self._cursor_type = CursorType.CALLABLE
1578
1782
  self._cleanup()
1579
1783
  self._preparse()
1580
1784
  self._stored_results = []
1581
-
1785
+
1582
1786
  if not self._get_cached_info():
1583
1787
  self._prepare_stored_procedure()
1584
1788
 
1585
- #execute() in IrisPreparedStatement
1789
+ # execute() in IrisPreparedStatement
1586
1790
  if self._multiple_result_sets:
1587
1791
  return self._execute_multiple_result_sets(True)
1588
1792
  if self._statementType == StatementType.QUERY or self._statementType == StatementType.PREPARED_CALL_QUERY:
@@ -1603,12 +1807,12 @@ class Cursor(_BaseCursor):
1603
1807
  if param.mode in [ParameterMode.RETURN_VALUE, ParameterMode.OUTPUT, ParameterMode.INPUT]:
1604
1808
  offset = self._params._get_user_list_offset(i + 1)
1605
1809
  val = self._output_parameter_list._get_at_offset(offset)
1606
- if param.type == -51: # RESULT_SET_TYPE
1810
+ if param.type == -51: # RESULT_SET_TYPE
1607
1811
  self._get_result_set(val)
1608
1812
  self.nextset()
1609
1813
  return_args.append(self._stored_results[0])
1610
1814
  else:
1611
- if val == '\x01': # Either represents the number 1 or a null/None value
1815
+ if val == "\x01": # Either represents the number 1 or a null/None value
1612
1816
  # maybe move this to _grab_ascii_string in DBList?
1613
1817
  off = self._output_parameter_list.list_item.data_offset
1614
1818
  buf = self._output_parameter_list.list_item.buffer
@@ -1617,7 +1821,7 @@ class Cursor(_BaseCursor):
1617
1821
  else:
1618
1822
  return_args.append(val)
1619
1823
  if len(return_args) > 0:
1620
- if any(i != None for i in return_args):
1824
+ if any(i != None for i in return_args):
1621
1825
  return return_args
1622
1826
  else:
1623
1827
  return
@@ -1634,23 +1838,26 @@ class Cursor(_BaseCursor):
1634
1838
  if self._connection == None or self._connection.isClosed():
1635
1839
  return None
1636
1840
 
1637
- if self._statementType is not StatementType.UPDATE:
1841
+ if self._statementType is not StatementType.UPDATE or self._rowcount < 1:
1638
1842
  return None
1639
-
1640
- # In multivalue inserts it returns the first inserted value, not the last one
1641
- # with self._connection._lock:
1642
- # self._out_message.wire._write_header(_Message.GET_AUTO_GENERATED_KEYS)
1643
- # sequence_number = self._connection._get_new_sequence_number()
1644
- # self._out_message._send(sequence_number)
1645
- # self._in_message._read_message_sql(sequence_number)
1646
- # self._sqlcode = self._in_message.wire.header._get_function_code()
1647
- # if self._sqlcode != 100:
1648
- # raise DatabaseError(self._get_error_info(self._sqlcode))
1649
- # self._get_column_info(self._in_message.wire)
1650
- # self._lastrowid = self._in_message.wire._get()
1651
-
1652
- self.execute('SELECT LAST_IDENTITY()')
1653
- self._lastrowid = self.fetchone()[0]
1843
+
1844
+ if self._rowcount > 1:
1845
+ with self._connection.cursor() as cursor:
1846
+ cursor.execute("SELECT LAST_IDENTITY()")
1847
+ self._lastrowid = cursor.fetchone()[0]
1848
+ return self._lastrowid
1849
+
1850
+ # In multiple rows inserted it returns the first inserted value, not the last one
1851
+ with self._connection._lock:
1852
+ self._out_message.wire._write_header(_Message.GET_AUTO_GENERATED_KEYS)
1853
+ sequence_number = self._connection._get_new_sequence_number()
1854
+ self._out_message._send(sequence_number)
1855
+ self._in_message._read_message_sql(sequence_number)
1856
+ self._sqlcode = self._in_message.wire.header._get_function_code()
1857
+ if self._sqlcode != 100:
1858
+ raise DatabaseError(self._get_error_info(self._sqlcode))
1859
+ self._get_column_info(self._in_message.wire)
1860
+ self._lastrowid = self._in_message.wire._get()
1654
1861
  return self._lastrowid
1655
1862
 
1656
1863
  def _cleanup(self):
@@ -1696,7 +1903,7 @@ class Cursor(_BaseCursor):
1696
1903
  self._params = None
1697
1904
  self._parsed_statement = None
1698
1905
  self._cursor_type = CursorType.DEFAULT
1699
- self._statementType = StatementType.UPDATE # default
1906
+ self._statementType = StatementType.UPDATE # default
1700
1907
  self._paramInfo = None
1701
1908
  self.statement = None
1702
1909
  self.statementFeatureOption = Feature.optionNone
@@ -1726,15 +1933,15 @@ class Cursor(_BaseCursor):
1726
1933
  return self._rowcount
1727
1934
 
1728
1935
  def scroll(self, value, mode):
1729
- if mode == None or mode == '':
1730
- mode = 'relative'
1936
+ if mode == None or mode == "":
1937
+ mode = "relative"
1731
1938
  mode = mode.lower()
1732
- if mode != 'absolute' and mode != 'relative':
1939
+ if mode != "absolute" and mode != "relative":
1733
1940
  raise ValueError("This mode is not supported - use 'relative' or 'absolute'.")
1734
1941
 
1735
1942
  # Backward Scrolling
1736
1943
  if value < 0:
1737
- if mode == 'relative':
1944
+ if mode == "relative":
1738
1945
  self._rownumber = self._cursor_ptr + value - 1
1739
1946
  else:
1740
1947
  raise ValueError("Negative values with absolute scrolling are not allowed.")
@@ -1753,13 +1960,13 @@ class Cursor(_BaseCursor):
1753
1960
  return self._warehouse[self._rownumber - self._last_row_in_warehouse_dict - 1]
1754
1961
  # Forward Scrolling
1755
1962
  else:
1756
- if mode == 'absolute':
1963
+ if mode == "absolute":
1757
1964
  self._cursor_ptr = 0
1758
1965
  self._scroll_flag = True
1759
1966
  self._rownumber = self._cursor_ptr + value - 1
1760
1967
  if self._rs_index == 0:
1761
1968
  if self._rownumber >= len(self._warehouse):
1762
- if mode == 'absolute':
1969
+ if mode == "absolute":
1763
1970
  self._cursor_ptr = len(self._warehouse)
1764
1971
  return self.fetchone()
1765
1972
  else:
@@ -1781,7 +1988,7 @@ class Cursor(_BaseCursor):
1781
1988
  self._cursor_ptr = self._rownumber + 1
1782
1989
  return self._warehouse[self._rownumber - self._last_row_in_warehouse_dict - 1]
1783
1990
  else:
1784
- if mode == 'absolute':
1991
+ if mode == "absolute":
1785
1992
  self._cursor_ptr = rows_available + 1
1786
1993
  return self.fetchone()
1787
1994
 
@@ -1797,7 +2004,9 @@ class Cursor(_BaseCursor):
1797
2004
  if self._sqlcode == 0:
1798
2005
  with self._connection._lock:
1799
2006
  self._out_message.wire._write_header(_Message.FETCH_DATA)
1800
- intersystems_iris._MessageHeader._MessageHeader._set_statement_id(self._out_message.wire.buffer, self._statement_id)
2007
+ intersystems_iris._MessageHeader._MessageHeader._set_statement_id(
2008
+ self._out_message.wire.buffer, self._statement_id
2009
+ )
1801
2010
 
1802
2011
  sequence_number = self._connection._get_new_sequence_number()
1803
2012
  self._out_message._send(sequence_number)
@@ -1831,7 +2040,7 @@ class Cursor(_BaseCursor):
1831
2040
  list_item = self._current_wire.list_item
1832
2041
  buffer = list_item.buffer
1833
2042
  length = list_item.list_buffer_end
1834
-
2043
+
1835
2044
  if self._rsrow._new_buffer:
1836
2045
  prev_offset = list_item.next_offset
1837
2046
  self._rsrow._new_buffer = False
@@ -1848,10 +2057,10 @@ class Cursor(_BaseCursor):
1848
2057
  intersystems_iris._DBList._DBList._get_list_element(list_item)
1849
2058
  length = list_item.next_offset
1850
2059
  prev_offset = list_item.data_offset
1851
- if list_item.data_length == 0: #
2060
+ if list_item.data_length == 0: #
1852
2061
  for j in range(self._rsrow.colCount):
1853
2062
  rowItems[j] = -1
1854
- self._rsrow._offsets = self._rsrow.update(rowItems) # ???
2063
+ self._rsrow._offsets = self._rsrow.update(rowItems) # ???
1855
2064
  return True
1856
2065
  else:
1857
2066
  if self._rsrow.rowItems != None:
@@ -1878,10 +2087,12 @@ class Cursor(_BaseCursor):
1878
2087
 
1879
2088
  self._cursor_ptr += 1
1880
2089
  return row_indexing
1881
-
2090
+
1882
2091
  def fetchone(self):
1883
2092
  if self._result_set == None:
1884
- raise InterfaceError("Either execute has not yet been called, or the previous call of execute did not return a result set")
2093
+ raise InterfaceError(
2094
+ "Either execute has not yet been called, or the previous call of execute did not return a result set"
2095
+ )
1885
2096
 
1886
2097
  if self._current_wire == None and self._cursor_ptr > self._last_row_in_warehouse_dict:
1887
2098
  return None
@@ -1920,9 +2131,11 @@ class Cursor(_BaseCursor):
1920
2131
  return retval.as_tuple()
1921
2132
  # return tuple(retval[:])
1922
2133
 
1923
- def fetchmany(self, size = None):
2134
+ def fetchmany(self, size=None):
1924
2135
  if self._result_set == None:
1925
- raise InterfaceError("Either execute has not yet been called, or the previous call of execute did not return a result set")
2136
+ raise InterfaceError(
2137
+ "Either execute has not yet been called, or the previous call of execute did not return a result set"
2138
+ )
1926
2139
 
1927
2140
  if self._current_wire == None:
1928
2141
  if self._cursor_ptr > self._last_row_in_warehouse_dict:
@@ -1950,7 +2163,7 @@ class Cursor(_BaseCursor):
1950
2163
  break
1951
2164
  self._cursor_ptr += 1
1952
2165
  return rows
1953
-
2166
+
1954
2167
  if size is None:
1955
2168
  size = self.arraysize
1956
2169
 
@@ -1964,8 +2177,10 @@ class Cursor(_BaseCursor):
1964
2177
 
1965
2178
  def fetchall(self):
1966
2179
  if self._result_set == None:
1967
- raise InterfaceError("Either execute has not yet been called, or the previous call of execute did not return a result set")
1968
-
2180
+ raise InterfaceError(
2181
+ "Either execute has not yet been called, or the previous call of execute did not return a result set"
2182
+ )
2183
+
1969
2184
  if self._current_wire == None:
1970
2185
  if self._cursor_ptr > self._last_row_in_warehouse_dict:
1971
2186
  return []
@@ -1990,15 +2205,17 @@ class Cursor(_BaseCursor):
1990
2205
  break
1991
2206
  self._cursor_ptr += 1
1992
2207
  return rows
1993
-
2208
+
1994
2209
  rows = []
1995
2210
  while self._current_wire is not None:
1996
2211
  row = self.fetchone()
1997
- if not row: break
2212
+ if not row:
2213
+ break
1998
2214
  rows.append(row)
1999
-
2215
+
2000
2216
  return rows
2001
2217
 
2218
+
2002
2219
  class EmbdeddedCursor(_BaseCursor):
2003
2220
  embedded = True
2004
2221
  _result_set = None
@@ -2008,7 +2225,7 @@ class EmbdeddedCursor(_BaseCursor):
2008
2225
  self._sql = connection.iris.sql
2009
2226
  self._iris = connection.iris
2010
2227
  self._closed = False
2011
-
2228
+
2012
2229
  # $System.SQL.SetSelectMode(1 /* ODBC */)
2013
2230
  # $System.SQL.Util.SetOption("SelectMode", 1 /* ODBC */)
2014
2231
  connection.iris.system.SQL.SetSelectMode(1)
@@ -2016,12 +2233,12 @@ class EmbdeddedCursor(_BaseCursor):
2016
2233
  def _get_cached_info(self):
2017
2234
  return False
2018
2235
 
2019
- def _get_parameters(self, params_set = 0):
2236
+ def _get_parameters(self, params_set=0):
2020
2237
  params = self._params.collect(params_set)
2021
2238
  # None = '', '' = b'\x00'
2022
2239
  _conv = {
2023
- type(None): lambda v: '',
2024
- str: lambda v: v or b'\x00',
2240
+ type(None): lambda v: "",
2241
+ str: lambda v: v or b"\x00",
2025
2242
  decimal.Decimal: lambda v: float(v),
2026
2243
  }
2027
2244
  params = [_conv[type(v)](v) if type(v) in _conv else v for v in params]
@@ -2031,9 +2248,9 @@ class EmbdeddedCursor(_BaseCursor):
2031
2248
  self._columns = []
2032
2249
  if self._result_set is None:
2033
2250
  return
2034
-
2251
+
2035
2252
  metadata = self._result_set.ResultSet._GetMetadata()
2036
- count = metadata.columnCount if metadata != '' and metadata is not None else 0
2253
+ count = metadata.columnCount if metadata != "" and metadata is not None else 0
2037
2254
  for i in range(count):
2038
2255
  slotPosition = i + 1
2039
2256
  _column_info = metadata.columns.GetAt(slotPosition)
@@ -2065,7 +2282,21 @@ class EmbdeddedCursor(_BaseCursor):
2065
2282
  _column_info.isKeyColumn,
2066
2283
  _column_info.isRowId,
2067
2284
  ]
2068
- self._columns.append(intersystems_iris.dbapi._Column._Column(name, odbctype, precision, scale, nullable, label, tableName, schema, catalog, additionalData, slotPosition))
2285
+ self._columns.append(
2286
+ intersystems_iris.dbapi._Column._Column(
2287
+ name,
2288
+ odbctype,
2289
+ precision,
2290
+ scale,
2291
+ nullable,
2292
+ label,
2293
+ tableName,
2294
+ schema,
2295
+ catalog,
2296
+ additionalData,
2297
+ slotPosition,
2298
+ )
2299
+ )
2069
2300
 
2070
2301
  @property
2071
2302
  def lastrowid(self):
@@ -2138,8 +2369,22 @@ class EmbdeddedCursor(_BaseCursor):
2138
2369
  self._rowcount = 0
2139
2370
  self._lastrowid = None
2140
2371
  sets = self._parameter_sets or 1
2372
+ metadata = self._statement.Statement._Metadata.parameters
2373
+ param_types = [metadata.GetAt(i + 1).ODBCType for i in range(metadata.Size)]
2374
+
2375
+ stream_chunk_size = 32000
2376
+
2141
2377
  for i in range(sets):
2142
2378
  params = self._get_parameters(i)
2379
+ for ip, param in enumerate(params):
2380
+ if param_types[ip] in (SQLType.LONGVARBINARY, SQLType.LONGVARCHAR):
2381
+ stream_class = '%Stream.GlobalBinary' if param_types[ip] == SQLType.LONGVARBINARY else '%Stream.GlobalCharacter'
2382
+ stream = self._iris.cls(stream_class)._New()
2383
+ while param:
2384
+ stream.Write(param[:stream_chunk_size])
2385
+ param = param[stream_chunk_size:]
2386
+ params[ip] = stream
2387
+
2143
2388
  sqlcode = 0
2144
2389
  message = None
2145
2390
  try:
@@ -2155,8 +2400,8 @@ class EmbdeddedCursor(_BaseCursor):
2155
2400
  sqlproc = self._parsed_statement
2156
2401
  self._rowcount = 0
2157
2402
  params = self._get_parameters()
2158
- params_marks = ', '.join(['?'] * len(params))
2159
- statement = f'CALL {sqlproc} ({params_marks})'
2403
+ params_marks = ", ".join(["?"] * len(params))
2404
+ statement = f"CALL {sqlproc} ({params_marks})"
2160
2405
 
2161
2406
  sqlcode = 0
2162
2407
  message = None
@@ -2172,29 +2417,34 @@ class EmbdeddedCursor(_BaseCursor):
2172
2417
  @property
2173
2418
  def rowcount(self):
2174
2419
  return self._rowcount
2175
-
2420
+
2176
2421
  def fetchone(self):
2177
2422
  if self._result_set == None:
2178
- raise InterfaceError("Either execute has not yet been called, or the previous call of execute did not return a result set")
2179
-
2423
+ raise InterfaceError(
2424
+ "Either execute has not yet been called, or the previous call of execute did not return a result set"
2425
+ )
2426
+
2180
2427
  try:
2181
2428
  values = self._result_set.__next__()
2182
2429
  except:
2183
2430
  return None
2184
2431
 
2185
- values = [None if v == '' else '' if v == '\x00' else v for v in values]
2186
- row = namedtuple('Row', [col.name for col in self._columns], rename=True)
2432
+ values = [None if v == "" else "" if v == "\x00" else v for v in values]
2433
+ row = namedtuple("Row", [col.name for col in self._columns], rename=True)
2187
2434
 
2188
2435
  _types = {
2189
2436
  SQLType.BIGINT: int,
2190
2437
  SQLType.BINARY: bytes,
2438
+ SQLType.VARBINARY: bytes,
2191
2439
  SQLType.BIT: bool,
2440
+ SQLType.FLOAT: float,
2441
+ SQLType.NUMERIC: decimal.Decimal,
2192
2442
  SQLType.INTEGER: int,
2193
2443
  SQLType.VARCHAR: str,
2194
2444
  SQLType.LONGVARBINARY: IRISBinaryStream,
2195
2445
  SQLType.LONGVARCHAR: IRISStream,
2196
2446
  }
2197
-
2447
+
2198
2448
  if self._columns:
2199
2449
  for _column in self._columns:
2200
2450
  value = values[_column.slotPosition - 1]
@@ -2202,12 +2452,15 @@ class EmbdeddedCursor(_BaseCursor):
2202
2452
  ctype = _column.type
2203
2453
  value_type = _types[ctype] if ctype in _types else None
2204
2454
  try:
2205
- if type(value) == float:
2206
- value = decimal.Decimal(str(value))
2207
- elif not _column.tableName and not _column.schema:
2208
- pass
2455
+ if not _column.tableName and not _column.schema:
2456
+ if type(value) == float:
2457
+ value = decimal.Decimal(str(value))
2209
2458
  elif value is None or value_type is None:
2210
2459
  pass
2460
+ elif value_type is bytes:
2461
+ value = bytes(map(ord, value))
2462
+ elif value_type is decimal.Decimal:
2463
+ value = decimal.Decimal(str(value))
2211
2464
  elif issubclass(value_type, IRISStream):
2212
2465
  stream = value_type(self._connection, value, embedded=True)
2213
2466
  value = stream.fetch()
@@ -2221,18 +2474,23 @@ class EmbdeddedCursor(_BaseCursor):
2221
2474
 
2222
2475
  def fetchall(self):
2223
2476
  if self._result_set == None:
2224
- raise InterfaceError("Either execute has not yet been called, or the previous call of execute did not return a result set")
2477
+ raise InterfaceError(
2478
+ "Either execute has not yet been called, or the previous call of execute did not return a result set"
2479
+ )
2225
2480
 
2226
2481
  rows = []
2227
2482
  while True:
2228
2483
  row = self.fetchone()
2229
- if not row: break
2484
+ if not row:
2485
+ break
2230
2486
  rows.append(row)
2231
2487
  return rows
2232
-
2233
- def fetchmany(self, size = None):
2488
+
2489
+ def fetchmany(self, size=None):
2234
2490
  if self._result_set == None:
2235
- raise InterfaceError("Either execute has not yet been called, or the previous call of execute did not return a result set")
2491
+ raise InterfaceError(
2492
+ "Either execute has not yet been called, or the previous call of execute did not return a result set"
2493
+ )
2236
2494
 
2237
2495
  if size is None:
2238
2496
  size = self.arraysize
@@ -2253,21 +2511,27 @@ class EmbdeddedCursor(_BaseCursor):
2253
2511
  def Date(year, month, day):
2254
2512
  raise NotImplementedErrorDBAPI()
2255
2513
 
2514
+
2256
2515
  def Time(hour, minutes, second):
2257
2516
  raise NotImplementedErrorDBAPI()
2258
2517
 
2518
+
2259
2519
  def Timestamp(year, month, day, hour, minute, second):
2260
2520
  raise NotImplementedErrorDBAPI()
2261
2521
 
2522
+
2262
2523
  def DateFromTicks(ticks):
2263
2524
  raise NotImplementedErrorDBAPI()
2264
2525
 
2526
+
2265
2527
  def TimeFromTicks(ticks):
2266
2528
  raise NotImplementedErrorDBAPI()
2267
2529
 
2530
+
2268
2531
  def TimestampFromTicks(ticks):
2269
2532
  raise NotImplementedErrorDBAPI()
2270
2533
 
2534
+
2271
2535
  # def Binary(string):
2272
2536
  # return string
2273
2537
 
@@ -2281,33 +2545,43 @@ ROWID = str
2281
2545
 
2282
2546
  # still needs type singletons (?)
2283
2547
 
2548
+
2284
2549
  # Exception architecture
2285
2550
  class Error(Exception):
2286
2551
  pass
2287
2552
 
2553
+
2288
2554
  class Warning(Exception):
2289
- pass
2555
+ pass
2556
+
2290
2557
 
2291
2558
  class InterfaceError(Error):
2292
2559
  pass
2293
2560
 
2561
+
2294
2562
  class DatabaseError(Error):
2295
2563
  pass
2296
2564
 
2565
+
2297
2566
  class InternalError(DatabaseError):
2298
2567
  pass
2299
2568
 
2569
+
2300
2570
  class OperationalError(DatabaseError):
2301
2571
  pass
2302
2572
 
2573
+
2303
2574
  class ProgrammingError(DatabaseError):
2304
2575
  pass
2305
2576
 
2577
+
2306
2578
  class IntegrityError(DatabaseError):
2307
2579
  pass
2308
2580
 
2581
+
2309
2582
  class DataError(DatabaseError):
2310
2583
  pass
2311
2584
 
2585
+
2312
2586
  class NotSupportedError(DatabaseError):
2313
2587
  pass