Code

*** empty log message ***
authorrichard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2>
Fri, 5 Mar 2004 00:08:09 +0000 (00:08 +0000)
committerrichard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2>
Fri, 5 Mar 2004 00:08:09 +0000 (00:08 +0000)
git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/trunk@2143 57a73879-2fb5-44c3-a270-3262357dd7e2

CHANGES.txt
roundup/backends/back_mysql.py
roundup/backends/back_postgresql.py
roundup/backends/back_sqlite.py
roundup/backends/rdbms_common.py
roundup/rcsv.py
roundup/roundupdb.py

index 4348098f3ef4b54cbe6675dbd04c1402d5c8d4d4..4152d2f9b1d977ccba16b6cb0117713e836d8785 100644 (file)
@@ -13,9 +13,6 @@ Feature:
 - all RDBMS backends now have indexes on several columns
 - change nosymessage and send_message to accept msgid=None (RFE #707235).
 - handle Resent-From: headers (sf bug 841151)
-- existing trackers (ie. live ones) may be used as templates for new
-  trackers - the TEMPLATE-INFO.txt name entry has the tracker's dir name
-  appended (so the demo tracker's template name is "classic-demo")
 - always sort MultilinkHTMLProperty in the correct order, usually
   alphabetically (sf feature 790512).
 - added script for copying user(s) from tracker to tracker (sf patch
@@ -74,8 +71,16 @@ Cleanup:
   * form_parser.py - parsePropsFromForm & extractFormList in a FormParser class
 
 
-2004-??-?? 0.6.7
+2004-??-?? 0.6.8
+Fixed:
+- existing trackers (ie. live ones) may be used as templates for new
+  trackers - the TEMPLATE-INFO.txt name entry has the tracker's dir name
+  appended (so the demo tracker's template name is "classic-demo")
+
+
+2004-03-01 0.6.7
 Fixed:
+- be more backward-compatible when asking for EMAIL_CHARSET
 - made error on create consistent with edit when user enters invalid data
   for Multilink and Link form fields (sf bug 904072)
 - made errors from bad input in the quick "Show issue:" form more
index 8d8ea34af8fee75838dc0653f9365d0902db6740..c9ebfd69ad92f57e99dc17d2ec5ab8fb2a5c82b9 100644 (file)
@@ -68,7 +68,7 @@ class Database(Database):
         self.sql("SET AUTOCOMMIT=0")
         self.sql("BEGIN")
         try:
-            self.database_schema = self.load_dbschema()
+            self.load_dbschema()
         except MySQLdb.OperationalError, message:
             if message[0] != ER.NO_DB_ERROR:
                 raise
@@ -82,7 +82,16 @@ class Database(Database):
             #       http://www.mysql.com/doc/en/CREATE_TABLE.html
             self.sql("CREATE TABLE ids (name varchar(255), num INT) TYPE=%s"%
                 self.mysql_backend)
-            self.sql("CREATE INDEX ids_name_idx on ids(name)")
+            self.sql("CREATE INDEX ids_name_idx ON ids(name)")
+            self.create_version_2_tables()
+
+    def create_version_2_tables(self):
+        self.cursor.execute('CREATE TABLE otks (key VARCHAR(255), '
+            'value VARCHAR(255), __time FLOAT(20))')
+        self.cursor.execute('CREATE INDEX otks_key_idx ON otks(key)')
+        self.cursor.execute('CREATE TABLE sessions (key VARCHAR(255), '
+            'last_use FLOAT(20), user VARCHAR(255))')
+        self.cursor.execute('CREATE INDEX sessions_key_idx ON sessions(key)')
 
     def __repr__(self):
         return '<myroundsql 0x%x>'%id(self)
@@ -104,13 +113,6 @@ class Database(Database):
         s = repr(self.database_schema)
         self.sql('INSERT INTO schema VALUES (%s)', (s,))
     
-    def load_dbschema(self):
-        self.cursor.execute('SELECT schema FROM schema')
-        schema = self.cursor.fetchone()
-        if schema:
-            return eval(schema[0])
-        return None
-
     def save_journal(self, classname, cols, nodeid, journaldate,
                 journaltag, action, params):
         params = repr(params)
index 13f2e2f04c1c38c0a0eda7e55b380956772b05ce..147cb83f1b6960298f1bd58301ec0edcdc9fb83a 100644 (file)
@@ -27,12 +27,22 @@ class Database(rdbms_common.Database):
         self.cursor = self.conn.cursor()
 
         try:
-            self.database_schema = self.load_dbschema()
+            self.load_dbschema()
         except:
             self.rollback()
             self.database_schema = {}
             self.sql("CREATE TABLE schema (schema TEXT)")
             self.sql("CREATE TABLE ids (name VARCHAR(255), num INT4)")
+            self.sql("CREATE INDEX ids_name_idx ON ids(name)")
+            self.create_version_2_tables()
+
+    def create_version_2_tables(self):
+        self.cursor.execute('CREATE TABLE otks (key VARCHAR(255), '
+            'value VARCHAR(255), __time NUMERIC)')
+        self.cursor.execute('CREATE INDEX otks_key_idx ON otks(key)')
+        self.cursor.execute('CREATE TABLE sessions (key VARCHAR(255), '
+            'last_use NUMERIC, user VARCHAR(255))')
+        self.cursor.execute('CREATE INDEX sessions_key_idx ON sessions(key)')
 
     def __repr__(self):
         return '<roundpsycopgsql 0x%x>' % id(self)
index c17235dc75bf2a720b5eaf96b9887c186b0696ff..6d28cea8d53d32bedc76ed5bc104ee9cb806bdd3 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: back_sqlite.py,v 1.13 2004-02-11 23:55:09 richard Exp $
+# $Id: back_sqlite.py,v 1.14 2004-03-05 00:08:09 richard Exp $
 '''Implements a backend for SQLite.
 
 See https://pysqlite.sourceforge.net/ for pysqlite info
@@ -30,7 +30,7 @@ class Database(rdbms_common.Database):
         self.conn = sqlite.connect(db=db)
         self.cursor = self.conn.cursor()
         try:
-            self.database_schema = self.load_dbschema()
+            self.load_dbschema()
         except sqlite.DatabaseError, error:
             if str(error) != 'no such table: schema':
                 raise
@@ -38,6 +38,15 @@ class Database(rdbms_common.Database):
             self.cursor.execute('create table schema (schema varchar)')
             self.cursor.execute('create table ids (name varchar, num integer)')
             self.cursor.execute('create index ids_name_idx on ids(name)')
+            self.create_version_2_tables()
+
+    def create_version_2_tables(self):
+        self.cursor.execute('create table otks (key varchar, '
+            'value varchar, __time varchar)')
+        self.cursor.execute('create index otks_key_idx on otks(key)')
+        self.cursor.execute('create table sessions (key varchar, '
+            'last_use varchar, user varchar)')
+        self.cursor.execute('create index sessions_key_idx on sessions(key)')
 
     def sql_close(self):
         ''' Squash any error caused by us already having closed the
index e7d141c64c516dbfb1b49cb5c05b374140bdbf57..16392c68aba7f229095fb0044a34bb525f5a0c03 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: rdbms_common.py,v 1.75 2004-02-11 23:55:09 richard Exp $
+# $Id: rdbms_common.py,v 1.76 2004-03-05 00:08:09 richard Exp $
 ''' Relational database (SQL) backend common code.
 
 Basics:
@@ -19,6 +19,12 @@ sql_* methods, since everything else should be fairly generic. There's
 probably a bit of work to be done if a database is used that actually
 honors column typing, since the initial databases don't (sqlite stores
 everything as a string.)
+
+The schema of the hyperdb being mapped to the database is stored in the
+database itself as a repr()'ed dictionary of information about each Class
+that maps to a table. If that information differs from the hyperdb schema,
+then we update it. We also store in the schema dict a __version__ which
+allows us to upgrade the database schema when necessary. See upgrade_db().
 '''
 __docformat__ = 'restructuredtext'
 
@@ -77,7 +83,9 @@ class Database(FileStorage, hyperdb.Database, roundupdb.Database):
         self.cache_lru = []
 
     def sql_open_connection(self):
-        ''' Open a connection to the database, creating it if necessary
+        ''' Open a connection to the database, creating it if necessary.
+
+            Must call self.load_dbschema()
         '''
         raise NotImplemented
 
@@ -106,24 +114,26 @@ class Database(FileStorage, hyperdb.Database, roundupdb.Database):
         '''
         return re.sub("'", "''", str(value))
 
+    def load_dbschema(self):
+        ''' Load the schema definition that the database currently implements
+        '''
+        self.cursor.execute('select schema from schema')
+        self.database_schema = eval(self.cursor.fetchone()[0])
+
     def save_dbschema(self, schema):
         ''' Save the schema definition that the database currently implements
         '''
         s = repr(self.database_schema)
         self.sql('insert into schema values (%s)', (s,))
 
-    def load_dbschema(self):
-        ''' Load the schema definition that the database currently implements
-        '''
-        self.cursor.execute('select schema from schema')
-        return eval(self.cursor.fetchone()[0])
-
     def post_init(self):
         ''' Called once the schema initialisation has finished.
 
             We should now confirm that the schema defined by our "classes"
             attribute actually matches the schema in the database.
         '''
+        self.upgrade_db()
+
         # now detect changes in the schema
         save = 0
         for classname, spec in self.classes.items():
@@ -155,6 +165,21 @@ class Database(FileStorage, hyperdb.Database, roundupdb.Database):
         # commit
         self.conn.commit()
 
+    # update this number when we need to make changes to the SQL structure
+    # of the backen database
+    current_db_version = 2
+    def upgrade_db(self):
+        ''' Update the SQL database to reflect changes in the backend code.
+        '''
+        version = self.database_schema.get('__version', 1)
+        if version == 1:
+            # version 1 doesn't have the OTK, session and indexing in the
+            # database
+            self.create_version_2_tables()
+
+        self.database_schema['__version'] = self.current_db_version
+
+
     def refresh_database(self):
         self.post_init()
 
index 91a8125dc7a2482ee75871823307945ea470cef7..08798d028a0d05602c46af28e0c0193b453faebd 100644 (file)
@@ -5,12 +5,10 @@ __docformat__ = 'restructuredtext'
 
 from roundup.i18n import _
 from cStringIO import StringIO
-error = """Sorry, you need a module compatible with the csv module.
-Either upgrade your Python to 2.3 or later, or get and install
-the csv module from:
+error = """
+Sorry, you need a csv module. Either upgrade your Python to 2.3 or later,
+or get and install the csv module from:
 http://www.object-craft.com.au/projects/csv/
-
-These two csv modules are different but Roundup can use either.
 """
 try:
     import csv
index ddaf4dd2979b3ca4a3b0770a38213e600648a0d8..0a39ee3116f12d9cbf418ca7c45c3dbfdc1fc995 100644 (file)
@@ -15,7 +15,7 @@
 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 # 
-# $Id: roundupdb.py,v 1.99 2004-02-29 00:35:55 richard Exp $
+# $Id: roundupdb.py,v 1.100 2004-03-05 00:08:09 richard Exp $
 
 """Extending hyperdb with types specific to issue-tracking.
 """
@@ -149,14 +149,14 @@ class IssueClass:
             if address:
                 sendto.append(address)
                 recipients.append(userid)
-        
+
         def good_recipient(userid):
             # Make sure we don't send mail to either the anonymous
             # user or a user who has already seen the message.
             return (userid and
                     (self.db.user.get(userid, 'username') != 'anonymous') and
                     not seen_message.has_key(userid))
-        
+
         # possibly send the message to the author, as long as they aren't
         # anonymous
         if (good_recipient(authid) and