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 = 51 // filemeta.meta
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{}) *sql.Rows {
51 var rows *sql.Rows
52 if strings.HasPrefix(s, "select") {
53 if tx != nil {
54 rows, err = tx.Query(s, args...)
55 } else {
56 rows, err = db.Query(s, args...)
57 }
58 } else {
59 if tx != nil {
60 _, err = tx.Exec(s, args...)
61 } else {
62 _, err = db.Exec(s, args...)
63 }
64 }
65 if err != nil {
66 elog.Fatalf("can't run %s: %s", s, err)
67 }
68 return rows
69 }
70 setV := func(ver int64) {
71 try("update config set value = ? where key = 'dbversion'", ver)
72 }
73
74 switch dbversion {
75 case 41:
76 tx, err := db.Begin()
77 if err != nil {
78 elog.Fatal(err)
79 }
80 rows, err := tx.Query("select honkid, noise from honks where format = 'markdown' and precis <> ''")
81 if err != nil {
82 elog.Fatal(err)
83 }
84 m := make(map[int64]string)
85 var dummy Honk
86 for rows.Next() {
87 err = rows.Scan(&dummy.ID, &dummy.Noise)
88 if err != nil {
89 elog.Fatal(err)
90 }
91 precipitate(&dummy)
92 m[dummy.ID] = dummy.Noise
93 }
94 rows.Close()
95 for id, noise := range m {
96 _, err = tx.Exec("update honks set noise = ? where honkid = ?", noise, id)
97 if err != nil {
98 elog.Fatal(err)
99 }
100 }
101 err = tx.Commit()
102 if err != nil {
103 elog.Fatal(err)
104 }
105 doordie(db, "update config set value = 42 where key = 'dbversion'")
106 fallthrough
107 case 42:
108 doordie(db, "update honks set what = 'honk', flags = flags & ~ 32 where what = 'tonk' or what = 'wonk'")
109 doordie(db, "delete from honkmeta where genus = 'wonkles' or genus = 'guesses'")
110 doordie(db, "update config set value = 43 where key = 'dbversion'")
111 fallthrough
112 case 43:
113 try("alter table honks add column plain text")
114 try("update honks set plain = ''")
115 setV(44)
116 fallthrough
117 case 44:
118 makeplain := func(noise, precis, format string) []string {
119 var plain []string
120 var filt htfilter.Filter
121 filt.WithLinks = true
122 if precis != "" {
123 t, _ := filt.TextOnly(precis)
124 plain = append(plain, t)
125 }
126 if format == "html" {
127 t, _ := filt.TextOnly(noise)
128 plain = append(plain, t)
129 } else {
130 plain = append(plain, noise)
131 }
132 return plain
133 }
134 tx, err = db.Begin()
135 if err != nil {
136 elog.Fatal(err)
137 }
138 plainmap := make(map[int64][]string)
139 rows, err := tx.Query("select honkid, noise, precis, format from honks")
140 if err != nil {
141 elog.Fatal(err)
142 }
143 for rows.Next() {
144 var honkid int64
145 var noise, precis, format string
146 err = rows.Scan(&honkid, &noise, &precis, &format)
147 if err != nil {
148 elog.Fatal(err)
149 }
150 plainmap[honkid] = makeplain(noise, precis, format)
151 }
152 rows.Close()
153 rows, err = tx.Query("select honkid, name, description from donks join filemeta on donks.fileid = filemeta.fileid")
154 if err != nil {
155 elog.Fatal(err)
156 }
157 for rows.Next() {
158 var honkid int64
159 var name, desc string
160 err = rows.Scan(&honkid, &name, &desc)
161 if err != nil {
162 elog.Fatal(err)
163 }
164 plainmap[honkid] = append(plainmap[honkid], name)
165 plainmap[honkid] = append(plainmap[honkid], desc)
166 }
167 rows.Close()
168 for honkid, plain := range plainmap {
169 try("update honks set plain = ? where honkid = ?", strings.Join(plain, " "), honkid)
170 }
171 setV(45)
172 err = tx.Commit()
173 if err != nil {
174 elog.Fatal(err)
175 }
176 tx = nil
177 fallthrough
178 case 45:
179 try("create index idx_honkswhotwo on honks(whofore) where whofore = 2")
180 setV(46)
181 fallthrough
182 case 46:
183 try("create index idx_honksforme on honks(whofore) where whofore = 1")
184 setV(47)
185 fallthrough
186 case 47:
187 rows := try("select userid, options from users where userid > 0")
188 var users []*WhatAbout
189 for rows.Next() {
190 var user WhatAbout
191 var jopt string
192 err = rows.Scan(&user.ID, &jopt)
193 if err != nil {
194 elog.Fatal(err)
195 }
196 err = unjsonify(jopt, &user.Options)
197 if err != nil {
198 elog.Fatal(err)
199 }
200 users = append(users, &user)
201 }
202 rows.Close()
203 for _, user := range users {
204 chatpubkey, chatseckey := newChatKeys()
205 user.Options.ChatPubKey = tob64(chatpubkey.key[:])
206 user.Options.ChatSecKey = tob64(chatseckey.key[:])
207 jopt, _ := jsonify(user.Options)
208 try("update users set options = ? where userid = ?", jopt, user.ID)
209 }
210 setV(48)
211 fallthrough
212 case 48:
213 try("create index idx_honksurl on honks(url)")
214 setV(49)
215 fallthrough
216 case 49:
217 try("create index idx_honksrid on honks(rid) where rid <> ''")
218 setV(50)
219 fallthrough
220 case 50:
221 try("alter table filemeta add column meta text")
222 try("update filemeta set meta = '{}'")
223 setV(51)
224 fallthrough
225 case 51:
226 try("analyze")
227 closedatabases()
228
229 default:
230 elog.Fatalf("can't upgrade unknown version %d", dbversion)
231 }
232 os.Exit(0)
233}