/* $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_SERIES, STMT_SERIES_AUTHORS, STMT_SERIE, STMT_SERIE_BOOKS, STMT_SERIE_AUTHORS, STMT__MAX }; static const char *const stmts[STMT__MAX] = { /* STMT_SERIES */ "SELECT series.id, series.name, count(book) FROM series \ LEFT OUTER JOIN books_series_link ON books_series_link.series = series.id \ GROUP BY series.id ORDER BY series.id LIMIT ? OFFSET ?", /* STMT_SERIES_AUTHORS */ "SELECT DISTINCT authors.id, authors.name, books_series_link.series \ FROM authors, books_authors_link, books_series_link \ WHERE books_authors_link.book = books_series_link.book AND books_authors_link.author = authors.id \ AND books_series_link.series IN ( SELECT id FROM series ORDER BY series.id LIMIT ? OFFSET ?)", /* STMT_SERIE */ "SELECT series.id, series.name FROM series WHERE series.id = ?", /* STMT_SERIE_BOOKS */ "SELECT books.id, title, series_index FROM books \ LEFT OUTER JOIN books_series_link ON books.id = books_series_link.book \ WHERE books_series_link.series = ?", /* STMT_SERIE_AUTHORS */ "SELECT DISTINCT authors.id, authors.name \ FROM authors, books_authors_link, books_series_link \ WHERE books_authors_link.book = books_series_link.book AND books_authors_link.author = authors.id \ AND books_series_link.series = ?", }; struct seriesbook { SeriesFull *s; Book *b; struct seriesbook *p; }; struct seriesauth { SeriesAdv *s; Author *a; struct seriesauth *p; }; void db_series_unfill(Series *p) { if (NULL == p) return; free(p->name); } void db_series_free(Series *p) { if (NULL == p) return; db_series_unfill(p); free(p); } void db_series_adv_free(SeriesAdv *p) { if (NULL == p) return; db_series_unfill(&p->s); free(p); } static void db_assign_series_authors(struct seriesauth *list) { struct seriesauth *item = NULL; struct seriesauth *p = NULL; p = list; while (NULL != p) { if (NULL != p->s && NULL == p->s->a && p->s->asize > 0) { p->s->a = kcalloc(p->s->asize, sizeof(Author)); p->s->asize = 0; // use as counter for insert } p->s->a[p->s->asize] = p->a; p->s->asize++; item = p; p = p->p; free(item); } } static struct seriesauth * db_load_series_authors(SeriesAdv **series, int count, struct ksqlstmt *stmt) { struct seriesauth *item = NULL; struct seriesauth *p = NULL; int64_t sid = -1; int i = 0; while (KSQL_ROW == ksql_stmt_step(stmt)) { item = kcalloc(1, sizeof(struct seriesauth)); item->a = kcalloc(1, sizeof(Author)); item->a->id = ksql_stmt_int(stmt, 0); item->a->name = kstrdup(ksql_stmt_str(stmt, 1)); sid = ksql_stmt_int(stmt, 2); for (i = 0; i < count && NULL == item->s; i++) { if (series[i]->s.id == sid) { item->s = series[i]; item->s->asize++; } } item->p = p; p = item; } return p; } static struct seriesbook* db_load_series_books(struct kreq *r, SeriesFull *series, int64_t id) { struct ksqlstmt *stmt; struct seriesbook *p = NULL; struct seriesbook *item = NULL; ksql_stmt_alloc(r->arg, &stmt, stmts[STMT_SERIE_BOOKS], STMT_SERIE_BOOKS); ksql_bind_int(stmt, 0, id); while (KSQL_ROW == ksql_stmt_step(stmt)) { item = kcalloc(1,sizeof(struct seriesbook)); Book *b = kcalloc(1, sizeof(Book)); b->id = ksql_stmt_int(stmt, 0); b->title = kstrdup(ksql_stmt_str(stmt, 1)); b->s_idx = ksql_stmt_int(stmt, 2); b->s = series->s.s; item->b = b; item->s = series; series->s.books++; item->p = p; p = item; } ksql_stmt_free(stmt); return p; } static void db_assign_series_books(struct seriesbook *list) { struct seriesbook *p = NULL; struct seriesbook *item = NULL; p = list; while (NULL != p) { if (NULL != p->s && NULL == p->s->b && p->s->s.books > 0) { p->s->b = kcalloc(p->s->s.books, sizeof(Book)); p->s->s.books = 0; // use as counter for insert } p->s->b[p->s->s.books] = p->b; p->s->s.books++; item = p; p = p->p; free(item); } } SeriesFull * db_serie_load(struct kreq *r, int64_t id) { struct ksqlstmt *stmt; SeriesFull *series; struct seriesauth *p = NULL; struct seriesauth *item = NULL; struct seriesbook *list = NULL; ksql_stmt_alloc(r->arg, &stmt, stmts[STMT_SERIE], STMT_SERIE); ksql_bind_int(stmt, 0, id); if (KSQL_ROW != ksql_stmt_step(stmt)) { ksql_stmt_free(stmt); return(NULL); } series = kcalloc(1, sizeof(SeriesFull)); series->s.s.id = ksql_stmt_int(stmt, 0); series->s.s.name = kstrdup(ksql_stmt_str(stmt, 1)); series->s.books = 0; series->s.asize = 0; ksql_stmt_free(stmt); list = db_load_series_books(r, series, id); db_assign_series_books(list); ksql_stmt_alloc(r->arg, &stmt, stmts[STMT_SERIE_AUTHORS], STMT_SERIE_AUTHORS); ksql_bind_int(stmt, 0, id); while (KSQL_ROW == ksql_stmt_step(stmt)) { item = kcalloc(1, sizeof(struct seriesauth)); item->a = kcalloc(1, sizeof(Author)); item->a->id = ksql_stmt_int(stmt, 0); item->a->name = kstrdup(ksql_stmt_str(stmt, 1)); item->s = &series->s; item->s->asize++; item->p = p; p = item; } ksql_stmt_free(stmt); db_assign_series_authors(p); return series; } int db_series_load(struct kreq *r, SeriesAdv **series, int limit, int offset) { if (limit < 0 || offset < 0) { return 0; } struct ksqlstmt *stmt; int count = 0; struct seriesauth *p = NULL; ksql_stmt_alloc(r->arg, &stmt, stmts[STMT_SERIES], STMT_SERIES); ksql_bind_int(stmt, 0, limit); ksql_bind_int(stmt, 1, offset); while (KSQL_ROW == ksql_stmt_step(stmt)) { series[count] = kcalloc(1, sizeof(SeriesAdv)); series[count]->s.id = ksql_stmt_int(stmt, 0); series[count]->s.name = kstrdup(ksql_stmt_str(stmt, 1)); series[count]->books = ksql_stmt_int(stmt, 2); series[count]->asize = 0; count++; } ksql_stmt_free(stmt); ksql_stmt_alloc(r->arg, &stmt, stmts[STMT_SERIES_AUTHORS], STMT_SERIES_AUTHORS); ksql_bind_int(stmt, 0, limit); ksql_bind_int(stmt, 1, offset); p = db_load_series_authors(series, count, stmt); ksql_stmt_free(stmt); db_assign_series_authors(p); return count; }