From b82967565b01243bce28b9b06be6d30114d1fab5 Mon Sep 17 00:00:00 2001 From: Meutel Date: Wed, 2 Aug 2017 19:54:09 +0200 Subject: [PATCH] Reuse prepared statements, close rows --- bouquins/db.go | 79 +++++++++++++++++++++++++++++++++++++++++--------- main.go | 4 +++ 2 files changed, 69 insertions(+), 14 deletions(-) diff --git a/bouquins/db.go b/bouquins/db.go index fdfb47a..58e744f 100644 --- a/bouquins/db.go +++ b/bouquins/db.go @@ -2,6 +2,8 @@ package bouquins import ( "database/sql" + "errors" + "fmt" "log" ) @@ -56,6 +58,10 @@ const ( BOOKS QueryType = iota BOOKS_TAGS QueryType = iota BOOKS_AUTHORS QueryType = iota + BOOK QueryType = iota + BOOK_TAGS QueryType = iota + BOOK_DATA QueryType = iota + BOOKS_COUNT QueryType = iota ) var QUERIES = map[Query]string{ @@ -71,7 +77,12 @@ var QUERIES = map[Query]string{ Query{BOOKS_AUTHORS, true, false}: STMT_BOOKS_AUTHORS_TITLE_ASC, Query{BOOKS_AUTHORS, false, true}: STMT_BOOKS_AUTHORS_ID_DESC, Query{BOOKS_AUTHORS, false, false}: STMT_BOOKS_AUTHORS_ID_ASC, + Query{BOOK, false, false}: STMT_BOOK, + Query{BOOK_TAGS, false, false}: STMT_BOOK_TAGS, + Query{BOOK_DATA, false, false}: STMT_BOOK_DATA, + Query{BOOKS_COUNT, false, false}: STMT_BOOKS_COUNT, } +var STMTS = make(map[Query]*sql.Stmt) type QueryType uint type Query struct { @@ -81,11 +92,42 @@ type Query struct { } // PREPARED STATEMENTS // -func (app *Bouquins) psBooks(qt QueryType, sort, order string) (*sql.Stmt, error) { - //TODO cache - query := QUERIES[Query{qt, sort == "title", order == "desc"}] +func (app *Bouquins) PrepareAll() error { + errcount := 0 + for q, v := range QUERIES { + stmt, err := app.DB.Prepare(v) + if err != nil { + log.Println(err, v) + errcount++ + } + STMTS[q] = stmt + } + if errcount > 0 { + return errors.New(fmt.Sprintf("%d errors on queries, see logs", errcount)) + } + return nil +} + +// prepared statement with sort on books +func (app *Bouquins) psSortBooks(qt QueryType, sort, order string) (*sql.Stmt, error) { + q := Query{qt, sort == "title", order == "desc"} + query := QUERIES[q] log.Println(query) - return app.DB.Prepare(query) + stmt := STMTS[q] + if stmt == nil { + log.Println("Missing statement for ", q) + var err error + stmt, err = app.DB.Prepare(query) + if err != nil { + return nil, err + } + } + return stmt, nil +} + +// prepared statement without sort +func (app *Bouquins) ps(qt QueryType) (*sql.Stmt, error) { + return app.psSortBooks(qt, "", "") } // MERGE SUB QUERIES // @@ -100,7 +142,7 @@ func assignAuthorsTagsBooks(books []*BookAdv, authors map[int64][]*Author, tags func (app *Bouquins) queryBooks(limit, offset int, sort, order string) ([]*BookAdv, error) { books := make([]*BookAdv, 0, limit) - stmt, err := app.psBooks(BOOKS, sort, order) + stmt, err := app.psSortBooks(BOOKS, sort, order) if err != nil { return nil, err } @@ -108,6 +150,7 @@ func (app *Bouquins) queryBooks(limit, offset int, sort, order string) ([]*BookA if err != nil { return nil, err } + defer rows.Close() for rows.Next() { book := new(BookAdv) var series_name sql.NullString @@ -131,7 +174,7 @@ func (app *Bouquins) queryBooks(limit, offset int, sort, order string) ([]*BookA func (app *Bouquins) queryBooksAuthors(limit, offset int, sort, order string) (map[int64][]*Author, error) { authors := make(map[int64][]*Author) - stmt, err := app.psBooks(BOOKS_AUTHORS, sort, order) + stmt, err := app.psSortBooks(BOOKS_AUTHORS, sort, order) if err != nil { return nil, err } @@ -139,6 +182,7 @@ func (app *Bouquins) queryBooksAuthors(limit, offset int, sort, order string) (m if err != nil { return nil, err } + defer rows.Close() for rows.Next() { author := new(Author) var book int64 @@ -158,7 +202,7 @@ func (app *Bouquins) queryBooksAuthors(limit, offset int, sort, order string) (m } func (app *Bouquins) queryBooksTags(limit, offset int, sort, order string) (map[int64][]string, error) { - stmt, err := app.psBooks(BOOKS_TAGS, sort, order) + stmt, err := app.psSortBooks(BOOKS_TAGS, sort, order) if err != nil { return nil, err } @@ -166,6 +210,7 @@ func (app *Bouquins) queryBooksTags(limit, offset int, sort, order string) (map[ if err != nil { return nil, err } + defer rows.Close() tags := make(map[int64][]string) for rows.Next() { var tag string @@ -186,7 +231,7 @@ func (app *Bouquins) queryBooksTags(limit, offset int, sort, order string) (map[ return tags, nil } func (app *Bouquins) queryBook(id int64) (*BookFull, error) { - stmt, err := app.DB.Prepare(STMT_BOOK) + stmt, err := app.ps(BOOK) if err != nil { return nil, err } @@ -231,7 +276,7 @@ func (app *Bouquins) queryBook(id int64) (*BookFull, error) { return book, nil } func (app *Bouquins) queryBookTags(book *BookFull) error { - stmt, err := app.DB.Prepare(STMT_BOOK_TAGS) + stmt, err := app.ps(BOOK_TAGS) if err != nil { return err } @@ -239,6 +284,7 @@ func (app *Bouquins) queryBookTags(book *BookFull) error { if err != nil { return err } + defer rows.Close() for rows.Next() { var tag string if err = rows.Scan(&tag); err != nil { @@ -251,8 +297,8 @@ func (app *Bouquins) queryBookTags(book *BookFull) error { } return nil } -func (app *Bouquins) queryBookAuthors(book *BookFull) error { - stmt, err := app.DB.Prepare(STMT_BOOK_DATA) +func (app *Bouquins) queryBookData(book *BookFull) error { + stmt, err := app.ps(BOOK_DATA) if err != nil { return err } @@ -260,6 +306,7 @@ func (app *Bouquins) queryBookAuthors(book *BookFull) error { if err != nil { return err } + defer rows.Close() for rows.Next() { data := new(BookData) if err = rows.Scan(&data.Name, &data.Format, &data.Size); err != nil { @@ -272,7 +319,7 @@ func (app *Bouquins) queryBookAuthors(book *BookFull) error { } return nil } -func (app *Bouquins) queryBookData(book *BookFull) error { +func (app *Bouquins) queryBookAuthors(book *BookFull) error { return nil } @@ -280,8 +327,12 @@ func (app *Bouquins) queryBookData(book *BookFull) error { func (app *Bouquins) BookCount() (int64, error) { var count int64 - row := app.DB.QueryRow(STMT_BOOKS_COUNT) - err := row.Scan(&count) + stmt, err := app.ps(BOOKS_COUNT) + if err != nil { + return 0, err + } + row := stmt.QueryRow() + err = row.Scan(&count) return count, err } func (app *Bouquins) SeriesAdv(limit, offset int, sort, order string) ([]*SeriesAdv, error) { diff --git a/main.go b/main.go index 4b65a82..6019ff2 100644 --- a/main.go +++ b/main.go @@ -63,6 +63,10 @@ func initApp() *BouquinsConf { tpl, db, } + err = app.PrepareAll() + if err != nil { + log.Fatalln(err) + } assets() router(app) return conf