DB Connection Manager now supports mxODBC, win32ODBC and PyODBC  | Moderator | | Join Date: Sep 2006 Location: Minden, Nevada, USA
Posts: 6,400
# 1
Oct 18 '07
| |
This is a work in progress (current and active).
There are some issues to resolve in supporting multiple connection types and I plan to add PySQLite to the mix. The this update is due to my suggesting the accompanying helper functions in a recent post and noticing that the ones posted here are a bit out of date. I'll post those helpers in a separate thread.
I've also been working with the following database engines:
MySQL 5.x
SQLite3
JET engine 4.0
Here is the latest dbConection container which was originally called dbServer, but I'd love suggestions for a better name: - #-----------------------------------------------------------------------------
-
# Name: SQLConMan.py ### This needs a better name ###
-
# Purpose: database connection handling. The DBServer() traps all errors and
-
# writes status to its master (which can be stdout). If an error does
-
# occure, Execute() returns None. This might be confusing since pyodbc
-
# returns None from execute() on quries that don't return a result set.
-
# It's interesting to not that db interface creator have begun add an
-
# execute() funtion to their connection objects.
-
#
-
# Author: <your name>
-
#
-
# Created: 2007/10/13
-
# RCS-ID: $Id: wxdbtools.py $
-
# Copyright: (c) 2007
-
# Licence: <your licence>
-
#-----------------------------------------------------------------------------
-
-
from time import time
-
-
## MySQL is the default db here:
-
## MySQL differs from MSSQL and SQLite regarding TRANSACTION statemets ##
-
TRANSACTIONS = ('START TRANSACTION', 'BEGIN TRANSACTION') # MySQL, SQLite & MSSQL
-
TransactionQuery = TRANSACTIONS[0]
-
## and these have a different matrix of support
-
LASTINSERTQUERIES = ('SELECT Last_Insert_Id()', 'SELECT @@IDENTITY') # MySQL & SQLite, MSSQL
-
LastInsertQuery = LASTINSERTQUERIES[0]
-
## One idea for detecting the DB type is to try each one until it works ##
-
-
PYODBC = 'pyodbc'
-
MXODBC = 'mxodbc'
-
WIN23ODBC = 'win32odbc'
-
-
class SQLConMan(object):
-
global TransactionQuery
-
def __init__(self, master):
-
self.master = master # a place to call write() on
-
self.dbConnection = None # the API 2.0 connection object
-
self.dbCursor = None # the API 2.0 cursor object
-
-
def __getattribute__(self, name):
-
"""Redirect method calls to the connection 'object'."""
-
try:
-
return object.__getattribute__(self, name)
-
except AttributeError:
-
# __getattribute__() only work for subtypes of object.
-
## return object.__getattribute__(self.dbConnection, name)
-
return eval("self.dbConnection.%s" %(name))
-
-
def Login(self, servername, username, password, autocommit=1, database="", conType=PYODBC):
-
"""Attempt to create a database login. If successful, return
-
an open connection. Otherwise, return None."""
-
global OperationalError, ProgrammingError, DatabaseError, DriverError
-
-
odbcstring = "DSN=%s;UID=%s;PWD=%s" %(servername, username, password)
-
-
if conType == PYODBC:
-
from pyodbc import connect
-
from pyodbc import OperationalError
-
from pyodbc import ProgrammingError
-
from pyodbc import DatabaseError
-
from pyodbc import Error as DriverError
-
cac = int(not autocommit)
-
try:
-
self.dbConnection = connect(odbcstring, autocommit=autocommit)
-
self.dbCursor = self.dbConnection.cursor()
-
except (DatabaseError, OperationalError, DriverError), message:
-
self.NoLogin(servername, username, message)
-
return
-
elif conType == MXODBC:
-
from mx.ODBC.Windows import Connect
-
from mx.ODBC.Windows import OperationalError
-
from mx.ODBC.Windows import ProgrammingError
-
from mx.ODBC.Windows import DatabaseError
-
from mx.ODBC.Windows import error as DriverError
-
cac = int(not autocommit)
-
try:
-
self.dbConnection = Connect(servername, user=username, password=password,
-
clear_auto_commit=cac)
-
self.dbCursor = self.dbConnection.cursor()
-
except (DatabaseError, OperationalError), message:
-
self.NoLogin(servername, username, message)
-
return
-
elif conType == WIN32ODBC:
-
import odbc
-
from dbi import opError as OperationalError
-
from dbi import progError as ProgrammingError
-
from dbi import dataError as DatabaseError
-
from odbc import OdbcError as DriverError
-
try:
-
self.dbConnection = odbc.odbc(odbcstring)
-
self.dbCursor = self.dbConnection.cursor()
-
except (DatabaseError, OperationalError), message:
-
self.NoLogin(servername, username, message)
-
return
-
-
self.master.write("%s has been logged onto %s\n" %(username, servername))
-
if database:
-
try:
-
self.dbCursor('USE %s' %database)
-
except (DatabaseError, OperationalError):
-
pass
-
return self.dbConnection
-
-
def NoLogin(self, servername, username, message):
-
self.master.write('Couldn\'t log on to the server `%s` as `%s`\n' %(servername, username))
-
self.DBError("", message)
-
-
def DBError(self, query, message):
-
"""Format the current message and display it.
-
Report the query and error to the master."""
-
self.master.write('ODBC Error: %s\n' %message)
-
## raise
-
# all raised by PyODBC from various DBs #
-
# """('42000', "[42000] [Microsoft][ODBC Microsoft Access Driver]
-
# Invalid SQL statement; expected 'DELETE', 'INSERT', 'PROCEDURE', 'SELECT', or 'UPDATE'. (-3500)")"""
-
# """ ('42S02', "[42S02] [Microsoft][ODBC Microsoft Access Driver]
-
# The Microsoft Jet database engine cannot find the input table or query 'main'.
-
# Make sure it exists and that its name is spelled correctly. (-1305)")"""
-
-
-
# """('42S02', "[42S02] [MySQL][ODBC 3.51 Driver][mysqld-5.0.22-community-max-nt]
-
# Table 'hetap_setup.main' doesn't exist (1146)")"""
-
-
# """('HY000', '[HY000] near "USE": syntax error (1) (1)')"""
-
# """('HY000', '[HY000] no such table: main (1) (1)')"""
-
-
## self.master.write('%s\nODBC Error %s #%d: %s #%d\n' %(query, message[0], message[1],
-
## message[-2].split(']')[-1], message[-1]))
-
-
def Execute(self, query, *params):
-
"""Execution method reports on the number of rows affected and duration
-
of the database query execution and catches errors. Return a reference
-
to the cursor if no error ocurred, otherwise, None."""
-
cursor = self.dbCursor
-
if cursor:
-
try:
-
now = time()
-
if params:
-
cursor.execute(query, *params)
-
else:
-
cursor.execute(query)
-
## print cursor
-
## nRows = cursor.rowcount
-
## self.master.write("%s " % query)
-
## self.master.write("%d rows affected: %.2f sec.\n" %(nRows, time() - now))
-
except (DatabaseError, OperationalError, DriverError), message:
-
self.DBError(query, message)
-
return
-
return cursor
-
-
def ExecuteScript(self, query):
-
""""""
-
for singlequery in query.split(';'):
-
if singlequery:
-
self.Execute(singlequery + ';')
-
-
def DBExists(self, database):
-
"""Return True if database exists"""
-
cursor = self.Execute("show databases")
-
if cursor:
-
rows = cursor.fetchall()
-
return (database.strip('`').lower(),) in rows
-
-
def TableExists(self, table):
-
"""Return True if database exists"""
-
cursor = self.Execute("show tables")
-
if cursor:
-
rows = cursor.fetchall()
-
return (table.strip('`').lower(),) in rows
-
-
def ConnectionIsOpen(self):
-
## """Return 1 if the connection has been established and is not closed.
-
## Return 0 if it is closed; None, if it has not been established."""
-
return self.dbConnection is not None
-
-
def CloseConnection(self):
-
"""Close the connection if it exists and is open."""
-
if self.dbConnection is not None:
-
try:
-
self.dbConnection.close()
-
self.master.write("Closed connection.\n")
-
except ProgrammingError:
-
self.master.write("Connection is already closed!\n")
-
else:
-
self.master.write("Connection does not exist!\n")
-
-
def SetMaster(self, master):
-
"""Allow the master to be reset."""
-
self.master = master
-
-
## May want to rethink these ones ##
-
-
def GetMaster(self):
-
return self.master
-
-
def GetDbConnection(self):
-
return self.dbConnection
Last edited by bartonc; Oct 18 '07 at 07:19 PM.
|  | | | | /bytes/about
We are a network of experts and professionals in IT and software development that help one another with answers to tough questions and share insights.
Get the best answers to your questions from over 226,382 network members.
|