velocity-python 0.0.34__py3-none-any.whl → 0.0.64__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of velocity-python might be problematic. Click here for more details.
- 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 +179 -184
- 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 +5 -237
- velocity/db/servers/mysql_reserved.py +237 -0
- velocity/db/servers/postgres/__init__.py +19 -0
- velocity/db/servers/postgres/operators.py +23 -0
- velocity/db/servers/postgres/reserved.py +254 -0
- velocity/db/servers/postgres/sql.py +1041 -0
- velocity/db/servers/postgres/types.py +109 -0
- velocity/db/servers/sqlite.py +1 -210
- velocity/db/servers/sqlite_reserved.py +208 -0
- velocity/db/servers/sqlserver.py +1 -316
- velocity/db/servers/sqlserver_reserved.py +314 -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.34.dist-info → velocity_python-0.0.64.dist-info}/METADATA +6 -6
- velocity_python-0.0.64.dist-info/RECORD +47 -0
- {velocity_python-0.0.34.dist-info → velocity_python-0.0.64.dist-info}/WHEEL +1 -1
- velocity/db/servers/postgres.py +0 -1396
- velocity_python-0.0.34.dist-info/RECORD +0 -39
- {velocity_python-0.0.34.dist-info → velocity_python-0.0.64.dist-info}/LICENSE +0 -0
- {velocity_python-0.0.34.dist-info → velocity_python-0.0.64.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,126 @@ 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
|
-
Returns:
|
|
73
|
-
If `func_or_cls` is a function or method, returns a wrapped version of the function or method that
|
|
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
|
+
if func_or_cls is None:
|
|
61
|
+
return Transaction(self)
|
|
62
|
+
|
|
63
|
+
if isinstance(func_or_cls, classmethod):
|
|
64
|
+
return classmethod(self.transaction(func_or_cls.__func__))
|
|
65
|
+
|
|
89
66
|
if inspect.isfunction(func_or_cls) or inspect.ismethod(func_or_cls):
|
|
90
67
|
|
|
91
68
|
@wraps(func_or_cls)
|
|
92
|
-
def
|
|
69
|
+
def new_function(*args, **kwds):
|
|
93
70
|
tx = None
|
|
94
71
|
names = list(inspect.signature(func_or_cls).parameters.keys())
|
|
95
72
|
if "_tx" in names:
|
|
96
73
|
raise NameError(
|
|
97
|
-
f"In function
|
|
74
|
+
f"In function {func_or_cls.__name__}, '_tx' is not allowed as a parameter."
|
|
98
75
|
)
|
|
76
|
+
|
|
99
77
|
if "tx" not in names:
|
|
78
|
+
# The function doesn't even declare a `tx` parameter, so run normally.
|
|
100
79
|
return func_or_cls(*args, **kwds)
|
|
101
|
-
|
|
80
|
+
|
|
81
|
+
if "tx" in kwds:
|
|
102
82
|
if isinstance(kwds["tx"], Transaction):
|
|
103
83
|
tx = kwds["tx"]
|
|
104
84
|
else:
|
|
105
85
|
raise TypeError(
|
|
106
|
-
f"In function
|
|
86
|
+
f"In function {func_or_cls.__name__}, keyword argument `tx` must be a Transaction object."
|
|
107
87
|
)
|
|
108
|
-
|
|
88
|
+
else:
|
|
89
|
+
# Might be in positional args
|
|
109
90
|
pos = names.index("tx")
|
|
110
|
-
if len(args) > pos
|
|
111
|
-
|
|
91
|
+
if len(args) > pos:
|
|
92
|
+
if isinstance(args[pos], Transaction):
|
|
93
|
+
tx = args[pos]
|
|
94
|
+
else:
|
|
95
|
+
raise TypeError(
|
|
96
|
+
f"In function {func_or_cls.__name__}, positional argument `tx` must be a Transaction object."
|
|
97
|
+
)
|
|
112
98
|
if tx:
|
|
113
|
-
return
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
return engine.exec_function(func_or_cls, tx, *args, **kwds)
|
|
99
|
+
return self.exec_function(func_or_cls, tx, *args, **kwds)
|
|
100
|
+
with Transaction(self) as local_tx:
|
|
101
|
+
pos = names.index("tx")
|
|
102
|
+
args = list(args)
|
|
103
|
+
args.insert(pos, local_tx)
|
|
104
|
+
args = tuple(args)
|
|
105
|
+
return self.exec_function(func_or_cls, local_tx, *args, **kwds)
|
|
121
106
|
|
|
122
|
-
return
|
|
123
|
-
elif inspect.isclass(func_or_cls):
|
|
107
|
+
return new_function
|
|
124
108
|
|
|
125
|
-
|
|
126
|
-
def __getattribute__(self, key):
|
|
127
|
-
attr = super(NewCls, self).__getattribute__(key)
|
|
128
|
-
if key in ["start_response"]:
|
|
129
|
-
return attr
|
|
130
|
-
if inspect.ismethod(attr):
|
|
131
|
-
return engine.transaction(attr)
|
|
132
|
-
return attr
|
|
109
|
+
if inspect.isclass(func_or_cls):
|
|
133
110
|
|
|
111
|
+
class NewCls(func_or_cls):
|
|
112
|
+
pass
|
|
113
|
+
|
|
114
|
+
for attr_name, attr_value in func_or_cls.__dict__.items():
|
|
115
|
+
if (
|
|
116
|
+
isinstance(attr_value, classmethod)
|
|
117
|
+
or inspect.isfunction(attr_value)
|
|
118
|
+
or inspect.ismethod(attr_value)
|
|
119
|
+
):
|
|
120
|
+
setattr(NewCls, attr_name, self.transaction(attr_value))
|
|
134
121
|
return NewCls
|
|
135
122
|
|
|
136
|
-
return Transaction(
|
|
123
|
+
return Transaction(self)
|
|
137
124
|
|
|
138
125
|
def exec_function(self, function, _tx, *args, **kwds):
|
|
139
126
|
"""
|
|
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")
|
|
127
|
+
Executes the given function inside the transaction `_tx`.
|
|
128
|
+
Retries if it raises DbRetryTransaction or DbLockTimeoutError, up to MAX_RETRIES times.
|
|
129
|
+
"""
|
|
130
|
+
depth = getattr(_tx, "_exec_function_depth", 0)
|
|
131
|
+
setattr(_tx, "_exec_function_depth", depth + 1)
|
|
132
|
+
|
|
133
|
+
try:
|
|
134
|
+
if depth > 0:
|
|
135
|
+
# Not top-level. Just call the function.
|
|
136
|
+
return function(*args, **kwds)
|
|
137
|
+
else:
|
|
138
|
+
retry_count = 0
|
|
139
|
+
lock_timeout_count = 0
|
|
140
|
+
while True:
|
|
141
|
+
try:
|
|
142
|
+
return function(*args, **kwds)
|
|
143
|
+
except exceptions.DbRetryTransaction as e:
|
|
144
|
+
retry_count += 1
|
|
145
|
+
if retry_count > self.MAX_RETRIES:
|
|
146
|
+
raise
|
|
147
|
+
_tx.rollback()
|
|
148
|
+
except exceptions.DbLockTimeoutError as e:
|
|
149
|
+
lock_timeout_count += 1
|
|
150
|
+
if lock_timeout_count > self.MAX_RETRIES:
|
|
151
|
+
raise
|
|
174
152
|
_tx.rollback()
|
|
175
153
|
continue
|
|
176
|
-
|
|
177
|
-
if retry_count > self.MAX_RETRIES:
|
|
154
|
+
except:
|
|
178
155
|
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
|
|
156
|
+
finally:
|
|
157
|
+
setattr(_tx, "_exec_function_depth", depth)
|
|
158
|
+
# or if depth was 0, you might delete the attribute:
|
|
159
|
+
# if depth == 0:
|
|
160
|
+
# delattr(_tx, "_exec_function_depth")
|
|
191
161
|
|
|
192
162
|
@property
|
|
193
163
|
def driver(self):
|
|
@@ -203,24 +173,36 @@ class Engine(object):
|
|
|
203
173
|
|
|
204
174
|
@property
|
|
205
175
|
def version(self):
|
|
176
|
+
"""
|
|
177
|
+
Returns the DB server version.
|
|
178
|
+
"""
|
|
206
179
|
with Transaction(self) as tx:
|
|
207
180
|
sql, vals = self.sql.version()
|
|
208
181
|
return tx.execute(sql, vals).scalar()
|
|
209
182
|
|
|
210
183
|
@property
|
|
211
184
|
def timestamp(self):
|
|
185
|
+
"""
|
|
186
|
+
Returns the current timestamp from the DB server.
|
|
187
|
+
"""
|
|
212
188
|
with Transaction(self) as tx:
|
|
213
189
|
sql, vals = self.sql.timestamp()
|
|
214
190
|
return tx.execute(sql, vals).scalar()
|
|
215
191
|
|
|
216
192
|
@property
|
|
217
193
|
def user(self):
|
|
194
|
+
"""
|
|
195
|
+
Returns the current user as known by the DB server.
|
|
196
|
+
"""
|
|
218
197
|
with Transaction(self) as tx:
|
|
219
198
|
sql, vals = self.sql.user()
|
|
220
199
|
return tx.execute(sql, vals).scalar()
|
|
221
200
|
|
|
222
201
|
@property
|
|
223
202
|
def databases(self):
|
|
203
|
+
"""
|
|
204
|
+
Returns a list of available databases.
|
|
205
|
+
"""
|
|
224
206
|
with Transaction(self) as tx:
|
|
225
207
|
sql, vals = self.sql.databases()
|
|
226
208
|
result = tx.execute(sql, vals)
|
|
@@ -228,13 +210,19 @@ class Engine(object):
|
|
|
228
210
|
|
|
229
211
|
@property
|
|
230
212
|
def current_database(self):
|
|
213
|
+
"""
|
|
214
|
+
Returns the name of the current database.
|
|
215
|
+
"""
|
|
231
216
|
with Transaction(self) as tx:
|
|
232
217
|
sql, vals = self.sql.current_database()
|
|
233
218
|
return tx.execute(sql, vals).scalar()
|
|
234
219
|
|
|
235
220
|
def create_database(self, name=None):
|
|
221
|
+
"""
|
|
222
|
+
Creates a database if it doesn't exist, or does nothing if it does.
|
|
223
|
+
"""
|
|
236
224
|
old = None
|
|
237
|
-
if name
|
|
225
|
+
if name is None:
|
|
238
226
|
old = self.config["database"]
|
|
239
227
|
self.set_config({"database": "postgres"})
|
|
240
228
|
name = old
|
|
@@ -246,19 +234,27 @@ class Engine(object):
|
|
|
246
234
|
return self
|
|
247
235
|
|
|
248
236
|
def switch_to_database(self, database):
|
|
237
|
+
"""
|
|
238
|
+
Switch the config to use a different database name, closing any existing connection.
|
|
239
|
+
"""
|
|
249
240
|
conf = self.config
|
|
250
241
|
if "database" in conf:
|
|
251
242
|
conf["database"] = database
|
|
252
243
|
if "dbname" in conf:
|
|
253
244
|
conf["dbname"] = database
|
|
254
|
-
|
|
255
245
|
return self
|
|
256
246
|
|
|
257
247
|
def set_config(self, config):
|
|
248
|
+
"""
|
|
249
|
+
Updates the internal config dictionary.
|
|
250
|
+
"""
|
|
258
251
|
self.config.update(config)
|
|
259
252
|
|
|
260
253
|
@property
|
|
261
254
|
def schemas(self):
|
|
255
|
+
"""
|
|
256
|
+
Returns a list of schemas in the current database.
|
|
257
|
+
"""
|
|
262
258
|
with Transaction(self) as tx:
|
|
263
259
|
sql, vals = self.sql.schemas()
|
|
264
260
|
result = tx.execute(sql, vals)
|
|
@@ -266,107 +262,106 @@ class Engine(object):
|
|
|
266
262
|
|
|
267
263
|
@property
|
|
268
264
|
def current_schema(self):
|
|
265
|
+
"""
|
|
266
|
+
Returns the current schema in use.
|
|
267
|
+
"""
|
|
269
268
|
with Transaction(self) as tx:
|
|
270
269
|
sql, vals = self.sql.current_schema()
|
|
271
270
|
return tx.execute(sql, vals).scalar()
|
|
272
271
|
|
|
273
272
|
@property
|
|
274
273
|
def tables(self):
|
|
274
|
+
"""
|
|
275
|
+
Returns a list of 'schema.table' for all tables in the current DB.
|
|
276
|
+
"""
|
|
275
277
|
with Transaction(self) as tx:
|
|
276
278
|
sql, vals = self.sql.tables()
|
|
277
279
|
result = tx.execute(sql, vals)
|
|
278
|
-
return ["
|
|
280
|
+
return [f"{x[0]}.{x[1]}" for x in result.as_tuple()]
|
|
279
281
|
|
|
280
282
|
@property
|
|
281
283
|
def views(self):
|
|
284
|
+
"""
|
|
285
|
+
Returns a list of 'schema.view' for all views in the current DB.
|
|
286
|
+
"""
|
|
282
287
|
with Transaction(self) as tx:
|
|
283
288
|
sql, vals = self.sql.views()
|
|
284
289
|
result = tx.execute(sql, vals)
|
|
285
|
-
return ["
|
|
290
|
+
return [f"{x[0]}.{x[1]}" for x in result.as_tuple()]
|
|
286
291
|
|
|
287
|
-
def
|
|
288
|
-
|
|
292
|
+
def process_error(self, sql_stmt=None, sql_params=None):
|
|
293
|
+
"""
|
|
294
|
+
Central method to parse driver exceptions and re-raise them as our custom exceptions.
|
|
295
|
+
"""
|
|
289
296
|
e = sys.exc_info()[1]
|
|
290
297
|
msg = str(e).strip().lower()
|
|
298
|
+
|
|
291
299
|
if isinstance(e, exceptions.DbException):
|
|
292
300
|
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:
|
|
301
|
+
|
|
302
|
+
error_code, error_mesg = self.sql.get_error(e)
|
|
303
|
+
|
|
304
|
+
if error_code in self.sql.ApplicationErrorCodes:
|
|
311
305
|
raise exceptions.DbApplicationError(e)
|
|
312
|
-
|
|
306
|
+
if error_code in self.sql.ColumnMissingErrorCodes:
|
|
313
307
|
raise exceptions.DbColumnMissingError(e)
|
|
314
|
-
|
|
308
|
+
if error_code in self.sql.TableMissingErrorCodes:
|
|
315
309
|
raise exceptions.DbTableMissingError(e)
|
|
316
|
-
|
|
310
|
+
if error_code in self.sql.DatabaseMissingErrorCodes:
|
|
317
311
|
raise exceptions.DbDatabaseMissingError(e)
|
|
318
|
-
|
|
312
|
+
if error_code in self.sql.ForeignKeyMissingErrorCodes:
|
|
319
313
|
raise exceptions.DbForeignKeyMissingError(e)
|
|
320
|
-
|
|
314
|
+
if error_code in self.sql.TruncationErrorCodes:
|
|
321
315
|
raise exceptions.DbTruncationError(e)
|
|
322
|
-
|
|
316
|
+
if error_code in self.sql.DataIntegrityErrorCodes:
|
|
323
317
|
raise exceptions.DbDataIntegrityError(e)
|
|
324
|
-
|
|
318
|
+
if error_code in self.sql.ConnectionErrorCodes:
|
|
325
319
|
raise exceptions.DbConnectionError(e)
|
|
326
|
-
|
|
320
|
+
if error_code in self.sql.DuplicateKeyErrorCodes:
|
|
327
321
|
raise exceptions.DbDuplicateKeyError(e)
|
|
328
|
-
|
|
322
|
+
if re.search(r"key \(sys_id\)=\(\d+\) already exists.", msg, re.M):
|
|
329
323
|
raise exceptions.DbDuplicateKeyError(e)
|
|
330
|
-
|
|
324
|
+
if error_code in self.sql.DatabaseObjectExistsErrorCodes:
|
|
331
325
|
raise exceptions.DbObjectExistsError(e)
|
|
332
|
-
|
|
326
|
+
if error_code in self.sql.LockTimeoutErrorCodes:
|
|
333
327
|
raise exceptions.DbLockTimeoutError(e)
|
|
334
|
-
|
|
328
|
+
if error_code in self.sql.RetryTransactionCodes:
|
|
335
329
|
raise exceptions.DbRetryTransaction(e)
|
|
336
|
-
|
|
330
|
+
if re.findall(r"database.*does not exist", msg, re.M):
|
|
337
331
|
raise exceptions.DbDatabaseMissingError(e)
|
|
338
|
-
|
|
332
|
+
if re.findall(r"no such database", msg, re.M):
|
|
339
333
|
raise exceptions.DbDatabaseMissingError(e)
|
|
340
|
-
|
|
334
|
+
if re.findall(r"already exists", msg, re.M):
|
|
341
335
|
raise exceptions.DbObjectExistsError(e)
|
|
342
|
-
|
|
336
|
+
if re.findall(r"server closed the connection unexpectedly", msg, re.M):
|
|
343
337
|
raise exceptions.DbConnectionError(e)
|
|
344
|
-
|
|
338
|
+
if re.findall(r"no connection to the server", msg, re.M):
|
|
345
339
|
raise exceptions.DbConnectionError(e)
|
|
346
|
-
|
|
340
|
+
if re.findall(r"connection timed out", msg, re.M):
|
|
347
341
|
raise exceptions.DbConnectionError(e)
|
|
348
|
-
|
|
342
|
+
if re.findall(r"could not connect to server", msg, re.M):
|
|
349
343
|
raise exceptions.DbConnectionError(e)
|
|
350
|
-
|
|
344
|
+
if re.findall(r"cannot connect to server", msg, re.M):
|
|
351
345
|
raise exceptions.DbConnectionError(e)
|
|
352
|
-
|
|
346
|
+
if re.findall(r"connection already closed", msg, re.M):
|
|
353
347
|
raise exceptions.DbConnectionError(e)
|
|
354
|
-
|
|
348
|
+
if re.findall(r"cursor already closed", msg, re.M):
|
|
355
349
|
raise exceptions.DbConnectionError(e)
|
|
356
|
-
|
|
357
|
-
elif "no such table:" in msg:
|
|
350
|
+
if "no such table:" in msg:
|
|
358
351
|
raise exceptions.DbTableMissingError(e)
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
352
|
+
|
|
353
|
+
msg = f"""
|
|
354
|
+
Unhandled/Unknown Error in engine.process_error
|
|
355
|
+
EXC_TYPE = {type(e)}
|
|
356
|
+
EXC_MSG = {str(e).strip()}
|
|
357
|
+
|
|
358
|
+
ERROR_CODE = {error_code}
|
|
359
|
+
ERROR_MSG = {error_mesg}
|
|
360
|
+
|
|
361
|
+
SQL_STMT = {sql_stmt}
|
|
362
|
+
SQL_PARAMS = {sql_params}
|
|
363
|
+
|
|
364
|
+
{traceback.format_exc()}
|
|
365
|
+
"""
|
|
366
|
+
print(msg)
|
|
372
367
|
raise
|