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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: dbobj3
3
- Version: 0.6.0
3
+ Version: 0.7.0
4
4
  Summary: High-level MySQL/MSSQL/Oracle access module
5
5
  Requires-Python: >=3.6
6
6
  Requires-Dist: pymysql
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "dbobj3"
7
- version = "0.6.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.6.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.6.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=35078, envProgress={}, driver=None):
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
- pass
846
+ return
854
847
  self.msSqlPing()
855
848
  # does not work
856
849
  elif(self.dbType == "ORACLE"):
857
- pass
850
+ return
858
851
  self.oraclePing()
859
852
  # untested
860
853
  elif(self.dbType in ("SQLITE", "SQLITE3")):
861
- pass
854
+ return
862
855
  self.sqlite3Ping()
863
856
  # untested
864
857
  elif(self.dbType == "PROGRESS"):
865
- pass
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