dbobj3 0.6.0__tar.gz → 0.8.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.
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "dbobj3"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.8.0"
|
|
8
8
|
description = "High-level MySQL/MSSQL/Oracle access module"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.6"
|
|
@@ -16,7 +16,7 @@ dependencies = [
|
|
|
16
16
|
packages = ["src/dbobj3.py"]
|
|
17
17
|
|
|
18
18
|
[tool.bumpversion]
|
|
19
|
-
current_version = "0.
|
|
19
|
+
current_version = "0.8.0"
|
|
20
20
|
commit = true
|
|
21
21
|
tag = true
|
|
22
22
|
parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#!/usr/bin/env python3.
|
|
1
|
+
#!/usr/bin/env python3.9
|
|
2
2
|
|
|
3
3
|
"""
|
|
4
4
|
High-Level Access to MySQL, MS SQL Server, Oracle Module and more.
|
|
@@ -21,9 +21,10 @@ Example:
|
|
|
21
21
|
rsServices.next()
|
|
22
22
|
|
|
23
23
|
"""
|
|
24
|
-
__version__ = "0.
|
|
24
|
+
__version__ = "0.8.0"
|
|
25
25
|
|
|
26
26
|
from sys import version as sys_version, exit
|
|
27
|
+
from datetime import datetime, date, time
|
|
27
28
|
pyversion = sys_version[0:sys_version.find(' ')]
|
|
28
29
|
using_mysqlclient, using_pymysql = False, False
|
|
29
30
|
|
|
@@ -32,10 +33,10 @@ try:
|
|
|
32
33
|
#raise ImportError
|
|
33
34
|
import MySQLdb
|
|
34
35
|
import MySQLdb.cursors
|
|
35
|
-
import MySQLdb.converters
|
|
36
|
-
# MySQLdb dropped Python3.x support
|
|
37
|
-
# - For Centos/Python2.x use
|
|
38
|
-
# - yum install mysql-devel, MySQL-python
|
|
36
|
+
#import MySQLdb.converters
|
|
37
|
+
# MySQLdb dropped Python3.x support
|
|
38
|
+
# - For Centos/Python2.x use
|
|
39
|
+
# - yum install mysql-devel, MySQL-python
|
|
39
40
|
# - pip install mysql-python
|
|
40
41
|
# - For Python3.x use the fork MySQLdb
|
|
41
42
|
# - pip install mysqlclient ( developed by pymysql devs )
|
|
@@ -49,11 +50,11 @@ if not using_mysqlclient:
|
|
|
49
50
|
# pymysql is a pure python implementation of MySQLdb
|
|
50
51
|
# Linux:
|
|
51
52
|
import pymysql as MySQLdb
|
|
52
|
-
import MySQLdb.cursors
|
|
53
|
-
import MySQLdb.converters
|
|
53
|
+
#import MySQLdb.cursors
|
|
54
|
+
#import MySQLdb.converters
|
|
54
55
|
# Windows:
|
|
55
56
|
#import pymysql
|
|
56
|
-
#pymysql.install_as_MySQLdb()
|
|
57
|
+
#pymysql.install_as_MySQLdb()
|
|
57
58
|
#import pymysql.cursors
|
|
58
59
|
#import pymysql.converters
|
|
59
60
|
using_pymysql = True
|
|
@@ -63,6 +64,43 @@ if not using_mysqlclient:
|
|
|
63
64
|
lstLoadedDrivers.append({"pymysql": "Not Loaded (MySQL)"})
|
|
64
65
|
#'''
|
|
65
66
|
|
|
67
|
+
def _build_pymysql_conv():
|
|
68
|
+
"""
|
|
69
|
+
Return a PyMySQL conversion dict that parses DATETIME / TIMESTAMP / DATE
|
|
70
|
+
into real Python datetime/date objects (mimicking mysqlclient behavior).
|
|
71
|
+
"""
|
|
72
|
+
if not using_pymysql:
|
|
73
|
+
return None
|
|
74
|
+
from pymysql.constants import FIELD_TYPE
|
|
75
|
+
from pymysql.converters import conversions
|
|
76
|
+
conv = conversions.copy()
|
|
77
|
+
|
|
78
|
+
def _parse_dt(val):
|
|
79
|
+
if val is None:
|
|
80
|
+
return None
|
|
81
|
+
v = val.strip()
|
|
82
|
+
# Try common formats (truncate fractional seconds)
|
|
83
|
+
base = v.split('.')[0]
|
|
84
|
+
for fmt in ("%Y-%m-%d %H:%M:%S",
|
|
85
|
+
"%Y-%m-%d %H:%M",
|
|
86
|
+
"%Y-%m-%dT%H:%M:%S",
|
|
87
|
+
"%Y-%m-%d"):
|
|
88
|
+
try:
|
|
89
|
+
return datetime.strptime(base, fmt)
|
|
90
|
+
except Exception:
|
|
91
|
+
pass
|
|
92
|
+
# ISO fallback
|
|
93
|
+
try:
|
|
94
|
+
return datetime.fromisoformat(v.replace('Z',''))
|
|
95
|
+
except Exception:
|
|
96
|
+
return v # leave as original string if unparseable
|
|
97
|
+
|
|
98
|
+
conv[FIELD_TYPE.DATETIME] = _parse_dt
|
|
99
|
+
conv[FIELD_TYPE.TIMESTAMP] = _parse_dt
|
|
100
|
+
conv[FIELD_TYPE.DATE] = (lambda v: date.fromisoformat(v) if v else None)
|
|
101
|
+
return conv
|
|
102
|
+
|
|
103
|
+
|
|
66
104
|
try:
|
|
67
105
|
import pymssql
|
|
68
106
|
lstLoadedDrivers.append({"pymssql": "Loaded (Microsoft SQL Server)"})
|
|
@@ -304,35 +342,6 @@ class dbObjCursor:
|
|
|
304
342
|
else:
|
|
305
343
|
self.EOF = 1
|
|
306
344
|
|
|
307
|
-
'''
|
|
308
|
-
if(self.recordPointer <= self.numRows): #???? what about 0?
|
|
309
|
-
self.fieldByName = {}
|
|
310
|
-
self.fieldNames = []
|
|
311
|
-
print(self.recordPointer)
|
|
312
|
-
print(self.numRows)
|
|
313
|
-
print(self.cursor)
|
|
314
|
-
print("-----------------------------------------------------")
|
|
315
|
-
#print(self.cursor.description)
|
|
316
|
-
print(self.lstRecords)
|
|
317
|
-
print(self.recordPointer <= self.numRows)
|
|
318
|
-
print(self.recordPointer)
|
|
319
|
-
print(self.numRows)
|
|
320
|
-
print(type(self.recordPointer))
|
|
321
|
-
print(type(self.numRows))
|
|
322
|
-
columns = [column[0] for column in self.cursor.description]
|
|
323
|
-
self.fieldByName = (dict(zip(columns, self.lstRecords[self.recordPointer])))
|
|
324
|
-
#fieldNo = 0
|
|
325
|
-
#for cursorFieldname in self.cursor.description:
|
|
326
|
-
# self.fieldByName[cursorFieldname[0]] = self.lstRecords[(self.recordPointer-1)][fieldNo]
|
|
327
|
-
# self.fieldNames.append(cursorFieldname[0])
|
|
328
|
-
# fieldNo = fieldNo + 1
|
|
329
|
-
self.fields = self.fieldByName
|
|
330
|
-
self.recordPointer += 1
|
|
331
|
-
self.EOF = 0
|
|
332
|
-
else:
|
|
333
|
-
self.EOF = 1
|
|
334
|
-
'''
|
|
335
|
-
|
|
336
345
|
def first(self):
|
|
337
346
|
"""Move to the next record in the record set and loads the data into the fields property. Sets EOF at end of records."""
|
|
338
347
|
if(self.dbType == "MYSQL"):
|
|
@@ -394,18 +403,18 @@ class dbObjConnection:
|
|
|
394
403
|
dbObjConnection is the database connection object. It is responsible for connecting to
|
|
395
404
|
the database. This object supports access to MySQL, Microsoft SQL Server, Oracle,
|
|
396
405
|
SQLite3, and Progress DataDirect.
|
|
397
|
-
|
|
406
|
+
|
|
398
407
|
prmDBType can be: MYSQL, MSSQL, ORACLE, SQLITE3, PROGRESS, API, or JDBC
|
|
399
408
|
|
|
400
409
|
"""
|
|
401
|
-
def __init__(self,
|
|
402
|
-
prmDBType="MYSQL",
|
|
403
|
-
prmHost="localhost",
|
|
404
|
-
prmDb="",
|
|
405
|
-
prmUser="",
|
|
406
|
-
prmPass="",
|
|
407
|
-
prmPort=3306,
|
|
408
|
-
envOracle={},
|
|
410
|
+
def __init__(self,
|
|
411
|
+
prmDBType="MYSQL",
|
|
412
|
+
prmHost="localhost",
|
|
413
|
+
prmDb="",
|
|
414
|
+
prmUser="",
|
|
415
|
+
prmPass="",
|
|
416
|
+
prmPort=3306,
|
|
417
|
+
envOracle={},
|
|
409
418
|
envProgress={},
|
|
410
419
|
driver='',
|
|
411
420
|
driverClass="",
|
|
@@ -499,8 +508,23 @@ class dbObjConnection:
|
|
|
499
508
|
|
|
500
509
|
def mySqlConnect(self, prmHost, prmDb, prmUser, prmPass, prmPort=3306):
|
|
501
510
|
try:
|
|
502
|
-
|
|
503
|
-
|
|
511
|
+
kwargs = dict(host=prmHost, db=prmDb, user=prmUser, passwd=prmPass, port=prmPort)
|
|
512
|
+
if using_pymysql:
|
|
513
|
+
conv = _build_pymysql_conv()
|
|
514
|
+
if conv:
|
|
515
|
+
kwargs["conv"] = conv
|
|
516
|
+
# Ensure utf8mb4 for PyMySQL
|
|
517
|
+
kwargs.setdefault("charset", "utf8mb4")
|
|
518
|
+
kwargs.setdefault("autocommit", True)
|
|
519
|
+
self.connHandle = MySQLdb.connect(**kwargs)
|
|
520
|
+
# Uniform autocommit enabling (mysqlclient vs pymysql)
|
|
521
|
+
try:
|
|
522
|
+
self.connHandle.autocommit(True)
|
|
523
|
+
except Exception:
|
|
524
|
+
try:
|
|
525
|
+
self.connHandle.autocommit = True
|
|
526
|
+
except Exception:
|
|
527
|
+
pass
|
|
504
528
|
if(self.connHandle):
|
|
505
529
|
self.setConnectSuccess()
|
|
506
530
|
else:
|
|
@@ -544,7 +568,7 @@ class dbObjConnection:
|
|
|
544
568
|
self.setConnectFail(e)
|
|
545
569
|
return self.msgObj
|
|
546
570
|
|
|
547
|
-
def progressConnect(self, prmHost, prmDb, prmUser, prmPass, prmPort=
|
|
571
|
+
def progressConnect(self, prmHost, prmDb, prmUser, prmPass, prmPort=35028, envProgress={}, driver=None):
|
|
548
572
|
try:
|
|
549
573
|
driver = driver or self.driver
|
|
550
574
|
strCnxn = 'Driver={};'.format(driver)
|
|
@@ -599,10 +623,10 @@ class dbObjConnection:
|
|
|
599
623
|
|
|
600
624
|
You may also need to increase the innodb_log_file_size mysql variable in your my.cnf configuration
|
|
601
625
|
to for example 128MB or higher.
|
|
602
|
-
|
|
603
|
-
Server dropped an incorrect or too large packet. If mysqld gets a packet that is too large or
|
|
604
|
-
incorrect, it assumes that something has gone wrong with the client and closes the connection.
|
|
605
|
-
To fix, you can increase the maximal packet size limit max_allowed_packet in my.cnf file,
|
|
626
|
+
|
|
627
|
+
Server dropped an incorrect or too large packet. If mysqld gets a packet that is too large or
|
|
628
|
+
incorrect, it assumes that something has gone wrong with the client and closes the connection.
|
|
629
|
+
To fix, you can increase the maximal packet size limit max_allowed_packet in my.cnf file,
|
|
606
630
|
eg. set max_allowed_packet = 128M, then restart your MySQL server.
|
|
607
631
|
'''
|
|
608
632
|
|
|
@@ -613,16 +637,16 @@ class dbObjConnection:
|
|
|
613
637
|
|
|
614
638
|
self.msgObj.success = False
|
|
615
639
|
|
|
616
|
-
while ( self.autoreconnect
|
|
617
|
-
and( self.reconnect_attempts <= self.reconnect_max )
|
|
640
|
+
while ( self.autoreconnect
|
|
641
|
+
and( self.reconnect_attempts <= self.reconnect_max )
|
|
618
642
|
and not self.msgObj.success ):
|
|
619
|
-
|
|
643
|
+
|
|
620
644
|
self.reconnect_attempts += 1
|
|
621
645
|
if self.reconnect_attempts > self.reconnect_max:
|
|
622
646
|
self.msgObj.message += ' - Exceeded Maximum autoreconnect Attempts to {0} ({1} attempts).'.format(self.dbType, self.reconnect_attempts)
|
|
623
647
|
print(self.msgObj.message)
|
|
624
648
|
return self.msgObj
|
|
625
|
-
|
|
649
|
+
|
|
626
650
|
print("ATTEMPT {0} of Reconnect to {1}".format(self.reconnect_attempts,self.dbType))
|
|
627
651
|
if(self.dbType == "MYSQL"):
|
|
628
652
|
self.mySqlConnect(self.host, self.db, self.user, self.passwd, self.port)
|
|
@@ -634,7 +658,7 @@ class dbObjConnection:
|
|
|
634
658
|
self.sqlite3Connect(self.db)
|
|
635
659
|
elif(self.dbType == "PROGRESS"):
|
|
636
660
|
self.progressConnect(self.host, self.db, self.user, self.passwd, self.port)
|
|
637
|
-
|
|
661
|
+
|
|
638
662
|
if self.msgObj.success:
|
|
639
663
|
print('Connection to {0} Restored.'.format(self.dbType))
|
|
640
664
|
return self.msgObj
|
|
@@ -764,16 +788,19 @@ class dbObjConnection:
|
|
|
764
788
|
|
|
765
789
|
def apiDisconnect(self):
|
|
766
790
|
pass
|
|
791
|
+
if self.connHandle:
|
|
792
|
+
self.connHandle.close()
|
|
793
|
+
self.connHandle = None
|
|
767
794
|
|
|
768
795
|
def jdbcDisconnect(self):
|
|
769
796
|
if self.connHandle:
|
|
770
797
|
self.connHandle.close()
|
|
771
798
|
self.connHandle = None
|
|
772
799
|
|
|
773
|
-
def execute(self, prmSql, *args):
|
|
800
|
+
def execute(self, prmSql, *args, **kw):
|
|
774
801
|
"""Execute the SQL and return a record set if applicable"""
|
|
775
802
|
if(self.dbType == "MYSQL"):
|
|
776
|
-
return self.mySqlExecute(prmSql, *args)
|
|
803
|
+
return self.mySqlExecute(prmSql, *args, **kw)
|
|
777
804
|
if(self.dbType == "MSSQL"):
|
|
778
805
|
return self.msSqlExecute(prmSql)
|
|
779
806
|
if(self.dbType == "ORACLE"):
|
|
@@ -787,6 +814,29 @@ class dbObjConnection:
|
|
|
787
814
|
if(self.dbType in ("JDBC")):
|
|
788
815
|
return self.jdbcExecute(prmSql)
|
|
789
816
|
|
|
817
|
+
def executemany(self, prmSql, *args):
|
|
818
|
+
"""Execute the SQL and return a record set if applicable"""
|
|
819
|
+
if(self.dbType == "MYSQL"):
|
|
820
|
+
return self.mySqlExecuteMany(prmSql, *args)
|
|
821
|
+
if(self.dbType == "MSSQL"):
|
|
822
|
+
return
|
|
823
|
+
#return self.msSqlExecuteMany(prmSql)
|
|
824
|
+
if(self.dbType == "ORACLE"):
|
|
825
|
+
return
|
|
826
|
+
#return self.oracleExecuteMany(prmSql)
|
|
827
|
+
if(self.dbType in ("SQLITE","SQLITE3")):
|
|
828
|
+
return
|
|
829
|
+
#return self.sqlite3ExecuteMany(prmSql)
|
|
830
|
+
if(self.dbType in ("PROGRESS")):
|
|
831
|
+
return
|
|
832
|
+
#return self.progressExecuteMany(prmSql)
|
|
833
|
+
if(self.dbType in ("API")):
|
|
834
|
+
return
|
|
835
|
+
#return self.apiExecuteMany(prmSql)
|
|
836
|
+
if(self.dbType in ("JDBC")):
|
|
837
|
+
return
|
|
838
|
+
#return self.jdbcExecuteMany(prmSql)
|
|
839
|
+
|
|
790
840
|
def fetchall(self, prmSql, *args):
|
|
791
841
|
"""Returns result set as a list of dictionaries"""
|
|
792
842
|
rset = []
|
|
@@ -796,21 +846,18 @@ class dbObjConnection:
|
|
|
796
846
|
crsr.next()
|
|
797
847
|
return rset
|
|
798
848
|
|
|
799
|
-
|
|
800
849
|
def fetchone(self, prmSql, *args):
|
|
801
850
|
"""Returns a single row as a dictionary"""
|
|
802
851
|
crsr = self.execute( prmSql, *args )
|
|
803
852
|
dictRow = {} if crsr.EOF else crsr.fields
|
|
804
853
|
return dictRow
|
|
805
854
|
|
|
806
|
-
|
|
807
855
|
def fetchval(self, prmSql, *args):
|
|
808
856
|
"""Returns a single value"""
|
|
809
857
|
dictRow = self.fetchone( prmSql, *args )
|
|
810
858
|
listVals = list(dictRow.values())
|
|
811
859
|
return None if not listVals else listVals[0]
|
|
812
860
|
|
|
813
|
-
|
|
814
861
|
def fetchlistvals(self, prmSql, *args):
|
|
815
862
|
"""Returns a list of vals; if more than one key/column, returns a list of value tuples"""
|
|
816
863
|
listvals = []
|
|
@@ -822,13 +869,12 @@ class dbObjConnection:
|
|
|
822
869
|
listvals.append( vals )
|
|
823
870
|
return listvals
|
|
824
871
|
|
|
825
|
-
|
|
826
872
|
def insert(self, table, prmDict, update_on_duplicate=False):
|
|
827
873
|
if update_on_duplicate:
|
|
828
874
|
keystr = ','.join(prmDict.keys())
|
|
829
875
|
valstr = ','.join(['%s' for i in range(len(prmDict.keys()))])
|
|
830
876
|
setstr = ",".join([ "{k}=%s".format(k=k) for k in prmDict.keys()])
|
|
831
|
-
args = tuple(prmDict.values()) * 2
|
|
877
|
+
args = tuple(prmDict.values()) * 2
|
|
832
878
|
strSql = "INSERT INTO {table} ({keystr}) VALUES ({valstr})".format(table=table,keystr=keystr,valstr=valstr)
|
|
833
879
|
strSql += "ON DUPLICATE KEY UPDATE {setstr}".format(setstr=setstr)
|
|
834
880
|
return self.execute(strSql, *args)
|
|
@@ -850,20 +896,24 @@ class dbObjConnection:
|
|
|
850
896
|
self.mySqlPing()
|
|
851
897
|
# untested
|
|
852
898
|
elif(self.dbType == "MSSQL"):
|
|
853
|
-
|
|
899
|
+
return
|
|
854
900
|
self.msSqlPing()
|
|
855
901
|
# does not work
|
|
856
902
|
elif(self.dbType == "ORACLE"):
|
|
857
|
-
|
|
903
|
+
return
|
|
858
904
|
self.oraclePing()
|
|
859
905
|
# untested
|
|
860
906
|
elif(self.dbType in ("SQLITE", "SQLITE3")):
|
|
861
|
-
|
|
907
|
+
return
|
|
862
908
|
self.sqlite3Ping()
|
|
863
909
|
# untested
|
|
864
910
|
elif(self.dbType == "PROGRESS"):
|
|
865
|
-
|
|
911
|
+
return
|
|
866
912
|
self.progressPing()
|
|
913
|
+
# untested
|
|
914
|
+
elif(self.dbType == "JDBC"):
|
|
915
|
+
return
|
|
916
|
+
self.jdbcPing()
|
|
867
917
|
|
|
868
918
|
def mySqlPing(self, reconnect=True):
|
|
869
919
|
"""
|
|
@@ -903,7 +953,7 @@ class dbObjConnection:
|
|
|
903
953
|
else:
|
|
904
954
|
raise Exception
|
|
905
955
|
|
|
906
|
-
def setMySqlExecuteFail(self, mySqlCursor, prmSql, e, *args):
|
|
956
|
+
def setMySqlExecuteFail(self, mySqlCursor, prmSql, e, *args, **kw):
|
|
907
957
|
self.msgObj.success = False
|
|
908
958
|
prmSql += '' if not args else ' ({0}) '.format( repr(args) )
|
|
909
959
|
self.msgObj.message = "SQL Failed: {0} - {1}".format( prmSql, e )
|
|
@@ -917,9 +967,9 @@ class dbObjConnection:
|
|
|
917
967
|
finally:
|
|
918
968
|
return mySqlCursor
|
|
919
969
|
|
|
920
|
-
def setMySqlExecuteSuccess(self, mySqlCursor, prmSql, *args):
|
|
970
|
+
def setMySqlExecuteSuccess(self, mySqlCursor, prmSql, *args, **kw):
|
|
921
971
|
self.msgObj.success = True
|
|
922
|
-
self.msgObj.message = "SQL Executed: {0} {1}".format(prmSql,'' if not args else repr(args))
|
|
972
|
+
self.msgObj.message = "SQL Executed: {0} {1}".format(prmSql,'' if not args else repr(args)+ ' ' + repr(kw))
|
|
923
973
|
try:
|
|
924
974
|
mySqlCursor.numFields = len(mySqlCursor.cursor.description)
|
|
925
975
|
if(mySqlCursor.numRows):
|
|
@@ -932,10 +982,14 @@ class dbObjConnection:
|
|
|
932
982
|
finally:
|
|
933
983
|
return mySqlCursor
|
|
934
984
|
|
|
935
|
-
def mySqlExecute(self, prmSql, *args):
|
|
985
|
+
def mySqlExecute(self, prmSql, *args, **kw):
|
|
936
986
|
mySqlCursor = self.getCursor()
|
|
937
987
|
try:
|
|
938
|
-
if
|
|
988
|
+
if not hasattr(self.connHandle, 'open') or self.connHandle.open==0 :
|
|
989
|
+
self.reconnect()
|
|
990
|
+
if kw:
|
|
991
|
+
mySqlCursor.cursor.execute(prmSql, kw)
|
|
992
|
+
elif args:
|
|
939
993
|
mySqlCursor.cursor.execute(prmSql, args)
|
|
940
994
|
else:
|
|
941
995
|
mySqlCursor.cursor.execute(prmSql)
|
|
@@ -953,22 +1007,23 @@ class dbObjConnection:
|
|
|
953
1007
|
self.msgObj.message += ' or killed process/connection.'
|
|
954
1008
|
self.msgObj.message += ' connHandle={0}, connHandle.open={1}'.format(self.connHandle,self.connHandle.open)
|
|
955
1009
|
self.reconnect()
|
|
956
|
-
elif self.connHandle.open==0 or "
|
|
1010
|
+
elif not hasattr(self.connHandle, 'open') or self.connHandle.open==0 or "t connect t" in str(e).lower():
|
|
957
1011
|
self.msgObj.message += ' - Database Connection Closed or Never Established.'
|
|
958
1012
|
self.msgObj.message += ' connHandle={0}, connHandle.open={1}'.format(self.connHandle,self.connHandle.open)
|
|
959
1013
|
self.reconnect()
|
|
960
|
-
return mySqlCursor if not self.msgObj.success else self.mySqlExecute( prmSql, *args )
|
|
1014
|
+
return mySqlCursor if not self.msgObj.success else self.mySqlExecute( prmSql, *args, **kw )
|
|
961
1015
|
except Exception as e:
|
|
962
1016
|
mySqlCursor = self.setMySqlExecuteFail(mySqlCursor, prmSql, e, *args)
|
|
963
|
-
if self.connHandle.open==0 or "Can't connect to" in str(e):
|
|
1017
|
+
#if self.connHandle.open==0 or "Can't connect to" in str(e): # This line was failing (self.connHandle was an "int") and so not reconnecting
|
|
1018
|
+
if not hasattr(self.connHandle, 'open') or self.connHandle.open==0 or "t connect t" in str(e).lower():
|
|
964
1019
|
self.msgObj.message += ' - Database Connection Closed or Never Established.'
|
|
965
1020
|
self.msgObj.message += ' connHandle={0}, connHandle.open={1}'.format(self.connHandle,self.connHandle.open)
|
|
966
1021
|
self.reconnect()
|
|
967
|
-
return mySqlCursor if not self.msgObj.success else self.mySqlExecute( prmSql, *args )
|
|
1022
|
+
return mySqlCursor if not self.msgObj.success else self.mySqlExecute( prmSql, *args, **kw )
|
|
968
1023
|
print(self.msgObj.message)
|
|
969
1024
|
return mySqlCursor
|
|
970
1025
|
else:
|
|
971
|
-
mySqlCursor = self.setMySqlExecuteSuccess(mySqlCursor, prmSql, *args)
|
|
1026
|
+
mySqlCursor = self.setMySqlExecuteSuccess(mySqlCursor, prmSql, *args, **kw)
|
|
972
1027
|
return mySqlCursor
|
|
973
1028
|
|
|
974
1029
|
def msSqlExecute(self, prmSql):
|
|
@@ -1113,6 +1168,101 @@ class dbObjConnection:
|
|
|
1113
1168
|
jdbcCursor.next()
|
|
1114
1169
|
return jdbcCursor
|
|
1115
1170
|
|
|
1171
|
+
def mySqlExecuteMany(self, prmSql, *args):
|
|
1172
|
+
# https://dev.mysql.com/doc/connector-python/en/connector-python-api-mysqlcursor-executemany.html
|
|
1173
|
+
mySqlCursor = self.getCursor()
|
|
1174
|
+
try:
|
|
1175
|
+
mySqlCursor.cursor.executemany(prmSql, *args)
|
|
1176
|
+
self.msgObj.message = "SQL Executed: "+prmSql
|
|
1177
|
+
self.msgObj.success = True
|
|
1178
|
+
mySqlCursor.numRows = mySqlCursor.cursor.rowcount
|
|
1179
|
+
self.lastInsId = self.connHandle.insert_id()
|
|
1180
|
+
except MySQLdb.OperationalError as e:
|
|
1181
|
+
self.msgObj.message += ' - OperationalError: {0}'.format(e)
|
|
1182
|
+
mySqlCursor = self.setMySqlExecuteFail(mySqlCursor, prmSql, e, *args)
|
|
1183
|
+
print(self.msgObj.message)
|
|
1184
|
+
if "server has gone away" in str(e):
|
|
1185
|
+
self.msgObj.message += ' - Lost Connection Due to timeout,'
|
|
1186
|
+
self.msgObj.message += ' innodb_log_file_size, dropped incorrect/large packet,'
|
|
1187
|
+
self.msgObj.message += ' or killed process/connection.'
|
|
1188
|
+
self.msgObj.message += ' connHandle={0}, connHandle.open={1}'.format(self.connHandle,self.connHandle.open)
|
|
1189
|
+
self.reconnect()
|
|
1190
|
+
elif self.connHandle.open==0 or "Can't connect to" in str(e):
|
|
1191
|
+
self.msgObj.message += ' - Database Connection Closed or Never Established.'
|
|
1192
|
+
self.msgObj.message += ' connHandle={0}, connHandle.open={1}'.format(self.connHandle,self.connHandle.open)
|
|
1193
|
+
self.reconnect()
|
|
1194
|
+
return mySqlCursor if not self.msgObj.success else self.mySqlExecuteMany( prmSql, *args )
|
|
1195
|
+
except Exception as e:
|
|
1196
|
+
mySqlCursor = self.setMySqlExecuteFail(mySqlCursor, prmSql, e, *args)
|
|
1197
|
+
if self.connHandle.open==0 or "Can't connect to" in str(e):
|
|
1198
|
+
self.msgObj.message += ' - Database Connection Closed or Never Established.'
|
|
1199
|
+
self.msgObj.message += ' connHandle={0}, connHandle.open={1}'.format(self.connHandle,self.connHandle.open)
|
|
1200
|
+
self.reconnect()
|
|
1201
|
+
return mySqlCursor if not self.msgObj.success else self.mySqlExecuteMany( prmSql, *args )
|
|
1202
|
+
print(self.msgObj.message)
|
|
1203
|
+
return mySqlCursor
|
|
1204
|
+
else:
|
|
1205
|
+
mySqlCursor = self.setMySqlExecuteSuccess(mySqlCursor, prmSql, *args)
|
|
1206
|
+
return mySqlCursor
|
|
1207
|
+
|
|
1208
|
+
def getTransactionIsolation(self):
|
|
1209
|
+
# untested
|
|
1210
|
+
if(self.dbType == "MYSQL"):
|
|
1211
|
+
return
|
|
1212
|
+
self.mySqlGetTransactionIsolation()
|
|
1213
|
+
# will not work
|
|
1214
|
+
elif(self.dbType == "MSSQL"):
|
|
1215
|
+
return
|
|
1216
|
+
self.msSqlGetTransactionIsolation()
|
|
1217
|
+
# untested
|
|
1218
|
+
elif(self.dbType == "ORACLE"):
|
|
1219
|
+
return
|
|
1220
|
+
self.oracleGetTransactionIsolation()
|
|
1221
|
+
# untested
|
|
1222
|
+
elif(self.dbType in ("SQLITE", "SQLITE3")):
|
|
1223
|
+
return
|
|
1224
|
+
self.sqlite3GetTransactionIsolation()
|
|
1225
|
+
# untested
|
|
1226
|
+
elif(self.dbType == "PROGRESS"):
|
|
1227
|
+
return
|
|
1228
|
+
self.progressGetTransactionIsolation()
|
|
1229
|
+
# untested
|
|
1230
|
+
elif(self.dbType == "JDBC"):
|
|
1231
|
+
return self.jdbcGetTransactionIsolation()
|
|
1232
|
+
|
|
1233
|
+
def setTransactionIsolation(self, lvl):
|
|
1234
|
+
# untested
|
|
1235
|
+
if(self.dbType == "MYSQL"):
|
|
1236
|
+
return
|
|
1237
|
+
self.mySqlSetTransactionIsolation(lvl)
|
|
1238
|
+
# will not work
|
|
1239
|
+
elif(self.dbType == "MSSQL"):
|
|
1240
|
+
return
|
|
1241
|
+
self.msSqlSetTransactionIsolation(lvl)
|
|
1242
|
+
# does not work
|
|
1243
|
+
elif(self.dbType == "ORACLE"):
|
|
1244
|
+
return
|
|
1245
|
+
self.oracleSetTransactionIsolation(lvl)
|
|
1246
|
+
# untested
|
|
1247
|
+
elif(self.dbType in ("SQLITE", "SQLITE3")):
|
|
1248
|
+
return
|
|
1249
|
+
self.sqlite3SetTransactionIsolation(lvl)
|
|
1250
|
+
# untested
|
|
1251
|
+
elif(self.dbType == "PROGRESS"):
|
|
1252
|
+
return
|
|
1253
|
+
self.progressSetTransactionIsolation(lvl)
|
|
1254
|
+
# untested
|
|
1255
|
+
elif(self.dbType == "JDBC"):
|
|
1256
|
+
return self.jdbcSetTransactionIsolation(lvl)
|
|
1257
|
+
|
|
1258
|
+
def jdbcGetTransactionIsolation(self):
|
|
1259
|
+
r = self.connHandle.jconn.getTransactionIsolation()
|
|
1260
|
+
return r
|
|
1261
|
+
|
|
1262
|
+
def jdbcSetTransactionIsolation(self, lvl):
|
|
1263
|
+
r = self.connHandle.jconn.setTransactionIsolation(lvl)
|
|
1264
|
+
return r
|
|
1265
|
+
|
|
1116
1266
|
def commit(self):
|
|
1117
1267
|
if(self.dbType == "MYSQL"):
|
|
1118
1268
|
self.connHandle.commit()
|
|
@@ -1164,11 +1314,11 @@ if __name__ == '__main__':
|
|
|
1164
1314
|
running_test = getInput("Run MySQL Test? ")
|
|
1165
1315
|
if running_test.lower() not in ('n','no'):
|
|
1166
1316
|
odb = dbtest()
|
|
1167
|
-
|
|
1317
|
+
|
|
1168
1318
|
print('\n')
|
|
1169
1319
|
|
|
1170
1320
|
if not odb:
|
|
1171
|
-
print( "Type run_test() to interactively test db connection")
|
|
1321
|
+
print( "Type run_test() to interactively test db connection")
|
|
1172
1322
|
else:
|
|
1173
1323
|
sqls, rset = sqltest( odb )
|
|
1174
1324
|
print( "\n - autoreconnect is True by default for MySQL, so if a connection socket error occurs (MySQL tested), it should auto reconnect" )
|
|
@@ -1196,17 +1346,17 @@ if __name__ == '__main__':
|
|
|
1196
1346
|
print( "now odb.reconnect_attempts = {0}".format(odb.reconnect_attempts) )
|
|
1197
1347
|
print( "setting odb.msgObj.message = ''" )
|
|
1198
1348
|
odb.msgObj.message = ''
|
|
1199
|
-
|
|
1349
|
+
|
|
1200
1350
|
print( "rerunning {s}".format(s=sqls) )
|
|
1201
|
-
|
|
1351
|
+
|
|
1202
1352
|
try:
|
|
1203
1353
|
sqls, rset = sqltest( odb, sqls )
|
|
1204
1354
|
except Exception as e:
|
|
1205
1355
|
print( "\nException in dbobj: {e}\n".format(e=e) )
|
|
1206
|
-
|
|
1356
|
+
|
|
1207
1357
|
print( "setting odb.autoreconnect back to True")
|
|
1208
1358
|
odb.autoreconnect = True
|
|
1209
1359
|
return odb
|
|
1210
1360
|
|
|
1211
|
-
# odb will be the interactively instantiated dbObj connection
|
|
1212
|
-
odb = run_test()
|
|
1361
|
+
# odb will be the interactively instantiated dbObj connection
|
|
1362
|
+
odb = run_test()
|
|
File without changes
|