From 29dba59574b45e7dad37e387073cbf1f11688268 Mon Sep 17 00:00:00 2001 From: Jan-Lukas Else Date: Sat, 29 May 2021 13:32:00 +0200 Subject: [PATCH] Improve database usage --- activityPub.go | 8 +-- blogstats.go | 8 +-- comments.go | 10 ++-- database.go | 111 ++++++++++++++++++++++---------------- databaseMigrations.go | 9 +--- indieAuthServer.go | 12 ++--- notifications.go | 8 +-- persistentCache.go | 6 +-- postAliases.go | 4 +- postsDb.go | 103 +++++++++++++---------------------- queue.go | 8 +-- sessions.go | 10 ++-- shortPath.go | 6 +-- webmention.go | 10 ++-- webmentionVerification.go | 6 +-- 15 files changed, 152 insertions(+), 167 deletions(-) diff --git a/activityPub.go b/activityPub.go index 909acfa..1612be5 100644 --- a/activityPub.go +++ b/activityPub.go @@ -278,7 +278,7 @@ func apGetRemoteActor(iri string) (*asPerson, int, error) { } func apGetAllInboxes(blog string) ([]string, error) { - rows, err := appDbQuery("select distinct inbox from activitypub_followers where blog = @blog", sql.Named("blog", blog)) + rows, err := appDb.query("select distinct inbox from activitypub_followers where blog = @blog", sql.Named("blog", blog)) if err != nil { return nil, err } @@ -295,17 +295,17 @@ func apGetAllInboxes(blog string) ([]string, error) { } func apAddFollower(blog, follower, inbox string) error { - _, err := appDbExec("insert or replace into activitypub_followers (blog, follower, inbox) values (@blog, @follower, @inbox)", sql.Named("blog", blog), sql.Named("follower", follower), sql.Named("inbox", inbox)) + _, err := appDb.exec("insert or replace into activitypub_followers (blog, follower, inbox) values (@blog, @follower, @inbox)", sql.Named("blog", blog), sql.Named("follower", follower), sql.Named("inbox", inbox)) return err } func apRemoveFollower(blog, follower string) error { - _, err := appDbExec("delete from activitypub_followers where blog = @blog and follower = @follower", sql.Named("blog", blog), sql.Named("follower", follower)) + _, err := appDb.exec("delete from activitypub_followers where blog = @blog and follower = @follower", sql.Named("blog", blog), sql.Named("follower", follower)) return err } func apRemoveInbox(inbox string) error { - _, err := appDbExec("delete from activitypub_followers where inbox = @inbox", sql.Named("inbox", inbox)) + _, err := appDb.exec("delete from activitypub_followers where inbox = @inbox", sql.Named("inbox", inbox)) return err } diff --git a/blogstats.go b/blogstats.go index 014adeb..c9ad71a 100644 --- a/blogstats.go +++ b/blogstats.go @@ -67,7 +67,7 @@ func getBlogStats(blog string) (data map[string]interface{}, err error) { Name, Posts, Chars, Words, WordsPerPost string } // Count total posts - row, err := appDbQueryRow("select *, "+wordsPerPost+" from (select "+postCount+", "+charCount+", "+wordCount+" from ("+query+"))", params...) + row, err := appDb.queryRow("select *, "+wordsPerPost+" from (select "+postCount+", "+charCount+", "+wordCount+" from ("+query+"))", params...) if err != nil { return nil, err } @@ -76,7 +76,7 @@ func getBlogStats(blog string) (data map[string]interface{}, err error) { return nil, err } // Count posts per year - rows, err := appDbQuery("select *, "+wordsPerPost+" from (select year, "+postCount+", "+charCount+", "+wordCount+" from ("+query+") where published != '' group by year order by year desc)", params...) + rows, err := appDb.query("select *, "+wordsPerPost+" from (select year, "+postCount+", "+charCount+", "+wordCount+" from ("+query+") where published != '' group by year order by year desc)", params...) if err != nil { return nil, err } @@ -90,7 +90,7 @@ func getBlogStats(blog string) (data map[string]interface{}, err error) { } } // Count posts without date - row, err = appDbQueryRow("select *, "+wordsPerPost+" from (select "+postCount+", "+charCount+", "+wordCount+" from ("+query+") where published = '')", params...) + row, err = appDb.queryRow("select *, "+wordsPerPost+" from (select "+postCount+", "+charCount+", "+wordCount+" from ("+query+") where published = '')", params...) if err != nil { return nil, err } @@ -102,7 +102,7 @@ func getBlogStats(blog string) (data map[string]interface{}, err error) { months := map[string][]statsTableType{} month := statsTableType{} for _, year := range years { - rows, err = appDbQuery("select *, "+wordsPerPost+" from (select month, "+postCount+", "+charCount+", "+wordCount+" from ("+query+") where published != '' and year = @year group by month order by month desc)", append(params, sql.Named("year", year.Name))...) + rows, err = appDb.query("select *, "+wordsPerPost+" from (select month, "+postCount+", "+charCount+", "+wordCount+" from ("+query+") where published != '' and year = @year group by month order by month desc)", append(params, sql.Named("year", year.Name))...) if err != nil { return nil, err } diff --git a/comments.go b/comments.go index 3ea0196..1266bb7 100644 --- a/comments.go +++ b/comments.go @@ -26,7 +26,7 @@ func serveComment(w http.ResponseWriter, r *http.Request) { serveError(w, r, err.Error(), http.StatusBadRequest) return } - row, err := appDbQueryRow("select id, target, name, website, comment from comments where id = @id", sql.Named("id", id)) + row, err := appDb.queryRow("select id, target, name, website, comment from comments where id = @id", sql.Named("id", id)) if err != nil { serveError(w, r, err.Error(), http.StatusInternalServerError) return @@ -66,7 +66,7 @@ func createComment(w http.ResponseWriter, r *http.Request) { } website := strings.TrimSpace(strict.Sanitize(r.FormValue("website"))) // Insert - result, err := appDbExec("insert into comments (target, comment, name, website) values (@target, @comment, @name, @website)", sql.Named("target", target), sql.Named("comment", comment), sql.Named("name", name), sql.Named("website", website)) + result, err := appDb.exec("insert into comments (target, comment, name, website) values (@target, @comment, @name, @website)", sql.Named("target", target), sql.Named("comment", comment), sql.Named("name", name), sql.Named("website", website)) if err != nil { serveError(w, r, err.Error(), http.StatusInternalServerError) return @@ -117,7 +117,7 @@ func buildCommentsQuery(config *commentsRequestConfig) (query string, args []int func getComments(config *commentsRequestConfig) ([]*comment, error) { comments := []*comment{} query, args := buildCommentsQuery(config) - rows, err := appDbQuery(query, args...) + rows, err := appDb.query(query, args...) if err != nil { return nil, err } @@ -135,7 +135,7 @@ func getComments(config *commentsRequestConfig) ([]*comment, error) { func countComments(config *commentsRequestConfig) (count int, err error) { query, params := buildCommentsQuery(config) query = "select count(*) from (" + query + ")" - row, err := appDbQueryRow(query, params...) + row, err := appDb.queryRow(query, params...) if err != nil { return } @@ -144,6 +144,6 @@ func countComments(config *commentsRequestConfig) (count int, err error) { } func deleteComment(id int) error { - _, err := appDbExec("delete from comments where id = @id", sql.Named("id", id)) + _, err := appDb.exec("delete from comments where id = @id", sql.Named("id", id)) return err } diff --git a/database.go b/database.go index 0a28b89..f37c0fc 100644 --- a/database.go +++ b/database.go @@ -2,21 +2,23 @@ package main import ( "database/sql" + "errors" "log" "os" - "sync" sqlite "github.com/mattn/go-sqlite3" "github.com/schollz/sqlite3dump" ) -var ( - appDb *sql.DB - appDbWriteMutex = &sync.Mutex{} - dbStatementCache = map[string]*sql.Stmt{} -) +var appDb *goblogDb + +type goblogDb struct { + db *sql.DB + statementCache map[string]*sql.Stmt +} func initDatabase() (err error) { + // Setup db sql.Register("goblog_db", &sqlite.SQLiteDriver{ ConnectHook: func(c *sqlite.SQLiteConn) error { if err := c.RegisterFunc("tolocal", toLocalSafe, true); err != nil { @@ -31,71 +33,87 @@ func initDatabase() (err error) { return nil }, }) - appDb, err = sql.Open("goblog_db", appConfig.Db.File+"?cache=shared&mode=rwc&_journal_mode=WAL") + db, err := sql.Open("goblog_db", appConfig.Db.File+"?cache=shared&mode=rwc&_journal_mode=WAL") if err != nil { return err } - err = appDb.Ping() + db.SetMaxOpenConns(1) + err = db.Ping() if err != nil { return err } + // Check available SQLite features + rows, err := db.Query("pragma compile_options") + if err != nil { + return err + } + cos := map[string]bool{} + var co string + for rows.Next() { + err = rows.Scan(&co) + if err != nil { + return err + } + cos[co] = true + } + if _, ok := cos["ENABLE_FTS5"]; !ok { + return errors.New("sqlite not compiled with FTS5") + } + // Migrate DB + err = migrateDb(db) + if err != nil { + return err + } + // Create appDB + appDb = &goblogDb{ + db: db, + statementCache: map[string]*sql.Stmt{}, + } + appDb.vacuum() addShutdownFunc(func() { - _ = closeDb() + _ = appDb.close() log.Println("Closed database") }) - vacuumDb() - err = migrateDb() - if err != nil { - return err - } if appConfig.Db.DumpFile != "" { - hourlyHooks = append(hourlyHooks, dumpDb) - dumpDb() + hourlyHooks = append(hourlyHooks, func() { + appDb.dump() + }) + appDb.dump() } return nil } -func dumpDb() { +func (db *goblogDb) dump() { f, err := os.Create(appConfig.Db.DumpFile) if err != nil { log.Println("Error while dump db:", err.Error()) return } - startWritingToDb() - defer finishWritingToDb() - if err = sqlite3dump.DumpDB(appDb, f); err != nil { + if err = sqlite3dump.DumpDB(db.db, f); err != nil { log.Println("Error while dump db:", err.Error()) } } -func startWritingToDb() { - appDbWriteMutex.Lock() +func (db *goblogDb) close() error { + db.vacuum() + return db.db.Close() } -func finishWritingToDb() { - appDbWriteMutex.Unlock() +func (db *goblogDb) vacuum() { + _, _ = db.exec("VACUUM") } -func closeDb() error { - vacuumDb() - return appDb.Close() -} - -func vacuumDb() { - _, _ = appDbExec("VACUUM") -} - -func prepareAppDbStatement(query string) (*sql.Stmt, error) { +func (db *goblogDb) prepare(query string) (*sql.Stmt, error) { stmt, err, _ := cacheGroup.Do(query, func() (interface{}, error) { - stmt, ok := dbStatementCache[query] + stmt, ok := db.statementCache[query] if ok && stmt != nil { return stmt, nil } - stmt, err := appDb.Prepare(query) + stmt, err := db.db.Prepare(query) if err != nil { return nil, err } - dbStatementCache[query] = stmt + db.statementCache[query] = stmt return stmt, nil }) if err != nil { @@ -104,26 +122,29 @@ func prepareAppDbStatement(query string) (*sql.Stmt, error) { return stmt.(*sql.Stmt), nil } -func appDbExec(query string, args ...interface{}) (sql.Result, error) { - stmt, err := prepareAppDbStatement(query) +func (db *goblogDb) exec(query string, args ...interface{}) (sql.Result, error) { + stmt, err := db.prepare(query) if err != nil { return nil, err } - startWritingToDb() - defer finishWritingToDb() return stmt.Exec(args...) } -func appDbQuery(query string, args ...interface{}) (*sql.Rows, error) { - stmt, err := prepareAppDbStatement(query) +func (db *goblogDb) execMulti(query string, args ...interface{}) (sql.Result, error) { + // Can't prepare the statement + return db.db.Exec(query, args...) +} + +func (db *goblogDb) query(query string, args ...interface{}) (*sql.Rows, error) { + stmt, err := db.prepare(query) if err != nil { return nil, err } return stmt.Query(args...) } -func appDbQueryRow(query string, args ...interface{}) (*sql.Row, error) { - stmt, err := prepareAppDbStatement(query) +func (db *goblogDb) queryRow(query string, args ...interface{}) (*sql.Row, error) { + stmt, err := db.prepare(query) if err != nil { return nil, err } diff --git a/databaseMigrations.go b/databaseMigrations.go index eee1806..c4885eb 100644 --- a/databaseMigrations.go +++ b/databaseMigrations.go @@ -6,9 +6,7 @@ import ( "github.com/lopezator/migrator" ) -func migrateDb() error { - startWritingToDb() - defer finishWritingToDb() +func migrateDb(db *sql.DB) error { m, err := migrator.New( migrator.Migrations( &migrator.Migration{ @@ -171,8 +169,5 @@ func migrateDb() error { if err != nil { return err } - if err := m.Migrate(appDb); err != nil { - return err - } - return nil + return m.Migrate(db) } diff --git a/indieAuthServer.go b/indieAuthServer.go index b5b360d..561a7b1 100644 --- a/indieAuthServer.go +++ b/indieAuthServer.go @@ -218,13 +218,13 @@ func indieAuthToken(w http.ResponseWriter, r *http.Request) { } func (data *indieAuthData) saveAuthorization() (err error) { - _, err = appDbExec("insert into indieauthauth (time, code, client, redirect, scope) values (?, ?, ?, ?, ?)", data.time.Unix(), data.code, data.ClientID, data.RedirectURI, strings.Join(data.Scopes, " ")) + _, err = appDb.exec("insert into indieauthauth (time, code, client, redirect, scope) values (?, ?, ?, ?, ?)", data.time.Unix(), data.code, data.ClientID, data.RedirectURI, strings.Join(data.Scopes, " ")) return } func (data *indieAuthData) verifyAuthorization() (valid bool, err error) { // code valid for 600 seconds - row, err := appDbQueryRow("select code, client, redirect, scope from indieauthauth where time >= ? and code = ? and client = ? and redirect = ?", time.Now().Unix()-600, data.code, data.ClientID, data.RedirectURI) + row, err := appDb.queryRow("select code, client, redirect, scope from indieauthauth where time >= ? and code = ? and client = ? and redirect = ?", time.Now().Unix()-600, data.code, data.ClientID, data.RedirectURI) if err != nil { return false, err } @@ -239,13 +239,13 @@ func (data *indieAuthData) verifyAuthorization() (valid bool, err error) { data.Scopes = strings.Split(scope, " ") } valid = true - _, err = appDbExec("delete from indieauthauth where code = ? or time < ?", data.code, time.Now().Unix()-600) + _, err = appDb.exec("delete from indieauthauth where code = ? or time < ?", data.code, time.Now().Unix()-600) data.code = "" return } func (data *indieAuthData) saveToken() (err error) { - _, err = appDbExec("insert into indieauthtoken (time, token, client, scope) values (?, ?, ?, ?)", data.time.Unix(), data.token, data.ClientID, strings.Join(data.Scopes, " ")) + _, err = appDb.exec("insert into indieauthtoken (time, token, client, scope) values (?, ?, ?, ?)", data.time.Unix(), data.token, data.ClientID, strings.Join(data.Scopes, " ")) return } @@ -254,7 +254,7 @@ func verifyIndieAuthToken(token string) (data *indieAuthData, err error) { data = &indieAuthData{ Scopes: []string{}, } - row, err := appDbQueryRow("select time, token, client, scope from indieauthtoken where token = @token", sql.Named("token", token)) + row, err := appDb.queryRow("select time, token, client, scope from indieauthtoken where token = @token", sql.Named("token", token)) if err != nil { return nil, err } @@ -275,6 +275,6 @@ func verifyIndieAuthToken(token string) (data *indieAuthData, err error) { func revokeIndieAuthToken(token string) { if token != "" { - _, _ = appDbExec("delete from indieauthtoken where token=?", token) + _, _ = appDb.exec("delete from indieauthtoken where token=?", token) } } diff --git a/notifications.go b/notifications.go index c3c25e4..b4ef948 100644 --- a/notifications.go +++ b/notifications.go @@ -40,14 +40,14 @@ func sendNotification(text string) { } func saveNotification(n *notification) error { - if _, err := appDbExec("insert into notifications (time, text) values (@time, @text)", sql.Named("time", n.Time), sql.Named("text", n.Text)); err != nil { + if _, err := appDb.exec("insert into notifications (time, text) values (@time, @text)", sql.Named("time", n.Time), sql.Named("text", n.Text)); err != nil { return err } return nil } func deleteNotification(id int) error { - _, err := appDbExec("delete from notifications where id = @id", sql.Named("id", id)) + _, err := appDb.exec("delete from notifications where id = @id", sql.Named("id", id)) return err } @@ -68,7 +68,7 @@ func buildNotificationsQuery(config *notificationsRequestConfig) (query string, func getNotifications(config *notificationsRequestConfig) ([]*notification, error) { notifications := []*notification{} query, args := buildNotificationsQuery(config) - rows, err := appDbQuery(query, args...) + rows, err := appDb.query(query, args...) if err != nil { return nil, err } @@ -86,7 +86,7 @@ func getNotifications(config *notificationsRequestConfig) ([]*notification, erro func countNotifications(config *notificationsRequestConfig) (count int, err error) { query, params := buildNotificationsQuery(config) query = "select count(*) from (" + query + ")" - row, err := appDbQueryRow(query, params...) + row, err := appDb.queryRow(query, params...) if err != nil { return } diff --git a/persistentCache.go b/persistentCache.go index e568708..bd26b13 100644 --- a/persistentCache.go +++ b/persistentCache.go @@ -9,7 +9,7 @@ import ( func cachePersistently(key string, data []byte) error { date, _ := toLocal(time.Now().String()) - _, err := appDbExec("insert or replace into persistent_cache(key, data, date) values(@key, @data, @date)", sql.Named("key", key), sql.Named("data", data), sql.Named("date", date)) + _, err := appDb.exec("insert or replace into persistent_cache(key, data, date) values(@key, @data, @date)", sql.Named("key", key), sql.Named("data", data), sql.Named("date", date)) return err } @@ -17,7 +17,7 @@ var persistentCacheGroup singleflight.Group func retrievePersistentCache(key string) (data []byte, err error) { d, err, _ := persistentCacheGroup.Do(key, func() (interface{}, error) { - if row, err := appDbQueryRow("select data from persistent_cache where key = @key", sql.Named("key", key)); err == sql.ErrNoRows { + if row, err := appDb.queryRow("select data from persistent_cache where key = @key", sql.Named("key", key)); err == sql.ErrNoRows { return nil, nil } else if err != nil { return nil, err @@ -33,6 +33,6 @@ func retrievePersistentCache(key string) (data []byte, err error) { } func clearPersistentCache(pattern string) error { - _, err := appDbExec("delete from persistent_cache where key like @pattern", sql.Named("pattern", pattern)) + _, err := appDb.exec("delete from persistent_cache where key like @pattern", sql.Named("pattern", pattern)) return err } diff --git a/postAliases.go b/postAliases.go index b230253..cac696d 100644 --- a/postAliases.go +++ b/postAliases.go @@ -7,7 +7,7 @@ import ( func allPostAliases() ([]string, error) { var aliases []string - rows, err := appDbQuery("select distinct value from post_parameters where parameter = 'aliases' and value != path") + rows, err := appDb.query("select distinct value from post_parameters where parameter = 'aliases' and value != path") if err != nil { return nil, err } @@ -22,7 +22,7 @@ func allPostAliases() ([]string, error) { } func servePostAlias(w http.ResponseWriter, r *http.Request) { - row, err := appDbQueryRow("select path from post_parameters where parameter = 'aliases' and value = @alias", sql.Named("alias", r.URL.Path)) + row, err := appDb.queryRow("select path from post_parameters where parameter = 'aliases' and value = @alias", sql.Named("alias", r.URL.Path)) if err != nil { serveError(w, r, err.Error(), http.StatusInternalServerError) return diff --git a/postsDb.go b/postsDb.go index eec73ac..8ff9ab0 100644 --- a/postsDb.go +++ b/postsDb.go @@ -125,80 +125,49 @@ func (p *post) createOrReplace(o *postCreationOptions) error { if err != nil { return err } - startWritingToDb() - // Create transaction - tx, err := appDb.Begin() - if err != nil { - finishWritingToDb() - return err - } - if !o.new { - // Remove old post - path := p.Path - if o.oldPath != "" { - path = o.oldPath - } - _, err := tx.Exec("delete from posts where path = @path", sql.Named("path", path)) + // Check if path is already in use + if o.new || (p.Path != o.oldPath) { + // Post is new or post path was changed + newPathExists := false + row, err := appDb.queryRow("select exists(select 1 from posts where path = @path)", sql.Named("path", p.Path)) if err != nil { - _ = tx.Rollback() - finishWritingToDb() return err } - } - // Check if new path exists - postExists := func(path string) (bool, error) { - result := 0 - row := tx.QueryRow("select exists(select 1 from posts where path = @path)", sql.Named("path", path)) - if err = row.Scan(&result); err != nil { - return false, err + err = row.Scan(&newPathExists) + if err != nil { + return err + } + if newPathExists { + // New path already exists + return errors.New("post already exists at given path") } - return result == 1, nil } - if exists, err := postExists(p.Path); err != nil { - _ = tx.Rollback() - finishWritingToDb() - return err - } else if exists { - _ = tx.Rollback() - finishWritingToDb() - return errors.New("post already exists at given path") - } - // Create new post - _, err = tx.Exec( - `insert into posts (path, content, published, updated, blog, section, status) - values (@path, @content, @published, @updated, @blog, @section, @status)`, - sql.Named("path", p.Path), sql.Named("content", p.Content), sql.Named("published", p.Published), - sql.Named("updated", p.Updated), sql.Named("blog", p.Blog), sql.Named("section", p.Section), - sql.Named("status", p.Status)) - if err != nil { - _ = tx.Rollback() - finishWritingToDb() - return err - } - // Create parameters - ppStmt, err := tx.Prepare("insert into post_parameters (path, parameter, value) values (@path, @parameter, @value)") - if err != nil { - _ = tx.Rollback() - finishWritingToDb() - return err + // Build SQL + var sqlBuilder strings.Builder + var sqlArgs []interface{} + // Delete old post + if !o.new { + sqlBuilder.WriteString("delete from posts where path = ?;") + sqlArgs = append(sqlArgs, o.oldPath) } + // Insert new post + sqlBuilder.WriteString("insert into posts (path, content, published, updated, blog, section, status) values (?, ?, ?, ?, ?, ?, ?);") + sqlArgs = append(sqlArgs, p.Path, p.Content, p.Published, p.Updated, p.Blog, p.Section, p.Status) + // Insert post parameters for param, value := range p.Parameters { for _, value := range value { if value != "" { - _, err := ppStmt.Exec(sql.Named("path", p.Path), sql.Named("parameter", param), sql.Named("value", value)) - if err != nil { - _ = tx.Rollback() - finishWritingToDb() - return err - } + sqlBuilder.WriteString("insert into post_parameters (path, parameter, value) values (?, ?, ?);") + sqlArgs = append(sqlArgs, p.Path, param, value) } } } - if tx.Commit() != nil { - finishWritingToDb() + // Execute + _, err = appDb.execMulti(sqlBuilder.String(), sqlArgs...) + if err != nil { return err } - finishWritingToDb() + // Update FTS index, trigger hooks and reload router rebuildFTSIndex() if p.Status == statusPublished { if o.new || o.oldStatus == statusDraft { @@ -218,7 +187,7 @@ func deletePost(path string) error { if err != nil { return err } - _, err = appDbExec("delete from posts where path = @path", sql.Named("path", p.Path)) + _, err = appDb.exec("delete from posts where path = @path", sql.Named("path", p.Path)) if err != nil { return err } @@ -228,7 +197,7 @@ func deletePost(path string) error { } func rebuildFTSIndex() { - _, _ = appDbExec("insert into posts_fts(posts_fts) values ('rebuild')") + _, _ = appDb.exec("insert into posts_fts(posts_fts) values ('rebuild')") } func getPost(path string) (*post, error) { @@ -344,7 +313,7 @@ func buildPostsQuery(config *postsRequestConfig) (query string, args []interface func getPosts(config *postsRequestConfig) (posts []*post, err error) { query, queryParams := buildPostsQuery(config) - rows, err := appDbQuery(query, queryParams...) + rows, err := appDb.query(query, queryParams...) if err != nil { return nil, err } @@ -379,7 +348,7 @@ func getPosts(config *postsRequestConfig) (posts []*post, err error) { func countPosts(config *postsRequestConfig) (count int, err error) { query, params := buildPostsQuery(config) query = "select count(distinct path) from (" + query + ")" - row, err := appDbQueryRow(query, params...) + row, err := appDb.queryRow(query, params...) if err != nil { return } @@ -389,7 +358,7 @@ func countPosts(config *postsRequestConfig) (count int, err error) { func allPostPaths(status postStatus) ([]string, error) { var postPaths []string - rows, err := appDbQuery("select path from posts where status = @status", sql.Named("status", status)) + rows, err := appDb.query("select path from posts where status = @status", sql.Named("status", status)) if err != nil { return nil, err } @@ -405,7 +374,7 @@ func allPostPaths(status postStatus) ([]string, error) { func allTaxonomyValues(blog string, taxonomy string) ([]string, error) { var values []string - rows, err := appDbQuery("select distinct pp.value from posts p left outer join post_parameters pp on p.path = pp.path where pp.parameter = @tax and length(coalesce(pp.value, '')) > 1 and blog = @blog and status = @status", sql.Named("tax", taxonomy), sql.Named("blog", blog), sql.Named("status", statusPublished)) + rows, err := appDb.query("select distinct pp.value from posts p left outer join post_parameters pp on p.path = pp.path where pp.parameter = @tax and length(coalesce(pp.value, '')) > 1 and blog = @blog and status = @status", sql.Named("tax", taxonomy), sql.Named("blog", blog), sql.Named("status", statusPublished)) if err != nil { return nil, err } @@ -422,7 +391,7 @@ type publishedDate struct { } func allPublishedDates(blog string) (dates []publishedDate, err error) { - rows, err := appDbQuery("select distinct substr(published, 1, 4) as year, substr(published, 6, 2) as month, substr(published, 9, 2) as day from posts where blog = @blog and status = @status and year != '' and month != '' and day != ''", sql.Named("blog", blog), sql.Named("status", statusPublished)) + rows, err := appDb.query("select distinct substr(published, 1, 4) as year, substr(published, 6, 2) as month, substr(published, 9, 2) as day from posts where blog = @blog and status = @status and year != '' and month != '' and day != ''", sql.Named("blog", blog), sql.Named("status", statusPublished)) if err != nil { return nil, err } diff --git a/queue.go b/queue.go index 04b3bad..56e4f2d 100644 --- a/queue.go +++ b/queue.go @@ -12,7 +12,7 @@ func enqueue(name string, content []byte, schedule time.Time) error { if len(content) == 0 { return errors.New("empty content") } - _, err := appDbExec("insert into queue (name, content, schedule) values (@name, @content, @schedule)", + _, err := appDb.exec("insert into queue (name, content, schedule) values (@name, @content, @schedule)", sql.Named("name", name), sql.Named("content", content), sql.Named("schedule", schedule.UTC().String())) return err } @@ -25,17 +25,17 @@ type queueItem struct { } func (qi *queueItem) reschedule(dur time.Duration) error { - _, err := appDbExec("update queue set schedule = @schedule, content = @content where id = @id", sql.Named("schedule", qi.schedule.Add(dur).UTC().String()), sql.Named("content", qi.content), sql.Named("id", qi.id)) + _, err := appDb.exec("update queue set schedule = @schedule, content = @content where id = @id", sql.Named("schedule", qi.schedule.Add(dur).UTC().String()), sql.Named("content", qi.content), sql.Named("id", qi.id)) return err } func (qi *queueItem) dequeue() error { - _, err := appDbExec("delete from queue where id = @id", sql.Named("id", qi.id)) + _, err := appDb.exec("delete from queue where id = @id", sql.Named("id", qi.id)) return err } func peekQueue(name string) (*queueItem, error) { - row, err := appDbQueryRow("select id, name, content, schedule from queue where schedule <= @schedule and name = @name order by schedule asc limit 1", sql.Named("name", name), sql.Named("schedule", time.Now().UTC().String())) + row, err := appDb.queryRow("select id, name, content, schedule from queue where schedule <= @schedule and name = @name order by schedule asc limit 1", sql.Named("name", name), sql.Named("schedule", time.Now().UTC().String())) if err != nil { return nil, err } diff --git a/sessions.go b/sessions.go index 5c044c7..bab1881 100644 --- a/sessions.go +++ b/sessions.go @@ -23,7 +23,7 @@ const ( func initSessions() { deleteExpiredSessions := func() { - if _, err := appDbExec("delete from sessions where expires < @now", + if _, err := appDb.exec("delete from sessions where expires < @now", sql.Named("now", time.Now().Local().String())); err != nil { log.Println("Failed to delete expired sessions:", err.Error()) } @@ -101,14 +101,14 @@ func (s *dbSessionStore) Delete(r *http.Request, w http.ResponseWriter, session for k := range session.Values { delete(session.Values, k) } - if _, err := appDbExec("delete from sessions where id = @id", sql.Named("id", session.ID)); err != nil { + if _, err := appDb.exec("delete from sessions where id = @id", sql.Named("id", session.ID)); err != nil { return err } return nil } func (s *dbSessionStore) load(session *sessions.Session) (err error) { - row, err := appDbQueryRow("select data, created, modified, expires from sessions where id = @id", sql.Named("id", session.ID)) + row, err := appDb.queryRow("select data, created, modified, expires from sessions where id = @id", sql.Named("id", session.ID)) if err != nil { return err } @@ -144,7 +144,7 @@ func (s *dbSessionStore) insert(session *sessions.Session) (err error) { if err != nil { return err } - res, err := appDbExec("insert into sessions(data, created, modified, expires) values(@data, @created, @modified, @expires)", + res, err := appDb.exec("insert into sessions(data, created, modified, expires) values(@data, @created, @modified, @expires)", sql.Named("data", encoded), sql.Named("created", created.Local().String()), sql.Named("modified", modified.Local().String()), sql.Named("expires", expires.Local().String())) if err != nil { return err @@ -168,7 +168,7 @@ func (s *dbSessionStore) save(session *sessions.Session) (err error) { if err != nil { return err } - _, err = appDbExec("update sessions set data = @data, modified = @modified where id = @id", + _, err = appDb.exec("update sessions set data = @data, modified = @modified where id = @id", sql.Named("data", encoded), sql.Named("modified", time.Now().Local().String()), sql.Named("id", session.ID)) if err != nil { return err diff --git a/shortPath.go b/shortPath.go index 087a588..30b3b59 100644 --- a/shortPath.go +++ b/shortPath.go @@ -16,7 +16,7 @@ func shortenPath(p string) (string, error) { } id := getShortPathID(p) if id == -1 { - _, err := appDbExec("insert or ignore into shortpath (path) values (@path)", sql.Named("path", p)) + _, err := appDb.exec("insert or ignore into shortpath (path) values (@path)", sql.Named("path", p)) if err != nil { return "", err } @@ -32,7 +32,7 @@ func getShortPathID(p string) (id int) { if p == "" { return -1 } - row, err := appDbQueryRow("select id from shortpath where path = @path", sql.Named("path", p)) + row, err := appDb.queryRow("select id from shortpath where path = @path", sql.Named("path", p)) if err != nil { return -1 } @@ -49,7 +49,7 @@ func redirectToLongPath(rw http.ResponseWriter, r *http.Request) { serve404(rw, r) return } - row, err := appDbQueryRow("select path from shortpath where id = @id", sql.Named("id", id)) + row, err := appDb.queryRow("select path from shortpath where id = @id", sql.Named("id", id)) if err != nil { serve404(rw, r) return diff --git a/webmention.go b/webmention.go index 02392d7..4e91a3c 100644 --- a/webmention.go +++ b/webmention.go @@ -84,7 +84,7 @@ func extractMention(r *http.Request) (*mention, error) { func webmentionExists(source, target string) bool { result := 0 - row, err := appDbQueryRow("select exists(select 1 from webmentions where source = ? and target = ?)", source, target) + row, err := appDb.queryRow("select exists(select 1 from webmentions where source = ? and target = ?)", source, target) if err != nil { return false } @@ -103,12 +103,12 @@ func createWebmention(source, target string) (err error) { } func deleteWebmention(id int) error { - _, err := appDbExec("delete from webmentions where id = @id", sql.Named("id", id)) + _, err := appDb.exec("delete from webmentions where id = @id", sql.Named("id", id)) return err } func approveWebmention(id int) error { - _, err := appDbExec("update webmentions set status = ? where id = ?", webmentionStatusApproved, id) + _, err := appDb.exec("update webmentions set status = ? where id = ?", webmentionStatusApproved, id) return err } @@ -172,7 +172,7 @@ func buildWebmentionsQuery(config *webmentionsRequestConfig) (query string, args func getWebmentions(config *webmentionsRequestConfig) ([]*mention, error) { mentions := []*mention{} query, args := buildWebmentionsQuery(config) - rows, err := appDbQuery(query, args...) + rows, err := appDb.query(query, args...) if err != nil { return nil, err } @@ -190,7 +190,7 @@ func getWebmentions(config *webmentionsRequestConfig) ([]*mention, error) { func countWebmentions(config *webmentionsRequestConfig) (count int, err error) { query, params := buildWebmentionsQuery(config) query = "select count(*) from (" + query + ")" - row, err := appDbQueryRow(query, params...) + row, err := appDb.queryRow(query, params...) if err != nil { return } diff --git a/webmentionVerification.go b/webmentionVerification.go index 6415199..1f1b78a 100644 --- a/webmentionVerification.go +++ b/webmentionVerification.go @@ -82,7 +82,7 @@ func (m *mention) verifyMention() error { err = m.verifyReader(resp.Body) _ = resp.Body.Close() if err != nil { - _, err := appDbExec("delete from webmentions where source = @source and target = @target", sql.Named("source", m.Source), sql.Named("target", m.Target)) + _, err := appDb.exec("delete from webmentions where source = @source and target = @target", sql.Named("source", m.Source), sql.Named("target", m.Target)) return err } if len(m.Content) > 500 { @@ -93,10 +93,10 @@ func (m *mention) verifyMention() error { } newStatus := webmentionStatusVerified if webmentionExists(m.Source, m.Target) { - _, err = appDbExec("update webmentions set status = @status, title = @title, content = @content, author = @author where source = @source and target = @target", + _, err = appDb.exec("update webmentions set status = @status, title = @title, content = @content, author = @author where source = @source and target = @target", sql.Named("status", newStatus), sql.Named("title", m.Title), sql.Named("content", m.Content), sql.Named("author", m.Author), sql.Named("source", m.Source), sql.Named("target", m.Target)) } else { - _, err = appDbExec("insert into webmentions (source, target, created, status, title, content, author) values (@source, @target, @created, @status, @title, @content, @author)", + _, err = appDb.exec("insert into webmentions (source, target, created, status, title, content, author) values (@source, @target, @created, @status, @title, @content, @author)", sql.Named("source", m.Source), sql.Named("target", m.Target), sql.Named("created", m.Created), sql.Named("status", newStatus), sql.Named("title", m.Title), sql.Named("content", m.Content), sql.Named("author", m.Author)) sendNotification(fmt.Sprintf("New webmention from %s to %s", m.Source, m.Target)) }