upgradedb.go (view raw)
1//
2// Copyright (c) 2019 Ted Unangst <tedu@tedunangst.com>
3//
4// Permission to use, copy, modify, and distribute this software for any
5// purpose with or without fee is hereby granted, provided that the above
6// copyright notice and this permission notice appear in all copies.
7//
8// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15
16package main
17
18import (
19 "database/sql"
20 "os"
21 "strings"
22
23 "humungus.tedunangst.com/r/webs/htfilter"
24)
25
26var myVersion = 47 // idx forme
27
28type dbexecer interface {
29 Exec(query string, args ...interface{}) (sql.Result, error)
30}
31
32func doordie(db dbexecer, s string, args ...interface{}) {
33 _, err := db.Exec(s, args...)
34 if err != nil {
35 elog.Fatalf("can't run %s: %s", s, err)
36 }
37}
38
39func upgradedb() {
40 db := opendatabase()
41 dbversion := 0
42 getconfig("dbversion", &dbversion)
43 getconfig("servername", &serverName)
44
45 if dbversion < 40 {
46 elog.Fatal("database is too old to upgrade")
47 }
48 var err error
49 var tx *sql.Tx
50 try := func(s string, args ...interface{}) {
51 if tx != nil {
52 _, err = tx.Exec(s, args...)
53 } else {
54 _, err = db.Exec(s, args...)
55 }
56 if err != nil {
57 elog.Fatalf("can't run %s: %s", s, err)
58 }
59 }
60 setV := func(ver int64) {
61 try("update config set value = ? where key = 'dbversion'", ver)
62 }
63
64 switch dbversion {
65 case 40:
66 doordie(db, "PRAGMA journal_mode=WAL")
67 blobdb := openblobdb()
68 doordie(blobdb, "PRAGMA journal_mode=WAL")
69 doordie(db, "update config set value = 41 where key = 'dbversion'")
70 fallthrough
71 case 41:
72 tx, err := db.Begin()
73 if err != nil {
74 elog.Fatal(err)
75 }
76 rows, err := tx.Query("select honkid, noise from honks where format = 'markdown' and precis <> ''")
77 if err != nil {
78 elog.Fatal(err)
79 }
80 m := make(map[int64]string)
81 var dummy Honk
82 for rows.Next() {
83 err = rows.Scan(&dummy.ID, &dummy.Noise)
84 if err != nil {
85 elog.Fatal(err)
86 }
87 precipitate(&dummy)
88 m[dummy.ID] = dummy.Noise
89 }
90 rows.Close()
91 for id, noise := range m {
92 _, err = tx.Exec("update honks set noise = ? where honkid = ?", noise, id)
93 if err != nil {
94 elog.Fatal(err)
95 }
96 }
97 err = tx.Commit()
98 if err != nil {
99 elog.Fatal(err)
100 }
101 doordie(db, "update config set value = 42 where key = 'dbversion'")
102 fallthrough
103 case 42:
104 doordie(db, "update honks set what = 'honk', flags = flags & ~ 32 where what = 'tonk' or what = 'wonk'")
105 doordie(db, "delete from honkmeta where genus = 'wonkles' or genus = 'guesses'")
106 doordie(db, "update config set value = 43 where key = 'dbversion'")
107 fallthrough
108 case 43:
109 try("alter table honks add column plain text")
110 try("update honks set plain = ''")
111 setV(44)
112 fallthrough
113 case 44:
114 makeplain := func(noise, precis, format string) []string {
115 var plain []string
116 var filt htfilter.Filter
117 filt.WithLinks = true
118 if precis != "" {
119 t, _ := filt.TextOnly(precis)
120 plain = append(plain, t)
121 }
122 if format == "html" {
123 t, _ := filt.TextOnly(noise)
124 plain = append(plain, t)
125 } else {
126 plain = append(plain, noise)
127 }
128 return plain
129 }
130 tx, err = db.Begin()
131 if err != nil {
132 elog.Fatal(err)
133 }
134 plainmap := make(map[int64][]string)
135 rows, err := tx.Query("select honkid, noise, precis, format from honks")
136 if err != nil {
137 elog.Fatal(err)
138 }
139 for rows.Next() {
140 var honkid int64
141 var noise, precis, format string
142 err = rows.Scan(&honkid, &noise, &precis, &format)
143 if err != nil {
144 elog.Fatal(err)
145 }
146 plainmap[honkid] = makeplain(noise, precis, format)
147 }
148 rows.Close()
149 rows, err = tx.Query("select honkid, name, description from donks join filemeta on donks.fileid = filemeta.fileid")
150 if err != nil {
151 elog.Fatal(err)
152 }
153 for rows.Next() {
154 var honkid int64
155 var name, desc string
156 err = rows.Scan(&honkid, &name, &desc)
157 if err != nil {
158 elog.Fatal(err)
159 }
160 plainmap[honkid] = append(plainmap[honkid], name)
161 plainmap[honkid] = append(plainmap[honkid], desc)
162 }
163 rows.Close()
164 for honkid, plain := range plainmap {
165 try("update honks set plain = ? where honkid = ?", strings.Join(plain, " "), honkid)
166 }
167 setV(45)
168 err = tx.Commit()
169 if err != nil {
170 elog.Fatal(err)
171 }
172 tx = nil
173 fallthrough
174 case 45:
175 try("create index idx_honkswhotwo on honks(whofore) where whofore = 2")
176 setV(46)
177 fallthrough
178 case 46:
179 try("create index idx_honksforme on honks(whofore) where whofore = 1")
180 setV(47)
181 fallthrough
182 case 47:
183 try("analyze")
184
185 default:
186 elog.Fatalf("can't upgrade unknown version %d", dbversion)
187 }
188 os.Exit(0)
189}