sqlalchemy-iris 0.15.5b1__tar.gz → 0.16.0__tar.gz
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.
- {sqlalchemy_iris-0.15.5b1/sqlalchemy_iris.egg-info → sqlalchemy_iris-0.16.0}/PKG-INFO +3 -2
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/dbapi/_Column.py +3 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/dbapi/_DBAPI.py +38 -4
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/dbapi/_IRISStream.py +2 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/dbapi/_ResultSetRow.py +1 -1
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/dbapi/preparser/_PreParser.py +52 -3
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/dbapi/preparser/_Token.py +3 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/dbapi/preparser/_TokenList.py +3 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/setup.cfg +1 -1
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/sqlalchemy_iris/base.py +62 -3
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/sqlalchemy_iris/information_schema.py +2 -1
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/sqlalchemy_iris/requirements.py +16 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0/sqlalchemy_iris.egg-info}/PKG-INFO +3 -2
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/sqlalchemy_iris.egg-info/SOURCES.txt +0 -6
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/sqlalchemy_iris.egg-info/top_level.txt +0 -1
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/tests/test_alembic.py +6 -4
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/tests/test_suite.py +32 -2
- sqlalchemy_iris-0.15.5b1/iris/__init__.py +0 -66
- sqlalchemy_iris-0.15.5b1/iris/__init__.pyi +0 -236
- sqlalchemy_iris-0.15.5b1/iris/_cli.py +0 -75
- sqlalchemy_iris-0.15.5b1/iris/iris_ipm.py +0 -40
- sqlalchemy_iris-0.15.5b1/iris/iris_ipm.pyi +0 -17
- sqlalchemy_iris-0.15.5b1/iris/iris_utils.py +0 -336
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/LICENSE +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/README.md +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/_BufferReader.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/_BufferWriter.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/_ConnectionInformation.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/_ConnectionParameters.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/_Constant.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/_DBList.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/_Device.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/_GatewayContext.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/_GatewayException.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/_GatewayUtility.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/_IRIS.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/_IRISConnection.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/_IRISEmbedded.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/_IRISGlobalNode.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/_IRISGlobalNodeView.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/_IRISIterator.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/_IRISList.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/_IRISNative.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/_IRISOREF.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/_IRISObject.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/_IRISReference.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/_InStream.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/_LegacyIterator.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/_ListItem.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/_ListReader.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/_ListWriter.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/_LogFileStream.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/_MessageHeader.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/_OutStream.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/_PrintStream.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/_PythonGateway.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/_SharedMemorySocket.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/__init__.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/__main__.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/dbapi/_Descriptor.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/dbapi/_Message.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/dbapi/_Parameter.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/dbapi/_ParameterCollection.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/dbapi/_SQLType.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/dbapi/__init__.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/dbapi/preparser/_Scanner.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/dbapi/preparser/__init__.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/pex/_BusinessHost.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/pex/_BusinessOperation.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/pex/_BusinessProcess.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/pex/_BusinessService.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/pex/_Common.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/pex/_Director.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/pex/_IRISBusinessOperation.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/pex/_IRISBusinessService.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/pex/_IRISInboundAdapter.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/pex/_IRISOutboundAdapter.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/pex/_InboundAdapter.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/pex/_Message.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/pex/_OutboundAdapter.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/pex/__init__.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/irisnative/_IRISNative.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/irisnative/__init__.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/setup.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/sqlalchemy_iris/__init__.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/sqlalchemy_iris/alembic.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/sqlalchemy_iris/embedded.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/sqlalchemy_iris/iris.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/sqlalchemy_iris/irisasync.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/sqlalchemy_iris/provision.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/sqlalchemy_iris/types.py +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/sqlalchemy_iris.egg-info/dependency_links.txt +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/sqlalchemy_iris.egg-info/entry_points.txt +0 -0
- {sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/sqlalchemy_iris.egg-info/requires.txt +0 -0
@@ -1,6 +1,6 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.2
|
2
2
|
Name: sqlalchemy-iris
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.16.0
|
4
4
|
Summary: InterSystems IRIS for SQLAlchemy
|
5
5
|
Home-page: https://github.com/caretdev/sqlalchemy-iris
|
6
6
|
Maintainer: CaretDev
|
@@ -23,6 +23,7 @@ Requires-Python: >=3.8
|
|
23
23
|
Description-Content-Type: text/markdown
|
24
24
|
License-File: LICENSE
|
25
25
|
Requires-Dist: SQLAlchemy>=1.3
|
26
|
+
Dynamic: requires-dist
|
26
27
|
|
27
28
|
sqlalchemy-iris
|
28
29
|
===
|
@@ -54,3 +54,6 @@ class _Column(intersystems_iris.dbapi._Descriptor._Descriptor):
|
|
54
54
|
self.isKeyColumn,
|
55
55
|
self.isRowId]
|
56
56
|
return _Column(self.name, self.type, self.precision, self.scale, self.nullable, self.label, self.tableName, self.schema, self.catalog, additionalData, self.slotPosition)
|
57
|
+
|
58
|
+
def __repr__(self) -> str:
|
59
|
+
return f"<Column name='{self.name}' type='{self.type}'>"
|
@@ -14,7 +14,7 @@ from ._ResultSetRow import _ResultSetRow
|
|
14
14
|
import intersystems_iris.dbapi._ParameterCollection
|
15
15
|
import intersystems_iris.dbapi.preparser._PreParser
|
16
16
|
from intersystems_iris.dbapi._Parameter import ParameterMode
|
17
|
-
from intersystems_iris.dbapi.preparser._PreParser import StatementType, MultiValuesInsert
|
17
|
+
from intersystems_iris.dbapi.preparser._PreParser import StatementType, MultiValuesInsert, InsertWithReturning
|
18
18
|
from intersystems_iris._IRISConnection import Feature
|
19
19
|
from intersystems_iris._InStream import _InStream
|
20
20
|
from intersystems_iris.dbapi._IRISStream import (
|
@@ -252,6 +252,11 @@ class _BaseCursor:
|
|
252
252
|
self._cleanup()
|
253
253
|
try:
|
254
254
|
self._preparse()
|
255
|
+
except InsertWithReturning as ex:
|
256
|
+
ids = intersystems_iris._ListWriter._ListWriter()
|
257
|
+
self.execute(ex.insert_query, params)
|
258
|
+
ids._set(self.lastrowid)
|
259
|
+
return self.execute(ex.select_query, bytes(ids._get_buffer()))
|
255
260
|
except MultiValuesInsert as ex:
|
256
261
|
# convert to executemany
|
257
262
|
params = params or ex.params
|
@@ -269,6 +274,7 @@ class _BaseCursor:
|
|
269
274
|
|
270
275
|
self._execute()
|
271
276
|
return self._rowcount
|
277
|
+
# return self.execute(returning_query)
|
272
278
|
|
273
279
|
def add_batch(self):
|
274
280
|
self._is_alive()
|
@@ -321,7 +327,17 @@ class _BaseCursor:
|
|
321
327
|
self._cleanup()
|
322
328
|
self._is_batch_update = True
|
323
329
|
|
324
|
-
|
330
|
+
try:
|
331
|
+
self._preparse()
|
332
|
+
except InsertWithReturning as ex:
|
333
|
+
ids = intersystems_iris._ListWriter._ListWriter()
|
334
|
+
for params in seq_of_params:
|
335
|
+
self.execute(ex.insert_query, params)
|
336
|
+
ids._set(self.lastrowid)
|
337
|
+
self.execute(ex.select_query, bytes(ids._get_buffer()))
|
338
|
+
raise
|
339
|
+
except Exception:
|
340
|
+
raise
|
325
341
|
self._prepare()
|
326
342
|
|
327
343
|
for row_num, param_row in enumerate(seq_of_params):
|
@@ -389,6 +405,8 @@ class _BaseCursor:
|
|
389
405
|
)
|
390
406
|
try:
|
391
407
|
pOut = parser.PreParse(self.statement, self._params)
|
408
|
+
except InsertWithReturning:
|
409
|
+
raise
|
392
410
|
except MultiValuesInsert:
|
393
411
|
raise
|
394
412
|
except Exception as e:
|
@@ -1182,6 +1200,8 @@ class Cursor(_BaseCursor):
|
|
1182
1200
|
sets = self._parameter_sets or 1
|
1183
1201
|
self.params = list(self.params).copy()
|
1184
1202
|
param_types = [param.type for param in self._params._params_list]
|
1203
|
+
if not self.params:
|
1204
|
+
return
|
1185
1205
|
|
1186
1206
|
for i in range(sets):
|
1187
1207
|
params = self._params.collect(i)
|
@@ -1949,7 +1969,12 @@ class Cursor(_BaseCursor):
|
|
1949
1969
|
self._closed = True
|
1950
1970
|
|
1951
1971
|
def executemany(self, operation, seq_of_params):
|
1952
|
-
|
1972
|
+
try:
|
1973
|
+
super().executemany(operation, seq_of_params)
|
1974
|
+
except InsertWithReturning:
|
1975
|
+
return
|
1976
|
+
except Exception:
|
1977
|
+
raise
|
1953
1978
|
self._rowcount = 0
|
1954
1979
|
for i in range(len(self.params)):
|
1955
1980
|
self._rowcount += self._in_message.wire._get()
|
@@ -2263,13 +2288,21 @@ class EmbdeddedCursor(_BaseCursor):
|
|
2263
2288
|
def __del__(self):
|
2264
2289
|
try:
|
2265
2290
|
self.close()
|
2266
|
-
except:
|
2291
|
+
except Exception:
|
2267
2292
|
pass
|
2268
2293
|
return
|
2269
2294
|
|
2270
2295
|
def _get_cached_info(self):
|
2271
2296
|
return False
|
2272
2297
|
|
2298
|
+
def executemany(self, operation, seq_of_params):
|
2299
|
+
try:
|
2300
|
+
super().executemany(operation, seq_of_params)
|
2301
|
+
except InsertWithReturning:
|
2302
|
+
return
|
2303
|
+
except Exception:
|
2304
|
+
raise
|
2305
|
+
|
2273
2306
|
def _get_parameters(self, params_set=0):
|
2274
2307
|
params = self._params.collect(params_set)
|
2275
2308
|
# None = '', '' = b'\x00'
|
@@ -2394,6 +2427,7 @@ class EmbdeddedCursor(_BaseCursor):
|
|
2394
2427
|
sqlcode = 0
|
2395
2428
|
message = None
|
2396
2429
|
try:
|
2430
|
+
print("!!!! _send_direct_query_request:params", [statement, params])
|
2397
2431
|
self._result_set = self._sql.exec(statement, *params)
|
2398
2432
|
self._rowcount = self._result_set.ResultSet._ROWCOUNT
|
2399
2433
|
self._get_column_info()
|
{sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/dbapi/_ResultSetRow.py
RENAMED
@@ -162,7 +162,7 @@ class _ResultSetRow:
|
|
162
162
|
self._list_item.next_offset = self._offsets[key]
|
163
163
|
_DBList._get_list_element(self._list_item)
|
164
164
|
item = _DBList._get(self._list_item, self._locale)
|
165
|
-
_column: _Column = self._columns[
|
165
|
+
_column: _Column = self._columns[key]
|
166
166
|
ctype = _column.type
|
167
167
|
value_type = self._types[ctype] if ctype in self._types else None
|
168
168
|
try:
|
{sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/dbapi/preparser/_PreParser.py
RENAMED
@@ -11,6 +11,7 @@ from intersystems_iris.dbapi._Parameter import ParameterMode
|
|
11
11
|
from intersystems_iris.dbapi.preparser._Token import TOKEN
|
12
12
|
from intersystems_iris.dbapi.preparser._Scanner import ParseToken
|
13
13
|
|
14
|
+
|
14
15
|
class MultiValuesInsert(Exception):
|
15
16
|
|
16
17
|
def __init__(self, *args: object, query: str, rows: int, params=None) -> None:
|
@@ -20,6 +21,15 @@ class MultiValuesInsert(Exception):
|
|
20
21
|
self.params = params
|
21
22
|
|
22
23
|
|
24
|
+
class InsertWithReturning(Exception):
|
25
|
+
|
26
|
+
def __init__(self, *args: object, insert_query: str, insert_params, select_query: str) -> None:
|
27
|
+
super().__init__(*args)
|
28
|
+
self.insert_query = insert_query
|
29
|
+
self.insert_params = insert_params
|
30
|
+
self.select_query = select_query
|
31
|
+
|
32
|
+
|
23
33
|
# May want to move to its own file eventually
|
24
34
|
# SQL Statement Types
|
25
35
|
class StatementType(enum.IntEnum):
|
@@ -480,6 +490,11 @@ class _PreParser(object):
|
|
480
490
|
if found_insert:
|
481
491
|
self.Tokenize(t_query)
|
482
492
|
|
493
|
+
_, t_query, t_select_query = self.InsertReturning(t_query)
|
494
|
+
if t_select_query:
|
495
|
+
raise InsertWithReturning(insert_query=t_query, insert_params=p_Parameters, select_query=t_select_query)
|
496
|
+
self.Tokenize(t_query)
|
497
|
+
|
483
498
|
# Resolve the tokens and determine output
|
484
499
|
return self.Resolve(t_query, p_Parameters)
|
485
500
|
|
@@ -549,9 +564,39 @@ class _PreParser(object):
|
|
549
564
|
new_query += _query(False)
|
550
565
|
|
551
566
|
return found, new_query
|
552
|
-
except:
|
567
|
+
except Exception:
|
553
568
|
return False, query
|
554
|
-
|
569
|
+
|
570
|
+
def InsertReturning(self, query):
|
571
|
+
plain_query = ''
|
572
|
+
|
573
|
+
tokens = self.m_Tokens.GetEnumerator()
|
574
|
+
keywords = list(self.s_StatementTable.keys()) + list(self.s_ParsedStatements.keys()) + list(self.s_TransactionStatements.keys())
|
575
|
+
while tokens.MoveNext() and not tokens.Current().UpperOnOf(keywords):
|
576
|
+
plain_query += tokens.Current().Lexeme + ' '
|
577
|
+
if tokens.AtEnd() or not tokens.Current().UpperEquals("INSERT"):
|
578
|
+
return False, query, None
|
579
|
+
|
580
|
+
if not tokens.MoveNext() or not tokens.Current().UpperEquals("INTO"):
|
581
|
+
return False, query, None
|
582
|
+
plain_query += 'INSERT INTO '
|
583
|
+
table_name = ""
|
584
|
+
while tokens.MoveNext() and not tokens.Current().UpperOnOf(["(", "SET", "VALUES", "DEFAULT"]):
|
585
|
+
table_name += tokens.Current().Lexeme + ' '
|
586
|
+
plain_query += table_name + ' ' + tokens.Current().Lexeme + ' '
|
587
|
+
while tokens.MoveNext() and not tokens.Current().UpperEquals("RETURNING"):
|
588
|
+
plain_query += tokens.Current().Lexeme + ' '
|
589
|
+
|
590
|
+
select_query = None
|
591
|
+
if not tokens.AtEnd():
|
592
|
+
select_query = 'SELECT '
|
593
|
+
while tokens.MoveNext():
|
594
|
+
select_query += tokens.Current().Lexeme + ' '
|
595
|
+
select_query += "FROM " + table_name
|
596
|
+
select_query += " WHERE %ID %INLIST ?"
|
597
|
+
|
598
|
+
return False, plain_query, select_query
|
599
|
+
|
555
600
|
def InsertMultiValues(self, query):
|
556
601
|
new_query = ''
|
557
602
|
values_list = []
|
@@ -580,7 +625,10 @@ class _PreParser(object):
|
|
580
625
|
break
|
581
626
|
if token.TokenType is TOKEN.CONSTANT:
|
582
627
|
values += '?'
|
583
|
-
|
628
|
+
param = token.Lexeme
|
629
|
+
if param.__len__ and param[0] == "'" and param[0] == param[-1]:
|
630
|
+
param = param[1: -1]
|
631
|
+
params += [param]
|
584
632
|
else:
|
585
633
|
values += token.Lexeme
|
586
634
|
values += ' '
|
@@ -1047,6 +1095,7 @@ class _PreParser(object):
|
|
1047
1095
|
nParamIndex += 1
|
1048
1096
|
if nParamIndex == length + 1:
|
1049
1097
|
break
|
1098
|
+
|
1050
1099
|
return pOut
|
1051
1100
|
|
1052
1101
|
# '?' represents a parameter; adds a parameter to p_Parameters if none were provided
|
{sqlalchemy_iris-0.15.5b1 → sqlalchemy_iris-0.16.0}/intersystems_iris/dbapi/preparser/_Token.py
RENAMED
@@ -76,6 +76,9 @@ It records the classification of the token as well as retaining the original str
|
|
76
76
|
def UpperEquals(self, p_str):
|
77
77
|
return self.UpperLexeme == p_str
|
78
78
|
|
79
|
+
def UpperOnOf(self, p_str_list):
|
80
|
+
return self.UpperLexeme in p_str_list
|
81
|
+
|
79
82
|
def UpperContains(self, p_str):
|
80
83
|
return p_str in self.UpperLexeme
|
81
84
|
|
@@ -653,6 +653,20 @@ class IRISDDLCompiler(sql.compiler.DDLCompiler):
|
|
653
653
|
def visit_check_constraint(self, constraint, **kw):
|
654
654
|
pass
|
655
655
|
|
656
|
+
def create_table_constraints(self, table, **kw):
|
657
|
+
description = ""
|
658
|
+
comment = table.comment
|
659
|
+
if comment:
|
660
|
+
# hack to keep \r, kind of
|
661
|
+
comment = comment.replace('\r', '\n\t')
|
662
|
+
literal = self.sql_compiler.render_literal_value(comment, sqltypes.String())
|
663
|
+
description = "%DESCRIPTION " + literal
|
664
|
+
|
665
|
+
constraints = super().create_table_constraints(table, **kw)
|
666
|
+
if constraints and description:
|
667
|
+
description = ", \n\t" + description
|
668
|
+
return constraints + description
|
669
|
+
|
656
670
|
def visit_add_constraint(self, create, **kw):
|
657
671
|
if isinstance(create.element, schema.CheckConstraint):
|
658
672
|
raise exc.CompileError("Can't add CHECK constraint")
|
@@ -701,6 +715,7 @@ class IRISDDLCompiler(sql.compiler.DDLCompiler):
|
|
701
715
|
|
702
716
|
comment = column.comment
|
703
717
|
if comment is not None:
|
718
|
+
comment = comment.replace('\r', '\n\t')
|
704
719
|
literal = self.sql_compiler.render_literal_value(comment, sqltypes.String())
|
705
720
|
colspec.append("%DESCRIPTION " + literal)
|
706
721
|
|
@@ -883,6 +898,12 @@ class IRISDialect(default.DefaultDialect):
|
|
883
898
|
type_compiler = IRISTypeCompiler
|
884
899
|
execution_ctx_cls = IRISExecutionContext
|
885
900
|
|
901
|
+
insert_returning = True
|
902
|
+
insert_executemany_returning = True
|
903
|
+
insert_executemany_returning_sort_by_parameter_order = True
|
904
|
+
update_executemany_returning = False
|
905
|
+
delete_executemany_returning = False
|
906
|
+
|
886
907
|
construct_arguments = [
|
887
908
|
(schema.Index, {"include": None}),
|
888
909
|
]
|
@@ -1105,6 +1126,38 @@ There are no access to %Dictionary, may be required for some advanced features,
|
|
1105
1126
|
return "SQLUser"
|
1106
1127
|
return schema
|
1107
1128
|
|
1129
|
+
@reflection.cache
|
1130
|
+
def get_table_options(self, connection, table_name, schema=None, **kw):
|
1131
|
+
if not self.has_table(connection=connection, table_name=table_name, schema=schema):
|
1132
|
+
raise exc.NoSuchTableError(
|
1133
|
+
f"{schema}.{table_name}" if schema else table_name
|
1134
|
+
) from None
|
1135
|
+
return {}
|
1136
|
+
|
1137
|
+
@reflection.cache
|
1138
|
+
def get_table_comment(self, connection, table_name, schema=None, **kw):
|
1139
|
+
if not self.has_table(connection=connection, table_name=table_name, schema=schema):
|
1140
|
+
raise exc.NoSuchTableError(
|
1141
|
+
f"{schema}.{table_name}" if schema else table_name
|
1142
|
+
) from None
|
1143
|
+
|
1144
|
+
tables = ischema.tables
|
1145
|
+
schema_name = self.get_schema(schema)
|
1146
|
+
|
1147
|
+
s = sql.select(tables.c.description).where(
|
1148
|
+
sql.and_(
|
1149
|
+
tables.c.table_schema == str(schema_name),
|
1150
|
+
tables.c.table_name == str(table_name),
|
1151
|
+
)
|
1152
|
+
)
|
1153
|
+
comment = connection.execute(s).scalar()
|
1154
|
+
if comment:
|
1155
|
+
# make it as \r
|
1156
|
+
comment = comment.replace(' \t\t\t\t', '\r')
|
1157
|
+
# restore \n
|
1158
|
+
comment = comment.replace(' \t\t\t', '\n')
|
1159
|
+
return {"text": comment}
|
1160
|
+
|
1108
1161
|
@reflection.cache
|
1109
1162
|
def get_schema_names(self, connection, **kw):
|
1110
1163
|
s = sql.select(ischema.schemata.c.schema_name).order_by(
|
@@ -1131,7 +1184,7 @@ There are no access to %Dictionary, may be required for some advanced features,
|
|
1131
1184
|
return table_names
|
1132
1185
|
|
1133
1186
|
@reflection.cache
|
1134
|
-
def get_temp_table_names(self, connection,
|
1187
|
+
def get_temp_table_names(self, connection, **kw):
|
1135
1188
|
tables = ischema.tables
|
1136
1189
|
s = (
|
1137
1190
|
sql.select(tables.c.table_name)
|
@@ -1598,6 +1651,7 @@ There are no access to %Dictionary, may be required for some advanced features,
|
|
1598
1651
|
columns.c.column_default,
|
1599
1652
|
columns.c.collation_name,
|
1600
1653
|
columns.c.auto_increment,
|
1654
|
+
columns.c.description,
|
1601
1655
|
)
|
1602
1656
|
.select_from(columns)
|
1603
1657
|
.where(
|
@@ -1650,7 +1704,12 @@ There are no access to %Dictionary, may be required for some advanced features,
|
|
1650
1704
|
sqlComputeCode = row[property.c.SqlComputeCode]
|
1651
1705
|
calculated = row[property.c.Calculated]
|
1652
1706
|
transient = row[property.c.Transient]
|
1653
|
-
|
1707
|
+
comment = row[columns.c.description]
|
1708
|
+
if comment:
|
1709
|
+
# make it as \r
|
1710
|
+
comment = comment.replace(' \t\t\t\t', '\r')
|
1711
|
+
# restore \n
|
1712
|
+
comment = comment.replace(' \t\t\t', '\n')
|
1654
1713
|
|
1655
1714
|
coltype = self.ischema_names.get(type_, None)
|
1656
1715
|
|
@@ -1696,7 +1755,7 @@ There are no access to %Dictionary, may be required for some advanced features,
|
|
1696
1755
|
"nullable": nullable,
|
1697
1756
|
"default": default,
|
1698
1757
|
"autoincrement": autoincrement,
|
1699
|
-
|
1758
|
+
"comment": comment,
|
1700
1759
|
}
|
1701
1760
|
if sqlComputeCode and "set {*} = " in sqlComputeCode.lower():
|
1702
1761
|
sqltext = sqlComputeCode
|
@@ -44,6 +44,7 @@ tables = Table(
|
|
44
44
|
Column("TABLE_NAME", String, key="table_name"),
|
45
45
|
Column("TABLE_TYPE", String, key="table_type"),
|
46
46
|
Column("CLASSNAME", String, key="classname"),
|
47
|
+
Column("DESCRIPTION", String, key="description"),
|
47
48
|
schema="INFORMATION_SCHEMA",
|
48
49
|
)
|
49
50
|
|
@@ -69,7 +70,7 @@ columns = Table(
|
|
69
70
|
Column("AUTO_INCREMENT", YESNO, key="auto_increment"),
|
70
71
|
Column("UNIQUE_COLUMN", YESNO, key="unique_column"),
|
71
72
|
Column("PRIMARY_KEY", YESNO, key="primary_key"),
|
72
|
-
Column("
|
73
|
+
Column("DESCRIPTION", String, key="description"),
|
73
74
|
schema="INFORMATION_SCHEMA",
|
74
75
|
)
|
75
76
|
property_definition = Table(
|
@@ -58,6 +58,22 @@ class Requirements(SuiteRequirements, AlembicRequirements):
|
|
58
58
|
|
59
59
|
return exclusions.open()
|
60
60
|
|
61
|
+
@property
|
62
|
+
def reflect_table_options(self):
|
63
|
+
return exclusions.open()
|
64
|
+
|
65
|
+
@property
|
66
|
+
def comment_reflection(self):
|
67
|
+
return exclusions.open()
|
68
|
+
|
69
|
+
@property
|
70
|
+
def insert_returning(self):
|
71
|
+
return exclusions.open()
|
72
|
+
|
73
|
+
@property
|
74
|
+
def unusual_column_name_characters(self):
|
75
|
+
return exclusions.open()
|
76
|
+
|
61
77
|
@property
|
62
78
|
def computed_columns(self):
|
63
79
|
"Supports computed columns"
|
@@ -1,6 +1,6 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.2
|
2
2
|
Name: sqlalchemy-iris
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.16.0
|
4
4
|
Summary: InterSystems IRIS for SQLAlchemy
|
5
5
|
Home-page: https://github.com/caretdev/sqlalchemy-iris
|
6
6
|
Maintainer: CaretDev
|
@@ -23,6 +23,7 @@ Requires-Python: >=3.8
|
|
23
23
|
Description-Content-Type: text/markdown
|
24
24
|
License-File: LICENSE
|
25
25
|
Requires-Dist: SQLAlchemy>=1.3
|
26
|
+
Dynamic: requires-dist
|
26
27
|
|
27
28
|
sqlalchemy-iris
|
28
29
|
===
|
@@ -65,12 +65,6 @@ intersystems_iris/pex/_InboundAdapter.py
|
|
65
65
|
intersystems_iris/pex/_Message.py
|
66
66
|
intersystems_iris/pex/_OutboundAdapter.py
|
67
67
|
intersystems_iris/pex/__init__.py
|
68
|
-
iris/__init__.py
|
69
|
-
iris/__init__.pyi
|
70
|
-
iris/_cli.py
|
71
|
-
iris/iris_ipm.py
|
72
|
-
iris/iris_ipm.pyi
|
73
|
-
iris/iris_utils.py
|
74
68
|
irisnative/_IRISNative.py
|
75
69
|
irisnative/__init__.py
|
76
70
|
sqlalchemy_iris/__init__.py
|
@@ -70,7 +70,9 @@ else:
|
|
70
70
|
self.meta.drop_all(connection)
|
71
71
|
|
72
72
|
def test_drop_col_with_fk(self, ops_context, connection, tables):
|
73
|
-
ops_context.drop_column(
|
73
|
+
ops_context.drop_column(
|
74
|
+
"round_trip_table", "oid_fk", schema=self.meta.schema
|
75
|
+
)
|
74
76
|
insp = inspect(connection)
|
75
77
|
eq_(insp.get_foreign_keys("round_trip_table", schema=self.meta.schema), [])
|
76
78
|
|
@@ -112,9 +114,9 @@ else:
|
|
112
114
|
|
113
115
|
result = connection.execute(text("select col from tab")).all()
|
114
116
|
assert result == [
|
115
|
-
(
|
116
|
-
(
|
117
|
-
(
|
117
|
+
(b"some data 1",),
|
118
|
+
(b"some data 2",),
|
119
|
+
(b"some data 3",),
|
118
120
|
]
|
119
121
|
|
120
122
|
insp = inspect(connection)
|
@@ -2,6 +2,8 @@ from enum import Enum
|
|
2
2
|
|
3
3
|
from sqlalchemy.testing.suite import FetchLimitOffsetTest as _FetchLimitOffsetTest
|
4
4
|
from sqlalchemy.testing.suite import CompoundSelectTest as _CompoundSelectTest
|
5
|
+
from sqlalchemy.testing.suite import TableDDLTest as _TableDDLTest
|
6
|
+
from sqlalchemy.testing.suite import FutureTableDDLTest as _FutureTableDDLTest
|
5
7
|
from sqlalchemy.testing.suite import CTETest as _CTETest
|
6
8
|
from sqlalchemy.testing.suite import DifficultParametersTest as _DifficultParametersTest
|
7
9
|
from sqlalchemy.testing import fixtures
|
@@ -63,9 +65,19 @@ class CTETest(_CTETest):
|
|
63
65
|
pass
|
64
66
|
|
65
67
|
|
66
|
-
@pytest.mark.skip()
|
67
68
|
class DifficultParametersTest(_DifficultParametersTest):
|
68
|
-
|
69
|
+
|
70
|
+
tough_parameters = _DifficultParametersTest.tough_parameters
|
71
|
+
|
72
|
+
@tough_parameters
|
73
|
+
def test_round_trip_same_named_column(
|
74
|
+
self, paramname, connection, metadata
|
75
|
+
):
|
76
|
+
if paramname == 'dot.s':
|
77
|
+
# not supported
|
78
|
+
pytest.skip()
|
79
|
+
return
|
80
|
+
super().test_round_trip_same_named_column(paramname, connection, metadata)
|
69
81
|
|
70
82
|
|
71
83
|
class FetchLimitOffsetTest(_FetchLimitOffsetTest):
|
@@ -486,3 +498,21 @@ class ConcatTest(fixtures.TablesTest):
|
|
486
498
|
("sometestdata",),
|
487
499
|
],
|
488
500
|
)
|
501
|
+
|
502
|
+
|
503
|
+
class TableDDLTest(_TableDDLTest):
|
504
|
+
# IRIS does not want to update comments on the fly
|
505
|
+
def test_add_table_comment(self, connection):
|
506
|
+
pass
|
507
|
+
|
508
|
+
def test_drop_table_comment(self, connection):
|
509
|
+
pass
|
510
|
+
|
511
|
+
|
512
|
+
class FutureTableDDLTest(_FutureTableDDLTest):
|
513
|
+
# IRIS does not want to update comments on the fly
|
514
|
+
def test_add_table_comment(self, connection):
|
515
|
+
pass
|
516
|
+
|
517
|
+
def test_drop_table_comment(self, connection):
|
518
|
+
pass
|
@@ -1,66 +0,0 @@
|
|
1
|
-
import os
|
2
|
-
import sys
|
3
|
-
import importlib
|
4
|
-
|
5
|
-
from .iris_ipm import ipm
|
6
|
-
from .iris_utils import update_dynalib_path
|
7
|
-
|
8
|
-
# check for install dir in environment
|
9
|
-
# environment to check is IRISINSTALLDIR
|
10
|
-
# if not found, raise exception and exit
|
11
|
-
# ISC_PACKAGE_INSTALLDIR - defined by default in Docker images
|
12
|
-
installdir = os.environ.get('IRISINSTALLDIR') or os.environ.get('ISC_PACKAGE_INSTALLDIR')
|
13
|
-
if installdir is None:
|
14
|
-
raise Exception("""Cannot find InterSystems IRIS installation directory
|
15
|
-
Please set IRISINSTALLDIR environment variable to the InterSystems IRIS installation directory""")
|
16
|
-
|
17
|
-
__sysversion_info = sys.version_info
|
18
|
-
__syspath = sys.path
|
19
|
-
__osname = os.name
|
20
|
-
|
21
|
-
# join the install dir with the bin directory
|
22
|
-
__syspath.append(os.path.join(installdir, 'bin'))
|
23
|
-
# also append lib/python
|
24
|
-
__syspath.append(os.path.join(installdir, 'lib', 'python'))
|
25
|
-
|
26
|
-
# update the dynalib path
|
27
|
-
update_dynalib_path(os.path.join(installdir, 'bin'))
|
28
|
-
|
29
|
-
# save working directory
|
30
|
-
__ospath = os.getcwd()
|
31
|
-
|
32
|
-
__irispythonint = None
|
33
|
-
|
34
|
-
if __osname=='nt':
|
35
|
-
if __sysversion_info.minor==9:
|
36
|
-
__irispythonint = 'pythonint39'
|
37
|
-
elif __sysversion_info.minor==10:
|
38
|
-
__irispythonint = 'pythonint310'
|
39
|
-
elif __sysversion_info.minor==11:
|
40
|
-
__irispythonint = 'pythonint311'
|
41
|
-
elif __sysversion_info.minor==12:
|
42
|
-
__irispythonint = 'pythonint312'
|
43
|
-
elif __sysversion_info.minor==13:
|
44
|
-
__irispythonint = 'pythonint313'
|
45
|
-
else:
|
46
|
-
__irispythonint = 'pythonint'
|
47
|
-
|
48
|
-
if __irispythonint is not None:
|
49
|
-
# equivalent to from pythonint import *
|
50
|
-
try:
|
51
|
-
__irispythonintmodule = importlib.import_module(__irispythonint)
|
52
|
-
except ImportError:
|
53
|
-
__irispythonint = 'pythonint'
|
54
|
-
__irispythonintmodule = importlib.import_module(__irispythonint)
|
55
|
-
globals().update(vars(__irispythonintmodule))
|
56
|
-
|
57
|
-
# restore working directory
|
58
|
-
os.chdir(__ospath)
|
59
|
-
|
60
|
-
# TODO: Figure out how to hide __syspath and __ospath from anyone that
|
61
|
-
# imports iris. Tried __all__ but that only applies to this:
|
62
|
-
# from iris import *
|
63
|
-
|
64
|
-
#
|
65
|
-
# End-of-file
|
66
|
-
#
|