1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 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 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272
|
#author: James Henstridge <james@daa.com.au>
"""This is a class that implements an interface to mySQL databases, conforming
to the API published by the Python db-sig at
http://www.python.org/sigs/db-sig/DatabaseAPI.html
It is really just a wrapper for an older python interface to mySQL databases
called mySQL, which I modified to facilitate use of a cursor. That module was
Joseph Skinner's port of the mSQL module by David Gibson, which was a modified
version of Anthony Baxter's msql module.
As an example, to add some extra (unprivelledged) users to your database system,
and delete them again:
>>> import Mysqldb
>>> conn = Mysqldb.mysqldb('mysql@localhost root rootpasswd')
>>> curs = conn.cursor()
>>> curs.execute("insert into user (host, user) values ('%s', '%s')",
... [('localhost', 'linus'), ('somewhere.com.au', 'james')])
2
>>> curs.execute("select * from user")
>>> curs.fetchall()
-- record listing --
>>> curs.execute("delete from user where host = 'somewhere.com.au' or user = 'linus'")
2
>>> curs.close()
>>> conn.close()
The argument to mysqldb.mysqldb is of the form 'db@host user pass',
'db@host user', 'db@host', 'db', 'db user pass' or 'db user'.
As always, the source is a good manual :-)
James Henstridge <james@daa.com.au>
"""
import MySQL
from string import upper, split, join
error = 'mysqldb.error'
_type = {}
for a in ('char', 'varchar', 'string', 'unhandled', '????'):
_type[a] = 'STRING'
for a in ('tiny blob', 'medium blob', 'long blob', 'blob'):
_type[a] = 'RAW'
for a in ('short', 'long', 'float', 'double', 'decimal'):
_type[a] = 'NUMBER'
for a in ('date', 'time', 'datetime', 'timestamp'):
_type[a] = 'DATE'
del a
def isDDL(q):
return upper(split(q)[0]) in ('CREATE', 'ALTER', 'GRANT', 'REVOKE',
'DROP', 'SET')
def isDML(q):
return upper(split(q)[0]) in ('DELETE', 'INSERT', 'UPDATE', 'LOAD')
def isDQL(q):
return upper(split(q)[0]) in ('SELECT', 'SHOW', 'DESC', 'DESCRIBE')
class Connection:
"""This is the connection object for the mySQL database interface."""
def __init__(self, host, user, passwd, db):
try:
self.__conn = MySQL.connect(host, user, passwd)
self.__conn.selectdb(db)
except MySQL.error, msg:
raise error, msg
self.__curs = Cursor(self.__conn)
def __del__(self):
self.close()
def __getattr__(self, key):
return getattr(self.__curs, key)
def __setattr__(self, key, val):
if key in ('arraysize', 'description', 'insert_id'):
setattr(self.__curs, key, val)
else:
self.__dict__[key] = val
def close(self):
self.__conn = None
def cursor(self):
if self.__conn == None: raise error, "Connection is closed."
return Cursor(self.__conn)
def commit(self): pass
def rollback(self): pass
def callproc(self, params=None): pass
# These functions are just here so that every action that is
# covered by mySQL is covered by mysqldb. They are not standard
# DB API. The list* methods are not included, since they can be
# done with the SQL SHOW command.
def create(self, dbname):
"""This is not a standard part of Python DB API."""
return self.__conn.create(dbname)
def drop(self, dbname):
"""This is not a standard part of Python DB API."""
return self.__conn.drop(dbname)
def reload(self):
"""This is not a standard part of Python DB API."""
return self.__conn.reload()
def shutdown(self):
"""This is not a standard part of Python DB API."""
return self.__conn.shutdown()
class Cursor:
"""A cursor object for use with connecting to mySQL databases."""
def __init__(self, conn):
self.__conn = conn
self.__res = None
self.arraysize = 1
self.__dict__['description'] = None
self.__open = 1
self.insert_id = 0
def __del__(self):
self.close()
def __setattr__(self, key, val):
if key == 'description':
raise error, "description is a read-only attribute."
else:
self.__dict__[key] = val
def __delattr__(self, key):
if key in ('description', 'arraysize', 'insert_id'):
raise error, "%s can't be deleted." % (key,)
else:
del self.__dict__[key]
def close(self):
self.__conn = None
self.__res = None
self.__open = 0
def execute(self, op, params=None):
if not self.__open: raise error, "Cursor has been closed."
if params:
if type(params[0]) not in (type(()), type([])):
params = [params]
if isDDL(op):
self.__dict__['description'] = None
try:
for x in params:
self.__res = \
self.__conn.query(op % x)
self.insert_id = self.__res.insert_id()
except MySQL.error, msg:
raise error, msg
return 1
if isDML(op):
self.__dict__['description'] = None
af = 0
try:
for x in params:
self.__res = \
self.__conn.query(op % x)
af =af+self.__res.affectedrows()
self.insert_id = self.__res.insert_id()
except MySQL.error, msg:
raise error, msg
return af
if isDQL(op):
try:
self.__res = self.__conn.query(
op % params[-1])
self.insert_id = self.__res.insert_id()
f = self.__res.fields()
except MySQL.error, msg:
raise error, msg
self.__dict__['description'] = tuple(map(
lambda x: (x[0], _type[x[2]], x[3],
x[3]), f))
return None
else:
try:
self.__res = self.__conn.query(op)
self.insert_id = self.__res.insert_id()
except MySQL.error, msg:
raise error, msg
self.__dict__['description'] = None
if isDDL(op):
return 1
elif isDML(op):
if self.__res.affectedrows() != -1:
return self.__res.affectedrows()
else:
return 0
elif isDQL(op):
try:
f = self.__res.fields()
#print f
except MySQL.error, msg:
raise error, msg
self.__dict__['description'] = tuple(map(
lambda x: (x[0], _type[x[2]], x[3],
x[3], x[1]), f))
return None
def fetchone(self):
if not self.__res: raise error, "no query made yet."
try:
return self.__res.fetchrows(1)[0]
except MySQL.error, msg:
raise error, msg
def fetchmany(self, size=None):
if not self.__res: raise error, "no query made yet."
try:
return self.__res.fetchrows(size or self.arraysize)
except MySQL.error, msg:
raise error, msg
def fetchall(self):
if not self.__res: raise error, "no query made yet."
try:
return self.__res.fetchrows()
except MySQL.error, msg:
raise error, msg
def fetchoneDict(self):
"""This is not a standard part of Python DB API."""
if not self.__res: raise error, "no query made yet."
try:
return self.__res.fetchdict(1)[0]
except MySQL.error, msg:
raise error, msg
def fetchmanyDict(self, size=None):
"""This is not a standard part of Python DB API."""
if not self.__res: raise error, "no query made yet."
try:
return self.__res.fetchdict(size or self.arraysize)
except MySQL.error, msg:
raise error, msg
def fetchallDict(self):
"""This is not a standard part of Python DB API."""
if not self.__res: raise error, "no query made yet."
try:
return self.__res.fetchdict()
except MySQL.error, msg:
raise error, msg
def setinputsizes(self, sizes): pass
def setoutputsize(self, size, col=None): pass
def mysqldb(connect_string):
"""Makes a connection to the MySQL server. The Argument should be of
the form 'db@host user pass' or 'db@host user' or 'db@host' or 'db'
or 'db user pass' or 'db user', where db is the database name, host
is the server's host name, user is your user name, and pass is your
password."""
val = split(connect_string)
if len(val) == 0: raise error, "no database specified"
while len(val) < 3: val.append('')
dh = split(val[0], '@')
if len(dh) == 0: raise error, "no database specified"
while len(dh) < 2: dh.append('')
if dh[1] == '': dh[1] = 'localhost'
return Connection(dh[1], val[1], val[2], dh[0])
|