[Zope-CVS] CVS: Products/Ape/lib/apelib/sql - dbapi.py:1.9
interfaces.py:1.4 properties.py:1.9 security.py:1.8 sqlbase.py:1.13
Shane Hathaway
shane at zope.com
Wed Mar 24 22:17:40 EST 2004
Update of /cvs-repository/Products/Ape/lib/apelib/sql
In directory cvs.zope.org:/tmp/cvs-serv22204/lib/apelib/sql
Modified Files:
dbapi.py interfaces.py properties.py security.py sqlbase.py
Log Message:
Made multi-table properties the default.
Also removed the default "zodb_" prefix from table names and
added a MySQL example.
Incidentally, ran Zope on pure MySQL tonight. It was stable and even
seemed snappy.
=== Products/Ape/lib/apelib/sql/dbapi.py 1.8 => 1.9 ===
--- Products/Ape/lib/apelib/sql/dbapi.py:1.8 Wed Mar 24 10:52:07 2004
+++ Products/Ape/lib/apelib/sql/dbapi.py Wed Mar 24 22:17:08 2004
@@ -36,8 +36,10 @@
column_type_translations = {} # { local type name -> db type name }
column_name_translations = {} # { local col name -> db col name }
+ module = None
+ connector = None
- def __init__(self, module_name, connect_expression, prefix='zodb_'):
+ def __init__(self, module_name, connect_expression, prefix=''):
# connect_expression is a Python expression.
self.module_name = module_name
self.module = __import__(module_name, {}, {}, ('__doc__',))
@@ -110,10 +112,19 @@
table_name = self.prefix + table
dbcols = [self.translate_name(col) for col in result_columns]
where = self.generate_conditions(filter.keys())
- sql = 'SELECT %s FROM %s WHERE %s' % (
- ', '.join(dbcols), table_name, where)
+ sql = 'SELECT %s FROM %s' % (', '.join(dbcols), table_name)
+ if where:
+ sql += ' WHERE %s' % where
return self.execute(sql, filter, fetch=1)
+ def insert(self, table, columns, row):
+ """Inserts one row in the table.
+ """
+ table_name = self.prefix + table
+ kw = self.make_dict(columns, row)
+ sql = self.generate_insert(table_name, columns)
+ self.execute(sql, kw)
+
def set_one(self, table, oid, columns, row, is_new):
"""Sets one row in a table.
@@ -223,6 +234,13 @@
sql = "CREATE TABLE %s (%s)" % (table_name, ', '.join(cols))
self.execute(sql)
+ def drop_table(self, table):
+ """Drops a table.
+ """
+ table_name = self.prefix + table
+ sql = "DROP TABLE %s" % table_name
+ self.execute(sql)
+
def create_sequence(self, name, start=1):
"""Creates a sequence.
"""
@@ -388,10 +406,10 @@
'WHERE tablename = :name')
elif type_name == 'sequence':
sql = ("SELECT relname FROM pg_class "
- "WHERE relkind = 'S' and relname = :name")
+ "WHERE relkind = 'S' AND relname = :name")
else:
raise ValueError(type_name)
- rows = self.execute(sql, {'name': table_name}, fetch=1)
+ rows = self.execute(sql, {'name': table_name.lower()}, fetch=1)
return len(rows)
def list_table_names(self):
=== Products/Ape/lib/apelib/sql/interfaces.py 1.3 => 1.4 ===
--- Products/Ape/lib/apelib/sql/interfaces.py:1.3 Sat Mar 20 01:34:23 2004
+++ Products/Ape/lib/apelib/sql/interfaces.py Wed Mar 24 22:17:08 2004
@@ -17,6 +17,7 @@
"""
from Interface import Interface
+from Interface.Attribute import Attribute
class IRDBMSConnection (Interface):
"""Interface of basic RDBMS connections.
@@ -25,14 +26,18 @@
subinterfaces for complex and vendor-specific extensions.
"""
- # module = Attribute("The DB-API module")
+ module = Attribute("module", "The DB-API module")
- # connector = Attribute("The shared DB-API connection")
+ connector = Attribute("connector", "The shared DB-API connection")
def select(table, result_columns, **filter):
"""Selects rows from a table and returns column values for those rows.
"""
+ def insert(table, columns, row):
+ """Inserts one row in a table.
+ """
+
def set_one(table, oid, columns, row, is_new):
"""Sets one row in a table.
@@ -70,6 +75,10 @@
"""Creates a table.
column_defs is [(name, type, is_unique)].
+ """
+
+ def drop_table(table):
+ """Drops a table.
"""
def create_sequence(name, start=1):
=== Products/Ape/lib/apelib/sql/properties.py 1.8 => 1.9 ===
--- Products/Ape/lib/apelib/sql/properties.py:1.8 Sat Mar 20 01:34:23 2004
+++ Products/Ape/lib/apelib/sql/properties.py Wed Mar 24 22:17:08 2004
@@ -53,14 +53,6 @@
state.sort()
return tuple(state)
-######################################################################
-#
-# Experimental fixed-schema property storage.
-#
-# To enable, use SQLMultiTableProperties in place of SQLProperties.
-#
-######################################################################
-
class SQLFixedProperties (SQLGatewayBase):
"""SQL fixed-schema properties gateway.
@@ -74,16 +66,6 @@
SQLGatewayBase.__init__(self, conn_name)
- def prepare_table(self, event):
- """Creates the fixed property table without triggering an error.
- """
- # Note: event is any kind of IGatewayEvent.
- conn = self.get_connection(event)
- if not conn.exists(self.table, 'table'):
- defs = (self.oid_column_def,) + self.column_defs
- conn.create_table(self.table, defs)
-
-
def load(self, event):
conn = self.get_connection(event)
recs = conn.select(self.table, self.columns, oid=event.oid)
@@ -139,36 +121,39 @@
-class SQLMultiTableProperties:
+class SQLMultiTableProperties (SQLGatewayBase):
"""Combines fixed and variable properties.
"""
__implements__ = IGateway, IDatabaseInitializer
- schema = RowSequenceSchema()
- schema.add('id', 'string', 1)
- schema.add('type', 'string')
- schema.add('data', 'string')
+ schema = SQLProperties.schema
+
+ table = 'property_tables'
+ column_defs = (
+ ('class_name', 'string', 1),
+ ('table_name', 'string', 0),
+ )
+ oid_column_def = () # No OID column
def __init__(self, conn_name='db'):
- self.conn_name = conn_name
self.var_props = SQLProperties(conn_name=conn_name)
self.fixed_props = {} # class name -> SQLFixedProperties instance
+ SQLGatewayBase.__init__(self, conn_name)
def get_sources(self, event):
return None
def init(self, event):
+ conn = self.get_connection(event)
+ if not conn.exists(self.table, 'table'):
+ self.create(event)
self.var_props.init(event)
- conn = event.connections[self.conn_name]
if event.clear_all:
- # Clear the fixed property tables by searching for tables
- # with a special name, 'fp_*'.
- names = conn.list_table_names()
- for name in names:
- if name.startswith('fp_'):
- # This is a fixed property table. Clear it.
- conn.delete_from(name)
+ # Clear the fixed property tables.
+ recs = conn.select(self.table, ('table_name',))
+ for (name,) in recs:
+ conn.delete_from(name)
def get_columns_for_class(self, module_name, class_name):
@@ -204,22 +189,42 @@
return None
if self.fixed_props.has_key(cn):
return self.fixed_props[cn] # May be None
+
+ # Gather info about the class
pos = cn.rfind('.')
if pos < 0:
raise ValueError, "Not a qualified class name: %s" % repr(cn)
module_name = cn[:pos]
class_name = cn[pos + 1:]
- # XXX There's a major potential for conflicting table names,
- # but databases like PostgreSQL truncate table names, so
- # we shouldn't put the module name in the table name.
- table_name = 'fp_%s' % class_name
cols = self.get_columns_for_class(module_name, class_name)
if not cols:
- # No fixed properties for this class.
+ # No fixed properties exist for this class.
self.fixed_props[cn] = None
return None
+
+ # Allocate a table name
+ conn = self.get_connection(event)
+ rows = conn.select(self.table, ('table_name',), class_name=cn)
+ if rows:
+ table_name = rows[0][0]
+ else:
+ attempt = 0
+ while 1:
+ # Find an available table name.
+ if not attempt:
+ table_name = '%s_properties' % class_name
+ else:
+ table_name = '%s_%d_properties' % (class_name, attempt)
+ if not conn.exists(table_name, 'table'):
+ break
+ attempt += 1
+ conn.insert(
+ self.table, ('class_name', 'table_name'), (cn, table_name))
+
+ # Create the fixed properties and table
fp = SQLFixedProperties(self.conn_name, table_name, cols)
- fp.prepare_table(event)
+ if not conn.exists(table_name, 'table'):
+ fp.create(event)
# XXX If the transaction gets aborted, the table creation will
# be undone, but self.fixed_props won't see the change.
# Perhaps we need to reset self.fixed_props on abort.
@@ -235,7 +240,7 @@
fixed_state, fixed_hash = fp.load(event)
# Merge fixed_state and var_state, letting fixed_state
# override var_state except when the value in fixed_state is
- # NULL.
+ # None.
res = []
placement = {} # property name -> placement in results
for rec in fixed_state:
=== Products/Ape/lib/apelib/sql/security.py 1.7 => 1.8 ===
--- Products/Ape/lib/apelib/sql/security.py:1.7 Sat Mar 20 01:34:23 2004
+++ Products/Ape/lib/apelib/sql/security.py Wed Mar 24 22:17:08 2004
@@ -32,7 +32,7 @@
schema.add('username', 'string')
table = 'security'
- oid_column_def = ('oid', 'int', 0) # Don't create a primary key
+ oid_column_def = (('oid', 'int', 0),) # Don't create a primary key
def load(self, event):
conn = self.get_connection(event)
=== Products/Ape/lib/apelib/sql/sqlbase.py 1.12 => 1.13 ===
--- Products/Ape/lib/apelib/sql/sqlbase.py:1.12 Sat Mar 20 01:34:23 2004
+++ Products/Ape/lib/apelib/sql/sqlbase.py Wed Mar 24 22:17:08 2004
@@ -28,7 +28,7 @@
table = '(override this)'
schema = None # override
column_defs = None # optional override
- oid_column_def = ('oid', 'int', 1)
+ oid_column_def = (('oid', 'int', 1),)
def __init__(self, conn_name='db'):
self.conn_name = conn_name
@@ -39,6 +39,11 @@
def get_connection(self, event):
return event.connections[self.conn_name]
+ def create(self, event):
+ conn = self.get_connection(event)
+ defs = self.oid_column_def + self.column_defs
+ conn.create_table(self.table, defs)
+
def init(self, event):
conn = self.get_connection(event)
assert IRDBMSConnection.isImplementedBy(conn)
@@ -46,8 +51,7 @@
if event.clear_all:
conn.delete_from(self.table)
else:
- defs = (self.oid_column_def,) + self.column_defs
- conn.create_table(self.table, defs)
+ self.create(event)
def load(self, event):
raise NotImplementedError, "abstract method"
More information about the Zope-CVS
mailing list