[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