velocity-python 0.0.35__py3-none-any.whl → 0.0.65__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.
- velocity/__init__.py +1 -1
- velocity/db/core/column.py +25 -105
- velocity/db/core/database.py +79 -23
- velocity/db/core/decorators.py +84 -47
- velocity/db/core/engine.py +190 -189
- velocity/db/core/result.py +94 -49
- velocity/db/core/row.py +81 -46
- velocity/db/core/sequence.py +112 -22
- velocity/db/core/table.py +660 -243
- velocity/db/core/transaction.py +75 -77
- velocity/db/servers/mysql.py +4 -0
- velocity/db/servers/postgres/__init__.py +19 -0
- velocity/db/servers/postgres/operators.py +23 -0
- velocity/db/servers/{postgres.py → postgres/sql.py} +508 -589
- velocity/db/servers/postgres/types.py +109 -0
- velocity/db/servers/tablehelper.py +277 -0
- velocity/misc/conv/iconv.py +277 -91
- velocity/misc/conv/oconv.py +5 -4
- velocity/misc/db.py +2 -2
- velocity/misc/format.py +2 -2
- {velocity_python-0.0.35.dist-info → velocity_python-0.0.65.dist-info}/METADATA +7 -6
- velocity_python-0.0.65.dist-info/RECORD +47 -0
- {velocity_python-0.0.35.dist-info → velocity_python-0.0.65.dist-info}/WHEEL +1 -1
- velocity_python-0.0.35.dist-info/RECORD +0 -43
- /velocity/db/servers/{postgres_reserved.py → postgres/reserved.py} +0 -0
- {velocity_python-0.0.35.dist-info → velocity_python-0.0.65.dist-info/licenses}/LICENSE +0 -0
- {velocity_python-0.0.35.dist-info → velocity_python-0.0.65.dist-info}/top_level.txt +0 -0
velocity/db/core/engine.py
CHANGED
|
@@ -1,11 +1,17 @@
|
|
|
1
|
+
import inspect
|
|
2
|
+
import sys
|
|
3
|
+
import re
|
|
4
|
+
import traceback
|
|
5
|
+
from functools import wraps
|
|
1
6
|
from velocity.db import exceptions
|
|
2
7
|
from velocity.db.core.transaction import Transaction
|
|
3
8
|
|
|
4
|
-
from functools import wraps
|
|
5
|
-
import inspect, sys, re, traceback
|
|
6
9
|
|
|
10
|
+
class Engine:
|
|
11
|
+
"""
|
|
12
|
+
Encapsulates driver config, connection logic, error handling, and transaction decoration.
|
|
13
|
+
"""
|
|
7
14
|
|
|
8
|
-
class Engine(object):
|
|
9
15
|
MAX_RETRIES = 100
|
|
10
16
|
|
|
11
17
|
def __init__(self, driver, config, sql):
|
|
@@ -14,16 +20,12 @@ class Engine(object):
|
|
|
14
20
|
self.__driver = driver
|
|
15
21
|
|
|
16
22
|
def __str__(self):
|
|
17
|
-
return "
|
|
23
|
+
return f"[{self.sql.server}] engine({self.config})"
|
|
18
24
|
|
|
19
25
|
def connect(self):
|
|
20
26
|
"""
|
|
21
27
|
Connects to the database and returns the connection object.
|
|
22
|
-
|
|
23
|
-
If the database is missing, it creates the database and then connects to it.
|
|
24
|
-
|
|
25
|
-
Returns:
|
|
26
|
-
conn: The connection object to the database.
|
|
28
|
+
If the database is missing, tries to create it, then reconnect.
|
|
27
29
|
"""
|
|
28
30
|
try:
|
|
29
31
|
conn = self.__connect()
|
|
@@ -36,158 +38,132 @@ class Engine(object):
|
|
|
36
38
|
|
|
37
39
|
def __connect(self):
|
|
38
40
|
"""
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
Returns:
|
|
42
|
-
A connection object representing the connection to the database.
|
|
43
|
-
|
|
44
|
-
Raises:
|
|
45
|
-
Exception: If the configuration parameter is not handled properly.
|
|
46
|
-
ProcessError is called to handle other exceptions.
|
|
41
|
+
Internal connection logic, raising suitable exceptions on error.
|
|
47
42
|
"""
|
|
48
43
|
try:
|
|
49
44
|
if isinstance(self.config, dict):
|
|
50
45
|
return self.driver.connect(**self.config)
|
|
51
|
-
|
|
46
|
+
if isinstance(self.config, (tuple, list)):
|
|
52
47
|
return self.driver.connect(*self.config)
|
|
53
|
-
|
|
48
|
+
if isinstance(self.config, str):
|
|
54
49
|
return self.driver.connect(self.config)
|
|
55
|
-
|
|
56
|
-
raise Exception("Unhandled configuration parameter")
|
|
50
|
+
raise Exception("Unhandled configuration parameter.")
|
|
57
51
|
except:
|
|
58
|
-
self.
|
|
52
|
+
self.process_error()
|
|
59
53
|
|
|
60
54
|
def transaction(self, func_or_cls=None):
|
|
61
55
|
"""
|
|
62
|
-
Decorator
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
automatically starts a transaction if necessary. If `func_or_cls` is a class, returns a subclass of
|
|
75
|
-
`func_or_cls` that wraps all its methods with the transaction decorator.
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
If `func_or_cls` is not provided, returns a new `Transaction` object associated with the engine.
|
|
80
|
-
"""
|
|
81
|
-
# If you are having trouble passing TWO transaction objects, for
|
|
82
|
-
# example as a source database to draw data from, pass the second as
|
|
83
|
-
# a keyword. For example:
|
|
84
|
-
# @engine.transaction
|
|
85
|
-
# def function(tx, src=src) <-- pass second as a kwd and tx will populate correctly.
|
|
86
|
-
# ...
|
|
87
|
-
#
|
|
88
|
-
engine = self
|
|
56
|
+
Decorator that provides a Transaction. If `tx` is passed in, uses it; otherwise, creates a new one.
|
|
57
|
+
May also be used to decorate a class, in which case all methods are wrapped in a transaction if they accept `tx`.
|
|
58
|
+
With no arguments, returns a new Transaction directly.
|
|
59
|
+
"""
|
|
60
|
+
# print("Transaction", func_or_cls.__name__, type(func_or_cls))
|
|
61
|
+
|
|
62
|
+
if func_or_cls is None:
|
|
63
|
+
return Transaction(self)
|
|
64
|
+
|
|
65
|
+
if isinstance(func_or_cls, classmethod):
|
|
66
|
+
return classmethod(self.transaction(func_or_cls.__func__))
|
|
67
|
+
|
|
89
68
|
if inspect.isfunction(func_or_cls) or inspect.ismethod(func_or_cls):
|
|
69
|
+
names = list(inspect.signature(func_or_cls).parameters.keys())
|
|
70
|
+
# print(func_or_cls.__name__, names)
|
|
71
|
+
if "_tx" in names:
|
|
72
|
+
raise NameError(
|
|
73
|
+
f"In function {func_or_cls.__name__}, '_tx' is not allowed as a parameter."
|
|
74
|
+
)
|
|
90
75
|
|
|
91
76
|
@wraps(func_or_cls)
|
|
92
|
-
def
|
|
77
|
+
def new_function(*args, **kwds):
|
|
93
78
|
tx = None
|
|
94
79
|
names = list(inspect.signature(func_or_cls).parameters.keys())
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
80
|
+
|
|
81
|
+
# print("inside", func_or_cls.__name__)
|
|
82
|
+
# print(names)
|
|
83
|
+
# print(args, kwds)
|
|
84
|
+
|
|
99
85
|
if "tx" not in names:
|
|
86
|
+
# The function doesn't even declare a `tx` parameter, so run normally.
|
|
100
87
|
return func_or_cls(*args, **kwds)
|
|
101
|
-
|
|
88
|
+
|
|
89
|
+
if "tx" in kwds:
|
|
102
90
|
if isinstance(kwds["tx"], Transaction):
|
|
103
91
|
tx = kwds["tx"]
|
|
104
92
|
else:
|
|
105
93
|
raise TypeError(
|
|
106
|
-
f"In function
|
|
94
|
+
f"In function {func_or_cls.__name__}, keyword argument `tx` must be a Transaction object."
|
|
107
95
|
)
|
|
108
|
-
|
|
96
|
+
else:
|
|
97
|
+
# Might be in positional args
|
|
109
98
|
pos = names.index("tx")
|
|
110
|
-
if len(args) > pos
|
|
111
|
-
|
|
99
|
+
if len(args) > pos:
|
|
100
|
+
if isinstance(args[pos], Transaction):
|
|
101
|
+
tx = args[pos]
|
|
102
|
+
|
|
112
103
|
if tx:
|
|
113
|
-
return
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
104
|
+
return self.exec_function(func_or_cls, tx, *args, **kwds)
|
|
105
|
+
|
|
106
|
+
with Transaction(self) as local_tx:
|
|
107
|
+
pos = names.index("tx")
|
|
108
|
+
new_args = args[:pos] + (local_tx,) + args[pos:]
|
|
109
|
+
return self.exec_function(func_or_cls, local_tx, *new_args, **kwds)
|
|
110
|
+
|
|
111
|
+
return new_function
|
|
112
|
+
|
|
113
|
+
if inspect.isclass(func_or_cls):
|
|
114
|
+
|
|
115
|
+
NewCls = type(func_or_cls.__name__, (func_or_cls,), {})
|
|
116
|
+
|
|
117
|
+
for attr_name in dir(func_or_cls):
|
|
118
|
+
# Optionally skip special methods
|
|
119
|
+
if attr_name.startswith("__") and attr_name.endswith("__"):
|
|
120
|
+
continue
|
|
121
|
+
|
|
122
|
+
attr = getattr(func_or_cls, attr_name)
|
|
123
|
+
|
|
124
|
+
if callable(attr):
|
|
125
|
+
setattr(NewCls, attr_name, self.transaction(attr))
|
|
133
126
|
|
|
134
127
|
return NewCls
|
|
135
128
|
|
|
136
|
-
return Transaction(
|
|
129
|
+
return Transaction(self)
|
|
137
130
|
|
|
138
131
|
def exec_function(self, function, _tx, *args, **kwds):
|
|
139
132
|
"""
|
|
140
|
-
Executes the given function
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
return function(*args, **kwds)
|
|
166
|
-
else:
|
|
167
|
-
while True:
|
|
168
|
-
try:
|
|
169
|
-
return function(*args, **kwds)
|
|
170
|
-
except exceptions.DbRetryTransaction as e:
|
|
171
|
-
if e.args and e.args[0]:
|
|
172
|
-
print(e)
|
|
173
|
-
print("**Retry Transaction. Rollback and start over")
|
|
133
|
+
Executes the given function inside the transaction `_tx`.
|
|
134
|
+
Retries if it raises DbRetryTransaction or DbLockTimeoutError, up to MAX_RETRIES times.
|
|
135
|
+
"""
|
|
136
|
+
depth = getattr(_tx, "_exec_function_depth", 0)
|
|
137
|
+
setattr(_tx, "_exec_function_depth", depth + 1)
|
|
138
|
+
|
|
139
|
+
try:
|
|
140
|
+
if depth > 0:
|
|
141
|
+
# Not top-level. Just call the function.
|
|
142
|
+
return function(*args, **kwds)
|
|
143
|
+
else:
|
|
144
|
+
retry_count = 0
|
|
145
|
+
lock_timeout_count = 0
|
|
146
|
+
while True:
|
|
147
|
+
try:
|
|
148
|
+
return function(*args, **kwds)
|
|
149
|
+
except exceptions.DbRetryTransaction as e:
|
|
150
|
+
retry_count += 1
|
|
151
|
+
if retry_count > self.MAX_RETRIES:
|
|
152
|
+
raise
|
|
153
|
+
_tx.rollback()
|
|
154
|
+
except exceptions.DbLockTimeoutError as e:
|
|
155
|
+
lock_timeout_count += 1
|
|
156
|
+
if lock_timeout_count > self.MAX_RETRIES:
|
|
157
|
+
raise
|
|
174
158
|
_tx.rollback()
|
|
175
159
|
continue
|
|
176
|
-
|
|
177
|
-
if retry_count > self.MAX_RETRIES:
|
|
160
|
+
except:
|
|
178
161
|
raise
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
if tmout_count > self.MAX_RETRIES:
|
|
185
|
-
raise
|
|
186
|
-
print("**DbLockTimeoutError. Rollback and start over")
|
|
187
|
-
_tx.rollback()
|
|
188
|
-
continue
|
|
189
|
-
except:
|
|
190
|
-
raise
|
|
162
|
+
finally:
|
|
163
|
+
setattr(_tx, "_exec_function_depth", depth)
|
|
164
|
+
# or if depth was 0, you might delete the attribute:
|
|
165
|
+
# if depth == 0:
|
|
166
|
+
# delattr(_tx, "_exec_function_depth")
|
|
191
167
|
|
|
192
168
|
@property
|
|
193
169
|
def driver(self):
|
|
@@ -203,24 +179,36 @@ class Engine(object):
|
|
|
203
179
|
|
|
204
180
|
@property
|
|
205
181
|
def version(self):
|
|
182
|
+
"""
|
|
183
|
+
Returns the DB server version.
|
|
184
|
+
"""
|
|
206
185
|
with Transaction(self) as tx:
|
|
207
186
|
sql, vals = self.sql.version()
|
|
208
187
|
return tx.execute(sql, vals).scalar()
|
|
209
188
|
|
|
210
189
|
@property
|
|
211
190
|
def timestamp(self):
|
|
191
|
+
"""
|
|
192
|
+
Returns the current timestamp from the DB server.
|
|
193
|
+
"""
|
|
212
194
|
with Transaction(self) as tx:
|
|
213
195
|
sql, vals = self.sql.timestamp()
|
|
214
196
|
return tx.execute(sql, vals).scalar()
|
|
215
197
|
|
|
216
198
|
@property
|
|
217
199
|
def user(self):
|
|
200
|
+
"""
|
|
201
|
+
Returns the current user as known by the DB server.
|
|
202
|
+
"""
|
|
218
203
|
with Transaction(self) as tx:
|
|
219
204
|
sql, vals = self.sql.user()
|
|
220
205
|
return tx.execute(sql, vals).scalar()
|
|
221
206
|
|
|
222
207
|
@property
|
|
223
208
|
def databases(self):
|
|
209
|
+
"""
|
|
210
|
+
Returns a list of available databases.
|
|
211
|
+
"""
|
|
224
212
|
with Transaction(self) as tx:
|
|
225
213
|
sql, vals = self.sql.databases()
|
|
226
214
|
result = tx.execute(sql, vals)
|
|
@@ -228,13 +216,19 @@ class Engine(object):
|
|
|
228
216
|
|
|
229
217
|
@property
|
|
230
218
|
def current_database(self):
|
|
219
|
+
"""
|
|
220
|
+
Returns the name of the current database.
|
|
221
|
+
"""
|
|
231
222
|
with Transaction(self) as tx:
|
|
232
223
|
sql, vals = self.sql.current_database()
|
|
233
224
|
return tx.execute(sql, vals).scalar()
|
|
234
225
|
|
|
235
226
|
def create_database(self, name=None):
|
|
227
|
+
"""
|
|
228
|
+
Creates a database if it doesn't exist, or does nothing if it does.
|
|
229
|
+
"""
|
|
236
230
|
old = None
|
|
237
|
-
if name
|
|
231
|
+
if name is None:
|
|
238
232
|
old = self.config["database"]
|
|
239
233
|
self.set_config({"database": "postgres"})
|
|
240
234
|
name = old
|
|
@@ -246,19 +240,27 @@ class Engine(object):
|
|
|
246
240
|
return self
|
|
247
241
|
|
|
248
242
|
def switch_to_database(self, database):
|
|
243
|
+
"""
|
|
244
|
+
Switch the config to use a different database name, closing any existing connection.
|
|
245
|
+
"""
|
|
249
246
|
conf = self.config
|
|
250
247
|
if "database" in conf:
|
|
251
248
|
conf["database"] = database
|
|
252
249
|
if "dbname" in conf:
|
|
253
250
|
conf["dbname"] = database
|
|
254
|
-
|
|
255
251
|
return self
|
|
256
252
|
|
|
257
253
|
def set_config(self, config):
|
|
254
|
+
"""
|
|
255
|
+
Updates the internal config dictionary.
|
|
256
|
+
"""
|
|
258
257
|
self.config.update(config)
|
|
259
258
|
|
|
260
259
|
@property
|
|
261
260
|
def schemas(self):
|
|
261
|
+
"""
|
|
262
|
+
Returns a list of schemas in the current database.
|
|
263
|
+
"""
|
|
262
264
|
with Transaction(self) as tx:
|
|
263
265
|
sql, vals = self.sql.schemas()
|
|
264
266
|
result = tx.execute(sql, vals)
|
|
@@ -266,107 +268,106 @@ class Engine(object):
|
|
|
266
268
|
|
|
267
269
|
@property
|
|
268
270
|
def current_schema(self):
|
|
271
|
+
"""
|
|
272
|
+
Returns the current schema in use.
|
|
273
|
+
"""
|
|
269
274
|
with Transaction(self) as tx:
|
|
270
275
|
sql, vals = self.sql.current_schema()
|
|
271
276
|
return tx.execute(sql, vals).scalar()
|
|
272
277
|
|
|
273
278
|
@property
|
|
274
279
|
def tables(self):
|
|
280
|
+
"""
|
|
281
|
+
Returns a list of 'schema.table' for all tables in the current DB.
|
|
282
|
+
"""
|
|
275
283
|
with Transaction(self) as tx:
|
|
276
284
|
sql, vals = self.sql.tables()
|
|
277
285
|
result = tx.execute(sql, vals)
|
|
278
|
-
return ["
|
|
286
|
+
return [f"{x[0]}.{x[1]}" for x in result.as_tuple()]
|
|
279
287
|
|
|
280
288
|
@property
|
|
281
289
|
def views(self):
|
|
290
|
+
"""
|
|
291
|
+
Returns a list of 'schema.view' for all views in the current DB.
|
|
292
|
+
"""
|
|
282
293
|
with Transaction(self) as tx:
|
|
283
294
|
sql, vals = self.sql.views()
|
|
284
295
|
result = tx.execute(sql, vals)
|
|
285
|
-
return ["
|
|
296
|
+
return [f"{x[0]}.{x[1]}" for x in result.as_tuple()]
|
|
286
297
|
|
|
287
|
-
def
|
|
288
|
-
|
|
298
|
+
def process_error(self, sql_stmt=None, sql_params=None):
|
|
299
|
+
"""
|
|
300
|
+
Central method to parse driver exceptions and re-raise them as our custom exceptions.
|
|
301
|
+
"""
|
|
289
302
|
e = sys.exc_info()[1]
|
|
290
303
|
msg = str(e).strip().lower()
|
|
304
|
+
|
|
291
305
|
if isinstance(e, exceptions.DbException):
|
|
292
306
|
raise
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
hasattr(e, "args") and isinstance(e.args, (tuple, list)) and len(e.args) > 1
|
|
298
|
-
):
|
|
299
|
-
error_code = e[0]
|
|
300
|
-
error_mesg = e[1]
|
|
301
|
-
elif hasattr(e, "number") and hasattr(e, "text"):
|
|
302
|
-
error_code = e.number
|
|
303
|
-
error_mesg = e.text
|
|
304
|
-
elif hasattr(e, "args") and hasattr(e, "message"):
|
|
305
|
-
# SQLite3
|
|
306
|
-
error_code = None
|
|
307
|
-
error_mesg = e.message
|
|
308
|
-
else:
|
|
309
|
-
raise
|
|
310
|
-
if error_code in sql.ApplicationErrorCodes:
|
|
307
|
+
|
|
308
|
+
error_code, error_mesg = self.sql.get_error(e)
|
|
309
|
+
|
|
310
|
+
if error_code in self.sql.ApplicationErrorCodes:
|
|
311
311
|
raise exceptions.DbApplicationError(e)
|
|
312
|
-
|
|
312
|
+
if error_code in self.sql.ColumnMissingErrorCodes:
|
|
313
313
|
raise exceptions.DbColumnMissingError(e)
|
|
314
|
-
|
|
314
|
+
if error_code in self.sql.TableMissingErrorCodes:
|
|
315
315
|
raise exceptions.DbTableMissingError(e)
|
|
316
|
-
|
|
316
|
+
if error_code in self.sql.DatabaseMissingErrorCodes:
|
|
317
317
|
raise exceptions.DbDatabaseMissingError(e)
|
|
318
|
-
|
|
318
|
+
if error_code in self.sql.ForeignKeyMissingErrorCodes:
|
|
319
319
|
raise exceptions.DbForeignKeyMissingError(e)
|
|
320
|
-
|
|
320
|
+
if error_code in self.sql.TruncationErrorCodes:
|
|
321
321
|
raise exceptions.DbTruncationError(e)
|
|
322
|
-
|
|
322
|
+
if error_code in self.sql.DataIntegrityErrorCodes:
|
|
323
323
|
raise exceptions.DbDataIntegrityError(e)
|
|
324
|
-
|
|
324
|
+
if error_code in self.sql.ConnectionErrorCodes:
|
|
325
325
|
raise exceptions.DbConnectionError(e)
|
|
326
|
-
|
|
326
|
+
if error_code in self.sql.DuplicateKeyErrorCodes:
|
|
327
327
|
raise exceptions.DbDuplicateKeyError(e)
|
|
328
|
-
|
|
328
|
+
if re.search(r"key \(sys_id\)=\(\d+\) already exists.", msg, re.M):
|
|
329
329
|
raise exceptions.DbDuplicateKeyError(e)
|
|
330
|
-
|
|
330
|
+
if error_code in self.sql.DatabaseObjectExistsErrorCodes:
|
|
331
331
|
raise exceptions.DbObjectExistsError(e)
|
|
332
|
-
|
|
332
|
+
if error_code in self.sql.LockTimeoutErrorCodes:
|
|
333
333
|
raise exceptions.DbLockTimeoutError(e)
|
|
334
|
-
|
|
334
|
+
if error_code in self.sql.RetryTransactionCodes:
|
|
335
335
|
raise exceptions.DbRetryTransaction(e)
|
|
336
|
-
|
|
336
|
+
if re.findall(r"database.*does not exist", msg, re.M):
|
|
337
337
|
raise exceptions.DbDatabaseMissingError(e)
|
|
338
|
-
|
|
338
|
+
if re.findall(r"no such database", msg, re.M):
|
|
339
339
|
raise exceptions.DbDatabaseMissingError(e)
|
|
340
|
-
|
|
340
|
+
if re.findall(r"already exists", msg, re.M):
|
|
341
341
|
raise exceptions.DbObjectExistsError(e)
|
|
342
|
-
|
|
342
|
+
if re.findall(r"server closed the connection unexpectedly", msg, re.M):
|
|
343
343
|
raise exceptions.DbConnectionError(e)
|
|
344
|
-
|
|
344
|
+
if re.findall(r"no connection to the server", msg, re.M):
|
|
345
345
|
raise exceptions.DbConnectionError(e)
|
|
346
|
-
|
|
346
|
+
if re.findall(r"connection timed out", msg, re.M):
|
|
347
347
|
raise exceptions.DbConnectionError(e)
|
|
348
|
-
|
|
348
|
+
if re.findall(r"could not connect to server", msg, re.M):
|
|
349
349
|
raise exceptions.DbConnectionError(e)
|
|
350
|
-
|
|
350
|
+
if re.findall(r"cannot connect to server", msg, re.M):
|
|
351
351
|
raise exceptions.DbConnectionError(e)
|
|
352
|
-
|
|
352
|
+
if re.findall(r"connection already closed", msg, re.M):
|
|
353
353
|
raise exceptions.DbConnectionError(e)
|
|
354
|
-
|
|
354
|
+
if re.findall(r"cursor already closed", msg, re.M):
|
|
355
355
|
raise exceptions.DbConnectionError(e)
|
|
356
|
-
|
|
357
|
-
elif "no such table:" in msg:
|
|
356
|
+
if "no such table:" in msg:
|
|
358
357
|
raise exceptions.DbTableMissingError(e)
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
358
|
+
|
|
359
|
+
msg = f"""
|
|
360
|
+
Unhandled/Unknown Error in engine.process_error
|
|
361
|
+
EXC_TYPE = {type(e)}
|
|
362
|
+
EXC_MSG = {str(e).strip()}
|
|
363
|
+
|
|
364
|
+
ERROR_CODE = {error_code}
|
|
365
|
+
ERROR_MSG = {error_mesg}
|
|
366
|
+
|
|
367
|
+
SQL_STMT = {sql_stmt}
|
|
368
|
+
SQL_PARAMS = {sql_params}
|
|
369
|
+
|
|
370
|
+
{traceback.format_exc()}
|
|
371
|
+
"""
|
|
372
|
+
print(msg)
|
|
372
373
|
raise
|