dbobj3 0.6.0__tar.gz → 0.7.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.7.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.7.0"
|
|
20
20
|
commit = true
|
|
21
21
|
tag = true
|
|
22
22
|
parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)"
|
|
@@ -21,7 +21,7 @@ Example:
|
|
|
21
21
|
rsServices.next()
|
|
22
22
|
|
|
23
23
|
"""
|
|
24
|
-
__version__ = "0.
|
|
24
|
+
__version__ = "0.7.0"
|
|
25
25
|
|
|
26
26
|
from sys import version as sys_version, exit
|
|
27
27
|
pyversion = sys_version[0:sys_version.find(' ')]
|
|
@@ -33,9 +33,9 @@ try:
|
|
|
33
33
|
import MySQLdb
|
|
34
34
|
import MySQLdb.cursors
|
|
35
35
|
import MySQLdb.converters
|
|
36
|
-
# MySQLdb dropped Python3.x support
|
|
37
|
-
# - For Centos/Python2.x use
|
|
38
|
-
# - yum install mysql-devel, MySQL-python
|
|
36
|
+
# MySQLdb dropped Python3.x support
|
|
37
|
+
# - For Centos/Python2.x use
|
|
38
|
+
# - yum install mysql-devel, MySQL-python
|
|
39
39
|
# - pip install mysql-python
|
|
40
40
|
# - For Python3.x use the fork MySQLdb
|
|
41
41
|
# - pip install mysqlclient ( developed by pymysql devs )
|
|
@@ -53,7 +53,7 @@ if not using_mysqlclient:
|
|
|
53
53
|
import MySQLdb.converters
|
|
54
54
|
# Windows:
|
|
55
55
|
#import pymysql
|
|
56
|
-
#pymysql.install_as_MySQLdb()
|
|
56
|
+
#pymysql.install_as_MySQLdb()
|
|
57
57
|
#import pymysql.cursors
|
|
58
58
|
#import pymysql.converters
|
|
59
59
|
using_pymysql = True
|
|
@@ -304,35 +304,6 @@ class dbObjCursor:
|
|
|
304
304
|
else:
|
|
305
305
|
self.EOF = 1
|
|
306
306
|
|
|
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
307
|
def first(self):
|
|
337
308
|
"""Move to the next record in the record set and loads the data into the fields property. Sets EOF at end of records."""
|
|
338
309
|
if(self.dbType == "MYSQL"):
|
|
@@ -394,18 +365,18 @@ class dbObjConnection:
|
|
|
394
365
|
dbObjConnection is the database connection object. It is responsible for connecting to
|
|
395
366
|
the database. This object supports access to MySQL, Microsoft SQL Server, Oracle,
|
|
396
367
|
SQLite3, and Progress DataDirect.
|
|
397
|
-
|
|
368
|
+
|
|
398
369
|
prmDBType can be: MYSQL, MSSQL, ORACLE, SQLITE3, PROGRESS, API, or JDBC
|
|
399
370
|
|
|
400
371
|
"""
|
|
401
|
-
def __init__(self,
|
|
402
|
-
prmDBType="MYSQL",
|
|
403
|
-
prmHost="localhost",
|
|
404
|
-
prmDb="",
|
|
405
|
-
prmUser="",
|
|
406
|
-
prmPass="",
|
|
407
|
-
prmPort=3306,
|
|
408
|
-
envOracle={},
|
|
372
|
+
def __init__(self,
|
|
373
|
+
prmDBType="MYSQL",
|
|
374
|
+
prmHost="localhost",
|
|
375
|
+
prmDb="",
|
|
376
|
+
prmUser="",
|
|
377
|
+
prmPass="",
|
|
378
|
+
prmPort=3306,
|
|
379
|
+
envOracle={},
|
|
409
380
|
envProgress={},
|
|
410
381
|
driver='',
|
|
411
382
|
driverClass="",
|
|
@@ -544,7 +515,7 @@ class dbObjConnection:
|
|
|
544
515
|
self.setConnectFail(e)
|
|
545
516
|
return self.msgObj
|
|
546
517
|
|
|
547
|
-
def progressConnect(self, prmHost, prmDb, prmUser, prmPass, prmPort=
|
|
518
|
+
def progressConnect(self, prmHost, prmDb, prmUser, prmPass, prmPort=35028, envProgress={}, driver=None):
|
|
548
519
|
try:
|
|
549
520
|
driver = driver or self.driver
|
|
550
521
|
strCnxn = 'Driver={};'.format(driver)
|
|
@@ -599,10 +570,10 @@ class dbObjConnection:
|
|
|
599
570
|
|
|
600
571
|
You may also need to increase the innodb_log_file_size mysql variable in your my.cnf configuration
|
|
601
572
|
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,
|
|
573
|
+
|
|
574
|
+
Server dropped an incorrect or too large packet. If mysqld gets a packet that is too large or
|
|
575
|
+
incorrect, it assumes that something has gone wrong with the client and closes the connection.
|
|
576
|
+
To fix, you can increase the maximal packet size limit max_allowed_packet in my.cnf file,
|
|
606
577
|
eg. set max_allowed_packet = 128M, then restart your MySQL server.
|
|
607
578
|
'''
|
|
608
579
|
|
|
@@ -613,16 +584,16 @@ class dbObjConnection:
|
|
|
613
584
|
|
|
614
585
|
self.msgObj.success = False
|
|
615
586
|
|
|
616
|
-
while ( self.autoreconnect
|
|
617
|
-
and( self.reconnect_attempts <= self.reconnect_max )
|
|
587
|
+
while ( self.autoreconnect
|
|
588
|
+
and( self.reconnect_attempts <= self.reconnect_max )
|
|
618
589
|
and not self.msgObj.success ):
|
|
619
|
-
|
|
590
|
+
|
|
620
591
|
self.reconnect_attempts += 1
|
|
621
592
|
if self.reconnect_attempts > self.reconnect_max:
|
|
622
593
|
self.msgObj.message += ' - Exceeded Maximum autoreconnect Attempts to {0} ({1} attempts).'.format(self.dbType, self.reconnect_attempts)
|
|
623
594
|
print(self.msgObj.message)
|
|
624
595
|
return self.msgObj
|
|
625
|
-
|
|
596
|
+
|
|
626
597
|
print("ATTEMPT {0} of Reconnect to {1}".format(self.reconnect_attempts,self.dbType))
|
|
627
598
|
if(self.dbType == "MYSQL"):
|
|
628
599
|
self.mySqlConnect(self.host, self.db, self.user, self.passwd, self.port)
|
|
@@ -634,7 +605,7 @@ class dbObjConnection:
|
|
|
634
605
|
self.sqlite3Connect(self.db)
|
|
635
606
|
elif(self.dbType == "PROGRESS"):
|
|
636
607
|
self.progressConnect(self.host, self.db, self.user, self.passwd, self.port)
|
|
637
|
-
|
|
608
|
+
|
|
638
609
|
if self.msgObj.success:
|
|
639
610
|
print('Connection to {0} Restored.'.format(self.dbType))
|
|
640
611
|
return self.msgObj
|
|
@@ -764,6 +735,9 @@ class dbObjConnection:
|
|
|
764
735
|
|
|
765
736
|
def apiDisconnect(self):
|
|
766
737
|
pass
|
|
738
|
+
if self.connHandle:
|
|
739
|
+
self.connHandle.close()
|
|
740
|
+
self.connHandle = None
|
|
767
741
|
|
|
768
742
|
def jdbcDisconnect(self):
|
|
769
743
|
if self.connHandle:
|
|
@@ -787,6 +761,29 @@ class dbObjConnection:
|
|
|
787
761
|
if(self.dbType in ("JDBC")):
|
|
788
762
|
return self.jdbcExecute(prmSql)
|
|
789
763
|
|
|
764
|
+
def executemany(self, prmSql, *args):
|
|
765
|
+
"""Execute the SQL and return a record set if applicable"""
|
|
766
|
+
if(self.dbType == "MYSQL"):
|
|
767
|
+
return self.mySqlExecuteMany(prmSql, *args)
|
|
768
|
+
if(self.dbType == "MSSQL"):
|
|
769
|
+
return
|
|
770
|
+
#return self.msSqlExecuteMany(prmSql)
|
|
771
|
+
if(self.dbType == "ORACLE"):
|
|
772
|
+
return
|
|
773
|
+
#return self.oracleExecuteMany(prmSql)
|
|
774
|
+
if(self.dbType in ("SQLITE","SQLITE3")):
|
|
775
|
+
return
|
|
776
|
+
#return self.sqlite3ExecuteMany(prmSql)
|
|
777
|
+
if(self.dbType in ("PROGRESS")):
|
|
778
|
+
return
|
|
779
|
+
#return self.progressExecuteMany(prmSql)
|
|
780
|
+
if(self.dbType in ("API")):
|
|
781
|
+
return
|
|
782
|
+
#return self.apiExecuteMany(prmSql)
|
|
783
|
+
if(self.dbType in ("JDBC")):
|
|
784
|
+
return
|
|
785
|
+
#return self.jdbcExecuteMany(prmSql)
|
|
786
|
+
|
|
790
787
|
def fetchall(self, prmSql, *args):
|
|
791
788
|
"""Returns result set as a list of dictionaries"""
|
|
792
789
|
rset = []
|
|
@@ -796,21 +793,18 @@ class dbObjConnection:
|
|
|
796
793
|
crsr.next()
|
|
797
794
|
return rset
|
|
798
795
|
|
|
799
|
-
|
|
800
796
|
def fetchone(self, prmSql, *args):
|
|
801
797
|
"""Returns a single row as a dictionary"""
|
|
802
798
|
crsr = self.execute( prmSql, *args )
|
|
803
799
|
dictRow = {} if crsr.EOF else crsr.fields
|
|
804
800
|
return dictRow
|
|
805
801
|
|
|
806
|
-
|
|
807
802
|
def fetchval(self, prmSql, *args):
|
|
808
803
|
"""Returns a single value"""
|
|
809
804
|
dictRow = self.fetchone( prmSql, *args )
|
|
810
805
|
listVals = list(dictRow.values())
|
|
811
806
|
return None if not listVals else listVals[0]
|
|
812
807
|
|
|
813
|
-
|
|
814
808
|
def fetchlistvals(self, prmSql, *args):
|
|
815
809
|
"""Returns a list of vals; if more than one key/column, returns a list of value tuples"""
|
|
816
810
|
listvals = []
|
|
@@ -822,13 +816,12 @@ class dbObjConnection:
|
|
|
822
816
|
listvals.append( vals )
|
|
823
817
|
return listvals
|
|
824
818
|
|
|
825
|
-
|
|
826
819
|
def insert(self, table, prmDict, update_on_duplicate=False):
|
|
827
820
|
if update_on_duplicate:
|
|
828
821
|
keystr = ','.join(prmDict.keys())
|
|
829
822
|
valstr = ','.join(['%s' for i in range(len(prmDict.keys()))])
|
|
830
823
|
setstr = ",".join([ "{k}=%s".format(k=k) for k in prmDict.keys()])
|
|
831
|
-
args = tuple(prmDict.values()) * 2
|
|
824
|
+
args = tuple(prmDict.values()) * 2
|
|
832
825
|
strSql = "INSERT INTO {table} ({keystr}) VALUES ({valstr})".format(table=table,keystr=keystr,valstr=valstr)
|
|
833
826
|
strSql += "ON DUPLICATE KEY UPDATE {setstr}".format(setstr=setstr)
|
|
834
827
|
return self.execute(strSql, *args)
|
|
@@ -850,20 +843,24 @@ class dbObjConnection:
|
|
|
850
843
|
self.mySqlPing()
|
|
851
844
|
# untested
|
|
852
845
|
elif(self.dbType == "MSSQL"):
|
|
853
|
-
|
|
846
|
+
return
|
|
854
847
|
self.msSqlPing()
|
|
855
848
|
# does not work
|
|
856
849
|
elif(self.dbType == "ORACLE"):
|
|
857
|
-
|
|
850
|
+
return
|
|
858
851
|
self.oraclePing()
|
|
859
852
|
# untested
|
|
860
853
|
elif(self.dbType in ("SQLITE", "SQLITE3")):
|
|
861
|
-
|
|
854
|
+
return
|
|
862
855
|
self.sqlite3Ping()
|
|
863
856
|
# untested
|
|
864
857
|
elif(self.dbType == "PROGRESS"):
|
|
865
|
-
|
|
858
|
+
return
|
|
866
859
|
self.progressPing()
|
|
860
|
+
# untested
|
|
861
|
+
elif(self.dbType == "JDBC"):
|
|
862
|
+
return
|
|
863
|
+
self.jdbcPing()
|
|
867
864
|
|
|
868
865
|
def mySqlPing(self, reconnect=True):
|
|
869
866
|
"""
|
|
@@ -1113,6 +1110,101 @@ class dbObjConnection:
|
|
|
1113
1110
|
jdbcCursor.next()
|
|
1114
1111
|
return jdbcCursor
|
|
1115
1112
|
|
|
1113
|
+
def mySqlExecuteMany(self, prmSql, *args):
|
|
1114
|
+
# https://dev.mysql.com/doc/connector-python/en/connector-python-api-mysqlcursor-executemany.html
|
|
1115
|
+
mySqlCursor = self.getCursor()
|
|
1116
|
+
try:
|
|
1117
|
+
mySqlCursor.cursor.executemany(prmSql, *args)
|
|
1118
|
+
self.msgObj.message = "SQL Executed: "+prmSql
|
|
1119
|
+
self.msgObj.success = True
|
|
1120
|
+
mySqlCursor.numRows = mySqlCursor.cursor.rowcount
|
|
1121
|
+
self.lastInsId = self.connHandle.insert_id()
|
|
1122
|
+
except MySQLdb.OperationalError as e:
|
|
1123
|
+
self.msgObj.message += ' - OperationalError: {0}'.format(e)
|
|
1124
|
+
mySqlCursor = self.setMySqlExecuteFail(mySqlCursor, prmSql, e, *args)
|
|
1125
|
+
print(self.msgObj.message)
|
|
1126
|
+
if "server has gone away" in str(e):
|
|
1127
|
+
self.msgObj.message += ' - Lost Connection Due to timeout,'
|
|
1128
|
+
self.msgObj.message += ' innodb_log_file_size, dropped incorrect/large packet,'
|
|
1129
|
+
self.msgObj.message += ' or killed process/connection.'
|
|
1130
|
+
self.msgObj.message += ' connHandle={0}, connHandle.open={1}'.format(self.connHandle,self.connHandle.open)
|
|
1131
|
+
self.reconnect()
|
|
1132
|
+
elif self.connHandle.open==0 or "Can't connect to" in str(e):
|
|
1133
|
+
self.msgObj.message += ' - Database Connection Closed or Never Established.'
|
|
1134
|
+
self.msgObj.message += ' connHandle={0}, connHandle.open={1}'.format(self.connHandle,self.connHandle.open)
|
|
1135
|
+
self.reconnect()
|
|
1136
|
+
return mySqlCursor if not self.msgObj.success else self.mySqlExecute( prmSql, *args )
|
|
1137
|
+
except Exception as e:
|
|
1138
|
+
mySqlCursor = self.setMySqlExecuteFail(mySqlCursor, prmSql, e, *args)
|
|
1139
|
+
if self.connHandle.open==0 or "Can't connect to" in str(e):
|
|
1140
|
+
self.msgObj.message += ' - Database Connection Closed or Never Established.'
|
|
1141
|
+
self.msgObj.message += ' connHandle={0}, connHandle.open={1}'.format(self.connHandle,self.connHandle.open)
|
|
1142
|
+
self.reconnect()
|
|
1143
|
+
return mySqlCursor if not self.msgObj.success else self.mySqlExecute( prmSql, *args )
|
|
1144
|
+
print(self.msgObj.message)
|
|
1145
|
+
return mySqlCursor
|
|
1146
|
+
else:
|
|
1147
|
+
mySqlCursor = self.setMySqlExecuteSuccess(mySqlCursor, prmSql, *args)
|
|
1148
|
+
return mySqlCursor
|
|
1149
|
+
|
|
1150
|
+
def getTransactionIsolation(self):
|
|
1151
|
+
# untested
|
|
1152
|
+
if(self.dbType == "MYSQL"):
|
|
1153
|
+
return
|
|
1154
|
+
self.mySqlGetTransactionIsolation()
|
|
1155
|
+
# will not work
|
|
1156
|
+
elif(self.dbType == "MSSQL"):
|
|
1157
|
+
return
|
|
1158
|
+
self.msSqlGetTransactionIsolation()
|
|
1159
|
+
# untested
|
|
1160
|
+
elif(self.dbType == "ORACLE"):
|
|
1161
|
+
return
|
|
1162
|
+
self.oracleGetTransactionIsolation()
|
|
1163
|
+
# untested
|
|
1164
|
+
elif(self.dbType in ("SQLITE", "SQLITE3")):
|
|
1165
|
+
return
|
|
1166
|
+
self.sqlite3GetTransactionIsolation()
|
|
1167
|
+
# untested
|
|
1168
|
+
elif(self.dbType == "PROGRESS"):
|
|
1169
|
+
return
|
|
1170
|
+
self.progressGetTransactionIsolation()
|
|
1171
|
+
# untested
|
|
1172
|
+
elif(self.dbType == "JDBC"):
|
|
1173
|
+
return self.jdbcGetTransactionIsolation()
|
|
1174
|
+
|
|
1175
|
+
def setTransactionIsolation(self, lvl):
|
|
1176
|
+
# untested
|
|
1177
|
+
if(self.dbType == "MYSQL"):
|
|
1178
|
+
return
|
|
1179
|
+
self.mySqlSetTransactionIsolation(lvl)
|
|
1180
|
+
# will not work
|
|
1181
|
+
elif(self.dbType == "MSSQL"):
|
|
1182
|
+
return
|
|
1183
|
+
self.msSqlSetTransactionIsolation(lvl)
|
|
1184
|
+
# does not work
|
|
1185
|
+
elif(self.dbType == "ORACLE"):
|
|
1186
|
+
return
|
|
1187
|
+
self.oracleSetTransactionIsolation(lvl)
|
|
1188
|
+
# untested
|
|
1189
|
+
elif(self.dbType in ("SQLITE", "SQLITE3")):
|
|
1190
|
+
return
|
|
1191
|
+
self.sqlite3SetTransactionIsolation(lvl)
|
|
1192
|
+
# untested
|
|
1193
|
+
elif(self.dbType == "PROGRESS"):
|
|
1194
|
+
return
|
|
1195
|
+
self.progressSetTransactionIsolation(lvl)
|
|
1196
|
+
# untested
|
|
1197
|
+
elif(self.dbType == "JDBC"):
|
|
1198
|
+
return self.jdbcSetTransactionIsolation(lvl)
|
|
1199
|
+
|
|
1200
|
+
def jdbcGetTransactionIsolation(self):
|
|
1201
|
+
r = self.connHandle.jconn.getTransactionIsolation()
|
|
1202
|
+
return r
|
|
1203
|
+
|
|
1204
|
+
def jdbcSetTransactionIsolation(self, lvl):
|
|
1205
|
+
r = self.connHandle.jconn.setTransactionIsolation(lvl)
|
|
1206
|
+
return r
|
|
1207
|
+
|
|
1116
1208
|
def commit(self):
|
|
1117
1209
|
if(self.dbType == "MYSQL"):
|
|
1118
1210
|
self.connHandle.commit()
|
|
@@ -1164,11 +1256,11 @@ if __name__ == '__main__':
|
|
|
1164
1256
|
running_test = getInput("Run MySQL Test? ")
|
|
1165
1257
|
if running_test.lower() not in ('n','no'):
|
|
1166
1258
|
odb = dbtest()
|
|
1167
|
-
|
|
1259
|
+
|
|
1168
1260
|
print('\n')
|
|
1169
1261
|
|
|
1170
1262
|
if not odb:
|
|
1171
|
-
print( "Type run_test() to interactively test db connection")
|
|
1263
|
+
print( "Type run_test() to interactively test db connection")
|
|
1172
1264
|
else:
|
|
1173
1265
|
sqls, rset = sqltest( odb )
|
|
1174
1266
|
print( "\n - autoreconnect is True by default for MySQL, so if a connection socket error occurs (MySQL tested), it should auto reconnect" )
|
|
@@ -1196,17 +1288,17 @@ if __name__ == '__main__':
|
|
|
1196
1288
|
print( "now odb.reconnect_attempts = {0}".format(odb.reconnect_attempts) )
|
|
1197
1289
|
print( "setting odb.msgObj.message = ''" )
|
|
1198
1290
|
odb.msgObj.message = ''
|
|
1199
|
-
|
|
1291
|
+
|
|
1200
1292
|
print( "rerunning {s}".format(s=sqls) )
|
|
1201
|
-
|
|
1293
|
+
|
|
1202
1294
|
try:
|
|
1203
1295
|
sqls, rset = sqltest( odb, sqls )
|
|
1204
1296
|
except Exception as e:
|
|
1205
1297
|
print( "\nException in dbobj: {e}\n".format(e=e) )
|
|
1206
|
-
|
|
1298
|
+
|
|
1207
1299
|
print( "setting odb.autoreconnect back to True")
|
|
1208
1300
|
odb.autoreconnect = True
|
|
1209
1301
|
return odb
|
|
1210
1302
|
|
|
1211
|
-
# odb will be the interactively instantiated dbObj connection
|
|
1212
|
-
odb = run_test()
|
|
1303
|
+
# odb will be the interactively instantiated dbObj connection
|
|
1304
|
+
odb = run_test()
|
|
File without changes
|