From 4e3b29f50208cfad1980e27aa60a74aaa6714221 Mon Sep 17 00:00:00 2001 From: Julien BLACHE Date: Sun, 7 Jun 2009 18:59:59 +0200 Subject: [PATCH] Remove the old database code --- src/db-generic.c | 688 ------------------ src/db-generic.h | 133 ---- src/db-sql-sqlite3.c | 576 --------------- src/db-sql-sqlite3.h | 42 -- src/db-sql-updates.c | 418 ----------- src/db-sql.c | 1649 ------------------------------------------ src/db-sql.h | 126 ---- src/ff-dbstruct.h | 199 ----- 8 files changed, 3831 deletions(-) delete mode 100644 src/db-generic.c delete mode 100644 src/db-generic.h delete mode 100644 src/db-sql-sqlite3.c delete mode 100644 src/db-sql-sqlite3.h delete mode 100644 src/db-sql-updates.c delete mode 100644 src/db-sql.c delete mode 100644 src/db-sql.h delete mode 100644 src/ff-dbstruct.h diff --git a/src/db-generic.c b/src/db-generic.c deleted file mode 100644 index 487abc08..00000000 --- a/src/db-generic.c +++ /dev/null @@ -1,688 +0,0 @@ -/* - * Generic db implementation for specific sql backend - * - * Copyright (C) 2005 Ron Pedde (ron@pedde.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#define _XOPEN_SOURCE 500 /** unix98? pthread_once_t, etc */ - -#include -#include -#include -#include -#ifdef HAVE_STRING_H -# include -#endif -#ifdef HAVE_STRINGS_H -# include -#endif -#ifdef HAVE_STDINT_H -# include -#endif - -#include "db-generic.h" -#include "logger.h" - -#include "db-sql.h" - -#define DB_VERSION 1 -#define MAYBEFREE(a) { if((a)) free((a)); }; - -/** pointers to database-specific functions */ -typedef struct tag_db_functions { - char *name; - int(*dbs_open)(char **, char *); - int(*dbs_init)(int); - int(*dbs_deinit)(void); - int(*dbs_add)(char **, MP3FILE*, int*); - int(*dbs_add_playlist)(char **, char *, int, char *,char *, int, int *); - int(*dbs_add_playlist_item)(char **, int, int); - int(*dbs_delete_playlist)(char **, int); - int(*dbs_delete_playlist_item)(char **, int, int); - int(*dbs_edit_playlist)(char **, int, char*, char*); - int(*dbs_playcount_increment)(char **, int); - int(*dbs_enum_start)(char **, DBQUERYINFO *); - int(*dbs_enum_fetch_row)(char **, PACKED_MP3FILE **, DBQUERYINFO *); - int(*dbs_enum_reset)(char **, DBQUERYINFO *); - int(*dbs_enum_end)(char **); - int(*dbs_force_rescan)(char **); - int(*dbs_start_scan)(void); - int(*dbs_end_song_scan)(void); - int(*dbs_end_scan)(void); - int(*dbs_get_count)(char **, int *, CountType_t); - MP3FILE*(*dbs_fetch_item)(char **, int); - MP3FILE*(*dbs_fetch_path)(char **, char *,int); - M3UFILE*(*dbs_fetch_playlist)(char **, char *, int); - void(*dbs_dispose_item)(MP3FILE*); - void(*dbs_dispose_playlist)(M3UFILE*); -}DB_FUNCTIONS; - -/** All supported backend databases, and pointers to the db specific implementations */ -DB_FUNCTIONS db_functions[] = { -#ifdef HAVE_SQLITE3 - { - "sqlite3", - db_sql_open_sqlite3, - db_sql_init, - db_sql_deinit, - db_sql_add, - db_sql_add_playlist, - db_sql_add_playlist_item, - db_sql_delete_playlist, - db_sql_delete_playlist_item, - db_sql_edit_playlist, - db_sql_playcount_increment, - db_sql_enum_start, - db_sql_enum_fetch_row, - db_sql_enum_reset, - db_sql_enum_end, - db_sql_force_rescan, - db_sql_start_scan, - db_sql_end_song_scan, - db_sql_end_scan, - db_sql_get_count, - db_sql_fetch_item, - db_sql_fetch_path, - db_sql_fetch_playlist, - db_sql_dispose_item, - db_sql_dispose_playlist - }, -#endif - { NULL,NULL } -}; -char *db_error_list[] = { - "Success", - "Misc SQL Error: %s", - "Duplicate Playlist: %s", - "Missing playlist spec", - "Cannot add playlist items to a playlist of that type", - "No rows returned", - "Invalid playlist id: %d", - "Invalid song id: %d", - "Parse error: %s", - "No backend database support for type: %s", - "Could not initialize thread pool", - "Passed buffer too small for result", - "Wrong db schema. Use mtd-update to upgrade the db.", - "Database error: %s", - "Malloc error", - "Path not found" -}; - -/* Globals */ -static DB_FUNCTIONS *db_current=&db_functions[0]; /**< current database backend */ -static int db_revision_no=2; /**< current revision of the db */ -static pthread_once_t db_initlock=PTHREAD_ONCE_INIT; /**< to initialize the rwlock */ -static int db_is_scanning=0; -static pthread_rwlock_t db_rwlock; /**< pthread r/w sync for the database */ - -/* Forwards */ -static void db_writelock(void); -static void db_readlock(void); -static int db_unlock(void); -static void db_init_once(void); -static void db_utf8_validate(MP3FILE *pmp3); -static int db_utf8_validate_string(char *string); -static void db_trim_strings(MP3FILE *pmp3); -static void db_trim_string(char *string); - -/* - * db_readlock - * - * If this fails, something is so amazingly hosed, we might just as well - * terminate. - */ -void db_readlock(void) { - int err; - - DPRINTF(E_SPAM,L_LOCK,"entering db_readlock\n"); - if((err=pthread_rwlock_rdlock(&db_rwlock))) { - DPRINTF(E_FATAL,L_DB,"cannot lock rdlock: %s\n",strerror(err)); - } - DPRINTF(E_SPAM,L_LOCK,"db_readlock acquired\n"); -} - -/* - * db_writelock - * - * same as above - */ -void db_writelock(void) { - int err; - - DPRINTF(E_SPAM,L_LOCK,"entering db_writelock\n"); - if((err=pthread_rwlock_wrlock(&db_rwlock))) { - DPRINTF(E_FATAL,L_DB,"cannot lock rwlock: %s\n",strerror(err)); - } - DPRINTF(E_SPAM,L_LOCK,"db_writelock acquired\n"); -} - -/* - * db_unlock - * - * useless, but symmetrical - */ -int db_unlock(void) { - DPRINTF(E_SPAM,L_LOCK,"releasing db lock\n"); - return pthread_rwlock_unlock(&db_rwlock); -} - -/** - * Build an error string - */ -void db_get_error(char **pe, int error, ...) { - va_list ap; - char errbuf[1024]; - - if(!pe) - return; - - va_start(ap, error); - vsnprintf(errbuf, sizeof(errbuf), db_error_list[error], ap); - va_end(ap); - - DPRINTF(E_SPAM,L_MISC,"Raising error: %s\n",errbuf); - - *pe = strdup(errbuf); -} - -/** - * Must dynamically initialize the rwlock, as Mac OSX 10.3 (at least) - * doesn't have a static initializer for rwlocks - */ -void db_init_once(void) { - pthread_rwlock_init(&db_rwlock,NULL); -} - -/** - * Open the database. This is done before we drop privs, that - * way if the database only has root perms, then it can still - * be opened. - * - * \param parameters This is backend-specific (mysql, sqlite, etc) - */ -int db_open(char **pe, char *type, char *parameters) { - int result; - - DPRINTF(E_DBG,L_DB,"Opening database\n"); - - if(pthread_once(&db_initlock,db_init_once)) - return -1; - - db_current = &db_functions[0]; - if(type) { - while((db_current->name) && (strcasecmp(db_current->name,type))) { - db_current++; - } - - if(!db_current->name) { - /* end of list -- no match */ - db_get_error(pe,DB_E_BADPROVIDER,type); - return DB_E_BADPROVIDER; - } - } - - result=db_current->dbs_open(pe, parameters); - - - DPRINTF(E_DBG,L_DB,"Results: %d\n",result); - return result; -} - -/** - * Initialize the database, including marking it for full reload if necessary. - * - * \param reload whether or not to do a full reload of the database - */ -int db_init(int reload) { - return db_current->dbs_init(reload); -} - -/** - * Close the database. - */ -int db_deinit(void) { - return db_current->dbs_deinit(); -} - -/** - * return the current db revision. this is mostly to determine - * when its time to send an updated version to the client - */ -int db_revision(void) { - int revision; - - db_readlock(); - revision=db_revision_no; - db_unlock(); - - return revision; -} - -/** - * is the db currently in scanning mode? - */ -int db_scanning(void) { - return db_is_scanning; -} - -/** - * add (or update) a file - */ -int db_add(char **pe, MP3FILE *pmp3, int *id) { - int retval; - - db_writelock(); - db_utf8_validate(pmp3); - db_trim_strings(pmp3); - retval=db_current->dbs_add(pe,pmp3,id); - db_revision_no++; - db_unlock(); - - return retval; -} - -/** - * add a playlist - * - * \param name name of playlist to add - * \param type type of playlist to add: 0 - static, 1 - smart, 2 - m3u - * \param clause where clause (if type 1) - * \param playlistid returns the id of the playlist created - * \returns 0 on success, error code otherwise - */ -int db_add_playlist(char **pe, char *name, int type, char *clause, char *path, int index, int *playlistid) { - int retval; - - db_writelock(); - retval=db_current->dbs_add_playlist(pe,name,type,clause,path,index,playlistid); - if(retval == DB_E_SUCCESS) - db_revision_no++; - db_unlock(); - - return retval; -} - -/** - * add a song to a static playlist - * - * \param playlistid playlist to add song to - * \param songid song to add to playlist - * \returns 0 on success, DB_E_ code otherwise - */ -int db_add_playlist_item(char **pe, int playlistid, int songid) { - int retval; - - db_writelock(); - retval=db_current->dbs_add_playlist_item(pe,playlistid,songid); - if(retval == DB_E_SUCCESS) - db_revision_no++; - db_unlock(); - - return retval; -} - -/** - * delete a playlist - * - * \param playlistid id of the playlist to delete - * \returns 0 on success, error code otherwise - */ -int db_delete_playlist(char **pe, int playlistid) { - int retval; - - db_writelock(); - retval=db_current->dbs_delete_playlist(pe,playlistid); - if(retval == DB_E_SUCCESS) - db_revision_no++; - db_unlock(); - - return retval; -} - -/** - * delete an item from a playlist - * - * \param playlistid id of the playlist to delete - * \param songid id of the song to delete - * \returns 0 on success, error code otherwise - */ -int db_delete_playlist_item(char **pe, int playlistid, int songid) { - int retval; - - db_writelock(); - retval=db_current->dbs_delete_playlist_item(pe,playlistid,songid); - if(retval == DB_E_SUCCESS) - db_revision_no++; - db_unlock(); - - return retval; -} - -/** - * edit a playlist - * - * @param id playlist id to edit - * @param name new name of playlist - * @param clause new where clause - */ -int db_edit_playlist(char **pe, int id, char *name, char *clause) { - int retval; - - db_writelock(); - - retval = db_current->dbs_edit_playlist(pe, id, name, clause); - db_unlock(); - return retval; -} - - -/** - * increment the playcount info for a particular song - * (play_count and time_played). - * - * @param pe error string - * @param id id of song to incrmrent - * @returns DB_E_SUCCESS on success, error code otherwise - */ -int db_playcount_increment(char **pe, int id) { - int retval; - - db_writelock(); - retval = db_current->dbs_playcount_increment(pe, id); - db_unlock(); - - return retval; -} - -/** - * start a db enumeration, based info in the DBQUERYINFO struct - * - * \param pinfo pointer to DBQUERYINFO struction - * \returns 0 on success, -1 on failure - */ -int db_enum_start(char **pe, DBQUERYINFO *pinfo) { - int retval; - - db_writelock(); - retval=db_current->dbs_enum_start(pe, pinfo); - - if(retval) { - db_unlock(); - return retval; - } - - return 0; -} - -/** - * fetch the next item int he result set started by the db enum. this - * will be in native packed row format - */ -int db_enum_fetch_row(char **pe, PACKED_MP3FILE **row, DBQUERYINFO *pinfo) { - return db_current->dbs_enum_fetch_row(pe, row, pinfo); -} - - -/** - * reset the enum, without coming out the the db_writelock - */ -int db_enum_reset(char **pe, DBQUERYINFO *pinfo) { - return db_current->dbs_enum_reset(pe,pinfo); -} - -/** - * finish the enumeration - */ -int db_enum_end(char **pe) { - int retval; - - retval=db_current->dbs_enum_end(pe); - db_unlock(); - return retval; -} - - -/** - * fetch a MP3FILE struct given an id. This will be done - * mostly only by the web interface, and when streaming a song - * - * \param id id of the item to get details for - */ -MP3FILE *db_fetch_item(char **pe, int id) { - MP3FILE *retval; - - db_readlock(); - retval=db_current->dbs_fetch_item(pe, id); - db_unlock(); - - return retval; -} - -MP3FILE *db_fetch_path(char **pe, char *path,int index) { - MP3FILE *retval; - - db_readlock(); - retval=db_current->dbs_fetch_path(pe,path, index); - db_unlock(); - - return retval; -} - -M3UFILE *db_fetch_playlist(char **pe, char *path, int index) { - M3UFILE *retval; - - db_readlock(); - retval=db_current->dbs_fetch_playlist(pe,path,index); - db_unlock(); - - return retval; -} - -int db_force_rescan(char **pe) { - int retval; - db_writelock(); - retval = db_current->dbs_force_rescan(pe); - db_unlock(); - - return retval; -} - -int db_start_scan(void) { - int retval; - - db_writelock(); - retval=db_current->dbs_start_scan(); - db_is_scanning=1; - db_unlock(); - - return retval; -} - -int db_end_song_scan(void) { - int retval; - - db_writelock(); - retval=db_current->dbs_end_song_scan(); - db_unlock(); - - return retval; -} - -int db_end_scan(void) { - int retval; - - db_writelock(); - retval=db_current->dbs_end_scan(); - db_is_scanning=0; - db_unlock(); - - return retval; -} - -void db_dispose_item(MP3FILE *pmp3) { - db_current->dbs_dispose_item(pmp3); -} - -void db_dispose_playlist(M3UFILE *pm3u) { - db_current->dbs_dispose_playlist(pm3u); -} - -int db_get_count(char **pe, int *count, CountType_t type) { - int retval; - - db_readlock(); - retval=db_current->dbs_get_count(pe,count,type); - db_unlock(); - - return retval; -} - - -/* - * FIXME: clearly a stub - */ -int db_get_song_count(char **pe, int *count) { - return db_get_count(pe, count, countSongs); -} - -int db_get_playlist_count(char **pe, int *count) { - return db_get_count(pe, count, countPlaylists); -} - - -/** - * check the strings in a MP3FILE to ensure they are - * valid utf-8. If they are not, the string will be corrected - * - * \param pmp3 MP3FILE to verify for valid utf-8 - */ -void db_utf8_validate(MP3FILE *pmp3) { - int is_invalid=0; - - /* we won't bother with path and fname... those were culled with the - * scan. Even if they are invalid (_could_ they be?), then we - * won't be able to open the file if we change them. Likewise, - * we won't do type or description, as these can't be bad, or they - * wouldn't have been scanned */ - - is_invalid = db_utf8_validate_string(pmp3->title); - is_invalid |= db_utf8_validate_string(pmp3->artist); - is_invalid |= db_utf8_validate_string(pmp3->album); - is_invalid |= db_utf8_validate_string(pmp3->genre); - is_invalid |= db_utf8_validate_string(pmp3->comment); - is_invalid |= db_utf8_validate_string(pmp3->composer); - is_invalid |= db_utf8_validate_string(pmp3->orchestra); - is_invalid |= db_utf8_validate_string(pmp3->conductor); - is_invalid |= db_utf8_validate_string(pmp3->grouping); - is_invalid |= db_utf8_validate_string(pmp3->url); - - if(is_invalid) { - DPRINTF(E_LOG,L_SCAN,"Invalid UTF-8 in %s\n",pmp3->path); - } -} - -/** - * check a string to verify it is valid utf-8. The passed - * string will be in-place modified to be utf-8 clean by substituting - * the character '?' for invalid utf-8 codepoints - * - * \param string string to clean - */ -int db_utf8_validate_string(char *string) { - char *current = string; - int run,r_current; - int retval=0; - - if(!string) - return 0; - - while(*current) { - if(!((*current) & 0x80)) { - current++; - } else { - run=0; - - /* it's a lead utf-8 character */ - if((*current & 0xE0) == 0xC0) run=1; - if((*current & 0xF0) == 0xE0) run=2; - if((*current & 0xF8) == 0xF0) run=3; - - if(!run) { - /* high bit set, but invalid */ - *current++='?'; - retval=1; - } else { - r_current=0; - while((r_current != run) && (*(current + r_current + 1)) && - ((*(current + r_current + 1) & 0xC0) == 0x80)) { - r_current++; - } - - if(r_current != run) { - *current++ = '?'; - retval=1; - } else { - current += (1 + run); - } - } - } - } - - return retval; -} - -/** - * Trim the spaces off the string values. It throws off - * browsing when there are some with and without spaces. - * This should probably be better fixed by having clean tags, - * but seemed simple enough, and it does make sense that - * while we are cleaning tags for, say, utf-8 hygene we might - * as well get this too. - * - * @param pmp3 mp3 struct to fix - */ -void db_trim_strings(MP3FILE *pmp3) { - db_trim_string(pmp3->title); - db_trim_string(pmp3->artist); - db_trim_string(pmp3->album); - db_trim_string(pmp3->genre); - db_trim_string(pmp3->comment); - db_trim_string(pmp3->composer); - db_trim_string(pmp3->orchestra); - db_trim_string(pmp3->conductor); - db_trim_string(pmp3->grouping); - db_trim_string(pmp3->url); -} - -/** - * trim trailing spaces in a string. Used by db_trim_strings - * - * @param string string to trim - */ -void db_trim_string(char *string) { - if(!string) - return; - - while(strlen(string) && (string[strlen(string) - 1] == ' ')) - string[strlen(string) - 1] = '\0'; -} - diff --git a/src/db-generic.h b/src/db-generic.h deleted file mode 100644 index ddf7b0ef..00000000 --- a/src/db-generic.h +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Header info for generic database - * - * Copyright (C) 2005 Ron Pedde (ron@pedde.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _DB_GENERIC_H_ -#define _DB_GENERIC_H_ - -#include "ff-dbstruct.h" /** for MP3FILE */ - -typedef enum { - queryTypeItems, - queryTypePlaylists, - queryTypePlaylistItems, - queryTypeBrowseArtists, - queryTypeBrowseAlbums, - queryTypeBrowseGenres, - queryTypeBrowseComposers -} QueryType_t; - -typedef enum { - indexTypeNone, - indexTypeFirst, - indexTypeLast, - indexTypeSub -} IndexType_t; - -typedef enum { - countSongs, - countPlaylists -} CountType_t; - -typedef struct tag_dbqueryinfo { - QueryType_t query_type; - IndexType_t index_type; - int zero_length; /* emit zero-length strings? */ - int index_low; - int index_high; - int playlist_id; - int db_id; - int session_id; - int want_count; - int specifiedtotalcount; - int uri_count; - int correct_order; - char *uri_sections[10]; - char *filter; /* SQL WHERE clause */ - void *output_info; -} DBQUERYINFO; - -extern int db_open(char **pe, char *type, char *parameters); -extern int db_init(int reload); -extern int db_deinit(void); - -extern int db_revision(void); - -extern int db_add(char **pe, MP3FILE *pmp3, int *id); - -extern int db_enum_start(char **pe, DBQUERYINFO *pinfo); -extern int db_enum_fetch_row(char **pe, PACKED_MP3FILE **row, DBQUERYINFO *pinfo); -extern int db_enum_reset(char **pe, DBQUERYINFO *pinfo); -extern int db_enum_end(char **pe); -extern int db_start_scan(void); -extern int db_end_song_scan(void); -extern int db_end_scan(void); -extern int db_exists(char *path); -extern int db_scanning(void); - -extern int db_add_playlist(char **pe, char *name, int type, char *clause, char *path, int index, int *playlistid); -extern int db_add_playlist_item(char **pe, int playlistid, int songid); -extern int db_edit_playlist(char **pe, int id, char *name, char *clause); -extern int db_delete_playlist(char **pe, int playlistid); -extern int db_delete_playlist_item(char **pe, int playlistid, int songid); - -extern void db_get_error(char **pe, int err, ...); - -extern MP3FILE *db_fetch_item(char **pe, int id); -extern MP3FILE *db_fetch_path(char **pe, char *path, int index); -extern M3UFILE *db_fetch_playlist(char **pe, char *path, int index); - - -/* Holdover functions from old db interface... - * should these be removed? Refactored? - */ - -extern int db_playcount_increment(char **pe, int id); -extern int db_get_song_count(char **pe, int *count); -extern int db_get_playlist_count(char **pe, int *count); -extern void db_dispose_item(MP3FILE *pmp3); -extern void db_dispose_playlist(M3UFILE *pm3u); -extern int db_force_rescan(char **pe); - -#define DB_E_SUCCESS 0x00 -#define DB_E_SQL_ERROR 0x01 /**< some kind of sql error - typically bad syntax */ -#define DB_E_DUPLICATE_PLAYLIST 0x02 /**< playlist already exists when adding */ -#define DB_E_NOCLAUSE 0x03 /**< adding smart playlist with no clause */ -#define DB_E_INVALIDTYPE 0x04 /**< trying to add playlist items to invalid type */ -#define DB_E_NOROWS 0x05 /**< sql query returned no rows */ -#define DB_E_INVALID_PLAYLIST 0x06 /**< bad playlist id */ -#define DB_E_INVALID_SONGID 0x07 /**< bad song id */ -#define DB_E_PARSE 0x08 /**< could not parse result */ -#define DB_E_BADPROVIDER 0x09 /**< requested db backend not there */ -#define DB_E_PROC 0x0A /**< could not start threadpool */ -#define DB_E_SIZE 0x0B /**< passed buffer too small */ -#define DB_E_WRONGVERSION 0x0C /**< must upgrade db */ -#define DB_E_MALLOC 0x0E /**< malloc error */ -#define DB_E_NOTFOUND 0x0F /**< path not found */ - -/* describes the individual database handlers */ -typedef struct tag_dbinfo { - char *handler_name; - char *description; - int stores_playlists; -} DB_INFO; - - - -#endif /* _DB_GENERIC_H_ */ diff --git a/src/db-sql-sqlite3.c b/src/db-sql-sqlite3.c deleted file mode 100644 index 3348771e..00000000 --- a/src/db-sql-sqlite3.c +++ /dev/null @@ -1,576 +0,0 @@ -/* - * sqlite3-specific db implementation - * - * Copyright (C) 2005 Ron Pedde (ron@pedde.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* - * This file handles sqlite3 databases. SQLite3 databases - * should have a dsn of: - * - * sqlite3:/path/to/folder - * - * The actual db will be appended to the passed path. - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#define _XOPEN_SOURCE 500 - -#include -#include -#include -#include -#include -#include -#include -#ifdef HAVE_STDINT_H -#include -#endif -#ifdef HAVE_UNISTD_H -# include -#endif - -#include "logger.h" -#include "db-generic.h" -#include "db-sql.h" -#include "db-sql-sqlite3.h" - -#ifndef TRUE -# define TRUE 1 -# define FALSE 0 -#endif - - -/* Globals */ -static pthread_mutex_t db_sqlite3_mutex = PTHREAD_MUTEX_INITIALIZER; /**< sqlite not reentrant */ -static sqlite3_stmt *db_sqlite3_stmt; -static const char *db_sqlite3_ptail; -static int db_sqlite3_finalized; -static int db_sqlite3_reload=0; -static char *db_sqlite3_enum_query=NULL; -static char **db_sqlite3_row = NULL; -static pthread_key_t db_sqlite3_key; -static char db_sqlite3_path[PATH_MAX + 1]; - -#define DB_SQLITE3_VERSION 13 - - -/* Forwards */ -void db_sqlite3_lock(void); -void db_sqlite3_unlock(void); -extern char *db_sqlite3_initial1; -extern char *db_sqlite3_initial2; -int db_sqlite3_enum_begin_helper(char **pe); - - - -/** - * get (or create) the db handle - */ -sqlite3 *db_sqlite3_handle(void) { - sqlite3 *pdb = NULL; - char *pe = NULL; - - pdb = (sqlite3*)pthread_getspecific(db_sqlite3_key); - if(pdb == NULL) { /* don't have a handle yet */ - DPRINTF(E_DBG,L_DB,"Creating new db handle\n"); - if(sqlite3_open(db_sqlite3_path,&pdb) != SQLITE_OK) { - db_get_error(&pe,DB_E_SQL_ERROR,sqlite3_errmsg(pdb)); - DPRINTF(E_FATAL,L_DB,"db_sqlite3_open: %s (%s)\n",pe,db_sqlite3_path); - db_sqlite3_unlock(); - return NULL; - } - sqlite3_busy_timeout(pdb,30000); /* 30 seconds */ - pthread_setspecific(db_sqlite3_key,(void*)pdb); - } - - return pdb; -} - -/** - * free a thread-specific db handle - */ -void db_sqlite3_freedb(sqlite3 *pdb) { - sqlite3_close(pdb); -} - -/** - * lock the db_mutex - */ -void db_sqlite3_lock(void) { - int err; - - if((err=pthread_mutex_lock(&db_sqlite3_mutex))) { - DPRINTF(E_FATAL,L_DB,"cannot lock sqlite lock: %s\n",strerror(err)); - } -} - -/** - * unlock the db_mutex - */ -void db_sqlite3_unlock(void) { - int err; - - if((err=pthread_mutex_unlock(&db_sqlite3_mutex))) { - DPRINTF(E_FATAL,L_DB,"cannot unlock sqlite3 lock: %s\n",strerror(err)); - } -} - -/** - * - */ -char *db_sqlite3_vmquery(char *fmt,va_list ap) { - return sqlite3_vmprintf(fmt,ap); -} - -/** - * - */ -void db_sqlite3_vmfree(char *query) { - sqlite3_free(query); -} - - -/** - * open a sqlite3 database - * - * @param dsn the full dns to the database - * (sqlite3:/path/to/database) - * - * @returns DB_E_SUCCESS on success - */ -int db_sqlite3_open(char **pe, char *dsn) { - int ver; - int err; - sqlite3 *pdb; - - pthread_key_create(&db_sqlite3_key, (void*)db_sqlite3_freedb); - snprintf(db_sqlite3_path,sizeof(db_sqlite3_path),"%s/songs3.db",dsn); - - db_sqlite3_lock(); - if(sqlite3_open(db_sqlite3_path,&pdb) != SQLITE_OK) { - db_get_error(pe,DB_E_SQL_ERROR,sqlite3_errmsg(pdb)); - DPRINTF(E_LOG,L_DB,"db_sqlite3_open: %s (%s)\n",pe ? *pe : "Unknown", - db_sqlite3_path); - db_sqlite3_unlock(); - return DB_E_SQL_ERROR; - } - sqlite3_close(pdb); - db_sqlite3_unlock(); - - err = db_sql_fetch_int(pe,&ver,"select value from config where " - "term='version'"); - if(err != DB_E_SUCCESS) { - if(pe) { free(*pe); } - /* we'll catch this on the init */ - DPRINTF(E_LOG,L_DB,"Can't get db version. New database?\n"); - } else if(ver < DB_SQLITE3_VERSION) { - DPRINTF(E_LOG,L_DB,"Old database version: %d, expecting %d\n", - ver,DB_SQLITE3_VERSION); - db_get_error(pe,DB_E_WRONGVERSION); - return DB_E_WRONGVERSION; - } else if(ver > DB_SQLITE3_VERSION) { - db_sqlite3_exec(pe,E_FATAL,"insert into config (term, value) " - "values ('rescan',1)"); - } - - return DB_E_SUCCESS; -} - -/** - * close the database - */ -int db_sqlite3_close(void) { - /* this doens't actually make much sense, as the closes get done by the threads */ - return DB_E_SUCCESS; -} - -/** - * execute a throwaway query against the database, disregarding - * the outcome - * - * @param pe db error structure - * @param loglevel error level to return if the query fails - * @param fmt sprintf-style arguements - * - * @returns DB_E_SUCCESS on success - */ -int db_sqlite3_exec(char **pe, int loglevel, char *fmt, ...) { - va_list ap; - char *query; - int err; - char *perr; - - db_sqlite3_lock(); - - va_start(ap,fmt); - query=sqlite3_vmprintf(fmt,ap); - va_end(ap); - - DPRINTF(E_DBG,L_DB,"Executing: %s\n",query); - - err=sqlite3_exec(db_sqlite3_handle(),query,NULL,NULL,&perr); - if(err != SQLITE_OK) { - db_get_error(pe,DB_E_SQL_ERROR,perr); - - DPRINTF(loglevel == E_FATAL ? E_LOG : loglevel,L_DB,"Query: %s\n", - query); - DPRINTF(loglevel,L_DB,"Error: %s\n",perr); - sqlite3_free(perr); - } else { - DPRINTF(E_DBG,L_DB,"Rows: %d\n",sqlite3_changes(db_sqlite3_handle())); - } - sqlite3_free(query); - - db_sqlite3_unlock(); - - if(err != SQLITE_OK) - return DB_E_SQL_ERROR; - return DB_E_SUCCESS; -} - -/** - * start enumerating rows in a select - */ -int db_sqlite3_enum_begin(char **pe, char *fmt, ...) { - va_list ap; - - db_sqlite3_lock(); - va_start(ap, fmt); - db_sqlite3_enum_query = sqlite3_vmprintf(fmt,ap); - va_end(ap); - - db_sqlite3_finalized=0; - return db_sqlite3_enum_begin_helper(pe); -} - -int db_sqlite3_enum_begin_helper(char **pe) { - int err; - - if(!db_sqlite3_enum_query) - *((int*)NULL) = 1; - - DPRINTF(E_DBG,L_DB,"Executing: %s\n",db_sqlite3_enum_query); - err=sqlite3_prepare(db_sqlite3_handle(),db_sqlite3_enum_query,-1, - &db_sqlite3_stmt,&db_sqlite3_ptail); - - if(err != SQLITE_OK) { - db_get_error(pe,DB_E_SQL_ERROR,sqlite3_errmsg(db_sqlite3_handle())); - sqlite3_free(db_sqlite3_enum_query); - db_sqlite3_enum_query=NULL; - db_sqlite3_unlock(); - return DB_E_SQL_ERROR; - } - - DPRINTF(E_SPAM,L_DB,"Prepared statement: %08X\n",db_sqlite3_stmt); - - /* otherwise, we leave the db locked while we walk through the enums */ - if(db_sqlite3_row) - free(db_sqlite3_row); - db_sqlite3_row=NULL; - - return DB_E_SUCCESS; - -} - -/** - * fetch the next row. This will return DB_E_SUCCESS if it got a - * row, or it's done. If it's done, the row will be empty, otherwise - * it will be full of data. Either way, if fetch fails, you must close. - * - * @param pe error string, if result isn't DB_E_SUCCESS - * @param pr pointer to a row struct - * - * @returns DB_E_SUCCESS with *pr=NULL when end of table, - * DB_E_SUCCESS with a valid row when more data, - * DB_E_* on error - */ -int db_sqlite3_enum_fetch(char **pe, SQL_ROW *pr) { - int err; - int cols; - int idx; - int counter=10; - - if(!db_sqlite3_enum_query) - *((int*)NULL) = 1; - - while(counter--) { - DPRINTF(E_SPAM,L_DB,"Fetching statement: %08X\n",db_sqlite3_stmt); - err=sqlite3_step(db_sqlite3_stmt); - if(err != SQLITE_BUSY) - break; - usleep(1000); - } - - if(err == SQLITE_DONE) { - *pr = NULL; - if(db_sqlite3_row) - free(db_sqlite3_row); - db_sqlite3_row = NULL; - return DB_E_SUCCESS; - } - - if(err == SQLITE_ROW) { - DPRINTF(E_SPAM,L_DB,"Got row\n"); - cols = sqlite3_column_count(db_sqlite3_stmt); - - if(!db_sqlite3_row) { - /* gotta alloc space */ - db_sqlite3_row = (char**)malloc((sizeof(char*)) * cols); - if(!db_sqlite3_row) - DPRINTF(E_FATAL,L_DB,"Malloc error\n"); - } - - for(idx=0; idx < cols; idx++) { - db_sqlite3_row[idx] = (char*) sqlite3_column_blob(db_sqlite3_stmt,idx); - } - - *pr = db_sqlite3_row; - return DB_E_SUCCESS; - } - - if(db_sqlite3_row) - free(db_sqlite3_row); - db_sqlite3_row = NULL; - - db_get_error(pe,DB_E_SQL_ERROR,sqlite3_errmsg(db_sqlite3_handle())); - DPRINTF(E_SPAM,L_DB,"Finalizing statement: %08X\n",db_sqlite3_stmt); - sqlite3_finalize(db_sqlite3_stmt); - db_sqlite3_finalized=1; - - return DB_E_SQL_ERROR; -} - -/** - * end the db enumeration - */ -int db_sqlite3_enum_end(char **pe) { - int err; - - if(!db_sqlite3_enum_query) - *((int*)NULL) = 1; - - if(db_sqlite3_row) - free(db_sqlite3_row); - db_sqlite3_row = NULL; - sqlite3_free(db_sqlite3_enum_query); - db_sqlite3_enum_query = NULL; - - if(!db_sqlite3_finalized) { - DPRINTF(E_SPAM,L_DB,"Finalizing statement: %08X\n",db_sqlite3_stmt); - err = sqlite3_finalize(db_sqlite3_stmt); - if(err != SQLITE_OK) { - db_get_error(pe,DB_E_SQL_ERROR,sqlite3_errmsg(db_sqlite3_handle())); - db_sqlite3_unlock(); - return DB_E_SQL_ERROR; - } - } - - db_sqlite3_unlock(); - return DB_E_SUCCESS; -} - -/** - * restart the enumeration - */ -int db_sqlite3_enum_restart(char **pe) { - return db_sqlite3_enum_begin_helper(pe); -} - - -int db_sqlite3_event(int event_type) { - switch(event_type) { - - case DB_SQL_EVENT_STARTUP: /* this is a startup with existing songs */ - db_sqlite3_exec(NULL,E_DBG,"create index idx_path on " - "songs(path,idx)"); - db_sqlite3_exec(NULL,E_DBG,"create index idx_songid on " - "playlistitems(songid)"); - db_sqlite3_exec(NULL,E_DBG,"create index idx_playlistid on " - "playlistitems(playlistid,songid)"); - db_sqlite3_reload=0; - break; - - case DB_SQL_EVENT_FULLRELOAD: /* either a fresh load or force load */ - db_sqlite3_exec(NULL,E_DBG,"drop index idx_path"); - db_sqlite3_exec(NULL,E_DBG,"drop index idx_songid"); - db_sqlite3_exec(NULL,E_DBG,"drop index idx_playlistid"); - - db_sqlite3_exec(NULL,E_DBG,"drop table songs"); -// db_sqlite3_exec(NULL,E_DBG,"drop table playlists"); - db_sqlite3_exec(NULL,E_DBG,"delete from playlists where not type=1 and not type=0"); - db_sqlite3_exec(NULL,E_DBG,"drop table playlistitems"); - db_sqlite3_exec(NULL,E_DBG,"drop table config"); - - db_sqlite3_exec(NULL,E_DBG,"vacuum"); - - db_sqlite3_exec(NULL,E_DBG,db_sqlite3_initial1); - db_sqlite3_exec(NULL,E_DBG,db_sqlite3_initial2); - db_sqlite3_reload=1; - break; - - case DB_SQL_EVENT_SONGSCANSTART: - if(db_sqlite3_reload) { - db_sqlite3_exec(NULL,E_FATAL,"pragma synchronous = off"); - db_sqlite3_exec(NULL,E_FATAL,"begin transaction"); - } else { - db_sqlite3_exec(NULL,E_DBG,"drop table updated"); - db_sqlite3_exec(NULL,E_FATAL,"create temp table updated (id int)"); - db_sqlite3_exec(NULL,E_DBG,"drop table plupdated"); - db_sqlite3_exec(NULL,E_FATAL,"create temp table plupdated(id int)"); - } - break; - - case DB_SQL_EVENT_SONGSCANEND: - if(db_sqlite3_reload) { - db_sqlite3_exec(NULL,E_FATAL,"commit transaction"); - db_sqlite3_exec(NULL,E_FATAL,"pragma synchronous = normal"); - db_sqlite3_exec(NULL,E_FATAL,"create index idx_path on songs(path,idx)"); - db_sqlite3_exec(NULL,E_DBG,"delete from config where term='rescan'"); - } - break; - - case DB_SQL_EVENT_PLSCANSTART: - db_sqlite3_exec(NULL,E_FATAL,"pragma synchronous = off"); - db_sqlite3_exec(NULL,E_FATAL,"begin transaction"); - break; - - case DB_SQL_EVENT_PLSCANEND: - db_sqlite3_exec(NULL,E_FATAL,"end transaction"); - db_sqlite3_exec(NULL,E_FATAL,"pragma synchronous=normal"); - - if(db_sqlite3_reload) { - db_sqlite3_exec(NULL,E_FATAL,"create index idx_songid on playlistitems(songid)"); - db_sqlite3_exec(NULL,E_FATAL,"create index idx_playlistid on playlistitems(playlistid,songid)"); - - } else { - db_sqlite3_exec(NULL,E_FATAL,"delete from songs where id not in (select id from updated)"); - db_sqlite3_exec(NULL,E_FATAL,"update songs set force_update=0"); - db_sqlite3_exec(NULL,E_FATAL,"drop table updated"); - - db_sqlite3_exec(NULL,E_FATAL,"delete from playlists where " - "((type=%d) OR (type=%d)) and " - "id not in (select id from plupdated)", - PL_STATICFILE,PL_STATICXML); - db_sqlite3_exec(NULL,E_FATAL,"delete from playlistitems where " - "playlistid not in (select distinct " - "id from playlists)"); - db_sqlite3_exec(NULL,E_FATAL,"drop table plupdated"); - } - db_sqlite3_reload=0; - break; - - default: - break; - } - - return DB_E_SUCCESS; -} - -/** - * get the id of the last auto_update inserted item - * - * @returns autoupdate value - */ - -int db_sqlite3_insert_id(void) { - int result; - - db_sqlite3_lock(); - result = (int)sqlite3_last_insert_rowid(db_sqlite3_handle()); - db_sqlite3_unlock(); - - return result; -} - - - -char *db_sqlite3_initial1 = -"create table songs (\n" -" id INTEGER PRIMARY KEY NOT NULL,\n" -" path VARCHAR(4096) NOT NULL,\n" -" fname VARCHAR(255) NOT NULL,\n" -" title VARCHAR(1024) DEFAULT NULL,\n" -" artist VARCHAR(1024) DEFAULT NULL,\n" -" album VARCHAR(1024) DEFAULT NULL,\n" -" genre VARCHAR(255) DEFAULT NULL,\n" -" comment VARCHAR(4096) DEFAULT NULL,\n" -" type VARCHAR(255) DEFAULT NULL,\n" -" composer VARCHAR(1024) DEFAULT NULL,\n" -" orchestra VARCHAR(1024) DEFAULT NULL,\n" -" conductor VARCHAR(1024) DEFAULT NULL,\n" -" grouping VARCHAR(1024) DEFAULT NULL,\n" -" url VARCHAR(1024) DEFAULT NULL,\n" -" bitrate INTEGER DEFAULT 0,\n" -" samplerate INTEGER DEFAULT 0,\n" -" song_length INTEGER DEFAULT 0,\n" -" file_size INTEGER DEFAULT 0,\n" -" year INTEGER DEFAULT 0,\n" -" track INTEGER DEFAULT 0,\n" -" total_tracks INTEGER DEFAULT 0,\n" -" disc INTEGER DEFAULT 0,\n" -" total_discs INTEGER DEFAULT 0,\n" -" bpm INTEGER DEFAULT 0,\n" -" compilation INTEGER DEFAULT 0,\n" -" rating INTEGER DEFAULT 0,\n" -" play_count INTEGER DEFAULT 0,\n" -" data_kind INTEGER DEFAULT 0,\n" -" item_kind INTEGER DEFAULT 0,\n" -" description INTEGER DEFAULT 0,\n" -" time_added INTEGER DEFAULT 0,\n" -" time_modified INTEGER DEFAULT 0,\n" -" time_played INTEGER DEFAULT 0,\n" -" db_timestamp INTEGER DEFAULT 0,\n" -" disabled INTEGER DEFAULT 0,\n" -" sample_count INTEGER DEFAULT 0,\n" -" force_update INTEGER DEFAULT 0,\n" -" codectype VARCHAR(5) DEFAULT NULL,\n" -" idx INTEGER NOT NULL,\n" -" has_video INTEGER DEFAULT 0,\n" -" contentrating INTEGER DEFAULT 0,\n" -" bits_per_sample INTEGER DEFAULT 0,\n" -" album_artist VARCHAR(1024)\n" -");\n" -"create table playlistitems (\n" -" id INTEGER PRIMARY KEY NOT NULL,\n" -" playlistid INTEGER NOT NULL,\n" -" songid INTEGER NOT NULL\n" -");\n" -"create table config (\n" -" term VARCHAR(255) NOT NULL,\n" -" subterm VARCHAR(255) DEFAULT NULL,\n" -" value VARCHAR(1024) NOT NULL\n" -");\n" -"insert into config values ('version','','13');\n"; - -char *db_sqlite3_initial2 = -"create table playlists (\n" -" id INTEGER PRIMARY KEY NOT NULL,\n" -" title VARCHAR(255) NOT NULL,\n" -" type INTEGER NOT NULL,\n" -" items INTEGER NOT NULL,\n" -" query VARCHAR(1024),\n" -" db_timestamp INTEGER NOT NULL,\n" -" path VARCHAR(4096),\n" -" idx INTEGER NOT NULL\n" -");\n" -"insert into playlists values (1,'Library',1,0,'1',0,'',0);\n"; - - diff --git a/src/db-sql-sqlite3.h b/src/db-sql-sqlite3.h deleted file mode 100644 index 6858ac24..00000000 --- a/src/db-sql-sqlite3.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * sqlite3-specific db implementation - * - * Copyright (C) 2005 Ron Pedde (ron@pedde.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _DB_SQL_SQLITE3_ -#define _DB_SQL_SQLITE3_ - -extern int db_sqlite3_open(char **pe, char *dsn); -extern int db_sqlite3_close(void); - -/* simple utility functions */ -extern int db_sqlite3_exec(char **pe, int loglevel, char *fmt, ...); -extern char *db_sqlite3_vmquery(char *fmt,va_list ap); -extern void db_sqlite3_vmfree(char *query); - -/* walk through a table */ -extern int db_sqlite3_enum_begin(char **pe, char *fmt, ...); -extern int db_sqlite3_enum_fetch(char **pe, SQL_ROW *pr); -extern int db_sqlite3_enum_end(char **pe); -extern int db_sqlite3_enum_restart(char **pe); - -extern int db_sqlite3_event(int event_type); -extern int db_sqlite3_insert_id(void); - -#endif /* _DB_SQL_SQLITE3_ */ - diff --git a/src/db-sql-updates.c b/src/db-sql-updates.c deleted file mode 100644 index c59713a3..00000000 --- a/src/db-sql-updates.c +++ /dev/null @@ -1,418 +0,0 @@ -/* - * Commands to update database to new version - * - */ - -#include - -char *db_sqlite_updates[] = { - /* version 0 -> version 1 -- initial update */ - "CREATE TABLE songs (\n" - " id INTEGER PRIMARY KEY NOT NULL,\n" - " path VARCHAR(4096) UNIQUE NOT NULL,\n" - " fname VARCHAR(255) NOT NULL,\n" - " title VARCHAR(1024) DEFAULT NULL,\n" - " artist VARCHAR(1024) DEFAULT NULL,\n" - " album VARCHAR(1024) DEFAULT NULL,\n" - " genre VARCHAR(255) DEFAULT NULL,\n" - " comment VARCHAR(4096) DEFAULT NULL,\n" - " type VARCHAR(255) DEFAULT NULL,\n" - " composer VARCHAR(1024) DEFAULT NULL,\n" - " orchestra VARCHAR(1024) DEFAULT NULL,\n" - " conductor VARCHAR(1024) DEFAULT NULL,\n" - " grouping VARCHAR(1024) DEFAULT NULL,\n" - " url VARCHAR(1024) DEFAULT NULL,\n" - " bitrate INTEGER DEFAULT 0,\n" - " samplerate INTEGER DEFAULT 0,\n" - " song_length INTEGER DEFAULT 0,\n" - " file_size INTEGER DEFAULT 0,\n" - " year INTEGER DEFAULT 0,\n" - " track INTEGER DEFAULT 0,\n" - " total_tracks INTEGER DEFAULT 0,\n" - " disc INTEGER DEFAULT 0,\n" - " total_discs INTEGER DEFAULT 0,\n" - " bpm INTEGER DEFAULT 0,\n" - " compilation INTEGER DEFAULT 0,\n" - " rating INTEGER DEFAULT 0,\n" - " play_count INTEGER DEFAULT 0,\n" - " data_kind INTEGER DEFAULT 0,\n" - " item_kind INTEGER DEFAULT 0,\n" - " description INTEGER DEFAULT 0,\n" - " time_added INTEGER DEFAULT 0,\n" - " time_modified INTEGER DEFAULT 0,\n" - " time_played INTEGER DEFAULT 0,\n" - " db_timestamp INTEGER DEFAULT 0,\n" - " disabled INTEGER DEFAULT 0,\n" - " sample_count INTEGER DEFAULT 0,\n" - " force_update INTEGER DEFAULT 0\n" - ");\n" - "CREATE INDEX idx_path ON songs(path);\n" - "CREATE TABLE config (\n" - " term VARCHAR(255) NOT NULL,\n" - " subterm VARCHAR(255) DEFAULT NULL,\n" - " value VARCHAR(1024) NOT NULL\n" - ");\n" - "CREATE TABLE playlists (\n" - " id INTEGER PRIMARY KEY NOT NULL,\n" - " title VARCHAR(255) NOT NULL,\n" - " smart INTEGER NOT NULL,\n" - " items INTEGER NOT NULL,\n" - " query VARCHAR(1024)\n" - ");\n" - "CREATE TABLE playlistitems (\n" - " id INTEGER NOT NULL,\n" - " songid INTEGER NOT NULL\n" - ");\n" - "INSERT INTO config VALUES ('version','','1');\n" - "INSERT INTO playlists VALUES (1,'Library',1,0,'1');\n", - - /* version 1 -> version 2 */ - /* force rescan for invalid utf-8 data */ - "REPLACE INTO config VALUES('rescan',NULL,1);\n" - "UPDATE config SET value=2 WHERE term='version';\n", - - /* version 2 -> version 3 */ - /* add daap.songcodectype, normalize daap.songformat and daap.songdescription */ - "drop index idx_path;\n" - "create temp table tempsongs as select * from songs;\n" - "drop table songs;\n" - "CREATE TABLE songs (\n" - " id INTEGER PRIMARY KEY NOT NULL,\n" - " path VARCHAR(4096) UNIQUE NOT NULL,\n" - " fname VARCHAR(255) NOT NULL,\n" - " title VARCHAR(1024) DEFAULT NULL,\n" - " artist VARCHAR(1024) DEFAULT NULL,\n" - " album VARCHAR(1024) DEFAULT NULL,\n" - " genre VARCHAR(255) DEFAULT NULL,\n" - " comment VARCHAR(4096) DEFAULT NULL,\n" - " type VARCHAR(255) DEFAULT NULL,\n" - " composer VARCHAR(1024) DEFAULT NULL,\n" - " orchestra VARCHAR(1024) DEFAULT NULL,\n" - " conductor VARCHAR(1024) DEFAULT NULL,\n" - " grouping VARCHAR(1024) DEFAULT NULL,\n" - " url VARCHAR(1024) DEFAULT NULL,\n" - " bitrate INTEGER DEFAULT 0,\n" - " samplerate INTEGER DEFAULT 0,\n" - " song_length INTEGER DEFAULT 0,\n" - " file_size INTEGER DEFAULT 0,\n" - " year INTEGER DEFAULT 0,\n" - " track INTEGER DEFAULT 0,\n" - " total_tracks INTEGER DEFAULT 0,\n" - " disc INTEGER DEFAULT 0,\n" - " total_discs INTEGER DEFAULT 0,\n" - " bpm INTEGER DEFAULT 0,\n" - " compilation INTEGER DEFAULT 0,\n" - " rating INTEGER DEFAULT 0,\n" - " play_count INTEGER DEFAULT 0,\n" - " data_kind INTEGER DEFAULT 0,\n" - " item_kind INTEGER DEFAULT 0,\n" - " description INTEGER DEFAULT 0,\n" - " time_added INTEGER DEFAULT 0,\n" - " time_modified INTEGER DEFAULT 0,\n" - " time_played INTEGER DEFAULT 0,\n" - " db_timestamp INTEGER DEFAULT 0,\n" - " disabled INTEGER DEFAULT 0,\n" - " sample_count INTEGER DEFAULT 0,\n" - " force_update INTEGER DEFAULT 0,\n" - " codectype VARCHAR(5) DEFAULT NULL\n" - ");\n" - "begin transaction;\n" - "insert into songs select *,NULL from tempsongs;\n" - "commit transaction;\n" - "update songs set type=lower(type);\n" - "update songs set type='m4a' where type='aac' or type='mp4';\n" - "update songs set type='flac' where type='fla';\n" - "update songs set type='mpc' where type='mpp';\n" - "update songs set type='mpc' where type='mp+';\n" - "update songs set description='AAC audio file' where type='m4a';\n" - "update songs set description='MPEG audio file' where type='mp3';\n" - "update songs set description='WAV audio file' where type='wav';\n" - "update songs set description='Playlist URL' where type='pls';\n" - "update songs set description='Ogg Vorbis audio file' where type='ogg';\n" - "update songs set description='FLAC audio file' where type='flac';\n" - "update songs set description='Musepack audio file' where type='mpc';\n" - "update songs set codectype='mp4a' where type='m4a' or type='m4p';\n" - "update songs set codectype='mpeg' where type='mp3';\n" - "update songs set codectype='ogg' where type='ogg';\n" - "update songs set codectype='flac' where type='flac';\n" - "update songs set codectype='mpc' where type='mpc';\n" - "update songs set force_update=1 where type='m4a';\n" /* look for alac */ - "create index idx_path on songs(path);\n" - "drop table tempsongs;\n" - "update config set value=3 where term='version';\n", - - /* version 3 -> version 4 */ - /* add db_timestamp and path to playlist table */ - "create temp table tempplaylists as select * from playlists;\n" - "drop table playlists;\n" - "CREATE TABLE playlists (\n" - " id INTEGER PRIMARY KEY NOT NULL,\n" - " title VARCHAR(255) NOT NULL,\n" - " type INTEGER NOT NULL,\n" - " items INTEGER NOT NULL,\n" - " query VARCHAR(1024),\n" - " db_timestamp INTEGER NOT NULL,\n" - " path VARCHAR(4096)\n" - ");\n" - "insert into playlists select *,0,NULL from tempplaylists;\n" - "drop table tempplaylists;\n" - "update config set value=4 where term='version';\n", - - /* version 4 -> version 5 */ - /* add index to playlist table */ - "create temp table tempplaylists as select * from playlists;\n" - "drop table playlists;\n" - "CREATE TABLE playlists (\n" - " id INTEGER PRIMARY KEY NOT NULL,\n" - " title VARCHAR(255) NOT NULL,\n" - " type INTEGER NOT NULL,\n" - " items INTEGER NOT NULL,\n" - " query VARCHAR(1024),\n" - " db_timestamp INTEGER NOT NULL,\n" - " path VARCHAR(4096),\n" - " idx INTEGER NOT NULL\n" - ");\n" - "insert into playlists select *,0 from tempplaylists;\n" - "drop table tempplaylists;\n" - "update config set value=5 where term='version';\n", - - /* version 5 -> version 6 */ - "drop index idx_path;\n" - "create temp table tempsongs as select * from songs;\n" - "drop table songs;\n" - "CREATE TABLE songs (\n" - " id INTEGER PRIMARY KEY NOT NULL,\n" - " path VARCHAR(4096) UNIQUE NOT NULL,\n" - " fname VARCHAR(255) NOT NULL,\n" - " title VARCHAR(1024) DEFAULT NULL,\n" - " artist VARCHAR(1024) DEFAULT NULL,\n" - " album VARCHAR(1024) DEFAULT NULL,\n" - " genre VARCHAR(255) DEFAULT NULL,\n" - " comment VARCHAR(4096) DEFAULT NULL,\n" - " type VARCHAR(255) DEFAULT NULL,\n" - " composer VARCHAR(1024) DEFAULT NULL,\n" - " orchestra VARCHAR(1024) DEFAULT NULL,\n" - " conductor VARCHAR(1024) DEFAULT NULL,\n" - " grouping VARCHAR(1024) DEFAULT NULL,\n" - " url VARCHAR(1024) DEFAULT NULL,\n" - " bitrate INTEGER DEFAULT 0,\n" - " samplerate INTEGER DEFAULT 0,\n" - " song_length INTEGER DEFAULT 0,\n" - " file_size INTEGER DEFAULT 0,\n" - " year INTEGER DEFAULT 0,\n" - " track INTEGER DEFAULT 0,\n" - " total_tracks INTEGER DEFAULT 0,\n" - " disc INTEGER DEFAULT 0,\n" - " total_discs INTEGER DEFAULT 0,\n" - " bpm INTEGER DEFAULT 0,\n" - " compilation INTEGER DEFAULT 0,\n" - " rating INTEGER DEFAULT 0,\n" - " play_count INTEGER DEFAULT 0,\n" - " data_kind INTEGER DEFAULT 0,\n" - " item_kind INTEGER DEFAULT 0,\n" - " description INTEGER DEFAULT 0,\n" - " time_added INTEGER DEFAULT 0,\n" - " time_modified INTEGER DEFAULT 0,\n" - " time_played INTEGER DEFAULT 0,\n" - " db_timestamp INTEGER DEFAULT 0,\n" - " disabled INTEGER DEFAULT 0,\n" - " sample_count INTEGER DEFAULT 0,\n" - " force_update INTEGER DEFAULT 0,\n" - " codectype VARCHAR(5) DEFAULT NULL,\n" - " idx INTEGER NOT NULL\n" - ");\n" - "begin transaction;\n" - "insert into songs select *,0 from tempsongs;\n" - "commit transaction;\n" - "create index idx_path on songs(path);\n" - "drop table tempsongs;\n" - "update config set value=6 where term='version';\n", - - /* version 6 -> version 7 */ - "create temp table tempitems as select * from playlistitems;\n" - "drop table playlistitems;\n" - "CREATE TABLE playlistitems (\n" - " id INTEGER PRIMARY KEY NOT NULL,\n" - " playlistid INTEGER NOT NULL,\n" - " songid INTEGER NOT NULL\n" - ");\n" - "insert into playlistitems (playlistid, songid) select * from tempitems;\n" - "drop table tempitems;\n" - "update config set value=7 where term='version';\n", - - /* version 7 -> version 8 */ - "create index idx_songid on playlistitems(songid)\n" - "create index idx_playlistid on playlistitems(playlistid)\n" - "update config set value=8 where term='version';\n", - - /* version 8 -> version 9 */ - "drop index idx_path;\n" - "create temp table tempsongs as select * from songs;\n" - "drop table songs;\n" - "CREATE TABLE songs (\n" - " id INTEGER PRIMARY KEY NOT NULL,\n" - " path VARCHAR(4096) UNIQUE NOT NULL,\n" - " fname VARCHAR(255) NOT NULL,\n" - " title VARCHAR(1024) DEFAULT NULL,\n" - " artist VARCHAR(1024) DEFAULT NULL,\n" - " album VARCHAR(1024) DEFAULT NULL,\n" - " genre VARCHAR(255) DEFAULT NULL,\n" - " comment VARCHAR(4096) DEFAULT NULL,\n" - " type VARCHAR(255) DEFAULT NULL,\n" - " composer VARCHAR(1024) DEFAULT NULL,\n" - " orchestra VARCHAR(1024) DEFAULT NULL,\n" - " conductor VARCHAR(1024) DEFAULT NULL,\n" - " grouping VARCHAR(1024) DEFAULT NULL,\n" - " url VARCHAR(1024) DEFAULT NULL,\n" - " bitrate INTEGER DEFAULT 0,\n" - " samplerate INTEGER DEFAULT 0,\n" - " song_length INTEGER DEFAULT 0,\n" - " file_size INTEGER DEFAULT 0,\n" - " year INTEGER DEFAULT 0,\n" - " track INTEGER DEFAULT 0,\n" - " total_tracks INTEGER DEFAULT 0,\n" - " disc INTEGER DEFAULT 0,\n" - " total_discs INTEGER DEFAULT 0,\n" - " bpm INTEGER DEFAULT 0,\n" - " compilation INTEGER DEFAULT 0,\n" - " rating INTEGER DEFAULT 0,\n" - " play_count INTEGER DEFAULT 0,\n" - " data_kind INTEGER DEFAULT 0,\n" - " item_kind INTEGER DEFAULT 0,\n" - " description INTEGER DEFAULT 0,\n" - " time_added INTEGER DEFAULT 0,\n" - " time_modified INTEGER DEFAULT 0,\n" - " time_played INTEGER DEFAULT 0,\n" - " db_timestamp INTEGER DEFAULT 0,\n" - " disabled INTEGER DEFAULT 0,\n" - " sample_count INTEGER DEFAULT 0,\n" - " force_update INTEGER DEFAULT 0,\n" - " codectype VARCHAR(5) DEFAULT NULL,\n" - " idx INTEGER NOT NULL,\n" - " has_video INTEGER DEFAULT 0,\n" - " contentrating INTEGER DEFAULT 0\n" - ");\n" - "begin transaction;\n" - "insert into songs select *,0,0 from tempsongs;\n" - "commit transaction;\n" - "update songs set has_video=1 where fname like '%.m4v';\n" - "create index idx_path on songs(path);\n" - "drop table tempsongs;\n" - "update config set value=9 where term='version';\n", - - /* version 9 -> version 10 */ - "drop index idx_path;\n" - "create temp table tempsongs as select * from songs;\n" - "drop table songs;\n" - "CREATE TABLE songs (\n" - " id INTEGER PRIMARY KEY NOT NULL,\n" - " path VARCHAR(4096) NOT NULL,\n" - " fname VARCHAR(255) NOT NULL,\n" - " title VARCHAR(1024) DEFAULT NULL,\n" - " artist VARCHAR(1024) DEFAULT NULL,\n" - " album VARCHAR(1024) DEFAULT NULL,\n" - " genre VARCHAR(255) DEFAULT NULL,\n" - " comment VARCHAR(4096) DEFAULT NULL,\n" - " type VARCHAR(255) DEFAULT NULL,\n" - " composer VARCHAR(1024) DEFAULT NULL,\n" - " orchestra VARCHAR(1024) DEFAULT NULL,\n" - " conductor VARCHAR(1024) DEFAULT NULL,\n" - " grouping VARCHAR(1024) DEFAULT NULL,\n" - " url VARCHAR(1024) DEFAULT NULL,\n" - " bitrate INTEGER DEFAULT 0,\n" - " samplerate INTEGER DEFAULT 0,\n" - " song_length INTEGER DEFAULT 0,\n" - " file_size INTEGER DEFAULT 0,\n" - " year INTEGER DEFAULT 0,\n" - " track INTEGER DEFAULT 0,\n" - " total_tracks INTEGER DEFAULT 0,\n" - " disc INTEGER DEFAULT 0,\n" - " total_discs INTEGER DEFAULT 0,\n" - " bpm INTEGER DEFAULT 0,\n" - " compilation INTEGER DEFAULT 0,\n" - " rating INTEGER DEFAULT 0,\n" - " play_count INTEGER DEFAULT 0,\n" - " data_kind INTEGER DEFAULT 0,\n" - " item_kind INTEGER DEFAULT 0,\n" - " description INTEGER DEFAULT 0,\n" - " time_added INTEGER DEFAULT 0,\n" - " time_modified INTEGER DEFAULT 0,\n" - " time_played INTEGER DEFAULT 0,\n" - " db_timestamp INTEGER DEFAULT 0,\n" - " disabled INTEGER DEFAULT 0,\n" - " sample_count INTEGER DEFAULT 0,\n" - " force_update INTEGER DEFAULT 0,\n" - " codectype VARCHAR(5) DEFAULT NULL,\n" - " idx INTEGER NOT NULL,\n" - " has_video INTEGER DEFAULT 0,\n" - " contentrating INTEGER DEFAULT 0\n" - ");\n" - "begin transaction;\n" - "insert into songs select * from tempsongs;\n" - "commit transaction;\n" - "create index idx_path on songs(path,idx);\n" - "drop table tempsongs;\n" - "update config set value=10 where term='version';\n", - /* version 10 -> version 11 */ - "drop index idx_playlistid;\n" - "create index idx_playlistid on playlistitems(playlistid,songid);\n" - "update config set value=11 where term='version';\n", - /* version 11 -> version 12 */ - "REPLACE INTO config VALUES('rescan',NULL,1);\n" - "UPDATE config SET value=12 WHERE term='version';\n", - /* version 12 -> version 13 */ - "create temp table tempsongs as select * from songs;\n" - "drop table songs;\n" - "CREATE TABLE songs (\n" - " id INTEGER PRIMARY KEY NOT NULL,\n" - " path VARCHAR(4096) NOT NULL,\n" - " fname VARCHAR(255) NOT NULL,\n" - " title VARCHAR(1024) DEFAULT NULL,\n" - " artist VARCHAR(1024) DEFAULT NULL,\n" - " album VARCHAR(1024) DEFAULT NULL,\n" - " genre VARCHAR(255) DEFAULT NULL,\n" - " comment VARCHAR(4096) DEFAULT NULL,\n" - " type VARCHAR(255) DEFAULT NULL,\n" - " composer VARCHAR(1024) DEFAULT NULL,\n" - " orchestra VARCHAR(1024) DEFAULT NULL,\n" - " conductor VARCHAR(1024) DEFAULT NULL,\n" - " grouping VARCHAR(1024) DEFAULT NULL,\n" - " url VARCHAR(1024) DEFAULT NULL,\n" - " bitrate INTEGER DEFAULT 0,\n" - " samplerate INTEGER DEFAULT 0,\n" - " song_length INTEGER DEFAULT 0,\n" - " file_size INTEGER DEFAULT 0,\n" - " year INTEGER DEFAULT 0,\n" - " track INTEGER DEFAULT 0,\n" - " total_tracks INTEGER DEFAULT 0,\n" - " disc INTEGER DEFAULT 0,\n" - " total_discs INTEGER DEFAULT 0,\n" - " bpm INTEGER DEFAULT 0,\n" - " compilation INTEGER DEFAULT 0,\n" - " rating INTEGER DEFAULT 0,\n" - " play_count INTEGER DEFAULT 0,\n" - " data_kind INTEGER DEFAULT 0,\n" - " item_kind INTEGER DEFAULT 0,\n" - " description INTEGER DEFAULT 0,\n" - " time_added INTEGER DEFAULT 0,\n" - " time_modified INTEGER DEFAULT 0,\n" - " time_played INTEGER DEFAULT 0,\n" - " db_timestamp INTEGER DEFAULT 0,\n" - " disabled INTEGER DEFAULT 0,\n" - " sample_count INTEGER DEFAULT 0,\n" - " force_update INTEGER DEFAULT 0,\n" - " codectype VARCHAR(5) DEFAULT NULL,\n" - " idx INTEGER NOT NULL,\n" - " has_video INTEGER DEFAULT 0,\n" - " contentrating INTEGER DEFAULT 0,\n" - " bits_per_sample INTEGER DEFAULT 0,\n" - " album_artist VARCHAR(1024)\n" - ");\n" - "begin transaction;\n" - "insert into songs select *,0,'' from tempsongs;\n" - "commit transaction;\n" - "drop table tempsongs;\n" - "update config set value=13 where term='version';\n", - NULL /* No more versions! */ - -}; diff --git a/src/db-sql.c b/src/db-sql.c deleted file mode 100644 index 62fd8877..00000000 --- a/src/db-sql.c +++ /dev/null @@ -1,1649 +0,0 @@ -/* - * sql-specific db implementation - * - * Copyright (C) 2005 Ron Pedde (ron@pedde.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#define _XOPEN_SOURCE 500 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef HAVE_STDINT_H -# include -#endif -#include - -#include "logger.h" -#include "db-generic.h" -#include "db-sql.h" - -#define TRUE ((1 == 1)) -#define FALSE (!TRUE) - -#ifdef HAVE_SQLITE3 -#include "db-sql-sqlite3.h" -#endif - -/* Globals */ -static int db_sql_reload=0; -static int db_sql_in_playlist_scan=0; -static int db_sql_in_scan=0; -static int db_sql_need_dispose=0; - -extern char *db_sqlite_updates[]; - -/* Forwards */ - - -void db_sql_build_mp3file(char **valarray, MP3FILE *pmp3); -int db_sql_update(char **pe, MP3FILE *pmp3, int *id); -int db_sql_update_playlists(char **pe); -int db_sql_parse_smart(char **pe, char **clause, char *phrase); - -#define STR(a) (a) ? (a) : "" -#define ISSTR(a) ((a) && strlen((a))) -#define MAYBEFREE(a) { if((a)) free((a)); }; -/* -#define DMAPLEN(a) (((a) && strlen(a)) ? (8+(int)strlen((a))) : \ - ((pinfo->zero_length) ? 8 : 0)) -#define EMIT(a) (pinfo->zero_length ? 1 : ((a) && strlen((a))) ? 1 : 0) -*/ -/** - * functions for the specific db backend - */ -int (*db_sql_open_fn)(char **pe, char *dsn) = NULL; -int (*db_sql_close_fn)(void) = NULL; -int (*db_sql_exec_fn)(char **pe, int loglevel, char *fmt, ...) = NULL; -char* (*db_sql_vmquery_fn)(char *fmt,va_list ap) = NULL; -void (*db_sql_vmfree_fn)(char *query) = NULL; -int (*db_sql_enum_begin_fn)(char **pe, char *fmt, ...) = NULL; -int (*db_sql_enum_fetch_fn)(char **pe, SQL_ROW *pr) = NULL; -int (*db_sql_enum_end_fn)(char **pe) = NULL; -int (*db_sql_enum_restart_fn)(char **pe); -int (*db_sql_event_fn)(int event_type); -int (*db_sql_insert_id_fn)(void); - -#ifdef HAVE_SQLITE3 -int db_sql_open_sqlite3(char **pe, char *parameters) { - /* first, set our external links to sqlite3 */ - db_sql_open_fn = db_sqlite3_open; - db_sql_close_fn = db_sqlite3_close; - db_sql_exec_fn = db_sqlite3_exec; - db_sql_vmquery_fn = db_sqlite3_vmquery; - db_sql_vmfree_fn = db_sqlite3_vmfree; - db_sql_enum_begin_fn = db_sqlite3_enum_begin; - db_sql_enum_fetch_fn = db_sqlite3_enum_fetch; - db_sql_enum_end_fn = db_sqlite3_enum_end; - db_sql_enum_restart_fn = db_sqlite3_enum_restart; - db_sql_event_fn = db_sqlite3_event; - db_sql_insert_id_fn = db_sqlite3_insert_id; - - return db_sql_open(pe,parameters); -} -#endif - -int db_sql_atoi(const char *what) { - return what ? atoi(what) : 0; -} -char *db_sql_strdup(const char *what) { - return what ? (strlen(what) ? strdup(what) : NULL) : NULL; -} - -uint64_t db_sql_atol(const char *what) { - return what ? atoll(what) : 0; -} -/** - * escape a sql string, returning it the supplied buffer. - * note that this uses the sqlite escape format -- use %q for quoted - * sql. - * - * @param buffer buffer to throw the escaped sql into - * @param size size of buffer (or size required, if DB_E_SIZE) - * @param fmt printf style format - * @returns DB_E_SUCCESS with buffer filled, or DB_E_SIZE, with size - * set to the required size - */ -int db_sql_escape(char *buffer, int *size, char *fmt, ...) { - va_list ap; - char *escaped; - - va_start(ap,fmt); - escaped = db_sql_vmquery_fn(fmt,ap); - va_end(ap); - - if(*size < (int)strlen(escaped)) { - *size = (int)strlen(escaped) + 1; - db_sql_vmfree_fn(escaped); - return DB_E_SIZE; - } - - strcpy(buffer,escaped); - *size = (int)strlen(escaped); - db_sql_vmfree_fn(escaped); - - return DB_E_SUCCESS; -} - -char * -db_sql_escape_dup(char *fmt, ...) -{ - va_list ap; - char *escaped; - char *ret; - - va_start(ap, fmt); - escaped = db_sql_vmquery_fn(fmt, ap); - va_end(ap); - - ret = strdup(escaped); - - db_sql_vmfree_fn(escaped); - - return ret; -} - -/** - * fetch a single row, using the underlying database enum - * functions - */ -int db_sql_fetch_row(char **pe, SQL_ROW *row, char *fmt, ...) { - int err; - char *query; - va_list ap; - - - *row=NULL; - - va_start(ap,fmt); - query=db_sql_vmquery_fn(fmt,ap); - va_end(ap); - - err=db_sql_enum_begin_fn(pe,"%s",query); - db_sql_vmfree_fn(query); - - if(err != DB_E_SUCCESS) { - DPRINTF(E_LOG,L_DB,"Error: enum_begin failed (error %d): %s\n", - err,(pe) ? *pe : "?"); - return err; - } - - err=db_sql_enum_fetch_fn(pe, row); - if(err != DB_E_SUCCESS) { - DPRINTF(E_LOG,L_DB,"Error: enum_fetch failed (error %d): %s\n", - err,(pe) ? *pe : "?"); - db_sql_enum_end_fn(NULL); - return err; - } - - if(!(*row)) { - db_sql_need_dispose=0; - db_sql_enum_end_fn(NULL); - db_get_error(pe,DB_E_NOROWS); - return DB_E_NOROWS; - } - - db_sql_need_dispose = 1; - return DB_E_SUCCESS; -} - -int db_sql_fetch_int(char **pe, int *result, char *fmt, ...) { - int err; - char *query; - va_list ap; - SQL_ROW row; - - va_start(ap,fmt); - query=db_sql_vmquery_fn(fmt,ap); - va_end(ap); - - err = db_sql_fetch_row(pe, &row, "%s", query); - db_sql_vmfree_fn(query); - - if(err != DB_E_SUCCESS) { - DPRINTF(E_SPAM,L_DB,"fetch_row failed in fetch_int: %s\n",pe ? *pe : NULL); - return err; - } - - *result = atoi(row[0]); - db_sql_dispose_row(); - return DB_E_SUCCESS; -} - -int db_sql_fetch_char(char **pe, char **result, char *fmt, ...) { - int err; - char *query; - va_list ap; - SQL_ROW row; - - va_start(ap,fmt); - query=db_sql_vmquery_fn(fmt,ap); - va_end(ap); - - err = db_sql_fetch_row(pe, &row, "%s", query); - if(err != DB_E_SUCCESS) - return err; - - *result = strdup(row[0]); - db_sql_dispose_row(); - return DB_E_SUCCESS; -} - -int db_sql_dispose_row(void) { - int err = DB_E_SUCCESS; - - /* don't really need the row */ - if(db_sql_need_dispose) { - db_sql_need_dispose=0; - err=db_sql_enum_end_fn(NULL); - } - - return err; -} - -/** - * get the sql where clause for a smart playlist spec. This - * where clause must be freed by the caller - * - * @param phrase playlist spec to be converted - * @returns sql where clause if successful, NULL otherwise - */ -int db_sql_parse_smart(char **pe, char **clause, char *phrase) { -#if 0 - /* The smart parser is gone, and this function and its callers - * will soon be gone too.*/ - PARSETREE pt; - - if(strcmp(phrase,"1") == 0) { - *clause = strdup("1"); - return TRUE; - } - - pt=sp_init(); - if(!pt) { - if(pe) *pe = strdup("Could not initialize parse tree"); - return FALSE; - } - - if(!sp_parse(pt,phrase,SP_TYPE_PLAYLIST)) { - if(pe) *pe = strdup(sp_get_error(pt)); - - DPRINTF(E_LOG,L_DB,"Error parsing playlist: %s\n",sp_get_error(pt)); - - sp_dispose(pt); - return FALSE; - } else { - *clause = sp_sql_clause(pt); - } - - sp_dispose(pt); - return TRUE; -#endif /* 0 */ - *pe = *clause = NULL; - return FALSE; -} - -/** - * open sqlite database - * - * @returns DB_E_SUCCESS on success, error code otherwise - */ -int db_sql_open(char **pe, char *parameters) { - int result; - int current_version; - int max_version; - char **db_updates; - - result = db_sql_open_fn(pe,parameters); - - if(result == DB_E_WRONGVERSION) { - /* need to update the version */ - if(pe) free(*pe); - - db_updates = db_sqlite_updates; - - result = db_sql_fetch_int(pe,¤t_version,"select value from " - "config where term='version'"); - - if(result != DB_E_SUCCESS) - return result; - - max_version = 0; - while(db_updates[max_version]) - max_version++; - - DPRINTF(E_DBG,L_DB,"Current db version: %d\n",current_version); - DPRINTF(E_DBG,L_DB,"Target db version: %d\n",max_version); - - while(current_version < max_version) { - DPRINTF(E_LOG,L_DB,"Upgrading db: %d --> %d\n",current_version, - current_version + 1); - result = db_sql_exec_fn(pe,E_LOG,"%s",db_updates[current_version]); - if(result != DB_E_SUCCESS) { - DPRINTF(E_LOG,L_DB,"Error upgrading db: %s\n", pe ? *pe : - "Unknown"); - return result; - } - current_version++; - } - } - - return result; -} - -/** - * initialize the sqlite database, reloading if requested - * - * @param reload whether or not to do a full reload on the db - * on return, reload is set to 1 if the db MUST be rescanned - * @returns DB_E_SUCCESS on success, error code otherwise - */ -int db_sql_init(int reload) { - int items; - int rescan = 0; - int err; - int do_reload = reload; - - err=db_sql_get_count(NULL,&items, countSongs); - if(err != DB_E_SUCCESS) - items = 0; - - /* check if a request has been written into the db (by a db upgrade?) */ - if(db_sql_fetch_int(NULL,&rescan,"select value from config where " - "term='rescan'") == DB_E_SUCCESS) { - if(rescan) - do_reload=1; - } - - - /* we could pass back a status to describe whether a reaload was - * required (for reasons other than expicit request) - */ - if(do_reload || (!items)) { - DPRINTF(E_LOG,L_DB,"Full reload...\n"); - db_sql_event_fn(DB_SQL_EVENT_FULLRELOAD); - db_sql_reload=1; - } else { - db_sql_event_fn(DB_SQL_EVENT_STARTUP); - db_sql_reload=0; - } - - return DB_E_SUCCESS; -} - -/** - * close the database - * @returns DB_E_SUCCESS on success, error code otherwise - */ -int db_sql_deinit(void) { - return db_sql_close_fn(); -} - - -/** - * force a rescan - */ -int db_sql_force_rescan(char **pe) { - int result; - result = db_sql_exec_fn(pe,E_LOG,"update playlists set db_timestamp=0"); - if(result != DB_E_SUCCESS) - return result; - - return db_sql_exec_fn(pe,E_LOG,"update songs set force_update=1"); - -} - -/** - * start a background scan - * - * @returns DB_E_SUCCESS on success, error code otherwise - */ -int db_sql_start_scan() { - DPRINTF(E_DBG,L_DB,"Starting db scan\n"); - db_sql_event_fn(DB_SQL_EVENT_SONGSCANSTART); - - db_sql_in_scan=1; - db_sql_in_playlist_scan=0; - return DB_E_SUCCESS; -} - -/** - * end song scan -- start playlist scan - * - * @returns DB_E_SUCCESS on success, error code otherwise - */ -int db_sql_end_song_scan(void) { - DPRINTF(E_DBG,L_DB,"Ending song scan\n"); - - db_sql_event_fn(DB_SQL_EVENT_SONGSCANEND); - db_sql_event_fn(DB_SQL_EVENT_PLSCANSTART); - - db_sql_in_scan=0; - db_sql_in_playlist_scan=1; - - return DB_E_SUCCESS; -} - -/** - * stop a db scan - * - * @returns DB_E_SUCCESS on success, error code otherwise - */ -int db_sql_end_scan(void) { - db_sql_event_fn(DB_SQL_EVENT_PLSCANEND); - - db_sql_update_playlists(NULL); - db_sql_reload=0; - db_sql_in_playlist_scan=0; - - return DB_E_SUCCESS; -} - -/** - * delete a playlist - * - * @param playlistid playlist to delete - * @returns DB_E_SUCCESS on success, error code otherwise - */ -int db_sql_delete_playlist(char **pe, int playlistid) { - int type; - int result; - - result=db_sql_fetch_int(pe,&type,"select type from playlists where id=%d", - playlistid); - - if(result != DB_E_SUCCESS) { - if(result == DB_E_NOROWS) { /* Override the generic error */ - if(pe) { free(*pe); }; - db_get_error(pe,DB_E_INVALID_PLAYLIST); - return DB_E_INVALID_PLAYLIST; - } - - return result; - } - - /* got a good playlist, now do what we need to do */ - db_sql_exec_fn(pe,E_FATAL,"delete from playlists where id=%d",playlistid); - db_sql_exec_fn(pe,E_FATAL,"delete from playlistitems where playlistid=%d",playlistid); - - return DB_E_SUCCESS; -} - -/** - * delete a song from a playlist - * - * @param playlistid playlist to delete item from - * @param songid song to delete from playlist - * @returns DB_E_SUCCESS on success, error code otherwise - */ -int db_sql_delete_playlist_item(char **pe, int playlistid, int songid) { - int result; - int playlist_type; - int count; - - /* first, check the playlist */ - result=db_sql_fetch_int(pe,&playlist_type, - "select type from playlists where id=%d", - playlistid); - - if(result != DB_E_SUCCESS) { - if(result == DB_E_NOROWS) { /* Override generic error */ - if(pe) { free(*pe); }; - db_get_error(pe,DB_E_INVALID_PLAYLIST); - return DB_E_INVALID_PLAYLIST; - } - return result; - } - - if(playlist_type == PL_SMART) { /* can't delete from a smart playlist */ - db_get_error(pe,DB_E_INVALIDTYPE); - return DB_E_INVALIDTYPE; - } - - /* make sure the songid is valid */ - result=db_sql_fetch_int(pe,&count,"select count(*) from playlistitems " - "where playlistid=%d and songid=%d", - playlistid,songid); - - if(result != DB_E_SUCCESS) { - if(result == DB_E_NOROWS) { /* Override generic error */ - if(pe) { free(*pe); }; - db_get_error(pe,DB_E_INVALID_SONGID); - return DB_E_INVALID_SONGID; - } - return result; - } - - /* looks valid, so lets add the item */ - result=db_sql_exec_fn(pe,E_DBG,"delete from playlistitems where " - "playlistid=%d and songid=%d",playlistid,songid); - - return result; -} - -/** - * edit a playlist. The only things worth changing are the name - * and the "where" clause. - * - * @param id id of the playlist to alter - * @param name new name of the playlist (or NULL) - * @param where new where clause (or NULL) - * @returns DB_E_SUCCESS on success, error code otherwise - */ -int db_sql_edit_playlist(char **pe, int id, char *name, char *clause) { - int result; - int playlist_type; - int dup_id=id; - char *criteria; - char *estring; - - if((name == NULL) && (clause == NULL)) - return DB_E_SUCCESS; /* I guess?? */ - - if(id == 1) { /* can't edit the library query */ - db_get_error(pe,DB_E_INVALID_PLAYLIST); - return DB_E_INVALID_PLAYLIST; - } - - /* first, check the playlist */ - result=db_sql_fetch_int(pe,&playlist_type, - "select type from playlists where id=%d",id); - - if(result != DB_E_SUCCESS) { - if(result == DB_E_NOROWS) { /* Override generic error */ - if(pe) { free(*pe); }; - db_get_error(pe,DB_E_INVALID_PLAYLIST); - return DB_E_INVALID_PLAYLIST; - } - return result; - } - - - if((playlist_type == PL_SMART) && (clause)) { - if(!db_sql_parse_smart(&estring,&criteria,clause)) { - db_get_error(pe,DB_E_PARSE,estring); - free(estring); - return DB_E_PARSE; - } - free(criteria); - } - - /* TODO: check for duplicate names here */ - if(name) { - result = db_sql_fetch_int(pe,&dup_id,"select id from playlists " - "where upper(title)=upper('%q')",name); - - if((result != DB_E_SUCCESS) && (result != DB_E_NOROWS)) - return result; - - if(result == DB_E_NOROWS) - if(pe) free(*pe); - - if(dup_id != id) { - db_get_error(pe,DB_E_DUPLICATE_PLAYLIST,name); - return DB_E_DUPLICATE_PLAYLIST; - } - - if((playlist_type == PL_SMART)&&(clause)) { - result=db_sql_exec_fn(pe,E_LOG,"update playlists set title='%q', " - "query='%q' where id=%d",name,clause,id); - - } else { - result=db_sql_exec_fn(pe,E_LOG,"update playlists set title='%q' " - "where id=%d",name,id); - } - db_sql_update_playlists(NULL); - return result; - } - - if((playlist_type == PL_SMART) && (clause)) { - result= db_sql_exec_fn(pe,E_LOG,"update playlists set query='%q' " - "where id=%d",clause,id); - db_sql_update_playlists(NULL); - return result; - } - - return DB_E_SUCCESS; /* ?? */ -} - -/** - * add a playlist - * - * @param name name of the playlist - * @param type playlist type: 0 - static, 1 - smart, 2 - m3u - * @param clause: "where" clause for smart playlist - * @returns DB_E_SUCCESS on success, error code otherwise - */ -int db_sql_add_playlist(char **pe, char *name, int type, char *clause, char *path, int index, int *playlistid) { - int cnt=0; - int result=DB_E_SUCCESS; - char *criteria; - char *estring; - SQL_ROW row; - - result=db_sql_fetch_int(pe,&cnt,"select count(*) from playlists where " - "upper(title)=upper('%q')",name); - - if(result != DB_E_SUCCESS) { - return result; - } - - if(cnt != 0) { /* duplicate */ - db_sql_fetch_row(NULL,&row, "select * from playlists where " - "upper(title)=upper('%q')",name); - DPRINTF(E_LOG,L_MISC,"Attempt to add duplicate playlist: '%s' " - "type: %d, path: %s, idx: %d\n",name,atoi(row[PL_TYPE]), - row[PL_PATH],atoi(row[PL_IDX])); - db_sql_dispose_row(); - db_get_error(pe,DB_E_DUPLICATE_PLAYLIST,name); - return DB_E_DUPLICATE_PLAYLIST; - } - - if((type == PL_SMART) && (!clause)) { - db_get_error(pe,DB_E_NOCLAUSE); - return DB_E_NOCLAUSE; - } - - /* Let's throw it in */ - switch(type) { - case PL_STATICFILE: /* static, from file */ - case PL_STATICXML: /* from iTunes XML file */ - result = db_sql_exec_fn(pe,E_LOG,"insert into playlists " - "(title,type,items,query,db_timestamp,path,idx) " - "values ('%q',%d,0,NULL,%d,'%q',%d)", - name,type,(int)time(NULL),path,index); - break; - case PL_STATICWEB: /* static, maintained in web interface */ - result = db_sql_exec_fn(pe,E_LOG,"insert into playlists " - "(title,type,items,query,db_timestamp,path,idx) " - "values ('%q',%d,0,NULL,%d,NULL,%d)", - name,type,time(NULL),index); - break; - case PL_SMART: /* smart */ - if(!db_sql_parse_smart(&estring,&criteria,clause)) { - db_get_error(pe,DB_E_PARSE,estring); - free(estring); - return DB_E_PARSE; - } - free(criteria); - - result = db_sql_exec_fn(pe,E_LOG,"insert into playlists " - "(title,type,items,query,db_timestamp,idx) " - "values ('%q',%d,%d,'%q',%d,0)", - name,PL_SMART,cnt,clause,time(NULL)); - break; - } - - if(result) - return result; - - result = db_sql_fetch_int(pe,playlistid, - "select id from playlists where title='%q'", - name); - - if(((type==PL_STATICFILE)||(type==PL_STATICXML)) - && (db_sql_in_playlist_scan) && (!db_sql_reload)) { - db_sql_exec_fn(NULL,E_FATAL,"insert into plupdated values (%d)",*playlistid); - } - - db_sql_update_playlists(NULL); - return result; -} - -/** - * add a song to a static playlist - * - * @param playlistid playlist to add song to - * @param songid song to add - * @returns DB_E_SUCCESS on success, error code otherwise - */ -int db_sql_add_playlist_item(char **pe, int playlistid, int songid) { - int result; - int playlist_type; - int count; - - /* first, check the playlist */ - result=db_sql_fetch_int(pe,&playlist_type, - "select type from playlists where id=%d", - playlistid); - - if(result != DB_E_SUCCESS) { - if(result == DB_E_NOROWS) { /* Override generic error */ - if(pe) { free(*pe); }; - db_get_error(pe,DB_E_INVALID_PLAYLIST); - return DB_E_INVALID_PLAYLIST; - } - return result; - } - - if(playlist_type == PL_SMART) { /* can't add to smart playlists */ - db_get_error(pe,DB_E_INVALIDTYPE); - return DB_E_INVALIDTYPE; - } - - /* make sure the songid is valid */ - result=db_sql_fetch_int(pe,&count,"select count(*) from songs where " - "id=%d",songid); - - if(result != DB_E_SUCCESS) { - if(result == DB_E_NOROWS) { /* Override generic error */ - if(pe) { free(*pe); }; - db_get_error(pe,DB_E_INVALID_SONGID); - return DB_E_INVALID_SONGID; - } - return result; - } - - /* looks valid, so lets add the item */ - result=db_sql_exec_fn(pe,E_DBG,"insert into playlistitems " - "(playlistid, songid) values (%d,%d)", - playlistid,songid); - return result; -} - - -/** - * add a database item - * - * @param pmp3 mp3 file to add - */ -int db_sql_add(char **pe, MP3FILE *pmp3, int *id) { - int err; - int count; - int insertid; - char *query; - char sample_count[40]; - char file_size[40]; - - DPRINTF(E_SPAM,L_DB,"Entering db_sql_add\n"); - - if(!pmp3->time_added) - pmp3->time_added = (int)time(NULL); - - if(!pmp3->time_modified) - pmp3->time_modified = (int)time(NULL); - - pmp3->db_timestamp = (int)time(NULL); - - /* Always an add if in song scan on full reload */ - if((!db_sql_reload)||(!db_sql_in_scan)) { - query = "select count(*) from songs where path='%q' and idx=%d"; - err=db_sql_fetch_int(NULL,&count,query,pmp3->path,pmp3->index); - - if((err == DB_E_SUCCESS) && (count == 1)) { /* we should update */ - return db_sql_update(pe,pmp3,id); - } else if((err != DB_E_SUCCESS) && (err != DB_E_NOROWS)) { - DPRINTF(E_LOG,L_DB,"Error: %s\n",pe); - return err; - } - - } - - pmp3->play_count=0; - pmp3->time_played=0; - - /* sqlite2 doesn't support 64 bit ints */ /* JB: FIXME */ - sprintf(sample_count, "%" PRIu64, pmp3->sample_count); - sprintf(file_size, "%" PRIu64, pmp3->file_size); - - err=db_sql_exec_fn(pe,E_DBG,"INSERT INTO songs VALUES " - "(NULL," // id - "'%q'," // path - "'%q'," // fname - "'%q'," // title - "'%q'," // artist - "'%q'," // album - "'%q'," // genre - "'%q'," // comment - "'%q'," // type - "'%q'," // composer - "'%q'," // orchestra - "'%q'," // conductor - "'%q'," // grouping - "'%q'," // url - "%d," // bitrate - "%d," // samplerate - "%d," // song_length - "%s," // file_size - "%d," // year - "%d," // track - "%d," // total_tracks - "%d," // disc - "%d," // total_discs - "%d," // bpm - "%d," // compilation - "%d," // rating - "0," // play_count - "%d," // data_kind - "%d," // item_kind - "'%q'," // description - "%d," // time_added - "%d," // time_modified - "%d," // time_played - "%d," // db_timestamp - "%d," // disabled - "%s," // sample_count - "0," // force_update - "'%q'," // codectype - "%d," // index - "%d," // has_video - "%d," // contentrating - "%d," // bits_per_sample - "'%q')", // albumartist - pmp3->path, - STR(pmp3->fname), - STR(pmp3->title), - STR(pmp3->artist), - STR(pmp3->album), - STR(pmp3->genre), - STR(pmp3->comment), - STR(pmp3->type), - STR(pmp3->composer), - STR(pmp3->orchestra), - STR(pmp3->conductor), - STR(pmp3->grouping), - STR(pmp3->url), - pmp3->bitrate, - pmp3->samplerate, - pmp3->song_length, - file_size, - pmp3->year, - pmp3->track, - pmp3->total_tracks, - pmp3->disc, - pmp3->total_discs, - pmp3->bpm, - pmp3->compilation, - pmp3->rating, - pmp3->data_kind, - pmp3->item_kind, - STR(pmp3->description), - pmp3->time_added, - pmp3->time_modified, - pmp3->time_played, - pmp3->db_timestamp, - pmp3->disabled, - sample_count, - STR(pmp3->codectype), - pmp3->index, - pmp3->has_video, - pmp3->contentrating, - pmp3->bits_per_sample, - STR(pmp3->album_artist)); - - if(err != DB_E_SUCCESS) - DPRINTF(E_FATAL,L_DB,"Error inserting file %s in database\n",pmp3->fname); - - insertid = db_sql_insert_id_fn(); - if((db_sql_in_scan || db_sql_in_playlist_scan)&&(!db_sql_reload)) { - /* fetch threads have different sqlite handle -- won't see the update table */ - db_sql_exec_fn(NULL,E_DBG,"insert into updated values (%d)", - insertid); - } - - if((!db_sql_in_scan) && (!db_sql_in_playlist_scan)) - db_sql_update_playlists(NULL); - - if(id) - *id = insertid; - - DPRINTF(E_SPAM,L_DB,"Exiting db_sql_add\n"); - return DB_E_SUCCESS; -} - -/** - * update a database item - * - * @param pmp3 mp3 file to update - */ -int db_sql_update(char **pe, MP3FILE *pmp3, int *id) { - int err; - char query[1024]; - char sample_count[40]; - char file_size[40]; - - if(!pmp3->time_modified) - pmp3->time_modified = (int)time(NULL); - - pmp3->db_timestamp = (int)time(NULL); - - sprintf(sample_count, "%" PRIu64, pmp3->sample_count); - sprintf(file_size, "%" PRIu64, pmp3->file_size); - - strcpy(query,"UPDATE songs SET " - "title='%q'," // title - "artist='%q'," // artist - "album='%q'," // album - "genre='%q'," // genre - "comment='%q'," // comment - "type='%q'," // type - "composer='%q'," // composer - "orchestra='%q'," // orchestra - "conductor='%q'," // conductor - "grouping='%q'," // grouping - "url='%q'," // url - "bitrate=%d," // bitrate - "samplerate=%d," // samplerate - "song_length=%d," // song_length - "file_size=%s," // file_size - "year=%d," // year - "track=%d," // track - "total_tracks=%d," // total_tracks - "disc=%d," // disc - "total_discs=%d," // total_discs - "time_modified=%d," // time_modified - "db_timestamp=%d," // db_timestamp - "bpm=%d," // bpm - "disabled=%d," // disabled - "compilation=%d," // compilation - "rating=%d," // rating - "sample_count=%s," // sample_count - "codectype='%q'," // codec - "album_artist='%q'" - " WHERE path='%q' and idx=%d"); - - err = db_sql_exec_fn(pe,E_LOG,query, - STR(pmp3->title), - STR(pmp3->artist), - STR(pmp3->album), - STR(pmp3->genre), - STR(pmp3->comment), - STR(pmp3->type), - STR(pmp3->composer), - STR(pmp3->orchestra), - STR(pmp3->conductor), - STR(pmp3->grouping), - STR(pmp3->url), - pmp3->bitrate, - pmp3->samplerate, - pmp3->song_length, - file_size, - pmp3->year, - pmp3->track, - pmp3->total_tracks, - pmp3->disc, - pmp3->total_discs, - pmp3->time_modified, - pmp3->db_timestamp, - pmp3->bpm, - pmp3->disabled, - pmp3->compilation, - pmp3->rating, - sample_count, - STR(pmp3->codectype), - STR(pmp3->album_artist), - pmp3->path, - pmp3->index); - - if(err != DB_E_SUCCESS) - DPRINTF(E_FATAL,L_DB,"Error updating file: %s\n",pmp3->fname); - - if(id) { /* we need the insert/update id */ - strcpy(query,"select id from songs where path='%q' and idx=%d"); - - err=db_sql_fetch_int(pe,id,query,pmp3->path,pmp3->index); - if(err != DB_E_SUCCESS) { - return err; - } - } - - if((db_sql_in_scan || db_sql_in_playlist_scan) && (!db_sql_reload)) { - if(id) { - db_sql_exec_fn(NULL,E_FATAL,"insert into updated (id) values (%d)",*id); - } else { - strcpy(query,"insert into updated (id) select id from " - "songs where path='%q' and idx=%d"); - db_sql_exec_fn(NULL,E_FATAL,query,pmp3->path,pmp3->index); - } - } - - if((!db_sql_in_scan) && (!db_sql_in_playlist_scan)) - db_sql_update_playlists(NULL); - - return 0; -} - - -/** - * Update the playlist item counts - */ -int db_sql_update_playlists(char **pe) { - typedef struct tag_plinfo { - char *plid; - char *type; - char *clause; - } PLINFO; - - PLINFO *pinfo; - int playlists; - int err; - int index; - SQL_ROW row; - char *where_clause; - - DPRINTF(E_LOG,L_DB,"Updating playlists\n"); - - /* FIXME: There is a race here for externally added playlists */ - - err = db_sql_fetch_int(pe,&playlists,"select count(*) from playlists"); - - if(err != DB_E_SUCCESS) { - return err; - } - - pinfo = (PLINFO*)malloc(sizeof(PLINFO) * playlists); - if(!pinfo) { - DPRINTF(E_FATAL,L_DB,"Malloc error\n"); - } - - /* now, let's walk through the table */ - err = db_sql_enum_begin_fn(pe,"select * from playlists"); - if(err != DB_E_SUCCESS) - return err; - - /* otherwise, walk the table */ - index=0; - while((db_sql_enum_fetch_fn(pe, &row) == DB_E_SUCCESS) && (row) && - (index < playlists)) - { - /* process row */ - pinfo[index].plid=strdup(STR(row[PL_ID])); - pinfo[index].type=strdup(STR(row[PL_TYPE])); - pinfo[index].clause=strdup(STR(row[PL_QUERY])); - DPRINTF(E_SPAM,L_DB,"Found playlist %s: type %s, clause %s\n",pinfo[index].plid, - pinfo[index].type,pinfo[index].clause); - index++; - } - db_sql_enum_end_fn(pe); - if(index != playlists) { - DPRINTF(E_FATAL,L_DB,"Playlist count mismatch -- transaction problem?\n"); - } - - /* Now, update the playlists */ - for(index=0;index < playlists; index++) { - if(atoi(pinfo[index].type) == PL_SMART) { - /* smart */ - if(!db_sql_parse_smart(NULL,&where_clause,pinfo[index].clause)) { - DPRINTF(E_LOG,L_DB,"Playlist %d bad syntax",pinfo[index].plid); - where_clause = strdup("0"); - } - db_sql_exec_fn(NULL,E_FATAL,"update playlists set items=(" - "select count(*) from songs where %s) " - "where id=%s",where_clause,pinfo[index].plid); - free(where_clause); - } else { - db_sql_exec_fn(NULL,E_FATAL,"update playlists set items=(" - "select count(*) from playlistitems where " - "playlistid=%s) where id=%s", - pinfo[index].plid, pinfo[index].plid); - } - - if(pinfo[index].plid) free(pinfo[index].plid); - if(pinfo[index].type) free(pinfo[index].type); - if(pinfo[index].clause) free(pinfo[index].clause); - } - - free(pinfo); - return DB_E_SUCCESS; -} - - -/** - * start enum based on the DBQUERYINFO struct passed - * - * @param pinfo DBQUERYINFO struct detailing what to enum - */ -int db_sql_enum_start(char **pe, DBQUERYINFO *pinfo) { - char scratch[4096]; - char query[4096]; - char query_select[255]; - char query_count[255]; - char query_rest[4096]; - char *where_clause; - - int is_smart; - int have_clause=0; - int err; - int browse=0; - int results=0; - SQL_ROW temprow; - - query[0] = '\0'; - query_select[0] = '\0'; - query_count[0] = '\0'; - query_rest[0] = '\0'; - - - /* get the where qualifier to filter based on playlist, if there */ - if((pinfo->playlist_id) && (pinfo->playlist_id != 1)) { - err = db_sql_enum_begin_fn(pe, "select type,query from playlists " - "where id=%d",pinfo->playlist_id); - - if(err != DB_E_SUCCESS) - return err; - - err = db_sql_enum_fetch_fn(pe,&temprow); - - if(err != DB_E_SUCCESS) { - db_sql_enum_end_fn(NULL); - return err; - } - - if(!temprow) { /* bad playlist */ - db_get_error(pe,DB_E_INVALID_PLAYLIST); - db_sql_enum_end_fn(NULL); - return DB_E_INVALID_PLAYLIST; - } - - is_smart=(atoi(temprow[0]) == 1); - if(is_smart) { - if(!db_sql_parse_smart(NULL,&where_clause,temprow[1])) - where_clause = strdup("0"); - - if(!where_clause) { - db_sql_enum_end_fn(NULL); - db_get_error(pe,DB_E_PARSE); - return DB_E_PARSE; - } - - snprintf(query_rest,sizeof(query_rest)," where (%s)",where_clause); - free(where_clause); - } else { - - /* We need to fix playlist queries to stop - * pulling the whole song db... the performance - * of these playlist queries sucks. - */ - - if(pinfo->correct_order) { - sprintf(query_rest,",playlistitems where " - "(songs.id=playlistitems.songid and " - "playlistitems.playlistid=%d) order by " - "playlistitems.id",pinfo->playlist_id); - } else { - sprintf(query_rest," where (songs.id in (select songid from " - "playlistitems where playlistid=%d))", - pinfo->playlist_id); - } - } - have_clause=1; - db_sql_enum_end_fn(NULL); - } - - switch(pinfo->query_type) { - case queryTypeItems: - strcpy(query_select,"select * from songs "); - strcpy(query_count,"select count (*) from songs "); - break; - - case queryTypePlaylists: - strcpy(query_select,"select * from playlists "); - strcpy(query_count,"select count (*) from playlists "); - // sprintf(query_rest,"where (%s)",query_playlist); - break; - - case queryTypePlaylistItems: /* Figure out if it's smart or dull */ - sprintf(query_select,"select * from songs "); - sprintf(query_count,"select count(songs.id) from songs "); - break; - - /* Note that sqlite doesn't support COUNT(DISTINCT x) */ - case queryTypeBrowseAlbums: - strcpy(query_select,"select distinct album from songs "); - strcpy(query_count,"select count(album) from (select " - "distinct album from songs "); - browse=1; - break; - - case queryTypeBrowseArtists: - strcpy(query_select,"select distinct artist from songs "); - strcpy(query_count,"select count(artist) from (select " - "distinct artist from songs "); - browse=1; - break; - - case queryTypeBrowseGenres: - strcpy(query_select,"select distinct genre from songs "); - strcpy(query_count,"select count(genre) from (select " - "distinct genre from songs "); - browse=1; - break; - - case queryTypeBrowseComposers: - strcpy(query_select,"select distinct composer from songs "); - strcpy(query_count,"select count(composer) from (select " - "distinct composer from songs "); - browse=1; - break; - default: - DPRINTF(E_LOG,L_DB,"Unknown query type\n"); - return -1; - } - - /* don't browse radio station metadata */ - if(browse) { - if(have_clause) { - strcat(query_rest," and "); - } else { - strcpy(query_rest," where "); - have_clause = 1; - } - - strcat(query_rest,"(data_kind = 0) "); - } - - /* Apply the query/filter */ - if (pinfo->filter) { - DPRINTF(E_DBG, L_DB, "Got new-style query/filter\n"); - - if(have_clause) { - strcat(query_rest, " and "); - } else { - strcpy(query_rest, " where "); - have_clause = 1; - } - strcat(query_rest, pinfo->filter); - } else { - DPRINTF(E_DBG,L_DB,"No query/filter\n"); - } - - /* disable empty */ - if(browse) { - if((have_clause) || (pinfo->filter)) { - strcat(query_rest," and ("); - } else { - strcpy(query_rest," where ("); - have_clause = 1; - } - - switch(pinfo->query_type) { - case queryTypeBrowseAlbums: - strcat(query_rest,"album"); - break; - case queryTypeBrowseArtists: - strcat(query_rest,"artist"); - break; - case queryTypeBrowseGenres: - strcat(query_rest,"genre"); - break; - case queryTypeBrowseComposers: - strcat(query_rest,"composer"); - break; - default: /* ?? */ - strcat(query_rest,"album"); - break; - } - - strcat(query_rest, " !='')"); - } - - if((pinfo->index_type != indexTypeNone) || (pinfo->want_count)) { - /* the only time returned count is not specifiedtotalcount - * is if we have an index. */ - strcpy(scratch,query_count); - strcat(scratch,query_rest); - if(browse) - strcat(scratch,")"); - - err = db_sql_fetch_int(pe,&results,"%s",scratch); - if(err != DB_E_SUCCESS) - return err; - DPRINTF(E_DBG,L_DB,"Number of results: %d\n",results); - pinfo->specifiedtotalcount = results; - } - - strcpy(query,query_select); - strcat(query,query_rest); - - /* FIXME: sqlite specific */ - /* Apply any index */ - switch(pinfo->index_type) { - case indexTypeFirst: - sprintf(scratch," limit %d",pinfo->index_low); - break; - case indexTypeLast: - if(pinfo->index_low >= results) { - sprintf(scratch," limit %d",pinfo->index_low); /* unnecessary */ - } else { - sprintf(scratch," limit %d offset %d",pinfo->index_low, results-pinfo->index_low); - } - break; - case indexTypeSub: - sprintf(scratch," limit %d offset %d", - pinfo->index_high - pinfo->index_low + 1, - pinfo->index_low); - break; - case indexTypeNone: - break; - default: - DPRINTF(E_LOG,L_DB,"Bad indexType: %d\n",(int)pinfo->index_type); - scratch[0]='\0'; - break; - } - - if(pinfo->index_type != indexTypeNone) - strcat(query,scratch); - - /* start fetching... */ - err=db_sql_enum_begin_fn(pe,"%s",query); - return err; -} - - -/** - * fetch the next row in raw row format - */ -int db_sql_enum_fetch_row(char **pe, PACKED_MP3FILE **row, DBQUERYINFO *pinfo) { - int err; - - err=db_sql_enum_fetch_fn(pe, (char***)row); - if(err != DB_E_SUCCESS) { - db_sql_enum_end_fn(NULL); - return err; - } - - return DB_E_SUCCESS; -} - -/** - * start the enum again - */ -int db_sql_enum_reset(char **pe, DBQUERYINFO *pinfo) { - return db_sql_enum_restart_fn(pe); -} - - -/** - * stop the enum - */ -int db_sql_enum_end(char **pe) { - return db_sql_enum_end_fn(pe); -} - -void db_sql_build_m3ufile(SQL_ROW valarray, M3UFILE *pm3u) { - memset(pm3u,0x00,sizeof(M3UFILE)); - - pm3u->id=db_sql_atoi(valarray[0]); - pm3u->title=db_sql_strdup(valarray[1]); - pm3u->type=db_sql_atoi(valarray[2]); - pm3u->items=db_sql_atoi(valarray[3]); - pm3u->query=db_sql_strdup(valarray[4]); - pm3u->db_timestamp=db_sql_atoi(valarray[5]); - pm3u->path=db_sql_strdup(valarray[6]); - pm3u->index=db_sql_atoi(valarray[7]); - return; -} - -void db_sql_build_mp3file(SQL_ROW valarray, MP3FILE *pmp3) { - memset(pmp3,0x00,sizeof(MP3FILE)); - pmp3->id=db_sql_atoi(valarray[0]); - pmp3->path=db_sql_strdup(valarray[1]); - pmp3->fname=db_sql_strdup(valarray[2]); - pmp3->title=db_sql_strdup(valarray[3]); - pmp3->artist=db_sql_strdup(valarray[4]); - pmp3->album=db_sql_strdup(valarray[5]); - pmp3->genre=db_sql_strdup(valarray[6]); - pmp3->comment=db_sql_strdup(valarray[7]); - pmp3->type=db_sql_strdup(valarray[8]); - pmp3->composer=db_sql_strdup(valarray[9]); - pmp3->orchestra=db_sql_strdup(valarray[10]); - pmp3->conductor=db_sql_strdup(valarray[11]); - pmp3->grouping=db_sql_strdup(valarray[12]); - pmp3->url=db_sql_strdup(valarray[13]); - pmp3->bitrate=db_sql_atoi(valarray[14]); - pmp3->samplerate=db_sql_atoi(valarray[15]); - pmp3->song_length=db_sql_atoi(valarray[16]); - pmp3->file_size=db_sql_atol(valarray[17]); - pmp3->year=db_sql_atoi(valarray[18]); - pmp3->track=db_sql_atoi(valarray[19]); - pmp3->total_tracks=db_sql_atoi(valarray[20]); - pmp3->disc=db_sql_atoi(valarray[21]); - pmp3->total_discs=db_sql_atoi(valarray[22]); - pmp3->bpm=db_sql_atoi(valarray[23]); - pmp3->compilation=db_sql_atoi(valarray[24]); - pmp3->rating=db_sql_atoi(valarray[25]); - pmp3->play_count=db_sql_atoi(valarray[26]); - pmp3->data_kind=db_sql_atoi(valarray[27]); - pmp3->item_kind=db_sql_atoi(valarray[28]); - pmp3->description=db_sql_strdup(valarray[29]); - pmp3->time_added=db_sql_atoi(valarray[30]); - pmp3->time_modified=db_sql_atoi(valarray[31]); - pmp3->time_played=db_sql_atoi(valarray[32]); - pmp3->db_timestamp=db_sql_atoi(valarray[33]); - pmp3->disabled=db_sql_atoi(valarray[34]); - pmp3->sample_count=db_sql_atol(valarray[35]); - pmp3->force_update=db_sql_atoi(valarray[36]); - pmp3->codectype=db_sql_strdup(valarray[37]); - pmp3->index=db_sql_atoi(valarray[38]); - pmp3->has_video=db_sql_atoi(valarray[39]); - pmp3->contentrating=db_sql_atoi(valarray[40]); - pmp3->bits_per_sample=db_sql_atoi(valarray[41]); - pmp3->album_artist=db_sql_strdup(valarray[42]); -} - -/** - * fetch a playlist by path and index - * - * @param path path to fetch - */ -M3UFILE *db_sql_fetch_playlist(char **pe, char *path, int index) { - int result; - M3UFILE *pm3u=NULL; - SQL_ROW row; - - result = db_sql_fetch_row(pe, &row, "select * from playlists where " - "path='%q' and idx=%d",path,index); - - if(result != DB_E_SUCCESS) { - if(result == DB_E_NOROWS) { - if(pe) { free(*pe); }; - db_get_error(pe,DB_E_INVALID_PLAYLIST); - return NULL; - } - - return NULL; /* sql error or something */ - } - - pm3u=(M3UFILE*)malloc(sizeof(M3UFILE)); - if(!pm3u) - DPRINTF(E_FATAL,L_MISC,"malloc error: db_sql_fetch_playlist\n"); - - db_sql_build_m3ufile(row,pm3u); - db_sql_dispose_row(); - - if((db_sql_in_playlist_scan) && (!db_sql_reload)) { - db_sql_exec_fn(NULL,E_FATAL,"insert into plupdated values (%d)", - pm3u->id); - } - - return pm3u; -} - - -/* FIXME: bad error handling -- not like the rest */ - -/** - * fetch a MP3FILE for a specific id - * - * @param id id to fetch - */ -MP3FILE *db_sql_fetch_item(char **pe, int id) { - SQL_ROW row; - MP3FILE *pmp3=NULL; - int err; - - err=db_sql_fetch_row(pe,&row,"select * from songs where id=%d",id); - if(err != DB_E_SUCCESS) { - if(err == DB_E_NOROWS) { /* Override generic error */ - if(pe) { free(*pe); }; - db_get_error(pe,DB_E_INVALID_SONGID); - return NULL; - } - return NULL; - } - - pmp3=(MP3FILE*)malloc(sizeof(MP3FILE)); - if(!pmp3) - DPRINTF(E_FATAL,L_MISC,"Malloc error in db_sql_fetch_item\n"); - - db_sql_build_mp3file(row,pmp3); - - db_sql_dispose_row(); - - if ((db_sql_in_scan || db_sql_in_playlist_scan) && (!db_sql_reload)) { - db_sql_exec_fn(pe,E_DBG,"INSERT INTO updated VALUES (%d)",id); - } - - return pmp3; -} - -/** - * retrieve a MP3FILE struct for the song with a given path - * - * @param path path of the file to retreive - */ -MP3FILE *db_sql_fetch_path(char **pe, char *path, int index) { - SQL_ROW row; - MP3FILE *pmp3=NULL; - int err; - char *query; - - /* if we are doing a full reload, then it can't be in here. - * besides, we don't have an index anyway, so we don't want to - * do this fetch right now - */ - if((db_sql_in_scan) && (db_sql_reload)) - return NULL; - - /* not very portable, but works for sqlite */ - query="select * from songs where path='%q' and idx=%d"; - - err=db_sql_fetch_row(pe,&row,query,path,index); - - if(err != DB_E_SUCCESS) { - if(err == DB_E_NOROWS) { /* Override generic error */ - if(pe) { free(*pe); }; - db_get_error(pe,DB_E_NOTFOUND); - return NULL; - } - return NULL; - } - - pmp3=(MP3FILE*)malloc(sizeof(MP3FILE)); - if(!pmp3) - DPRINTF(E_FATAL,L_MISC,"Malloc error in db_sql_fetch_path\n"); - - db_sql_build_mp3file(row,pmp3); - - db_sql_dispose_row(); - - if ((db_sql_in_scan || db_sql_in_playlist_scan) && (!db_sql_reload)) { - db_sql_exec_fn(pe,E_DBG,"INSERT INTO updated VALUES (%d)",pmp3->id); - } - - return pmp3; -} - -/** - * dispose of a MP3FILE struct that was obtained - * from db_sql_fetch_item - * - * @param pmp3 item obtained from db_sql_fetch_item - */ -void db_sql_dispose_item(MP3FILE *pmp3) { - if(!pmp3) - return; - - MAYBEFREE(pmp3->path); - MAYBEFREE(pmp3->fname); - MAYBEFREE(pmp3->title); - MAYBEFREE(pmp3->artist); - MAYBEFREE(pmp3->album); - MAYBEFREE(pmp3->genre); - MAYBEFREE(pmp3->comment); - MAYBEFREE(pmp3->type); - MAYBEFREE(pmp3->composer); - MAYBEFREE(pmp3->orchestra); - MAYBEFREE(pmp3->conductor); - MAYBEFREE(pmp3->grouping); - MAYBEFREE(pmp3->description); - MAYBEFREE(pmp3->url); - MAYBEFREE(pmp3->codectype); - MAYBEFREE(pmp3->album_artist); - free(pmp3); -} - -void db_sql_dispose_playlist(M3UFILE *pm3u) { - if(!pm3u) - return; - - MAYBEFREE(pm3u->title); - MAYBEFREE(pm3u->query); - MAYBEFREE(pm3u->path); - free(pm3u); -} - -/** - * count either the number of playlists, or the number of - * songs - * - * @param type either countPlaylists or countSongs (type to count) - */ -int db_sql_get_count(char **pe, int *count, CountType_t type) { - char *table; - int err; - - switch(type) { - case countPlaylists: - table="playlists"; - break; - - case countSongs: - default: - table="songs"; - break; - } - - err=db_sql_fetch_int(pe,count,"select count(*) FROM %q", table); - return err; -} - -/** - * increment the play_count and time_played - * - * @param pe error string - * @param id id of the song to increment - * @returns DB_E_SUCCESS on success, error code otherwise - */ -int db_sql_playcount_increment(char **pe, int id) { - time_t now = time(NULL); - - return db_sql_exec_fn(pe,E_INFO,"update songs set play_count=play_count + 1" - ", time_played=%d where id=%d",now,id); -} - - diff --git a/src/db-sql.h b/src/db-sql.h deleted file mode 100644 index 73ab7b92..00000000 --- a/src/db-sql.h +++ /dev/null @@ -1,126 +0,0 @@ -/* - * sql-specific db implementation - * - * Copyright (C) 2005 Ron Pedde (ron@pedde.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _DB_SQL_H_ -#define _DB_SQL_H_ - -typedef char** SQL_ROW; - -#ifdef HAVE_SQLITE3 -extern int db_sql_open_sqlite3(char **pe, char *parameters); -#endif - -extern int db_sql_open(char **pe, char *parameters); -extern int db_sql_init(int reload); -extern int db_sql_deinit(void); -extern int db_sql_escape(char *buffer, int *size, char *fmt, ...); -extern char * db_sql_escape_dup(char *fmt, ...); -extern int db_sql_add(char **pe, MP3FILE *pmp3, int *id); -extern int db_sql_enum_start(char **pe, DBQUERYINFO *pinfo); - - -extern int db_sql_enum_fetch_row(char **pe, PACKED_MP3FILE **row, DBQUERYINFO *pinfo); -extern int db_sql_enum_reset(char **pe, DBQUERYINFO *pinfo); -extern int db_sql_enum_end(char **pe); -extern int db_sql_force_rescan(char **pe); -extern int db_sql_start_scan(void); -extern int db_sql_end_song_scan(void); -extern int db_sql_end_scan(void); -extern int db_sql_get_count(char **pe, int *count, CountType_t type); -extern MP3FILE *db_sql_fetch_item(char **pe, int id); -extern MP3FILE *db_sql_fetch_path(char **pe, char *path,int index); -extern M3UFILE *db_sql_fetch_playlist(char **pe, char *path, int index); -extern void db_sql_dispose_item(MP3FILE *pmp3); -extern void db_sql_dispose_playlist(M3UFILE *pm3u); -extern int db_sql_add_playlist(char **pe, char *name, int type, char *clause, char *path, int index, int *playlistid); -extern int db_sql_add_playlist_item(char **pe, int playlistid, int songid); -extern int db_sql_edit_playlist(char **pe, int id, char *name, char *clause); -extern int db_sql_delete_playlist(char **pe, int playlistid); -extern int db_sql_delete_playlist_item(char **pe, int playlistid, int songid); -extern int db_sql_playcount_increment(char **pe, int id); - -extern int db_sql_fetch_row(char **pe, SQL_ROW *row, char *fmt, ...); -extern int db_sql_fetch_int(char **pe, int *result, char *fmt, ...); -extern int db_sql_fetch_char(char **pe, char **result, char *fmt, ...); -extern int db_sql_dispose_row(void); - -/* -typedef enum { - songID, - songPath, - songFname, - songTitle, - songArtist, - songAlbum, - songGenre, - songComment, - songType, - songComposer, - songOrchestra, - songGrouping, - songURL, - songBitrate, - songSampleRate, - songLength, - songFilesize, - songYear, - songTrack, - songTotalTracks, - songDisc, - songTotalDiscs, - songBPM, - songCompilation, - songRating, - songPlayCount, - songDataKind, - songItemKind, - songDescription, - songTimeAdded, - songTimeModified, - songTimePlayed, - songDBTimestamp, - songDisabled, - songSampleCount, - songForceUpdate, - songCodecType -} SongField_t; -*/ - -/* -typedef enum { - plID, - plTitle, - plType, - plItems, - plQuery, - plDBTimestamp, - plPath -} PlaylistField_t; -*/ - -#define DB_SQL_EVENT_STARTUP 0 -#define DB_SQL_EVENT_SONGSCANSTART 1 -#define DB_SQL_EVENT_SONGSCANEND 2 -#define DB_SQL_EVENT_PLSCANSTART 3 -#define DB_SQL_EVENT_PLSCANEND 4 -#define DB_SQL_EVENT_FULLRELOAD 5 - - -#endif /* _DB_SQL_H_ */ diff --git a/src/ff-dbstruct.h b/src/ff-dbstruct.h deleted file mode 100644 index 97e7303c..00000000 --- a/src/ff-dbstruct.h +++ /dev/null @@ -1,199 +0,0 @@ -/* - * Database structure and fields - */ - -#ifndef _FF_DBSTRUCT_H_ -#define _FF_DBSTRUCT_H_ - -#include - -#define PL_ID 0 -#define PL_TITLE 1 -#define PL_TYPE 2 -#define PL_ITEMS 3 -#define PL_QUERY 4 -#define PL_DB_TIMESTAMP 5 -#define PL_PATH 6 -#define PL_IDX 7 - -#define SG_ID 0 -#define SG_PATH 1 -#define SG_FNAME 2 -#define SG_TITLE 3 -#define SG_ARTIST 4 -#define SG_ALBUM 5 -#define SG_GENRE 6 -#define SG_COMMENT 7 -#define SG_TYPE 8 -#define SG_COMPOSER 9 -#define SG_ORCHESTRA 10 -#define SG_CONDUCTOR 11 -#define SG_GROUPING 12 -#define SG_URL 13 -#define SG_BITRATE 14 -#define SG_SAMPLERATE 15 -#define SG_SONG_LENGTH 16 -#define SG_FILE_SIZE 17 -#define SG_YEAR 18 -#define SG_TRACK 19 -#define SG_TOTAL_TRACKS 20 -#define SG_DISC 21 -#define SG_TOTAL_DISCS 22 -#define SG_BPM 23 -#define SG_COMPILATION 24 -#define SG_RATING 25 -#define SG_PLAY_COUNT 26 -#define SG_DATA_KIND 27 -#define SG_ITEM_KIND 28 -#define SG_DESCRIPTION 29 -#define SG_TIME_ADDED 30 -#define SG_TIME_MODIFIED 31 -#define SG_TIME_PLAYED 32 -#define SG_DB_TIMESTAMP 33 -#define SG_DISABLED 34 -#define SG_SAMPLE_COUNT 35 -#define SG_FORCE_UPDATE 36 -#define SG_CODECTYPE 37 -#define SG_IDX 38 -#define SG_HAS_VIDEO 39 -#define SG_CONTENTRATING 40 -#define SG_BITS_PER_SAMPLE 41 -#define SG_ALBUM_ARTIST 42 - -/* Packed and unpacked formats */ -typedef struct media_file_info { - char *path; - uint32_t index; - char *fname; - char *title; /* TIT2 */ - char *artist; /* TPE1 */ - char *album; /* TALB */ - char *genre; /* TCON */ - char *comment; /* COMM */ - char *type; /* daap.songformat */ - char *composer; /* TCOM */ - char *orchestra; /* TPE2 */ - char *conductor; /* TPE3 */ - char *grouping; /* TIT1 */ - char *url; /* daap.songdataurl (asul) */ - - uint32_t bitrate; - uint32_t samplerate; - uint32_t song_length; - uint64_t file_size; /* ?? */ - uint32_t year; /* TDRC */ - - uint32_t track; /* TRCK */ - uint32_t total_tracks; - - uint32_t disc; /* TPOS */ - uint32_t total_discs; - - uint32_t time_added; /* really should be a time_t */ - uint32_t time_modified; - uint32_t time_played; - - uint32_t play_count; - uint32_t rating; - uint32_t db_timestamp; - - uint32_t disabled; - uint32_t bpm; /* TBPM */ - - uint32_t got_id3; - uint32_t id; - - char *description; /* daap.songdescription */ - char *codectype; /* song.codectype */ - /* codectype will be encoded as a short int, no more than 4 chars */ - - uint32_t item_kind; /* song or movie */ - uint32_t data_kind; /* dmap.datakind (asdk) */ - uint32_t force_update; - uint64_t sample_count; - char compilation; - - /* iTunes 5+ */ - uint32_t contentrating; - - /* iTunes 6.0.2 */ - uint32_t has_video; - uint32_t bits_per_sample; - - char *album_artist; -} MP3FILE; - -typedef struct playlist_info { - uint32_t id; /**< integer id (miid) */ - char *title; /**< playlist name as displayed in iTunes (minm) */ - uint32_t type; /**< see PL_ types */ - uint32_t items; /**< number of items (mimc) */ - char *query; /**< where clause if type 1 (MSPS) */ - uint32_t db_timestamp;/**< time last updated */ - char *path; /**< path of underlying playlist (if type 2) */ - uint32_t index; /**< index of playlist for paths with multiple playlists */ -} M3UFILE; - -typedef struct db_playlist_info { - char *id; - char *title; - char *type; - char *items; - char *query; - char *db_timestamp; - char *path; - char *index; -} PACKED_M3UFILE; - -typedef struct db_media_file_info { - char *id; - char *path; - char *fname; - char *title; - char *artist; - char *album; - char *genre; - char *comment; - char *type; - char *composer; - char *orchestra; - char *conductor; - char *grouping; - char *url; - char *bitrate; - char *samplerate; - char *song_length; - char *file_size; - char *year; - char *track; - char *total_tracks; - char *disc; - char *total_discs; - char *bpm; - char *compilation; - char *rating; - char *play_count; - char *data_kind; - char *item_kind; - char *description; - char *time_added; - char *time_modified; - char *time_played; - char *db_timestamp; - char *disabled; - char *sample_count; - char *force_update; - char *codectype; - char *idx; - char *has_video; - char *contentrating; - char *bits_per_sample; - char *album_artist; -} PACKED_MP3FILE; - -#define PL_STATICWEB 0 -#define PL_SMART 1 -#define PL_STATICFILE 2 -#define PL_STATICXML 3 - -#endif /* _FF_DBSTRUCT_H_ */