@@ -22,7 +22,7 @@ class SQLite3:
2222 a trigger for automated orphan removal.
2323 """
2424
25- MAX_VERSION = 3
25+ MAX_VERSION = 5
2626
2727 def __init__ (self , path , conf ):
2828
@@ -68,7 +68,7 @@ def migrate(self, to):
6868 if self .version >= to :
6969 return
7070
71- logger .info ("migrate database from version %i to %i" , self .version , to )
71+ logger .info ("Migrating database from version %i to %i" , self .version , to )
7272
7373 # re-initialize voters blob due a bug in the bloomfilter signature
7474 # which added older commenter's ip addresses to the current voters blob
@@ -78,20 +78,36 @@ def migrate(self, to):
7878 bf = memoryview (Bloomfilter (iterable = ["127.0.0.0" ]).array )
7979
8080 with sqlite3 .connect (self .path ) as con :
81- con .execute ('UPDATE comments SET voters=?' , (bf , ))
82- con .execute ('PRAGMA user_version = 1' )
83- logger .info ("%i rows changed" , con .total_changes )
81+ con .execute ("BEGIN TRANSACTION" )
82+ try :
83+ con .execute ('UPDATE comments SET voters=?' , (bf , ))
84+ con .execute ('PRAGMA user_version = 1' )
85+ con .execute ("COMMIT" )
86+ logger .info ("Migrating DB version 0 to 1 by re-initializing voters blob, %i rows changed" ,
87+ con .total_changes )
88+ except sqlite3 .Error as e :
89+ con .execute ("ROLLBACK" )
90+ logger .error ("Migrating DB version 0 to 1 failed: %s" , e )
91+ raise RuntimeError ("Migrating DB version 0 to 1 failed: %s" % e )
8492
8593 # move [general] session-key to database
8694 if self .version == 1 :
8795
8896 with sqlite3 .connect (self .path ) as con :
89- if self .conf .has_option ("general" , "session-key" ):
90- con .execute ('UPDATE preferences SET value=? WHERE key=?' , (
91- self .conf .get ("general" , "session-key" ), "session-key" ))
92-
93- con .execute ('PRAGMA user_version = 2' )
94- logger .info ("%i rows changed" , con .total_changes )
97+ con .execute ("BEGIN TRANSACTION" )
98+ try :
99+ if self .conf .has_option ("general" , "session-key" ):
100+ con .execute ('UPDATE preferences SET value=? WHERE key=?' , (
101+ self .conf .get ("general" , "session-key" ), "session-key" ))
102+
103+ con .execute ('PRAGMA user_version = 2' )
104+ con .execute ("COMMIT" )
105+ logger .info ("Migrating DB version 1 to 2 by moving session-key to database, %i rows changed" ,
106+ con .total_changes )
107+ except sqlite3 .Error as e :
108+ con .execute ("ROLLBACK" )
109+ logger .error ("Migrating DB version 1 to 2 failed: %s" , e )
110+ raise RuntimeError ("Migrating DB version 1 to 2 failed: %s" % e )
95111
96112 # limit max. nesting level to 1
97113 if self .version == 2 :
@@ -114,10 +130,76 @@ def first(rv):
114130 ids .extend (rv )
115131 flattened [id ].update (set (rv ))
116132
117- for id in flattened .keys ():
118- for n in flattened [id ]:
119- con .execute (
120- "UPDATE comments SET parent=? WHERE id=?" , (id , n ))
133+ con .execute ("BEGIN TRANSACTION" )
134+ try :
135+ for id in flattened .keys ():
136+ for n in flattened [id ]:
137+ con .execute (
138+ "UPDATE comments SET parent=? WHERE id=?" , (id , n ))
139+
140+ con .execute ('PRAGMA user_version = 3' )
141+ con .execute ("COMMIT" )
142+ logger .info ("Migrating DB version 2 to 3 by limiting nesting level to 1, %i rows changed" ,
143+ con .total_changes )
144+ except sqlite3 .Error as e :
145+ con .execute ("ROLLBACK" )
146+ logger .error ("Migrating DB version 2 to 3 failed: %s" , e )
147+ raise RuntimeError ("Migrating DB version 2 to 3 failed: %s" % e )
148+
149+ # add notification field to comments (moved from Comments class to migration)
150+ if self .version == 3 :
151+ with sqlite3 .connect (self .path ) as con :
152+ self .migrate_to_version_4 (con )
153+
154+ # "text" field in "comments" became NOT NULL
155+ if self .version == 4 :
156+ with sqlite3 .connect (self .path ) as con :
157+ con .execute ("BEGIN TRANSACTION" )
158+ con .execute ("UPDATE comments SET text = '' WHERE text IS NULL" )
159+
160+ # create new table with NOT NULL constraint for "text" field
161+ con .execute (Comments .create_table_query ("comments_new" ))
162+
163+ try :
164+ # copy data from old table to new table
165+ con .execute ("""
166+ INSERT INTO comments_new (
167+ tid, id, parent, created, modified, mode, remote_addr, text, author, email, website, likes, dislikes, voters, notification
168+ )
169+ SELECT
170+ tid, id, parent, created, modified, mode, remote_addr, text, author, email, website, likes, dislikes, voters, notification
171+ FROM comments
172+ """ )
173+
174+ # swap tables and drop old table
175+ con .execute ("ALTER TABLE comments RENAME TO comments_backup_v4" )
176+ con .execute ("ALTER TABLE comments_new RENAME TO comments" )
177+ con .execute ("DROP TABLE comments_backup_v4" )
178+
179+ con .execute ('PRAGMA user_version = 5' )
180+ con .execute ("COMMIT" )
181+ logger .info ("Migrating DB version 4 to 5 by setting empty comments.text to '', %i rows changed" ,
182+ con .total_changes )
183+ except sqlite3 .Error as e :
184+ con .execute ("ROLLBACK" )
185+ logger .error ("Migrating DB version 4 to 5 failed: %s" , e )
186+ raise RuntimeError ("Migrating DB version 4 to 5 failed: %s" % e )
187+
188+ def migrate_to_version_4 (self , con ):
189+ # check if "notification" column exists in "comments" table
190+ rv = con .execute ("PRAGMA table_info(comments)" ).fetchall ()
191+ if any ([row [1 ] == 'notification' for row in rv ]):
192+ logger .info ("Migrating DB version 3 to 4 skipped, 'notification' field already exists in comments" )
193+ con .execute ('PRAGMA user_version = 4' )
194+ return
121195
122- con .execute ('PRAGMA user_version = 3' )
123- logger .info ("%i rows changed" , con .total_changes )
196+ con .execute ("BEGIN TRANSACTION" )
197+ try :
198+ con .execute ('ALTER TABLE comments ADD COLUMN notification INTEGER DEFAULT 0;' )
199+ con .execute ('PRAGMA user_version = 4' )
200+ con .execute ("COMMIT" )
201+ logger .info ("Migrating DB version 3 to 4 by adding 'notification' field to comments" )
202+ except sqlite3 .Error as e :
203+ con .execute ("ROLLBACK" )
204+ logger .error ("Migrating DB version 3 to 4 failed: %s" , e )
205+ raise RuntimeError ("Migrating DB version 3 to 4 failed: %s" % e )
0 commit comments