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"
2016-11-04 10:34:00 -04:00
# include "listener.h"
2010-03-06 11:21:54 -05:00
# include "misc.h"
2009-06-07 12:56:35 -04:00
# include "db.h"
2016-11-04 02:10:36 -04:00
# include "db_init.h"
2015-12-19 01:51:10 -05:00
# include "db_upgrade.h"
2016-11-04 10:34:00 -04:00
# include "rng.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 ) ,
2016-06-11 17:10:13 -04:00
dbgri_offsetof ( song_length ) ,
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 " ,
2016-12-04 02:18:33 -05:00
" ORDER BY pos ASC " ,
" ORDER BY shuffle_pos ASC " ,
2010-08-05 12:24:50 -04:00
} ;
2016-11-04 10:34:00 -04:00
/* Shuffle RNG state */
struct rng_ctx shuffle_rng ;
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 ) ;
2016-11-12 06:35:22 -05:00
static int
db_query_run ( char * query , int free , int cache_update ) ;
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 )
{
2016-11-12 06:35:22 -05:00
# define Q_TMPL "DELETE FROM directories WHERE id >= %d AND db_timestamp < %" PRIi64 ";"
2009-06-07 14:49:13 -04:00
int i ;
int ret ;
2016-11-12 06:35:22 -05:00
char * query ;
char * queries_tmpl [ 3 ] =
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 " ; " ,
2009-06-07 14:49:13 -04:00
} ;
2016-12-27 15:31:01 -05:00
db_transaction_begin ( ) ;
2009-06-07 14:49:13 -04:00
for ( i = 0 ; i < ( sizeof ( queries_tmpl ) / sizeof ( queries_tmpl [ 0 ] ) ) ; i + + )
{
2016-11-12 06:35:22 -05:00
query = sqlite3_mprintf ( queries_tmpl [ i ] , PL_SPECIAL , ( int64_t ) ref ) ;
if ( ! query )
2009-06-07 14:49:13 -04:00
{
DPRINTF ( E_LOG , L_DB , " Out of memory for query string \n " ) ;
2016-12-27 15:31:01 -05:00
db_transaction_end ( ) ;
2016-11-12 06:35:22 -05:00
return ;
2009-06-07 14:49:13 -04:00
}
2016-11-12 06:35:22 -05:00
DPRINTF ( E_DBG , L_DB , " Running purge query '%s' \n " , query ) ;
2009-06-07 14:49:13 -04:00
2016-11-12 06:35:22 -05:00
ret = db_query_run ( query , 1 , 0 ) ;
if ( ret = = 0 )
2009-06-07 14:49:13 -04:00
DPRINTF ( E_DBG , L_DB , " Purged %d rows \n " , sqlite3_changes ( hdl ) ) ;
}
2016-11-12 06:35:22 -05:00
query = sqlite3_mprintf ( Q_TMPL , DIR_MAX , ( int64_t ) ref ) ;
if ( ! query )
2009-06-07 14:49:13 -04:00
{
2016-11-12 06:35:22 -05:00
DPRINTF ( E_LOG , L_DB , " Out of memory for query string \n " ) ;
2016-12-27 15:31:01 -05:00
db_transaction_end ( ) ;
2016-11-12 06:35:22 -05:00
return ;
2009-06-07 14:49:13 -04:00
}
2016-11-12 06:35:22 -05:00
DPRINTF ( E_DBG , L_DB , " Running purge query '%s' \n " , query ) ;
2016-12-18 15:18:15 -05:00
ret = db_query_run ( query , 1 , 1 ) ;
2016-11-12 06:35:22 -05:00
if ( ret = = 0 )
DPRINTF ( E_DBG , L_DB , " Purged %d rows \n " , sqlite3_changes ( hdl ) ) ;
2016-12-27 15:31:01 -05:00
db_transaction_end ( ) ;
2016-11-12 06:35:22 -05:00
# undef Q_TMPL
2009-06-07 14:49:13 -04:00
}
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
2016-12-09 10:20:03 -05:00
db_get_one_int ( 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 ) ;
}
}
2016-11-04 10:34:00 -04:00
void
db_transaction_rollback ( void )
{
char * query = " ROLLBACK 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 ) ;
}
}
2014-05-11 17:13:09 -04:00
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 ;
}
2016-12-09 10:20:03 -05:00
qp - > results = db_get_one_int ( 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 ;
2016-12-09 10:20:03 -05:00
qp - > results = db_get_one_int ( " 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 ;
}
2016-12-09 10:20:03 -05:00
qp - > results = db_get_one_int ( 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 ;
}
2016-12-09 10:20:03 -05:00
qp - > results = db_get_one_int ( count ) ;
2010-01-21 11:52:51 -05: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 ) ;
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 ;
2016-12-09 10:20:03 -05:00
qp - > results = db_get_one_int ( " 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 )
2016-06-11 17:10:13 -04:00
query = sqlite3_mprintf ( " SELECT g.id, g.persistentid, f.album, f.album_sort, COUNT(f.id), 1, f.album_artist, f.songartistid, SUM(f.song_length) 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 )
2016-06-11 17:10:13 -04:00
query = sqlite3_mprintf ( " SELECT g.id, g.persistentid, f.album, f.album_sort, COUNT(f.id), 1, f.album_artist, f.songartistid, SUM(f.song_length) 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 )
2016-06-11 17:10:13 -04:00
query = sqlite3_mprintf ( " SELECT g.id, g.persistentid, f.album, f.album_sort, COUNT(f.id), 1, f.album_artist, f.songartistid, SUM(f.song_length) 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
2016-06-11 17:10:13 -04:00
query = sqlite3_mprintf ( " SELECT g.id, g.persistentid, f.album, f.album_sort, COUNT(f.id), 1, f.album_artist, f.songartistid, SUM(f.song_length) 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 ;
2016-12-09 10:20:03 -05:00
qp - > results = db_get_one_int ( " 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 )
2016-06-11 17:10:13 -04: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, SUM(f.song_length) 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 )
2016-06-11 17:10:13 -04: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, SUM(f.song_length) 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 )
2016-06-11 17:10:13 -04: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, SUM(f.song_length) 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
2016-06-11 17:10:13 -04: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, SUM(f.song_length) 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 ;
}
2016-12-09 10:20:03 -05:00
qp - > results = db_get_one_int ( count ) ;
2010-03-07 06:53:23 -05:00
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 ;
}
2016-12-09 10:20:03 -05:00
qp - > results = db_get_one_int ( count ) ;
2010-03-07 06:53:23 -05:00
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 ;
}
2016-12-09 10:20:03 -05:00
qp - > results = db_get_one_int ( 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
2016-02-21 12:05:11 -05:00
db_query_fetch_pl ( struct query_params * qp , struct db_playlist_info * dbpli , int with_itemcount )
2009-06-07 12:56:35 -04:00
{
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 ) ;
}
2016-02-21 12:05:11 -05:00
if ( with_itemcount )
2010-01-21 11:52:51 -05:00
{
2016-02-21 12:05:11 -05:00
type = sqlite3_column_int ( qp - > stmt , 2 ) ;
2010-01-21 11:52:51 -05:00
2016-02-21 12:05:11 -05:00
switch ( type )
{
case PL_PLAIN :
case PL_FOLDER :
id = sqlite3_column_int ( qp - > stmt , 0 ) ;
nitems = db_pl_count_items ( id , 0 ) ;
nstreams = db_pl_count_items ( id , 1 ) ;
break ;
case PL_SPECIAL :
case PL_SMART :
nitems = db_smartpl_count_items ( dbpli - > query ) ;
nstreams = 0 ;
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
2016-02-21 12:05:11 -05:00
dbpli - > items = qp - > buf1 ;
ret = snprintf ( qp - > buf1 , sizeof ( qp - > buf1 ) , " %d " , nitems ) ;
if ( ( ret < 0 ) | | ( ret > = sizeof ( qp - > buf1 ) ) )
{
DPRINTF ( E_LOG , L_DB , " Could not convert item count, buffer too small \n " ) ;
2009-06-11 12:28:01 -04:00
2016-02-21 12:05:11 -05: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 " ) ;
2015-03-16 18:33:42 -04:00
2016-02-21 12:05:11 -05:00
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
{
2016-12-09 10:20:03 -05:00
return db_get_one_int ( " 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 )
{
2016-12-09 10:20:03 -05:00
return db_get_one_int ( " SELECT COUNT(DISTINCT songartistid) FROM files f WHERE f . disabled = 0 ; " );
2015-11-01 03:15:24 -05:00
}
int
db_files_get_album_count ( void )
{
2016-12-09 10:20:03 -05:00
return db_get_one_int ( " SELECT COUNT(DISTINCT songalbumid) FROM files f WHERE f . disabled = 0 ; " );
2015-11-01 03:15:24 -05:00
}
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
}
2016-12-09 10:20:03 -05:00
count = db_get_one_int ( query ) ;
2013-08-21 17:16:25 -04:00
sqlite3_free ( query ) ;
return count ;
2013-11-30 17:12:09 -05:00
# undef Q_TMPL
2013-08-21 17:16:25 -04: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
2016-12-18 15:18:15 -05: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_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 ) ;
2016-12-18 15:18:15 -05: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
}
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
}
2009-11-22 10:30:45 -05:00
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 ;
2016-12-16 12:38:28 -05:00
* id = 0 ;
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, " \
2016-02-12 18:27:22 -05:00
" directory_id, date_released) " \
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))), " \
2016-02-12 18:27:22 -05:00
" TRIM(%Q), TRIM(%Q), TRIM(%Q), TRIM(%Q), TRIM(%Q), TRIM(%Q), %d, %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 ,
2016-02-12 18:27:22 -05:00
mfi - > composer_sort , mfi - > album_artist_sort , mfi - > virtual_path , mfi - > directory_id , mfi - > date_released ) ;
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), " \
2016-02-12 18:27:22 -05:00
" virtual_path = TRIM(%Q), directory_id = %d, date_released = %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 ,
2016-02-12 18:27:22 -05:00
mfi - > composer_sort , mfi - > album_artist_sort ,
mfi - > virtual_path , mfi - > directory_id , mfi - > date_released ,
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-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
{
2016-12-09 10:20:03 -05:00
return db_get_one_int ( " 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 ;
}
2016-12-09 10:20:03 -05:00
ret = db_get_one_int ( query ) ;
2009-06-11 12:28:01 -04:00
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 ;
}
2016-12-09 10:20:03 -05:00
ret = db_get_one_int ( query ) ;
2010-01-21 11:52:51 -05:00
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 ;
}
2016-12-09 10:20:03 -05:00
ret = db_get_one_int ( 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 */
2016-12-18 15:18:15 -05:00
// Remove album and artist entries in the groups table that are not longer referenced from the files table
2016-12-14 13:28:27 -05:00
int
db_groups_cleanup ( )
{
# define Q_TMPL_ALBUM "DELETE FROM groups WHERE type = 1 AND NOT persistentid IN (SELECT songalbumid from files WHERE disabled = 0);"
# define Q_TMPL_ARTIST "DELETE FROM groups WHERE type = 2 AND NOT persistentid IN (SELECT songartistid from files WHERE disabled = 0);"
int ret ;
db_transaction_begin ( ) ;
2016-12-18 15:18:15 -05:00
ret = db_query_run ( Q_TMPL_ALBUM , 0 , 1 ) ;
2016-12-14 13:28:27 -05:00
if ( ret < 0 )
{
db_transaction_rollback ( ) ;
return - 1 ;
}
DPRINTF ( E_DBG , L_DB , " Removed album group-entries: %d \n " , sqlite3_changes ( hdl ) ) ;
2016-12-18 15:18:15 -05:00
ret = db_query_run ( Q_TMPL_ARTIST , 0 , 1 ) ;
2016-12-14 13:28:27 -05:00
if ( ret < 0 )
{
db_transaction_rollback ( ) ;
return - 1 ;
}
DPRINTF ( E_DBG , L_DB , " Removed artist group-entries: %d \n " , sqlite3_changes ( hdl ) ) ;
db_transaction_end ( ) ;
return 0 ;
# undef Q_TMPL_ALBUM
# undef Q_TMPL_ARTIST
}
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 ) ;
2016-12-18 15:18:15 -05:00
db_query_run ( query , 1 , 0 ) ;
2015-12-27 01:16:50 -05:00
# 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 ) ;
2016-12-18 15:18:15 -05:00
ret = db_query_run ( query , 1 , 1 ) ;
2015-12-27 01:16:50 -05:00
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 ) ;
2016-12-18 15:18:15 -05:00
ret = db_query_run ( query , 1 , 1 ) ;
2016-01-30 01:27:20 -05:00
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-11-12 06:35:22 -05:00
# define Q_TMPL "UPDATE directories SET disabled = %" PRIi64 " WHERE virtual_path = ' / spotify:';"
char * queries [ 4 ] =
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:/%%'; " ,
2014-03-11 18:20:29 -04:00
} ;
2016-11-12 06:35:22 -05:00
char * query ;
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 )
2016-11-13 14:28:29 -05:00
DPRINTF ( E_DBG , L_DB , " Processed %d rows \n " , sqlite3_changes ( hdl ) ) ;
2014-03-11 18:20:29 -04:00
}
2016-11-12 06:35:22 -05:00
// Disable the spotify directory by setting 'disabled' to INOTIFY_FAKE_COOKIE value
query = sqlite3_mprintf ( Q_TMPL , INOTIFY_FAKE_COOKIE ) ;
if ( ! query )
{
DPRINTF ( E_LOG , L_DB , " Out of memory for query string \n " ) ;
return ;
}
ret = db_query_run ( query , 1 , 1 ) ;
if ( ret = = 0 )
DPRINTF ( E_DBG , L_DB , " Disabled spotify directory \n " ) ;
# undef Q_TMPL
2014-03-11 18:20:29 -04:00
}
/* 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
2016-11-13 14:28:29 -05:00
db_spotify_files_delete ( void )
2016-01-16 11:02:03 -05:00
{
# 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
2016-12-09 10:31:42 -05:00
db_admin_set ( const char * key , const char * value )
2014-08-15 16:54:47 -04:00
{
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_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
}
2016-11-04 10:34:00 -04:00
/* Queue */
2010-11-02 13:40:14 -04:00
2016-11-04 10:34:00 -04:00
void
free_queue_item ( struct db_queue_item * queue_item , int content_only )
{
if ( queue_item - > path )
free ( queue_item - > path ) ;
if ( queue_item - > virtual_path )
free ( queue_item - > virtual_path ) ;
if ( queue_item - > title )
free ( queue_item - > title ) ;
if ( queue_item - > artist )
free ( queue_item - > artist ) ;
if ( queue_item - > album_artist )
free ( queue_item - > album_artist ) ;
if ( queue_item - > album )
free ( queue_item - > album ) ;
if ( queue_item - > genre )
free ( queue_item - > genre ) ;
if ( queue_item - > artist_sort )
free ( queue_item - > artist_sort ) ;
if ( queue_item - > album_sort )
free ( queue_item - > album_sort ) ;
if ( queue_item - > album_artist_sort )
free ( queue_item - > album_artist_sort ) ;
if ( ! content_only & & queue_item )
free ( queue_item ) ;
2009-06-10 12:11:11 -04:00
}
2016-11-04 10:34:00 -04:00
/*
* Returns the queue version from the admin table
*
* @ return queue version
*/
2009-06-10 12:11:11 -04:00
int
2016-11-04 10:34:00 -04:00
db_queue_get_version ( )
2009-06-10 12:11:11 -04:00
{
2016-11-04 10:34:00 -04:00
char * version ;
2016-12-03 01:00:28 -05:00
int32_t queue_version ;
2016-11-04 10:34:00 -04:00
int ret ;
2009-06-10 12:11:11 -04:00
2016-12-03 01:00:28 -05:00
queue_version = 0 ;
version = db_admin_get ( " queue_version " ) ;
2016-11-04 10:34:00 -04:00
if ( version )
{
2016-12-03 01:00:28 -05:00
ret = safe_atoi32 ( version , & queue_version ) ;
2016-11-04 10:34:00 -04:00
free ( version ) ;
if ( ret < 0 )
{
DPRINTF ( E_LOG , L_DB , " Could not get playlist version \n " ) ;
return - 1 ;
}
}
2009-06-11 10:12:17 -04:00
2016-12-03 01:00:28 -05:00
return queue_version ;
2009-06-11 10:12:17 -04:00
}
2016-11-04 10:34:00 -04:00
/*
* Increments the version of the queue in the admin table and notifies listener of LISTENER_PLAYLIST
* about the change .
*
* This function must be called after successfully modifying the queue table in order to send
* notification messages to the clients ( e . g . dacp or mpd clients ) .
*/
static void
queue_inc_version_and_notify ( )
2009-06-11 10:12:17 -04:00
{
2016-12-03 01:00:28 -05:00
int queue_version ;
2016-11-04 10:34:00 -04:00
char version [ 10 ] ;
int ret ;
2009-06-11 10:12:17 -04:00
2016-11-04 10:34:00 -04:00
db_transaction_begin ( ) ;
2009-06-11 10:12:17 -04:00
2016-12-03 01:00:28 -05:00
queue_version = db_queue_get_version ( ) ;
if ( queue_version < 0 )
queue_version = 0 ;
2009-06-11 10:12:17 -04:00
2016-12-03 01:00:28 -05:00
queue_version + + ;
ret = snprintf ( version , sizeof ( version ) , " %d " , queue_version ) ;
2016-11-04 10:34:00 -04:00
if ( ret > = sizeof ( version ) )
{
2016-12-03 01:00:28 -05:00
DPRINTF ( E_LOG , L_DB , " Error incrementing queue version. Could not convert version to string: %d \n " , queue_version ) ;
2016-11-04 10:34:00 -04:00
db_transaction_rollback ( ) ;
return ;
}
2009-06-11 10:12:17 -04:00
2016-12-09 10:31:42 -05:00
ret = db_admin_set ( " queue_version " , version ) ;
2016-11-04 10:34:00 -04:00
if ( ret < 0 )
{
2016-12-03 01:00:28 -05:00
DPRINTF ( E_LOG , L_DB , " Error incrementing queue version. Could not update version in admin table: %d \n " , queue_version ) ;
2016-11-04 10:34:00 -04:00
db_transaction_rollback ( ) ;
return ;
}
2009-06-11 10:12:17 -04:00
2016-11-04 10:34:00 -04:00
db_transaction_end ( ) ;
listener_notify ( LISTENER_PLAYLIST ) ;
2009-06-11 10:12:17 -04:00
}
2016-11-12 07:23:41 -05:00
void
db_queue_update_icymetadata ( int id , char * artist , char * album )
{
# define Q_TMPL "UPDATE queue 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 ;
}
db_query_run ( query , 1 , 0 ) ;
queue_inc_version_and_notify ( ) ;
# undef Q_TMPL
}
2016-11-04 10:34:00 -04:00
static int
2016-12-03 01:07:01 -05:00
queue_add_file ( struct db_media_file_info * dbmfi , int pos , int shuffle_pos )
2016-11-04 10:34:00 -04:00
{
# define Q_TMPL "INSERT INTO queue " \
" (id, file_id, song_length, data_kind, media_kind, " \
" pos, shuffle_pos, path, virtual_path, title, " \
" artist, album_artist, album, genre, songalbumid, " \
" time_modified, artist_sort, album_sort, album_artist_sort, year, " \
" track, disc) " \
" VALUES " \
" (NULL, %s, %s, %s, %s, " \
" %d, %d, %Q, %Q, %Q, " \
" %Q, %Q, %Q, %Q, %s, " \
" %s, %Q, %Q, %Q, %s, " \
" %s, %s); "
2009-06-11 10:12:17 -04:00
char * query ;
2016-11-04 10:34:00 -04:00
int ret ;
2009-06-11 10:12:17 -04:00
2016-11-04 10:34:00 -04:00
query = sqlite3_mprintf ( Q_TMPL ,
dbmfi - > id , dbmfi - > song_length , dbmfi - > data_kind , dbmfi - > media_kind ,
pos , pos , dbmfi - > path , dbmfi - > virtual_path , dbmfi - > title ,
dbmfi - > artist , dbmfi - > album_artist , dbmfi - > album , dbmfi - > genre , dbmfi - > songalbumid ,
dbmfi - > time_modified , dbmfi - > artist_sort , dbmfi - > album_sort , dbmfi - > album_artist_sort , dbmfi - > year ,
dbmfi - > track , dbmfi - > disc ) ;
ret = db_query_run ( query , 1 , 0 ) ;
2009-06-11 10:12:17 -04:00
2016-11-04 10:34:00 -04:00
return ret ;
2009-06-10 12:11:11 -04:00
# undef Q_TMPL
}
2016-11-04 10:34:00 -04:00
/*
* Adds the files matching the given query to the queue after the item with the given item id
*
* The files table is queried with the given parameters and all found files are added after the
* item with the given item id to the " normal " queue . They are appended to end of the shuffled queue
* ( assuming that the shuffled queue will get reshuffled after adding new items ) .
*
* The function returns - 1 on failure ( e . g . error reading from database ) and if the given item id
* does not exist . It wraps all database access in a transaction and performs a rollback if an error
* occurs , leaving the queue in a consistent state .
*
* @ param qp Query parameters for the files table
* @ param item_id Files are added after item with this id
* @ return 0 on success , - 1 on failure
*/
int
db_queue_add_by_queryafteritemid ( struct query_params * qp , uint32_t item_id )
2009-06-10 12:11:11 -04:00
{
2016-11-04 10:34:00 -04:00
struct db_media_file_info dbmfi ;
char * query ;
int shuffle_pos ;
int pos ;
2009-06-10 12:11:11 -04:00
int ret ;
2016-11-04 10:34:00 -04:00
db_transaction_begin ( ) ;
2009-06-10 12:11:11 -04:00
2016-11-04 10:34:00 -04:00
// Position of the first new item
pos = db_queue_get_pos ( item_id , 0 ) ;
if ( pos < 0 )
2009-06-10 12:11:11 -04:00
{
2016-11-04 10:34:00 -04:00
DPRINTF ( E_LOG , L_DB , " Could not fetch queue item for item-id %d \n " , item_id ) ;
db_transaction_rollback ( ) ;
2009-06-10 12:11:11 -04:00
return - 1 ;
}
2016-11-04 10:34:00 -04:00
pos + + ;
2009-06-10 12:11:11 -04:00
2016-11-04 10:34:00 -04:00
// Shuffle position of the first new item
shuffle_pos = db_queue_get_count ( ) ;
if ( shuffle_pos < 0 )
2009-06-10 12:11:11 -04:00
{
2016-11-04 10:34:00 -04:00
DPRINTF ( E_LOG , L_DB , " Could not get count from queue \n " ) ;
db_transaction_rollback ( ) ;
return - 1 ;
}
2009-06-10 12:11:11 -04:00
2016-11-04 10:34:00 -04:00
// Start query for new items from files table
ret = db_query_start ( qp ) ;
if ( ret < 0 )
{
DPRINTF ( E_LOG , L_DB , " Could not start query \n " ) ;
db_transaction_rollback ( ) ;
2009-06-10 12:11:11 -04:00
return - 1 ;
}
2016-11-04 10:34:00 -04:00
DPRINTF ( E_DBG , L_DB , " Player queue query returned %d items \n " , qp - > results ) ;
2009-06-10 12:11:11 -04:00
2016-11-04 10:34:00 -04:00
// Update pos for all items after the item with item_id
query = sqlite3_mprintf ( " UPDATE queue SET pos = pos + %d WHERE pos > %d; " , qp - > results , ( pos - 1 ) ) ;
ret = db_query_run ( query , 1 , 0 ) ;
if ( ret < 0 )
2009-06-10 12:11:11 -04:00
{
2016-11-04 10:34:00 -04:00
db_transaction_rollback ( ) ;
2009-06-10 12:11:11 -04:00
return - 1 ;
}
2016-11-04 10:34:00 -04:00
// Iterate over new items from files table and insert into queue
while ( ( ( ret = db_query_fetch_file ( qp , & dbmfi ) ) = = 0 ) & & ( dbmfi . id ) )
2009-06-10 12:11:11 -04:00
{
2016-12-03 01:07:01 -05:00
ret = queue_add_file ( & dbmfi , pos , shuffle_pos ) ;
2009-06-10 12:11:11 -04:00
2016-11-04 10:34:00 -04:00
if ( ret < 0 )
{
2016-12-03 01:41:12 -05:00
DPRINTF ( E_LOG , L_DB , " Failed to add song with id %s (%s) to queue \n " , dbmfi . id , dbmfi . title ) ;
2016-11-04 10:34:00 -04:00
break ;
}
2009-06-10 12:11:11 -04:00
2016-11-04 10:34:00 -04:00
DPRINTF ( E_DBG , L_DB , " Added song with id %s (%s) to queue \n " , dbmfi . id , dbmfi . title ) ;
shuffle_pos + + ;
pos + + ;
}
2009-06-10 12:11:11 -04:00
2016-11-04 10:34:00 -04:00
db_query_end ( qp ) ;
2009-06-10 12:11:11 -04:00
2016-11-04 10:34:00 -04:00
if ( ret < 0 )
{
DPRINTF ( E_LOG , L_DB , " Error fetching results \n " ) ;
db_transaction_rollback ( ) ;
return - 1 ;
2009-06-10 12:11:11 -04:00
}
2016-11-04 10:34:00 -04:00
db_transaction_end ( ) ;
2011-06-11 11:24:59 -04:00
2016-11-04 10:34:00 -04:00
queue_inc_version_and_notify ( ) ;
2009-06-10 12:11:11 -04:00
return 0 ;
2014-06-09 17:42:02 -04:00
}
2016-11-04 10:34:00 -04:00
/*
* Adds the files matching the given query to the queue
*
* The files table is queried with the given parameters and all found files are added to the end of the
* " normal " queue and the shuffled queue .
*
* The function returns - 1 on failure ( e . g . error reading from database ) . It wraps all database access
* in a transaction and performs a rollback if an error occurs , leaving the queue in a consistent state .
*
* @ param qp Query parameters for the files table
* @ param reshuffle If 1 queue will be reshuffled after adding new items
* @ param item_id The base item id , all items after this will be reshuffled
* @ return 0 on success , - 1 on failure
*/
2014-06-09 17:42:02 -04:00
int
2016-11-04 10:34:00 -04:00
db_queue_add_by_query ( struct query_params * qp , char reshuffle , uint32_t item_id )
2014-06-09 17:42:02 -04:00
{
2016-11-04 10:34:00 -04:00
struct db_media_file_info dbmfi ;
int pos ;
int ret ;
2014-06-09 17:42:02 -04:00
2016-11-04 10:34:00 -04:00
db_transaction_begin ( ) ;
pos = db_queue_get_count ( ) ;
if ( pos < 0 )
2014-06-09 17:42:02 -04:00
{
2016-11-04 10:34:00 -04:00
DPRINTF ( E_LOG , L_DB , " Could not get count from queue \n " ) ;
db_transaction_rollback ( ) ;
2014-06-09 17:42:02 -04:00
return - 1 ;
}
2016-11-04 10:34:00 -04:00
ret = db_query_start ( qp ) ;
if ( ret < 0 )
{
DPRINTF ( E_LOG , L_DB , " Could not start query \n " ) ;
db_transaction_rollback ( ) ;
return - 1 ;
}
2014-06-09 17:42:02 -04:00
2016-11-04 10:34:00 -04:00
DPRINTF ( E_DBG , L_DB , " Player queue query returned %d items \n " , qp - > results ) ;
2014-06-09 17:42:02 -04:00
2016-11-04 10:34:00 -04:00
while ( ( ( ret = db_query_fetch_file ( qp , & dbmfi ) ) = = 0 ) & & ( dbmfi . id ) )
2014-06-09 17:42:02 -04:00
{
2016-12-03 01:07:01 -05:00
ret = queue_add_file ( & dbmfi , pos , pos ) ;
2016-11-04 10:34:00 -04:00
if ( ret < 0 )
{
DPRINTF ( E_DBG , L_DB , " Failed to add song id %s (%s) \n " , dbmfi . id , dbmfi . title ) ;
break ;
}
DPRINTF ( E_DBG , L_DB , " Added song id %s (%s) to queue \n " , dbmfi . id , dbmfi . title ) ;
pos + + ;
}
db_query_end ( qp ) ;
if ( ret < 0 )
{
DPRINTF ( E_LOG , L_DB , " Error fetching results \n " ) ;
db_transaction_rollback ( ) ;
2014-06-09 17:42:02 -04:00
return - 1 ;
}
2009-06-10 12:11:11 -04:00
2016-11-04 10:34:00 -04:00
ret = ( int ) sqlite3_last_insert_rowid ( hdl ) ;
db_transaction_end ( ) ;
// Reshuffle after adding new items
if ( reshuffle )
{
db_queue_reshuffle ( item_id ) ;
}
else
{
queue_inc_version_and_notify ( ) ;
}
return ret ;
2009-06-10 12:11:11 -04:00
}
2016-11-04 10:34:00 -04:00
/*
* Adds the items of the stored playlist with the given id to the end of the queue
*
* @ param plid Id of the stored playlist
* @ param reshuffle If 1 queue will be reshuffled after adding new items
* @ param item_id The base item id , all items after this will be reshuffled
* @ return 0 on success , - 1 on failure
*/
int
db_queue_add_by_playlistid ( int plid , char reshuffle , uint32_t item_id )
2009-06-11 09:24:10 -04:00
{
2016-11-04 10:34:00 -04:00
struct query_params qp ;
int ret ;
2009-06-11 09:24:10 -04:00
2016-11-04 10:34:00 -04:00
memset ( & qp , 0 , sizeof ( struct query_params ) ) ;
2009-06-11 09:24:10 -04:00
2016-11-04 10:34:00 -04:00
qp . id = plid ;
qp . type = Q_PLITEMS ;
2009-06-11 09:24:10 -04:00
2016-11-04 10:34:00 -04:00
ret = db_queue_add_by_query ( & qp , reshuffle , item_id ) ;
return ret ;
2009-06-11 09:24:10 -04:00
}
2016-11-04 10:34:00 -04:00
/*
* Adds the file with the given id to the queue
*
* @ param id Id of the file
* @ param reshuffle If 1 queue will be reshuffled after adding new items
* @ param item_id The base item id , all items after this will be reshuffled
* @ return 0 on success , - 1 on failure
*/
int
db_queue_add_by_fileid ( int id , char reshuffle , uint32_t item_id )
2009-06-11 09:24:10 -04:00
{
2016-11-04 10:34:00 -04:00
struct query_params qp ;
char buf [ 124 ] ;
int ret ;
2009-06-11 09:24:10 -04:00
2016-11-04 10:34:00 -04:00
memset ( & qp , 0 , sizeof ( struct query_params ) ) ;
2009-06-11 09:24:10 -04:00
2016-11-04 10:34:00 -04:00
qp . type = Q_ITEMS ;
snprintf ( buf , sizeof ( buf ) , " f.id = % " PRIu32 , id ) ;
qp . filter = buf ;
2009-06-11 09:24:10 -04:00
2016-11-04 10:34:00 -04:00
ret = db_queue_add_by_query ( & qp , reshuffle , item_id ) ;
return ret ;
2009-06-11 09:24:10 -04:00
}
2009-06-10 12:11:11 -04:00
2016-11-04 10:34:00 -04:00
static int
2016-12-04 02:18:33 -05:00
queue_enum_start ( struct query_params * query_params )
2016-11-04 10:34:00 -04:00
{
2016-12-04 05:34:19 -05:00
# define Q_TMPL "SELECT * FROM queue WHERE %s %s;"
2016-11-04 10:34:00 -04:00
char * query ;
2016-12-04 02:18:33 -05:00
const char * orderby ;
2016-11-04 10:34:00 -04:00
int ret ;
2016-12-04 02:18:33 -05:00
query_params - > stmt = NULL ;
2016-11-04 10:34:00 -04:00
2016-12-04 05:34:19 -05:00
if ( query_params - > sort )
2016-12-04 02:18:33 -05:00
orderby = sort_clause [ query_params - > sort ] ;
2016-11-04 10:34:00 -04:00
else
2016-12-04 02:18:33 -05:00
orderby = sort_clause [ S_POS ] ;
2016-11-04 10:34:00 -04:00
2016-12-04 02:18:33 -05:00
if ( query_params - > filter )
query = sqlite3_mprintf ( Q_TMPL , query_params - > filter , orderby ) ;
2016-11-04 10:34:00 -04:00
else
query = sqlite3_mprintf ( Q_TMPL , " 1=1 " , orderby ) ;
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 ) ;
2016-12-04 02:18:33 -05:00
ret = db_blocking_prepare_v2 ( query , - 1 , & query_params - > stmt , NULL ) ;
2016-11-04 10:34:00 -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_TMPL
}
static inline char *
strdup_if ( char * str , int cond )
{
if ( str = = NULL )
return NULL ;
if ( cond )
return strdup ( str ) ;
return str ;
}
static int
2016-12-04 02:18:33 -05:00
queue_enum_fetch ( struct query_params * query_params , struct db_queue_item * queue_item , int keep_item )
2016-11-04 10:34:00 -04:00
{
int ret ;
memset ( queue_item , 0 , sizeof ( struct db_queue_item ) ) ;
2016-12-04 02:18:33 -05:00
if ( ! query_params - > stmt )
2016-11-04 10:34:00 -04:00
{
DPRINTF ( E_LOG , L_DB , " Queue enum not started! \n " ) ;
return - 1 ;
}
2016-12-04 02:18:33 -05:00
ret = db_blocking_step ( query_params - > stmt ) ;
2016-11-04 10:34:00 -04:00
if ( ret = = SQLITE_DONE )
{
DPRINTF ( E_DBG , L_DB , " End of queue 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 ;
}
2016-12-04 02:18:33 -05:00
queue_item - > id = ( uint32_t ) sqlite3_column_int ( query_params - > stmt , 0 ) ;
queue_item - > file_id = ( uint32_t ) sqlite3_column_int ( query_params - > stmt , 1 ) ;
queue_item - > pos = ( uint32_t ) sqlite3_column_int ( query_params - > stmt , 2 ) ;
queue_item - > shuffle_pos = ( uint32_t ) sqlite3_column_int ( query_params - > stmt , 3 ) ;
queue_item - > data_kind = sqlite3_column_int ( query_params - > stmt , 4 ) ;
queue_item - > media_kind = sqlite3_column_int ( query_params - > stmt , 5 ) ;
queue_item - > song_length = ( uint32_t ) sqlite3_column_int ( query_params - > stmt , 6 ) ;
queue_item - > path = strdup_if ( ( char * ) sqlite3_column_text ( query_params - > stmt , 7 ) , keep_item ) ;
queue_item - > virtual_path = strdup_if ( ( char * ) sqlite3_column_text ( query_params - > stmt , 8 ) , keep_item ) ;
queue_item - > title = strdup_if ( ( char * ) sqlite3_column_text ( query_params - > stmt , 9 ) , keep_item ) ;
queue_item - > artist = strdup_if ( ( char * ) sqlite3_column_text ( query_params - > stmt , 10 ) , keep_item ) ;
queue_item - > album_artist = strdup_if ( ( char * ) sqlite3_column_text ( query_params - > stmt , 11 ) , keep_item ) ;
queue_item - > album = strdup_if ( ( char * ) sqlite3_column_text ( query_params - > stmt , 12 ) , keep_item ) ;
queue_item - > genre = strdup_if ( ( char * ) sqlite3_column_text ( query_params - > stmt , 13 ) , keep_item ) ;
queue_item - > songalbumid = sqlite3_column_int64 ( query_params - > stmt , 14 ) ;
queue_item - > time_modified = sqlite3_column_int ( query_params - > stmt , 15 ) ;
queue_item - > artist_sort = strdup_if ( ( char * ) sqlite3_column_text ( query_params - > stmt , 16 ) , keep_item ) ;
queue_item - > album_sort = strdup_if ( ( char * ) sqlite3_column_text ( query_params - > stmt , 17 ) , keep_item ) ;
queue_item - > album_artist_sort = strdup_if ( ( char * ) sqlite3_column_text ( query_params - > stmt , 18 ) , keep_item ) ;
queue_item - > year = sqlite3_column_int ( query_params - > stmt , 19 ) ;
queue_item - > track = sqlite3_column_int ( query_params - > stmt , 20 ) ;
queue_item - > disc = sqlite3_column_int ( query_params - > stmt , 21 ) ;
2016-11-04 10:34:00 -04:00
return 0 ;
}
int
2016-12-04 02:18:33 -05:00
db_queue_enum_start ( struct query_params * query_params )
2016-11-04 10:34:00 -04:00
{
int ret ;
db_transaction_begin ( ) ;
2016-12-04 02:18:33 -05:00
ret = queue_enum_start ( query_params ) ;
2016-11-04 10:34:00 -04:00
if ( ret < 0 )
db_transaction_rollback ( ) ;
return ret ;
}
void
2016-12-04 02:18:33 -05:00
db_queue_enum_end ( struct query_params * query_params )
2016-11-04 10:34:00 -04:00
{
2016-12-04 02:18:33 -05:00
db_query_end ( query_params ) ;
2016-11-04 10:34:00 -04:00
db_transaction_end ( ) ;
}
int
2016-12-04 02:18:33 -05:00
db_queue_enum_fetch ( struct query_params * query_params , struct db_queue_item * queue_item )
2016-11-04 10:34:00 -04:00
{
2016-12-04 02:18:33 -05:00
return queue_enum_fetch ( query_params , queue_item , 0 ) ;
2016-11-04 10:34:00 -04:00
}
int
db_queue_get_pos ( uint32_t item_id , char shuffle )
{
# define Q_TMPL "SELECT pos FROM queue WHERE id = %d;"
# define Q_TMPL_SHUFFLE "SELECT shuffle_pos FROM queue WHERE id = %d;"
char * query ;
int pos ;
if ( shuffle )
query = sqlite3_mprintf ( Q_TMPL_SHUFFLE , item_id ) ;
else
query = sqlite3_mprintf ( Q_TMPL , item_id ) ;
2016-12-09 10:20:03 -05:00
pos = db_get_one_int ( query ) ;
2016-11-04 10:34:00 -04:00
sqlite3_free ( query ) ;
return pos ;
# undef Q_TMPL
# undef Q_TMPL_SHUFFLE
}
int
db_queue_get_pos_byfileid ( uint32_t file_id , char shuffle )
{
# define Q_TMPL "SELECT pos FROM queue WHERE file_id = %d LIMIT 1;"
# define Q_TMPL_SHUFFLE "SELECT shuffle_pos FROM queue WHERE file_id = %d LIMIT 1;"
char * query ;
int pos ;
if ( shuffle )
query = sqlite3_mprintf ( Q_TMPL_SHUFFLE , file_id ) ;
else
query = sqlite3_mprintf ( Q_TMPL , file_id ) ;
2016-12-09 10:20:03 -05:00
pos = db_get_one_int ( query ) ;
2016-11-04 10:34:00 -04:00
sqlite3_free ( query ) ;
return pos ;
# undef Q_TMPL
# undef Q_TMPL_SHUFFLE
}
static int
2016-12-04 03:30:21 -05:00
queue_fetch_byitemid ( uint32_t item_id , struct db_queue_item * queue_item , int with_metadata )
2016-11-04 10:34:00 -04:00
{
2016-12-04 03:30:21 -05:00
struct query_params query_params ;
2016-11-04 10:34:00 -04:00
int ret ;
2016-12-04 03:30:21 -05:00
memset ( & query_params , 0 , sizeof ( struct query_params ) ) ;
query_params . filter = sqlite3_mprintf ( " id = %d " , item_id ) ;
2016-11-04 10:34:00 -04:00
2016-12-04 03:30:21 -05:00
ret = queue_enum_start ( & query_params ) ;
2016-11-04 10:34:00 -04:00
if ( ret < 0 )
{
2016-12-04 03:30:21 -05:00
sqlite3_free ( query_params . filter ) ;
2016-11-04 10:34:00 -04:00
return - 1 ;
}
2016-12-04 03:30:21 -05:00
ret = queue_enum_fetch ( & query_params , queue_item , with_metadata ) ;
db_query_end ( & query_params ) ;
sqlite3_free ( query_params . filter ) ;
2016-11-04 10:34:00 -04:00
return ret ;
}
struct db_queue_item *
db_queue_fetch_byitemid ( uint32_t item_id )
{
struct db_queue_item * queue_item ;
int ret ;
queue_item = calloc ( 1 , sizeof ( struct db_queue_item ) ) ;
if ( ! queue_item )
{
DPRINTF ( E_LOG , L_DB , " Out of memory for queue_item \n " ) ;
return NULL ;
}
db_transaction_begin ( ) ;
2016-12-04 03:30:21 -05:00
ret = queue_fetch_byitemid ( item_id , queue_item , 1 ) ;
2016-11-04 10:34:00 -04:00
db_transaction_end ( ) ;
if ( ret < 0 )
{
free_queue_item ( queue_item , 0 ) ;
DPRINTF ( E_LOG , L_DB , " Error fetching queue item by item id \n " ) ;
return NULL ;
}
2016-12-03 02:03:19 -05:00
else if ( queue_item - > id = = 0 )
2016-11-12 12:45:54 -05:00
{
// No item found
free_queue_item ( queue_item , 0 ) ;
return NULL ;
}
2016-11-04 10:34:00 -04:00
return queue_item ;
}
struct db_queue_item *
db_queue_fetch_byfileid ( uint32_t file_id )
{
struct db_queue_item * queue_item ;
2016-12-04 02:18:33 -05:00
struct query_params query_params ;
2016-11-04 10:34:00 -04:00
int ret ;
2016-12-04 02:18:33 -05:00
memset ( & query_params , 0 , sizeof ( struct query_params ) ) ;
2016-11-04 10:34:00 -04:00
queue_item = calloc ( 1 , sizeof ( struct db_queue_item ) ) ;
if ( ! queue_item )
{
DPRINTF ( E_LOG , L_DB , " Out of memory for queue_item \n " ) ;
return NULL ;
}
db_transaction_begin ( ) ;
2016-12-04 02:18:33 -05:00
query_params . filter = sqlite3_mprintf ( " file_id = %d " , file_id ) ;
2016-11-04 10:34:00 -04:00
2016-12-04 02:18:33 -05:00
ret = queue_enum_start ( & query_params ) ;
2016-11-04 10:34:00 -04:00
if ( ret < 0 )
{
2016-12-04 02:18:33 -05:00
sqlite3_free ( query_params . filter ) ;
2016-11-04 10:34:00 -04:00
db_transaction_end ( ) ;
free_queue_item ( queue_item , 0 ) ;
DPRINTF ( E_LOG , L_DB , " Error fetching queue item by file id \n " ) ;
return NULL ;
}
2016-12-04 02:18:33 -05:00
ret = queue_enum_fetch ( & query_params , queue_item , 1 ) ;
db_query_end ( & query_params ) ;
sqlite3_free ( query_params . filter ) ;
2016-11-04 10:34:00 -04:00
db_transaction_end ( ) ;
if ( ret < 0 )
{
free_queue_item ( queue_item , 0 ) ;
DPRINTF ( E_LOG , L_DB , " Error fetching queue item by file id \n " ) ;
return NULL ;
}
2016-12-03 02:03:19 -05:00
else if ( queue_item - > id = = 0 )
2016-11-12 12:45:54 -05:00
{
// No item found
free_queue_item ( queue_item , 0 ) ;
return NULL ;
}
2016-11-04 10:34:00 -04:00
return queue_item ;
}
static int
2016-12-04 03:30:21 -05:00
queue_fetch_bypos ( uint32_t pos , char shuffle , struct db_queue_item * queue_item , int with_metadata )
2016-11-04 10:34:00 -04:00
{
2016-12-04 03:30:21 -05:00
struct query_params query_params ;
2016-11-04 10:34:00 -04:00
int ret ;
2016-12-04 03:30:21 -05:00
memset ( & query_params , 0 , sizeof ( struct query_params ) ) ;
2016-11-04 10:34:00 -04:00
if ( shuffle )
2016-12-04 03:30:21 -05:00
query_params . filter = sqlite3_mprintf ( " shuffle_pos = %d " , pos ) ;
2016-11-04 10:34:00 -04:00
else
2016-12-04 03:30:21 -05:00
query_params . filter = sqlite3_mprintf ( " pos = %d " , pos ) ;
2016-11-04 10:34:00 -04:00
2016-12-04 03:30:21 -05:00
ret = queue_enum_start ( & query_params ) ;
2016-11-04 10:34:00 -04:00
if ( ret < 0 )
{
2016-12-04 03:30:21 -05:00
sqlite3_free ( query_params . filter ) ;
2016-11-04 10:34:00 -04:00
return - 1 ;
}
2016-12-04 03:30:21 -05:00
ret = queue_enum_fetch ( & query_params , queue_item , with_metadata ) ;
db_query_end ( & query_params ) ;
sqlite3_free ( query_params . filter ) ;
2016-11-04 10:34:00 -04:00
return ret ;
}
struct db_queue_item *
db_queue_fetch_bypos ( uint32_t pos , char shuffle )
{
struct db_queue_item * queue_item ;
int ret ;
queue_item = calloc ( 1 , sizeof ( struct db_queue_item ) ) ;
if ( ! queue_item )
{
DPRINTF ( E_LOG , L_MAIN , " Out of memory for queue_item \n " ) ;
return NULL ;
}
db_transaction_begin ( ) ;
2016-12-04 03:30:21 -05:00
ret = queue_fetch_bypos ( pos , shuffle , queue_item , 1 ) ;
2016-11-04 10:34:00 -04:00
db_transaction_end ( ) ;
if ( ret < 0 )
{
free_queue_item ( queue_item , 0 ) ;
DPRINTF ( E_LOG , L_DB , " Error fetching queue item by pos id \n " ) ;
return NULL ;
}
2016-12-03 02:03:19 -05:00
else if ( queue_item - > id = = 0 )
2016-11-12 12:45:54 -05:00
{
// No item found
free_queue_item ( queue_item , 0 ) ;
return NULL ;
}
2016-11-04 10:34:00 -04:00
return queue_item ;
}
static int
2016-12-04 03:30:21 -05:00
queue_fetch_byposrelativetoitem ( int pos , uint32_t item_id , char shuffle , struct db_queue_item * queue_item , int with_metadata )
2016-11-04 10:34:00 -04:00
{
int pos_absolute ;
int ret ;
DPRINTF ( E_DBG , L_DB , " Fetch by pos: pos (%d) relative to item with id (%d) \n " , pos , item_id ) ;
pos_absolute = db_queue_get_pos ( item_id , shuffle ) ;
if ( pos_absolute < 0 )
{
return - 1 ;
}
DPRINTF ( E_DBG , L_DB , " Fetch by pos: item (%d) has absolute pos %d \n " , item_id , pos_absolute ) ;
pos_absolute + = pos ;
2016-12-04 03:30:21 -05:00
ret = queue_fetch_bypos ( pos_absolute , shuffle , queue_item , with_metadata ) ;
2016-11-04 10:34:00 -04:00
2016-12-03 02:03:19 -05:00
DPRINTF ( E_DBG , L_DB , " Fetch by pos: fetched item (id=%d, pos=%d, file-id=%d) \n " , queue_item - > id , queue_item - > pos , queue_item - > file_id ) ;
2016-11-04 10:34:00 -04:00
return ret ;
}
struct db_queue_item *
db_queue_fetch_byposrelativetoitem ( int pos , uint32_t item_id , char shuffle )
{
struct db_queue_item * queue_item ;
int ret ;
DPRINTF ( E_DBG , L_DB , " Fetch by pos: pos (%d) relative to item with id (%d) \n " , pos , item_id ) ;
queue_item = calloc ( 1 , sizeof ( struct db_queue_item ) ) ;
if ( ! queue_item )
{
DPRINTF ( E_LOG , L_MAIN , " Out of memory for queue_item \n " ) ;
return NULL ;
}
db_transaction_begin ( ) ;
2016-12-04 03:30:21 -05:00
ret = queue_fetch_byposrelativetoitem ( pos , item_id , shuffle , queue_item , 1 ) ;
2016-11-04 10:34:00 -04:00
db_transaction_end ( ) ;
if ( ret < 0 )
{
free_queue_item ( queue_item , 0 ) ;
DPRINTF ( E_LOG , L_DB , " Error fetching queue item by pos relative to item id \n " ) ;
return NULL ;
}
2016-12-03 02:03:19 -05:00
else if ( queue_item - > id = = 0 )
2016-11-12 12:45:54 -05:00
{
// No item found
free_queue_item ( queue_item , 0 ) ;
return NULL ;
}
2016-11-04 10:34:00 -04:00
2016-12-03 02:03:19 -05:00
DPRINTF ( E_DBG , L_DB , " Fetch by pos: fetched item (id=%d, pos=%d, file-id=%d) \n " , queue_item - > id , queue_item - > pos , queue_item - > file_id ) ;
2016-11-04 10:34:00 -04:00
return queue_item ;
}
struct db_queue_item *
db_queue_fetch_next ( uint32_t item_id , char shuffle )
{
return db_queue_fetch_byposrelativetoitem ( 1 , item_id , shuffle ) ;
}
struct db_queue_item *
db_queue_fetch_prev ( uint32_t item_id , char shuffle )
{
return db_queue_fetch_byposrelativetoitem ( - 1 , item_id , shuffle ) ;
}
/*
* Remove files that are disabled or non existant in the library and repair ordering of
* the queue ( shuffle and normal )
*/
int
db_queue_cleanup ( )
{
# define Q_TMPL "DELETE FROM queue WHERE NOT file_id IN (SELECT id from files WHERE disabled = 0);"
# define Q_TMPL_UPDATE "UPDATE queue SET pos = %d WHERE id = %d;"
# define Q_TMPL_UPDATE_SHUFFLE "UPDATE queue SET shuffle_pos = %d WHERE id = %d;"
2016-12-04 02:18:33 -05:00
struct query_params query_params ;
2016-11-04 10:34:00 -04:00
struct db_queue_item queue_item ;
char * query ;
int pos ;
int deleted ;
int ret ;
db_transaction_begin ( ) ;
ret = db_query_run ( Q_TMPL , 0 , 0 ) ;
if ( ret < 0 )
{
db_transaction_rollback ( ) ;
return - 1 ;
}
deleted = sqlite3_changes ( hdl ) ;
if ( deleted < = 0 )
{
// Nothing to do
db_transaction_end ( ) ;
return 0 ;
}
// Update position of normal queue
2016-12-04 02:18:33 -05:00
memset ( & query_params , 0 , sizeof ( struct query_params ) ) ;
2016-11-04 10:34:00 -04:00
2016-12-04 02:18:33 -05:00
ret = queue_enum_start ( & query_params ) ;
2016-11-04 10:34:00 -04:00
if ( ret < 0 )
{
db_transaction_rollback ( ) ;
return - 1 ;
}
pos = 0 ;
2016-12-04 02:18:33 -05:00
while ( ( ret = queue_enum_fetch ( & query_params , & queue_item , 0 ) ) = = 0 & & ( queue_item . id > 0 ) )
2016-11-04 10:34:00 -04:00
{
if ( queue_item . pos ! = pos )
{
2016-12-03 02:03:19 -05:00
query = sqlite3_mprintf ( Q_TMPL_UPDATE , pos , queue_item . id ) ;
2016-11-04 10:34:00 -04:00
ret = db_query_run ( query , 1 , 0 ) ;
if ( ret < 0 )
{
2016-12-03 02:03:19 -05:00
DPRINTF ( E_LOG , L_DB , " Failed to update item with item-id: %d \n " , queue_item . id ) ;
2016-11-04 10:34:00 -04:00
break ;
}
}
pos + + ;
}
2016-12-04 02:18:33 -05:00
db_query_end ( & query_params ) ;
2016-11-04 10:34:00 -04:00
if ( ret < 0 )
{
db_transaction_rollback ( ) ;
return - 1 ;
}
// Update position of shuffle queue
2016-12-04 02:18:33 -05:00
memset ( & query_params , 0 , sizeof ( struct query_params ) ) ;
query_params . sort = S_SHUFFLE_POS ;
2016-11-04 10:34:00 -04:00
2016-12-04 02:18:33 -05:00
ret = queue_enum_start ( & query_params ) ;
2016-11-04 10:34:00 -04:00
if ( ret < 0 )
{
db_transaction_rollback ( ) ;
return - 1 ;
}
pos = 0 ;
2016-12-04 02:18:33 -05:00
while ( ( ret = queue_enum_fetch ( & query_params , & queue_item , 0 ) ) = = 0 & & ( queue_item . id > 0 ) )
2016-11-04 10:34:00 -04:00
{
if ( queue_item . shuffle_pos ! = pos )
{
2016-12-03 02:03:19 -05:00
query = sqlite3_mprintf ( Q_TMPL_UPDATE_SHUFFLE , pos , queue_item . id ) ;
2016-11-04 10:34:00 -04:00
ret = db_query_run ( query , 1 , 0 ) ;
if ( ret < 0 )
{
2016-12-03 02:03:19 -05:00
DPRINTF ( E_LOG , L_DB , " Failed to update item with item-id: %d \n " , queue_item . id ) ;
2016-11-04 10:34:00 -04:00
break ;
}
}
pos + + ;
}
2016-12-04 02:18:33 -05:00
db_query_end ( & query_params ) ;
2016-11-04 10:34:00 -04:00
if ( ret < 0 )
{
db_transaction_rollback ( ) ;
return - 1 ;
}
db_transaction_end ( ) ;
queue_inc_version_and_notify ( ) ;
return 0 ;
# undef Q_TMPL_UPDATE_SHUFFLE
# undef Q_TMPL_UPDATE
# undef Q_TMPL
}
int
db_queue_clear ( )
{
int ret ;
db_transaction_begin ( ) ;
ret = db_query_run ( " DELETE FROM queue; " , 0 , 0 ) ;
if ( ret < 0 )
{
db_transaction_rollback ( ) ;
}
else
{
db_transaction_end ( ) ;
queue_inc_version_and_notify ( ) ;
}
return ret ;
}
static int
queue_delete_item ( struct db_queue_item * queue_item )
{
char * query ;
int ret ;
// Remove item with the given item_id
2016-12-03 02:03:19 -05:00
query = sqlite3_mprintf ( " DELETE FROM queue where id = %d; " , queue_item - > id ) ;
2016-11-04 10:34:00 -04:00
ret = db_query_run ( query , 1 , 0 ) ;
if ( ret < 0 )
{
return - 1 ;
}
// Update pos for all items after the item with given item_id
query = sqlite3_mprintf ( " UPDATE queue SET pos = pos - 1 WHERE pos > %d; " , queue_item - > pos ) ;
ret = db_query_run ( query , 1 , 0 ) ;
if ( ret < 0 )
{
return - 1 ;
}
// Update shuffle_pos for all items after the item with given item_id
query = sqlite3_mprintf ( " UPDATE queue SET shuffle_pos = shuffle_pos - 1 WHERE shuffle_pos > %d; " , queue_item - > shuffle_pos ) ;
ret = db_query_run ( query , 1 , 0 ) ;
if ( ret < 0 )
{
return - 1 ;
}
return 0 ;
}
int
db_queue_delete_byitemid ( uint32_t item_id )
{
struct db_queue_item queue_item ;
int ret ;
db_transaction_begin ( ) ;
2016-12-04 03:30:21 -05:00
ret = queue_fetch_byitemid ( item_id , & queue_item , 0 ) ;
2016-11-04 10:34:00 -04:00
if ( ret < 0 )
{
db_transaction_rollback ( ) ;
return - 1 ;
}
2016-12-03 02:03:19 -05:00
if ( queue_item . id = = 0 )
2016-11-04 10:34:00 -04:00
{
db_transaction_end ( ) ;
return 0 ;
}
ret = queue_delete_item ( & queue_item ) ;
if ( ret < 0 )
{
db_transaction_rollback ( ) ;
}
else
{
db_transaction_end ( ) ;
queue_inc_version_and_notify ( ) ;
}
return ret ;
}
int
db_queue_delete_bypos ( uint32_t pos , int count )
{
2016-12-04 02:18:33 -05:00
struct query_params query_params ;
2016-11-04 10:34:00 -04:00
struct db_queue_item queue_item ;
int to_pos ;
int ret ;
// Find items with the given position
2016-12-04 02:18:33 -05:00
memset ( & query_params , 0 , sizeof ( struct query_params ) ) ;
2016-11-04 10:34:00 -04:00
to_pos = pos + count ;
2016-12-04 02:18:33 -05:00
query_params . filter = sqlite3_mprintf ( " pos => %d AND pos < %d " , pos , to_pos ) ;
2016-11-04 10:34:00 -04:00
db_transaction_begin ( ) ;
2016-12-04 02:18:33 -05:00
ret = queue_enum_start ( & query_params ) ;
2016-11-04 10:34:00 -04:00
if ( ret < 0 )
{
return - 1 ;
}
2016-12-04 02:18:33 -05:00
while ( ( ret = queue_enum_fetch ( & query_params , & queue_item , 0 ) ) = = 0 & & ( queue_item . id > 0 ) )
2016-11-04 10:34:00 -04:00
{
ret = queue_delete_item ( & queue_item ) ;
if ( ret < 0 )
{
2016-12-03 02:03:19 -05:00
DPRINTF ( E_LOG , L_DB , " Failed to delete item with item-id: %d \n " , queue_item . id ) ;
2016-11-04 10:34:00 -04:00
break ;
}
}
2016-12-04 02:18:33 -05:00
db_query_end ( & query_params ) ;
2016-12-04 03:05:11 -05:00
sqlite3_free ( query_params . filter ) ;
2016-11-04 10:34:00 -04:00
if ( ret < 0 )
{
db_transaction_rollback ( ) ;
}
else
{
db_transaction_end ( ) ;
queue_inc_version_and_notify ( ) ;
}
return ret ;
}
int
db_queue_delete_byposrelativetoitem ( uint32_t pos , uint32_t item_id , char shuffle )
{
struct db_queue_item queue_item ;
int ret ;
db_transaction_begin ( ) ;
2016-12-04 03:30:21 -05:00
ret = queue_fetch_byposrelativetoitem ( pos , item_id , shuffle , & queue_item , 0 ) ;
2016-11-04 10:34:00 -04:00
if ( ret < 0 )
{
db_transaction_rollback ( ) ;
return - 1 ;
}
2016-12-03 02:03:19 -05:00
else if ( queue_item . id = = 0 )
2016-11-12 12:45:54 -05:00
{
// No item found
db_transaction_end ( ) ;
return 0 ;
}
2016-11-04 10:34:00 -04:00
ret = queue_delete_item ( & queue_item ) ;
if ( ret < 0 )
{
db_transaction_rollback ( ) ;
}
else
{
db_transaction_end ( ) ;
queue_inc_version_and_notify ( ) ;
}
return ret ;
}
/*
* Moves the queue item with the given id to the given position ( zero - based ) .
*
* @ param item_id Queue item id
* @ param pos_to target position in the queue ( zero - based )
* @ return 0 on success , - 1 on failure
*/
int
db_queue_move_byitemid ( uint32_t item_id , int pos_to )
{
char * query ;
int pos_from ;
int ret ;
db_transaction_begin ( ) ;
// Find item with the given item_id
pos_from = db_queue_get_pos ( item_id , 0 ) ;
if ( pos_from < 0 )
{
db_transaction_rollback ( ) ;
return - 1 ;
}
// Update pos for all items after the item with given item_id
query = sqlite3_mprintf ( " UPDATE queue SET pos = pos - 1 WHERE pos > %d; " , pos_from ) ;
ret = db_query_run ( query , 1 , 0 ) ;
if ( ret < 0 )
{
db_transaction_rollback ( ) ;
return - 1 ;
}
// Update pos for all items from the given pos_to
query = sqlite3_mprintf ( " UPDATE queue SET pos = pos + 1 WHERE pos >= %d; " , pos_to ) ;
ret = db_query_run ( query , 1 , 0 ) ;
if ( ret < 0 )
{
db_transaction_rollback ( ) ;
return - 1 ;
}
// Update item with the given item_id
query = sqlite3_mprintf ( " UPDATE queue SET pos = %d where id = %d; " , pos_to , item_id ) ;
ret = db_query_run ( query , 1 , 0 ) ;
if ( ret < 0 )
{
db_transaction_rollback ( ) ;
return - 1 ;
}
db_transaction_end ( ) ;
queue_inc_version_and_notify ( ) ;
return 0 ;
}
/*
* Moves the queue item at the given position to the given position ( zero - based ) .
*
* @ param pos_from Position of the queue item to move
* @ param pos_to target position in the queue ( zero - based )
* @ return 0 on success , - 1 on failure
*/
int
db_queue_move_bypos ( int pos_from , int pos_to )
{
struct db_queue_item queue_item ;
char * query ;
int ret ;
db_transaction_begin ( ) ;
// Find item to move
2016-12-04 03:30:21 -05:00
ret = queue_fetch_bypos ( pos_from , 0 , & queue_item , 0 ) ;
2016-11-04 10:34:00 -04:00
if ( ret < 0 )
{
db_transaction_rollback ( ) ;
return - 1 ;
}
2016-12-03 02:03:19 -05:00
if ( queue_item . id = = 0 )
2016-11-04 10:34:00 -04:00
{
db_transaction_end ( ) ;
return 0 ;
}
// Update pos for all items after the item with given position
query = sqlite3_mprintf ( " UPDATE queue SET pos = pos - 1 WHERE pos > %d; " , queue_item . pos ) ;
ret = db_query_run ( query , 1 , 0 ) ;
if ( ret < 0 )
{
db_transaction_rollback ( ) ;
return - 1 ;
}
// Update pos for all items from the given pos_to
query = sqlite3_mprintf ( " UPDATE queue SET pos = pos + 1 WHERE pos >= %d; " , pos_to ) ;
ret = db_query_run ( query , 1 , 0 ) ;
if ( ret < 0 )
{
db_transaction_rollback ( ) ;
return - 1 ;
}
// Update item with the given item_id
2016-12-03 02:03:19 -05:00
query = sqlite3_mprintf ( " UPDATE queue SET pos = %d where id = %d; " , pos_to , queue_item . id ) ;
2016-11-04 10:34:00 -04:00
ret = db_query_run ( query , 1 , 0 ) ;
if ( ret < 0 )
{
db_transaction_rollback ( ) ;
return - 1 ;
}
db_transaction_end ( ) ;
queue_inc_version_and_notify ( ) ;
return 0 ;
}
/*
* Moves the queue item at the given position to the given target position . The positions
* are relavtive to the given base item ( item id ) .
*
* @ param from_pos Relative position of the queue item to the base item
* @ param to_offset Target position relative to the base item
* @ param item_id The base item id ( normaly the now playing item )
* @ return 0 on success , - 1 on failure
*/
int
db_queue_move_byposrelativetoitem ( uint32_t from_pos , uint32_t to_offset , uint32_t item_id , char shuffle )
{
struct db_queue_item queue_item ;
char * query ;
int pos_move_from ;
int pos_move_to ;
int ret ;
db_transaction_begin ( ) ;
DPRINTF ( E_DBG , L_DB , " Move by pos: from %d offset %d relative to item (%d) \n " , from_pos , to_offset , item_id ) ;
// Find item with the given item_id
2016-12-04 03:30:21 -05:00
ret = queue_fetch_byitemid ( item_id , & queue_item , 0 ) ;
2016-11-04 10:34:00 -04:00
if ( ret < 0 )
{
db_transaction_rollback ( ) ;
return - 1 ;
}
2016-12-03 02:03:19 -05:00
DPRINTF ( E_DBG , L_DB , " Move by pos: base item (id=%d, pos=%d, file-id=%d) \n " , queue_item . id , queue_item . pos , queue_item . file_id ) ;
2016-11-04 10:34:00 -04:00
2016-12-03 02:03:19 -05:00
if ( queue_item . id = = 0 )
2016-11-04 10:34:00 -04:00
{
db_transaction_end ( ) ;
return 0 ;
}
// Calculate the position of the item to move
if ( shuffle )
pos_move_from = queue_item . shuffle_pos + from_pos ;
else
pos_move_from = queue_item . pos + from_pos ;
// Calculate the position where to move the item to
if ( shuffle )
pos_move_to = queue_item . shuffle_pos + to_offset ;
else
pos_move_to = queue_item . pos + to_offset ;
if ( pos_move_to < pos_move_from )
{
/*
* Moving an item to a previous position seems to send an offset incremented by one
*/
pos_move_to + + ;
}
DPRINTF ( E_DBG , L_DB , " Move by pos: absolute pos: move from %d to %d \n " , pos_move_from , pos_move_to ) ;
// Find item to move
2016-12-04 03:30:21 -05:00
ret = queue_fetch_bypos ( pos_move_from , shuffle , & queue_item , 0 ) ;
2016-11-04 10:34:00 -04:00
if ( ret < 0 )
{
db_transaction_rollback ( ) ;
return - 1 ;
}
2016-12-03 02:03:19 -05:00
DPRINTF ( E_DBG , L_DB , " Move by pos: move item (id=%d, pos=%d, file-id=%d) \n " , queue_item . id , queue_item . pos , queue_item . file_id ) ;
2016-11-04 10:34:00 -04:00
2016-12-03 02:03:19 -05:00
if ( queue_item . id = = 0 )
2016-11-04 10:34:00 -04:00
{
db_transaction_end ( ) ;
return 0 ;
}
// Update pos for all items after the item with given position
if ( shuffle )
query = sqlite3_mprintf ( " UPDATE queue SET shuffle_pos = shuffle_pos - 1 WHERE shuffle_pos > %d; " , queue_item . shuffle_pos ) ;
else
query = sqlite3_mprintf ( " UPDATE queue SET pos = pos - 1 WHERE pos > %d; " , queue_item . pos ) ;
ret = db_query_run ( query , 1 , 0 ) ;
if ( ret < 0 )
{
db_transaction_rollback ( ) ;
return - 1 ;
}
// Update pos for all items from the given pos_to
if ( shuffle )
query = sqlite3_mprintf ( " UPDATE queue SET shuffle_pos = shuffle_pos + 1 WHERE shuffle_pos >= %d; " , pos_move_to ) ;
else
query = sqlite3_mprintf ( " UPDATE queue SET pos = pos + 1 WHERE pos >= %d; " , pos_move_to ) ;
ret = db_query_run ( query , 1 , 0 ) ;
if ( ret < 0 )
{
db_transaction_rollback ( ) ;
return - 1 ;
}
// Update item with the given item_id
if ( shuffle )
2016-12-03 02:03:19 -05:00
query = sqlite3_mprintf ( " UPDATE queue SET shuffle_pos = %d where id = %d; " , pos_move_to , queue_item . id ) ;
2016-11-04 10:34:00 -04:00
else
2016-12-03 02:03:19 -05:00
query = sqlite3_mprintf ( " UPDATE queue SET pos = %d where id = %d; " , pos_move_to , queue_item . id ) ;
2016-11-04 10:34:00 -04:00
ret = db_query_run ( query , 1 , 0 ) ;
if ( ret < 0 )
{
db_transaction_rollback ( ) ;
return - 1 ;
}
db_transaction_end ( ) ;
queue_inc_version_and_notify ( ) ;
return 0 ;
}
/*
* Reshuffles the shuffle queue
*
* If the given item_id is 0 , the whole shuffle queue is reshuffled , otherwise the
* queue is reshuffled after the item with the given id ( excluding this item ) .
*
* @ param item_id The base item , after this item the queue is reshuffled
* @ return 0 on success , - 1 on failure
*/
int
db_queue_reshuffle ( uint32_t item_id )
{
char * query ;
int pos ;
int count ;
struct db_queue_item queue_item ;
int * shuffle_pos ;
int len ;
int i ;
2016-12-04 02:18:33 -05:00
struct query_params query_params ;
2016-11-04 10:34:00 -04:00
int ret ;
db_transaction_begin ( ) ;
DPRINTF ( E_DBG , L_DB , " Reshuffle queue after item with item-id: %d \n " , item_id ) ;
// Reset the shuffled order
ret = db_query_run ( " UPDATE queue SET shuffle_pos = pos; " , 0 , 0 ) ;
if ( ret < 0 )
{
db_transaction_rollback ( ) ;
return - 1 ;
}
pos = 0 ;
if ( item_id > 0 )
{
pos = db_queue_get_pos ( item_id , 0 ) ;
if ( pos < 0 )
{
db_transaction_rollback ( ) ;
return - 1 ;
}
pos + + ; // Do not reshuffle the base item
}
count = db_queue_get_count ( ) ;
len = count - pos ;
DPRINTF ( E_DBG , L_DB , " Reshuffle %d items off %d total items, starting from pos %d \n " , len , count , pos ) ;
shuffle_pos = malloc ( len * sizeof ( int ) ) ;
for ( i = 0 ; i < len ; i + + )
{
shuffle_pos [ i ] = i + pos ;
}
shuffle_int ( & shuffle_rng , shuffle_pos , len ) ;
2016-12-04 02:18:33 -05:00
memset ( & query_params , 0 , sizeof ( struct query_params ) ) ;
query_params . filter = sqlite3_mprintf ( " pos >= %d " , pos ) ;
2016-11-04 10:34:00 -04:00
2016-12-04 02:18:33 -05:00
ret = queue_enum_start ( & query_params ) ;
2016-11-04 10:34:00 -04:00
if ( ret < 0 )
{
2016-12-04 02:18:33 -05:00
sqlite3_free ( query_params . filter ) ;
2016-11-04 10:34:00 -04:00
db_transaction_rollback ( ) ;
return - 1 ;
}
i = 0 ;
2016-12-04 02:18:33 -05:00
while ( ( ret = queue_enum_fetch ( & query_params , & queue_item , 0 ) ) = = 0 & & ( queue_item . id > 0 ) & & ( i < len ) )
2016-11-04 10:34:00 -04:00
{
2016-12-03 02:03:19 -05:00
query = sqlite3_mprintf ( " UPDATE queue SET shuffle_pos = %d where id = %d; " , shuffle_pos [ i ] , queue_item . id ) ;
2016-11-04 10:34:00 -04:00
ret = db_query_run ( query , 1 , 0 ) ;
if ( ret < 0 )
{
2016-12-03 02:03:19 -05:00
DPRINTF ( E_LOG , L_DB , " Failed to delete item with item-id: %d \n " , queue_item . id ) ;
2016-11-04 10:34:00 -04:00
break ;
}
i + + ;
}
2016-12-04 02:18:33 -05:00
db_query_end ( & query_params ) ;
2016-12-04 03:05:11 -05:00
sqlite3_free ( query_params . filter ) ;
2016-11-04 10:34:00 -04:00
if ( ret < 0 )
{
db_transaction_rollback ( ) ;
return - 1 ;
}
db_transaction_end ( ) ;
queue_inc_version_and_notify ( ) ;
return 0 ;
}
int
db_queue_get_count ( )
{
2016-12-09 10:20:03 -05:00
return db_get_one_int ( " SELECT COUNT(*) FROM queue ; " );
2016-11-04 10:34:00 -04:00
}
/* Inotify */
int
db_watch_clear ( void )
{
return db_query_run ( " DELETE FROM inotify; " , 0 , 0 ) ;
}
int
db_watch_add ( struct watch_info * wi )
{
# define Q_TMPL "INSERT INTO inotify (wd, cookie, path) VALUES (%d, 0, '%q');"
char * query ;
query = sqlite3_mprintf ( Q_TMPL , wi - > wd , wi - > path ) ;
return db_query_run ( query , 1 , 0 ) ;
# undef Q_TMPL
}
int
db_watch_delete_bywd ( uint32_t wd )
{
# define Q_TMPL "DELETE FROM inotify WHERE wd = %d;"
char * query ;
query = sqlite3_mprintf ( Q_TMPL , wd ) ;
return db_query_run ( query , 1 , 0 ) ;
# 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 ) ;
return db_query_run ( query , 1 , 0 ) ;
# 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 ) ;
return db_query_run ( query , 1 , 0 ) ;
# 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 ) ;
return db_query_run ( query , 1 , 0 ) ;
# undef Q_TMPL
}
static int
db_watch_get_byquery ( struct watch_info * wi , char * query )
{
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 ) ;
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 ) ) ;
return - 1 ;
}
ret = db_blocking_step ( stmt ) ;
if ( ret ! = SQLITE_ROW )
{
DPRINTF ( E_WARN , L_DB , " Watch not found: '%s' \n " , query ) ;
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 ;
}
}
# ifdef DB_PROFILE
while ( db_blocking_step ( stmt ) = = SQLITE_ROW )
; /* EMPTY */
# endif
sqlite3_finalize ( stmt ) ;
sqlite3_free ( query ) ;
return 0 ;
}
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 ;
}
return db_watch_get_byquery ( wi , query ) ;
# undef Q_TMPL
}
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 ) ;
db_query_run ( query , 1 , 0 ) ;
# 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 ) ;
db_query_run ( query , 1 , 0 ) ;
# undef Q_TMPL
}
void
2009-06-11 09:42:51 -04:00
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 ;
}
2016-12-09 10:20:03 -05:00
ret = db_get_one_int ( 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 ) ;
}
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 ;
}
2016-11-04 02:10:36 -04:00
ret = db_init_indices ( hdl ) ;
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
2016-11-04 02:10:36 -04:00
ret = db_init_tables ( hdl ) ;
2010-01-21 11:51:00 -05:00
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
2016-11-04 10:34:00 -04:00
rng_init ( & shuffle_rng ) ;
2009-06-07 12:56:35 -04:00
return 0 ;
}
2010-04-26 12:24:09 -04:00
void
db_deinit ( void )
{
sqlite3_shutdown ( ) ;
}