Code

- small performance optimisation for 'get': do common case first
[roundup.git] / roundup / backends / rdbms_common.py
index 9c7d7219f26cddd5fae6e8e39831ac0e8bbdcdf7..3ba789897e29cc8a92ce354fec182c09e25e0a52 100644 (file)
@@ -52,7 +52,7 @@ the same name.
 __docformat__ = 'restructuredtext'
 
 # standard python modules
-import sys, os, time, re, errno, weakref, copy, logging
+import sys, os, time, re, errno, weakref, copy, logging, datetime
 
 # roundup modules
 from roundup import hyperdb, date, password, roundupdb, security, support
@@ -62,6 +62,7 @@ from roundup.backends import locking
 from roundup.support import reversed
 from roundup.i18n import _
 
+
 # support
 from roundup.backends.blobfiles import FileStorage
 try:
@@ -90,6 +91,13 @@ def _bool_cvt(value):
     # assume it's a number returned from the db API
     return int(value)
 
+def date_to_hyperdb_value(d):
+    """ convert date d to a roundup date """
+    if isinstance (d, datetime.datetime):
+        return date.Date(d)
+    return date.Date (str(d).replace(' ', '.'))
+
+
 def connection_dict(config, dbnamestr=None):
     """ Used by Postgresql and MySQL to detemine the keyword args for
     opening the database connection."""
@@ -505,6 +513,9 @@ class Database(FileStorage, hyperdb.Database, roundupdb.Database):
             # no changes
             return 0
 
+        if not self.config.RDBMS_ALLOW_ALTER:
+            raise DatabaseError(_('ALTER operation disallowed: %r -> %r.'%(old_spec, new_spec)))
+
         logger = logging.getLogger('roundup.hyperdb')
         logger.info('update_class %s'%spec.classname)
 
@@ -729,6 +740,10 @@ class Database(FileStorage, hyperdb.Database, roundupdb.Database):
     def create_class(self, spec):
         """ Create a database table according to the given spec.
         """
+
+        if not self.config.RDBMS_ALLOW_CREATE:
+            raise DatabaseError(_('CREATE operation disallowed: "%s".'%spec.classname))
+
         cols, mls = self.create_class_table(spec)
         self.create_journal_table(spec)
 
@@ -741,6 +756,10 @@ class Database(FileStorage, hyperdb.Database, roundupdb.Database):
 
             Drop the journal and multilink tables too.
         """
+
+        if not self.config.RDBMS_ALLOW_DROP:
+            raise DatabaseError(_('DROP operation disallowed: "%s".'%cn))
+
         properties = spec[1]
         # figure the multilinks
         mls = []
@@ -1039,7 +1058,7 @@ class Database(FileStorage, hyperdb.Database, roundupdb.Database):
 
     sql_to_hyperdb_value = {
         hyperdb.String : str,
-        hyperdb.Date   : lambda x:date.Date(str(x).replace(' ', '.')),
+        hyperdb.Date   : date_to_hyperdb_value,
 #        hyperdb.Link   : int,      # XXX numeric ids
         hyperdb.Link   : str,
         hyperdb.Interval  : date.Interval,
@@ -1598,27 +1617,23 @@ class Class(hyperdb.Class):
 
         # get the node's dict
         d = self.db.getnode(self.classname, nodeid)
-
-        if propname == 'creation':
-            if 'creation' in d:
-                return d['creation']
-            else:
-                return date.Date()
-        if propname == 'activity':
-            if 'activity' in d:
-                return d['activity']
-            else:
-                return date.Date()
-        if propname == 'creator':
-            if 'creator' in d:
-                return d['creator']
-            else:
-                return self.db.getuid()
-        if propname == 'actor':
-            if 'actor' in d:
-                return d['actor']
-            else:
-                return self.db.getuid()
+        # handle common case -- that property is in dict -- first
+        # if None and one of creator/creation actor/activity return None
+        if propname in d:
+            r = d [propname]
+            # return copy of our list
+            if isinstance (r, list):
+                return r[:]
+            if r is not None:
+                return r
+            elif propname in ('creation', 'activity', 'creator', 'actor'):
+                return r
+
+        # propname not in d:
+        if propname == 'creation' or propname == 'activity':
+            return date.Date()
+        if propname == 'creator' or propname == 'actor':
+            return self.db.getuid()
 
         # get the property (raises KeyError if invalid)
         prop = self.properties[propname]
@@ -2660,6 +2675,7 @@ class Class(hyperdb.Class):
                 name = p.name
                 assert (name)
                 classes[key][name] = p
+                p.to_hyperdb = self.db.to_hyperdb_value(p.propclass.__class__)
         while True:
             row = cursor.fetchone()
             if not row: break
@@ -2674,8 +2690,7 @@ class Class(hyperdb.Class):
                 for propname, p in pt.iteritems():
                     value = row[p.sql_idx]
                     if value is not None:
-                        cls = p.propclass.__class__
-                        value = self.db.to_hyperdb_value(cls)(value)
+                        value = p.to_hyperdb(value)
                     node[propname] = value
                 self.db._cache_save(key, node)
             yield str(row[0])