deev 2.0.1__tar.gz → 2.0.2__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.
- {deev-2.0.1/src/deev.egg-info → deev-2.0.2}/PKG-INFO +1 -1
- {deev-2.0.1 → deev-2.0.2}/pyproject.toml +1 -1
- {deev-2.0.1 → deev-2.0.2}/src/deev/__init__.py +2 -2
- {deev-2.0.1 → deev-2.0.2}/src/deev/clickhouse/async_clickhouse_table_adapter.py +0 -2
- {deev-2.0.1 → deev-2.0.2}/src/deev/clickhouse/async_clickhouse_transaction_context.py +10 -6
- {deev-2.0.1 → deev-2.0.2}/src/deev/clickhouse/clickhouse_table_adapter.py +0 -2
- {deev-2.0.1 → deev-2.0.2}/src/deev/clickhouse/clickhouse_transaction_context.py +10 -6
- {deev-2.0.1 → deev-2.0.2}/src/deev/common/async_db_transaction_context.py +1 -1
- {deev-2.0.1 → deev-2.0.2}/src/deev/common/db_migrator.py +0 -1
- {deev-2.0.1 → deev-2.0.2}/src/deev/common/db_transaction_context.py +1 -1
- {deev-2.0.1 → deev-2.0.2}/src/deev/common/tlc_parser.py +46 -23
- {deev-2.0.1 → deev-2.0.2}/src/deev/mongodb/async_mongo_table_adapter.py +0 -2
- {deev-2.0.1 → deev-2.0.2}/src/deev/mongodb/async_mongo_transaction_context.py +11 -7
- {deev-2.0.1 → deev-2.0.2}/src/deev/mongodb/mongo_table_adapter.py +0 -2
- {deev-2.0.1 → deev-2.0.2}/src/deev/mongodb/mongo_transaction_context.py +11 -7
- {deev-2.0.1 → deev-2.0.2}/src/deev/mysql/async_mysql_proxy_cursor.py +2 -4
- {deev-2.0.1 → deev-2.0.2}/src/deev/mysql/async_mysql_table_adapter.py +0 -2
- {deev-2.0.1 → deev-2.0.2}/src/deev/mysql/async_mysql_transaction_context.py +11 -8
- {deev-2.0.1 → deev-2.0.2}/src/deev/mysql/mysql_proxy_cursor.py +2 -4
- {deev-2.0.1 → deev-2.0.2}/src/deev/mysql/mysql_table_adapter.py +0 -2
- {deev-2.0.1 → deev-2.0.2}/src/deev/mysql/mysql_transaction_context.py +18 -10
- {deev-2.0.1 → deev-2.0.2}/src/deev/sqlite/async_sqlite_transaction_context.py +1 -1
- {deev-2.0.1 → deev-2.0.2}/src/deev/sqlite/sqlite_proxy_cursor.py +2 -5
- {deev-2.0.1 → deev-2.0.2}/src/deev/sqlite/sqlite_table_adapter.py +0 -2
- {deev-2.0.1 → deev-2.0.2}/src/deev/sqlite/sqlite_transaction_context.py +16 -15
- {deev-2.0.1 → deev-2.0.2}/src/deev/utils.py +1 -1
- {deev-2.0.1 → deev-2.0.2/src/deev.egg-info}/PKG-INFO +1 -1
- {deev-2.0.1 → deev-2.0.2}/LICENSE +0 -0
- {deev-2.0.1 → deev-2.0.2}/README.md +0 -0
- {deev-2.0.1 → deev-2.0.2}/setup.cfg +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev/SKILL.md +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev/_immutable_mixin.py +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev/_migration_data.py +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev/clickhouse/__init__.py +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev/clickhouse/async_clickhouse_proxy_connection.py +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev/clickhouse/async_clickhouse_proxy_cursor.py +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev/clickhouse/clickhouse_ddl_generator.py +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev/clickhouse/clickhouse_proxy_connection.py +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev/clickhouse/clickhouse_proxy_cursor.py +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev/clickhouse/clickhouse_type_mapper.py +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev/clickhouse/utils.py +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev/common/__init__.py +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev/common/async_db_adapter.py +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev/common/async_db_connection.py +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev/common/async_db_cursor.py +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev/common/async_db_table_adapter.py +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev/common/connection_string.py +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev/common/db_adapter.py +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev/common/db_connection.py +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev/common/db_context.py +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev/common/db_cursor.py +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev/common/db_error.py +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev/common/db_parameters.py +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev/common/db_table_adapter.py +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev/common/db_type_mapper.py +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev/common/description_field.py +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev/common/noop_cursor.py +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev/db_migrate.py +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev/entities/__init__.py +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev/entities/entity_field_spec.py +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev/entities/entity_spec.py +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev/entities/index_options.py +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev/entities/index_order.py +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev/entities/utils.py +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev/mongodb/__init__.py +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev/mongodb/async_mongo_proxy_connection.py +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev/mongodb/async_mongo_proxy_cursor.py +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev/mongodb/mongo_proxy_connection.py +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev/mongodb/mongo_proxy_cursor.py +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev/mongodb/mongo_type_mapper.py +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev/mongodb/utils.py +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev/mysql/__init__.py +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev/mysql/async_mysql_proxy_connection.py +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev/mysql/mysql_ddl_generator.py +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev/mysql/mysql_proxy_connection.py +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev/mysql/mysql_type_mapper.py +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev/py.typed +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev/sqlite/__init__.py +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev/sqlite/async_sqlite_proxy_connection.py +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev/sqlite/async_sqlite_proxy_cursor.py +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev/sqlite/async_sqlite_table_adapter.py +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev/sqlite/sqlite_ddl_generator.py +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev/sqlite/sqlite_proxy_connection.py +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev/sqlite/sqlite_type_mapper.py +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev/translation/__init__.py +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev/translation/deev_json_decoder.py +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev/translation/deev_json_encoder.py +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev/translation/utils.py +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev/validation/__init__.py +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev/validation/utils.py +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev/validation/validation_error.py +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev.egg-info/SOURCES.txt +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev.egg-info/dependency_links.txt +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev.egg-info/entry_points.txt +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev.egg-info/requires.txt +0 -0
- {deev-2.0.1 → deev-2.0.2}/src/deev.egg-info/top_level.txt +0 -0
|
@@ -45,7 +45,6 @@ class AsyncClickHouseTableAdapter(AsyncDbTableAdapter[TEntity]):
|
|
|
45
45
|
__logger: logging.Logger
|
|
46
46
|
__dbtype_mapper: DbTypeMapper
|
|
47
47
|
__table_name: str | None
|
|
48
|
-
__transaction_state: int
|
|
49
48
|
|
|
50
49
|
def __init__(
|
|
51
50
|
self,
|
|
@@ -59,7 +58,6 @@ class AsyncClickHouseTableAdapter(AsyncDbTableAdapter[TEntity]):
|
|
|
59
58
|
self.__create_table = create_table is True
|
|
60
59
|
self.__initialized = False
|
|
61
60
|
self.__table_name = table_name
|
|
62
|
-
self.__transaction_state = 0
|
|
63
61
|
self.__is_sync_replicas_enabled = sync_replicas is True and getattr(self.__context, 'is_replicated', False) is True
|
|
64
62
|
self.__logger = hanaro.get_logger()
|
|
65
63
|
|
|
@@ -94,8 +94,12 @@ class AsyncClickHouseTransactionContext(AsyncDbTransactionContext):
|
|
|
94
94
|
For ClickHouse: all TLC keywords return None (scrubbed) since ClickHouse
|
|
95
95
|
has no transaction support. Depth tracking is for diagnostics/consistency.
|
|
96
96
|
"""
|
|
97
|
-
if self.__transaction_depth
|
|
98
|
-
raise DbError('Cannot use a transaction context that has
|
|
97
|
+
if self.__transaction_depth == -1:
|
|
98
|
+
raise DbError('Cannot use a transaction context that has exited.')
|
|
99
|
+
elif self.__transaction_depth == -2:
|
|
100
|
+
raise DbError('Cannot use a transaction context that has been committed.')
|
|
101
|
+
elif self.__transaction_depth == -3:
|
|
102
|
+
raise DbError('Cannot use a transaction context that has been rolled back.')
|
|
99
103
|
|
|
100
104
|
sql_upper = sql.lstrip().upper()
|
|
101
105
|
prefix = sql_upper[:4]
|
|
@@ -119,12 +123,12 @@ class AsyncClickHouseTransactionContext(AsyncDbTransactionContext):
|
|
|
119
123
|
self.__savepoints.clear()
|
|
120
124
|
self.__transaction_name = None
|
|
121
125
|
self.__ambient_transaction_id.set(None)
|
|
126
|
+
self.__transaction_depth = -2
|
|
122
127
|
return None
|
|
123
128
|
|
|
124
129
|
elif prefix == 'ROLL':
|
|
125
130
|
if self.__transaction_depth == 0:
|
|
126
131
|
raise DbError('Cannot rollback, no transaction.')
|
|
127
|
-
self.__transaction_depth = 0
|
|
128
132
|
name = extract_rollback_name(sql)
|
|
129
133
|
|
|
130
134
|
if name:
|
|
@@ -141,7 +145,7 @@ class AsyncClickHouseTransactionContext(AsyncDbTransactionContext):
|
|
|
141
145
|
else:
|
|
142
146
|
pass # full rollback, depth reset below
|
|
143
147
|
|
|
144
|
-
self.__transaction_depth =
|
|
148
|
+
self.__transaction_depth = -3
|
|
145
149
|
self.__savepoints.clear()
|
|
146
150
|
self.__transaction_name = None
|
|
147
151
|
self.__ambient_transaction_id.set(None)
|
|
@@ -250,8 +254,8 @@ class AsyncClickHouseTransactionContext(AsyncDbTransactionContext):
|
|
|
250
254
|
except Exception:
|
|
251
255
|
return cursor.rowcount
|
|
252
256
|
|
|
253
|
-
async def execute_script(self, sql: str, raw:
|
|
254
|
-
if raw is
|
|
257
|
+
async def execute_script(self, sql: str, raw: bool = False) -> None:
|
|
258
|
+
if raw is True:
|
|
255
259
|
await self.execute(sql, raw=True)
|
|
256
260
|
return
|
|
257
261
|
lines = sql.split('\n')
|
|
@@ -41,7 +41,6 @@ class ClickHouseTableAdapter(Generic[TEntity]):
|
|
|
41
41
|
__initialized: bool
|
|
42
42
|
__logger: logging.Logger
|
|
43
43
|
__table_name: str | None
|
|
44
|
-
__transaction_state: int
|
|
45
44
|
|
|
46
45
|
def __init__(
|
|
47
46
|
self,
|
|
@@ -55,7 +54,6 @@ class ClickHouseTableAdapter(Generic[TEntity]):
|
|
|
55
54
|
self.__create_table = create_table is True
|
|
56
55
|
self.__initialized = False
|
|
57
56
|
self.__table_name = table_name
|
|
58
|
-
self.__transaction_state = 0
|
|
59
57
|
self.__is_sync_replicas_enabled = sync_replicas is True and getattr(self.__context, 'is_replicated', False) is True
|
|
60
58
|
self.__logger = hanaro.get_logger()
|
|
61
59
|
|
|
@@ -91,8 +91,12 @@ class ClickHouseTransactionContext(DbTransactionContext):
|
|
|
91
91
|
For ClickHouse: all TLC keywords return None (scrubbed) since ClickHouse
|
|
92
92
|
has no transaction support. Depth tracking is for diagnostics/consistency.
|
|
93
93
|
"""
|
|
94
|
-
if self.__transaction_depth
|
|
95
|
-
raise DbError('Cannot use a transaction context that has
|
|
94
|
+
if self.__transaction_depth == -1:
|
|
95
|
+
raise DbError('Cannot use a transaction context that has exited.')
|
|
96
|
+
elif self.__transaction_depth == -2:
|
|
97
|
+
raise DbError('Cannot use a transaction context that has been committed.')
|
|
98
|
+
elif self.__transaction_depth == -3:
|
|
99
|
+
raise DbError('Cannot use a transaction context that has been rolled back.')
|
|
96
100
|
|
|
97
101
|
sql_upper = sql.lstrip().upper()
|
|
98
102
|
prefix = sql_upper[:4]
|
|
@@ -116,12 +120,12 @@ class ClickHouseTransactionContext(DbTransactionContext):
|
|
|
116
120
|
self.__savepoints.clear()
|
|
117
121
|
self.__transaction_name = None
|
|
118
122
|
self.__ambient_transaction_id.set(None)
|
|
123
|
+
self.__transaction_depth = -2
|
|
119
124
|
return None
|
|
120
125
|
|
|
121
126
|
elif prefix == 'ROLL':
|
|
122
127
|
if self.__transaction_depth == 0:
|
|
123
128
|
raise DbError('Cannot rollback, no transaction.')
|
|
124
|
-
self.__transaction_depth = 0
|
|
125
129
|
name = extract_rollback_name(sql)
|
|
126
130
|
|
|
127
131
|
if name:
|
|
@@ -138,7 +142,7 @@ class ClickHouseTransactionContext(DbTransactionContext):
|
|
|
138
142
|
else:
|
|
139
143
|
pass # full rollback, depth reset below
|
|
140
144
|
|
|
141
|
-
self.__transaction_depth =
|
|
145
|
+
self.__transaction_depth = -3
|
|
142
146
|
self.__savepoints.clear()
|
|
143
147
|
self.__transaction_name = None
|
|
144
148
|
self.__ambient_transaction_id.set(None)
|
|
@@ -242,8 +246,8 @@ class ClickHouseTransactionContext(DbTransactionContext):
|
|
|
242
246
|
except Exception:
|
|
243
247
|
return cursor.rowcount
|
|
244
248
|
|
|
245
|
-
def execute_script(self, sql: str, raw:
|
|
246
|
-
if raw is
|
|
249
|
+
def execute_script(self, sql: str, raw: bool = False) -> None:
|
|
250
|
+
if raw is True:
|
|
247
251
|
self.execute(sql, raw=True)
|
|
248
252
|
return
|
|
249
253
|
lines = sql.split('\n')
|
|
@@ -64,7 +64,7 @@ class AsyncDbTransactionContext(Protocol):
|
|
|
64
64
|
async def execute(self, sql: str, parameters: DbParameters | None = ..., raw: bool = ...) -> AsyncDbCursor:
|
|
65
65
|
...
|
|
66
66
|
|
|
67
|
-
async def execute_script(self, sql: str) -> None:
|
|
67
|
+
async def execute_script(self, sql: str, raw: bool = ...) -> None:
|
|
68
68
|
...
|
|
69
69
|
|
|
70
70
|
async def execute_nonquery(self, sql: str, parameters: DbParameters | None = ...) -> None:
|
|
@@ -161,7 +161,6 @@ class DbMigrator:
|
|
|
161
161
|
if migration_func is not None:
|
|
162
162
|
with begin_transaction(self.__connectionstring) as db_transaction:
|
|
163
163
|
migration_func(db_transaction)
|
|
164
|
-
db_transaction.commit()
|
|
165
164
|
# NOTE: callee (migration_func) is responsible for calling commit (or rollback)
|
|
166
165
|
migrations_table.delete(id=applied_migrations.get(migration_name, 0))
|
|
167
166
|
migrations_table.commit()
|
|
@@ -58,7 +58,7 @@ class DbTransactionContext(Protocol):
|
|
|
58
58
|
def execute(self, sql: str, parameters: DbParameters | None = ...) -> DbCursor:
|
|
59
59
|
...
|
|
60
60
|
|
|
61
|
-
def execute_script(self, sql: str) -> None:
|
|
61
|
+
def execute_script(self, sql: str, raw: bool = ...) -> None:
|
|
62
62
|
...
|
|
63
63
|
|
|
64
64
|
def execute_nonquery(self, sql: str, parameters: DbParameters | None = ...) -> None:
|
|
@@ -17,6 +17,11 @@ _BEGIN_PATTERN = re.compile(
|
|
|
17
17
|
re.IGNORECASE,
|
|
18
18
|
)
|
|
19
19
|
|
|
20
|
+
_START_PATTERN = re.compile(
|
|
21
|
+
r'^START\s+TRANSACTION\s+(\S+)',
|
|
22
|
+
re.IGNORECASE,
|
|
23
|
+
)
|
|
24
|
+
|
|
20
25
|
_SAVEPOINT_PATTERN = re.compile(
|
|
21
26
|
r'^(?:SAVEPOINT|SAVE\s+(?:TRANSACTION|TRAN))\s+(\S+)',
|
|
22
27
|
re.IGNORECASE,
|
|
@@ -24,14 +29,35 @@ _SAVEPOINT_PATTERN = re.compile(
|
|
|
24
29
|
|
|
25
30
|
# Handles: ROLLBACK name, ROLLBACK TO name, ROLLBACK TO SAVEPOINT name,
|
|
26
31
|
# ROLLBACK TRANSACTION name, ROLLBACK TO TRANSACTION name, etc.
|
|
27
|
-
#
|
|
28
|
-
#
|
|
29
|
-
|
|
32
|
+
# All valid syntaxes are enumerated as explicit alternations so the regex
|
|
33
|
+
# engine never backtracks into capturing bare keywords as names.
|
|
30
34
|
_ROLLBACK_TO_PREFIX = re.compile(
|
|
31
35
|
r'^ROLLBACK\s+TO\s',
|
|
32
36
|
re.IGNORECASE,
|
|
33
37
|
)
|
|
34
38
|
|
|
39
|
+
# Each alternative requires a name; alternatives that match return the
|
|
40
|
+
# captured group. Nothing else matches, so bare keywords return None.
|
|
41
|
+
_ROLLBACK_PATTERN = re.compile(
|
|
42
|
+
r'^ROLLBACK\s+'
|
|
43
|
+
r'(?:'
|
|
44
|
+
r'TO\s+SAVEPOINT\s+TRAN(?=\s|$)\s+(\S+)' # ROLLBACK TO SAVEPOINT TRAN name
|
|
45
|
+
r'|TO\s+SAVEPOINT\s+TRANSACTION\s+(\S+)' # ROLLBACK TO SAVEPOINT TRANSACTION name
|
|
46
|
+
r'|TO\s+SAVEPOINT\s+(\S+)' # ROLLBACK TO SAVEPOINT name
|
|
47
|
+
r'|TO\s+TRANSACTION\s+(\S+)' # ROLLBACK TO TRANSACTION name
|
|
48
|
+
r'|TO\s+TRAN(?=\s|$)\s+(\S+)' # ROLLBACK TO TRAN name
|
|
49
|
+
r'|TO\s+(?!SAVEPOINT\s*$|TRAN\s*$|TRANSACTION\s*$)(\S+)' # ROLLBACK TO name
|
|
50
|
+
r'|TRANSACTION\s+(\S+)' # ROLLBACK TRANSACTION name
|
|
51
|
+
r'|TRAN(?=\s|$)\s+(\S+)' # ROLLBACK TRAN name
|
|
52
|
+
# Reject bare keywords and TO-prefixed bare keywords
|
|
53
|
+
r'|(?!SAVEPOINT\s*$|TRANSACTION\s*$|TRAN\s*$'
|
|
54
|
+
r'|TO\s+(?:SAVEPOINT|TRAN|TRANSACTION)\s*$' # TO SAVEPOINT, TO TRAN, TO TRANSACTION
|
|
55
|
+
r'|TO\s*$)' # bare TO
|
|
56
|
+
r'\s*(\S+)' # ROLLBACK name
|
|
57
|
+
r')',
|
|
58
|
+
re.IGNORECASE,
|
|
59
|
+
)
|
|
60
|
+
|
|
35
61
|
|
|
36
62
|
def extract_begin_name(sql: str) -> str | None:
|
|
37
63
|
"""Extract the transaction name from a ``BEGIN [TRANSACTION|TRAN] name`` statement.
|
|
@@ -43,6 +69,16 @@ def extract_begin_name(sql: str) -> str | None:
|
|
|
43
69
|
return m.group(1) if m else None
|
|
44
70
|
|
|
45
71
|
|
|
72
|
+
def extract_start_name(sql: str) -> str | None:
|
|
73
|
+
"""Extract the transaction name from a ``START TRANSACTION name`` statement.
|
|
74
|
+
|
|
75
|
+
Returns the name exactly as written in the original SQL, or ``None`` if no
|
|
76
|
+
name is present.
|
|
77
|
+
"""
|
|
78
|
+
m = _START_PATTERN.match(sql.lstrip())
|
|
79
|
+
return m.group(1) if m else None
|
|
80
|
+
|
|
81
|
+
|
|
46
82
|
def extract_savepoint_name(sql: str) -> str | None:
|
|
47
83
|
"""Extract the savepoint name from a ``SAVEPOINT name`` or ``SAVE [TRANSACTION|TRAN] name`` statement.
|
|
48
84
|
|
|
@@ -59,27 +95,13 @@ def extract_rollback_name(sql: str) -> str | None:
|
|
|
59
95
|
Returns the name exactly as written in the original SQL, or ``None`` if no
|
|
60
96
|
name is present.
|
|
61
97
|
"""
|
|
62
|
-
|
|
63
|
-
if
|
|
98
|
+
m = _ROLLBACK_PATTERN.match(sql.lstrip())
|
|
99
|
+
if m is None:
|
|
64
100
|
return None
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
rest = rest[3:].lstrip()
|
|
70
|
-
|
|
71
|
-
# Skip optional "SAVEPOINT"
|
|
72
|
-
if rest.upper().startswith('SAVEPOINT'):
|
|
73
|
-
rest = rest[9:].lstrip()
|
|
74
|
-
# Skip optional "TRANSACTION" or "TRAN"
|
|
75
|
-
if rest.upper().startswith('TRANSACTION'):
|
|
76
|
-
rest = rest[11:].lstrip()
|
|
77
|
-
elif rest.upper().startswith('TRAN '):
|
|
78
|
-
rest = rest[5:].lstrip()
|
|
79
|
-
|
|
80
|
-
# Extract name
|
|
81
|
-
name = rest.split()[0] if rest else None
|
|
82
|
-
return name
|
|
101
|
+
for group in m.groups():
|
|
102
|
+
if group is not None:
|
|
103
|
+
return group
|
|
104
|
+
return None
|
|
83
105
|
|
|
84
106
|
|
|
85
107
|
def is_rollback_to(sql: str) -> bool:
|
|
@@ -93,6 +115,7 @@ def is_rollback_to(sql: str) -> bool:
|
|
|
93
115
|
|
|
94
116
|
__all__ = [
|
|
95
117
|
'extract_begin_name',
|
|
118
|
+
'extract_start_name',
|
|
96
119
|
'extract_savepoint_name',
|
|
97
120
|
'extract_rollback_name',
|
|
98
121
|
'is_rollback_to'
|
|
@@ -41,7 +41,6 @@ class AsyncMongoTableAdapter(AsyncDbTableAdapter[TEntity]):
|
|
|
41
41
|
__initialized: bool
|
|
42
42
|
__dbtype_mapper: DbTypeMapper
|
|
43
43
|
__table_name: str | None
|
|
44
|
-
__transaction_state: int
|
|
45
44
|
|
|
46
45
|
def __init__(
|
|
47
46
|
self,
|
|
@@ -55,7 +54,6 @@ class AsyncMongoTableAdapter(AsyncDbTableAdapter[TEntity]):
|
|
|
55
54
|
self.__create_table = create_table is True
|
|
56
55
|
self.__initialized = False
|
|
57
56
|
self.__table_name = table_name
|
|
58
|
-
self.__transaction_state = 0
|
|
59
57
|
|
|
60
58
|
self.__database_name = self.__context.mongo_database_name # type: ignore[missing-attribute, union-attr]
|
|
61
59
|
|
|
@@ -109,8 +109,12 @@ class AsyncMongoTransactionContext(AsyncDbTransactionContext):
|
|
|
109
109
|
For MongoDB: all TLC keywords return None (scrubbed) since MongoDB has
|
|
110
110
|
no SQL transaction syntax. Side effects happen via mongo_session.
|
|
111
111
|
"""
|
|
112
|
-
if self.__transaction_depth
|
|
113
|
-
raise DbError('Cannot use a transaction context that has
|
|
112
|
+
if self.__transaction_depth == -1:
|
|
113
|
+
raise DbError('Cannot use a transaction context that has exited.')
|
|
114
|
+
elif self.__transaction_depth == -2:
|
|
115
|
+
raise DbError('Cannot use a transaction context that has been committed.')
|
|
116
|
+
elif self.__transaction_depth == -3:
|
|
117
|
+
raise DbError('Cannot use a transaction context that has been rolled back.')
|
|
114
118
|
|
|
115
119
|
sql_upper = sql.lstrip().upper()
|
|
116
120
|
prefix = sql_upper[:4]
|
|
@@ -136,14 +140,14 @@ class AsyncMongoTransactionContext(AsyncDbTransactionContext):
|
|
|
136
140
|
self.__savepoints.clear()
|
|
137
141
|
self.__transaction_name = None
|
|
138
142
|
self.__ambient_transaction_id.set(None)
|
|
139
|
-
|
|
143
|
+
self.__transaction_depth = -2
|
|
144
|
+
if not self.__delegate_mode and self.__transaction_depth == -2:
|
|
140
145
|
await self.mongo_session.commit_transaction()
|
|
141
146
|
return None
|
|
142
147
|
|
|
143
148
|
elif prefix == 'ROLL':
|
|
144
149
|
if self.__transaction_depth == 0:
|
|
145
150
|
raise DbError('Cannot rollback, no transaction.')
|
|
146
|
-
self.__transaction_depth = 0
|
|
147
151
|
name = extract_rollback_name(sql)
|
|
148
152
|
|
|
149
153
|
if name:
|
|
@@ -160,7 +164,7 @@ class AsyncMongoTransactionContext(AsyncDbTransactionContext):
|
|
|
160
164
|
else:
|
|
161
165
|
pass # full rollback, depth reset below
|
|
162
166
|
|
|
163
|
-
self.__transaction_depth =
|
|
167
|
+
self.__transaction_depth = -3
|
|
164
168
|
self.__savepoints.clear()
|
|
165
169
|
self.__transaction_name = None
|
|
166
170
|
self.__ambient_transaction_id.set(None)
|
|
@@ -282,8 +286,8 @@ class AsyncMongoTransactionContext(AsyncDbTransactionContext):
|
|
|
282
286
|
except Exception:
|
|
283
287
|
return cursor.rowcount
|
|
284
288
|
|
|
285
|
-
async def execute_script(self, sql: str, raw:
|
|
286
|
-
if raw is
|
|
289
|
+
async def execute_script(self, sql: str, raw: bool = False) -> None:
|
|
290
|
+
if raw is True:
|
|
287
291
|
await self.execute(sql, raw=True)
|
|
288
292
|
return
|
|
289
293
|
lines = sql.split('\n')
|
|
@@ -40,7 +40,6 @@ class MongoTableAdapter(Generic[TEntity]):
|
|
|
40
40
|
__initialized: bool
|
|
41
41
|
__dbtype_mapper: DbTypeMapper
|
|
42
42
|
__table_name: str | None
|
|
43
|
-
__transaction_state: int
|
|
44
43
|
|
|
45
44
|
def __init__(
|
|
46
45
|
self,
|
|
@@ -54,7 +53,6 @@ class MongoTableAdapter(Generic[TEntity]):
|
|
|
54
53
|
self.__create_table = create_table is True
|
|
55
54
|
self.__initialized = False
|
|
56
55
|
self.__table_name = table_name
|
|
57
|
-
self.__transaction_state = 0
|
|
58
56
|
|
|
59
57
|
self.__database_name = self.__context.mongo_database_name # type: ignore[missing-attribute, union-attr]
|
|
60
58
|
|
|
@@ -111,8 +111,12 @@ class MongoTransactionContext(DbTransactionContext):
|
|
|
111
111
|
For MongoDB: all TLC keywords return None (scrubbed) since MongoDB has
|
|
112
112
|
no SQL transaction syntax. Side effects happen via mongo_session.
|
|
113
113
|
"""
|
|
114
|
-
if self.__transaction_depth
|
|
115
|
-
raise DbError('Cannot use a transaction context that has
|
|
114
|
+
if self.__transaction_depth == -1:
|
|
115
|
+
raise DbError('Cannot use a transaction context that has exited.')
|
|
116
|
+
elif self.__transaction_depth == -2:
|
|
117
|
+
raise DbError('Cannot use a transaction context that has been committed.')
|
|
118
|
+
elif self.__transaction_depth == -3:
|
|
119
|
+
raise DbError('Cannot use a transaction context that has been rolled back.')
|
|
116
120
|
|
|
117
121
|
sql_upper = sql.lstrip().upper()
|
|
118
122
|
prefix = sql_upper[:4]
|
|
@@ -138,14 +142,14 @@ class MongoTransactionContext(DbTransactionContext):
|
|
|
138
142
|
self.__savepoints.clear()
|
|
139
143
|
self.__transaction_name = None
|
|
140
144
|
self.__ambient_transaction_id.set(None)
|
|
141
|
-
|
|
145
|
+
self.__transaction_depth = -2
|
|
146
|
+
if not self.__delegate_mode and self.__transaction_depth == -2:
|
|
142
147
|
self.mongo_session.commit_transaction()
|
|
143
148
|
return None
|
|
144
149
|
|
|
145
150
|
elif prefix == 'ROLL':
|
|
146
151
|
if self.__transaction_depth == 0:
|
|
147
152
|
raise DbError('Cannot rollback, no transaction.')
|
|
148
|
-
self.__transaction_depth = 0
|
|
149
153
|
name = extract_rollback_name(sql)
|
|
150
154
|
|
|
151
155
|
if name:
|
|
@@ -162,7 +166,7 @@ class MongoTransactionContext(DbTransactionContext):
|
|
|
162
166
|
else:
|
|
163
167
|
pass # full rollback, depth reset below
|
|
164
168
|
|
|
165
|
-
self.__transaction_depth =
|
|
169
|
+
self.__transaction_depth = -3
|
|
166
170
|
self.__savepoints.clear()
|
|
167
171
|
self.__transaction_name = None
|
|
168
172
|
self.__ambient_transaction_id.set(None)
|
|
@@ -281,8 +285,8 @@ class MongoTransactionContext(DbTransactionContext):
|
|
|
281
285
|
except Exception:
|
|
282
286
|
return cursor.rowcount
|
|
283
287
|
|
|
284
|
-
def execute_script(self, sql: str, raw:
|
|
285
|
-
if raw is
|
|
288
|
+
def execute_script(self, sql: str, raw: bool = False) -> None:
|
|
289
|
+
if raw is True:
|
|
286
290
|
self.execute(sql, raw=True)
|
|
287
291
|
return
|
|
288
292
|
lines = sql.split('\n')
|
|
@@ -39,16 +39,14 @@ class AsyncMySQLProxyCursor(AsyncDbCursor):
|
|
|
39
39
|
return self.__cursor.rowcount
|
|
40
40
|
|
|
41
41
|
async def execute(self, operation: str, parameters: DbParameters | None = None) -> None:
|
|
42
|
-
|
|
43
|
-
self.__logger.debug(f'execute({operation!r}, {parameters!r})')
|
|
44
|
-
if parameters is None:
|
|
42
|
+
if parameters is None or len(parameters) == 0:
|
|
45
43
|
await self.__cursor.execute(operation)
|
|
46
44
|
else:
|
|
45
|
+
operation = operation.replace(self.__sql_arg_expect, self.__sql_arg_subst)
|
|
47
46
|
await self.__cursor.execute(operation, parameters) # type: ignore[arg-type]
|
|
48
47
|
|
|
49
48
|
async def executemany(self, operation: str, seq_of_parameters: Sequence[DbParameters]) -> None:
|
|
50
49
|
operation = operation.replace(self.__sql_arg_expect, self.__sql_arg_subst)
|
|
51
|
-
self.__logger.debug(f'execute({operation!r}, {seq_of_parameters!r})')
|
|
52
50
|
await self.__cursor.executemany(operation, seq_of_parameters) # type: ignore[arg-type]
|
|
53
51
|
|
|
54
52
|
async def fetchone(self) -> tuple[Any, ...] | None:
|
|
@@ -38,7 +38,6 @@ class AsyncMySQLTableAdapter(AsyncDbTableAdapter[TEntity]):
|
|
|
38
38
|
__entity_spec: EntitySpec
|
|
39
39
|
__initialized: bool
|
|
40
40
|
__table_name: str | None
|
|
41
|
-
__transaction_state: int
|
|
42
41
|
|
|
43
42
|
def __init__(
|
|
44
43
|
self,
|
|
@@ -52,7 +51,6 @@ class AsyncMySQLTableAdapter(AsyncDbTableAdapter[TEntity]):
|
|
|
52
51
|
self.__create_table = create_table is True
|
|
53
52
|
self.__initialized = False
|
|
54
53
|
self.__table_name = table_name
|
|
55
|
-
self.__transaction_state = 0
|
|
56
54
|
|
|
57
55
|
async def __deferred_init(self) -> None:
|
|
58
56
|
if not self.__initialized:
|
|
@@ -95,8 +95,12 @@ class AsyncMySQLTransactionContext(AsyncDbTransactionContext):
|
|
|
95
95
|
|
|
96
96
|
MySQL-specific: strips name from START TRANSACTION (MySQL doesn't support named transactions).
|
|
97
97
|
"""
|
|
98
|
-
if self.__transaction_depth
|
|
99
|
-
raise DbError('Cannot use a transaction context that has
|
|
98
|
+
if self.__transaction_depth == -1:
|
|
99
|
+
raise DbError('Cannot use a transaction context that has exited.')
|
|
100
|
+
elif self.__transaction_depth == -2:
|
|
101
|
+
raise DbError('Cannot use a transaction context that has been committed.')
|
|
102
|
+
elif self.__transaction_depth == -3:
|
|
103
|
+
raise DbError('Cannot use a transaction context that has been rolled back.')
|
|
100
104
|
|
|
101
105
|
sql_upper = sql.lstrip().upper()
|
|
102
106
|
prefix = sql_upper[:4]
|
|
@@ -123,7 +127,7 @@ class AsyncMySQLTransactionContext(AsyncDbTransactionContext):
|
|
|
123
127
|
self.__savepoints.clear()
|
|
124
128
|
self.__transaction_name = None
|
|
125
129
|
self.__ambient_transaction_id.set(None)
|
|
126
|
-
|
|
130
|
+
self.__transaction_depth = -2
|
|
127
131
|
return 'COMMIT'
|
|
128
132
|
else:
|
|
129
133
|
return None
|
|
@@ -131,7 +135,6 @@ class AsyncMySQLTransactionContext(AsyncDbTransactionContext):
|
|
|
131
135
|
elif prefix == 'ROLL':
|
|
132
136
|
if self.__transaction_depth == 0:
|
|
133
137
|
raise DbError('Cannot rollback, no transaction.')
|
|
134
|
-
self.__transaction_depth = 0
|
|
135
138
|
name = extract_rollback_name(sql)
|
|
136
139
|
|
|
137
140
|
if name:
|
|
@@ -140,7 +143,7 @@ class AsyncMySQLTransactionContext(AsyncDbTransactionContext):
|
|
|
140
143
|
sp = self.__savepoints.pop()
|
|
141
144
|
if sp == name:
|
|
142
145
|
break
|
|
143
|
-
return 'ROLLBACK
|
|
146
|
+
return f'ROLLBACK TO SAVEPOINT {name}'
|
|
144
147
|
elif name == self.__transaction_name:
|
|
145
148
|
pass # full rollback, depth reset below
|
|
146
149
|
else:
|
|
@@ -148,7 +151,7 @@ class AsyncMySQLTransactionContext(AsyncDbTransactionContext):
|
|
|
148
151
|
else:
|
|
149
152
|
pass # full rollback, depth reset below
|
|
150
153
|
|
|
151
|
-
self.__transaction_depth =
|
|
154
|
+
self.__transaction_depth = -3
|
|
152
155
|
self.__savepoints.clear()
|
|
153
156
|
self.__transaction_name = None
|
|
154
157
|
self.__ambient_transaction_id.set(None)
|
|
@@ -242,8 +245,8 @@ class AsyncMySQLTransactionContext(AsyncDbTransactionContext):
|
|
|
242
245
|
except mysql.connector.ProgrammingError:
|
|
243
246
|
return cursor.rowcount
|
|
244
247
|
|
|
245
|
-
async def execute_script(self, sql: str, raw:
|
|
246
|
-
if raw is
|
|
248
|
+
async def execute_script(self, sql: str, raw: bool = False) -> None:
|
|
249
|
+
if raw is True:
|
|
247
250
|
await self.execute(sql, raw=True)
|
|
248
251
|
return
|
|
249
252
|
lines = sql.split('\n')
|
|
@@ -41,16 +41,14 @@ class MySQLProxyCursor(DbCursor):
|
|
|
41
41
|
return self.__cursor.rowcount
|
|
42
42
|
|
|
43
43
|
def execute(self, operation: str, parameters: DbParameters | None = None) -> None:
|
|
44
|
-
|
|
45
|
-
self.__logger.debug(f'execute({operation!r}, {parameters!r})')
|
|
46
|
-
if parameters is None:
|
|
44
|
+
if parameters is None or len(parameters) == 0:
|
|
47
45
|
self.__cursor.execute(operation)
|
|
48
46
|
else:
|
|
47
|
+
operation = operation.replace(self.__sql_arg_expect, self.__sql_arg_subst)
|
|
49
48
|
self.__cursor.execute(operation, parameters) # type: ignore[arg-type]
|
|
50
49
|
|
|
51
50
|
def executemany(self, operation: str, seq_of_parameters: Sequence[DbParameters]) -> None:
|
|
52
51
|
operation = operation.replace(self.__sql_arg_expect, self.__sql_arg_subst)
|
|
53
|
-
self.__logger.debug(f'execute({operation!r}, {seq_of_parameters!r})')
|
|
54
52
|
self.__cursor.executemany(operation, seq_of_parameters)
|
|
55
53
|
|
|
56
54
|
def fetchone(self) -> tuple[Any, ...] | None:
|
|
@@ -40,7 +40,6 @@ class MySQLTableAdapter(Generic[TEntity]):
|
|
|
40
40
|
__initialized: bool
|
|
41
41
|
__dbtype_mapper: DbTypeMapper
|
|
42
42
|
__table_name: str | None
|
|
43
|
-
__transaction_state: int
|
|
44
43
|
|
|
45
44
|
def __init__(
|
|
46
45
|
self,
|
|
@@ -54,7 +53,6 @@ class MySQLTableAdapter(Generic[TEntity]):
|
|
|
54
53
|
self.__create_table = create_table is True
|
|
55
54
|
self.__initialized = False
|
|
56
55
|
self.__table_name = table_name
|
|
57
|
-
self.__transaction_state = 0
|
|
58
56
|
|
|
59
57
|
def __deferred_init(self) -> None:
|
|
60
58
|
if not self.__initialized:
|
|
@@ -17,7 +17,7 @@ from ..common.db_cursor import DbCursor
|
|
|
17
17
|
from ..common.db_error import DbError
|
|
18
18
|
from ..common.db_parameters import DbParameters
|
|
19
19
|
from ..common.db_transaction_context import DbTransactionContext
|
|
20
|
-
from ..common.tlc_parser import extract_begin_name, extract_rollback_name, extract_savepoint_name
|
|
20
|
+
from ..common.tlc_parser import extract_begin_name, extract_rollback_name, extract_savepoint_name, extract_start_name
|
|
21
21
|
from .mysql_proxy_connection import MySQLProxyConnection
|
|
22
22
|
|
|
23
23
|
|
|
@@ -84,8 +84,12 @@ class MySQLTransactionContext(DbTransactionContext):
|
|
|
84
84
|
|
|
85
85
|
MySQL-specific: strips name from START TRANSACTION (MySQL doesn't support named transactions).
|
|
86
86
|
"""
|
|
87
|
-
if self.__transaction_depth
|
|
88
|
-
raise DbError('Cannot use a transaction context that has
|
|
87
|
+
if self.__transaction_depth == -1:
|
|
88
|
+
raise DbError('Cannot use a transaction context that has exited.')
|
|
89
|
+
elif self.__transaction_depth == -2:
|
|
90
|
+
raise DbError('Cannot use a transaction context that has been committed.')
|
|
91
|
+
elif self.__transaction_depth == -3:
|
|
92
|
+
raise DbError('Cannot use a transaction context that has been rolled back.')
|
|
89
93
|
|
|
90
94
|
sql_upper = sql.lstrip().upper()
|
|
91
95
|
prefix = sql_upper[:4]
|
|
@@ -94,7 +98,12 @@ class MySQLTransactionContext(DbTransactionContext):
|
|
|
94
98
|
if self.__transaction_depth > 0:
|
|
95
99
|
return None
|
|
96
100
|
self.__transaction_depth += 1
|
|
97
|
-
|
|
101
|
+
if prefix == 'STAR':
|
|
102
|
+
self.__transaction_name = extract_start_name(sql)
|
|
103
|
+
elif sql_upper.startswith('BEGIN WORK') or sql_upper.startswith('BEGIN '):
|
|
104
|
+
self.__transaction_name = None
|
|
105
|
+
else:
|
|
106
|
+
self.__transaction_name = extract_begin_name(sql)
|
|
98
107
|
self.__ambient_transaction_id.set(self.__transaction_name or self.__transaction_id)
|
|
99
108
|
return 'START TRANSACTION'
|
|
100
109
|
|
|
@@ -112,7 +121,7 @@ class MySQLTransactionContext(DbTransactionContext):
|
|
|
112
121
|
self.__savepoints.clear()
|
|
113
122
|
self.__transaction_name = None
|
|
114
123
|
self.__ambient_transaction_id.set(None)
|
|
115
|
-
|
|
124
|
+
self.__transaction_depth = -2
|
|
116
125
|
return 'COMMIT'
|
|
117
126
|
else:
|
|
118
127
|
return None
|
|
@@ -120,7 +129,6 @@ class MySQLTransactionContext(DbTransactionContext):
|
|
|
120
129
|
elif prefix == 'ROLL':
|
|
121
130
|
if self.__transaction_depth == 0:
|
|
122
131
|
raise DbError('Cannot rollback, no transaction.')
|
|
123
|
-
self.__transaction_depth = 0
|
|
124
132
|
name = extract_rollback_name(sql)
|
|
125
133
|
|
|
126
134
|
if name:
|
|
@@ -129,7 +137,7 @@ class MySQLTransactionContext(DbTransactionContext):
|
|
|
129
137
|
sp = self.__savepoints.pop()
|
|
130
138
|
if sp == name:
|
|
131
139
|
break
|
|
132
|
-
return 'ROLLBACK'
|
|
140
|
+
return f'ROLLBACK TO SAVEPOINT {name}'
|
|
133
141
|
elif name == self.__transaction_name:
|
|
134
142
|
pass # full rollback, depth reset below
|
|
135
143
|
else:
|
|
@@ -137,7 +145,7 @@ class MySQLTransactionContext(DbTransactionContext):
|
|
|
137
145
|
else:
|
|
138
146
|
pass # full rollback, depth reset below
|
|
139
147
|
|
|
140
|
-
self.__transaction_depth =
|
|
148
|
+
self.__transaction_depth = -3
|
|
141
149
|
self.__savepoints.clear()
|
|
142
150
|
self.__transaction_name = None
|
|
143
151
|
self.__ambient_transaction_id.set(None)
|
|
@@ -234,8 +242,8 @@ class MySQLTransactionContext(DbTransactionContext):
|
|
|
234
242
|
except mysql.connector.ProgrammingError:
|
|
235
243
|
return cursor.rowcount
|
|
236
244
|
|
|
237
|
-
def execute_script(self, sql: str, raw:
|
|
238
|
-
if raw is
|
|
245
|
+
def execute_script(self, sql: str, raw: bool = False) -> None:
|
|
246
|
+
if raw is True:
|
|
239
247
|
self.execute(sql, raw=True)
|
|
240
248
|
return
|
|
241
249
|
lines = sql.split('\n')
|
|
@@ -126,7 +126,7 @@ class AsyncSQLiteTransactionContext(AsyncDbTransactionContext):
|
|
|
126
126
|
async def execute_scalar(self, sql: str, parameters: DbParameters | None = None) -> Any:
|
|
127
127
|
return self.__get_inner_ctx().execute_scalar(sql, parameters)
|
|
128
128
|
|
|
129
|
-
async def execute_script(self, sql: str, raw:
|
|
129
|
+
async def execute_script(self, sql: str, raw: bool = False) -> None:
|
|
130
130
|
self.__get_inner_ctx().execute_script(sql, raw)
|
|
131
131
|
|
|
132
132
|
async def rollback(self, name: str | None = None) -> None:
|
|
@@ -45,17 +45,14 @@ class SQLiteProxyCursor(DbCursor):
|
|
|
45
45
|
return self.__cursor.rowcount
|
|
46
46
|
|
|
47
47
|
def execute(self, operation: str, parameters: DbParameters | None = None) -> None:
|
|
48
|
-
if parameters is
|
|
49
|
-
operation = operation.replace(self.__sql_arg_expect, self.__sql_arg_subst)
|
|
50
|
-
self.__logger.debug(f'execute({operation!r}, {parameters!r})')
|
|
51
|
-
if parameters is None:
|
|
48
|
+
if parameters is None or len(parameters) == 0:
|
|
52
49
|
self.__cursor.execute(operation)
|
|
53
50
|
else:
|
|
51
|
+
operation = operation.replace(self.__sql_arg_expect, self.__sql_arg_subst)
|
|
54
52
|
self.__cursor.execute(operation, parameters) # type: ignore[arg-type]
|
|
55
53
|
|
|
56
54
|
def executemany(self, operation: str, seq_of_parameters: Sequence[DbParameters]) -> None:
|
|
57
55
|
operation = operation.replace(self.__sql_arg_expect, self.__sql_arg_subst)
|
|
58
|
-
self.__logger.debug(f'execute({operation!r}, {seq_of_parameters!r})')
|
|
59
56
|
self.__cursor.executemany(operation, seq_of_parameters)
|
|
60
57
|
|
|
61
58
|
def fetchone(self) -> tuple[Any, ...] | None:
|
|
@@ -39,7 +39,6 @@ class SQLiteTableAdapter(Generic[TEntity]):
|
|
|
39
39
|
__initialized: bool
|
|
40
40
|
__dbtype_mapper: DbTypeMapper
|
|
41
41
|
__entity_spec: EntitySpec
|
|
42
|
-
__transaction_state: int
|
|
43
42
|
__table_name: str | None
|
|
44
43
|
|
|
45
44
|
def __init__(
|
|
@@ -54,7 +53,6 @@ class SQLiteTableAdapter(Generic[TEntity]):
|
|
|
54
53
|
self.__create_table = create_table is True
|
|
55
54
|
self.__initialized = False
|
|
56
55
|
self.__table_name = table_name
|
|
57
|
-
self.__transaction_state = 0
|
|
58
56
|
|
|
59
57
|
def __deferred_init(self) -> None:
|
|
60
58
|
if not self.__initialized:
|
|
@@ -82,8 +82,12 @@ class SQLiteTransactionContext(DbTransactionContext):
|
|
|
82
82
|
- None if scrubbed because the DBMS does not support it.
|
|
83
83
|
- Raises DbError if operation is invalid.
|
|
84
84
|
"""
|
|
85
|
-
if self.__transaction_depth
|
|
86
|
-
raise DbError('Cannot use a transaction context that has
|
|
85
|
+
if self.__transaction_depth == -1:
|
|
86
|
+
raise DbError('Cannot use a transaction context that has exited.')
|
|
87
|
+
elif self.__transaction_depth == -2:
|
|
88
|
+
raise DbError('Cannot use a transaction context that has been committed.')
|
|
89
|
+
elif self.__transaction_depth == -3:
|
|
90
|
+
raise DbError('Cannot use a transaction context that has been rolled back.')
|
|
87
91
|
|
|
88
92
|
sql_upper = sql.lstrip().upper()
|
|
89
93
|
prefix = sql_upper[:4]
|
|
@@ -111,7 +115,7 @@ class SQLiteTransactionContext(DbTransactionContext):
|
|
|
111
115
|
self.__savepoints.clear()
|
|
112
116
|
self.__transaction_name = None
|
|
113
117
|
self.__ambient_transaction_id.set(None)
|
|
114
|
-
|
|
118
|
+
self.__transaction_depth = -2
|
|
115
119
|
return 'COMMIT'
|
|
116
120
|
else:
|
|
117
121
|
return None
|
|
@@ -122,8 +126,6 @@ class SQLiteTransactionContext(DbTransactionContext):
|
|
|
122
126
|
name = extract_rollback_name(sql)
|
|
123
127
|
is_savepoint_rollback = is_rollback_to(sql)
|
|
124
128
|
|
|
125
|
-
is_full_rollback = False
|
|
126
|
-
|
|
127
129
|
if name:
|
|
128
130
|
if name in self.__savepoints:
|
|
129
131
|
while self.__savepoints:
|
|
@@ -131,21 +133,20 @@ class SQLiteTransactionContext(DbTransactionContext):
|
|
|
131
133
|
if sp == name:
|
|
132
134
|
break
|
|
133
135
|
elif name == self.__transaction_name:
|
|
134
|
-
|
|
136
|
+
pass # full rollback, depth reset below
|
|
135
137
|
else:
|
|
136
138
|
raise DbError('Invalid Transaction Name')
|
|
137
139
|
else:
|
|
138
|
-
|
|
140
|
+
pass # full rollback, depth reset below
|
|
139
141
|
|
|
140
|
-
if
|
|
141
|
-
|
|
142
|
+
if is_savepoint_rollback:
|
|
143
|
+
return 'ROLLBACK TO SAVEPOINT ' + (name or '')
|
|
144
|
+
else:
|
|
145
|
+
self.__transaction_depth = -3
|
|
142
146
|
self.__savepoints.clear()
|
|
143
147
|
self.__transaction_name = None
|
|
144
148
|
self.__ambient_transaction_id.set(None)
|
|
145
|
-
|
|
146
|
-
if is_savepoint_rollback:
|
|
147
|
-
return 'ROLLBACK TO SAVEPOINT ' + (name or '')
|
|
148
|
-
return 'ROLLBACK TRANSACTION'
|
|
149
|
+
return 'ROLLBACK TRANSACTION'
|
|
149
150
|
|
|
150
151
|
return sql
|
|
151
152
|
|
|
@@ -239,8 +240,8 @@ class SQLiteTransactionContext(DbTransactionContext):
|
|
|
239
240
|
except sqlite3.ProgrammingError:
|
|
240
241
|
return cursor.rowcount
|
|
241
242
|
|
|
242
|
-
def execute_script(self, sql: str, raw:
|
|
243
|
-
if raw is
|
|
243
|
+
def execute_script(self, sql: str, raw: bool = False) -> None:
|
|
244
|
+
if raw is True:
|
|
244
245
|
self.execute(sql, raw=True)
|
|
245
246
|
return
|
|
246
247
|
lines = sql.split('\n')
|
|
@@ -235,7 +235,7 @@ def resolve_mongodb_auth_source(connectionstring: ConnectionString) -> str:
|
|
|
235
235
|
import pymongo
|
|
236
236
|
from pymongo import errors as _pymongo_errors
|
|
237
237
|
|
|
238
|
-
cache_key = f
|
|
238
|
+
cache_key = f'{connectionstring.server}:{connectionstring.database}:{connectionstring.user}'
|
|
239
239
|
cached = _MONGODB_AUTH_SOURCE_CACHE.get(cache_key)
|
|
240
240
|
if cached is not None:
|
|
241
241
|
return cached
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|