2009-06-07 12:56:35 -04:00
/*
2011-03-08 12:54:20 -05:00
* Copyright ( C ) 2009 - 2011 Julien BLACHE < jb @ jblache . org >
2010-08-29 04:21:35 -04:00
* Copyright ( C ) 2010 Kai Elwert < elwertk @ googlemail . com >
2009-06-07 12:56:35 -04:00
*
* 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
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <time.h>
# include <stdint.h>
# include <inttypes.h>
2010-08-29 04:21:35 -04:00
# include <errno.h>
2011-03-15 16:26:17 -04:00
# include <sys/types.h>
# include <sys/stat.h>
# include <unistd.h>
# include <sys/mman.h>
2014-12-21 14:41:44 -05:00
# include <limits.h>
2011-03-15 16:26:17 -04:00
2009-06-07 12:56:35 -04:00
# include <pthread.h>
# include <sqlite3.h>
2010-03-21 06:33:05 -04:00
# include "conffile.h"
2009-06-07 12:56:35 -04:00
# include "logger.h"
2014-11-10 16:53:08 -05:00
# include "cache.h"
2010-03-06 11:21:54 -05:00
# include "misc.h"
2009-06-07 12:56:35 -04:00
# include "db.h"
2015-12-19 01:51:10 -05:00
# include "db_upgrade.h"
2009-06-07 12:56:35 -04:00
# define STR(x) ((x) ? (x) : "")
2009-06-10 12:11:11 -04:00
/* Inotify cookies are uint32_t */
# define INOTIFY_FAKE_COOKIE ((int64_t)1 << 32)
2009-06-07 12:56:35 -04:00
2010-03-06 12:56:30 -05:00
enum group_type {
G_ALBUMS = 1 ,
2013-12-17 14:58:55 -05:00
G_ARTISTS = 2 ,
2010-03-06 12:56:30 -05:00
} ;
2010-04-26 12:24:09 -04:00
struct db_unlock {
int proceed ;
pthread_cond_t cond ;
pthread_mutex_t lck ;
} ;
2009-06-07 12:56:35 -04:00
# define DB_TYPE_CHAR 1
# define DB_TYPE_INT 2
# define DB_TYPE_INT64 3
# define DB_TYPE_STRING 4
struct col_type_map {
ssize_t offset ;
short type ;
} ;
/* This list must be kept in sync with
2009-06-11 17:03:53 -04:00
* - the order of the columns in the files table
2009-06-07 12:56:35 -04:00
* - the type and name of the fields in struct media_file_info
*/
2010-03-23 13:55:39 -04:00
static const struct col_type_map mfi_cols_map [ ] =
2009-06-07 12:56:35 -04:00
{
2009-12-26 02:44:55 -05:00
{ mfi_offsetof ( id ) , DB_TYPE_INT } ,
{ mfi_offsetof ( path ) , DB_TYPE_STRING } ,
{ mfi_offsetof ( fname ) , DB_TYPE_STRING } ,
{ mfi_offsetof ( title ) , DB_TYPE_STRING } ,
{ mfi_offsetof ( artist ) , DB_TYPE_STRING } ,
{ mfi_offsetof ( album ) , DB_TYPE_STRING } ,
{ mfi_offsetof ( genre ) , DB_TYPE_STRING } ,
{ mfi_offsetof ( comment ) , DB_TYPE_STRING } ,
{ mfi_offsetof ( type ) , DB_TYPE_STRING } ,
{ mfi_offsetof ( composer ) , DB_TYPE_STRING } ,
{ mfi_offsetof ( orchestra ) , DB_TYPE_STRING } ,
{ mfi_offsetof ( conductor ) , DB_TYPE_STRING } ,
{ mfi_offsetof ( grouping ) , DB_TYPE_STRING } ,
{ mfi_offsetof ( url ) , DB_TYPE_STRING } ,
{ mfi_offsetof ( bitrate ) , DB_TYPE_INT } ,
{ mfi_offsetof ( samplerate ) , DB_TYPE_INT } ,
{ mfi_offsetof ( song_length ) , DB_TYPE_INT } ,
{ mfi_offsetof ( file_size ) , DB_TYPE_INT64 } ,
{ mfi_offsetof ( year ) , DB_TYPE_INT } ,
{ mfi_offsetof ( track ) , DB_TYPE_INT } ,
{ mfi_offsetof ( total_tracks ) , DB_TYPE_INT } ,
{ mfi_offsetof ( disc ) , DB_TYPE_INT } ,
{ mfi_offsetof ( total_discs ) , DB_TYPE_INT } ,
{ mfi_offsetof ( bpm ) , DB_TYPE_INT } ,
{ mfi_offsetof ( compilation ) , DB_TYPE_CHAR } ,
2014-01-11 17:05:29 -05:00
{ mfi_offsetof ( artwork ) , DB_TYPE_CHAR } ,
2009-12-26 02:44:55 -05:00
{ mfi_offsetof ( rating ) , DB_TYPE_INT } ,
{ mfi_offsetof ( play_count ) , DB_TYPE_INT } ,
2013-12-17 14:58:55 -05:00
{ mfi_offsetof ( seek ) , DB_TYPE_INT } ,
2009-12-26 02:44:55 -05:00
{ mfi_offsetof ( data_kind ) , DB_TYPE_INT } ,
{ mfi_offsetof ( item_kind ) , DB_TYPE_INT } ,
{ mfi_offsetof ( description ) , DB_TYPE_STRING } ,
{ mfi_offsetof ( time_added ) , DB_TYPE_INT } ,
{ mfi_offsetof ( time_modified ) , DB_TYPE_INT } ,
{ mfi_offsetof ( time_played ) , DB_TYPE_INT } ,
{ mfi_offsetof ( db_timestamp ) , DB_TYPE_INT } ,
{ mfi_offsetof ( disabled ) , DB_TYPE_INT } ,
{ mfi_offsetof ( sample_count ) , DB_TYPE_INT64 } ,
{ mfi_offsetof ( codectype ) , DB_TYPE_STRING } ,
{ mfi_offsetof ( index ) , DB_TYPE_INT } ,
{ mfi_offsetof ( has_video ) , DB_TYPE_INT } ,
{ mfi_offsetof ( contentrating ) , DB_TYPE_INT } ,
{ mfi_offsetof ( bits_per_sample ) , DB_TYPE_INT } ,
{ mfi_offsetof ( album_artist ) , DB_TYPE_STRING } ,
{ mfi_offsetof ( media_kind ) , DB_TYPE_INT } ,
{ mfi_offsetof ( tv_series_name ) , DB_TYPE_STRING } ,
{ mfi_offsetof ( tv_episode_num_str ) , DB_TYPE_STRING } ,
{ mfi_offsetof ( tv_network_name ) , DB_TYPE_STRING } ,
{ mfi_offsetof ( tv_episode_sort ) , DB_TYPE_INT } ,
{ mfi_offsetof ( tv_season_num ) , DB_TYPE_INT } ,
2013-12-17 14:58:55 -05:00
{ mfi_offsetof ( songartistid ) , DB_TYPE_INT64 } ,
2010-03-06 11:13:56 -05:00
{ mfi_offsetof ( songalbumid ) , DB_TYPE_INT64 } ,
2010-09-21 07:16:38 -04:00
{ mfi_offsetof ( title_sort ) , DB_TYPE_STRING } ,
{ mfi_offsetof ( artist_sort ) , DB_TYPE_STRING } ,
{ mfi_offsetof ( album_sort ) , DB_TYPE_STRING } ,
{ mfi_offsetof ( composer_sort ) , DB_TYPE_STRING } ,
{ mfi_offsetof ( album_artist_sort ) , DB_TYPE_STRING } ,
2014-12-21 14:41:44 -05:00
{ mfi_offsetof ( virtual_path ) , DB_TYPE_STRING } ,
2015-12-27 01:16:50 -05:00
{ mfi_offsetof ( directory_id ) , DB_TYPE_INT } ,
2016-01-29 13:46:56 -05:00
{ mfi_offsetof ( date_released ) , DB_TYPE_INT } ,
2009-06-07 12:56:35 -04:00
} ;
/* This list must be kept in sync with
* - the order of the columns in the playlists table
* - the type and name of the fields in struct playlist_info
*/
2010-03-23 13:55:39 -04:00
static const struct col_type_map pli_cols_map [ ] =
2009-06-07 12:56:35 -04:00
{
{ pli_offsetof ( id ) , DB_TYPE_INT } ,
{ pli_offsetof ( title ) , DB_TYPE_STRING } ,
{ pli_offsetof ( type ) , DB_TYPE_INT } ,
{ pli_offsetof ( query ) , DB_TYPE_STRING } ,
{ pli_offsetof ( db_timestamp ) , DB_TYPE_INT } ,
2009-06-10 09:23:02 -04:00
{ pli_offsetof ( disabled ) , DB_TYPE_INT } ,
2009-06-07 12:56:35 -04:00
{ pli_offsetof ( path ) , DB_TYPE_STRING } ,
{ pli_offsetof ( index ) , DB_TYPE_INT } ,
2010-01-21 11:52:51 -05:00
{ pli_offsetof ( special_id ) , DB_TYPE_INT } ,
2014-12-21 14:41:44 -05:00
{ pli_offsetof ( virtual_path ) , DB_TYPE_STRING } ,
2015-03-14 18:35:19 -04:00
{ pli_offsetof ( parent_id ) , DB_TYPE_INT } ,
2015-12-27 01:16:50 -05:00
{ pli_offsetof ( directory_id ) , DB_TYPE_INT } ,
2009-06-11 12:28:01 -04:00
/* items is computed on the fly */
2009-06-07 12:56:35 -04:00
} ;
/* This list must be kept in sync with
2009-06-11 17:03:53 -04:00
* - the order of the columns in the files table
2009-06-07 12:56:35 -04:00
* - the name of the fields in struct db_media_file_info
*/
2010-03-23 13:55:39 -04:00
static const ssize_t dbmfi_cols_map [ ] =
2009-06-07 12:56:35 -04:00
{
dbmfi_offsetof ( id ) ,
dbmfi_offsetof ( path ) ,
dbmfi_offsetof ( fname ) ,
dbmfi_offsetof ( title ) ,
dbmfi_offsetof ( artist ) ,
dbmfi_offsetof ( album ) ,
dbmfi_offsetof ( genre ) ,
dbmfi_offsetof ( comment ) ,
dbmfi_offsetof ( type ) ,
dbmfi_offsetof ( composer ) ,
dbmfi_offsetof ( orchestra ) ,
dbmfi_offsetof ( conductor ) ,
dbmfi_offsetof ( grouping ) ,
dbmfi_offsetof ( url ) ,
dbmfi_offsetof ( bitrate ) ,
dbmfi_offsetof ( samplerate ) ,
dbmfi_offsetof ( song_length ) ,
dbmfi_offsetof ( file_size ) ,
dbmfi_offsetof ( year ) ,
dbmfi_offsetof ( track ) ,
dbmfi_offsetof ( total_tracks ) ,
dbmfi_offsetof ( disc ) ,
dbmfi_offsetof ( total_discs ) ,
dbmfi_offsetof ( bpm ) ,
dbmfi_offsetof ( compilation ) ,
2014-01-11 17:05:29 -05:00
dbmfi_offsetof ( artwork ) ,
2009-06-07 12:56:35 -04:00
dbmfi_offsetof ( rating ) ,
dbmfi_offsetof ( play_count ) ,
2013-12-17 14:58:55 -05:00
dbmfi_offsetof ( seek ) ,
2009-06-07 12:56:35 -04:00
dbmfi_offsetof ( data_kind ) ,
dbmfi_offsetof ( item_kind ) ,
dbmfi_offsetof ( description ) ,
dbmfi_offsetof ( time_added ) ,
dbmfi_offsetof ( time_modified ) ,
dbmfi_offsetof ( time_played ) ,
dbmfi_offsetof ( db_timestamp ) ,
dbmfi_offsetof ( disabled ) ,
dbmfi_offsetof ( sample_count ) ,
dbmfi_offsetof ( codectype ) ,
dbmfi_offsetof ( idx ) ,
dbmfi_offsetof ( has_video ) ,
dbmfi_offsetof ( contentrating ) ,
dbmfi_offsetof ( bits_per_sample ) ,
dbmfi_offsetof ( album_artist ) ,
2009-12-26 02:39:39 -05:00
dbmfi_offsetof ( media_kind ) ,
dbmfi_offsetof ( tv_series_name ) ,
dbmfi_offsetof ( tv_episode_num_str ) ,
dbmfi_offsetof ( tv_network_name ) ,
dbmfi_offsetof ( tv_episode_sort ) ,
dbmfi_offsetof ( tv_season_num ) ,
2013-12-17 14:58:55 -05:00
dbmfi_offsetof ( songartistid ) ,
2010-03-06 11:13:56 -05:00
dbmfi_offsetof ( songalbumid ) ,
2010-09-21 07:16:38 -04:00
dbmfi_offsetof ( title_sort ) ,
dbmfi_offsetof ( artist_sort ) ,
dbmfi_offsetof ( album_sort ) ,
dbmfi_offsetof ( composer_sort ) ,
dbmfi_offsetof ( album_artist_sort ) ,
2014-12-21 14:41:44 -05:00
dbmfi_offsetof ( virtual_path ) ,
2015-12-27 01:16:50 -05:00
dbmfi_offsetof ( directory_id ) ,
2016-01-29 13:46:56 -05:00
dbmfi_offsetof ( date_released ) ,
2009-06-07 12:56:35 -04:00
} ;
/* This list must be kept in sync with
* - the order of the columns in the playlists table
* - the name of the fields in struct playlist_info
*/
2010-03-23 13:55:39 -04:00
static const ssize_t dbpli_cols_map [ ] =
2009-06-07 12:56:35 -04:00
{
dbpli_offsetof ( id ) ,
dbpli_offsetof ( title ) ,
dbpli_offsetof ( type ) ,
dbpli_offsetof ( query ) ,
dbpli_offsetof ( db_timestamp ) ,
2009-06-10 09:23:02 -04:00
dbpli_offsetof ( disabled ) ,
2009-06-07 12:56:35 -04:00
dbpli_offsetof ( path ) ,
dbpli_offsetof ( index ) ,
2010-01-21 11:52:51 -05:00
dbpli_offsetof ( special_id ) ,
2015-02-23 14:49:53 -05:00
dbpli_offsetof ( virtual_path ) ,
2015-03-14 18:35:19 -04:00
dbpli_offsetof ( parent_id ) ,
2015-12-27 01:16:50 -05:00
dbpli_offsetof ( directory_id ) ,
2009-06-11 12:28:01 -04:00
/* items is computed on the fly */
2009-06-07 12:56:35 -04:00
} ;
2010-01-10 06:26:48 -05:00
/* This list must be kept in sync with
2013-08-29 16:00:37 -04:00
* - the order of fields in the Q_GROUP_ALBUMS and Q_GROUP_ARTISTS query
2010-01-10 06:26:48 -05:00
* - the name of the fields in struct group_info
*/
2010-03-23 13:55:39 -04:00
static const ssize_t dbgri_cols_map [ ] =
2010-01-10 06:26:48 -05:00
{
2010-03-06 12:56:30 -05:00
dbgri_offsetof ( id ) ,
2010-01-10 06:26:48 -05:00
dbgri_offsetof ( persistentid ) ,
dbgri_offsetof ( itemname ) ,
2013-12-18 13:14:39 -05:00
dbgri_offsetof ( itemname_sort ) ,
2013-12-15 15:47:49 -05:00
dbgri_offsetof ( itemcount ) ,
dbgri_offsetof ( groupalbumcount ) ,
dbgri_offsetof ( songalbumartist ) ,
2014-02-21 14:39:57 -05:00
dbgri_offsetof ( songartistid ) ,
2010-01-10 06:26:48 -05:00
} ;
2009-06-10 12:11:11 -04:00
/* This list must be kept in sync with
* - the order of the columns in the inotify table
* - the name and type of the fields in struct watch_info
*/
2010-03-23 13:55:39 -04:00
static const struct col_type_map wi_cols_map [ ] =
2009-06-10 12:11:11 -04:00
{
2009-12-26 02:44:55 -05:00
{ wi_offsetof ( wd ) , DB_TYPE_INT } ,
2009-06-10 12:11:11 -04:00
{ wi_offsetof ( cookie ) , DB_TYPE_INT } ,
2009-12-26 02:44:55 -05:00
{ wi_offsetof ( path ) , DB_TYPE_STRING } ,
2009-06-10 12:11:11 -04:00
} ;
2010-08-05 12:24:50 -04:00
/* Sort clauses */
/* Keep in sync with enum sort_type */
static const char * sort_clause [ ] =
{
" " ,
2011-03-28 13:06:48 -04:00
" ORDER BY f.title_sort ASC " ,
" ORDER BY f.album_sort ASC, f.disc ASC, f.track ASC " ,
2015-06-01 17:36:16 -04:00
" ORDER BY f.album_artist_sort ASC, f.album_sort ASC, f.disc ASC, f.track ASC " ,
2015-04-21 13:12:54 -04:00
" ORDER BY f.type ASC, f.parent_id ASC, f.special_id ASC, f.title ASC " ,
2015-02-23 12:43:38 -05:00
" ORDER BY f.year ASC " ,
2015-05-26 15:10:28 -04:00
" ORDER BY f.genre ASC " ,
" ORDER BY f.composer_sort ASC " ,
" ORDER BY f.disc ASC " ,
" ORDER BY f.track ASC " ,
2015-05-29 23:31:54 -04:00
" ORDER BY f.virtual_path ASC " ,
2010-08-05 12:24:50 -04:00
} ;
2010-03-21 06:33:05 -04:00
static char * db_path ;
2009-06-07 12:56:35 -04:00
static __thread sqlite3 * hdl ;
2009-06-11 12:28:01 -04:00
/* Forward */
static int
2015-03-16 18:33:42 -04:00
db_pl_count_items ( int id , int streams_only ) ;
2009-06-11 12:28:01 -04:00
2010-01-21 11:52:51 -05:00
static int
db_smartpl_count_items ( const char * smartpl_query ) ;
struct playlist_info *
db_pl_fetch_byid ( int id ) ;
2014-11-10 16:53:08 -05:00
static enum group_type
db_group_type_bypersistentid ( int64_t persistentid ) ;
2009-06-11 12:28:01 -04:00
2009-06-07 12:56:35 -04:00
char *
db_escape_string ( const char * str )
{
char * escaped ;
char * ret ;
escaped = sqlite3_mprintf ( " %q " , str ) ;
if ( ! escaped )
{
DPRINTF ( E_LOG , L_DB , " Out of memory for escaped string \n " ) ;
return NULL ;
}
ret = strdup ( escaped ) ;
sqlite3_free ( escaped ) ;
return ret ;
}
2010-01-30 11:01:27 -05:00
void
free_pi ( struct pairing_info * pi , int content_only )
{
if ( pi - > remote_id )
free ( pi - > remote_id ) ;
if ( pi - > name )
free ( pi - > name ) ;
if ( pi - > guid )
free ( pi - > guid ) ;
if ( ! content_only )
free ( pi ) ;
2014-04-18 07:08:31 -04:00
else
memset ( pi , 0 , sizeof ( struct pairing_info ) ) ;
2010-01-30 11:01:27 -05:00
}
2009-06-07 12:56:35 -04:00
void
free_mfi ( struct media_file_info * mfi , int content_only )
{
if ( mfi - > path )
free ( mfi - > path ) ;
if ( mfi - > fname )
free ( mfi - > fname ) ;
if ( mfi - > title )
free ( mfi - > title ) ;
if ( mfi - > artist )
free ( mfi - > artist ) ;
if ( mfi - > album )
free ( mfi - > album ) ;
if ( mfi - > genre )
free ( mfi - > genre ) ;
if ( mfi - > comment )
free ( mfi - > comment ) ;
if ( mfi - > type )
free ( mfi - > type ) ;
if ( mfi - > composer )
free ( mfi - > composer ) ;
if ( mfi - > orchestra )
free ( mfi - > orchestra ) ;
if ( mfi - > conductor )
free ( mfi - > conductor ) ;
if ( mfi - > grouping )
free ( mfi - > grouping ) ;
if ( mfi - > description )
free ( mfi - > description ) ;
if ( mfi - > codectype )
free ( mfi - > codectype ) ;
if ( mfi - > album_artist )
free ( mfi - > album_artist ) ;
2009-12-26 02:28:28 -05:00
if ( mfi - > tv_series_name )
free ( mfi - > tv_series_name ) ;
if ( mfi - > tv_episode_num_str )
free ( mfi - > tv_episode_num_str ) ;
if ( mfi - > tv_network_name )
free ( mfi - > tv_network_name ) ;
2010-09-21 07:16:38 -04:00
if ( mfi - > title_sort )
free ( mfi - > title_sort ) ;
if ( mfi - > artist_sort )
free ( mfi - > artist_sort ) ;
if ( mfi - > album_sort )
free ( mfi - > album_sort ) ;
if ( mfi - > composer_sort )
free ( mfi - > composer_sort ) ;
if ( mfi - > album_artist_sort )
free ( mfi - > album_artist_sort ) ;
2014-12-21 14:41:44 -05:00
if ( mfi - > virtual_path )
free ( mfi - > virtual_path ) ;
2009-06-07 12:56:35 -04:00
if ( ! content_only )
free ( mfi ) ;
2014-04-18 07:08:31 -04:00
else
memset ( mfi , 0 , sizeof ( struct media_file_info ) ) ;
2009-06-07 12:56:35 -04:00
}
2010-06-21 11:50:09 -04:00
void
unicode_fixup_mfi ( struct media_file_info * mfi )
{
char * ret ;
char * * field ;
int i ;
for ( i = 0 ; i < ( sizeof ( mfi_cols_map ) / sizeof ( mfi_cols_map [ 0 ] ) ) ; i + + )
{
if ( mfi_cols_map [ i ] . type ! = DB_TYPE_STRING )
continue ;
switch ( mfi_cols_map [ i ] . offset )
{
case mfi_offsetof ( path ) :
case mfi_offsetof ( fname ) :
case mfi_offsetof ( codectype ) :
continue ;
}
field = ( char * * ) ( ( char * ) mfi + mfi_cols_map [ i ] . offset ) ;
if ( ! * field )
continue ;
2015-06-02 17:10:04 -04:00
ret = unicode_fixup_string ( * field , " ascii " ) ;
2010-06-21 11:50:09 -04:00
if ( ret ! = * field )
{
free ( * field ) ;
* field = ret ;
}
}
}
2009-06-07 12:56:35 -04:00
void
free_pli ( struct playlist_info * pli , int content_only )
{
if ( pli - > title )
free ( pli - > title ) ;
if ( pli - > query )
free ( pli - > query ) ;
if ( pli - > path )
free ( pli - > path ) ;
2015-02-08 00:49:28 -05:00
if ( pli - > virtual_path )
free ( pli - > virtual_path ) ;
2009-06-07 12:56:35 -04:00
if ( ! content_only )
free ( pli ) ;
2014-04-18 07:08:31 -04:00
else
memset ( pli , 0 , sizeof ( struct playlist_info ) ) ;
2009-06-07 12:56:35 -04:00
}
2015-12-27 01:16:50 -05:00
void
free_di ( struct directory_info * di , int content_only )
{
if ( di - > virtual_path )
free ( di - > virtual_path ) ;
if ( ! content_only )
free ( di ) ;
else
memset ( di , 0 , sizeof ( struct directory_info ) ) ;
}
2010-04-26 12:24:09 -04:00
2010-04-26 12:24:09 -04:00
/* Unlock notification support */
static void
unlock_notify_cb ( void * * args , int nargs )
{
struct db_unlock * u ;
int i ;
for ( i = 0 ; i < nargs ; i + + )
{
u = ( struct db_unlock * ) args [ i ] ;
pthread_mutex_lock ( & u - > lck ) ;
u - > proceed = 1 ;
pthread_cond_signal ( & u - > cond ) ;
pthread_mutex_unlock ( & u - > lck ) ;
}
}
static int
db_wait_unlock ( void )
{
struct db_unlock u ;
int ret ;
u . proceed = 0 ;
pthread_mutex_init ( & u . lck , NULL ) ;
pthread_cond_init ( & u . cond , NULL ) ;
ret = sqlite3_unlock_notify ( hdl , unlock_notify_cb , & u ) ;
if ( ret = = SQLITE_OK )
{
pthread_mutex_lock ( & u . lck ) ;
if ( ! u . proceed )
2014-05-13 16:02:32 -04:00
{
DPRINTF ( E_INFO , L_DB , " Waiting for database unlock \n " ) ;
pthread_cond_wait ( & u . cond , & u . lck ) ;
}
2010-04-26 12:24:09 -04:00
pthread_mutex_unlock ( & u . lck ) ;
}
pthread_cond_destroy ( & u . cond ) ;
pthread_mutex_destroy ( & u . lck ) ;
return ret ;
}
static int
db_blocking_step ( sqlite3_stmt * stmt )
{
int ret ;
while ( ( ret = sqlite3_step ( stmt ) ) = = SQLITE_LOCKED )
{
ret = db_wait_unlock ( ) ;
if ( ret ! = SQLITE_OK )
{
DPRINTF ( E_LOG , L_DB , " Database deadlocked! \n " ) ;
break ;
}
sqlite3_reset ( stmt ) ;
}
return ret ;
}
static int
db_blocking_prepare_v2 ( const char * query , int len , sqlite3_stmt * * stmt , const char * * end )
{
int ret ;
while ( ( ret = sqlite3_prepare_v2 ( hdl , query , len , stmt , end ) ) = = SQLITE_LOCKED )
{
ret = db_wait_unlock ( ) ;
if ( ret ! = SQLITE_OK )
{
DPRINTF ( E_LOG , L_DB , " Database deadlocked! \n " ) ;
break ;
}
}
return ret ;
}
2010-04-26 12:24:09 -04:00
/* Modelled after sqlite3_exec() */
static int
db_exec ( const char * query , char * * errmsg )
{
sqlite3_stmt * stmt ;
2011-05-28 04:48:31 -04:00
int try ;
2010-04-26 12:24:09 -04:00
int ret ;
* errmsg = NULL ;
2011-05-28 04:48:31 -04:00
for ( try = 0 ; try < 5 ; try + + )
2010-04-26 12:24:09 -04:00
{
2011-05-28 04:48:31 -04:00
ret = db_blocking_prepare_v2 ( query , - 1 , & stmt , NULL ) ;
if ( ret ! = SQLITE_OK )
{
* errmsg = sqlite3_mprintf ( " prepare failed: %s " , sqlite3_errmsg ( hdl ) ) ;
return ret ;
}
while ( ( ret = db_blocking_step ( stmt ) ) = = SQLITE_ROW )
; /* EMPTY */
2010-04-26 12:24:09 -04:00
2011-05-28 04:48:31 -04:00
sqlite3_finalize ( stmt ) ;
if ( ret ! = SQLITE_SCHEMA )
break ;
}
2010-04-26 12:24:09 -04:00
if ( ret ! = SQLITE_DONE )
{
2011-05-28 04:46:41 -04:00
* errmsg = sqlite3_mprintf ( " step failed: %s " , sqlite3_errmsg ( hdl ) ) ;
2010-04-26 12:24:09 -04:00
return ret ;
}
return SQLITE_OK ;
}
2010-12-05 06:22:52 -05:00
/* Maintenance and DB hygiene */
static void
db_analyze ( void )
{
char * query = " ANALYZE; " ;
char * errmsg ;
int ret ;
DPRINTF ( E_DBG , L_DB , " Running query '%s' \n " , query ) ;
ret = db_exec ( query , & errmsg ) ;
if ( ret ! = SQLITE_OK )
{
DPRINTF ( E_LOG , L_DB , " ANALYZE failed: %s \n " , errmsg ) ;
sqlite3_free ( errmsg ) ;
}
}
2013-11-30 06:57:38 -05:00
/* Set names of default playlists according to config */
static void
db_set_cfg_names ( void )
{
2015-03-29 19:03:15 -04:00
# define Q_TMPL "UPDATE playlists SET title = '%q' WHERE type = %d AND special_id = %d;"
2013-12-08 17:03:03 -05:00
char * cfg_item [ 6 ] = { " name_library " , " name_music " , " name_movies " , " name_tvshows " , " name_podcasts " , " name_audiobooks " } ;
char special_id [ 6 ] = { 0 , 6 , 4 , 5 , 1 , 7 } ;
2013-11-30 06:57:38 -05:00
cfg_t * lib ;
char * query ;
char * title ;
char * errmsg ;
int ret ;
int i ;
lib = cfg_getsec ( cfg , " library " ) ;
for ( i = 0 ; i < ( sizeof ( cfg_item ) / sizeof ( cfg_item [ 0 ] ) ) ; i + + )
{
title = cfg_getstr ( lib , cfg_item [ i ] ) ;
if ( ! title )
{
DPRINTF ( E_LOG , L_DB , " Internal error, unknown config item '%s' \n " , cfg_item [ i ] ) ;
continue ;
}
2015-04-11 10:55:13 -04:00
query = sqlite3_mprintf ( Q_TMPL , title , PL_SPECIAL , special_id [ i ] ) ;
2013-11-30 06:57:38 -05:00
if ( ! query )
{
DPRINTF ( E_LOG , L_DB , " Out of memory for query string \n " ) ;
return ;
}
ret = db_exec ( query , & errmsg ) ;
if ( ret ! = SQLITE_OK )
{
DPRINTF ( E_LOG , L_DB , " Error setting playlist title, query %s, error: %s \n " , query , errmsg ) ;
sqlite3_free ( errmsg ) ;
}
else
DPRINTF ( E_DBG , L_DB , " Playlist title for config item '%s' set with query '%s' \n " , cfg_item [ i ] , query ) ;
sqlite3_free ( query ) ;
}
# undef Q_TMPL
}
2010-12-05 06:22:52 -05:00
void
db_hook_post_scan ( void )
{
DPRINTF ( E_DBG , L_DB , " Running post-scan DB maintenance tasks... \n " ) ;
db_analyze ( ) ;
DPRINTF ( E_DBG , L_DB , " Done with post-scan DB maintenance \n " ) ;
}
2009-06-07 14:49:13 -04:00
void
db_purge_cruft ( time_t ref )
{
char * errmsg ;
int i ;
int ret ;
2015-12-27 01:16:50 -05:00
char * queries [ 4 ] = { NULL , NULL , NULL , NULL } ;
char * queries_tmpl [ 4 ] =
2009-06-07 14:49:13 -04:00
{
2015-03-29 19:03:15 -04:00
" DELETE FROM playlistitems WHERE playlistid IN (SELECT id FROM playlists p WHERE p.type <> %d AND p.db_timestamp < % " PRIi64 " ); " ,
" DELETE FROM playlists WHERE type <> %d AND db_timestamp < % " PRIi64 " ; " ,
2015-12-27 01:16:50 -05:00
" DELETE FROM files WHERE -1 <> %d AND db_timestamp < % " PRIi64 " ; " ,
2016-01-24 12:45:28 -05:00
" DELETE FROM directories WHERE id > 4 AND -1 <> %d AND db_timestamp < % " PRIi64 " ; "
2009-06-07 14:49:13 -04:00
} ;
if ( sizeof ( queries ) ! = sizeof ( queries_tmpl ) )
{
DPRINTF ( E_LOG , L_DB , " db_purge_cruft(): queries out of sync with queries_tmpl \n " ) ;
return ;
}
for ( i = 0 ; i < ( sizeof ( queries_tmpl ) / sizeof ( queries_tmpl [ 0 ] ) ) ; i + + )
{
2015-04-11 10:55:13 -04:00
queries [ i ] = sqlite3_mprintf ( queries_tmpl [ i ] , PL_SPECIAL , ( int64_t ) ref ) ;
2009-06-07 14:49:13 -04:00
if ( ! queries [ i ] )
{
DPRINTF ( E_LOG , L_DB , " Out of memory for query string \n " ) ;
goto purge_fail ;
}
}
for ( i = 0 ; i < ( sizeof ( queries ) / sizeof ( queries [ 0 ] ) ) ; i + + )
{
DPRINTF ( E_DBG , L_DB , " Running purge query '%s' \n " , queries [ i ] ) ;
2010-04-26 12:24:09 -04:00
ret = db_exec ( queries [ i ] , & errmsg ) ;
2009-06-07 14:49:13 -04:00
if ( ret ! = SQLITE_OK )
{
DPRINTF ( E_LOG , L_DB , " Purge query %d error: %s \n " , i , errmsg ) ;
sqlite3_free ( errmsg ) ;
}
else
DPRINTF ( E_DBG , L_DB , " Purged %d rows \n " , sqlite3_changes ( hdl ) ) ;
}
purge_fail :
for ( i = 0 ; i < ( sizeof ( queries ) / sizeof ( queries [ 0 ] ) ) ; i + + )
{
sqlite3_free ( queries [ i ] ) ;
}
}
2013-11-29 16:48:53 -05:00
void
db_purge_all ( void )
{
2015-03-29 19:03:15 -04:00
# define Q_TMPL "DELETE FROM playlists WHERE type <> %d;"
2015-05-05 14:51:59 -04:00
char * queries [ 4 ] =
2013-11-29 16:48:53 -05:00
{
" DELETE FROM inotify; " ,
" DELETE FROM playlistitems; " ,
2013-12-16 16:21:04 -05:00
" DELETE FROM files; " ,
" DELETE FROM groups; " ,
2013-11-29 16:48:53 -05:00
} ;
char * errmsg ;
2015-03-29 19:03:15 -04:00
char * query ;
2013-11-29 16:48:53 -05:00
int i ;
int ret ;
for ( i = 0 ; i < ( sizeof ( queries ) / sizeof ( queries [ 0 ] ) ) ; i + + )
{
DPRINTF ( E_DBG , L_DB , " Running purge query '%s' \n " , queries [ i ] ) ;
ret = db_exec ( queries [ i ] , & errmsg ) ;
if ( ret ! = SQLITE_OK )
{
DPRINTF ( E_LOG , L_DB , " Purge query %d error: %s \n " , i , errmsg ) ;
sqlite3_free ( errmsg ) ;
}
else
DPRINTF ( E_DBG , L_DB , " Purged %d rows \n " , sqlite3_changes ( hdl ) ) ;
}
2015-03-29 19:03:15 -04:00
2015-04-11 10:55:13 -04:00
query = sqlite3_mprintf ( Q_TMPL , PL_SPECIAL ) ;
2015-03-29 19:03:15 -04:00
if ( ! query )
{
DPRINTF ( E_LOG , L_DB , " Out of memory for query string \n " ) ;
return ;
}
DPRINTF ( E_DBG , L_DB , " Running purge query '%s' \n " , query ) ;
ret = db_exec ( query , & errmsg ) ;
if ( ret ! = SQLITE_OK )
{
DPRINTF ( E_LOG , L_DB , " Purge query '%s' error: %s \n " , query , errmsg ) ;
sqlite3_free ( errmsg ) ;
}
else
DPRINTF ( E_DBG , L_DB , " Purged %d rows \n " , sqlite3_changes ( hdl ) ) ;
sqlite3_free ( query ) ;
# undef Q_TMPL
2013-11-29 16:48:53 -05:00
}
2009-06-07 12:56:35 -04:00
static int
2009-06-11 09:45:49 -04:00
db_get_count ( char * query )
2009-06-07 12:56:35 -04:00
{
sqlite3_stmt * stmt ;
int ret ;
DPRINTF ( E_DBG , L_DB , " Running query '%s' \n " , query ) ;
2010-04-26 12:24:09 -04:00
ret = db_blocking_prepare_v2 ( query , - 1 , & stmt , NULL ) ;
2009-06-07 12:56:35 -04:00
if ( ret ! = SQLITE_OK )
{
DPRINTF ( E_LOG , L_DB , " Could not prepare statement: %s \n " , sqlite3_errmsg ( hdl ) ) ;
return - 1 ;
}
2010-04-26 12:24:09 -04:00
ret = db_blocking_step ( stmt ) ;
2009-06-07 12:56:35 -04:00
if ( ret ! = SQLITE_ROW )
{
DPRINTF ( E_LOG , L_DB , " Could not step: %s \n " , sqlite3_errmsg ( hdl ) ) ;
sqlite3_finalize ( stmt ) ;
return - 1 ;
}
ret = sqlite3_column_int ( stmt , 0 ) ;
2011-06-11 11:24:59 -04:00
# ifdef DB_PROFILE
while ( db_blocking_step ( stmt ) = = SQLITE_ROW )
; /* EMPTY */
# endif
2009-06-07 12:56:35 -04:00
sqlite3_finalize ( stmt ) ;
return ret ;
}
2009-06-11 09:45:49 -04:00
2014-05-11 17:13:09 -04:00
/* Transactions */
void
db_transaction_begin ( void )
{
char * query = " BEGIN TRANSACTION; " ;
char * errmsg ;
int ret ;
DPRINTF ( E_DBG , L_DB , " Running query '%s' \n " , query ) ;
ret = db_exec ( query , & errmsg ) ;
if ( ret ! = SQLITE_OK )
{
DPRINTF ( E_LOG , L_DB , " SQL error running '%s': %s \n " , query , errmsg ) ;
sqlite3_free ( errmsg ) ;
}
}
void
db_transaction_end ( void )
{
char * query = " END TRANSACTION; " ;
char * errmsg ;
int ret ;
DPRINTF ( E_DBG , L_DB , " Running query '%s' \n " , query ) ;
ret = db_exec ( query , & errmsg ) ;
if ( ret ! = SQLITE_OK )
{
DPRINTF ( E_LOG , L_DB , " SQL error running '%s': %s \n " , query , errmsg ) ;
sqlite3_free ( errmsg ) ;
}
}
2009-06-11 09:45:49 -04:00
/* Queries */
2009-06-07 12:56:35 -04:00
static int
2015-09-29 16:51:23 -04:00
db_build_query_index_clause ( char * * i , struct query_params * qp )
2009-06-07 12:56:35 -04:00
{
char * idx ;
2015-09-29 16:51:23 -04:00
* i = NULL ;
2009-06-07 12:56:35 -04:00
switch ( qp - > idx_type )
{
case I_FIRST :
idx = sqlite3_mprintf ( " LIMIT %d " , qp - > limit ) ;
break ;
case I_LAST :
2011-06-05 05:04:57 -04:00
idx = sqlite3_mprintf ( " LIMIT -1 OFFSET %d " , qp - > results - qp - > limit ) ;
2009-06-07 12:56:35 -04:00
break ;
case I_SUB :
idx = sqlite3_mprintf ( " LIMIT %d OFFSET %d " , qp - > limit , qp - > offset ) ;
break ;
case I_NONE :
return 0 ;
default :
DPRINTF ( E_LOG , L_DB , " Unknown index type \n " ) ;
return - 1 ;
}
if ( ! idx )
{
DPRINTF ( E_LOG , L_DB , " Could not build index string; out of memory " ) ;
return - 1 ;
}
* i = idx ;
return 0 ;
}
static int
db_build_query_items ( struct query_params * qp , char * * q )
{
char * query ;
char * count ;
char * idx ;
2010-08-05 12:24:50 -04:00
const char * sort ;
2009-06-07 12:56:35 -04:00
int ret ;
if ( qp - > filter )
2011-03-28 13:06:48 -04:00
count = sqlite3_mprintf ( " SELECT COUNT(*) FROM files f WHERE f.disabled = 0 AND %s; " , qp - > filter ) ;
2009-06-07 12:56:35 -04:00
else
2011-03-28 13:06:48 -04:00
count = sqlite3_mprintf ( " SELECT COUNT(*) FROM files f WHERE f.disabled = 0; " ) ;
2009-06-07 12:56:35 -04:00
if ( ! count )
{
DPRINTF ( E_LOG , L_DB , " Out of memory for count query string \n " ) ;
return - 1 ;
}
2009-06-11 09:45:49 -04:00
qp - > results = db_get_count ( count ) ;
2009-06-07 12:56:35 -04:00
sqlite3_free ( count ) ;
if ( qp - > results < 0 )
return - 1 ;
/* Get index clause */
2015-09-29 16:51:23 -04:00
ret = db_build_query_index_clause ( & idx , qp ) ;
2009-06-07 12:56:35 -04:00
if ( ret < 0 )
return - 1 ;
2010-08-05 12:24:50 -04:00
sort = sort_clause [ qp - > sort ] ;
2010-04-24 04:20:26 -04:00
2009-06-07 12:56:35 -04:00
if ( idx & & qp - > filter )
2011-03-28 13:06:48 -04:00
query = sqlite3_mprintf ( " SELECT f.* FROM files f WHERE f.disabled = 0 AND %s %s %s; " , qp - > filter , sort , idx ) ;
2009-06-07 12:56:35 -04:00
else if ( idx )
2011-03-28 13:06:48 -04:00
query = sqlite3_mprintf ( " SELECT f.* FROM files f WHERE f.disabled = 0 %s %s; " , sort , idx ) ;
2009-06-07 12:56:35 -04:00
else if ( qp - > filter )
2011-03-28 13:06:48 -04:00
query = sqlite3_mprintf ( " SELECT f.* FROM files f WHERE f.disabled = 0 AND %s %s; " , qp - > filter , sort ) ;
2009-06-07 12:56:35 -04:00
else
2011-03-28 13:06:48 -04:00
query = sqlite3_mprintf ( " SELECT f.* FROM files f WHERE f.disabled = 0 %s; " , sort ) ;
2009-06-07 12:56:35 -04:00
2015-09-19 03:26:47 -04:00
if ( idx )
sqlite3_free ( idx ) ;
2009-06-07 12:56:35 -04:00
if ( ! query )
{
DPRINTF ( E_LOG , L_DB , " Out of memory for query string \n " ) ;
return - 1 ;
}
* q = query ;
return 0 ;
}
static int
db_build_query_pls ( struct query_params * qp , char * * q )
{
char * query ;
char * idx ;
2014-03-11 18:20:29 -04:00
const char * sort ;
2009-06-07 12:56:35 -04:00
int ret ;
2011-03-28 13:06:48 -04:00
qp - > results = db_get_count ( " SELECT COUNT(*) FROM playlists p WHERE p.disabled = 0; " ) ;
2009-06-07 12:56:35 -04:00
if ( qp - > results < 0 )
return - 1 ;
/* Get index clause */
2015-09-29 16:51:23 -04:00
ret = db_build_query_index_clause ( & idx , qp ) ;
2009-06-07 12:56:35 -04:00
if ( ret < 0 )
return - 1 ;
2014-03-11 18:20:29 -04:00
sort = sort_clause [ qp - > sort ] ;
2009-12-30 12:53:55 -05:00
if ( idx & & qp - > filter )
2014-03-11 18:20:29 -04:00
query = sqlite3_mprintf ( " SELECT f.* FROM playlists f WHERE f.disabled = 0 AND %s %s %s; " , qp - > filter , sort , idx ) ;
2009-12-30 12:53:55 -05:00
else if ( idx )
2014-03-11 18:20:29 -04:00
query = sqlite3_mprintf ( " SELECT f.* FROM playlists f WHERE f.disabled = 0 %s %s; " , sort , idx ) ;
2009-12-30 12:53:55 -05:00
else if ( qp - > filter )
2014-03-11 18:20:29 -04:00
query = sqlite3_mprintf ( " SELECT f.* FROM playlists f WHERE f.disabled = 0 AND %s %s; " , qp - > filter , sort ) ;
2009-06-07 12:56:35 -04:00
else
2014-03-11 18:20:29 -04:00
query = sqlite3_mprintf ( " SELECT f.* FROM playlists f WHERE f.disabled = 0 %s; " , sort ) ;
2009-06-07 12:56:35 -04:00
2015-09-26 03:28:20 -04:00
if ( idx )
sqlite3_free ( idx ) ;
2009-06-07 12:56:35 -04:00
if ( ! query )
{
DPRINTF ( E_LOG , L_DB , " Out of memory for query string \n " ) ;
return - 1 ;
}
* q = query ;
return 0 ;
}
static int
2010-01-21 11:52:51 -05:00
db_build_query_plitems_plain ( struct query_params * qp , char * * q )
2009-06-07 12:56:35 -04:00
{
char * query ;
char * count ;
char * idx ;
int ret ;
2010-01-21 11:52:51 -05:00
if ( qp - > filter )
2011-03-28 13:06:48 -04:00
count = sqlite3_mprintf ( " SELECT COUNT(*) FROM files f JOIN playlistitems pi ON f.path = pi.filepath "
" WHERE pi.playlistid = %d AND f.disabled = 0 AND %s; " , qp - > id , qp - > filter ) ;
2009-06-07 12:56:35 -04:00
else
2011-03-28 13:06:48 -04:00
count = sqlite3_mprintf ( " SELECT COUNT(*) FROM files f JOIN playlistitems pi ON f.path = pi.filepath "
" WHERE pi.playlistid = %d AND f.disabled = 0; " , qp - > id ) ;
2009-06-07 12:56:35 -04:00
if ( ! count )
{
DPRINTF ( E_LOG , L_DB , " Out of memory for count query string \n " ) ;
return - 1 ;
}
2009-06-11 09:45:49 -04:00
qp - > results = db_get_count ( count ) ;
2009-06-07 12:56:35 -04:00
sqlite3_free ( count ) ;
if ( qp - > results < 0 )
return - 1 ;
/* Get index clause */
2015-09-29 16:51:23 -04:00
ret = db_build_query_index_clause ( & idx , qp ) ;
2009-06-07 12:56:35 -04:00
if ( ret < 0 )
return - 1 ;
if ( idx & & qp - > filter )
2011-03-28 13:06:48 -04:00
query = sqlite3_mprintf ( " SELECT f.* FROM files f JOIN playlistitems pi ON f.path = pi.filepath "
" WHERE pi.playlistid = %d AND f.disabled = 0 AND %s ORDER BY pi.id ASC %s; " ,
2010-03-07 05:53:16 -05:00
qp - > id , qp - > filter , idx ) ;
2009-06-07 12:56:35 -04:00
else if ( idx )
2011-03-28 13:06:48 -04:00
query = sqlite3_mprintf ( " SELECT f.* FROM files f JOIN playlistitems pi ON f.path = pi.filepath "
" WHERE pi.playlistid = %d AND f.disabled = 0 ORDER BY pi.id ASC %s; " ,
2010-03-07 05:53:16 -05:00
qp - > id , idx ) ;
2009-06-07 12:56:35 -04:00
else if ( qp - > filter )
2011-03-28 13:06:48 -04:00
query = sqlite3_mprintf ( " SELECT f.* FROM files f JOIN playlistitems pi ON f.path = pi.filepath "
" WHERE pi.playlistid = %d AND f.disabled = 0 AND %s ORDER BY pi.id ASC; " ,
2010-03-07 05:53:16 -05:00
qp - > id , qp - > filter ) ;
2009-06-07 12:56:35 -04:00
else
2011-03-28 13:06:48 -04:00
query = sqlite3_mprintf ( " SELECT f.* FROM files f JOIN playlistitems pi ON f.path = pi.filepath "
" WHERE pi.playlistid = %d AND f.disabled = 0 ORDER BY pi.id ASC; " ,
2010-03-07 05:53:16 -05:00
qp - > id ) ;
2009-06-07 12:56:35 -04:00
2015-09-26 03:28:20 -04:00
if ( idx )
sqlite3_free ( idx ) ;
2009-06-07 12:56:35 -04:00
if ( ! query )
{
DPRINTF ( E_LOG , L_DB , " Out of memory for query string \n " ) ;
return - 1 ;
}
* q = query ;
return 0 ;
}
2010-01-21 11:52:51 -05:00
static int
db_build_query_plitems_smart ( struct query_params * qp , char * smartpl_query , char * * q )
{
char * query ;
char * count ;
char * filter ;
char * idx ;
2010-08-05 12:24:50 -04:00
const char * sort ;
2010-01-21 11:52:51 -05:00
int ret ;
if ( qp - > filter )
filter = qp - > filter ;
else
filter = " 1 = 1 " ;
2011-03-28 13:06:48 -04:00
count = sqlite3_mprintf ( " SELECT COUNT(*) FROM files f WHERE f.disabled = 0 AND %s AND %s; " , filter , smartpl_query ) ;
2010-01-21 11:52:51 -05:00
if ( ! count )
{
DPRINTF ( E_LOG , L_DB , " Out of memory for count query string \n " ) ;
return - 1 ;
}
qp - > results = db_get_count ( count ) ;
sqlite3_free ( count ) ;
if ( qp - > results < 0 )
return - 1 ;
/* Get index clause */
2015-09-29 16:51:23 -04:00
ret = db_build_query_index_clause ( & idx , qp ) ;
2010-01-21 11:52:51 -05:00
if ( ret < 0 )
return - 1 ;
2010-08-05 12:24:50 -04:00
sort = sort_clause [ qp - > sort ] ;
2010-08-03 17:29:16 -04:00
2015-09-26 03:28:20 -04:00
if ( idx )
query = sqlite3_mprintf ( " SELECT f.* FROM files f WHERE f.disabled = 0 AND %s AND %s %s %s; " , smartpl_query , filter , sort , idx ) ;
else
query = sqlite3_mprintf ( " SELECT f.* FROM files f WHERE f.disabled = 0 AND %s AND %s %s; " , smartpl_query , filter , sort ) ;
if ( idx )
sqlite3_free ( idx ) ;
2010-01-21 11:52:51 -05:00
if ( ! query )
{
DPRINTF ( E_LOG , L_DB , " Out of memory for query string \n " ) ;
return - 1 ;
}
* q = query ;
return 0 ;
}
static int
db_build_query_plitems ( struct query_params * qp , char * * q )
{
struct playlist_info * pli ;
int ret ;
2010-03-07 05:53:16 -05:00
if ( qp - > id < = 0 )
2010-01-21 11:52:51 -05:00
{
DPRINTF ( E_LOG , L_DB , " No playlist id specified in playlist items query \n " ) ;
return - 1 ;
}
2010-03-07 05:53:16 -05:00
pli = db_pl_fetch_byid ( qp - > id ) ;
2010-01-21 11:52:51 -05:00
if ( ! pli )
return - 1 ;
switch ( pli - > type )
{
2015-04-11 10:55:13 -04:00
case PL_SPECIAL :
2010-01-21 11:52:51 -05:00
case PL_SMART :
ret = db_build_query_plitems_smart ( qp , pli - > query , q ) ;
break ;
case PL_PLAIN :
2015-03-29 19:03:15 -04:00
case PL_FOLDER :
2010-01-21 11:52:51 -05:00
ret = db_build_query_plitems_plain ( qp , q ) ;
break ;
default :
DPRINTF ( E_LOG , L_DB , " Unknown playlist type %d in playlist items query \n " , pli - > type ) ;
ret = - 1 ;
break ;
}
free_pli ( pli , 0 ) ;
return ret ;
}
2010-01-10 06:26:48 -05:00
static int
2013-08-29 16:00:37 -04:00
db_build_query_group_albums ( struct query_params * qp , char * * q )
2010-01-10 06:26:48 -05:00
{
char * query ;
char * idx ;
2013-12-03 17:16:07 -05:00
const char * sort ;
2010-01-10 06:26:48 -05:00
int ret ;
2011-03-28 13:06:48 -04:00
qp - > results = db_get_count ( " SELECT COUNT(DISTINCT f.songalbumid) FROM files f WHERE f.disabled = 0; " ) ;
2010-01-10 06:26:48 -05:00
if ( qp - > results < 0 )
return - 1 ;
/* Get index clause */
2015-09-29 16:51:23 -04:00
ret = db_build_query_index_clause ( & idx , qp ) ;
2010-01-10 06:26:48 -05:00
if ( ret < 0 )
return - 1 ;
2013-12-03 17:16:07 -05:00
sort = sort_clause [ qp - > sort ] ;
2010-01-10 06:26:48 -05:00
if ( idx & & qp - > filter )
2015-01-09 17:04:50 -05:00
query = sqlite3_mprintf ( " SELECT g.id, g.persistentid, f.album, f.album_sort, COUNT(f.id), 1, f.album_artist, f.songartistid FROM files f JOIN groups g ON f.songalbumid = g.persistentid WHERE f.disabled = 0 AND %s GROUP BY f.songalbumid %s %s; " , qp - > filter , sort , idx ) ;
2010-01-10 06:26:48 -05:00
else if ( idx )
2015-01-09 17:04:50 -05:00
query = sqlite3_mprintf ( " SELECT g.id, g.persistentid, f.album, f.album_sort, COUNT(f.id), 1, f.album_artist, f.songartistid FROM files f JOIN groups g ON f.songalbumid = g.persistentid WHERE f.disabled = 0 GROUP BY f.songalbumid %s %s; " , sort , idx ) ;
2010-01-10 06:26:48 -05:00
else if ( qp - > filter )
2015-01-09 17:04:50 -05:00
query = sqlite3_mprintf ( " SELECT g.id, g.persistentid, f.album, f.album_sort, COUNT(f.id), 1, f.album_artist, f.songartistid FROM files f JOIN groups g ON f.songalbumid = g.persistentid WHERE f.disabled = 0 AND %s GROUP BY f.songalbumid %s; " , qp - > filter , sort ) ;
2010-01-10 06:26:48 -05:00
else
2015-01-09 17:04:50 -05:00
query = sqlite3_mprintf ( " SELECT g.id, g.persistentid, f.album, f.album_sort, COUNT(f.id), 1, f.album_artist, f.songartistid FROM files f JOIN groups g ON f.songalbumid = g.persistentid WHERE f.disabled = 0 GROUP BY f.songalbumid %s; " , sort ) ;
2010-01-10 06:26:48 -05:00
2015-09-26 03:28:20 -04:00
if ( idx )
sqlite3_free ( idx ) ;
2010-01-10 06:26:48 -05:00
if ( ! query )
{
DPRINTF ( E_LOG , L_DB , " Out of memory for query string \n " ) ;
return - 1 ;
}
* q = query ;
return 0 ;
}
2010-03-07 06:53:23 -05:00
static int
2013-08-29 16:00:37 -04:00
db_build_query_group_artists ( struct query_params * qp , char * * q )
{
char * query ;
char * idx ;
2013-12-03 17:16:07 -05:00
const char * sort ;
2013-08-29 16:00:37 -04:00
int ret ;
2013-12-17 14:58:55 -05:00
qp - > results = db_get_count ( " SELECT COUNT(DISTINCT f.songartistid) FROM files f WHERE f.disabled = 0; " ) ;
2013-08-29 16:00:37 -04:00
if ( qp - > results < 0 )
return - 1 ;
/* Get index clause */
2015-09-29 16:51:23 -04:00
ret = db_build_query_index_clause ( & idx , qp ) ;
2013-08-29 16:00:37 -04:00
if ( ret < 0 )
return - 1 ;
2013-12-03 17:16:07 -05:00
sort = sort_clause [ qp - > sort ] ;
2013-08-29 16:00:37 -04:00
if ( idx & & qp - > filter )
2015-01-09 17:04:50 -05:00
query = sqlite3_mprintf ( " SELECT g.id, g.persistentid, f.album_artist, f.album_artist_sort, COUNT(f.id), COUNT(DISTINCT f.songalbumid), f.album_artist, f.songartistid FROM files f JOIN groups g ON f.songartistid = g.persistentid WHERE f.disabled = 0 AND %s GROUP BY f.songartistid %s %s; " , qp - > filter , sort , idx ) ;
2013-08-29 16:00:37 -04:00
else if ( idx )
2015-01-09 17:04:50 -05:00
query = sqlite3_mprintf ( " SELECT g.id, g.persistentid, f.album_artist, f.album_artist_sort, COUNT(f.id), COUNT(DISTINCT f.songalbumid), f.album_artist, f.songartistid FROM files f JOIN groups g ON f.songartistid = g.persistentid WHERE f.disabled = 0 GROUP BY f.songartistid %s %s; " , sort , idx ) ;
2013-08-29 16:00:37 -04:00
else if ( qp - > filter )
2015-01-09 17:04:50 -05:00
query = sqlite3_mprintf ( " SELECT g.id, g.persistentid, f.album_artist, f.album_artist_sort, COUNT(f.id), COUNT(DISTINCT f.songalbumid), f.album_artist, f.songartistid FROM files f JOIN groups g ON f.songartistid = g.persistentid WHERE f.disabled = 0 AND %s GROUP BY f.songartistid %s; " , qp - > filter , sort ) ;
2013-08-29 16:00:37 -04:00
else
2015-01-09 17:04:50 -05:00
query = sqlite3_mprintf ( " SELECT g.id, g.persistentid, f.album_artist, f.album_artist_sort, COUNT(f.id), COUNT(DISTINCT f.songalbumid), f.album_artist, f.songartistid FROM files f JOIN groups g ON f.songartistid = g.persistentid WHERE f.disabled = 0 GROUP BY f.songartistid %s; " , sort ) ;
2013-08-29 16:00:37 -04:00
2015-09-26 03:28:20 -04:00
if ( idx )
sqlite3_free ( idx ) ;
2013-08-29 16:00:37 -04:00
if ( ! query )
{
DPRINTF ( E_LOG , L_DB , " Out of memory for query string \n " ) ;
return - 1 ;
}
* q = query ;
return 0 ;
}
static int
db_build_query_group_items ( struct query_params * qp , char * * q )
2010-03-07 06:53:23 -05:00
{
char * query ;
char * count ;
enum group_type gt ;
2014-11-10 16:53:08 -05:00
gt = db_group_type_bypersistentid ( qp - > persistentid ) ;
2010-03-07 06:53:23 -05:00
switch ( gt )
{
case G_ALBUMS :
2014-11-10 16:53:08 -05:00
count = sqlite3_mprintf ( " SELECT COUNT(*) FROM files f "
" WHERE f.songalbumid = % " PRIi64 " AND f.disabled = 0; " , qp - > persistentid ) ;
2010-03-07 06:53:23 -05:00
break ;
2013-12-17 14:58:55 -05:00
case G_ARTISTS :
2014-11-10 16:53:08 -05:00
count = sqlite3_mprintf ( " SELECT COUNT(*) FROM files f "
" WHERE f.songartistid = % " PRIi64 " AND f.disabled = 0; " , qp - > persistentid ) ;
2013-12-17 14:58:55 -05:00
break ;
2010-03-07 06:53:23 -05:00
default :
2014-11-10 16:53:08 -05:00
DPRINTF ( E_LOG , L_DB , " Unsupported group type %d for group id % " PRIi64 " \n " , gt , qp - > persistentid ) ;
2010-03-07 06:53:23 -05:00
return - 1 ;
}
if ( ! count )
{
DPRINTF ( E_LOG , L_DB , " Out of memory for count query string \n " ) ;
return - 1 ;
}
qp - > results = db_get_count ( count ) ;
sqlite3_free ( count ) ;
if ( qp - > results < 0 )
return - 1 ;
switch ( gt )
{
case G_ALBUMS :
2014-11-10 16:53:08 -05:00
query = sqlite3_mprintf ( " SELECT f.* FROM files f "
" WHERE f.songalbumid = % " PRIi64 " AND f.disabled = 0; " , qp - > persistentid ) ;
2010-03-07 06:53:23 -05:00
break ;
2013-12-17 14:58:55 -05:00
case G_ARTISTS :
2014-11-10 16:53:08 -05:00
query = sqlite3_mprintf ( " SELECT f.* FROM files f "
" WHERE f.songartistid = % " PRIi64 " AND f.disabled = 0; " , qp - > persistentid ) ;
2013-12-17 14:58:55 -05:00
break ;
default :
return - 1 ;
2010-03-07 06:53:23 -05:00
}
if ( ! query )
{
DPRINTF ( E_LOG , L_DB , " Out of memory for query string \n " ) ;
return - 1 ;
}
* q = query ;
return 0 ;
}
static int
db_build_query_group_dirs ( struct query_params * qp , char * * q )
{
char * query ;
char * count ;
enum group_type gt ;
2014-11-10 16:53:08 -05:00
gt = db_group_type_bypersistentid ( qp - > persistentid ) ;
2010-03-07 06:53:23 -05:00
switch ( gt )
{
case G_ALBUMS :
2011-03-28 13:06:48 -04:00
count = sqlite3_mprintf ( " SELECT COUNT(DISTINCT(SUBSTR(f.path, 1, LENGTH(f.path) - LENGTH(f.fname) - 1))) "
2014-11-10 16:53:08 -05:00
" FROM files f "
" WHERE f.songalbumid = % " PRIi64 " AND f.disabled = 0; " , qp - > persistentid ) ;
2010-03-07 06:53:23 -05:00
break ;
2013-12-17 14:58:55 -05:00
case G_ARTISTS :
count = sqlite3_mprintf ( " SELECT COUNT(DISTINCT(SUBSTR(f.path, 1, LENGTH(f.path) - LENGTH(f.fname) - 1))) "
2014-11-10 16:53:08 -05:00
" FROM files f "
" WHERE f.songartistid = % " PRIi64 " AND f.disabled = 0; " , qp - > persistentid ) ;
2013-12-17 14:58:55 -05:00
break ;
2010-03-07 06:53:23 -05:00
default :
2014-11-10 16:53:08 -05:00
DPRINTF ( E_LOG , L_DB , " Unsupported group type %d for group id % " PRIi64 " \n " , gt , qp - > persistentid ) ;
2010-03-07 06:53:23 -05:00
return - 1 ;
}
if ( ! count )
{
DPRINTF ( E_LOG , L_DB , " Out of memory for count query string \n " ) ;
return - 1 ;
}
qp - > results = db_get_count ( count ) ;
sqlite3_free ( count ) ;
if ( qp - > results < 0 )
return - 1 ;
switch ( gt )
{
case G_ALBUMS :
2011-03-28 13:06:48 -04:00
query = sqlite3_mprintf ( " SELECT DISTINCT(SUBSTR(f.path, 1, LENGTH(f.path) - LENGTH(f.fname) - 1)) "
2014-11-10 16:53:08 -05:00
" FROM files f "
" WHERE f.songalbumid = % " PRIi64 " AND f.disabled = 0; " , qp - > persistentid ) ;
2010-03-07 06:53:23 -05:00
break ;
2013-12-17 14:58:55 -05:00
case G_ARTISTS :
query = sqlite3_mprintf ( " SELECT DISTINCT(SUBSTR(f.path, 1, LENGTH(f.path) - LENGTH(f.fname) - 1)) "
2014-11-10 16:53:08 -05:00
" FROM files f "
" WHERE f.songartistid = % " PRIi64 " AND f.disabled = 0; " , qp - > persistentid ) ;
2013-12-17 14:58:55 -05:00
break ;
default :
return - 1 ;
2010-03-07 06:53:23 -05:00
}
if ( ! query )
{
DPRINTF ( E_LOG , L_DB , " Out of memory for query string \n " ) ;
return - 1 ;
}
* q = query ;
return 0 ;
}
2009-06-07 12:56:35 -04:00
static int
2015-05-26 15:10:28 -04:00
db_build_query_browse ( struct query_params * qp , const char * field , const char * group_field , char * * q )
2009-06-07 12:56:35 -04:00
{
char * query ;
char * count ;
char * idx ;
2015-05-26 15:10:28 -04:00
const char * sort ;
2009-06-07 12:56:35 -04:00
int ret ;
if ( qp - > filter )
2014-03-11 18:20:29 -04:00
count = sqlite3_mprintf ( " SELECT COUNT(DISTINCT f.%s) FROM files f WHERE f.disabled = 0 AND f.%s != '' AND %s; " ,
2009-06-10 09:23:02 -04:00
field , field , qp - > filter ) ;
2009-06-07 12:56:35 -04:00
else
2014-03-11 18:20:29 -04:00
count = sqlite3_mprintf ( " SELECT COUNT(DISTINCT f.%s) FROM files f WHERE f.disabled = 0 AND f.%s != ''; " ,
2009-06-10 09:23:02 -04:00
field , field ) ;
2009-06-07 12:56:35 -04:00
if ( ! count )
{
DPRINTF ( E_LOG , L_DB , " Out of memory for count query string \n " ) ;
return - 1 ;
}
2009-06-11 09:45:49 -04:00
qp - > results = db_get_count ( count ) ;
2009-06-07 12:56:35 -04:00
sqlite3_free ( count ) ;
if ( qp - > results < 0 )
return - 1 ;
/* Get index clause */
2015-09-29 16:51:23 -04:00
ret = db_build_query_index_clause ( & idx , qp ) ;
2009-06-07 12:56:35 -04:00
if ( ret < 0 )
return - 1 ;
2015-05-26 15:10:28 -04:00
sort = sort_clause [ qp - > sort ] ;
2013-12-03 17:16:07 -05:00
2009-06-07 12:56:35 -04:00
if ( idx & & qp - > filter )
2015-01-09 17:58:27 -05:00
query = sqlite3_mprintf ( " SELECT f.%s, f.%s FROM files f WHERE f.disabled = 0 AND f.%s != '' "
2015-05-26 15:10:28 -04:00
" AND %s GROUP BY f.%s %s %s; " , field , group_field , field , qp - > filter , group_field , sort , idx ) ;
2009-06-07 12:56:35 -04:00
else if ( idx )
2015-01-09 17:58:27 -05:00
query = sqlite3_mprintf ( " SELECT f.%s, f.%s FROM files f WHERE f.disabled = 0 AND f.%s != '' "
2015-05-26 15:10:28 -04:00
" GROUP BY f.%s %s %s; " , field , group_field , field , group_field , sort , idx ) ;
2009-06-07 12:56:35 -04:00
else if ( qp - > filter )
2015-01-09 17:58:27 -05:00
query = sqlite3_mprintf ( " SELECT f.%s, f.%s FROM files f WHERE f.disabled = 0 AND f.%s != '' "
2015-05-26 15:10:28 -04:00
" AND %s GROUP BY f.%s %s; " , field , group_field , field , qp - > filter , group_field , sort ) ;
2009-06-07 12:56:35 -04:00
else
2015-01-09 17:58:27 -05:00
query = sqlite3_mprintf ( " SELECT f.%s, f.%s FROM files f WHERE f.disabled = 0 AND f.%s != '' "
2015-05-26 15:10:28 -04:00
" GROUP BY f.%s %s " , field , group_field , field , group_field , sort ) ;
2009-06-07 12:56:35 -04:00
2015-09-26 03:28:20 -04:00
if ( idx )
sqlite3_free ( idx ) ;
2009-06-07 12:56:35 -04:00
if ( ! query )
{
DPRINTF ( E_LOG , L_DB , " Out of memory for query string \n " ) ;
return - 1 ;
}
* q = query ;
return 0 ;
}
2015-04-06 03:19:48 -04:00
static int
db_build_query_count_items ( struct query_params * qp , char * * q )
{
char * query ;
qp - > results = 1 ;
if ( qp - > filter )
query = sqlite3_mprintf ( " SELECT COUNT(*), SUM(song_length) FROM files f WHERE f.disabled = 0 AND %s; " , qp - > filter ) ;
else
2015-11-01 03:15:24 -05:00
query = sqlite3_mprintf ( " SELECT COUNT(*), SUM(song_length) FROM files f WHERE f.disabled = 0; " ) ;
2015-04-06 03:19:48 -04:00
if ( ! query )
{
DPRINTF ( E_LOG , L_DB , " Out of memory for query string \n " ) ;
return - 1 ;
}
* q = query ;
return 0 ;
}
2009-06-07 12:56:35 -04:00
int
db_query_start ( struct query_params * qp )
{
char * query ;
int ret ;
qp - > stmt = NULL ;
switch ( qp - > type )
{
case Q_ITEMS :
ret = db_build_query_items ( qp , & query ) ;
break ;
case Q_PL :
ret = db_build_query_pls ( qp , & query ) ;
break ;
case Q_PLITEMS :
ret = db_build_query_plitems ( qp , & query ) ;
break ;
2013-08-29 16:00:37 -04:00
case Q_GROUP_ALBUMS :
ret = db_build_query_group_albums ( qp , & query ) ;
break ;
case Q_GROUP_ARTISTS :
ret = db_build_query_group_artists ( qp , & query ) ;
2010-01-10 06:26:48 -05:00
break ;
2013-08-29 16:00:37 -04:00
case Q_GROUP_ITEMS :
ret = db_build_query_group_items ( qp , & query ) ;
2010-03-07 06:53:23 -05:00
break ;
case Q_GROUP_DIRS :
ret = db_build_query_group_dirs ( qp , & query ) ;
break ;
2009-06-07 12:56:35 -04:00
case Q_BROWSE_ALBUMS :
2013-12-05 15:56:02 -05:00
ret = db_build_query_browse ( qp , " album " , " album_sort " , & query ) ;
2009-06-07 12:56:35 -04:00
break ;
case Q_BROWSE_ARTISTS :
2013-12-05 15:56:02 -05:00
ret = db_build_query_browse ( qp , " album_artist " , " album_artist_sort " , & query ) ;
2009-06-07 12:56:35 -04:00
break ;
case Q_BROWSE_GENRES :
2013-12-05 15:56:02 -05:00
ret = db_build_query_browse ( qp , " genre " , " genre " , & query ) ;
2009-06-07 12:56:35 -04:00
break ;
case Q_BROWSE_COMPOSERS :
2013-12-05 16:46:12 -05:00
ret = db_build_query_browse ( qp , " composer " , " composer_sort " , & query ) ;
2009-06-07 12:56:35 -04:00
break ;
2015-02-23 12:43:38 -05:00
case Q_BROWSE_YEARS :
ret = db_build_query_browse ( qp , " year " , " year " , & query ) ;
break ;
2015-05-02 01:26:13 -04:00
case Q_BROWSE_DISCS :
ret = db_build_query_browse ( qp , " disc " , " disc " , & query ) ;
break ;
2015-05-02 03:18:18 -04:00
case Q_BROWSE_TRACKS :
ret = db_build_query_browse ( qp , " track " , " track " , & query ) ;
break ;
2015-05-29 23:31:54 -04:00
case Q_BROWSE_VPATH :
ret = db_build_query_browse ( qp , " virtual_path " , " virtual_path " , & query ) ;
break ;
2016-01-16 11:02:03 -05:00
case Q_BROWSE_PATH :
ret = db_build_query_browse ( qp , " path " , " path " , & query ) ;
break ;
2015-04-06 03:19:48 -04:00
case Q_COUNT_ITEMS :
ret = db_build_query_count_items ( qp , & query ) ;
break ;
2009-06-07 12:56:35 -04:00
default :
DPRINTF ( E_LOG , L_DB , " Unknown query type \n " ) ;
return - 1 ;
}
if ( ret < 0 )
return - 1 ;
DPRINTF ( E_DBG , L_DB , " Starting query '%s' \n " , query ) ;
2010-04-26 12:24:09 -04:00
ret = db_blocking_prepare_v2 ( query , - 1 , & qp - > stmt , NULL ) ;
2009-06-07 12:56:35 -04:00
if ( ret ! = SQLITE_OK )
{
DPRINTF ( E_LOG , L_DB , " Could not prepare statement: %s \n " , sqlite3_errmsg ( hdl ) ) ;
sqlite3_free ( query ) ;
return - 1 ;
}
sqlite3_free ( query ) ;
return 0 ;
}
void
db_query_end ( struct query_params * qp )
{
if ( ! qp - > stmt )
return ;
qp - > results = - 1 ;
sqlite3_finalize ( qp - > stmt ) ;
qp - > stmt = NULL ;
}
2014-08-17 18:20:23 -04:00
static int
2014-08-22 16:51:13 -04:00
db_query_run ( char * query , int free , int cache_update )
2014-08-17 18:20:23 -04:00
{
char * errmsg ;
int ret ;
if ( ! query )
{
DPRINTF ( E_LOG , L_DB , " Out of memory for query string \n " ) ;
return - 1 ;
}
DPRINTF ( E_DBG , L_DB , " Running query '%s' \n " , query ) ;
2015-06-08 17:07:56 -04:00
/* If the query will be long running we don't want the cache to start regenerating */
cache_daap_suspend ( ) ;
2014-08-17 18:20:23 -04:00
ret = db_exec ( query , & errmsg ) ;
if ( ret ! = SQLITE_OK )
DPRINTF ( E_LOG , L_DB , " Error '%s' while runnning '%s' \n " , errmsg , query ) ;
sqlite3_free ( errmsg ) ;
if ( free )
sqlite3_free ( query ) ;
2014-08-22 16:51:13 -04:00
if ( cache_update )
2014-11-10 16:53:08 -05:00
cache_daap_trigger ( ) ;
2015-06-08 17:07:56 -04:00
else
cache_daap_resume ( ) ;
2014-08-22 16:51:13 -04:00
2014-08-17 18:20:23 -04:00
return ( ( ret ! = SQLITE_OK ) ? - 1 : 0 ) ;
}
2009-06-07 12:56:35 -04:00
int
db_query_fetch_file ( struct query_params * qp , struct db_media_file_info * dbmfi )
{
int ncols ;
char * * strcol ;
int i ;
int ret ;
memset ( dbmfi , 0 , sizeof ( struct db_media_file_info ) ) ;
if ( ! qp - > stmt )
{
DPRINTF ( E_LOG , L_DB , " Query not started! \n " ) ;
return - 1 ;
}
2013-08-29 16:00:37 -04:00
if ( ( qp - > type ! = Q_ITEMS ) & & ( qp - > type ! = Q_PLITEMS ) & & ( qp - > type ! = Q_GROUP_ITEMS ) )
2009-06-07 12:56:35 -04:00
{
2010-03-07 06:53:23 -05:00
DPRINTF ( E_LOG , L_DB , " Not an items, playlist or group items query! \n " ) ;
2009-06-07 12:56:35 -04:00
return - 1 ;
}
2010-04-26 12:24:09 -04:00
ret = db_blocking_step ( qp - > stmt ) ;
2009-06-07 12:56:35 -04:00
if ( ret = = SQLITE_DONE )
{
2014-06-01 17:58:44 -04:00
DPRINTF ( E_DBG , L_DB , " End of query results \n " ) ;
2009-06-07 12:56:35 -04:00
dbmfi - > id = NULL ;
return 0 ;
}
else if ( ret ! = SQLITE_ROW )
{
DPRINTF ( E_LOG , L_DB , " Could not step: %s \n " , sqlite3_errmsg ( hdl ) ) ;
return - 1 ;
}
ncols = sqlite3_column_count ( qp - > stmt ) ;
if ( sizeof ( dbmfi_cols_map ) / sizeof ( dbmfi_cols_map [ 0 ] ) ! = ncols )
{
DPRINTF ( E_LOG , L_DB , " BUG: dbmfi column map out of sync with schema \n " ) ;
return - 1 ;
}
for ( i = 0 ; i < ncols ; i + + )
{
strcol = ( char * * ) ( ( char * ) dbmfi + dbmfi_cols_map [ i ] ) ;
* strcol = ( char * ) sqlite3_column_text ( qp - > stmt , i ) ;
}
return 0 ;
}
int
db_query_fetch_pl ( struct query_params * qp , struct db_playlist_info * dbpli )
{
int ncols ;
char * * strcol ;
2009-06-11 12:28:01 -04:00
int id ;
2010-01-21 11:52:51 -05:00
int type ;
int nitems ;
2015-03-16 18:33:42 -04:00
int nstreams ;
2009-06-07 12:56:35 -04:00
int i ;
int ret ;
memset ( dbpli , 0 , sizeof ( struct db_playlist_info ) ) ;
if ( ! qp - > stmt )
{
DPRINTF ( E_LOG , L_DB , " Query not started! \n " ) ;
return - 1 ;
}
if ( qp - > type ! = Q_PL )
{
DPRINTF ( E_LOG , L_DB , " Not a playlist query! \n " ) ;
return - 1 ;
}
2010-04-26 12:24:09 -04:00
ret = db_blocking_step ( qp - > stmt ) ;
2009-06-07 12:56:35 -04:00
if ( ret = = SQLITE_DONE )
{
2014-06-01 17:58:44 -04:00
DPRINTF ( E_DBG , L_DB , " End of query results \n " ) ;
2009-06-07 12:56:35 -04:00
dbpli - > id = NULL ;
return 0 ;
}
else if ( ret ! = SQLITE_ROW )
{
DPRINTF ( E_LOG , L_DB , " Could not step: %s \n " , sqlite3_errmsg ( hdl ) ) ;
return - 1 ;
}
ncols = sqlite3_column_count ( qp - > stmt ) ;
if ( sizeof ( dbpli_cols_map ) / sizeof ( dbpli_cols_map [ 0 ] ) ! = ncols )
{
DPRINTF ( E_LOG , L_DB , " BUG: dbpli column map out of sync with schema \n " ) ;
return - 1 ;
}
for ( i = 0 ; i < ncols ; i + + )
{
strcol = ( char * * ) ( ( char * ) dbpli + dbpli_cols_map [ i ] ) ;
* strcol = ( char * ) sqlite3_column_text ( qp - > stmt , i ) ;
}
2010-01-21 11:52:51 -05:00
type = sqlite3_column_int ( qp - > stmt , 2 ) ;
switch ( type )
{
case PL_PLAIN :
2015-03-29 19:03:15 -04:00
case PL_FOLDER :
2010-01-21 11:52:51 -05:00
id = sqlite3_column_int ( qp - > stmt , 0 ) ;
2015-03-16 18:33:42 -04:00
nitems = db_pl_count_items ( id , 0 ) ;
nstreams = db_pl_count_items ( id , 1 ) ;
2010-01-21 11:52:51 -05:00
break ;
2009-06-11 12:28:01 -04:00
2015-04-11 10:55:13 -04:00
case PL_SPECIAL :
2010-01-21 11:52:51 -05:00
case PL_SMART :
nitems = db_smartpl_count_items ( dbpli - > query ) ;
2015-03-16 18:33:42 -04:00
nstreams = 0 ;
2010-01-21 11:52:51 -05:00
break ;
default :
DPRINTF ( E_LOG , L_DB , " Unknown playlist type %d while fetching playlist \n " , type ) ;
return - 1 ;
}
2009-06-11 12:28:01 -04:00
2015-03-16 18:33:42 -04:00
dbpli - > items = qp - > buf1 ;
ret = snprintf ( qp - > buf1 , sizeof ( qp - > buf1 ) , " %d " , nitems ) ;
if ( ( ret < 0 ) | | ( ret > = sizeof ( qp - > buf1 ) ) )
2009-06-11 12:28:01 -04:00
{
2015-03-16 18:33:42 -04:00
DPRINTF ( E_LOG , L_DB , " Could not convert item count, buffer too small \n " ) ;
2009-06-11 12:28:01 -04:00
2015-03-16 18:33:42 -04:00
strcpy ( qp - > buf1 , " 0 " ) ;
}
dbpli - > streams = qp - > buf2 ;
ret = snprintf ( qp - > buf2 , sizeof ( qp - > buf2 ) , " %d " , nstreams ) ;
if ( ( ret < 0 ) | | ( ret > = sizeof ( qp - > buf2 ) ) )
{
DPRINTF ( E_LOG , L_DB , " Could not convert stream count, buffer too small \n " ) ;
strcpy ( qp - > buf2 , " 0 " ) ;
2009-06-11 12:28:01 -04:00
}
2009-06-07 12:56:35 -04:00
return 0 ;
}
2010-01-10 06:26:48 -05:00
int
db_query_fetch_group ( struct query_params * qp , struct db_group_info * dbgri )
{
int ncols ;
char * * strcol ;
int i ;
int ret ;
memset ( dbgri , 0 , sizeof ( struct db_group_info ) ) ;
if ( ! qp - > stmt )
{
DPRINTF ( E_LOG , L_DB , " Query not started! \n " ) ;
return - 1 ;
}
2013-08-29 16:00:37 -04:00
if ( ( qp - > type ! = Q_GROUP_ALBUMS ) & & ( qp - > type ! = Q_GROUP_ARTISTS ) )
2010-01-10 06:26:48 -05:00
{
DPRINTF ( E_LOG , L_DB , " Not a groups query! \n " ) ;
return - 1 ;
}
2010-04-26 12:24:09 -04:00
ret = db_blocking_step ( qp - > stmt ) ;
2010-01-10 06:26:48 -05:00
if ( ret = = SQLITE_DONE )
{
2014-06-01 17:58:44 -04:00
DPRINTF ( E_DBG , L_DB , " End of query results \n " ) ;
2010-01-10 06:26:48 -05:00
return 1 ;
}
else if ( ret ! = SQLITE_ROW )
{
DPRINTF ( E_LOG , L_DB , " Could not step: %s \n " , sqlite3_errmsg ( hdl ) ) ;
return - 1 ;
}
ncols = sqlite3_column_count ( qp - > stmt ) ;
if ( sizeof ( dbgri_cols_map ) / sizeof ( dbgri_cols_map [ 0 ] ) ! = ncols )
{
DPRINTF ( E_LOG , L_DB , " BUG: dbgri column map out of sync with schema \n " ) ;
return - 1 ;
}
for ( i = 0 ; i < ncols ; i + + )
{
strcol = ( char * * ) ( ( char * ) dbgri + dbgri_cols_map [ i ] ) ;
* strcol = ( char * ) sqlite3_column_text ( qp - > stmt , i ) ;
}
return 0 ;
}
2015-04-06 03:19:48 -04:00
int
2015-05-26 15:24:10 -04:00
db_query_fetch_count ( struct query_params * qp , struct filecount_info * fci )
2015-04-06 03:19:48 -04:00
{
int ret ;
2015-05-26 15:24:10 -04:00
memset ( fci , 0 , sizeof ( struct filecount_info ) ) ;
2015-04-06 03:19:48 -04:00
if ( ! qp - > stmt )
{
DPRINTF ( E_LOG , L_DB , " Query not started! \n " ) ;
return - 1 ;
}
if ( qp - > type ! = Q_COUNT_ITEMS )
{
DPRINTF ( E_LOG , L_DB , " Not a count query! \n " ) ;
return - 1 ;
}
ret = db_blocking_step ( qp - > stmt ) ;
if ( ret = = SQLITE_DONE )
{
DPRINTF ( E_DBG , L_DB , " End of query results for count query \n " ) ;
return 0 ;
}
else if ( ret ! = SQLITE_ROW )
{
DPRINTF ( E_LOG , L_DB , " Could not step: %s \n " , sqlite3_errmsg ( hdl ) ) ;
return - 1 ;
}
2015-05-26 15:24:10 -04:00
fci - > count = sqlite3_column_int ( qp - > stmt , 0 ) ;
fci - > length = sqlite3_column_int ( qp - > stmt , 1 ) ;
2015-04-06 03:19:48 -04:00
return 0 ;
}
2009-06-07 12:56:35 -04:00
int
db_query_fetch_string ( struct query_params * qp , char * * string )
{
int ret ;
* string = NULL ;
if ( ! qp - > stmt )
{
DPRINTF ( E_LOG , L_DB , " Query not started! \n " ) ;
return - 1 ;
}
if ( ! ( qp - > type & Q_F_BROWSE ) )
{
DPRINTF ( E_LOG , L_DB , " Not a browse query! \n " ) ;
return - 1 ;
}
2010-04-26 12:24:09 -04:00
ret = db_blocking_step ( qp - > stmt ) ;
2009-06-07 12:56:35 -04:00
if ( ret = = SQLITE_DONE )
{
2014-06-01 17:58:44 -04:00
DPRINTF ( E_DBG , L_DB , " End of query results \n " ) ;
2009-06-07 12:56:35 -04:00
* string = NULL ;
return 0 ;
}
else if ( ret ! = SQLITE_ROW )
{
DPRINTF ( E_LOG , L_DB , " Could not step: %s \n " , sqlite3_errmsg ( hdl ) ) ;
return - 1 ;
}
* string = ( char * ) sqlite3_column_text ( qp - > stmt , 0 ) ;
return 0 ;
}
2010-12-05 10:27:06 -05:00
int
db_query_fetch_string_sort ( struct query_params * qp , char * * string , char * * sortstring )
{
int ret ;
* string = NULL ;
if ( ! qp - > stmt )
{
DPRINTF ( E_LOG , L_DB , " Query not started! \n " ) ;
return - 1 ;
}
if ( ! ( qp - > type & Q_F_BROWSE ) )
{
DPRINTF ( E_LOG , L_DB , " Not a browse query! \n " ) ;
return - 1 ;
}
ret = db_blocking_step ( qp - > stmt ) ;
if ( ret = = SQLITE_DONE )
{
2014-06-01 17:58:44 -04:00
DPRINTF ( E_DBG , L_DB , " End of query results \n " ) ;
2010-12-05 10:27:06 -05:00
* string = NULL ;
return 0 ;
}
else if ( ret ! = SQLITE_ROW )
{
DPRINTF ( E_LOG , L_DB , " Could not step: %s \n " , sqlite3_errmsg ( hdl ) ) ;
return - 1 ;
}
* string = ( char * ) sqlite3_column_text ( qp - > stmt , 0 ) ;
* sortstring = ( char * ) sqlite3_column_text ( qp - > stmt , 1 ) ;
return 0 ;
}
2009-06-07 12:56:35 -04:00
/* Files */
int
2009-06-11 12:41:50 -04:00
db_files_get_count ( void )
2009-06-07 12:56:35 -04:00
{
2011-03-28 13:06:48 -04:00
return db_get_count ( " SELECT COUNT(*) FROM files f WHERE f . disabled = 0 ; " );
2009-06-07 12:56:35 -04:00
}
2015-11-01 03:15:24 -05:00
int
db_files_get_artist_count ( void )
{
return db_get_count ( " SELECT COUNT(DISTINCT songartistid) FROM files f WHERE f . disabled = 0 ; " );
}
int
db_files_get_album_count ( void )
{
return db_get_count ( " SELECT COUNT(DISTINCT songalbumid) FROM files f WHERE f . disabled = 0 ; " );
}
2013-08-21 17:16:25 -04:00
int
2013-11-30 17:12:09 -05:00
db_files_get_count_bymatch ( char * path )
2013-08-21 17:16:25 -04:00
{
2013-11-30 17:12:09 -05:00
# define Q_TMPL "SELECT COUNT(*) FROM files f WHERE f.path LIKE '%%%q';"
2013-08-21 17:16:25 -04:00
char * query ;
int count ;
2013-11-30 17:12:09 -05:00
query = sqlite3_mprintf ( Q_TMPL , path ) ;
2013-08-21 17:16:25 -04:00
if ( ! query )
{
DPRINTF ( E_LOG , L_DB , " Out of memory making count query string. \n " ) ;
2013-08-21 17:30:30 -04:00
return - 1 ;
2013-08-21 17:16:25 -04:00
}
count = db_get_count ( query ) ;
sqlite3_free ( query ) ;
return count ;
2013-11-30 17:12:09 -05:00
# undef Q_TMPL
2013-08-21 17:16:25 -04:00
}
2013-12-17 14:58:55 -05:00
void
db_files_update_songartistid ( void )
{
2014-08-22 16:51:13 -04:00
db_query_run ( " UPDATE files SET songartistid = daap_songalbumid(LOWER(album_artist), ''); " , 0 , 1 ) ;
2013-12-17 14:58:55 -05:00
}
2010-03-06 11:39:35 -05:00
void
db_files_update_songalbumid ( void )
{
2014-08-22 16:51:13 -04:00
db_query_run ( " UPDATE files SET songalbumid = daap_songalbumid(LOWER(album_artist), LOWER(album)); " , 0 , 1 ) ;
2010-03-06 11:39:35 -05:00
}
2009-06-07 12:56:35 -04:00
void
db_file_inc_playcount ( int id )
{
2015-08-04 16:33:32 -04:00
# define Q_TMPL "UPDATE files SET play_count = play_count + 1, time_played = %" PRIi64 ", seek = 0 WHERE id = %d;"
2009-06-07 12:56:35 -04:00
char * query ;
query = sqlite3_mprintf ( Q_TMPL , ( int64_t ) time ( NULL ) , id ) ;
if ( ! query )
{
DPRINTF ( E_LOG , L_DB , " Out of memory for query string \n " ) ;
return ;
}
2015-03-31 17:05:24 -04:00
db_query_run ( query , 1 , 0 ) ;
2009-06-07 12:56:35 -04:00
# undef Q_TMPL
}
void
2011-06-12 05:06:37 -04:00
db_file_ping ( int id )
2009-06-07 12:56:35 -04:00
{
2011-06-12 05:06:37 -04:00
# define Q_TMPL "UPDATE files SET db_timestamp = %" PRIi64 ", disabled = 0 WHERE id = %d;"
2009-06-07 12:56:35 -04:00
char * query ;
2011-06-12 05:06:37 -04:00
query = sqlite3_mprintf ( Q_TMPL , ( int64_t ) time ( NULL ) , id ) ;
2009-06-07 12:56:35 -04:00
2014-08-22 16:51:13 -04:00
db_query_run ( query , 1 , 1 ) ;
2009-06-07 12:56:35 -04:00
# undef Q_TMPL
}
2013-11-30 17:12:09 -05:00
void
2014-05-14 14:44:07 -04:00
db_file_ping_bymatch ( char * path , int isdir )
2013-11-30 17:12:09 -05:00
{
2014-05-14 14:44:07 -04:00
# define Q_TMPL_DIR "UPDATE files SET db_timestamp = %" PRIi64 " WHERE path LIKE '%q / %%';"
# define Q_TMPL_NODIR "UPDATE files SET db_timestamp = %" PRIi64 " WHERE path LIKE '%q%%';"
2013-11-30 17:12:09 -05:00
char * query ;
2014-05-14 14:44:07 -04:00
if ( isdir )
query = sqlite3_mprintf ( Q_TMPL_DIR , ( int64_t ) time ( NULL ) , path ) ;
else
query = sqlite3_mprintf ( Q_TMPL_NODIR , ( int64_t ) time ( NULL ) , path ) ;
2014-08-22 16:51:13 -04:00
db_query_run ( query , 1 , 1 ) ;
2014-05-14 14:44:07 -04:00
# undef Q_TMPL_DIR
# undef Q_TMPL_NODIR
2013-11-30 17:12:09 -05:00
}
2010-03-07 05:06:15 -05:00
char *
db_file_path_byid ( int id )
{
2011-03-28 13:06:48 -04:00
# define Q_TMPL "SELECT f.path FROM files f WHERE f.id = %d;"
2010-03-07 05:06:15 -05:00
char * query ;
sqlite3_stmt * stmt ;
char * res ;
int ret ;
query = sqlite3_mprintf ( Q_TMPL , id ) ;
if ( ! query )
{
DPRINTF ( E_LOG , L_DB , " Out of memory for query string \n " ) ;
return NULL ;
}
DPRINTF ( E_DBG , L_DB , " Running query '%s' \n " , query ) ;
2010-04-26 12:24:09 -04:00
ret = db_blocking_prepare_v2 ( query , strlen ( query ) + 1 , & stmt , NULL ) ;
2010-03-07 05:06:15 -05:00
if ( ret ! = SQLITE_OK )
{
DPRINTF ( E_LOG , L_DB , " Could not prepare statement: %s \n " , sqlite3_errmsg ( hdl ) ) ;
sqlite3_free ( query ) ;
return NULL ;
}
2010-04-26 12:24:09 -04:00
ret = db_blocking_step ( stmt ) ;
2010-03-07 05:06:15 -05:00
if ( ret ! = SQLITE_ROW )
{
if ( ret = = SQLITE_DONE )
2014-06-01 17:58:44 -04:00
DPRINTF ( E_DBG , L_DB , " No results \n " ) ;
2010-03-07 05:06:15 -05:00
else
2015-02-23 14:26:42 -05:00
DPRINTF ( E_LOG , L_DB , " Could not step: %s \n " , sqlite3_errmsg ( hdl ) ) ;
2010-03-07 05:06:15 -05:00
sqlite3_finalize ( stmt ) ;
sqlite3_free ( query ) ;
return NULL ;
}
res = ( char * ) sqlite3_column_text ( stmt , 0 ) ;
if ( res )
res = strdup ( res ) ;
2011-06-11 11:24:59 -04:00
# ifdef DB_PROFILE
while ( db_blocking_step ( stmt ) = = SQLITE_ROW )
; /* EMPTY */
# endif
2010-03-07 05:06:15 -05:00
sqlite3_finalize ( stmt ) ;
sqlite3_free ( query ) ;
return res ;
# undef Q_TMPL
}
2009-11-22 09:39:38 -05:00
static int
db_file_id_byquery ( char * query )
2009-06-07 12:56:35 -04:00
{
sqlite3_stmt * stmt ;
int ret ;
if ( ! query )
2009-11-22 09:39:38 -05:00
return 0 ;
2009-06-07 12:56:35 -04:00
DPRINTF ( E_DBG , L_DB , " Running query '%s' \n " , query ) ;
2010-04-26 12:24:09 -04:00
ret = db_blocking_prepare_v2 ( query , strlen ( query ) + 1 , & stmt , NULL ) ;
2009-06-07 12:56:35 -04:00
if ( ret ! = SQLITE_OK )
{
DPRINTF ( E_LOG , L_DB , " Could not prepare statement: %s \n " , sqlite3_errmsg ( hdl ) ) ;
2009-06-11 14:44:22 -04:00
return 0 ;
2009-06-07 12:56:35 -04:00
}
2010-04-26 12:24:09 -04:00
ret = db_blocking_step ( stmt ) ;
2009-06-07 12:56:35 -04:00
if ( ret ! = SQLITE_ROW )
{
if ( ret = = SQLITE_DONE )
2014-06-01 17:58:44 -04:00
DPRINTF ( E_DBG , L_DB , " No results \n " ) ;
2009-06-07 12:56:35 -04:00
else
2015-02-23 14:26:42 -05:00
DPRINTF ( E_LOG , L_DB , " Could not step: %s \n " , sqlite3_errmsg ( hdl ) ) ;
2009-06-07 12:56:35 -04:00
sqlite3_finalize ( stmt ) ;
2009-06-11 14:44:22 -04:00
return 0 ;
2009-06-07 12:56:35 -04:00
}
2009-06-11 14:44:22 -04:00
ret = sqlite3_column_int ( stmt , 0 ) ;
2009-06-07 12:56:35 -04:00
2011-06-11 11:24:59 -04:00
# ifdef DB_PROFILE
while ( db_blocking_step ( stmt ) = = SQLITE_ROW )
; /* EMPTY */
# endif
2009-06-07 12:56:35 -04:00
sqlite3_finalize ( stmt ) ;
2009-11-22 09:39:38 -05:00
return ret ;
}
int
db_file_id_bypath ( char * path )
{
2011-03-28 13:06:48 -04:00
# define Q_TMPL "SELECT f.id FROM files f WHERE f.path = '%q';"
2009-11-22 09:39:38 -05:00
char * query ;
int ret ;
query = sqlite3_mprintf ( Q_TMPL , path ) ;
2009-11-22 10:30:45 -05:00
if ( ! query )
{
DPRINTF ( E_LOG , L_DB , " Out of memory for query string \n " ) ;
return 0 ;
}
ret = db_file_id_byquery ( query ) ;
sqlite3_free ( query ) ;
return ret ;
# undef Q_TMPL
}
2013-08-20 15:58:35 -04:00
int
2013-11-30 17:12:09 -05:00
db_file_id_bymatch ( char * path )
2013-08-20 15:58:35 -04:00
{
# define Q_TMPL "SELECT f.id FROM files f WHERE f.path LIKE '%%%q';"
char * query ;
int ret ;
query = sqlite3_mprintf ( Q_TMPL , path ) ;
if ( ! query )
{
DPRINTF ( E_LOG , L_DB , " Out of memory for query string \n " ) ;
return 0 ;
}
ret = db_file_id_byquery ( query ) ;
sqlite3_free ( query ) ;
return ret ;
# undef Q_TMPL
}
2015-12-27 01:16:50 -05:00
//TODO [cleanup] unused function(?)
2009-11-22 10:30:45 -05:00
int
db_file_id_byfilebase ( char * filename , char * base )
{
2011-03-28 13:06:48 -04:00
# define Q_TMPL "SELECT f.id FROM files f WHERE f.path LIKE '%q / %% / %q';"
2009-11-22 10:30:45 -05:00
char * query ;
int ret ;
query = sqlite3_mprintf ( Q_TMPL , base , filename ) ;
if ( ! query )
{
DPRINTF ( E_LOG , L_DB , " Out of memory for query string \n " ) ;
return 0 ;
}
ret = db_file_id_byquery ( query ) ;
sqlite3_free ( query ) ;
return ret ;
# undef Q_TMPL
}
int
db_file_id_byfile ( char * filename )
{
2011-03-28 13:06:48 -04:00
# define Q_TMPL "SELECT f.id FROM files f WHERE f.fname = '%q';"
2009-11-22 10:30:45 -05:00
char * query ;
int ret ;
query = sqlite3_mprintf ( Q_TMPL , filename ) ;
2009-11-22 09:39:38 -05:00
if ( ! query )
{
DPRINTF ( E_LOG , L_DB , " Out of memory for query string \n " ) ;
return 0 ;
}
ret = db_file_id_byquery ( query ) ;
sqlite3_free ( query ) ;
return ret ;
# undef Q_TMPL
}
int
db_file_id_byurl ( char * url )
{
2011-03-28 13:06:48 -04:00
# define Q_TMPL "SELECT f.id FROM files f WHERE f.url = '%q';"
2009-11-22 09:39:38 -05:00
char * query ;
int ret ;
query = sqlite3_mprintf ( Q_TMPL , url ) ;
if ( ! query )
{
DPRINTF ( E_LOG , L_DB , " Out of memory for query string \n " ) ;
return 0 ;
}
ret = db_file_id_byquery ( query ) ;
2009-06-07 12:56:35 -04:00
sqlite3_free ( query ) ;
2009-06-11 14:44:22 -04:00
return ret ;
# undef Q_TMPL
}
2015-07-16 21:22:24 -04:00
int
db_file_id_by_virtualpath_match ( char * path )
{
# define Q_TMPL "SELECT f.id FROM files f WHERE f.virtual_path LIKE '%%%q%%';"
char * query ;
int ret ;
query = sqlite3_mprintf ( Q_TMPL , path ) ;
if ( ! query )
{
DPRINTF ( E_LOG , L_DB , " Out of memory for query string \n " ) ;
return 0 ;
}
ret = db_file_id_byquery ( query ) ;
sqlite3_free ( query ) ;
return ret ;
# undef Q_TMPL
}
2011-06-12 05:06:37 -04:00
void
db_file_stamp_bypath ( char * path , time_t * stamp , int * id )
2009-06-11 14:44:22 -04:00
{
2011-03-28 13:06:48 -04:00
# define Q_TMPL "SELECT f.id, f.db_timestamp FROM files f WHERE f.path = '%q';"
2009-06-11 14:44:22 -04:00
char * query ;
sqlite3_stmt * stmt ;
int ret ;
2011-06-12 05:06:37 -04:00
* stamp = 0 ;
2009-06-11 14:44:22 -04:00
query = sqlite3_mprintf ( Q_TMPL , path ) ;
if ( ! query )
{
DPRINTF ( E_LOG , L_DB , " Out of memory for query string \n " ) ;
2011-06-12 05:06:37 -04:00
return ;
2009-06-11 14:44:22 -04:00
}
DPRINTF ( E_DBG , L_DB , " Running query '%s' \n " , query ) ;
2010-04-26 12:24:09 -04:00
ret = db_blocking_prepare_v2 ( query , strlen ( query ) + 1 , & stmt , NULL ) ;
2009-06-11 14:44:22 -04:00
if ( ret ! = SQLITE_OK )
{
DPRINTF ( E_LOG , L_DB , " Could not prepare statement: %s \n " , sqlite3_errmsg ( hdl ) ) ;
sqlite3_free ( query ) ;
2011-06-12 05:06:37 -04:00
return ;
2009-06-11 14:44:22 -04:00
}
2010-04-26 12:24:09 -04:00
ret = db_blocking_step ( stmt ) ;
2009-06-11 14:44:22 -04:00
if ( ret ! = SQLITE_ROW )
{
if ( ret = = SQLITE_DONE )
2014-06-01 17:58:44 -04:00
DPRINTF ( E_DBG , L_DB , " No results \n " ) ;
2009-06-11 14:44:22 -04:00
else
2015-02-23 14:26:42 -05:00
DPRINTF ( E_LOG , L_DB , " Could not step: %s \n " , sqlite3_errmsg ( hdl ) ) ;
2009-06-11 14:44:22 -04:00
sqlite3_finalize ( stmt ) ;
sqlite3_free ( query ) ;
2011-06-12 05:06:37 -04:00
return ;
2009-06-11 14:44:22 -04:00
}
2011-06-12 05:06:37 -04:00
* id = sqlite3_column_int ( stmt , 0 ) ;
* stamp = ( time_t ) sqlite3_column_int64 ( stmt , 1 ) ;
2009-06-11 14:44:22 -04:00
2011-06-11 11:24:59 -04:00
# ifdef DB_PROFILE
while ( db_blocking_step ( stmt ) = = SQLITE_ROW )
; /* EMPTY */
# endif
2009-06-11 14:44:22 -04:00
sqlite3_finalize ( stmt ) ;
sqlite3_free ( query ) ;
2009-06-07 12:56:35 -04:00
# undef Q_TMPL
}
static struct media_file_info *
db_file_fetch_byquery ( char * query )
{
struct media_file_info * mfi ;
sqlite3_stmt * stmt ;
int ncols ;
char * cval ;
uint32_t * ival ;
uint64_t * i64val ;
char * * strval ;
2009-06-10 09:23:02 -04:00
uint64_t disabled ;
2009-06-07 12:56:35 -04:00
int i ;
int ret ;
if ( ! query )
return NULL ;
DPRINTF ( E_DBG , L_DB , " Running query '%s' \n " , query ) ;
mfi = ( struct media_file_info * ) malloc ( sizeof ( struct media_file_info ) ) ;
if ( ! mfi )
{
DPRINTF ( E_LOG , L_DB , " Could not allocate struct media_file_info, out of memory \n " ) ;
return NULL ;
}
memset ( mfi , 0 , sizeof ( struct media_file_info ) ) ;
2010-04-26 12:24:09 -04:00
ret = db_blocking_prepare_v2 ( query , - 1 , & stmt , NULL ) ;
2009-06-07 12:56:35 -04:00
if ( ret ! = SQLITE_OK )
{
DPRINTF ( E_LOG , L_DB , " Could not prepare statement: %s \n " , sqlite3_errmsg ( hdl ) ) ;
free ( mfi ) ;
return NULL ;
}
2010-04-26 12:24:09 -04:00
ret = db_blocking_step ( stmt ) ;
2009-06-07 12:56:35 -04:00
if ( ret ! = SQLITE_ROW )
{
if ( ret = = SQLITE_DONE )
2014-06-01 17:58:44 -04:00
DPRINTF ( E_DBG , L_DB , " No results \n " ) ;
2009-06-07 12:56:35 -04:00
else
DPRINTF ( E_LOG , L_DB , " Could not step: %s \n " , sqlite3_errmsg ( hdl ) ) ;
sqlite3_finalize ( stmt ) ;
free ( mfi ) ;
return NULL ;
}
ncols = sqlite3_column_count ( stmt ) ;
if ( sizeof ( mfi_cols_map ) / sizeof ( mfi_cols_map [ 0 ] ) ! = ncols )
{
DPRINTF ( E_LOG , L_DB , " BUG: mfi column map out of sync with schema \n " ) ;
sqlite3_finalize ( stmt ) ;
free ( mfi ) ;
return NULL ;
}
for ( i = 0 ; i < ncols ; i + + )
{
switch ( mfi_cols_map [ i ] . type )
{
case DB_TYPE_CHAR :
cval = ( char * ) mfi + mfi_cols_map [ i ] . offset ;
* cval = sqlite3_column_int ( stmt , i ) ;
break ;
case DB_TYPE_INT :
ival = ( uint32_t * ) ( ( char * ) mfi + mfi_cols_map [ i ] . offset ) ;
2009-06-10 09:23:02 -04:00
if ( mfi_cols_map [ i ] . offset = = mfi_offsetof ( disabled ) )
{
disabled = sqlite3_column_int64 ( stmt , i ) ;
* ival = ( disabled ! = 0 ) ;
}
else
* ival = sqlite3_column_int ( stmt , i ) ;
2009-06-07 12:56:35 -04:00
break ;
case DB_TYPE_INT64 :
i64val = ( uint64_t * ) ( ( char * ) mfi + mfi_cols_map [ i ] . offset ) ;
* i64val = sqlite3_column_int64 ( stmt , i ) ;
break ;
case DB_TYPE_STRING :
strval = ( char * * ) ( ( char * ) mfi + mfi_cols_map [ i ] . offset ) ;
cval = ( char * ) sqlite3_column_text ( stmt , i ) ;
if ( cval )
* strval = strdup ( cval ) ;
break ;
default :
DPRINTF ( E_LOG , L_DB , " BUG: Unknown type %d in mfi column map \n " , mfi_cols_map [ i ] . type ) ;
free_mfi ( mfi , 0 ) ;
sqlite3_finalize ( stmt ) ;
return NULL ;
}
}
2011-06-11 11:24:59 -04:00
# ifdef DB_PROFILE
while ( db_blocking_step ( stmt ) = = SQLITE_ROW )
; /* EMPTY */
# endif
2009-06-07 12:56:35 -04:00
sqlite3_finalize ( stmt ) ;
return mfi ;
}
struct media_file_info *
db_file_fetch_byid ( int id )
{
2011-03-28 13:06:48 -04:00
# define Q_TMPL "SELECT f.* FROM files f WHERE f.id = %d;"
2009-06-07 12:56:35 -04:00
struct media_file_info * mfi ;
char * query ;
query = sqlite3_mprintf ( Q_TMPL , id ) ;
if ( ! query )
{
DPRINTF ( E_LOG , L_DB , " Out of memory for query string \n " ) ;
return NULL ;
}
mfi = db_file_fetch_byquery ( query ) ;
sqlite3_free ( query ) ;
return mfi ;
# undef Q_TMPL
}
2014-12-21 14:41:44 -05:00
struct media_file_info *
db_file_fetch_byvirtualpath ( char * virtual_path )
{
# define Q_TMPL "SELECT f.* FROM files f WHERE f.virtual_path = %Q;"
struct media_file_info * mfi ;
char * query ;
query = sqlite3_mprintf ( Q_TMPL , virtual_path ) ;
if ( ! query )
{
DPRINTF ( E_LOG , L_DB , " Out of memory for query string \n " ) ;
return NULL ;
}
mfi = db_file_fetch_byquery ( query ) ;
sqlite3_free ( query ) ;
return mfi ;
# undef Q_TMPL
}
2009-06-07 12:56:35 -04:00
int
db_file_add ( struct media_file_info * mfi )
{
2009-06-11 17:03:53 -04:00
# define Q_TMPL "INSERT INTO files (id, path, fname, title, artist, album, genre, comment, type, composer," \
2009-06-07 12:56:35 -04:00
" orchestra, conductor, grouping, url, bitrate, samplerate, song_length, file_size, year, track, " \
2014-01-11 17:05:29 -05:00
" total_tracks, disc, total_discs, bpm, compilation, artwork, rating, play_count, seek, data_kind, item_kind, " \
2009-06-07 12:56:35 -04:00
" description, time_added, time_modified, time_played, db_timestamp, disabled, sample_count, " \
2009-12-26 02:39:39 -05:00
" codectype, idx, has_video, contentrating, bits_per_sample, album_artist, " \
2010-03-06 11:13:56 -05:00
" media_kind, tv_series_name, tv_episode_num_str, tv_network_name, tv_episode_sort, tv_season_num, " \
2014-04-30 17:30:08 -04:00
" songartistid, songalbumid, " \
2015-12-27 01:16:50 -05:00
" title_sort, artist_sort, album_sort, composer_sort, album_artist_sort, virtual_path, " \
" directory_id) " \
2011-03-08 12:54:20 -05:00
" VALUES (NULL, '%q', '%q', TRIM(%Q), TRIM(%Q), TRIM(%Q), TRIM(%Q), TRIM(%Q), %Q, TRIM(%Q), " \
" TRIM(%Q), TRIM(%Q), TRIM(%Q), %Q, %d, %d, %d, % " PRIi64 " , %d, %d, " \
2014-01-11 17:05:29 -05:00
" %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, " \
2009-06-07 12:56:35 -04:00
" %Q, % " PRIi64 " , % " PRIi64 " , % " PRIi64 " , % " PRIi64 " , %d, % " PRIi64 " , " \
2013-12-19 14:26:38 -05:00
" %Q, %d, %d, %d, %d, TRIM(%Q), " \
" %d, TRIM(%Q), TRIM(%Q), TRIM(%Q), %d, %d, " \
2015-01-08 16:40:47 -05:00
" daap_songalbumid(LOWER(TRIM(%Q)), ''), daap_songalbumid(LOWER(TRIM(%Q)), LOWER(TRIM(%Q))), " \
2015-12-27 01:16:50 -05:00
" TRIM(%Q), TRIM(%Q), TRIM(%Q), TRIM(%Q), TRIM(%Q), TRIM(%Q), %d); "
2010-09-21 07:16:38 -04:00
2009-06-07 12:56:35 -04:00
char * query ;
char * errmsg ;
int ret ;
if ( mfi - > id ! = 0 )
{
2010-04-30 12:28:29 -04:00
DPRINTF ( E_WARN , L_DB , " Trying to add file with non-zero id; use db_file_update()? \n " ) ;
2009-06-07 12:56:35 -04:00
return - 1 ;
}
mfi - > db_timestamp = ( uint64_t ) time ( NULL ) ;
2015-05-29 13:47:53 -04:00
if ( mfi - > time_added = = 0 )
mfi - > time_added = mfi - > db_timestamp ;
2009-06-07 12:56:35 -04:00
if ( mfi - > time_modified = = 0 )
mfi - > time_modified = mfi - > db_timestamp ;
query = sqlite3_mprintf ( Q_TMPL ,
STR ( mfi - > path ) , STR ( mfi - > fname ) , mfi - > title , mfi - > artist , mfi - > album ,
mfi - > genre , mfi - > comment , mfi - > type , mfi - > composer ,
mfi - > orchestra , mfi - > conductor , mfi - > grouping , mfi - > url , mfi - > bitrate ,
mfi - > samplerate , mfi - > song_length , mfi - > file_size , mfi - > year , mfi - > track ,
2014-01-11 17:05:29 -05:00
mfi - > total_tracks , mfi - > disc , mfi - > total_discs , mfi - > bpm , mfi - > compilation , mfi - > artwork ,
2013-12-19 14:26:38 -05:00
mfi - > rating , mfi - > play_count , mfi - > seek , mfi - > data_kind , mfi - > item_kind ,
2009-06-07 12:56:35 -04:00
mfi - > description , ( int64_t ) mfi - > time_added , ( int64_t ) mfi - > time_modified ,
( int64_t ) mfi - > time_played , ( int64_t ) mfi - > db_timestamp , mfi - > disabled , mfi - > sample_count ,
2009-06-11 13:15:22 -04:00
mfi - > codectype , mfi - > index , mfi - > has_video ,
2009-12-26 02:39:39 -05:00
mfi - > contentrating , mfi - > bits_per_sample , mfi - > album_artist ,
2014-12-21 14:41:44 -05:00
mfi - > media_kind , mfi - > tv_series_name , mfi - > tv_episode_num_str ,
mfi - > tv_network_name , mfi - > tv_episode_sort , mfi - > tv_season_num ,
2015-01-08 16:40:47 -05:00
mfi - > album_artist , mfi - > album_artist , mfi - > album , mfi - > title_sort , mfi - > artist_sort , mfi - > album_sort ,
2015-12-27 01:16:50 -05:00
mfi - > composer_sort , mfi - > album_artist_sort , mfi - > virtual_path , mfi - > directory_id ) ;
2010-09-21 07:16:38 -04:00
2009-06-07 12:56:35 -04:00
if ( ! query )
{
DPRINTF ( E_LOG , L_DB , " Out of memory for query string \n " ) ;
return - 1 ;
}
DPRINTF ( E_DBG , L_DB , " Running query '%s' \n " , query ) ;
2010-04-26 12:24:09 -04:00
ret = db_exec ( query , & errmsg ) ;
2009-06-07 12:56:35 -04:00
if ( ret ! = SQLITE_OK )
{
DPRINTF ( E_LOG , L_DB , " Query error: %s \n " , errmsg ) ;
sqlite3_free ( errmsg ) ;
sqlite3_free ( query ) ;
return - 1 ;
}
sqlite3_free ( query ) ;
2014-11-10 16:53:08 -05:00
cache_daap_trigger ( ) ;
2014-08-21 04:14:24 -04:00
2009-06-07 12:56:35 -04:00
return 0 ;
# undef Q_TMPL
}
int
db_file_update ( struct media_file_info * mfi )
{
2011-03-08 12:54:20 -05:00
# define Q_TMPL "UPDATE files SET path = '%q', fname = '%q', title = TRIM(%Q), artist = TRIM(%Q), album = TRIM(%Q), genre = TRIM(%Q)," \
2014-12-21 14:41:44 -05:00
" comment = TRIM(%Q), type = %Q, composer = TRIM(%Q), orchestra = TRIM(%Q), conductor = TRIM(%Q), grouping = TRIM(%Q), " \
" url = %Q, bitrate = %d, samplerate = %d, song_length = %d, file_size = % " PRIi64 " , " \
" year = %d, track = %d, total_tracks = %d, disc = %d, total_discs = %d, bpm = %d, " \
" compilation = %d, artwork = %d, rating = %d, seek = %d, data_kind = %d, item_kind = %d, " \
" description = %Q, time_modified = % " PRIi64 " , " \
" db_timestamp = % " PRIi64 " , disabled = % " PRIi64 " , sample_count = % " PRIi64 " , " \
" codectype = %Q, idx = %d, has_video = %d, " \
" bits_per_sample = %d, album_artist = TRIM(%Q), " \
" media_kind = %d, tv_series_name = TRIM(%Q), tv_episode_num_str = TRIM(%Q), " \
" tv_network_name = TRIM(%Q), tv_episode_sort = %d, tv_season_num = %d, " \
" songartistid = daap_songalbumid(LOWER(TRIM(%Q)), ''), songalbumid = daap_songalbumid(LOWER(TRIM(%Q)), LOWER(TRIM(%Q))), " \
" title_sort = TRIM(%Q), artist_sort = TRIM(%Q), album_sort = TRIM(%Q), composer_sort = TRIM(%Q), album_artist_sort = TRIM(%Q), " \
2015-12-27 01:16:50 -05:00
" virtual_path = TRIM(%Q), directory_id = %d " \
2014-12-21 14:41:44 -05:00
" WHERE id = %d; "
2009-06-07 12:56:35 -04:00
char * query ;
char * errmsg ;
int ret ;
if ( mfi - > id = = 0 )
{
DPRINTF ( E_WARN , L_DB , " Trying to update file with id 0; use db_file_add()? \n " ) ;
return - 1 ;
}
mfi - > db_timestamp = ( uint64_t ) time ( NULL ) ;
if ( mfi - > time_modified = = 0 )
mfi - > time_modified = mfi - > db_timestamp ;
query = sqlite3_mprintf ( Q_TMPL ,
STR ( mfi - > path ) , STR ( mfi - > fname ) , mfi - > title , mfi - > artist , mfi - > album , mfi - > genre ,
2015-02-23 14:26:42 -05:00
mfi - > comment , mfi - > type , mfi - > composer , mfi - > orchestra , mfi - > conductor , mfi - > grouping ,
2009-06-07 12:56:35 -04:00
mfi - > url , mfi - > bitrate , mfi - > samplerate , mfi - > song_length , mfi - > file_size ,
mfi - > year , mfi - > track , mfi - > total_tracks , mfi - > disc , mfi - > total_discs , mfi - > bpm ,
2014-01-11 17:05:29 -05:00
mfi - > compilation , mfi - > artwork , mfi - > rating , mfi - > seek , mfi - > data_kind , mfi - > item_kind ,
2009-06-07 12:56:35 -04:00
mfi - > description , ( int64_t ) mfi - > time_modified ,
2014-06-09 17:42:02 -04:00
( int64_t ) mfi - > db_timestamp , ( int64_t ) mfi - > disabled , mfi - > sample_count ,
2009-06-11 13:15:22 -04:00
mfi - > codectype , mfi - > index , mfi - > has_video ,
2009-12-26 02:39:39 -05:00
mfi - > bits_per_sample , mfi - > album_artist ,
2015-02-23 14:26:42 -05:00
mfi - > media_kind , mfi - > tv_series_name , mfi - > tv_episode_num_str ,
2009-12-26 02:39:39 -05:00
mfi - > tv_network_name , mfi - > tv_episode_sort , mfi - > tv_season_num ,
2015-01-08 16:40:47 -05:00
mfi - > album_artist , mfi - > album_artist , mfi - > album ,
2010-09-21 07:16:38 -04:00
mfi - > title_sort , mfi - > artist_sort , mfi - > album_sort ,
2015-12-27 01:16:50 -05:00
mfi - > composer_sort , mfi - > album_artist_sort , mfi - > virtual_path , mfi - > directory_id ,
2009-12-26 02:39:39 -05:00
mfi - > id ) ;
2009-06-07 12:56:35 -04:00
if ( ! query )
{
DPRINTF ( E_LOG , L_DB , " Out of memory for query string \n " ) ;
return - 1 ;
}
DPRINTF ( E_DBG , L_DB , " Running query '%s' \n " , query ) ;
2010-04-26 12:24:09 -04:00
ret = db_exec ( query , & errmsg ) ;
2009-06-07 12:56:35 -04:00
if ( ret ! = SQLITE_OK )
{
DPRINTF ( E_LOG , L_DB , " Query error: %s \n " , errmsg ) ;
sqlite3_free ( errmsg ) ;
sqlite3_free ( query ) ;
return - 1 ;
}
sqlite3_free ( query ) ;
2014-11-10 16:53:08 -05:00
cache_daap_trigger ( ) ;
2014-08-19 18:21:48 -04:00
2009-06-07 12:56:35 -04:00
return 0 ;
# undef Q_TMPL
}
2015-03-14 16:42:53 -04:00
void
db_file_update_icy ( int id , char * artist , char * album )
{
# define Q_TMPL "UPDATE files SET artist = TRIM(%Q), album = TRIM(%Q) WHERE id = %d;"
char * query ;
if ( id = = 0 )
return ;
query = sqlite3_mprintf ( Q_TMPL , artist , album , id ) ;
if ( ! query )
{
DPRINTF ( E_LOG , L_DB , " Out of memory for query string \n " ) ;
return ;
}
2015-03-31 17:05:24 -04:00
db_query_run ( query , 1 , 0 ) ;
2015-03-14 16:42:53 -04:00
# undef Q_TMPL
}
2015-08-04 16:33:32 -04:00
void
db_file_save_seek ( int id , uint32_t seek )
{
# define Q_TMPL "UPDATE files SET seek = %d WHERE id = %d;"
char * query ;
if ( id = = 0 )
return ;
query = sqlite3_mprintf ( Q_TMPL , seek , id ) ;
if ( ! query )
{
DPRINTF ( E_LOG , L_DB , " Out of memory for query string \n " ) ;
return ;
}
db_query_run ( query , 1 , 0 ) ;
# undef Q_TMPL
}
2009-06-10 15:36:43 -04:00
void
db_file_delete_bypath ( char * path )
{
2009-06-11 17:03:53 -04:00
# define Q_TMPL "DELETE FROM files WHERE path = '%q';"
2009-06-10 15:36:43 -04:00
char * query ;
query = sqlite3_mprintf ( Q_TMPL , path ) ;
2014-08-22 16:51:13 -04:00
db_query_run ( query , 1 , 1 ) ;
2009-06-10 15:36:43 -04:00
# undef Q_TMPL
}
2009-06-10 16:11:24 -04:00
void
db_file_disable_bypath ( char * path , char * strip , uint32_t cookie )
{
2015-12-27 01:16:50 -05:00
# define Q_TMPL "UPDATE files SET path = substr(path, %d), virtual_path = substr(virtual_path, %d), disabled = %" PRIi64 " WHERE path = '%q';"
2009-06-10 16:11:24 -04:00
char * query ;
int64_t disabled ;
int striplen ;
2015-12-27 01:16:50 -05:00
int striplenvpath ;
2009-06-10 16:11:24 -04:00
disabled = ( cookie ! = 0 ) ? cookie : INOTIFY_FAKE_COOKIE ;
striplen = strlen ( strip ) + 1 ;
2015-12-27 01:16:50 -05:00
if ( strlen ( strip ) > 0 )
striplenvpath = strlen ( strip ) + strlen ( " /file:/ " ) ;
else
striplenvpath = 0 ;
2009-06-10 16:11:24 -04:00
2015-12-27 01:16:50 -05:00
query = sqlite3_mprintf ( Q_TMPL , striplen , striplenvpath , disabled , path ) ;
2009-06-11 08:42:55 -04:00
2014-08-22 16:51:13 -04:00
db_query_run ( query , 1 , 1 ) ;
2009-06-11 08:42:55 -04:00
# undef Q_TMPL
}
void
db_file_disable_bymatch ( char * path , char * strip , uint32_t cookie )
{
2015-12-27 01:16:50 -05:00
# define Q_TMPL "UPDATE files SET path = substr(path, %d), virtual_path = substr(virtual_path, %d), disabled = %" PRIi64 " WHERE path LIKE '%q / %%';"
2009-06-11 08:42:55 -04:00
char * query ;
int64_t disabled ;
int striplen ;
2015-12-27 01:16:50 -05:00
int striplenvpath ;
2009-06-11 08:42:55 -04:00
disabled = ( cookie ! = 0 ) ? cookie : INOTIFY_FAKE_COOKIE ;
striplen = strlen ( strip ) + 1 ;
2015-12-27 01:16:50 -05:00
if ( strlen ( strip ) > 0 )
striplenvpath = strlen ( strip ) + strlen ( " /file:/ " ) ;
else
striplenvpath = 0 ;
2009-06-11 08:42:55 -04:00
2015-12-27 01:16:50 -05:00
query = sqlite3_mprintf ( Q_TMPL , striplen , striplenvpath , disabled , path ) ;
2009-06-10 16:11:24 -04:00
2014-08-22 16:51:13 -04:00
db_query_run ( query , 1 , 1 ) ;
2009-06-10 16:11:24 -04:00
# undef Q_TMPL
}
int
db_file_enable_bycookie ( uint32_t cookie , char * path )
{
2015-12-27 01:16:50 -05:00
# define Q_TMPL "UPDATE files SET path = '%q' || path, virtual_path = ' / file:%q' || virtual_path, disabled = 0 WHERE disabled = %" PRIi64 ";"
2009-06-10 16:11:24 -04:00
char * query ;
int ret ;
2015-12-27 01:16:50 -05:00
query = sqlite3_mprintf ( Q_TMPL , path , path , ( int64_t ) cookie ) ;
2009-06-10 16:11:24 -04:00
2014-08-22 16:51:13 -04:00
ret = db_query_run ( query , 1 , 1 ) ;
2014-08-21 17:06:52 -04:00
2014-08-17 18:20:23 -04:00
return ( ( ret < 0 ) ? - 1 : sqlite3_changes ( hdl ) ) ;
2009-06-10 16:11:24 -04:00
# undef Q_TMPL
}
2015-12-27 01:16:50 -05:00
int
db_file_update_directoryid ( char * path , int dir_id )
{
# define Q_TMPL "UPDATE files SET directory_id = %d WHERE path = %Q;"
char * query ;
int ret ;
query = sqlite3_mprintf ( Q_TMPL , dir_id , path ) ;
ret = db_query_run ( query , 1 , 0 ) ;
return ( ( ret < 0 ) ? - 1 : sqlite3_changes ( hdl ) ) ;
# undef Q_TMPL
}
2009-06-07 12:56:35 -04:00
/* Playlists */
int
2009-06-11 12:41:50 -04:00
db_pl_get_count ( void )
2009-06-07 12:56:35 -04:00
{
2011-03-28 13:06:48 -04:00
return db_get_count ( " SELECT COUNT(*) FROM playlists p WHERE p . disabled = 0 ; " );
2009-06-07 12:56:35 -04:00
}
2009-06-11 12:28:01 -04:00
static int
2015-03-16 18:33:42 -04:00
db_pl_count_items ( int id , int streams_only )
2009-06-11 12:28:01 -04:00
{
2011-03-28 13:06:48 -04:00
# define Q_TMPL "SELECT COUNT(*) FROM playlistitems pi JOIN files f" \
" ON pi.filepath = f.path WHERE f.disabled = 0 AND pi.playlistid = %d; "
2015-03-16 18:33:42 -04:00
# define Q_TMPL_STREAMS "SELECT COUNT(*) FROM playlistitems pi JOIN files f" \
" ON pi.filepath = f.path WHERE f.disabled = 0 AND f.data_kind = 1 AND pi.playlistid = %d; "
2009-06-11 12:28:01 -04:00
char * query ;
int ret ;
2015-03-16 18:33:42 -04:00
if ( ! streams_only )
query = sqlite3_mprintf ( Q_TMPL , id ) ;
else
query = sqlite3_mprintf ( Q_TMPL_STREAMS , id ) ;
2009-06-11 12:28:01 -04:00
if ( ! query )
{
DPRINTF ( E_LOG , L_DB , " Out of memory for query string \n " ) ;
return 0 ;
}
ret = db_get_count ( query ) ;
sqlite3_free ( query ) ;
return ret ;
2015-03-16 18:33:42 -04:00
# undef Q_TMPL_STREAMS
2009-06-11 12:28:01 -04:00
# undef Q_TMPL
}
2010-01-21 11:52:51 -05:00
static int
db_smartpl_count_items ( const char * smartpl_query )
{
2011-03-28 13:06:48 -04:00
# define Q_TMPL "SELECT COUNT(*) FROM files f WHERE f.disabled = 0 AND %s;"
2010-01-21 11:52:51 -05:00
char * query ;
int ret ;
query = sqlite3_mprintf ( Q_TMPL , smartpl_query ) ;
if ( ! query )
{
DPRINTF ( E_LOG , L_DB , " Out of memory for query string \n " ) ;
return 0 ;
}
ret = db_get_count ( query ) ;
sqlite3_free ( query ) ;
return ret ;
# undef Q_TMPL
}
2009-06-07 12:56:35 -04:00
void
db_pl_ping ( int id )
{
2009-06-10 09:23:02 -04:00
# define Q_TMPL "UPDATE playlists SET db_timestamp = %" PRIi64 ", disabled = 0 WHERE id = %d;"
2009-06-07 12:56:35 -04:00
char * query ;
query = sqlite3_mprintf ( Q_TMPL , ( int64_t ) time ( NULL ) , id ) ;
2014-08-22 16:51:13 -04:00
db_query_run ( query , 1 , 0 ) ;
2009-06-07 12:56:35 -04:00
# undef Q_TMPL
}
2013-11-30 17:12:09 -05:00
void
2014-05-14 14:44:07 -04:00
db_pl_ping_bymatch ( char * path , int isdir )
2013-11-30 17:12:09 -05:00
{
2014-05-14 14:44:07 -04:00
# define Q_TMPL_DIR "UPDATE playlists SET db_timestamp = %" PRIi64 " WHERE path LIKE '%q / %%';"
# define Q_TMPL_NODIR "UPDATE playlists SET db_timestamp = %" PRIi64 " WHERE path LIKE '%q%%';"
2013-11-30 17:12:09 -05:00
char * query ;
2014-05-14 14:44:07 -04:00
if ( isdir )
query = sqlite3_mprintf ( Q_TMPL_DIR , ( int64_t ) time ( NULL ) , path ) ;
else
query = sqlite3_mprintf ( Q_TMPL_NODIR , ( int64_t ) time ( NULL ) , path ) ;
2014-08-22 16:51:13 -04:00
db_query_run ( query , 1 , 0 ) ;
2014-05-14 14:44:07 -04:00
# undef Q_TMPL_DIR
# undef Q_TMPL_NODIR
2013-11-30 17:12:09 -05:00
}
2009-06-10 15:36:43 -04:00
static int
db_pl_id_bypath ( char * path , int * id )
{
2011-03-28 13:06:48 -04:00
# define Q_TMPL "SELECT p.id FROM playlists p WHERE p.path = '%q';"
2009-06-10 15:36:43 -04:00
char * query ;
sqlite3_stmt * stmt ;
int ret ;
query = sqlite3_mprintf ( Q_TMPL , path ) ;
if ( ! query )
{
DPRINTF ( E_LOG , L_DB , " Out of memory for query string \n " ) ;
return - 1 ;
}
DPRINTF ( E_DBG , L_DB , " Running query '%s' \n " , query ) ;
2010-04-26 12:24:09 -04:00
ret = db_blocking_prepare_v2 ( query , - 1 , & stmt , NULL ) ;
2009-06-10 15:36:43 -04:00
if ( ret ! = SQLITE_OK )
{
DPRINTF ( E_LOG , L_DB , " Could not prepare statement: %s \n " , sqlite3_errmsg ( hdl ) ) ;
sqlite3_free ( query ) ;
return - 1 ;
}
2010-04-26 12:24:09 -04:00
ret = db_blocking_step ( stmt ) ;
2009-06-10 15:36:43 -04:00
if ( ret ! = SQLITE_ROW )
{
if ( ret = = SQLITE_DONE )
2014-06-01 17:58:44 -04:00
DPRINTF ( E_DBG , L_DB , " No results \n " ) ;
2009-06-10 15:36:43 -04:00
else
DPRINTF ( E_LOG , L_DB , " Could not step: %s \n " , sqlite3_errmsg ( hdl ) ) ;
sqlite3_finalize ( stmt ) ;
sqlite3_free ( query ) ;
return - 1 ;
}
* id = sqlite3_column_int ( stmt , 0 ) ;
2011-06-11 11:24:59 -04:00
# ifdef DB_PROFILE
while ( db_blocking_step ( stmt ) = = SQLITE_ROW )
; /* EMPTY */
# endif
2009-06-10 15:36:43 -04:00
sqlite3_finalize ( stmt ) ;
sqlite3_free ( query ) ;
return 0 ;
# undef Q_TMPL
}
2009-06-07 12:56:35 -04:00
static struct playlist_info *
db_pl_fetch_byquery ( char * query )
{
struct playlist_info * pli ;
sqlite3_stmt * stmt ;
int ncols ;
char * cval ;
uint32_t * ival ;
char * * strval ;
2009-06-10 09:23:02 -04:00
uint64_t disabled ;
2009-06-07 12:56:35 -04:00
int i ;
int ret ;
if ( ! query )
return NULL ;
DPRINTF ( E_DBG , L_DB , " Running query '%s' \n " , query ) ;
pli = ( struct playlist_info * ) malloc ( sizeof ( struct playlist_info ) ) ;
if ( ! pli )
{
DPRINTF ( E_LOG , L_DB , " Could not allocate struct playlist_info, out of memory \n " ) ;
return NULL ;
}
memset ( pli , 0 , sizeof ( struct playlist_info ) ) ;
2010-04-26 12:24:09 -04:00
ret = db_blocking_prepare_v2 ( query , - 1 , & stmt , NULL ) ;
2009-06-07 12:56:35 -04:00
if ( ret ! = SQLITE_OK )
{
DPRINTF ( E_LOG , L_DB , " Could not prepare statement: %s \n " , sqlite3_errmsg ( hdl ) ) ;
free ( pli ) ;
return NULL ;
}
2010-04-26 12:24:09 -04:00
ret = db_blocking_step ( stmt ) ;
2009-06-07 12:56:35 -04:00
if ( ret ! = SQLITE_ROW )
{
if ( ret = = SQLITE_DONE )
2014-06-01 17:58:44 -04:00
DPRINTF ( E_DBG , L_DB , " No results \n " ) ;
2009-06-07 12:56:35 -04:00
else
DPRINTF ( E_LOG , L_DB , " Could not step: %s \n " , sqlite3_errmsg ( hdl ) ) ;
sqlite3_finalize ( stmt ) ;
free ( pli ) ;
return NULL ;
}
ncols = sqlite3_column_count ( stmt ) ;
if ( sizeof ( pli_cols_map ) / sizeof ( pli_cols_map [ 0 ] ) ! = ncols )
{
DPRINTF ( E_LOG , L_DB , " BUG: pli column map out of sync with schema \n " ) ;
sqlite3_finalize ( stmt ) ;
free ( pli ) ;
return NULL ;
}
for ( i = 0 ; i < ncols ; i + + )
{
switch ( pli_cols_map [ i ] . type )
{
case DB_TYPE_INT :
ival = ( uint32_t * ) ( ( char * ) pli + pli_cols_map [ i ] . offset ) ;
2009-06-10 09:23:02 -04:00
if ( pli_cols_map [ i ] . offset = = pli_offsetof ( disabled ) )
{
disabled = sqlite3_column_int64 ( stmt , i ) ;
* ival = ( disabled ! = 0 ) ;
}
else
* ival = sqlite3_column_int ( stmt , i ) ;
2009-06-07 12:56:35 -04:00
break ;
case DB_TYPE_STRING :
strval = ( char * * ) ( ( char * ) pli + pli_cols_map [ i ] . offset ) ;
cval = ( char * ) sqlite3_column_text ( stmt , i ) ;
if ( cval )
* strval = strdup ( cval ) ;
break ;
default :
DPRINTF ( E_LOG , L_DB , " BUG: Unknown type %d in pli column map \n " , pli_cols_map [ i ] . type ) ;
sqlite3_finalize ( stmt ) ;
free_pli ( pli , 0 ) ;
return NULL ;
}
}
2010-04-26 12:24:09 -04:00
ret = db_blocking_step ( stmt ) ;
2009-06-07 12:56:35 -04:00
sqlite3_finalize ( stmt ) ;
2009-11-22 06:30:29 -05:00
if ( ret ! = SQLITE_DONE )
{
DPRINTF ( E_WARN , L_DB , " Query had more than a single result! \n " ) ;
free_pli ( pli , 0 ) ;
return NULL ;
}
2010-01-21 11:52:51 -05:00
switch ( pli - > type )
{
case PL_PLAIN :
2015-03-29 19:03:15 -04:00
case PL_FOLDER :
2015-03-16 18:33:42 -04:00
pli - > items = db_pl_count_items ( pli - > id , 0 ) ;
pli - > streams = db_pl_count_items ( pli - > id , 1 ) ;
2010-01-21 11:52:51 -05:00
break ;
2015-04-11 10:55:13 -04:00
case PL_SPECIAL :
2010-01-21 11:52:51 -05:00
case PL_SMART :
pli - > items = db_smartpl_count_items ( pli - > query ) ;
break ;
default :
DPRINTF ( E_LOG , L_DB , " Unknown playlist type %d while fetching playlist \n " , pli - > type ) ;
free_pli ( pli , 0 ) ;
return NULL ;
}
2009-06-07 12:56:35 -04:00
return pli ;
}
struct playlist_info *
db_pl_fetch_bypath ( char * path )
{
2011-03-28 13:06:48 -04:00
# define Q_TMPL "SELECT p.* FROM playlists p WHERE p.path = '%q';"
2009-06-07 12:56:35 -04:00
struct playlist_info * pli ;
char * query ;
query = sqlite3_mprintf ( Q_TMPL , path ) ;
2009-11-22 06:34:37 -05:00
if ( ! query )
{
DPRINTF ( E_LOG , L_DB , " Out of memory for query string \n " ) ;
return NULL ;
}
pli = db_pl_fetch_byquery ( query ) ;
sqlite3_free ( query ) ;
return pli ;
# undef Q_TMPL
}
2014-12-21 14:41:44 -05:00
struct playlist_info *
db_pl_fetch_byvirtualpath ( char * virtual_path )
{
# define Q_TMPL "SELECT p.* FROM playlists p WHERE p.virtual_path = '%q';"
struct playlist_info * pli ;
char * query ;
query = sqlite3_mprintf ( Q_TMPL , virtual_path ) ;
if ( ! query )
{
DPRINTF ( E_LOG , L_DB , " Out of memory for query string \n " ) ;
return NULL ;
}
pli = db_pl_fetch_byquery ( query ) ;
sqlite3_free ( query ) ;
return pli ;
# undef Q_TMPL
}
2010-01-21 11:52:51 -05:00
struct playlist_info *
db_pl_fetch_byid ( int id )
{
2011-03-28 13:06:48 -04:00
# define Q_TMPL "SELECT p.* FROM playlists p WHERE p.id = %d;"
2010-01-21 11:52:51 -05:00
struct playlist_info * pli ;
char * query ;
query = sqlite3_mprintf ( Q_TMPL , id ) ;
if ( ! query )
{
DPRINTF ( E_LOG , L_DB , " Out of memory for query string \n " ) ;
return NULL ;
}
pli = db_pl_fetch_byquery ( query ) ;
sqlite3_free ( query ) ;
return pli ;
# undef Q_TMPL
}
2009-11-22 06:34:37 -05:00
struct playlist_info *
db_pl_fetch_bytitlepath ( char * title , char * path )
{
2011-03-28 13:06:48 -04:00
# define Q_TMPL "SELECT p.* FROM playlists p WHERE p.title = '%q' AND p.path = '%q';"
2009-11-22 06:34:37 -05:00
struct playlist_info * pli ;
char * query ;
query = sqlite3_mprintf ( Q_TMPL , title , path ) ;
2009-06-07 12:56:35 -04:00
if ( ! query )
{
DPRINTF ( E_LOG , L_DB , " Out of memory for query string \n " ) ;
return NULL ;
}
pli = db_pl_fetch_byquery ( query ) ;
sqlite3_free ( query ) ;
return pli ;
# undef Q_TMPL
}
int
2015-03-14 17:34:03 -04:00
db_pl_add ( struct playlist_info * pli , int * id )
2009-06-07 12:56:35 -04:00
{
2015-03-14 17:34:03 -04:00
# define QDUP_TMPL "SELECT COUNT(*) FROM playlists p WHERE p.title = TRIM(%Q) AND p.path = '%q';"
2015-12-27 01:16:50 -05:00
# define QADD_TMPL "INSERT INTO playlists (title, type, query, db_timestamp, disabled, path, idx, special_id, parent_id, virtual_path, directory_id)" \
" VALUES (TRIM(%Q), %d, '%q', % " PRIi64 " , %d, '%q', %d, %d, %d, '%q', %d); "
2009-06-07 12:56:35 -04:00
char * query ;
char * errmsg ;
int ret ;
/* Check duplicates */
2015-03-14 17:34:03 -04:00
query = sqlite3_mprintf ( QDUP_TMPL , pli - > title , STR ( pli - > path ) ) ;
2009-06-07 12:56:35 -04:00
if ( ! query )
{
DPRINTF ( E_LOG , L_DB , " Out of memory for query string \n " ) ;
return - 1 ;
}
2009-06-11 12:41:50 -04:00
ret = db_get_count ( query ) ;
2009-06-07 12:56:35 -04:00
sqlite3_free ( query ) ;
if ( ret > 0 )
{
2015-03-14 17:34:03 -04:00
DPRINTF ( E_WARN , L_DB , " Duplicate playlist with title '%s' path '%s' \n " , pli - > title , pli - > path ) ;
2009-06-07 12:56:35 -04:00
return - 1 ;
}
/* Add */
2015-03-14 17:34:03 -04:00
query = sqlite3_mprintf ( QADD_TMPL ,
2015-04-12 00:49:38 -04:00
pli - > title , pli - > type , pli - > query , ( int64_t ) time ( NULL ) , pli - > disabled , STR ( pli - > path ) ,
2015-12-27 01:16:50 -05:00
pli - > index , pli - > special_id , pli - > parent_id , pli - > virtual_path , pli - > directory_id ) ;
2015-03-14 17:34:03 -04:00
2009-06-07 12:56:35 -04:00
if ( ! query )
{
DPRINTF ( E_LOG , L_DB , " Out of memory for query string \n " ) ;
return - 1 ;
}
DPRINTF ( E_DBG , L_DB , " Running query '%s' \n " , query ) ;
2010-04-26 12:24:09 -04:00
ret = db_exec ( query , & errmsg ) ;
2009-06-07 12:56:35 -04:00
if ( ret ! = SQLITE_OK )
{
DPRINTF ( E_LOG , L_DB , " Query error: %s \n " , errmsg ) ;
sqlite3_free ( errmsg ) ;
sqlite3_free ( query ) ;
return - 1 ;
}
sqlite3_free ( query ) ;
* id = ( int ) sqlite3_last_insert_rowid ( hdl ) ;
if ( * id = = 0 )
{
DPRINTF ( E_LOG , L_DB , " Successful insert but no last_insert_rowid! \n " ) ;
return - 1 ;
}
2015-03-14 17:34:03 -04:00
DPRINTF ( E_DBG , L_DB , " Added playlist %s (path %s) with id %d \n " , pli - > title , pli - > path , * id ) ;
2009-06-07 12:56:35 -04:00
return 0 ;
# undef QDUP_TMPL
# undef QADD_TMPL
}
int
2009-11-22 06:21:21 -05:00
db_pl_add_item_bypath ( int plid , char * path )
2009-06-07 12:56:35 -04:00
{
2009-06-11 14:27:31 -04:00
# define Q_TMPL "INSERT INTO playlistitems (playlistid, filepath) VALUES (%d, '%q');"
2009-06-07 12:56:35 -04:00
char * query ;
2009-06-11 14:27:31 -04:00
query = sqlite3_mprintf ( Q_TMPL , plid , path ) ;
2009-11-22 06:17:28 -05:00
2014-08-22 16:51:13 -04:00
return db_query_run ( query , 1 , 0 ) ;
2009-11-22 06:17:28 -05:00
# undef Q_TMPL
}
int
db_pl_add_item_byid ( int plid , int fileid )
{
2011-03-28 13:06:48 -04:00
# define Q_TMPL "INSERT INTO playlistitems (playlistid, filepath) VALUES (%d, (SELECT f.path FROM files f WHERE f.id = %d));"
2009-11-22 06:17:28 -05:00
char * query ;
query = sqlite3_mprintf ( Q_TMPL , plid , fileid ) ;
2009-06-07 12:56:35 -04:00
2014-08-22 16:51:13 -04:00
return db_query_run ( query , 1 , 0 ) ;
2009-06-11 14:27:31 -04:00
# undef Q_TMPL
2009-06-07 12:56:35 -04:00
}
2014-03-11 18:20:29 -04:00
int
2015-03-14 17:34:03 -04:00
db_pl_update ( struct playlist_info * pli )
2014-03-11 18:20:29 -04:00
{
2015-04-12 00:49:38 -04:00
# define Q_TMPL "UPDATE playlists SET title = TRIM(%Q), type = %d, query = '%q', db_timestamp = %" PRIi64 ", disabled = %d, " \
2015-12-27 01:16:50 -05:00
" path = '%q', idx = %d, special_id = %d, parent_id = %d, virtual_path = '%q', directory_id = %d " \
2015-03-14 17:34:03 -04:00
" WHERE id = %d; "
2014-03-11 18:20:29 -04:00
char * query ;
2014-12-21 14:41:44 -05:00
int ret ;
2014-03-11 18:20:29 -04:00
2015-03-14 17:34:03 -04:00
query = sqlite3_mprintf ( Q_TMPL ,
2015-04-12 00:49:38 -04:00
pli - > title , pli - > type , pli - > query , ( int64_t ) time ( NULL ) , pli - > disabled , STR ( pli - > path ) ,
2015-12-27 01:16:50 -05:00
pli - > index , pli - > special_id , pli - > parent_id , pli - > virtual_path , pli - > directory_id , pli - > id ) ;
2014-03-11 18:20:29 -04:00
2014-12-21 14:41:44 -05:00
ret = db_query_run ( query , 1 , 0 ) ;
return ret ;
2014-03-11 18:20:29 -04:00
# undef Q_TMPL
}
2009-06-11 13:04:21 -04:00
void
2009-06-10 15:36:43 -04:00
db_pl_clear_items ( int id )
{
# define Q_TMPL "DELETE FROM playlistitems WHERE playlistid = %d;"
char * query ;
query = sqlite3_mprintf ( Q_TMPL , id ) ;
2014-08-22 16:51:13 -04:00
db_query_run ( query , 1 , 0 ) ;
2014-08-17 18:20:23 -04:00
# undef Q_TMPL
}
2009-06-10 15:36:43 -04:00
2009-06-07 12:56:35 -04:00
void
db_pl_delete ( int id )
{
2009-06-10 15:36:43 -04:00
# define Q_TMPL "DELETE FROM playlists WHERE id = %d;"
char * query ;
2009-06-07 12:56:35 -04:00
int ret ;
if ( id = = 1 )
return ;
2009-06-10 15:36:43 -04:00
query = sqlite3_mprintf ( Q_TMPL , id ) ;
2014-08-22 16:51:13 -04:00
ret = db_query_run ( query , 1 , 0 ) ;
2009-06-10 15:36:43 -04:00
2014-08-17 18:20:23 -04:00
if ( ret = = 0 )
db_pl_clear_items ( id ) ;
2009-06-10 15:36:43 -04:00
# undef Q_TMPL
}
void
db_pl_delete_bypath ( char * path )
{
int id ;
int ret ;
ret = db_pl_id_bypath ( path , & id ) ;
if ( ret < 0 )
return ;
2009-06-07 12:56:35 -04:00
2009-06-10 15:36:43 -04:00
db_pl_delete ( id ) ;
2009-06-07 12:56:35 -04:00
}
2009-06-10 16:11:24 -04:00
void
db_pl_disable_bypath ( char * path , char * strip , uint32_t cookie )
{
2015-12-27 01:16:50 -05:00
# define Q_TMPL "UPDATE playlists SET path = substr(path, %d), virtual_path = substr(virtual_path, %d), disabled = %" PRIi64 " WHERE path = '%q';"
2009-06-10 16:11:24 -04:00
char * query ;
int64_t disabled ;
int striplen ;
2015-12-27 01:16:50 -05:00
int striplenvpath ;
2009-06-10 16:11:24 -04:00
disabled = ( cookie ! = 0 ) ? cookie : INOTIFY_FAKE_COOKIE ;
striplen = strlen ( strip ) + 1 ;
2015-12-27 01:16:50 -05:00
if ( strlen ( strip ) > 0 )
striplenvpath = strlen ( strip ) + strlen ( " /file:/ " ) ;
else
striplenvpath = 0 ;
2009-06-10 16:11:24 -04:00
2015-12-27 01:16:50 -05:00
query = sqlite3_mprintf ( Q_TMPL , striplen , striplenvpath , disabled , path ) ;
2009-06-11 08:42:55 -04:00
2014-08-22 16:51:13 -04:00
db_query_run ( query , 1 , 0 ) ;
2009-06-11 08:42:55 -04:00
# undef Q_TMPL
}
void
db_pl_disable_bymatch ( char * path , char * strip , uint32_t cookie )
{
2015-12-27 01:16:50 -05:00
# define Q_TMPL "UPDATE playlists SET path = substr(path, %d), virtual_path = substr(virtual_path, %d), disabled = %" PRIi64 " WHERE path LIKE '%q / %%';"
2009-06-11 08:42:55 -04:00
char * query ;
int64_t disabled ;
int striplen ;
2015-12-27 01:16:50 -05:00
int striplenvpath ;
2009-06-11 08:42:55 -04:00
disabled = ( cookie ! = 0 ) ? cookie : INOTIFY_FAKE_COOKIE ;
striplen = strlen ( strip ) + 1 ;
2015-12-27 01:16:50 -05:00
if ( strlen ( strip ) > 0 )
striplenvpath = strlen ( strip ) + strlen ( " /file:/ " ) ;
else
striplenvpath = 0 ;
2009-06-11 08:42:55 -04:00
2015-12-27 01:16:50 -05:00
query = sqlite3_mprintf ( Q_TMPL , striplen , striplenvpath , disabled , path ) ;
2009-06-10 16:11:24 -04:00
2014-08-22 16:51:13 -04:00
db_query_run ( query , 1 , 0 ) ;
2009-06-10 16:11:24 -04:00
# undef Q_TMPL
}
int
db_pl_enable_bycookie ( uint32_t cookie , char * path )
{
2015-12-27 01:16:50 -05:00
# define Q_TMPL "UPDATE playlists SET path = '%q' || path, virtual_path = ' / file:%q' || virtual_path, disabled = 0 WHERE disabled = %" PRIi64 ";"
2009-06-10 16:11:24 -04:00
char * query ;
int ret ;
2015-12-27 01:16:50 -05:00
query = sqlite3_mprintf ( Q_TMPL , path , path , ( int64_t ) cookie ) ;
2009-06-10 16:11:24 -04:00
2014-08-22 16:51:13 -04:00
ret = db_query_run ( query , 1 , 0 ) ;
2009-06-10 16:11:24 -04:00
2014-08-17 18:20:23 -04:00
return ( ( ret < 0 ) ? - 1 : sqlite3_changes ( hdl ) ) ;
2009-06-10 16:11:24 -04:00
# undef Q_TMPL
}
2009-06-07 12:56:35 -04:00
2014-12-21 14:41:44 -05:00
2010-03-06 12:56:30 -05:00
/* Groups */
2015-01-08 16:40:47 -05:00
int
db_groups_clear ( void )
{
return db_query_run ( " DELETE FROM groups; " , 0 , 1 ) ;
}
2010-03-06 12:56:30 -05:00
2014-11-10 16:53:08 -05:00
static enum group_type
db_group_type_bypersistentid ( int64_t persistentid )
2010-03-07 06:53:23 -05:00
{
2015-01-08 16:40:47 -05:00
# define Q_TMPL "SELECT g.type FROM groups g WHERE g.persistentid = %" PRIi64 ";"
2010-03-07 06:53:23 -05:00
char * query ;
sqlite3_stmt * stmt ;
int ret ;
2014-11-10 16:53:08 -05:00
query = sqlite3_mprintf ( Q_TMPL , persistentid ) ;
2010-03-07 06:53:23 -05:00
if ( ! query )
{
DPRINTF ( E_LOG , L_DB , " Out of memory for query string \n " ) ;
return 0 ;
}
DPRINTF ( E_DBG , L_DB , " Running query '%s' \n " , query ) ;
2010-04-26 12:24:09 -04:00
ret = db_blocking_prepare_v2 ( query , strlen ( query ) + 1 , & stmt , NULL ) ;
2010-03-07 06:53:23 -05:00
if ( ret ! = SQLITE_OK )
{
DPRINTF ( E_LOG , L_DB , " Could not prepare statement: %s \n " , sqlite3_errmsg ( hdl ) ) ;
sqlite3_free ( query ) ;
return 0 ;
}
2010-04-26 12:24:09 -04:00
ret = db_blocking_step ( stmt ) ;
2010-03-07 06:53:23 -05:00
if ( ret ! = SQLITE_ROW )
{
if ( ret = = SQLITE_DONE )
2014-06-01 17:58:44 -04:00
DPRINTF ( E_DBG , L_DB , " No results \n " ) ;
2010-03-07 06:53:23 -05:00
else
DPRINTF ( E_LOG , L_DB , " Could not step: %s \n " , sqlite3_errmsg ( hdl ) ) ;
sqlite3_finalize ( stmt ) ;
sqlite3_free ( query ) ;
return 0 ;
}
ret = sqlite3_column_int ( stmt , 0 ) ;
2011-06-11 11:24:59 -04:00
# ifdef DB_PROFILE
while ( db_blocking_step ( stmt ) = = SQLITE_ROW )
; /* EMPTY */
# endif
2010-03-07 06:53:23 -05:00
sqlite3_finalize ( stmt ) ;
sqlite3_free ( query ) ;
return ret ;
# undef Q_TMPL
}
2010-03-06 12:56:30 -05:00
2015-01-08 16:40:47 -05:00
int
db_group_persistentid_byid ( int id , int64_t * persistentid )
{
# define Q_TMPL "SELECT g.persistentid FROM groups g WHERE g.id = %d;"
char * query ;
sqlite3_stmt * stmt ;
int ret ;
query = sqlite3_mprintf ( Q_TMPL , id ) ;
if ( ! query )
{
DPRINTF ( E_LOG , L_DB , " Out of memory for query string \n " ) ;
return - 1 ;
}
DPRINTF ( E_DBG , L_DB , " Running query '%s' \n " , query ) ;
ret = db_blocking_prepare_v2 ( query , - 1 , & stmt , NULL ) ;
if ( ret ! = SQLITE_OK )
{
DPRINTF ( E_LOG , L_DB , " Could not prepare statement: %s \n " , sqlite3_errmsg ( hdl ) ) ;
sqlite3_free ( query ) ;
return - 1 ;
}
ret = db_blocking_step ( stmt ) ;
if ( ret ! = SQLITE_ROW )
{
if ( ret = = SQLITE_DONE )
DPRINTF ( E_DBG , L_DB , " No results \n " ) ;
else
DPRINTF ( E_LOG , L_DB , " Could not step: %s \n " , sqlite3_errmsg ( hdl ) ) ;
sqlite3_finalize ( stmt ) ;
sqlite3_free ( query ) ;
return - 1 ;
}
* persistentid = sqlite3_column_int64 ( stmt , 0 ) ;
# ifdef DB_PROFILE
while ( db_blocking_step ( stmt ) = = SQLITE_ROW )
; /* EMPTY */
# endif
sqlite3_finalize ( stmt ) ;
sqlite3_free ( query ) ;
return 0 ;
# undef Q_TMPL
}
2014-11-10 16:53:08 -05:00
2015-12-27 01:16:50 -05:00
/* Directories */
int
db_directory_id_byvirtualpath ( char * virtual_path )
{
# define Q_TMPL "SELECT d.id FROM directories d WHERE d.virtual_path = '%q';"
char * query ;
int ret ;
query = sqlite3_mprintf ( Q_TMPL , virtual_path ) ;
if ( ! query )
{
DPRINTF ( E_LOG , L_DB , " Out of memory for query string \n " ) ;
return 0 ;
}
ret = db_file_id_byquery ( query ) ;
sqlite3_free ( query ) ;
return ret ;
# undef Q_TMPL
}
int
db_directory_enum_start ( struct directory_enum * de )
{
# define Q_TMPL "SELECT * FROM directories WHERE disabled = 0 AND parent_id = %d ORDER BY virtual_path;"
char * query ;
int ret ;
de - > stmt = NULL ;
query = sqlite3_mprintf ( Q_TMPL , de - > parent_id ) ;
if ( ! query )
{
DPRINTF ( E_LOG , L_DB , " Out of memory for query string \n " ) ;
return - 1 ;
}
DPRINTF ( E_DBG , L_DB , " Starting enum '%s' \n " , query ) ;
ret = db_blocking_prepare_v2 ( query , - 1 , & de - > stmt , NULL ) ;
if ( ret ! = SQLITE_OK )
{
DPRINTF ( E_LOG , L_DB , " Could not prepare statement: %s \n " , sqlite3_errmsg ( hdl ) ) ;
sqlite3_free ( query ) ;
return - 1 ;
}
sqlite3_free ( query ) ;
return 0 ;
# undef Q_TMPL
}
int
db_directory_enum_fetch ( struct directory_enum * de , struct directory_info * di )
{
uint64_t disabled ;
int ret ;
memset ( di , 0 , sizeof ( struct directory_info ) ) ;
if ( ! de - > stmt )
{
DPRINTF ( E_LOG , L_DB , " Directory enum not started! \n " ) ;
return - 1 ;
}
ret = db_blocking_step ( de - > stmt ) ;
if ( ret = = SQLITE_DONE )
{
DPRINTF ( E_DBG , L_DB , " End of directory enum results \n " ) ;
return 0 ;
}
else if ( ret ! = SQLITE_ROW )
{
DPRINTF ( E_LOG , L_DB , " Could not step: %s \n " , sqlite3_errmsg ( hdl ) ) ;
return - 1 ;
}
di - > id = sqlite3_column_int ( de - > stmt , 0 ) ;
di - > virtual_path = ( char * ) sqlite3_column_text ( de - > stmt , 1 ) ;
di - > db_timestamp = sqlite3_column_int ( de - > stmt , 2 ) ;
disabled = sqlite3_column_int64 ( de - > stmt , 3 ) ;
di - > disabled = ( disabled ! = 0 ) ;
di - > parent_id = sqlite3_column_int ( de - > stmt , 4 ) ;
return 0 ;
}
void
db_directory_enum_end ( struct directory_enum * de )
{
if ( ! de - > stmt )
return ;
sqlite3_finalize ( de - > stmt ) ;
de - > stmt = NULL ;
}
static int
db_directory_add ( struct directory_info * di , int * id )
{
# define QADD_TMPL "INSERT INTO directories (virtual_path, db_timestamp, disabled, parent_id)" \
" VALUES (TRIM(%Q), %d, %d, %d); "
char * query ;
char * errmsg ;
int ret ;
query = sqlite3_mprintf ( QADD_TMPL , di - > virtual_path , di - > db_timestamp , di - > disabled , di - > parent_id ) ;
if ( ! query )
{
DPRINTF ( E_LOG , L_DB , " Out of memory for query string \n " ) ;
return - 1 ;
}
DPRINTF ( E_DBG , L_DB , " Running query '%s' \n " , query ) ;
ret = db_exec ( query , & errmsg ) ;
if ( ret ! = SQLITE_OK )
{
DPRINTF ( E_LOG , L_DB , " Query error: %s \n " , errmsg ) ;
sqlite3_free ( errmsg ) ;
sqlite3_free ( query ) ;
return - 1 ;
}
sqlite3_free ( query ) ;
* id = ( int ) sqlite3_last_insert_rowid ( hdl ) ;
if ( * id = = 0 )
{
DPRINTF ( E_LOG , L_DB , " Successful insert but no last_insert_rowid! \n " ) ;
return - 1 ;
}
DPRINTF ( E_DBG , L_DB , " Added directory %s with id %d \n " , di - > virtual_path , * id ) ;
return 0 ;
# undef QADD_TMPL
}
static int
db_directory_update ( struct directory_info * di )
{
# define QADD_TMPL "UPDATE directories SET virtual_path = TRIM(%Q), db_timestamp = %d, disabled = %d, parent_id = %d" \
" WHERE id = %d; "
char * query ;
char * errmsg ;
int ret ;
/* Add */
query = sqlite3_mprintf ( QADD_TMPL , di - > virtual_path , di - > db_timestamp , di - > disabled , di - > parent_id , di - > id ) ;
if ( ! query )
{
DPRINTF ( E_LOG , L_DB , " Out of memory for query string \n " ) ;
return - 1 ;
}
DPRINTF ( E_DBG , L_DB , " Running query '%s' \n " , query ) ;
ret = db_exec ( query , & errmsg ) ;
if ( ret ! = SQLITE_OK )
{
DPRINTF ( E_LOG , L_DB , " Query error: %s \n " , errmsg ) ;
sqlite3_free ( errmsg ) ;
sqlite3_free ( query ) ;
return - 1 ;
}
sqlite3_free ( query ) ;
DPRINTF ( E_DBG , L_DB , " Updated directory %s with id %d \n " , di - > virtual_path , di - > id ) ;
return 0 ;
# undef QADD_TMPL
}
int
db_directory_addorupdate ( char * virtual_path , int disabled , int parent_id )
{
struct directory_info di ;
int id ;
int ret ;
id = db_directory_id_byvirtualpath ( virtual_path ) ;
di . id = id ;
di . parent_id = parent_id ;
di . virtual_path = virtual_path ;
di . disabled = disabled ;
di . db_timestamp = ( uint64_t ) time ( NULL ) ;
if ( di . id = = 0 )
ret = db_directory_add ( & di , & id ) ;
else
ret = db_directory_update ( & di ) ;
if ( ret < 0 | | id < = 0 )
{
DPRINTF ( E_LOG , L_DB , " Insert or update of directory failed '%s' \n " , virtual_path ) ;
return - 1 ;
}
return id ;
}
void
db_directory_ping_bymatch ( char * path )
{
# define Q_TMPL_DIR "UPDATE directories SET db_timestamp = %" PRIi64 " WHERE virtual_path = ' / file:%q' OR virtual_path LIKE ' / file:%q / %%';"
char * query ;
query = sqlite3_mprintf ( Q_TMPL_DIR , ( int64_t ) time ( NULL ) , path , path ) ;
db_query_run ( query , 1 , 1 ) ;
# undef Q_TMPL_DIR
}
void
db_directory_disable_bymatch ( char * path , char * strip , uint32_t cookie )
{
# define Q_TMPL "UPDATE directories SET virtual_path = substr(virtual_path, %d), disabled = %" PRIi64 " WHERE virtual_path = ' / file:%q' OR virtual_path LIKE ' / file:%q / %%';"
char * query ;
int64_t disabled ;
int striplen ;
disabled = ( cookie ! = 0 ) ? cookie : INOTIFY_FAKE_COOKIE ;
if ( strlen ( strip ) > 0 )
striplen = strlen ( strip ) + strlen ( " /file:/ " ) ;
else
striplen = 0 ;
query = sqlite3_mprintf ( Q_TMPL , striplen , disabled , path , path , path ) ;
db_query_run ( query , 1 , 1 ) ;
# undef Q_TMPL
}
int
db_directory_enable_bycookie ( uint32_t cookie , char * path )
{
# define Q_TMPL "UPDATE directories SET virtual_path = ' / file:%q' || virtual_path, disabled = 0 WHERE disabled = %" PRIi64 ";"
char * query ;
int ret ;
query = sqlite3_mprintf ( Q_TMPL , path , ( int64_t ) cookie ) ;
ret = db_query_run ( query , 1 , 0 ) ;
return ( ( ret < 0 ) ? - 1 : sqlite3_changes ( hdl ) ) ;
# undef Q_TMPL
}
2016-01-30 01:27:20 -05:00
int
db_directory_enable_bypath ( char * path )
{
# define Q_TMPL "UPDATE directories SET disabled = 0 WHERE virtual_path = %Q;"
char * query ;
int ret ;
query = sqlite3_mprintf ( Q_TMPL , path ) ;
ret = db_query_run ( query , 1 , 0 ) ;
return ( ( ret < 0 ) ? - 1 : sqlite3_changes ( hdl ) ) ;
# undef Q_TMPL
}
2015-12-27 01:16:50 -05:00
2010-01-30 11:01:27 -05:00
/* Remotes */
static int
db_pairing_delete_byremote ( char * remote_id )
{
# define Q_TMPL "DELETE FROM pairings WHERE remote = '%q';"
char * query ;
query = sqlite3_mprintf ( Q_TMPL , remote_id ) ;
2014-08-22 16:51:13 -04:00
return db_query_run ( query , 1 , 0 ) ;
2010-01-30 11:01:27 -05:00
# undef Q_TMPL
}
int
db_pairing_add ( struct pairing_info * pi )
{
# define Q_TMPL "INSERT INTO pairings (remote, name, guid) VALUES ('%q', '%q', '%q');"
char * query ;
int ret ;
ret = db_pairing_delete_byremote ( pi - > remote_id ) ;
if ( ret < 0 )
return ret ;
query = sqlite3_mprintf ( Q_TMPL , pi - > remote_id , pi - > name , pi - > guid ) ;
2014-08-22 16:51:13 -04:00
return db_query_run ( query , 1 , 0 ) ;
2010-01-30 11:01:27 -05:00
# undef Q_TMPL
}
int
db_pairing_fetch_byguid ( struct pairing_info * pi )
{
2011-03-28 13:06:48 -04:00
# define Q_TMPL "SELECT p.* FROM pairings p WHERE p.guid = '%q';"
2010-01-30 11:01:27 -05:00
char * query ;
sqlite3_stmt * stmt ;
int ret ;
query = sqlite3_mprintf ( Q_TMPL , pi - > guid ) ;
if ( ! query )
{
DPRINTF ( E_LOG , L_DB , " Out of memory for query string \n " ) ;
return - 1 ;
}
DPRINTF ( E_DBG , L_DB , " Running query '%s' \n " , query ) ;
2010-04-26 12:24:09 -04:00
ret = db_blocking_prepare_v2 ( query , - 1 , & stmt , NULL ) ;
2010-01-30 11:01:27 -05:00
if ( ret ! = SQLITE_OK )
{
DPRINTF ( E_LOG , L_DB , " Could not prepare statement: %s \n " , sqlite3_errmsg ( hdl ) ) ;
return - 1 ;
}
2010-04-26 12:24:09 -04:00
ret = db_blocking_step ( stmt ) ;
2010-01-30 11:01:27 -05:00
if ( ret ! = SQLITE_ROW )
{
if ( ret = = SQLITE_DONE )
DPRINTF ( E_INFO , L_DB , " Pairing GUID %s not found \n " , pi - > guid ) ;
else
DPRINTF ( E_LOG , L_DB , " Could not step: %s \n " , sqlite3_errmsg ( hdl ) ) ;
sqlite3_finalize ( stmt ) ;
sqlite3_free ( query ) ;
return - 1 ;
}
pi - > remote_id = strdup ( ( char * ) sqlite3_column_text ( stmt , 0 ) ) ;
pi - > name = strdup ( ( char * ) sqlite3_column_text ( stmt , 1 ) ) ;
2011-06-11 11:24:59 -04:00
# ifdef DB_PROFILE
while ( db_blocking_step ( stmt ) = = SQLITE_ROW )
; /* EMPTY */
# endif
2010-01-30 11:01:27 -05:00
sqlite3_finalize ( stmt ) ;
sqlite3_free ( query ) ;
return 0 ;
# undef Q_TMPL
}
2014-03-11 18:20:29 -04:00
# ifdef HAVE_SPOTIFY_H
/* Spotify */
void
db_spotify_purge ( void )
{
2016-01-30 01:27:20 -05:00
char * queries [ 5 ] =
2014-03-11 18:20:29 -04:00
{
" DELETE FROM files WHERE path LIKE 'spotify:%%'; " ,
" DELETE FROM playlistitems WHERE filepath LIKE 'spotify:%%'; " ,
" DELETE FROM playlists WHERE path LIKE 'spotify:%%'; " ,
2016-01-30 01:27:20 -05:00
" DELETE FROM directories WHERE virtual_path LIKE '/spotify:/%%'; " ,
" UPDATE directories SET disabled = 4294967296 WHERE virtual_path = '/spotify:'; " ,
2014-03-11 18:20:29 -04:00
} ;
int i ;
int ret ;
for ( i = 0 ; i < ( sizeof ( queries ) / sizeof ( queries [ 0 ] ) ) ; i + + )
{
2014-08-22 16:51:13 -04:00
ret = db_query_run ( queries [ i ] , 0 , 1 ) ;
2014-03-11 18:20:29 -04:00
2014-08-17 18:20:23 -04:00
if ( ret = = 0 )
2014-03-11 18:20:29 -04:00
DPRINTF ( E_DBG , L_DB , " Purged %d rows \n " , sqlite3_changes ( hdl ) ) ;
}
}
/* Spotify */
void
db_spotify_pl_delete ( int id )
{
2016-01-16 11:02:03 -05:00
char * queries_tmpl [ 2 ] =
2014-03-11 18:20:29 -04:00
{
" DELETE FROM playlists WHERE id = %d; " ,
" DELETE FROM playlistitems WHERE playlistid = %d; " ,
} ;
2014-08-17 18:20:23 -04:00
char * query ;
2014-03-11 18:20:29 -04:00
int i ;
int ret ;
for ( i = 0 ; i < ( sizeof ( queries_tmpl ) / sizeof ( queries_tmpl [ 0 ] ) ) ; i + + )
{
2014-08-17 18:20:23 -04:00
query = sqlite3_mprintf ( queries_tmpl [ i ] , id ) ;
2014-03-11 18:20:29 -04:00
2014-08-22 16:51:13 -04:00
ret = db_query_run ( query , 1 , 1 ) ;
2014-03-11 18:20:29 -04:00
2014-08-17 18:20:23 -04:00
if ( ret = = 0 )
2014-03-11 18:20:29 -04:00
DPRINTF ( E_DBG , L_DB , " Deleted %d rows \n " , sqlite3_changes ( hdl ) ) ;
}
}
2016-01-16 11:02:03 -05:00
/* Spotify */
void
db_spotify_files_delete ( )
{
# define Q_TMPL "DELETE FROM files WHERE path LIKE 'spotify:%%' AND NOT path IN (SELECT filepath FROM playlistitems);"
char * query ;
int ret ;
query = sqlite3_mprintf ( Q_TMPL ) ;
ret = db_query_run ( query , 1 , 1 ) ;
if ( ret = = 0 )
DPRINTF ( E_DBG , L_DB , " Deleted %d rows \n " , sqlite3_changes ( hdl ) ) ;
# undef Q_TMPL
}
2014-03-11 18:20:29 -04:00
# endif
2014-08-15 16:54:47 -04:00
/* Admin */
int
db_admin_add ( const char * key , const char * value )
{
2014-08-27 16:12:42 -04:00
# define Q_TMPL "INSERT OR REPLACE INTO admin (key, value) VALUES ('%q', '%q');"
2014-08-15 16:54:47 -04:00
char * query ;
query = sqlite3_mprintf ( Q_TMPL , key , value ) ;
2014-08-22 16:51:13 -04:00
return db_query_run ( query , 1 , 0 ) ;
2014-08-15 16:54:47 -04:00
# undef Q_TMPL
}
char *
db_admin_get ( const char * key )
{
# define Q_TMPL "SELECT value FROM admin a WHERE a.key = '%q';"
char * query ;
sqlite3_stmt * stmt ;
char * res ;
int ret ;
query = sqlite3_mprintf ( Q_TMPL , key ) ;
if ( ! query )
{
DPRINTF ( E_LOG , L_DB , " Out of memory for query string \n " ) ;
return NULL ;
}
DPRINTF ( E_DBG , L_DB , " Running query '%s' \n " , query ) ;
ret = db_blocking_prepare_v2 ( query , strlen ( query ) + 1 , & stmt , NULL ) ;
if ( ret ! = SQLITE_OK )
{
2015-01-14 14:32:36 -05:00
DPRINTF ( E_WARN , L_DB , " Could not prepare statement: %s \n " , sqlite3_errmsg ( hdl ) ) ;
2014-08-15 16:54:47 -04:00
sqlite3_free ( query ) ;
return NULL ;
}
ret = db_blocking_step ( stmt ) ;
if ( ret ! = SQLITE_ROW )
{
if ( ret = = SQLITE_DONE )
DPRINTF ( E_DBG , L_DB , " No results \n " ) ;
else
2015-01-14 14:32:36 -05:00
DPRINTF ( E_WARN , L_DB , " Could not step: %s \n " , sqlite3_errmsg ( hdl ) ) ;
2014-08-15 16:54:47 -04:00
sqlite3_finalize ( stmt ) ;
sqlite3_free ( query ) ;
return NULL ;
}
res = ( char * ) sqlite3_column_text ( stmt , 0 ) ;
if ( res )
res = strdup ( res ) ;
# ifdef DB_PROFILE
while ( db_blocking_step ( stmt ) = = SQLITE_ROW )
; /* EMPTY */
# endif
sqlite3_finalize ( stmt ) ;
sqlite3_free ( query ) ;
return res ;
# undef Q_TMPL
}
int
db_admin_update ( const char * key , const char * value )
{
# define Q_TMPL "UPDATE admin SET value='%q' WHERE key='%q';"
char * query ;
2015-06-04 16:10:30 -04:00
query = sqlite3_mprintf ( Q_TMPL , value , key ) ;
2014-08-15 16:54:47 -04:00
2014-08-22 16:51:13 -04:00
return db_query_run ( query , 1 , 0 ) ;
2014-08-15 16:54:47 -04:00
# undef Q_TMPL
}
int
db_admin_delete ( const char * key )
{
# define Q_TMPL "DELETE FROM admin where key='%q';"
char * query ;
query = sqlite3_mprintf ( Q_TMPL , key ) ;
2014-08-22 16:51:13 -04:00
return db_query_run ( query , 1 , 0 ) ;
2014-08-15 16:54:47 -04:00
# undef Q_TMPL
}
2010-01-30 11:01:27 -05:00
2010-11-02 13:40:14 -04:00
/* Speakers */
int
2016-02-08 16:17:10 -05:00
db_speaker_save ( uint64_t id , int selected , int volume , const char * name )
2010-11-02 13:40:14 -04:00
{
2016-02-08 16:17:10 -05:00
# define Q_TMPL "INSERT OR REPLACE INTO speakers (id, selected, volume, name) VALUES (%" PRIi64 ", %d, %d, '%q');"
2010-11-02 13:40:14 -04:00
char * query ;
2016-02-08 16:17:10 -05:00
query = sqlite3_mprintf ( Q_TMPL , id , selected , volume , name ) ;
2010-11-02 13:40:14 -04:00
2014-08-22 16:51:13 -04:00
return db_query_run ( query , 1 , 0 ) ;
2010-11-02 13:40:14 -04:00
# undef Q_TMPL
}
int
db_speaker_get ( uint64_t id , int * selected , int * volume )
{
2011-03-28 13:06:48 -04:00
# define Q_TMPL "SELECT s.selected, s.volume FROM speakers s WHERE s.id = %" PRIi64 ";"
2010-11-02 13:40:14 -04:00
sqlite3_stmt * stmt ;
char * query ;
int ret ;
query = sqlite3_mprintf ( Q_TMPL , id ) ;
if ( ! query )
{
DPRINTF ( E_LOG , L_DB , " Out of memory for query string \n " ) ;
return - 1 ;
}
DPRINTF ( E_DBG , L_DB , " Running query '%s' \n " , query ) ;
ret = db_blocking_prepare_v2 ( query , - 1 , & stmt , NULL ) ;
if ( ret ! = SQLITE_OK )
{
DPRINTF ( E_LOG , L_DB , " Could not prepare statement: %s \n " , sqlite3_errmsg ( hdl ) ) ;
ret = - 1 ;
goto out ;
}
ret = db_blocking_step ( stmt ) ;
if ( ret ! = SQLITE_ROW )
{
if ( ret ! = SQLITE_DONE )
DPRINTF ( E_LOG , L_DB , " Could not step: %s \n " , sqlite3_errmsg ( hdl ) ) ;
sqlite3_finalize ( stmt ) ;
ret = - 1 ;
goto out ;
}
* selected = sqlite3_column_int ( stmt , 0 ) ;
* volume = sqlite3_column_int ( stmt , 1 ) ;
2011-06-11 11:24:59 -04:00
# ifdef DB_PROFILE
while ( db_blocking_step ( stmt ) = = SQLITE_ROW )
; /* EMPTY */
# endif
2010-11-02 13:40:14 -04:00
sqlite3_finalize ( stmt ) ;
ret = 0 ;
out :
sqlite3_free ( query ) ;
return ret ;
# undef Q_TMPL
}
void
db_speaker_clear_all ( void )
{
2014-08-22 16:51:13 -04:00
db_query_run ( " UPDATE speakers SET selected = 0; " , 0 , 0 ) ;
2010-11-02 13:40:14 -04:00
}
2009-06-10 12:11:11 -04:00
/* Inotify */
int
db_watch_clear ( void )
{
2014-08-22 16:51:13 -04:00
return db_query_run ( " DELETE FROM inotify; " , 0 , 0 ) ;
2009-06-10 12:11:11 -04:00
}
int
db_watch_add ( struct watch_info * wi )
{
2010-03-19 14:06:47 -04:00
# define Q_TMPL "INSERT INTO inotify (wd, cookie, path) VALUES (%d, 0, '%q');"
2009-06-10 12:11:11 -04:00
char * query ;
2010-03-19 14:06:47 -04:00
query = sqlite3_mprintf ( Q_TMPL , wi - > wd , wi - > path ) ;
2009-06-10 12:11:11 -04:00
2014-08-22 16:51:13 -04:00
return db_query_run ( query , 1 , 0 ) ;
2009-06-10 12:11:11 -04:00
# undef Q_TMPL
}
int
2009-06-11 10:47:15 -04:00
db_watch_delete_bywd ( uint32_t wd )
2009-06-10 12:11:11 -04:00
{
# define Q_TMPL "DELETE FROM inotify WHERE wd = %d;"
char * query ;
2009-06-11 10:47:15 -04:00
query = sqlite3_mprintf ( Q_TMPL , wd ) ;
2009-06-11 10:12:17 -04:00
2014-08-22 16:51:13 -04:00
return db_query_run ( query , 1 , 0 ) ;
2009-06-11 10:12:17 -04:00
# undef Q_TMPL
}
int
db_watch_delete_bypath ( char * path )
{
# define Q_TMPL "DELETE FROM inotify WHERE path = '%q';"
char * query ;
query = sqlite3_mprintf ( Q_TMPL , path ) ;
2014-08-22 16:51:13 -04:00
return db_query_run ( query , 1 , 0 ) ;
2009-06-11 10:12:17 -04:00
# undef Q_TMPL
}
int
db_watch_delete_bymatch ( char * path )
{
# define Q_TMPL "DELETE FROM inotify WHERE path LIKE '%q / %%';"
char * query ;
query = sqlite3_mprintf ( Q_TMPL , path ) ;
2014-08-22 16:51:13 -04:00
return db_query_run ( query , 1 , 0 ) ;
2009-06-11 10:12:17 -04:00
# undef Q_TMPL
}
int
db_watch_delete_bycookie ( uint32_t cookie )
{
# define Q_TMPL "DELETE FROM inotify WHERE cookie = %" PRIi64 ";"
char * query ;
if ( cookie = = 0 )
return - 1 ;
query = sqlite3_mprintf ( Q_TMPL , ( int64_t ) cookie ) ;
2009-06-10 12:11:11 -04:00
2014-08-22 16:51:13 -04:00
return db_query_run ( query , 1 , 0 ) ;
2009-06-10 12:11:11 -04:00
# undef Q_TMPL
}
2014-06-09 17:42:02 -04:00
static int
db_watch_get_byquery ( struct watch_info * wi , char * query )
2009-06-10 12:11:11 -04:00
{
sqlite3_stmt * stmt ;
char * * strval ;
char * cval ;
uint32_t * ival ;
int64_t cookie ;
int ncols ;
int i ;
int ret ;
DPRINTF ( E_DBG , L_DB , " Running query '%s' \n " , query ) ;
2010-04-26 12:24:09 -04:00
ret = db_blocking_prepare_v2 ( query , - 1 , & stmt , NULL ) ;
2009-06-10 12:11:11 -04:00
if ( ret ! = SQLITE_OK )
{
DPRINTF ( E_LOG , L_DB , " Could not prepare statement: %s \n " , sqlite3_errmsg ( hdl ) ) ;
return - 1 ;
}
2010-04-26 12:24:09 -04:00
ret = db_blocking_step ( stmt ) ;
2009-06-10 12:11:11 -04:00
if ( ret ! = SQLITE_ROW )
{
2014-06-09 17:42:02 -04:00
DPRINTF ( E_WARN , L_DB , " Watch not found: '%s' \n " , query ) ;
2009-06-10 12:11:11 -04:00
sqlite3_finalize ( stmt ) ;
sqlite3_free ( query ) ;
return - 1 ;
}
ncols = sqlite3_column_count ( stmt ) ;
if ( sizeof ( wi_cols_map ) / sizeof ( wi_cols_map [ 0 ] ) ! = ncols )
{
DPRINTF ( E_LOG , L_DB , " BUG: wi column map out of sync with schema \n " ) ;
sqlite3_finalize ( stmt ) ;
sqlite3_free ( query ) ;
return - 1 ;
}
for ( i = 0 ; i < ncols ; i + + )
{
switch ( wi_cols_map [ i ] . type )
{
case DB_TYPE_INT :
ival = ( uint32_t * ) ( ( char * ) wi + wi_cols_map [ i ] . offset ) ;
if ( wi_cols_map [ i ] . offset = = wi_offsetof ( cookie ) )
{
cookie = sqlite3_column_int64 ( stmt , i ) ;
* ival = ( cookie = = INOTIFY_FAKE_COOKIE ) ? 0 : cookie ;
}
else
* ival = sqlite3_column_int ( stmt , i ) ;
break ;
case DB_TYPE_STRING :
strval = ( char * * ) ( ( char * ) wi + wi_cols_map [ i ] . offset ) ;
cval = ( char * ) sqlite3_column_text ( stmt , i ) ;
if ( cval )
* strval = strdup ( cval ) ;
break ;
default :
DPRINTF ( E_LOG , L_DB , " BUG: Unknown type %d in wi column map \n " , wi_cols_map [ i ] . type ) ;
sqlite3_finalize ( stmt ) ;
sqlite3_free ( query ) ;
return - 1 ;
}
}
2011-06-11 11:24:59 -04:00
# ifdef DB_PROFILE
while ( db_blocking_step ( stmt ) = = SQLITE_ROW )
; /* EMPTY */
# endif
2009-06-10 12:11:11 -04:00
sqlite3_finalize ( stmt ) ;
sqlite3_free ( query ) ;
return 0 ;
2014-06-09 17:42:02 -04:00
}
int
db_watch_get_bywd ( struct watch_info * wi )
{
# define Q_TMPL "SELECT * FROM inotify WHERE wd = %d;"
char * query ;
query = sqlite3_mprintf ( Q_TMPL , wi - > wd ) ;
if ( ! query )
{
DPRINTF ( E_LOG , L_DB , " Out of memory for query string \n " ) ;
return - 1 ;
}
return db_watch_get_byquery ( wi , query ) ;
# undef Q_TMPL
}
int
db_watch_get_bypath ( struct watch_info * wi )
{
# define Q_TMPL "SELECT * FROM inotify WHERE path = '%q';"
char * query ;
query = sqlite3_mprintf ( Q_TMPL , wi - > path ) ;
if ( ! query )
{
DPRINTF ( E_LOG , L_DB , " Out of memory for query string \n " ) ;
return - 1 ;
}
2009-06-10 12:11:11 -04:00
2014-06-09 17:42:02 -04:00
return db_watch_get_byquery ( wi , query ) ;
2009-06-10 12:11:11 -04:00
# undef Q_TMPL
}
2009-06-11 09:24:10 -04:00
void
db_watch_mark_bypath ( char * path , char * strip , uint32_t cookie )
{
# define Q_TMPL "UPDATE inotify SET path = substr(path, %d), cookie = %" PRIi64 " WHERE path = '%q';"
char * query ;
int64_t disabled ;
int striplen ;
disabled = ( cookie ! = 0 ) ? cookie : INOTIFY_FAKE_COOKIE ;
striplen = strlen ( strip ) + 1 ;
query = sqlite3_mprintf ( Q_TMPL , striplen , disabled , path ) ;
2014-08-22 16:51:13 -04:00
db_query_run ( query , 1 , 0 ) ;
2009-06-11 09:24:10 -04:00
# undef Q_TMPL
}
void
db_watch_mark_bymatch ( char * path , char * strip , uint32_t cookie )
{
# define Q_TMPL "UPDATE inotify SET path = substr(path, %d), cookie = %" PRIi64 " WHERE path LIKE '%q / %%';"
char * query ;
int64_t disabled ;
int striplen ;
disabled = ( cookie ! = 0 ) ? cookie : INOTIFY_FAKE_COOKIE ;
striplen = strlen ( strip ) + 1 ;
query = sqlite3_mprintf ( Q_TMPL , striplen , disabled , path ) ;
2014-08-22 16:51:13 -04:00
db_query_run ( query , 1 , 0 ) ;
2009-06-11 09:24:10 -04:00
# undef Q_TMPL
}
2009-06-10 12:11:11 -04:00
2009-06-11 09:42:51 -04:00
void
db_watch_move_bycookie ( uint32_t cookie , char * path )
{
# define Q_TMPL "UPDATE inotify SET path = '%q' || path, cookie = 0 WHERE cookie = %" PRIi64 ";"
char * query ;
if ( cookie = = 0 )
return ;
query = sqlite3_mprintf ( Q_TMPL , path , ( int64_t ) cookie ) ;
2014-08-22 16:51:13 -04:00
db_query_run ( query , 1 , 0 ) ;
2009-06-11 09:42:51 -04:00
# undef Q_TMPL
}
int
db_watch_cookie_known ( uint32_t cookie )
{
# define Q_TMPL "SELECT COUNT(*) FROM inotify WHERE cookie = %" PRIi64 ";"
char * query ;
int ret ;
if ( cookie = = 0 )
return 0 ;
query = sqlite3_mprintf ( Q_TMPL , ( int64_t ) cookie ) ;
if ( ! query )
{
DPRINTF ( E_LOG , L_DB , " Out of memory for query string \n " ) ;
return 0 ;
}
2009-06-11 09:45:49 -04:00
ret = db_get_count ( query ) ;
2009-06-11 09:42:51 -04:00
sqlite3_free ( query ) ;
return ( ret > 0 ) ;
# undef Q_TMPL
}
2009-06-11 10:44:49 -04:00
int
db_watch_enum_start ( struct watch_enum * we )
{
# define Q_MATCH_TMPL "SELECT wd FROM inotify WHERE path LIKE '%q / %%';"
# define Q_COOKIE_TMPL "SELECT wd FROM inotify WHERE cookie = %" PRIi64 ";"
char * query ;
int ret ;
we - > stmt = NULL ;
if ( we - > match )
query = sqlite3_mprintf ( Q_MATCH_TMPL , we - > match ) ;
else if ( we - > cookie ! = 0 )
query = sqlite3_mprintf ( Q_COOKIE_TMPL , we - > cookie ) ;
else
{
DPRINTF ( E_LOG , L_DB , " Could not start enum, no parameter given \n " ) ;
return - 1 ;
}
if ( ! query )
{
DPRINTF ( E_LOG , L_DB , " Out of memory for query string \n " ) ;
return - 1 ;
}
DPRINTF ( E_DBG , L_DB , " Starting enum '%s' \n " , query ) ;
2010-04-26 12:24:09 -04:00
ret = db_blocking_prepare_v2 ( query , - 1 , & we - > stmt , NULL ) ;
2009-06-11 10:44:49 -04:00
if ( ret ! = SQLITE_OK )
{
DPRINTF ( E_LOG , L_DB , " Could not prepare statement: %s \n " , sqlite3_errmsg ( hdl ) ) ;
sqlite3_free ( query ) ;
return - 1 ;
}
sqlite3_free ( query ) ;
return 0 ;
# undef Q_MATCH_TMPL
# undef Q_COOKIE_TMPL
}
void
db_watch_enum_end ( struct watch_enum * we )
{
if ( ! we - > stmt )
return ;
sqlite3_finalize ( we - > stmt ) ;
we - > stmt = NULL ;
}
int
db_watch_enum_fetchwd ( struct watch_enum * we , uint32_t * wd )
{
int ret ;
* wd = 0 ;
if ( ! we - > stmt )
{
DPRINTF ( E_LOG , L_DB , " Watch enum not started! \n " ) ;
return - 1 ;
}
2010-04-26 12:24:09 -04:00
ret = db_blocking_step ( we - > stmt ) ;
2009-06-11 10:44:49 -04:00
if ( ret = = SQLITE_DONE )
{
DPRINTF ( E_INFO , L_DB , " End of watch enum results \n " ) ;
return 0 ;
}
else if ( ret ! = SQLITE_ROW )
{
DPRINTF ( E_LOG , L_DB , " Could not step: %s \n " , sqlite3_errmsg ( hdl ) ) ;
return - 1 ;
}
* wd = ( uint32_t ) sqlite3_column_int ( we - > stmt , 0 ) ;
return 0 ;
}
2009-06-10 12:11:11 -04:00
2010-09-29 12:49:10 -04:00
# ifdef DB_PROFILE
static void
db_xprofile ( void * notused , const char * pquery , sqlite3_uint64 ptime )
{
2011-06-11 10:59:25 -04:00
sqlite3_stmt * stmt ;
char * query ;
int ret ;
DPRINTF ( E_DBG , L_DBPERF , " SQL PROFILE query: %s \n " , pquery ) ;
2011-06-11 11:25:24 -04:00
DPRINTF ( E_DBG , L_DBPERF , " SQL PROFILE time: % " PRIu64 " ms \n " , ( ( uint64_t ) ptime / 1000000 ) ) ;
2011-06-11 10:59:25 -04:00
if ( ( strncmp ( pquery , " SELECT " , 6 ) ! = 0 )
& & ( strncmp ( pquery , " UPDATE " , 6 ) ! = 0 )
& & ( strncmp ( pquery , " DELETE " , 6 ) ! = 0 ) )
return ;
/* Disable profiling callback */
sqlite3_profile ( hdl , NULL , NULL ) ;
query = sqlite3_mprintf ( " EXPLAIN QUERY PLAN %s " , pquery ) ;
if ( ! query )
{
DPRINTF ( E_DBG , L_DBPERF , " Query plan: Out of memory \n " ) ;
goto out ;
}
ret = db_blocking_prepare_v2 ( query , - 1 , & stmt , NULL ) ;
sqlite3_free ( query ) ;
if ( ret ! = SQLITE_OK )
{
DPRINTF ( E_DBG , L_DBPERF , " Query plan: Could not prepare statement: %s \n " , sqlite3_errmsg ( hdl ) ) ;
goto out ;
}
DPRINTF ( E_DBG , L_DBPERF , " Query plan: \n " ) ;
while ( ( ret = db_blocking_step ( stmt ) ) = = SQLITE_ROW )
{
DPRINTF ( E_DBG , L_DBPERF , " (%d,%d,%d) %s \n " ,
sqlite3_column_int ( stmt , 0 ) , sqlite3_column_int ( stmt , 1 ) , sqlite3_column_int ( stmt , 2 ) ,
sqlite3_column_text ( stmt , 3 ) ) ;
}
if ( ret ! = SQLITE_DONE )
DPRINTF ( E_DBG , L_DBPERF , " Query plan: Could not step: %s \n " , sqlite3_errmsg ( hdl ) ) ;
DPRINTF ( E_DBG , L_DBPERF , " --- \n " ) ;
sqlite3_finalize ( stmt ) ;
out :
/* Reenable profiling callback */
sqlite3_profile ( hdl , db_xprofile , NULL ) ;
2010-09-29 12:49:10 -04:00
}
# endif
2014-06-08 02:25:58 -04:00
static int
db_pragma_get_cache_size ( )
{
sqlite3_stmt * stmt ;
char * query = " PRAGMA cache_size; " ;
int ret ;
DPRINTF ( E_DBG , L_DB , " Running query '%s' \n " , query ) ;
ret = db_blocking_prepare_v2 ( query , - 1 , & stmt , NULL ) ;
if ( ret ! = SQLITE_OK )
{
DPRINTF ( E_LOG , L_DB , " Could not prepare statement: %s \n " , sqlite3_errmsg ( hdl ) ) ;
sqlite3_free ( query ) ;
return 0 ;
}
ret = db_blocking_step ( stmt ) ;
if ( ret = = SQLITE_DONE )
{
DPRINTF ( E_DBG , L_DB , " End of query results \n " ) ;
sqlite3_free ( query ) ;
return 0 ;
}
else if ( ret ! = SQLITE_ROW )
{
DPRINTF ( E_LOG , L_DB , " Could not step: %s \n " , sqlite3_errmsg ( hdl ) ) ;
sqlite3_free ( query ) ;
return - 1 ;
}
ret = sqlite3_column_int ( stmt , 0 ) ;
sqlite3_finalize ( stmt ) ;
return ret ;
}
static int
db_pragma_set_cache_size ( int pages )
{
# define Q_TMPL "PRAGMA cache_size=%d;"
sqlite3_stmt * stmt ;
char * query ;
int ret ;
query = sqlite3_mprintf ( Q_TMPL , pages ) ;
DPRINTF ( E_DBG , L_DB , " Running query '%s' \n " , query ) ;
ret = db_blocking_prepare_v2 ( query , - 1 , & stmt , NULL ) ;
if ( ret ! = SQLITE_OK )
{
DPRINTF ( E_LOG , L_DB , " Could not prepare statement: %s \n " , sqlite3_errmsg ( hdl ) ) ;
sqlite3_free ( query ) ;
return 0 ;
}
sqlite3_finalize ( stmt ) ;
sqlite3_free ( query ) ;
return 0 ;
2014-07-27 05:16:00 -04:00
# undef Q_TMPL
2014-06-08 02:25:58 -04:00
}
static char *
db_pragma_set_journal_mode ( char * mode )
{
# define Q_TMPL "PRAGMA journal_mode=%s;"
sqlite3_stmt * stmt ;
char * query ;
int ret ;
char * new_mode ;
query = sqlite3_mprintf ( Q_TMPL , mode ) ;
DPRINTF ( E_DBG , L_DB , " Running query '%s' \n " , query ) ;
ret = db_blocking_prepare_v2 ( query , - 1 , & stmt , NULL ) ;
if ( ret ! = SQLITE_OK )
{
DPRINTF ( E_LOG , L_DB , " Could not prepare statement: %s \n " , sqlite3_errmsg ( hdl ) ) ;
sqlite3_free ( query ) ;
return NULL ;
}
ret = db_blocking_step ( stmt ) ;
if ( ret = = SQLITE_DONE )
{
DPRINTF ( E_DBG , L_DB , " End of query results \n " ) ;
sqlite3_free ( query ) ;
return NULL ;
}
else if ( ret ! = SQLITE_ROW )
{
DPRINTF ( E_LOG , L_DB , " Could not step: %s \n " , sqlite3_errmsg ( hdl ) ) ;
sqlite3_free ( query ) ;
return NULL ;
}
new_mode = ( char * ) sqlite3_column_text ( stmt , 0 ) ;
sqlite3_finalize ( stmt ) ;
sqlite3_free ( query ) ;
return new_mode ;
# undef Q_TMPL
}
static int
db_pragma_get_synchronous ( )
{
sqlite3_stmt * stmt ;
char * query = " PRAGMA synchronous; " ;
int ret ;
DPRINTF ( E_DBG , L_DB , " Running query '%s' \n " , query ) ;
ret = db_blocking_prepare_v2 ( query , - 1 , & stmt , NULL ) ;
if ( ret ! = SQLITE_OK )
{
DPRINTF ( E_LOG , L_DB , " Could not prepare statement: %s \n " , sqlite3_errmsg ( hdl ) ) ;
sqlite3_free ( query ) ;
return 0 ;
}
ret = db_blocking_step ( stmt ) ;
if ( ret = = SQLITE_DONE )
{
DPRINTF ( E_DBG , L_DB , " End of query results \n " ) ;
sqlite3_free ( query ) ;
return 0 ;
}
else if ( ret ! = SQLITE_ROW )
{
DPRINTF ( E_LOG , L_DB , " Could not step: %s \n " , sqlite3_errmsg ( hdl ) ) ;
sqlite3_free ( query ) ;
return - 1 ;
}
ret = sqlite3_column_int ( stmt , 0 ) ;
sqlite3_finalize ( stmt ) ;
return ret ;
}
static int
db_pragma_set_synchronous ( int synchronous )
{
# define Q_TMPL "PRAGMA synchronous=%d;"
sqlite3_stmt * stmt ;
char * query ;
int ret ;
query = sqlite3_mprintf ( Q_TMPL , synchronous ) ;
DPRINTF ( E_DBG , L_DB , " Running query '%s' \n " , query ) ;
ret = db_blocking_prepare_v2 ( query , - 1 , & stmt , NULL ) ;
if ( ret ! = SQLITE_OK )
{
DPRINTF ( E_LOG , L_DB , " Could not prepare statement: %s \n " , sqlite3_errmsg ( hdl ) ) ;
sqlite3_free ( query ) ;
return 0 ;
}
sqlite3_finalize ( stmt ) ;
sqlite3_free ( query ) ;
return 0 ;
2014-07-27 05:16:00 -04:00
# undef Q_TMPL
2014-06-08 02:25:58 -04:00
}
2010-09-29 12:49:10 -04:00
2014-11-10 16:53:08 -05:00
2009-06-07 12:56:35 -04:00
int
db_perthread_init ( void )
{
2010-09-28 12:38:10 -04:00
char * errmsg ;
2009-06-07 12:56:35 -04:00
int ret ;
2014-06-08 02:25:58 -04:00
int cache_size ;
char * journal_mode ;
int synchronous ;
2009-06-07 12:56:35 -04:00
2010-03-21 06:33:05 -04:00
ret = sqlite3_open ( db_path , & hdl ) ;
2009-06-07 12:56:35 -04:00
if ( ret ! = SQLITE_OK )
{
DPRINTF ( E_LOG , L_DB , " Could not open database: %s \n " , sqlite3_errmsg ( hdl ) ) ;
sqlite3_close ( hdl ) ;
return - 1 ;
}
2010-09-28 12:38:10 -04:00
ret = sqlite3_enable_load_extension ( hdl , 1 ) ;
2010-01-04 12:00:40 -05:00
if ( ret ! = SQLITE_OK )
{
2010-09-28 12:38:10 -04:00
DPRINTF ( E_LOG , L_DB , " Could not enable extension loading \n " ) ;
sqlite3_close ( hdl ) ;
return - 1 ;
}
errmsg = NULL ;
ret = sqlite3_load_extension ( hdl , PKGLIBDIR " /forked-daapd-sqlext.so " , NULL , & errmsg ) ;
if ( ret ! = SQLITE_OK )
{
if ( errmsg )
{
DPRINTF ( E_LOG , L_DB , " Could not load SQLite extension: %s \n " , errmsg ) ;
sqlite3_free ( errmsg ) ;
}
else
DPRINTF ( E_LOG , L_DB , " Could not load SQLite extension: %s \n " , sqlite3_errmsg ( hdl ) ) ;
2010-01-04 12:00:40 -05:00
sqlite3_close ( hdl ) ;
return - 1 ;
}
2010-09-28 12:38:10 -04:00
ret = sqlite3_enable_load_extension ( hdl , 0 ) ;
2010-08-29 04:21:35 -04:00
if ( ret ! = SQLITE_OK )
{
2010-09-28 12:38:10 -04:00
DPRINTF ( E_LOG , L_DB , " Could not disable extension loading \n " ) ;
2010-08-29 04:21:35 -04:00
sqlite3_close ( hdl ) ;
return - 1 ;
}
2010-09-29 12:49:10 -04:00
# ifdef DB_PROFILE
sqlite3_profile ( hdl , db_xprofile , NULL ) ;
# endif
2014-11-10 16:53:08 -05:00
cache_size = cfg_getint ( cfg_getsec ( cfg , " sqlite " ) , " pragma_cache_size_library " ) ;
2014-06-08 02:25:58 -04:00
if ( cache_size > - 1 )
{
db_pragma_set_cache_size ( cache_size ) ;
cache_size = db_pragma_get_cache_size ( ) ;
DPRINTF ( E_DBG , L_DB , " Database cache size in pages: %d \n " , cache_size ) ;
}
2014-11-10 16:53:08 -05:00
journal_mode = cfg_getstr ( cfg_getsec ( cfg , " sqlite " ) , " pragma_journal_mode " ) ;
2014-06-08 02:25:58 -04:00
if ( journal_mode )
{
journal_mode = db_pragma_set_journal_mode ( journal_mode ) ;
DPRINTF ( E_DBG , L_DB , " Database journal mode: %s \n " , journal_mode ) ;
}
2014-11-10 16:53:08 -05:00
synchronous = cfg_getint ( cfg_getsec ( cfg , " sqlite " ) , " pragma_synchronous " ) ;
2014-06-08 02:25:58 -04:00
if ( synchronous > - 1 )
{
db_pragma_set_synchronous ( synchronous ) ;
synchronous = db_pragma_get_synchronous ( ) ;
DPRINTF ( E_DBG , L_DB , " Database synchronous: %d \n " , synchronous ) ;
}
2009-06-07 12:56:35 -04:00
return 0 ;
}
void
db_perthread_deinit ( void )
{
sqlite3_stmt * stmt ;
2010-07-17 06:48:11 -04:00
if ( ! hdl )
return ;
2009-06-07 12:56:35 -04:00
/* Tear down anything that's in flight */
while ( ( stmt = sqlite3_next_stmt ( hdl , 0 ) ) )
sqlite3_finalize ( stmt ) ;
sqlite3_close ( hdl ) ;
}
# define T_ADMIN \
" CREATE TABLE IF NOT EXISTS admin( " \
" key VARCHAR(32) NOT NULL, " \
" value VARCHAR(32) NOT NULL " \
" ); "
2009-12-26 02:44:55 -05:00
# define T_FILES \
2009-06-11 17:03:53 -04:00
" CREATE TABLE IF NOT EXISTS files ( " \
2009-12-26 02:44:55 -05:00
" id INTEGER PRIMARY KEY NOT NULL, " \
" path VARCHAR(4096) NOT NULL, " \
" fname VARCHAR(255) NOT NULL, " \
2010-12-05 04:25:09 -05:00
" title VARCHAR(1024) DEFAULT NULL COLLATE DAAP, " \
" artist VARCHAR(1024) DEFAULT NULL COLLATE DAAP, " \
" album VARCHAR(1024) NOT NULL COLLATE DAAP, " \
" genre VARCHAR(255) DEFAULT NULL COLLATE DAAP, " \
" comment VARCHAR(4096) DEFAULT NULL COLLATE DAAP, " \
" type VARCHAR(255) DEFAULT NULL COLLATE DAAP, " \
" composer VARCHAR(1024) DEFAULT NULL COLLATE DAAP, " \
" orchestra VARCHAR(1024) DEFAULT NULL COLLATE DAAP, " \
" conductor VARCHAR(1024) DEFAULT NULL COLLATE DAAP, " \
" grouping VARCHAR(1024) DEFAULT NULL COLLATE DAAP, " \
2009-12-26 02:44:55 -05:00
" url VARCHAR(1024) DEFAULT NULL, " \
" bitrate INTEGER DEFAULT 0, " \
" samplerate INTEGER DEFAULT 0, " \
" song_length INTEGER DEFAULT 0, " \
" file_size INTEGER DEFAULT 0, " \
" year INTEGER DEFAULT 0, " \
" track INTEGER DEFAULT 0, " \
" total_tracks INTEGER DEFAULT 0, " \
" disc INTEGER DEFAULT 0, " \
" total_discs INTEGER DEFAULT 0, " \
" bpm INTEGER DEFAULT 0, " \
" compilation INTEGER DEFAULT 0, " \
2014-01-11 17:05:29 -05:00
" artwork INTEGER DEFAULT 0, " \
2009-12-26 02:44:55 -05:00
" rating INTEGER DEFAULT 0, " \
" play_count INTEGER DEFAULT 0, " \
2013-12-17 14:58:55 -05:00
" seek INTEGER DEFAULT 0, " \
2009-12-26 02:44:55 -05:00
" data_kind INTEGER DEFAULT 0, " \
" item_kind INTEGER DEFAULT 0, " \
" description INTEGER DEFAULT 0, " \
" time_added INTEGER DEFAULT 0, " \
" time_modified INTEGER DEFAULT 0, " \
" time_played INTEGER DEFAULT 0, " \
" db_timestamp INTEGER DEFAULT 0, " \
" disabled INTEGER DEFAULT 0, " \
" sample_count INTEGER DEFAULT 0, " \
" codectype VARCHAR(5) DEFAULT NULL, " \
" idx INTEGER NOT NULL, " \
" has_video INTEGER DEFAULT 0, " \
" contentrating INTEGER DEFAULT 0, " \
" bits_per_sample INTEGER DEFAULT 0, " \
2010-12-05 04:25:09 -05:00
" album_artist VARCHAR(1024) NOT NULL COLLATE DAAP, " \
2009-12-26 02:44:55 -05:00
" media_kind INTEGER NOT NULL, " \
2010-12-05 04:25:09 -05:00
" tv_series_name VARCHAR(1024) DEFAULT NULL COLLATE DAAP, " \
" tv_episode_num_str VARCHAR(1024) DEFAULT NULL COLLATE DAAP, " \
" tv_network_name VARCHAR(1024) DEFAULT NULL COLLATE DAAP, " \
2009-12-26 02:44:55 -05:00
" tv_episode_sort INTEGER NOT NULL, " \
2010-03-06 11:13:56 -05:00
" tv_season_num INTEGER NOT NULL, " \
2013-12-17 14:58:55 -05:00
" songartistid INTEGER NOT NULL, " \
2010-09-21 07:16:38 -04:00
" songalbumid INTEGER NOT NULL, " \
" title_sort VARCHAR(1024) DEFAULT NULL COLLATE DAAP, " \
" artist_sort VARCHAR(1024) DEFAULT NULL COLLATE DAAP, " \
" album_sort VARCHAR(1024) DEFAULT NULL COLLATE DAAP, " \
" composer_sort VARCHAR(1024) DEFAULT NULL COLLATE DAAP, " \
2014-12-21 14:41:44 -05:00
" album_artist_sort VARCHAR(1024) DEFAULT NULL COLLATE DAAP, " \
2015-12-27 01:16:50 -05:00
" virtual_path VARCHAR(4096) DEFAULT NULL, " \
2016-01-29 13:46:56 -05:00
" directory_id INTEGER DEFAULT 0, " \
" date_released INTEGER DEFAULT 0 " \
2009-06-07 12:56:35 -04:00
" ); "
# define T_PL \
" CREATE TABLE IF NOT EXISTS playlists ( " \
" id INTEGER PRIMARY KEY NOT NULL, " \
2010-12-05 04:25:09 -05:00
" title VARCHAR(255) NOT NULL COLLATE DAAP, " \
2009-06-07 12:56:35 -04:00
" type INTEGER NOT NULL, " \
" query VARCHAR(1024), " \
" db_timestamp INTEGER NOT NULL, " \
2009-06-10 09:23:02 -04:00
" disabled INTEGER DEFAULT 0, " \
2009-06-07 12:56:35 -04:00
" path VARCHAR(4096), " \
2010-01-21 11:52:51 -05:00
" idx INTEGER NOT NULL, " \
2014-12-21 14:41:44 -05:00
" special_id INTEGER DEFAULT 0, " \
2015-03-14 18:35:19 -04:00
" virtual_path VARCHAR(4096), " \
2015-12-27 01:16:50 -05:00
" parent_id INTEGER DEFAULT 0, " \
" directory_id INTEGER DEFAULT 0 " \
2009-06-07 12:56:35 -04:00
" ); "
# define T_PLITEMS \
" CREATE TABLE IF NOT EXISTS playlistitems ( " \
" id INTEGER PRIMARY KEY NOT NULL, " \
" playlistid INTEGER NOT NULL, " \
2009-06-11 14:27:31 -04:00
" filepath VARCHAR(4096) NOT NULL " \
2009-06-07 12:56:35 -04:00
" ); "
2010-03-06 12:56:30 -05:00
# define T_GROUPS \
" CREATE TABLE IF NOT EXISTS groups ( " \
" id INTEGER PRIMARY KEY NOT NULL, " \
" type INTEGER NOT NULL, " \
2010-12-05 04:25:09 -05:00
" name VARCHAR(1024) NOT NULL COLLATE DAAP, " \
2015-01-08 16:40:47 -05:00
" persistentid INTEGER NOT NULL, " \
" CONSTRAINT groups_type_unique_persistentid UNIQUE (type, persistentid) " \
2010-03-06 12:56:30 -05:00
" ); "
2010-01-30 11:01:27 -05:00
# define T_PAIRINGS \
" CREATE TABLE IF NOT EXISTS pairings( " \
" remote VARCHAR(64) PRIMARY KEY NOT NULL, " \
" name VARCHAR(255) NOT NULL, " \
" guid VARCHAR(16) NOT NULL " \
" ); "
2010-11-02 13:40:14 -04:00
# define T_SPEAKERS \
" CREATE TABLE IF NOT EXISTS speakers( " \
" id INTEGER PRIMARY KEY NOT NULL, " \
" selected INTEGER NOT NULL, " \
2016-01-29 13:46:56 -05:00
" volume INTEGER NOT NULL, " \
" name VARCHAR(255) DEFAULT NULL " \
2010-11-02 13:40:14 -04:00
" ); "
2009-06-10 12:11:11 -04:00
# define T_INOTIFY \
" CREATE TABLE IF NOT EXISTS inotify ( " \
" wd INTEGER PRIMARY KEY NOT NULL, " \
" cookie INTEGER NOT NULL, " \
2010-03-19 14:06:47 -04:00
" path VARCHAR(4096) NOT NULL " \
2009-06-10 12:11:11 -04:00
" ); "
2015-12-27 01:16:50 -05:00
# define T_DIRECTORIES \
" CREATE TABLE IF NOT EXISTS directories ( " \
" id INTEGER PRIMARY KEY NOT NULL, " \
" virtual_path VARCHAR(4096) NOT NULL, " \
" db_timestamp INTEGER DEFAULT 0, " \
" disabled INTEGER DEFAULT 0, " \
" parent_id INTEGER DEFAULT 0 " \
" ); "
2014-12-21 14:41:44 -05:00
2015-01-08 16:40:47 -05:00
# define TRG_GROUPS_INSERT_FILES \
" CREATE TRIGGER update_groups_new_file AFTER INSERT ON files FOR EACH ROW " \
" BEGIN " \
" INSERT OR IGNORE INTO groups (type, name, persistentid) VALUES (1, NEW.album, NEW.songalbumid); " \
" INSERT OR IGNORE INTO groups (type, name, persistentid) VALUES (2, NEW.album_artist, NEW.songartistid); " \
" END; "
# define TRG_GROUPS_UPDATE_FILES \
" CREATE TRIGGER update_groups_update_file AFTER UPDATE OF songalbumid ON files FOR EACH ROW " \
" BEGIN " \
" INSERT OR IGNORE INTO groups (type, name, persistentid) VALUES (1, NEW.album, NEW.songalbumid); " \
" INSERT OR IGNORE INTO groups (type, name, persistentid) VALUES (2, NEW.album_artist, NEW.songartistid); " \
" END; "
2010-01-21 11:51:44 -05:00
# define Q_PL1 \
2010-01-21 11:52:51 -05:00
" INSERT INTO playlists (id, title, type, query, db_timestamp, path, idx, special_id) " \
2015-04-21 13:12:54 -04:00
" VALUES(1, 'Library', 0, '1 = 1', 0, '', 0, 0); "
2010-01-21 11:52:51 -05:00
# define Q_PL2 \
" INSERT INTO playlists (id, title, type, query, db_timestamp, path, idx, special_id) " \
2015-04-21 13:12:54 -04:00
" VALUES(2, 'Music', 0, 'f.media_kind = 1', 0, '', 0, 6); "
2010-01-21 11:52:51 -05:00
# define Q_PL3 \
" INSERT INTO playlists (id, title, type, query, db_timestamp, path, idx, special_id) " \
2015-04-21 13:12:54 -04:00
" VALUES(3, 'Movies', 0, 'f.media_kind = 2', 0, '', 0, 4); "
2010-01-21 11:52:51 -05:00
# define Q_PL4 \
" INSERT INTO playlists (id, title, type, query, db_timestamp, path, idx, special_id) " \
2015-04-21 13:12:54 -04:00
" VALUES(4, 'TV Shows', 0, 'f.media_kind = 64', 0, '', 0, 5); "
2010-01-21 11:52:51 -05:00
2013-10-18 17:07:40 -04:00
# define Q_PL5 \
" INSERT INTO playlists (id, title, type, query, db_timestamp, path, idx, special_id) " \
2015-04-21 13:12:54 -04:00
" VALUES(5, 'Podcasts', 0, 'f.media_kind = 4', 0, '', 0, 1); "
2013-10-18 17:07:40 -04:00
2013-12-08 17:03:03 -05:00
# define Q_PL6 \
" INSERT INTO playlists (id, title, type, query, db_timestamp, path, idx, special_id) " \
2015-04-21 13:12:54 -04:00
" VALUES(6, 'Audiobooks', 0, 'f.media_kind = 8', 0, '', 0, 7); "
2013-12-08 17:03:03 -05:00
2010-01-21 11:52:51 -05:00
/* These are the remaining automatically-created iTunes playlists, but
* their query is unknown
" VALUES(6, 'iTunes U', 0, 'media_kind = 256', 0, '', 0, 13); "
" VALUES(8, 'Purchased', 0, 'media_kind = 1024', 0, '', 0, 8); "
*/
2010-01-21 11:51:44 -05:00
2015-12-27 01:16:50 -05:00
# define Q_DIR1 \
" INSERT INTO directories (id, virtual_path, db_timestamp, disabled, parent_id) " \
" VALUES (1, '/', 0, 0, 0); "
2016-01-24 12:45:28 -05:00
# define Q_DIR2 \
" INSERT INTO directories (id, virtual_path, db_timestamp, disabled, parent_id) " \
" VALUES (2, '/file:', 0, 0, 1); "
# define Q_DIR3 \
" INSERT INTO directories (id, virtual_path, db_timestamp, disabled, parent_id) " \
" VALUES (3, '/http:', 0, 0, 1); "
# define Q_DIR4 \
" INSERT INTO directories (id, virtual_path, db_timestamp, disabled, parent_id) " \
2016-01-30 01:27:20 -05:00
" VALUES (4, '/spotify:', 0, 4294967296, 1); "
2015-12-27 01:16:50 -05:00
2015-06-04 15:58:01 -04:00
/* Rule of thumb: Will the current version of forked-daapd work with the new
* version of the database ? If yes , then it is a minor upgrade , if no , then it
* is a major upgrade . In other words minor version upgrades permit downgrading
* forked - daapd after the database was upgraded . */
2015-12-27 01:16:50 -05:00
# define SCHEMA_VERSION_MAJOR 19
# define SCHEMA_VERSION_MINOR 00
2015-01-14 14:37:29 -05:00
# define Q_SCVER_MAJOR \
2015-12-27 01:16:50 -05:00
" INSERT INTO admin (key, value) VALUES ('schema_version_major', '19'); "
2015-01-14 14:37:29 -05:00
# define Q_SCVER_MINOR \
2015-12-27 01:16:50 -05:00
" INSERT INTO admin (key, value) VALUES ('schema_version_minor', '00'); "
2009-06-08 12:41:59 -04:00
2009-06-07 12:56:35 -04:00
struct db_init_query {
char * query ;
char * desc ;
} ;
2015-01-08 18:28:06 -05:00
static const struct db_init_query db_init_table_queries [ ] =
2009-06-07 12:56:35 -04:00
{
{ T_ADMIN , " create table admin " } ,
2009-06-11 17:03:53 -04:00
{ T_FILES , " create table files " } ,
2009-06-07 12:56:35 -04:00
{ T_PL , " create table playlists " } ,
{ T_PLITEMS , " create table playlistitems " } ,
2010-03-06 12:56:30 -05:00
{ T_GROUPS , " create table groups " } ,
2010-01-30 11:01:27 -05:00
{ T_PAIRINGS , " create table pairings " } ,
2010-11-02 13:40:14 -04:00
{ T_SPEAKERS , " create table speakers " } ,
2009-06-10 12:11:11 -04:00
{ T_INOTIFY , " create table inotify " } ,
2015-12-27 01:16:50 -05:00
{ T_DIRECTORIES , " create table directories " } ,
2014-12-21 14:41:44 -05:00
2015-01-08 18:28:06 -05:00
{ TRG_GROUPS_INSERT_FILES , " create trigger update_groups_new_file " } ,
{ TRG_GROUPS_UPDATE_FILES , " create trigger update_groups_update_file " } ,
{ Q_PL1 , " create default playlist " } ,
{ Q_PL2 , " create default smart playlist 'Music' " } ,
{ Q_PL3 , " create default smart playlist 'Movies' " } ,
{ Q_PL4 , " create default smart playlist 'TV Shows' " } ,
{ Q_PL5 , " create default smart playlist 'Podcasts' " } ,
{ Q_PL6 , " create default smart playlist 'Audiobooks' " } ,
2015-12-27 01:16:50 -05:00
{ Q_DIR1 , " create default root directory '/' " } ,
2016-01-24 12:45:28 -05:00
{ Q_DIR2 , " create default base directory '/file:' " } ,
{ Q_DIR3 , " create default base directory '/http:' " } ,
{ Q_DIR4 , " create default base directory '/spotify:' " } ,
2015-01-08 18:28:06 -05:00
2015-01-14 14:37:29 -05:00
{ Q_SCVER_MAJOR , " set schema version major " } ,
{ Q_SCVER_MINOR , " set schema version minor " } ,
2015-01-08 18:28:06 -05:00
} ;
2015-01-10 13:19:45 -05:00
/* Indices must be prefixed with idx_ for db_drop_indices() to id them */
2015-01-09 17:04:50 -05:00
2015-01-08 18:28:06 -05:00
# define I_RESCAN \
" CREATE INDEX IF NOT EXISTS idx_rescan ON files(path, db_timestamp); "
# define I_SONGARTISTID \
" CREATE INDEX IF NOT EXISTS idx_sari ON files(songartistid); "
2015-01-09 17:04:50 -05:00
/* Used by Q_GROUP_ALBUMS */
2015-01-08 18:28:06 -05:00
# define I_SONGALBUMID \
2015-01-09 17:04:50 -05:00
" CREATE INDEX IF NOT EXISTS idx_sali ON files(songalbumid, disabled, media_kind, album_sort, disc, track); "
2015-01-08 18:28:06 -05:00
2015-01-09 17:04:50 -05:00
/* Used by Q_GROUP_ARTISTS */
2015-01-08 18:28:06 -05:00
# define I_STATEMKINDSARI \
" CREATE INDEX IF NOT EXISTS idx_state_mkind_sari ON files(disabled, media_kind, songartistid); "
# define I_STATEMKINDSALI \
" CREATE INDEX IF NOT EXISTS idx_state_mkind_sali ON files(disabled, media_kind, songalbumid); "
# define I_ARTIST \
" CREATE INDEX IF NOT EXISTS idx_artist ON files(artist, artist_sort); "
# define I_ALBUMARTIST \
" CREATE INDEX IF NOT EXISTS idx_albumartist ON files(album_artist, album_artist_sort); "
2015-01-09 17:58:27 -05:00
/* Used by Q_BROWSE_COMPOSERS */
2015-01-08 18:28:06 -05:00
# define I_COMPOSER \
2015-01-09 17:58:27 -05:00
" CREATE INDEX IF NOT EXISTS idx_composer ON files(disabled, media_kind, composer_sort); "
2015-01-08 18:28:06 -05:00
2015-01-09 17:58:27 -05:00
/* Used by Q_BROWSE_GENRES */
# define I_GENRE \
" CREATE INDEX IF NOT EXISTS idx_genre ON files(disabled, media_kind, genre); "
/* Used by Q_PLITEMS for smart playlists */
2015-01-08 18:28:06 -05:00
# define I_TITLE \
2015-01-09 17:58:27 -05:00
" CREATE INDEX IF NOT EXISTS idx_title ON files(disabled, media_kind, title_sort); "
2015-01-08 18:28:06 -05:00
# define I_ALBUM \
" CREATE INDEX IF NOT EXISTS idx_album ON files(album, album_sort); "
2015-02-14 02:46:21 -05:00
# define I_FILELIST \
" CREATE INDEX IF NOT EXISTS idx_filelist ON files(disabled, virtual_path, time_modified); "
2015-12-27 01:16:50 -05:00
# define I_FILE_DIR \
" CREATE INDEX IF NOT EXISTS idx_file_dir ON files(disabled, directory_id); "
2015-01-08 18:28:06 -05:00
# define I_PL_PATH \
" CREATE INDEX IF NOT EXISTS idx_pl_path ON playlists(path); "
# define I_PL_DISABLED \
2015-02-14 02:46:21 -05:00
" CREATE INDEX IF NOT EXISTS idx_pl_disabled ON playlists(disabled, type, virtual_path, db_timestamp); "
2015-01-08 18:28:06 -05:00
2015-12-27 01:16:50 -05:00
# define I_PL_DIR \
" CREATE INDEX IF NOT EXISTS idx_pl_dir ON files(disabled, directory_id); "
2015-01-08 18:28:06 -05:00
# define I_FILEPATH \
" CREATE INDEX IF NOT EXISTS idx_filepath ON playlistitems(filepath ASC); "
# define I_PLITEMID \
" CREATE INDEX IF NOT EXISTS idx_playlistid ON playlistitems(playlistid, filepath); "
2015-01-09 17:04:50 -05:00
# define I_GRP_PERSIST \
" CREATE INDEX IF NOT EXISTS idx_grp_persist ON groups(persistentid); "
2015-01-08 18:28:06 -05:00
# define I_PAIRING \
" CREATE INDEX IF NOT EXISTS idx_pairingguid ON pairings(guid); "
2015-12-27 01:16:50 -05:00
# define I_DIR_VPATH \
" CREATE INDEX IF NOT EXISTS idx_dir_vpath ON directories(disabled, virtual_path); "
# define I_DIR_PARENT \
" CREATE INDEX IF NOT EXISTS idx_dir_parentid ON directories(parent_id); "
2015-01-08 18:28:06 -05:00
static const struct db_init_query db_init_index_queries [ ] =
{
2011-06-12 05:06:37 -04:00
{ I_RESCAN , " create rescan index " } ,
2013-12-17 14:58:55 -05:00
{ I_SONGARTISTID , " create songartistid index " } ,
2011-06-12 05:22:57 -04:00
{ I_SONGALBUMID , " create songalbumid index " } ,
2013-12-17 14:58:55 -05:00
{ I_STATEMKINDSARI , " create state/mkind/sari index " } ,
{ I_STATEMKINDSALI , " create state/mkind/sali index " } ,
2011-06-12 05:06:37 -04:00
2015-01-08 16:40:47 -05:00
{ I_ARTIST , " create artist index " } ,
2011-06-12 05:30:13 -04:00
{ I_ALBUMARTIST , " create album_artist index " } ,
2015-01-08 16:40:47 -05:00
{ I_COMPOSER , " create composer index " } ,
2015-01-09 18:45:19 -05:00
{ I_GENRE , " create genre index " } ,
2015-01-08 16:40:47 -05:00
{ I_TITLE , " create title index " } ,
{ I_ALBUM , " create album index " } ,
2015-02-14 02:46:21 -05:00
{ I_FILELIST , " create filelist index " } ,
2015-12-27 01:16:50 -05:00
{ I_FILE_DIR , " create file dir index " } ,
2011-06-12 05:30:13 -04:00
2011-06-26 10:20:31 -04:00
{ I_PL_PATH , " create playlist path index " } ,
{ I_PL_DISABLED , " create playlist state index " } ,
2015-12-27 01:16:50 -05:00
{ I_PL_DIR , " create playlist dir index " } ,
2011-06-26 10:20:31 -04:00
2009-06-11 14:27:31 -04:00
{ I_FILEPATH , " create file path index " } ,
2009-06-07 12:56:35 -04:00
{ I_PLITEMID , " create playlist id index " } ,
2011-06-26 10:22:56 -04:00
2015-01-09 17:04:50 -05:00
{ I_GRP_PERSIST , " create groups persistentid index " } ,
2011-06-26 10:22:56 -04:00
2010-01-30 11:01:27 -05:00
{ I_PAIRING , " create pairing guid index " } ,
2015-12-27 01:16:50 -05:00
{ I_DIR_VPATH , " create directories disabled_virtualpath index " } ,
{ I_DIR_PARENT , " create directories parentid index " } ,
2015-01-08 18:28:06 -05:00
} ;
2010-01-21 11:51:44 -05:00
2015-01-08 18:28:06 -05:00
static int
db_create_indices ( void )
{
char * errmsg ;
int i ;
int ret ;
2015-01-08 16:40:47 -05:00
2015-01-08 18:28:06 -05:00
for ( i = 0 ; i < ( sizeof ( db_init_index_queries ) / sizeof ( db_init_index_queries [ 0 ] ) ) ; i + + )
{
DPRINTF ( E_DBG , L_DB , " DB init index query: %s \n " , db_init_index_queries [ i ] . desc ) ;
2010-01-21 11:51:44 -05:00
2015-01-08 18:28:06 -05:00
ret = sqlite3_exec ( hdl , db_init_index_queries [ i ] . query , NULL , NULL , & errmsg ) ;
if ( ret ! = SQLITE_OK )
{
DPRINTF ( E_FATAL , L_DB , " DB init error: %s \n " , errmsg ) ;
sqlite3_free ( errmsg ) ;
return - 1 ;
}
}
return 0 ;
}
2014-12-21 14:41:44 -05:00
static int
2015-12-19 01:51:10 -05:00
db_create_tables ( void )
2014-12-21 14:41:44 -05:00
{
char * errmsg ;
2015-12-19 01:51:10 -05:00
int i ;
2014-12-21 14:41:44 -05:00
int ret ;
2015-12-19 01:51:10 -05:00
for ( i = 0 ; i < ( sizeof ( db_init_table_queries ) / sizeof ( db_init_table_queries [ 0 ] ) ) ; i + + )
2014-12-21 14:41:44 -05:00
{
2015-12-19 01:51:10 -05:00
DPRINTF ( E_DBG , L_DB , " DB init table query: %s \n " , db_init_table_queries [ i ] . desc ) ;
2014-12-21 14:41:44 -05:00
2015-12-19 01:51:10 -05:00
ret = sqlite3_exec ( hdl , db_init_table_queries [ i ] . query , NULL , NULL , & errmsg ) ;
2014-12-21 14:41:44 -05:00
if ( ret ! = SQLITE_OK )
{
2015-12-19 01:51:10 -05:00
DPRINTF ( E_FATAL , L_DB , " DB init error: %s \n " , errmsg ) ;
2014-12-21 14:41:44 -05:00
sqlite3_free ( errmsg ) ;
2015-12-19 01:51:10 -05:00
return - 1 ;
2014-12-21 14:41:44 -05:00
}
}
2015-12-19 01:51:10 -05:00
ret = db_create_indices ( ) ;
2014-12-21 14:41:44 -05:00
2015-12-19 01:51:10 -05:00
return ret ;
2014-12-21 14:41:44 -05:00
}
2015-02-26 08:09:14 -05:00
2009-06-08 12:41:59 -04:00
static int
db_check_version ( void )
{
2009-12-26 03:18:56 -05:00
# define Q_VACUUM "VACUUM;"
2015-01-14 14:32:36 -05:00
char * buf ;
2009-12-26 03:18:56 -05:00
char * errmsg ;
2015-01-14 14:32:36 -05:00
int db_ver_major ;
int db_ver_minor ;
int db_ver ;
int vacuum ;
2009-06-08 12:41:59 -04:00
int ret ;
2015-01-14 14:32:36 -05:00
vacuum = cfg_getbool ( cfg_getsec ( cfg , " sqlite " ) , " vacuum " ) ;
2009-06-08 12:41:59 -04:00
2015-01-14 14:32:36 -05:00
buf = db_admin_get ( " schema_version_major " ) ;
if ( ! buf )
buf = db_admin_get ( " schema_version " ) ; // Pre schema v15.1
if ( ! buf )
return 1 ; // Will create new database
safe_atoi32 ( buf , & db_ver_major ) ;
free ( buf ) ;
buf = db_admin_get ( " schema_version_minor " ) ;
if ( buf )
2009-06-08 12:41:59 -04:00
{
2015-01-14 14:32:36 -05:00
safe_atoi32 ( buf , & db_ver_minor ) ;
free ( buf ) ;
2009-06-08 12:41:59 -04:00
}
2015-01-14 14:32:36 -05:00
else
db_ver_minor = 0 ;
2009-06-08 12:41:59 -04:00
2015-01-14 14:32:36 -05:00
db_ver = db_ver_major * 100 + db_ver_minor ;
if ( db_ver_major < 10 )
2009-06-08 12:41:59 -04:00
{
2015-01-14 14:32:36 -05:00
DPRINTF ( E_FATAL , L_DB , " Database schema v%d too old, cannot upgrade \n " , db_ver_major ) ;
2009-06-08 12:41:59 -04:00
return - 1 ;
}
2015-01-14 14:32:36 -05:00
else if ( db_ver_major > SCHEMA_VERSION_MAJOR )
2011-03-15 16:24:39 -04:00
{
2015-01-14 14:32:36 -05:00
DPRINTF ( E_FATAL , L_DB , " Database schema v%d is newer than the supported version \n " , db_ver_major ) ;
2011-03-15 16:24:39 -04:00
return - 1 ;
}
2015-01-14 14:32:36 -05:00
else if ( db_ver < ( SCHEMA_VERSION_MAJOR * 100 + SCHEMA_VERSION_MINOR ) )
2009-06-08 12:41:59 -04:00
{
2015-01-14 14:46:03 -05:00
DPRINTF ( E_LOG , L_DB , " Database schema outdated, upgrading schema v%d.%d -> v%d.%d... \n " ,
2015-01-14 14:32:36 -05:00
db_ver_major , db_ver_minor , SCHEMA_VERSION_MAJOR , SCHEMA_VERSION_MINOR ) ;
2015-02-26 08:09:14 -05:00
ret = sqlite3_exec ( hdl , " BEGIN TRANSACTION; " , NULL , NULL , & errmsg ) ;
if ( ret ! = SQLITE_OK )
2009-12-26 03:18:56 -05:00
{
2015-02-26 08:09:14 -05:00
DPRINTF ( E_LOG , L_DB , " DB error while running 'BEGIN TRANSACTION': %s \n " , errmsg ) ;
2014-01-11 17:05:29 -05:00
2015-02-26 08:09:14 -05:00
sqlite3_free ( errmsg ) ;
return - 1 ;
}
2014-12-21 14:41:44 -05:00
2015-12-19 01:51:10 -05:00
ret = db_upgrade ( hdl , db_ver ) ;
if ( ret < 0 )
{
DPRINTF ( E_LOG , L_DB , " Database upgrade errored out, rolling back changes ... \n " ) ;
ret = sqlite3_exec ( hdl , " ROLLBACK TRANSACTION; " , NULL , NULL , & errmsg ) ;
if ( ret ! = SQLITE_OK )
{
DPRINTF ( E_LOG , L_DB , " DB error while running 'ROLLBACK TRANSACTION': %s \n " , errmsg ) ;
sqlite3_free ( errmsg ) ;
}
return - 1 ;
}
ret = db_create_indices ( ) ;
2015-02-26 08:09:14 -05:00
if ( ret < 0 )
{
DPRINTF ( E_LOG , L_DB , " Database upgrade errored out, rolling back changes ... \n " ) ;
ret = sqlite3_exec ( hdl , " ROLLBACK TRANSACTION; " , NULL , NULL , & errmsg ) ;
if ( ret ! = SQLITE_OK )
{
DPRINTF ( E_LOG , L_DB , " DB error while running 'ROLLBACK TRANSACTION': %s \n " , errmsg ) ;
2014-12-21 14:41:44 -05:00
2015-02-26 08:09:14 -05:00
sqlite3_free ( errmsg ) ;
}
2014-12-21 14:41:44 -05:00
2015-02-26 08:09:14 -05:00
return - 1 ;
}
2015-01-14 14:37:29 -05:00
2015-02-26 08:09:14 -05:00
ret = sqlite3_exec ( hdl , " COMMIT TRANSACTION; " , NULL , NULL , & errmsg ) ;
if ( ret ! = SQLITE_OK )
{
DPRINTF ( E_LOG , L_DB , " DB error while running 'COMMIT TRANSACTION': %s \n " , errmsg ) ;
2009-12-26 03:18:56 -05:00
2015-02-26 08:09:14 -05:00
sqlite3_free ( errmsg ) ;
return - 1 ;
2009-12-26 03:18:56 -05:00
}
2015-02-26 08:09:14 -05:00
DPRINTF ( E_LOG , L_DB , " Upgrading schema to v%d.%d completed \n " , SCHEMA_VERSION_MAJOR , SCHEMA_VERSION_MINOR ) ;
2015-01-08 18:28:06 -05:00
2015-02-26 08:09:14 -05:00
vacuum = 1 ;
2015-01-14 14:32:36 -05:00
}
2009-12-26 03:18:56 -05:00
2015-01-14 14:32:36 -05:00
if ( vacuum )
2009-06-08 12:41:59 -04:00
{
2015-01-14 14:46:03 -05:00
DPRINTF ( E_LOG , L_DB , " Now vacuuming database, this may take some time... \n " ) ;
2015-01-10 16:44:26 -05:00
2015-01-14 14:32:36 -05:00
ret = sqlite3_exec ( hdl , Q_VACUUM , NULL , NULL , & errmsg ) ;
if ( ret ! = SQLITE_OK )
{
DPRINTF ( E_LOG , L_DB , " Could not VACUUM database: %s \n " , errmsg ) ;
2009-06-08 12:41:59 -04:00
2015-01-14 14:32:36 -05:00
sqlite3_free ( errmsg ) ;
return - 1 ;
}
}
2015-01-10 16:44:26 -05:00
2009-06-08 12:41:59 -04:00
return 0 ;
2009-12-26 03:18:56 -05:00
# undef Q_VACUUM
2009-06-08 12:41:59 -04:00
}
2009-06-07 12:56:35 -04:00
int
db_init ( void )
{
int files ;
int pls ;
int ret ;
2010-03-21 06:33:05 -04:00
db_path = cfg_getstr ( cfg_getsec ( cfg , " general " ) , " db_path " ) ;
2010-04-26 12:24:09 -04:00
ret = sqlite3_config ( SQLITE_CONFIG_MULTITHREAD ) ;
2010-04-26 12:24:09 -04:00
if ( ret ! = SQLITE_OK )
{
2010-04-26 12:24:09 -04:00
DPRINTF ( E_FATAL , L_DB , " Could not switch SQLite3 to multithread mode \n " ) ;
DPRINTF ( E_FATAL , L_DB , " Check that SQLite3 has been configured for thread-safe operations \n " ) ;
2010-04-26 12:24:09 -04:00
return - 1 ;
}
2010-04-27 13:46:39 -04:00
ret = sqlite3_enable_shared_cache ( 1 ) ;
if ( ret ! = SQLITE_OK )
{
DPRINTF ( E_FATAL , L_DB , " Could not enable SQLite3 shared-cache mode \n " ) ;
return - 1 ;
}
2010-04-26 12:24:09 -04:00
ret = sqlite3_initialize ( ) ;
if ( ret ! = SQLITE_OK )
2009-06-07 12:56:35 -04:00
{
2010-04-26 12:24:09 -04:00
DPRINTF ( E_FATAL , L_DB , " SQLite3 failed to initialize \n " ) ;
2009-06-07 12:56:35 -04:00
return - 1 ;
}
ret = db_perthread_init ( ) ;
if ( ret < 0 )
return ret ;
2009-06-08 12:41:59 -04:00
ret = db_check_version ( ) ;
if ( ret < 0 )
2010-04-27 14:48:46 -04:00
{
DPRINTF ( E_FATAL , L_DB , " Database version check errored out, incompatible database \n " ) ;
db_perthread_deinit ( ) ;
return - 1 ;
}
else if ( ret > 0 )
2009-06-08 12:41:59 -04:00
{
2015-01-14 14:32:36 -05:00
DPRINTF ( E_LOG , L_DB , " Could not check database version, trying DB init \n " ) ;
2010-01-21 11:51:00 -05:00
ret = db_create_tables ( ) ;
if ( ret < 0 )
{
DPRINTF ( E_FATAL , L_DB , " Could not create tables \n " ) ;
db_perthread_deinit ( ) ;
return - 1 ;
}
2009-06-08 12:41:59 -04:00
}
2011-06-11 10:22:05 -04:00
db_analyze ( ) ;
2013-11-30 06:57:38 -05:00
db_set_cfg_names ( ) ;
2009-06-11 12:41:50 -04:00
files = db_files_get_count ( ) ;
pls = db_pl_get_count ( ) ;
2009-06-07 12:56:35 -04:00
db_perthread_deinit ( ) ;
2015-01-14 14:46:03 -05:00
DPRINTF ( E_LOG , L_DB , " Database OK with %d active files and %d active playlists \n " , files , pls ) ;
2009-06-07 12:56:35 -04:00
return 0 ;
}
2010-04-26 12:24:09 -04:00
void
db_deinit ( void )
{
sqlite3_shutdown ( ) ;
}