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.
- grongier/pex/_business_host.py +9 -1
- intersystems_iris/dbapi/_DBAPI.py +517 -243
- intersystems_iris/dbapi/_IRISStream.py +2 -0
- intersystems_iris/dbapi/_Parameter.py +62 -31
- intersystems_iris/dbapi/_ParameterCollection.py +9 -1
- intersystems_iris/dbapi/_ResultSetRow.py +3 -1
- intersystems_iris/dbapi/preparser/_PreParser.py +47 -38
- {iris_pex_embedded_python-2.3.17.dist-info → iris_pex_embedded_python-2.3.18.dist-info}/METADATA +1 -1
- {iris_pex_embedded_python-2.3.17.dist-info → iris_pex_embedded_python-2.3.18.dist-info}/RECORD +13 -13
- {iris_pex_embedded_python-2.3.17.dist-info → iris_pex_embedded_python-2.3.18.dist-info}/LICENSE +0 -0
- {iris_pex_embedded_python-2.3.17.dist-info → iris_pex_embedded_python-2.3.18.dist-info}/WHEEL +0 -0
- {iris_pex_embedded_python-2.3.17.dist-info → iris_pex_embedded_python-2.3.18.dist-info}/entry_points.txt +0 -0
- {iris_pex_embedded_python-2.3.17.dist-info → iris_pex_embedded_python-2.3.18.dist-info}/top_level.txt +0 -0
|
@@ -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 (
|
|
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
|
-
|
|
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,
|
|
39
|
+
connection.connect(hostname, port, namespace, username, password, **kw)
|
|
32
40
|
return connection
|
|
33
41
|
|
|
34
|
-
|
|
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(
|
|
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(
|
|
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
|
|
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(
|
|
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
|
|
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
|
|
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
|
-
|
|
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(
|
|
256
|
-
|
|
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()
|
|
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
|
|
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)
|
|
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(
|
|
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(
|
|
368
|
-
|
|
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]
|
|
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 ==
|
|
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 ==
|
|
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(
|
|
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
|
|
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
|
|
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
|
|
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 (
|
|
521
|
-
self._statementType != StatementType.
|
|
522
|
-
self._statementType != StatementType.
|
|
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(
|
|
562
|
-
|
|
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 (
|
|
579
|
-
self.
|
|
580
|
-
self._statementType == StatementType.
|
|
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.
|
|
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(
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
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:
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
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,
|
|
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 (
|
|
694
|
-
self.
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
self._params._params_list
|
|
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
|
|
717
|
-
|
|
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(
|
|
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)
|
|
755
|
-
self._out_message.wire._set(self._parsed_statement)
|
|
756
|
-
self._out_message.wire._set_raw_bytes(self._paramInfo.getBuffer())
|
|
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
|
|
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 =
|
|
823
|
-
|
|
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()
|
|
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)
|
|
900
|
-
self._out_message.wire._set(len(self._params._params_list))
|
|
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(
|
|
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)
|
|
934
|
-
self._out_message.wire._set(0)
|
|
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(
|
|
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)
|
|
965
|
-
self._out_message.wire._set(0)
|
|
966
|
-
self._out_message.wire._set(0)
|
|
967
|
-
self._out_message.wire._set(0)
|
|
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 [
|
|
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(
|
|
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(
|
|
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)
|
|
1014
|
-
self._out_message.wire._set(self._parsed_statement)
|
|
1015
|
-
self._out_message.wire._set_raw_bytes(self._paramInfo.getBuffer())
|
|
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)
|
|
1018
|
-
self._out_message.wire._set(0)
|
|
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(
|
|
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)
|
|
1069
|
-
self._out_message.wire._set(0)
|
|
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(
|
|
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)
|
|
1095
|
-
self._out_message.wire._set(self._parsed_statement)
|
|
1096
|
-
self._out_message.wire._set_raw_bytes(self._paramInfo.getBuffer())
|
|
1097
|
-
self._out_message.wire._set(-1)
|
|
1098
|
-
self._out_message.wire._set(0)
|
|
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(
|
|
1114
|
-
|
|
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(
|
|
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)
|
|
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 (
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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)
|
|
1294
|
-
self._out_message.wire._set(0)
|
|
1295
|
-
self._out_message.wire._set(0)
|
|
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(
|
|
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)
|
|
1323
|
-
self._out_message.wire._set(0)
|
|
1324
|
-
self._out_message.wire._set(0)
|
|
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)
|
|
1358
|
-
self._out_message.wire._set(0)
|
|
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
|
|
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(
|
|
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 [
|
|
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 (
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
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)
|
|
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)
|
|
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:
|
|
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 ==
|
|
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
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
#
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
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
|
|
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 =
|
|
1936
|
+
if mode == None or mode == "":
|
|
1937
|
+
mode = "relative"
|
|
1731
1938
|
mode = mode.lower()
|
|
1732
|
-
if mode !=
|
|
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 ==
|
|
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 ==
|
|
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 ==
|
|
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 ==
|
|
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(
|
|
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(
|
|
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
|
|
2134
|
+
def fetchmany(self, size=None):
|
|
1924
2135
|
if self._result_set == None:
|
|
1925
|
-
raise InterfaceError(
|
|
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(
|
|
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:
|
|
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
|
|
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
|
|
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 !=
|
|
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(
|
|
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 =
|
|
2159
|
-
statement = f
|
|
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(
|
|
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 ==
|
|
2186
|
-
row = namedtuple(
|
|
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
|
|
2206
|
-
|
|
2207
|
-
|
|
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(
|
|
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:
|
|
2484
|
+
if not row:
|
|
2485
|
+
break
|
|
2230
2486
|
rows.append(row)
|
|
2231
2487
|
return rows
|
|
2232
|
-
|
|
2233
|
-
def fetchmany(self, size
|
|
2488
|
+
|
|
2489
|
+
def fetchmany(self, size=None):
|
|
2234
2490
|
if self._result_set == None:
|
|
2235
|
-
raise InterfaceError(
|
|
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
|
-
|
|
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
|