all repos — honk @ ff16378e7e65238d2279ebb00acece7a5a71c309

my fork of honk

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