@@ -26,34 +26,58 @@ func migrate(db *sql.DB, log *log.Logger) error {
2626 log .Printf ("db version is %d. migrating to %d" , version , maxVersion )
2727
2828 for v := version + 1 ; v <= maxVersion ; v ++ {
29- migratefunc := migrations [v - 1 ]
30- var tx * sql.Tx
31- var err error
29+ // Migrations altering schema using a sequence of steps due to SQLite limitations.
30+ // Must come with `pragma foreign_key_check` at the end. See:
31+ // "Making Other Kinds Of Table Schema Changes"
32+ // https://www.sqlite.org/lang_altertable.html
33+ trickyAlteration := (v == 3 )
3234
3335 log .Printf ("[migration:%d] starting" , v )
34- if tx , err = db .Begin (); err != nil {
35- log .Printf ("[migration:%d] failed to start transaction" , v )
36- return err
37- }
38- if err = migratefunc (tx ); err != nil {
39- log .Printf ("[migration:%d] failed to migrate" , v )
40- tx .Rollback ()
41- return err
36+
37+ if trickyAlteration {
38+ db .Exec ("pragma foreign_keys=off;" )
4239 }
43- if _ , err = tx .Exec (fmt .Sprintf ("pragma user_version = %d" , v )); err != nil {
44- log .Printf ("[migration:%d] failed to bump version" , v )
45- tx .Rollback ()
46- return err
40+
41+ err := migrateVersion (v , db )
42+
43+ if trickyAlteration {
44+ db .Exec ("pragma foreign_keys=on;" )
4745 }
48- if err = tx . Commit (); err != nil {
49- log . Printf ( "[migration:%d] failed to commit changes" , v )
46+
47+ if err != nil {
5048 return err
5149 }
50+
5251 log .Printf ("[migration:%d] done" , v )
5352 }
5453 return nil
5554}
5655
56+ func migrateVersion (v int64 , db * sql.DB ) error {
57+ var err error
58+ var tx * sql.Tx
59+ migratefunc := migrations [v - 1 ]
60+ if tx , err = db .Begin (); err != nil {
61+ log .Printf ("[migration:%d] failed to start transaction" , v )
62+ return err
63+ }
64+ if err = migratefunc (tx ); err != nil {
65+ log .Printf ("[migration:%d] failed to migrate" , v )
66+ tx .Rollback ()
67+ return err
68+ }
69+ if _ , err = tx .Exec (fmt .Sprintf ("pragma user_version = %d" , v )); err != nil {
70+ log .Printf ("[migration:%d] failed to bump version" , v )
71+ tx .Rollback ()
72+ return err
73+ }
74+ if err = tx .Commit (); err != nil {
75+ log .Printf ("[migration:%d] failed to commit changes" , v )
76+ return err
77+ }
78+ return nil
79+ }
80+
5781func m01_initial (tx * sql.Tx ) error {
5882 sql := `
5983 create table if not exists folders (
@@ -136,10 +160,7 @@ func m02_feed_states_and_errors(tx *sql.Tx) error {
136160
137161func m03_on_delete_actions (tx * sql.Tx ) error {
138162 sql := `
139- -- 01. disable foreignkey constraint
140- pragma foreign_keys=off;
141-
142- -- 02. create altered tables
163+ -- 01. create altered tables
143164 create table if not exists new_feeds (
144165 id integer primary key autoincrement,
145166 folder_id references folders(id) on delete set null,
@@ -176,25 +197,25 @@ func m03_on_delete_actions(tx *sql.Tx) error {
176197 error string
177198 );
178199
179- -- 03 . transfer content into new tables
200+ -- 02 . transfer data into new tables
180201 insert into new_feeds select * from feeds;
181202 insert into new_items select * from items;
182203 insert into new_http_states select * from http_states;
183204 insert into new_feed_errors select * from feed_errors;
184205
185- -- 04 . drop old tables
206+ -- 03 . drop old tables
186207 drop table feeds;
187208 drop table items;
188209 drop table http_states;
189210 drop table feed_errors;
190211
191- -- 05 . rename new tables
212+ -- 04 . rename new tables
192213 alter table new_feeds rename to feeds;
193214 alter table new_items rename to items;
194215 alter table new_http_states rename to http_states;
195216 alter table new_feed_errors rename to feed_errors;
196217
197- -- 06 . reconstruct indexes & triggers
218+ -- 05 . reconstruct indexes & triggers
198219 create index if not exists idx_feed_folder_id on feeds(folder_id);
199220 create unique index if not exists idx_feed_feed_link on feeds(feed_link);
200221 create index if not exists idx_item_feed_id on items(feed_id);
@@ -205,8 +226,8 @@ func m03_on_delete_actions(tx *sql.Tx) error {
205226 delete from search where rowid = old.search_rowid;
206227 end;
207228
229+ -- 06. check consistency
208230 pragma foreign_key_check;
209- pragma foreign_keys=on;
210231 `
211232 _ , err := tx .Exec (sql )
212233 return err
0 commit comments