/* $Id$ */ /* * Copyright (c) 2016 Kristaps Dzonsons * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include "ksql.h" #include "extern.h" enum stmt { STMT_AUTHORS_ID, STMT_AUTHORS_NAME, STMT_AUTHOR_BOOKS, STMT_AUTHORS_AUTHORS, STMT_AUTHOR, STMT__MAX }; static const char *const stmts[STMT__MAX] = { /* STMT_AUTHORS_ID */ "SELECT authors.id, authors.name, count(book) as count FROM authors, books_authors_link \ WHERE authors.id = books_authors_link.author GROUP BY author \ ORDER BY authors.id LIMIT ? OFFSET ?", /* STMT_AUTHORS_NAME */ "SELECT authors.id, authors.name, count(book) as count FROM authors, books_authors_link \ WHERE authors.id = books_authors_link.author GROUP BY author \ ORDER BY authors.sort LIMIT ? OFFSET ?", /* STMT_AUTHOR_BOOKS */ "SELECT books.id AS id,title,series_index,name as series_name,series.id AS series_id \ FROM books LEFT OUTER JOIN books_series_link ON books.id = books_series_link.book \ LEFT OUTER JOIN series ON series.id = books_series_link.series \ LEFT OUTER JOIN books_authors_link ON books.id = books_authors_link.book \ WHERE books_authors_link.author = ? ORDER BY id", /* STMT_AUTHORS_AUTHORS */ "SELECT authors.id, authors.name, books_authors_link.book as book \ FROM authors, books_authors_link WHERE books_authors_link.author = authors.id \ AND books_authors_link.book IN ( SELECT books.id FROM books LEFT OUTER JOIN books_authors_link \ ON books.id = books_authors_link.book WHERE books_authors_link.author = ? ORDER BY books.id)", /* STMT_AUTHOR */ "SELECT name FROM authors WHERE id = ?", }; void db_author_unfill(Author *p) { if (NULL == p) return; free(p->name); } void db_author_adv_free(AuthorAdv *p) { db_author_unfill(&p->a); free(p); } void db_author_free(Author *p) { db_author_unfill(p); free(p); } AuthorFull * db_author_load(struct kreq *r, int64_t id) { struct ksqlstmt *stmt; struct bookauth *item = NULL; struct bookauth *p = NULL; int books = 0; BookAdv *b; AuthorFull *a = kcalloc(1, sizeof(AuthorFull)); a->a.id = id; ksql_stmt_alloc(r->arg, &stmt, stmts[STMT_AUTHOR_BOOKS], STMT_AUTHOR_BOOKS); ksql_bind_int(stmt, 0, id); while (KSQL_ROW == ksql_stmt_step(stmt)) { books++; b = kcalloc(1, sizeof(BookAdv)); b->asize = 0; b->tsize = 0; db_book_fill(&b->b, stmt); item = kcalloc(1, sizeof(struct bookauth)); item->b = b; item->a = &a->a; item->p = p; p = item; } ksql_stmt_free(stmt); a->bsize = books; if (books>0) { a->books = kcalloc(books, sizeof(BookAdv)); while (NULL != p && books > 0) { a->books[--books] = p->b; item = p; p = p->p; free(item); } ksql_stmt_alloc(r->arg, &stmt, stmts[STMT_AUTHORS_AUTHORS], STMT_AUTHORS_AUTHORS); ksql_bind_int(stmt, 0, id); p = db_load_books_authors(a->books, a->bsize, stmt); ksql_stmt_free(stmt); db_assign_book_authors(p); // get name from 1st book for (size_t i=0; ibooks[0]->asize; i++) { if (a->a.id == a->books[0]->a[i]->id) a->a.name = a->books[0]->a[i]->name; } } else { // no books, get name ksql_stmt_alloc(r->arg, &stmt, stmts[STMT_AUTHOR], STMT_AUTHOR); ksql_bind_int(stmt, 0, id); if (KSQL_ROW == ksql_stmt_step(stmt)) a->a.name = kstrdup(ksql_stmt_str(stmt, 0)); else a = NULL; ksql_stmt_free(stmt); } return a; } int db_authors_load(struct kreq *r, AuthorAdv **authors, const char *sort, int limit, int offset) { if (limit < 0 || offset < 0) { return 0; } struct ksqlstmt *stmt; int query, count = 0; if (sort == NULL) query = STMT_AUTHORS_ID; else if (0 == strcmp(sort, "name")) query = STMT_AUTHORS_NAME; else query = STMT_AUTHORS_ID; ksql_stmt_alloc(r->arg, &stmt, stmts[query], query); ksql_bind_int(stmt, 0, limit); ksql_bind_int(stmt, 1, offset); while (KSQL_ROW == ksql_stmt_step(stmt)) { authors[count] = kcalloc(1, sizeof(AuthorAdv)); authors[count]->a.id = ksql_stmt_int(stmt, 0); authors[count]->a.name = kstrdup(ksql_stmt_str(stmt, 1)); authors[count]->count = ksql_stmt_int(stmt, 2); count++; } ksql_stmt_free(stmt); return count; }