2016-12-18 15:50:56 +00:00
/* $Id$ */
/*
* Copyright ( c ) 2016 Kristaps Dzonsons < kristaps @ bsd . lv >
*
* 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 <stdarg.h>
# include <stdint.h>
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <time.h>
# include <unistd.h>
# include <kcgi.h>
# include <kcgijson.h>
2016-12-29 19:41:31 +00:00
# include "ksql.h"
2016-12-18 15:50:56 +00:00
# include "extern.h"
2016-12-29 20:02:58 +00:00
enum stmt {
2016-12-30 09:10:55 +00:00
STMT_BOOK ,
STMT_BOOKS ,
2016-12-30 14:40:21 +00:00
STMT_BOOKS_AUTHORS ,
2016-12-30 09:10:55 +00:00
STMT__MAX
2016-12-29 20:02:58 +00:00
} ;
static const char * const stmts [ STMT__MAX ] = {
/* STMT_BOOK */
2016-12-30 09:10:55 +00:00
" 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 WHERE books.id = ? " ,
2016-12-30 14:40:21 +00:00
/* STMT_BOOKS */ //TODO offset
" 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 ORDER BY id LIMIT ? " ,
/* STMT_BOOKS_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 id FROM books ORDER BY id LIMIT ? ) " ,
} ;
/*
* Linked list authors of book .
*/
struct bookauth {
Author * a ;
BookAdv * b ;
struct bookauth * p ;
2016-12-29 20:02:58 +00:00
} ;
2016-12-30 10:19:23 +00:00
static void
db_series_unfill ( Series * p )
{
if ( NULL = = p )
return ;
free ( p - > name ) ;
}
2016-12-29 23:45:20 +00:00
void
2016-12-30 10:19:23 +00:00
db_series_free ( Series * p )
2016-12-29 23:45:20 +00:00
{
2016-12-30 10:19:23 +00:00
db_series_unfill ( p ) ;
free ( p ) ;
}
static void
db_book_unfill ( Book * p )
{
if ( NULL = = p )
2016-12-29 23:45:20 +00:00
return ;
2016-12-30 10:19:23 +00:00
free ( p - > title ) ;
db_series_unfill ( & p - > s ) ;
}
2016-12-30 14:54:32 +00:00
static void
db_author_unfill ( Author * p ) {
if ( NULL = = p )
return ;
free ( p - > name ) ;
}
2016-12-30 10:19:23 +00:00
void
db_book_free ( Book * p )
{
db_book_unfill ( p ) ;
free ( p ) ;
}
void
db_book_adv_free ( BookAdv * p )
{
db_book_unfill ( & p - > b ) ;
2016-12-30 14:54:32 +00:00
for ( size_t i = 0 ; i < p - > asize ; i + + ) {
db_author_unfill ( p - > a [ i ] ) ;
}
2016-12-30 10:19:23 +00:00
free ( p ) ;
2016-12-29 23:45:20 +00:00
}
2016-12-30 10:37:08 +00:00
static void
db_book_fill ( Book * book , struct ksqlstmt * stmt )
{
book - > id = ksql_stmt_int ( stmt , 0 ) ;
book - > title = kstrdup ( ksql_stmt_str ( stmt , 1 ) ) ;
if ( ksql_stmt_isnull ( stmt , 4 ) ) {
book - > s . id = - 1 ;
} else {
book - > s_idx = ksql_stmt_double ( stmt , 2 ) ;
book - > s . name = kstrdup ( ksql_stmt_str ( stmt , 3 ) ) ;
book - > s . id = ksql_stmt_int ( stmt , 4 ) ;
}
}
2016-12-29 23:38:31 +00:00
int
2016-12-30 10:19:23 +00:00
db_books_load ( struct kreq * r , BookAdv * * books , int limit )
2016-12-29 23:38:31 +00:00
{
if ( limit < 0 ) {
return 0 ;
}
struct ksqlstmt * stmt ;
2016-12-30 14:40:21 +00:00
struct bookauth * p = NULL ;
2016-12-30 14:54:32 +00:00
struct bookauth * item = NULL ;
2016-12-30 14:40:21 +00:00
int i , count = 0 ;
2016-12-30 14:54:32 +00:00
int64_t bid ;
2016-12-30 14:40:21 +00:00
2016-12-29 23:38:31 +00:00
ksql_stmt_alloc ( r - > arg , & stmt ,
stmts [ STMT_BOOKS ] ,
STMT_BOOKS ) ;
ksql_bind_int ( stmt , 0 , limit ) ;
while ( KSQL_ROW = = ksql_stmt_step ( stmt ) ) {
2016-12-30 14:40:21 +00:00
books [ count ] = kcalloc ( 1 , sizeof ( BookAdv ) ) ;
db_book_fill ( & books [ count ] - > b , stmt ) ;
books [ count ] - > asize = 0 ;
count + + ;
}
ksql_stmt_free ( stmt ) ;
ksql_stmt_alloc ( r - > arg , & stmt ,
stmts [ STMT_BOOKS_AUTHORS ] ,
STMT_BOOKS_AUTHORS ) ;
ksql_bind_int ( stmt , 0 , limit ) ;
while ( KSQL_ROW = = ksql_stmt_step ( stmt ) ) {
// add author to list, link related book and increment asize
2016-12-30 14:54:32 +00:00
item = kcalloc ( 1 , sizeof ( struct bookauth ) ) ;
2016-12-30 14:40:21 +00:00
item - > a = kcalloc ( 1 , sizeof ( Author ) ) ;
item - > a - > id = ksql_stmt_int ( stmt , 0 ) ;
item - > a - > name = kstrdup ( ksql_stmt_str ( stmt , 1 ) ) ;
2016-12-30 14:54:32 +00:00
bid = ksql_stmt_int ( stmt , 2 ) ;
2016-12-30 14:40:21 +00:00
for ( i = 0 ; i < count & & NULL = = item - > b ; i + + ) {
if ( books [ i ] - > b . id = = bid ) {
item - > b = books [ i ] ;
item - > b - > asize + + ;
}
}
item - > p = p ;
p = item ;
2016-12-29 23:38:31 +00:00
}
2016-12-30 14:40:21 +00:00
// assign authors to books
while ( NULL ! = p ) {
if ( NULL ! = p - > b & & NULL = = p - > b - > a & & p - > b - > asize > 0 ) {
p - > b - > a = kcalloc ( p - > b - > asize , sizeof ( Author ) ) ;
p - > b - > asize = 0 ; // use as counter for insert
}
p - > b - > a [ p - > b - > asize ] = p - > a ; // add author
p - > b - > asize + + ;
2016-12-30 14:54:32 +00:00
item = p ;
2016-12-30 14:40:21 +00:00
p = p - > p ;
2016-12-30 14:54:32 +00:00
free ( item ) ;
2016-12-30 14:40:21 +00:00
}
2016-12-29 23:38:31 +00:00
ksql_stmt_free ( stmt ) ;
2016-12-30 14:40:21 +00:00
return count ;
2016-12-29 23:38:31 +00:00
}
2016-12-30 09:10:55 +00:00
Book *
2016-12-29 20:02:58 +00:00
db_book_load ( struct kreq * r , int64_t id )
{
struct ksqlstmt * stmt ;
2016-12-30 09:10:55 +00:00
Book * book ;
2016-12-30 09:15:14 +00:00
2016-12-29 20:02:58 +00:00
ksql_stmt_alloc ( r - > arg , & stmt ,
stmts [ STMT_BOOK ] ,
STMT_BOOK ) ;
ksql_bind_int ( stmt , 0 , id ) ;
if ( KSQL_ROW ! = ksql_stmt_step ( stmt ) ) {
ksql_stmt_free ( stmt ) ;
return ( NULL ) ;
}
2016-12-30 09:10:55 +00:00
book = kcalloc ( 1 , sizeof ( Book ) ) ;
2016-12-30 10:37:08 +00:00
db_book_fill ( book , stmt ) ;
2016-12-29 20:02:58 +00:00
ksql_stmt_free ( stmt ) ;
return book ;
}
2016-12-18 15:50:56 +00:00
/*
2016-12-29 19:41:31 +00:00
* Open the database and stash the resulting handle in the d
2016-12-18 15:50:56 +00:00
*/
int
db_open ( struct kreq * r , const char * file )
{
2016-12-29 19:41:31 +00:00
struct ksqlcfg cfg ;
struct ksql * sql ;
2016-12-18 15:50:56 +00:00
2016-12-29 19:41:31 +00:00
/* Configure normal database except with foreign keys. */
memset ( & cfg , 0 , sizeof ( struct ksqlcfg ) ) ;
cfg . flags = KSQL_EXIT_ON_ERR |
KSQL_FOREIGN_KEYS |
KSQL_SAFE_EXIT ;
cfg . err = ksqlitemsg ;
cfg . dberr = ksqlitedbmsg ;
/* Allocate database. */
if ( NULL = = ( sql = ksql_alloc ( & cfg ) ) )
return ( 0 ) ;
ksql_open ( sql , file ) ;
r - > arg = sql ;
return ( 1 ) ;
2016-12-18 15:50:56 +00:00
}
/*
* Close the database stashed in the kreq ' s argument .
*/
void
db_close ( struct kreq * r )
{
2016-12-29 19:41:31 +00:00
ksql_free ( r - > arg ) ;
r - > arg = NULL ;
2016-12-18 15:50:56 +00:00
}