[Zope-CVS] CVS: Products/Ape/lib/apelib/sql - dbapi.py:1.1 keygen.py:1.3 querygen.py:1.2 pg.py:NONE
Shane Hathaway
shane@zope.com
Sat, 12 Apr 2003 16:56:57 -0400
Update of /cvs-repository/Products/Ape/lib/apelib/sql
In directory cvs.zope.org:/tmp/cvs-serv28924/lib/apelib/sql
Modified Files:
keygen.py querygen.py
Added Files:
dbapi.py
Removed Files:
pg.py
Log Message:
Implemented support for MySQL 4.0, this time for real. The change required
further abstraction of the query generator. Supporting more databases
should now be straightforward.
=== Added File Products/Ape/lib/apelib/sql/dbapi.py ===
##############################################################################
#
# Copyright (c) 2003 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""DB-API to Ape gateway connectivity
$Id: dbapi.py,v 1.1 2003/04/12 20:56:26 shane Exp $
"""
import os
from time import time
from types import StringType
from apelib.core.interfaces import ITPCConnection
from querygen import makeQueryGenerator
DEBUG = os.environ.get('APE_DEBUG_SQL')
PROFILE = os.environ.get('APE_PROFILE_SQL')
class DBAPIConnector:
__implements__ = ITPCConnection
_final = 0
db = None
cursor = None
def __init__(self, module_name, params=(), kwparams='', prefix='zodb'):
self.module_name = module_name
self.module = __import__(module_name, {}, {}, ('__doc__',))
self.error = self.module.DatabaseError
self.prefix = prefix
self.connect_callbacks = []
if isinstance(kwparams, StringType):
# Convert the keyword string to a dictionary.
kw = {}
for p in kwparams.split():
k, v = p.split(':')
kw[k.strip()] = v.strip()
kwparams = kw
self.kwparams = kwparams
if isinstance(params, StringType):
params = (params,)
self.params = params
def makeQueryGenerator(self, table_name, column_defs):
return makeQueryGenerator(self.module_name, table_name, column_defs)
def isConnected(self):
return (self.db is not None)
def addConnectCallback(self, f):
self.connect_callbacks.append(f)
def connect(self):
if self.kwparams:
self.db = self.module.connect(*self.params, **self.kwparams)
else:
self.db = self.module.connect(*self.params)
self.cursor = self.db.cursor()
for f in self.connect_callbacks:
f()
self.connect_callbacks = []
def sortKey(self):
return repr(self)
def getName(self):
return repr(self)
def execute(self, query, fetch=0, cursor=None, **kw):
if cursor is None:
cursor = self.cursor
if cursor is None:
raise RuntimeError('Not connected')
if DEBUG or PROFILE:
if kw:
print 'Query: %s, %s' % (repr(query), kw)
else:
print 'Query: %s' % repr(query)
if PROFILE:
start = time()
cursor.execute(query, kw)
end = time()
print 'Query time: %0.6fs' % (end - start)
else:
cursor.execute(query, kw)
if fetch:
res = list(cursor.fetchall())
if DEBUG:
print 'Query result: %s' % repr(res)
return res
return None
def asBinary(self, data):
return self.module.Binary(data)
def begin(self):
pass
def vote(self):
self._final = 1
def reset(self):
self._final = 0
def abort(self):
try:
self.db.rollback()
finally:
self.reset()
def finish(self):
if self._final:
try:
self.db.commit()
finally:
self.reset()
def close(self):
if self.isConnected():
self.cursor.close()
self.cursor = None
self.db.close()
self.db = None
=== Products/Ape/lib/apelib/sql/keygen.py 1.2 => 1.3 ===
--- Products/Ape/lib/apelib/sql/keygen.py:1.2 Fri Apr 11 02:17:49 2003
+++ Products/Ape/lib/apelib/sql/keygen.py Sat Apr 12 16:56:26 2003
@@ -31,6 +31,21 @@
gen = self.conn.makeQueryGenerator(self.table, ())
self.queries = gen.generateAllForSequence()
+ def setUpTables(self):
+ conn = self.conn
+ insert = 0
+ try:
+ rows = self.execute('check', 1)
+ if len(rows) != 1:
+ insert = 1
+ except conn.error:
+ conn.db.rollback()
+ self.execute('create')
+ insert = 1
+ if insert and self.queries.get('insert'):
+ self.execute('insert')
+ conn.db.commit()
+
def makeKeychain(self, event, name, stored):
if not stored:
raise RuntimeError(
@@ -39,6 +54,8 @@
# Request that the other side do the work (for ZEO)
n = event.getKeyedObjectSystem().newKey()
else:
+ if self.queries.get('update'):
+ self.execute('update')
n = self.execute('read', 1)[0][0]
return event.getKeychain()[:-1] + (long(n),)
=== Products/Ape/lib/apelib/sql/querygen.py 1.1 => 1.2 ===
--- Products/Ape/lib/apelib/sql/querygen.py:1.1 Fri Apr 11 02:17:49 2003
+++ Products/Ape/lib/apelib/sql/querygen.py Sat Apr 12 16:56:26 2003
@@ -16,16 +16,24 @@
$Id$
"""
-class QueryGenerator:
+query_generator_factories = {}
- db_column_types = {
- 'int': 'int',
- 'long': 'bigint',
- 'string': 'character varying(255)',
- 'blob': 'bytea',
- }
+def addFactory(name, f):
+ if query_generator_factories.has_key(name):
+ raise KeyError("Factory name %s conflicts" % repr(name))
+ query_generator_factories[name] = f
- db_column_names = {}
+def makeQueryGenerator(name, table_name, column_defs):
+ f = query_generator_factories.get(name)
+ if f is None:
+ raise KeyError("No query generator registered for %s" % repr(name))
+ return f(table_name, column_defs)
+
+
+class AbstractQueryGenerator:
+
+ column_type_translations = None # { local type name -> db type name }
+ column_name_translations = None # { local col name -> db col name }
key_column = ('key', 'int', 1)
@@ -39,14 +47,14 @@
Defaults to no translation.
"""
- return self.db_column_names.get(column_name, column_name)
+ return self.column_name_translations.get(column_name, column_name)
def translateType(self, column_type):
"""Returns a database type for a variable type.
If the type is unknown, raises KeyError.
"""
- return self.db_column_types[column_type]
+ return self.column_type_translations[column_type]
def generateAll(self):
@@ -131,7 +139,7 @@
def generateClear(self):
return 'DELETE FROM %s' % self.table_name
-
+
def generateAllForSequence(self):
table_name = self.table_name
@@ -142,3 +150,47 @@
'clear': "SELECT setval('%s', 1)" % table_name,
}
return res
+
+
+class PostgreSQLQueryGenerator (AbstractQueryGenerator):
+
+ column_type_translations = {
+ 'int': 'int',
+ 'long': 'bigint',
+ 'string': 'character varying(255)',
+ 'blob': 'bytea',
+ }
+
+ column_name_translations = {}
+
+addFactory('psycopg', PostgreSQLQueryGenerator)
+
+
+class MySQLQueryGenerator (AbstractQueryGenerator):
+
+ column_type_translations = {
+ 'int': 'int',
+ 'long': 'bigint',
+ 'string': 'character varying(255)',
+ 'blob': 'longblob',
+ }
+
+ column_name_translations = {
+ 'key': 'objkey',
+ }
+
+ def generateAllForSequence(self):
+ table_name = self.table_name
+ res = {
+ 'check': "SELECT last_value FROM %s" % table_name,
+ 'create': "CREATE TABLE %s (last_value int)" % table_name,
+ 'insert': "INSERT INTO %s VALUES (0)" % table_name,
+ 'update': ("UPDATE %s SET last_value=LAST_INSERT_ID(last_value+1)"
+ % table_name),
+ 'read': "SELECT LAST_INSERT_ID()",
+ 'clear': "UPDATE %s SET last_value=0" % table_name,
+ }
+ return res
+
+addFactory('MySQLdb', MySQLQueryGenerator)
+
=== Removed File Products/Ape/lib/apelib/sql/pg.py ===