Merge pull request #303 from chme/dbinit

Move db init into its own source file
This commit is contained in:
ejurgensen 2016-11-04 19:16:36 +01:00 committed by GitHub
commit f0e2218a8c
4 changed files with 477 additions and 394 deletions

View File

@ -79,6 +79,7 @@ forked_daapd_LDADD = -lrt \
forked_daapd_SOURCES = main.c \ forked_daapd_SOURCES = main.c \
db.c db.h \ db.c db.h \
db_init.c db_init.h \
db_upgrade.c db_upgrade.h \ db_upgrade.c db_upgrade.h \
logger.c logger.h \ logger.c logger.h \
conffile.c conffile.h \ conffile.c conffile.h \

397
src/db.c
View File

@ -44,6 +44,7 @@
#include "cache.h" #include "cache.h"
#include "misc.h" #include "misc.h"
#include "db.h" #include "db.h"
#include "db_init.h"
#include "db_upgrade.h" #include "db_upgrade.h"
@ -4808,398 +4809,6 @@ db_perthread_deinit(void)
} }
#define T_ADMIN \
"CREATE TABLE IF NOT EXISTS admin(" \
" key VARCHAR(32) NOT NULL," \
" value VARCHAR(32) NOT NULL" \
");"
#define T_FILES \
"CREATE TABLE IF NOT EXISTS files (" \
" id INTEGER PRIMARY KEY NOT NULL," \
" path VARCHAR(4096) NOT NULL," \
" fname VARCHAR(255) NOT NULL," \
" title VARCHAR(1024) DEFAULT NULL COLLATE DAAP," \
" artist VARCHAR(1024) DEFAULT NULL COLLATE DAAP," \
" album VARCHAR(1024) NOT NULL COLLATE DAAP," \
" genre VARCHAR(255) DEFAULT NULL COLLATE DAAP," \
" comment VARCHAR(4096) DEFAULT NULL COLLATE DAAP," \
" type VARCHAR(255) DEFAULT NULL COLLATE DAAP," \
" composer VARCHAR(1024) DEFAULT NULL COLLATE DAAP," \
" orchestra VARCHAR(1024) DEFAULT NULL COLLATE DAAP," \
" conductor VARCHAR(1024) DEFAULT NULL COLLATE DAAP," \
" grouping VARCHAR(1024) DEFAULT NULL COLLATE DAAP," \
" url VARCHAR(1024) DEFAULT NULL," \
" bitrate INTEGER DEFAULT 0," \
" samplerate INTEGER DEFAULT 0," \
" song_length INTEGER DEFAULT 0," \
" file_size INTEGER DEFAULT 0," \
" year INTEGER DEFAULT 0," \
" track INTEGER DEFAULT 0," \
" total_tracks INTEGER DEFAULT 0," \
" disc INTEGER DEFAULT 0," \
" total_discs INTEGER DEFAULT 0," \
" bpm INTEGER DEFAULT 0," \
" compilation INTEGER DEFAULT 0," \
" artwork INTEGER DEFAULT 0," \
" rating INTEGER DEFAULT 0," \
" play_count INTEGER DEFAULT 0," \
" seek INTEGER DEFAULT 0," \
" data_kind INTEGER DEFAULT 0," \
" item_kind INTEGER DEFAULT 0," \
" description INTEGER DEFAULT 0," \
" time_added INTEGER DEFAULT 0," \
" time_modified INTEGER DEFAULT 0," \
" time_played INTEGER DEFAULT 0," \
" db_timestamp INTEGER DEFAULT 0," \
" disabled INTEGER DEFAULT 0," \
" sample_count INTEGER DEFAULT 0," \
" codectype VARCHAR(5) DEFAULT NULL," \
" idx INTEGER NOT NULL," \
" has_video INTEGER DEFAULT 0," \
" contentrating INTEGER DEFAULT 0," \
" bits_per_sample INTEGER DEFAULT 0," \
" album_artist VARCHAR(1024) NOT NULL COLLATE DAAP," \
" media_kind INTEGER NOT NULL," \
" tv_series_name VARCHAR(1024) DEFAULT NULL COLLATE DAAP," \
" tv_episode_num_str VARCHAR(1024) DEFAULT NULL COLLATE DAAP," \
" tv_network_name VARCHAR(1024) DEFAULT NULL COLLATE DAAP," \
" tv_episode_sort INTEGER NOT NULL," \
" tv_season_num INTEGER NOT NULL," \
" songartistid INTEGER NOT NULL," \
" songalbumid INTEGER NOT NULL," \
" title_sort VARCHAR(1024) DEFAULT NULL COLLATE DAAP," \
" artist_sort VARCHAR(1024) DEFAULT NULL COLLATE DAAP," \
" album_sort VARCHAR(1024) DEFAULT NULL COLLATE DAAP," \
" composer_sort VARCHAR(1024) DEFAULT NULL COLLATE DAAP," \
" album_artist_sort VARCHAR(1024) DEFAULT NULL COLLATE DAAP," \
" virtual_path VARCHAR(4096) DEFAULT NULL," \
" directory_id INTEGER DEFAULT 0," \
" date_released INTEGER DEFAULT 0" \
");"
#define T_PL \
"CREATE TABLE IF NOT EXISTS playlists (" \
" id INTEGER PRIMARY KEY NOT NULL," \
" title VARCHAR(255) NOT NULL COLLATE DAAP," \
" type INTEGER NOT NULL," \
" query VARCHAR(1024)," \
" db_timestamp INTEGER NOT NULL," \
" disabled INTEGER DEFAULT 0," \
" path VARCHAR(4096)," \
" idx INTEGER NOT NULL," \
" special_id INTEGER DEFAULT 0," \
" virtual_path VARCHAR(4096)," \
" parent_id INTEGER DEFAULT 0," \
" directory_id INTEGER DEFAULT 0" \
");"
#define T_PLITEMS \
"CREATE TABLE IF NOT EXISTS playlistitems (" \
" id INTEGER PRIMARY KEY NOT NULL," \
" playlistid INTEGER NOT NULL," \
" filepath VARCHAR(4096) NOT NULL" \
");"
#define T_GROUPS \
"CREATE TABLE IF NOT EXISTS groups (" \
" id INTEGER PRIMARY KEY NOT NULL," \
" type INTEGER NOT NULL," \
" name VARCHAR(1024) NOT NULL COLLATE DAAP," \
" persistentid INTEGER NOT NULL," \
"CONSTRAINT groups_type_unique_persistentid UNIQUE (type, persistentid)" \
");"
#define T_PAIRINGS \
"CREATE TABLE IF NOT EXISTS pairings(" \
" remote VARCHAR(64) PRIMARY KEY NOT NULL," \
" name VARCHAR(255) NOT NULL," \
" guid VARCHAR(16) NOT NULL" \
");"
#define T_SPEAKERS \
"CREATE TABLE IF NOT EXISTS speakers(" \
" id INTEGER PRIMARY KEY NOT NULL," \
" selected INTEGER NOT NULL," \
" volume INTEGER NOT NULL," \
" name VARCHAR(255) DEFAULT NULL" \
");"
#define T_INOTIFY \
"CREATE TABLE IF NOT EXISTS inotify (" \
" wd INTEGER PRIMARY KEY NOT NULL," \
" cookie INTEGER NOT NULL," \
" path VARCHAR(4096) NOT NULL" \
");"
#define T_DIRECTORIES \
"CREATE TABLE IF NOT EXISTS directories (" \
" id INTEGER PRIMARY KEY NOT NULL," \
" virtual_path VARCHAR(4096) NOT NULL," \
" db_timestamp INTEGER DEFAULT 0," \
" disabled INTEGER DEFAULT 0," \
" parent_id INTEGER DEFAULT 0" \
");"
#define TRG_GROUPS_INSERT_FILES \
"CREATE TRIGGER update_groups_new_file AFTER INSERT ON files FOR EACH ROW" \
" BEGIN" \
" INSERT OR IGNORE INTO groups (type, name, persistentid) VALUES (1, NEW.album, NEW.songalbumid);" \
" INSERT OR IGNORE INTO groups (type, name, persistentid) VALUES (2, NEW.album_artist, NEW.songartistid);" \
" END;"
#define TRG_GROUPS_UPDATE_FILES \
"CREATE TRIGGER update_groups_update_file AFTER UPDATE OF songalbumid ON files FOR EACH ROW" \
" BEGIN" \
" INSERT OR IGNORE INTO groups (type, name, persistentid) VALUES (1, NEW.album, NEW.songalbumid);" \
" INSERT OR IGNORE INTO groups (type, name, persistentid) VALUES (2, NEW.album_artist, NEW.songartistid);" \
" END;"
#define Q_PL1 \
"INSERT INTO playlists (id, title, type, query, db_timestamp, path, idx, special_id)" \
" VALUES(1, 'Library', 0, '1 = 1', 0, '', 0, 0);"
#define Q_PL2 \
"INSERT INTO playlists (id, title, type, query, db_timestamp, path, idx, special_id)" \
" VALUES(2, 'Music', 0, 'f.media_kind = 1', 0, '', 0, 6);"
#define Q_PL3 \
"INSERT INTO playlists (id, title, type, query, db_timestamp, path, idx, special_id)" \
" VALUES(3, 'Movies', 0, 'f.media_kind = 2', 0, '', 0, 4);"
#define Q_PL4 \
"INSERT INTO playlists (id, title, type, query, db_timestamp, path, idx, special_id)" \
" VALUES(4, 'TV Shows', 0, 'f.media_kind = 64', 0, '', 0, 5);"
#define Q_PL5 \
"INSERT INTO playlists (id, title, type, query, db_timestamp, path, idx, special_id)" \
" VALUES(5, 'Podcasts', 0, 'f.media_kind = 4', 0, '', 0, 1);"
#define Q_PL6 \
"INSERT INTO playlists (id, title, type, query, db_timestamp, path, idx, special_id)" \
" VALUES(6, 'Audiobooks', 0, 'f.media_kind = 8', 0, '', 0, 7);"
/* These are the remaining automatically-created iTunes playlists, but
* their query is unknown
" VALUES(6, 'iTunes U', 0, 'media_kind = 256', 0, '', 0, 13);"
" VALUES(8, 'Purchased', 0, 'media_kind = 1024', 0, '', 0, 8);"
*/
#define Q_DIR1 \
"INSERT INTO directories (id, virtual_path, db_timestamp, disabled, parent_id)" \
" VALUES (1, '/', 0, 0, 0);"
#define Q_DIR2 \
"INSERT INTO directories (id, virtual_path, db_timestamp, disabled, parent_id)" \
" VALUES (2, '/file:', 0, 0, 1);"
#define Q_DIR3 \
"INSERT INTO directories (id, virtual_path, db_timestamp, disabled, parent_id)" \
" VALUES (3, '/http:', 0, 0, 1);"
#define Q_DIR4 \
"INSERT INTO directories (id, virtual_path, db_timestamp, disabled, parent_id)" \
" VALUES (4, '/spotify:', 0, 4294967296, 1);"
/* Rule of thumb: Will the current version of forked-daapd work with the new
* version of the database? If yes, then it is a minor upgrade, if no, then it
* is a major upgrade. In other words minor version upgrades permit downgrading
* forked-daapd after the database was upgraded. */
#define SCHEMA_VERSION_MAJOR 19
#define SCHEMA_VERSION_MINOR 00
#define Q_SCVER_MAJOR \
"INSERT INTO admin (key, value) VALUES ('schema_version_major', '19');"
#define Q_SCVER_MINOR \
"INSERT INTO admin (key, value) VALUES ('schema_version_minor', '00');"
struct db_init_query {
char *query;
char *desc;
};
static const struct db_init_query db_init_table_queries[] =
{
{ T_ADMIN, "create table admin" },
{ T_FILES, "create table files" },
{ T_PL, "create table playlists" },
{ T_PLITEMS, "create table playlistitems" },
{ T_GROUPS, "create table groups" },
{ T_PAIRINGS, "create table pairings" },
{ T_SPEAKERS, "create table speakers" },
{ T_INOTIFY, "create table inotify" },
{ T_DIRECTORIES, "create table directories" },
{ TRG_GROUPS_INSERT_FILES, "create trigger update_groups_new_file" },
{ TRG_GROUPS_UPDATE_FILES, "create trigger update_groups_update_file" },
{ Q_PL1, "create default playlist" },
{ Q_PL2, "create default smart playlist 'Music'" },
{ Q_PL3, "create default smart playlist 'Movies'" },
{ Q_PL4, "create default smart playlist 'TV Shows'" },
{ Q_PL5, "create default smart playlist 'Podcasts'" },
{ Q_PL6, "create default smart playlist 'Audiobooks'" },
{ Q_DIR1, "create default root directory '/'" },
{ Q_DIR2, "create default base directory '/file:'" },
{ Q_DIR3, "create default base directory '/http:'" },
{ Q_DIR4, "create default base directory '/spotify:'" },
{ Q_SCVER_MAJOR, "set schema version major" },
{ Q_SCVER_MINOR, "set schema version minor" },
};
/* Indices must be prefixed with idx_ for db_drop_indices() to id them */
#define I_RESCAN \
"CREATE INDEX IF NOT EXISTS idx_rescan ON files(path, db_timestamp);"
#define I_SONGARTISTID \
"CREATE INDEX IF NOT EXISTS idx_sari ON files(songartistid);"
/* Used by Q_GROUP_ALBUMS */
#define I_SONGALBUMID \
"CREATE INDEX IF NOT EXISTS idx_sali ON files(songalbumid, disabled, media_kind, album_sort, disc, track);"
/* Used by Q_GROUP_ARTISTS */
#define I_STATEMKINDSARI \
"CREATE INDEX IF NOT EXISTS idx_state_mkind_sari ON files(disabled, media_kind, songartistid);"
#define I_STATEMKINDSALI \
"CREATE INDEX IF NOT EXISTS idx_state_mkind_sali ON files(disabled, media_kind, songalbumid);"
#define I_ARTIST \
"CREATE INDEX IF NOT EXISTS idx_artist ON files(artist, artist_sort);"
#define I_ALBUMARTIST \
"CREATE INDEX IF NOT EXISTS idx_albumartist ON files(album_artist, album_artist_sort);"
/* Used by Q_BROWSE_COMPOSERS */
#define I_COMPOSER \
"CREATE INDEX IF NOT EXISTS idx_composer ON files(disabled, media_kind, composer_sort);"
/* Used by Q_BROWSE_GENRES */
#define I_GENRE \
"CREATE INDEX IF NOT EXISTS idx_genre ON files(disabled, media_kind, genre);"
/* Used by Q_PLITEMS for smart playlists */
#define I_TITLE \
"CREATE INDEX IF NOT EXISTS idx_title ON files(disabled, media_kind, title_sort);"
#define I_ALBUM \
"CREATE INDEX IF NOT EXISTS idx_album ON files(album, album_sort);"
#define I_FILELIST \
"CREATE INDEX IF NOT EXISTS idx_filelist ON files(disabled, virtual_path, time_modified);"
#define I_FILE_DIR \
"CREATE INDEX IF NOT EXISTS idx_file_dir ON files(disabled, directory_id);"
#define I_PL_PATH \
"CREATE INDEX IF NOT EXISTS idx_pl_path ON playlists(path);"
#define I_PL_DISABLED \
"CREATE INDEX IF NOT EXISTS idx_pl_disabled ON playlists(disabled, type, virtual_path, db_timestamp);"
#define I_PL_DIR \
"CREATE INDEX IF NOT EXISTS idx_pl_dir ON files(disabled, directory_id);"
#define I_FILEPATH \
"CREATE INDEX IF NOT EXISTS idx_filepath ON playlistitems(filepath ASC);"
#define I_PLITEMID \
"CREATE INDEX IF NOT EXISTS idx_playlistid ON playlistitems(playlistid, filepath);"
#define I_GRP_PERSIST \
"CREATE INDEX IF NOT EXISTS idx_grp_persist ON groups(persistentid);"
#define I_PAIRING \
"CREATE INDEX IF NOT EXISTS idx_pairingguid ON pairings(guid);"
#define I_DIR_VPATH \
"CREATE INDEX IF NOT EXISTS idx_dir_vpath ON directories(disabled, virtual_path);"
#define I_DIR_PARENT \
"CREATE INDEX IF NOT EXISTS idx_dir_parentid ON directories(parent_id);"
static const struct db_init_query db_init_index_queries[] =
{
{ I_RESCAN, "create rescan index" },
{ I_SONGARTISTID, "create songartistid index" },
{ I_SONGALBUMID, "create songalbumid index" },
{ I_STATEMKINDSARI, "create state/mkind/sari index" },
{ I_STATEMKINDSALI, "create state/mkind/sali index" },
{ I_ARTIST, "create artist index" },
{ I_ALBUMARTIST, "create album_artist index" },
{ I_COMPOSER, "create composer index" },
{ I_GENRE, "create genre index" },
{ I_TITLE, "create title index" },
{ I_ALBUM, "create album index" },
{ I_FILELIST, "create filelist index" },
{ I_FILE_DIR, "create file dir index" },
{ I_PL_PATH, "create playlist path index" },
{ I_PL_DISABLED, "create playlist state index" },
{ I_PL_DIR, "create playlist dir index" },
{ I_FILEPATH, "create file path index" },
{ I_PLITEMID, "create playlist id index" },
{ I_GRP_PERSIST, "create groups persistentid index" },
{ I_PAIRING, "create pairing guid index" },
{ I_DIR_VPATH, "create directories disabled_virtualpath index" },
{ I_DIR_PARENT, "create directories parentid index" },
};
static int
db_create_indices(void)
{
char *errmsg;
int i;
int ret;
for (i = 0; i < (sizeof(db_init_index_queries) / sizeof(db_init_index_queries[0])); i++)
{
DPRINTF(E_DBG, L_DB, "DB init index query: %s\n", db_init_index_queries[i].desc);
ret = sqlite3_exec(hdl, db_init_index_queries[i].query, NULL, NULL, &errmsg);
if (ret != SQLITE_OK)
{
DPRINTF(E_FATAL, L_DB, "DB init error: %s\n", errmsg);
sqlite3_free(errmsg);
return -1;
}
}
return 0;
}
static int
db_create_tables(void)
{
char *errmsg;
int i;
int ret;
for (i = 0; i < (sizeof(db_init_table_queries) / sizeof(db_init_table_queries[0])); i++)
{
DPRINTF(E_DBG, L_DB, "DB init table query: %s\n", db_init_table_queries[i].desc);
ret = sqlite3_exec(hdl, db_init_table_queries[i].query, NULL, NULL, &errmsg);
if (ret != SQLITE_OK)
{
DPRINTF(E_FATAL, L_DB, "DB init error: %s\n", errmsg);
sqlite3_free(errmsg);
return -1;
}
}
ret = db_create_indices();
return ret;
}
static int static int
@ -5278,7 +4887,7 @@ db_check_version(void)
return -1; return -1;
} }
ret = db_create_indices(); ret = db_init_indices(hdl);
if (ret < 0) if (ret < 0)
{ {
DPRINTF(E_LOG, L_DB, "Database upgrade errored out, rolling back changes ...\n"); DPRINTF(E_LOG, L_DB, "Database upgrade errored out, rolling back changes ...\n");
@ -5373,7 +4982,7 @@ db_init(void)
{ {
DPRINTF(E_LOG, L_DB, "Could not check database version, trying DB init\n"); DPRINTF(E_LOG, L_DB, "Could not check database version, trying DB init\n");
ret = db_create_tables(); ret = db_init_tables(hdl);
if (ret < 0) if (ret < 0)
{ {
DPRINTF(E_FATAL, L_DB, "Could not create tables\n"); DPRINTF(E_FATAL, L_DB, "Could not create tables\n");

436
src/db_init.c Normal file
View File

@ -0,0 +1,436 @@
/*
* Copyright (C) 2009-2011 Julien BLACHE <jb@jblache.org>
* Copyright (C) 2010 Kai Elwert <elwertk@googlemail.com>
* Copyright (C) 2016 Christian Meffert <christian.meffert@googlemail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <sqlite3.h>
#include <stddef.h>
#include "db_init.h"
#include "logger.h"
#define T_ADMIN \
"CREATE TABLE IF NOT EXISTS admin(" \
" key VARCHAR(32) NOT NULL," \
" value VARCHAR(32) NOT NULL" \
");"
#define T_FILES \
"CREATE TABLE IF NOT EXISTS files (" \
" id INTEGER PRIMARY KEY NOT NULL," \
" path VARCHAR(4096) NOT NULL," \
" fname VARCHAR(255) NOT NULL," \
" title VARCHAR(1024) DEFAULT NULL COLLATE DAAP," \
" artist VARCHAR(1024) DEFAULT NULL COLLATE DAAP," \
" album VARCHAR(1024) NOT NULL COLLATE DAAP," \
" genre VARCHAR(255) DEFAULT NULL COLLATE DAAP," \
" comment VARCHAR(4096) DEFAULT NULL COLLATE DAAP," \
" type VARCHAR(255) DEFAULT NULL COLLATE DAAP," \
" composer VARCHAR(1024) DEFAULT NULL COLLATE DAAP," \
" orchestra VARCHAR(1024) DEFAULT NULL COLLATE DAAP," \
" conductor VARCHAR(1024) DEFAULT NULL COLLATE DAAP," \
" grouping VARCHAR(1024) DEFAULT NULL COLLATE DAAP," \
" url VARCHAR(1024) DEFAULT NULL," \
" bitrate INTEGER DEFAULT 0," \
" samplerate INTEGER DEFAULT 0," \
" song_length INTEGER DEFAULT 0," \
" file_size INTEGER DEFAULT 0," \
" year INTEGER DEFAULT 0," \
" track INTEGER DEFAULT 0," \
" total_tracks INTEGER DEFAULT 0," \
" disc INTEGER DEFAULT 0," \
" total_discs INTEGER DEFAULT 0," \
" bpm INTEGER DEFAULT 0," \
" compilation INTEGER DEFAULT 0," \
" artwork INTEGER DEFAULT 0," \
" rating INTEGER DEFAULT 0," \
" play_count INTEGER DEFAULT 0," \
" seek INTEGER DEFAULT 0," \
" data_kind INTEGER DEFAULT 0," \
" item_kind INTEGER DEFAULT 0," \
" description INTEGER DEFAULT 0," \
" time_added INTEGER DEFAULT 0," \
" time_modified INTEGER DEFAULT 0," \
" time_played INTEGER DEFAULT 0," \
" db_timestamp INTEGER DEFAULT 0," \
" disabled INTEGER DEFAULT 0," \
" sample_count INTEGER DEFAULT 0," \
" codectype VARCHAR(5) DEFAULT NULL," \
" idx INTEGER NOT NULL," \
" has_video INTEGER DEFAULT 0," \
" contentrating INTEGER DEFAULT 0," \
" bits_per_sample INTEGER DEFAULT 0," \
" album_artist VARCHAR(1024) NOT NULL COLLATE DAAP," \
" media_kind INTEGER NOT NULL," \
" tv_series_name VARCHAR(1024) DEFAULT NULL COLLATE DAAP," \
" tv_episode_num_str VARCHAR(1024) DEFAULT NULL COLLATE DAAP," \
" tv_network_name VARCHAR(1024) DEFAULT NULL COLLATE DAAP," \
" tv_episode_sort INTEGER NOT NULL," \
" tv_season_num INTEGER NOT NULL," \
" songartistid INTEGER NOT NULL," \
" songalbumid INTEGER NOT NULL," \
" title_sort VARCHAR(1024) DEFAULT NULL COLLATE DAAP," \
" artist_sort VARCHAR(1024) DEFAULT NULL COLLATE DAAP," \
" album_sort VARCHAR(1024) DEFAULT NULL COLLATE DAAP," \
" composer_sort VARCHAR(1024) DEFAULT NULL COLLATE DAAP," \
" album_artist_sort VARCHAR(1024) DEFAULT NULL COLLATE DAAP," \
" virtual_path VARCHAR(4096) DEFAULT NULL," \
" directory_id INTEGER DEFAULT 0," \
" date_released INTEGER DEFAULT 0" \
");"
#define T_PL \
"CREATE TABLE IF NOT EXISTS playlists (" \
" id INTEGER PRIMARY KEY NOT NULL," \
" title VARCHAR(255) NOT NULL COLLATE DAAP," \
" type INTEGER NOT NULL," \
" query VARCHAR(1024)," \
" db_timestamp INTEGER NOT NULL," \
" disabled INTEGER DEFAULT 0," \
" path VARCHAR(4096)," \
" idx INTEGER NOT NULL," \
" special_id INTEGER DEFAULT 0," \
" virtual_path VARCHAR(4096)," \
" parent_id INTEGER DEFAULT 0," \
" directory_id INTEGER DEFAULT 0" \
");"
#define T_PLITEMS \
"CREATE TABLE IF NOT EXISTS playlistitems (" \
" id INTEGER PRIMARY KEY NOT NULL," \
" playlistid INTEGER NOT NULL," \
" filepath VARCHAR(4096) NOT NULL" \
");"
#define T_GROUPS \
"CREATE TABLE IF NOT EXISTS groups (" \
" id INTEGER PRIMARY KEY NOT NULL," \
" type INTEGER NOT NULL," \
" name VARCHAR(1024) NOT NULL COLLATE DAAP," \
" persistentid INTEGER NOT NULL," \
"CONSTRAINT groups_type_unique_persistentid UNIQUE (type, persistentid)" \
");"
#define T_PAIRINGS \
"CREATE TABLE IF NOT EXISTS pairings(" \
" remote VARCHAR(64) PRIMARY KEY NOT NULL," \
" name VARCHAR(255) NOT NULL," \
" guid VARCHAR(16) NOT NULL" \
");"
#define T_SPEAKERS \
"CREATE TABLE IF NOT EXISTS speakers(" \
" id INTEGER PRIMARY KEY NOT NULL," \
" selected INTEGER NOT NULL," \
" volume INTEGER NOT NULL," \
" name VARCHAR(255) DEFAULT NULL" \
");"
#define T_INOTIFY \
"CREATE TABLE IF NOT EXISTS inotify (" \
" wd INTEGER PRIMARY KEY NOT NULL," \
" cookie INTEGER NOT NULL," \
" path VARCHAR(4096) NOT NULL" \
");"
#define T_DIRECTORIES \
"CREATE TABLE IF NOT EXISTS directories (" \
" id INTEGER PRIMARY KEY NOT NULL," \
" virtual_path VARCHAR(4096) NOT NULL," \
" db_timestamp INTEGER DEFAULT 0," \
" disabled INTEGER DEFAULT 0," \
" parent_id INTEGER DEFAULT 0" \
");"
#define TRG_GROUPS_INSERT_FILES \
"CREATE TRIGGER update_groups_new_file AFTER INSERT ON files FOR EACH ROW" \
" BEGIN" \
" INSERT OR IGNORE INTO groups (type, name, persistentid) VALUES (1, NEW.album, NEW.songalbumid);" \
" INSERT OR IGNORE INTO groups (type, name, persistentid) VALUES (2, NEW.album_artist, NEW.songartistid);" \
" END;"
#define TRG_GROUPS_UPDATE_FILES \
"CREATE TRIGGER update_groups_update_file AFTER UPDATE OF songalbumid ON files FOR EACH ROW" \
" BEGIN" \
" INSERT OR IGNORE INTO groups (type, name, persistentid) VALUES (1, NEW.album, NEW.songalbumid);" \
" INSERT OR IGNORE INTO groups (type, name, persistentid) VALUES (2, NEW.album_artist, NEW.songartistid);" \
" END;"
#define Q_PL1 \
"INSERT INTO playlists (id, title, type, query, db_timestamp, path, idx, special_id)" \
" VALUES(1, 'Library', 0, '1 = 1', 0, '', 0, 0);"
#define Q_PL2 \
"INSERT INTO playlists (id, title, type, query, db_timestamp, path, idx, special_id)" \
" VALUES(2, 'Music', 0, 'f.media_kind = 1', 0, '', 0, 6);"
#define Q_PL3 \
"INSERT INTO playlists (id, title, type, query, db_timestamp, path, idx, special_id)" \
" VALUES(3, 'Movies', 0, 'f.media_kind = 2', 0, '', 0, 4);"
#define Q_PL4 \
"INSERT INTO playlists (id, title, type, query, db_timestamp, path, idx, special_id)" \
" VALUES(4, 'TV Shows', 0, 'f.media_kind = 64', 0, '', 0, 5);"
#define Q_PL5 \
"INSERT INTO playlists (id, title, type, query, db_timestamp, path, idx, special_id)" \
" VALUES(5, 'Podcasts', 0, 'f.media_kind = 4', 0, '', 0, 1);"
#define Q_PL6 \
"INSERT INTO playlists (id, title, type, query, db_timestamp, path, idx, special_id)" \
" VALUES(6, 'Audiobooks', 0, 'f.media_kind = 8', 0, '', 0, 7);"
/* These are the remaining automatically-created iTunes playlists, but
* their query is unknown
" VALUES(6, 'iTunes U', 0, 'media_kind = 256', 0, '', 0, 13);"
" VALUES(8, 'Purchased', 0, 'media_kind = 1024', 0, '', 0, 8);"
*/
#define Q_DIR1 \
"INSERT INTO directories (id, virtual_path, db_timestamp, disabled, parent_id)" \
" VALUES (1, '/', 0, 0, 0);"
#define Q_DIR2 \
"INSERT INTO directories (id, virtual_path, db_timestamp, disabled, parent_id)" \
" VALUES (2, '/file:', 0, 0, 1);"
#define Q_DIR3 \
"INSERT INTO directories (id, virtual_path, db_timestamp, disabled, parent_id)" \
" VALUES (3, '/http:', 0, 0, 1);"
#define Q_DIR4 \
"INSERT INTO directories (id, virtual_path, db_timestamp, disabled, parent_id)" \
" VALUES (4, '/spotify:', 0, 4294967296, 1);"
#define Q_SCVER_MAJOR \
"INSERT INTO admin (key, value) VALUES ('schema_version_major', '%d');"
#define Q_SCVER_MINOR \
"INSERT INTO admin (key, value) VALUES ('schema_version_minor', '%02d');"
struct db_init_query {
char *query;
char *desc;
};
static const struct db_init_query db_init_table_queries[] =
{
{ T_ADMIN, "create table admin" },
{ T_FILES, "create table files" },
{ T_PL, "create table playlists" },
{ T_PLITEMS, "create table playlistitems" },
{ T_GROUPS, "create table groups" },
{ T_PAIRINGS, "create table pairings" },
{ T_SPEAKERS, "create table speakers" },
{ T_INOTIFY, "create table inotify" },
{ T_DIRECTORIES, "create table directories" },
{ TRG_GROUPS_INSERT_FILES, "create trigger update_groups_new_file" },
{ TRG_GROUPS_UPDATE_FILES, "create trigger update_groups_update_file" },
{ Q_PL1, "create default playlist" },
{ Q_PL2, "create default smart playlist 'Music'" },
{ Q_PL3, "create default smart playlist 'Movies'" },
{ Q_PL4, "create default smart playlist 'TV Shows'" },
{ Q_PL5, "create default smart playlist 'Podcasts'" },
{ Q_PL6, "create default smart playlist 'Audiobooks'" },
{ Q_DIR1, "create default root directory '/'" },
{ Q_DIR2, "create default base directory '/file:'" },
{ Q_DIR3, "create default base directory '/http:'" },
{ Q_DIR4, "create default base directory '/spotify:'" },
};
/* Indices must be prefixed with idx_ for db_drop_indices() to id them */
#define I_RESCAN \
"CREATE INDEX IF NOT EXISTS idx_rescan ON files(path, db_timestamp);"
#define I_SONGARTISTID \
"CREATE INDEX IF NOT EXISTS idx_sari ON files(songartistid);"
/* Used by Q_GROUP_ALBUMS */
#define I_SONGALBUMID \
"CREATE INDEX IF NOT EXISTS idx_sali ON files(songalbumid, disabled, media_kind, album_sort, disc, track);"
/* Used by Q_GROUP_ARTISTS */
#define I_STATEMKINDSARI \
"CREATE INDEX IF NOT EXISTS idx_state_mkind_sari ON files(disabled, media_kind, songartistid);"
#define I_STATEMKINDSALI \
"CREATE INDEX IF NOT EXISTS idx_state_mkind_sali ON files(disabled, media_kind, songalbumid);"
#define I_ARTIST \
"CREATE INDEX IF NOT EXISTS idx_artist ON files(artist, artist_sort);"
#define I_ALBUMARTIST \
"CREATE INDEX IF NOT EXISTS idx_albumartist ON files(album_artist, album_artist_sort);"
/* Used by Q_BROWSE_COMPOSERS */
#define I_COMPOSER \
"CREATE INDEX IF NOT EXISTS idx_composer ON files(disabled, media_kind, composer_sort);"
/* Used by Q_BROWSE_GENRES */
#define I_GENRE \
"CREATE INDEX IF NOT EXISTS idx_genre ON files(disabled, media_kind, genre);"
/* Used by Q_PLITEMS for smart playlists */
#define I_TITLE \
"CREATE INDEX IF NOT EXISTS idx_title ON files(disabled, media_kind, title_sort);"
#define I_ALBUM \
"CREATE INDEX IF NOT EXISTS idx_album ON files(album, album_sort);"
#define I_FILELIST \
"CREATE INDEX IF NOT EXISTS idx_filelist ON files(disabled, virtual_path, time_modified);"
#define I_FILE_DIR \
"CREATE INDEX IF NOT EXISTS idx_file_dir ON files(disabled, directory_id);"
#define I_PL_PATH \
"CREATE INDEX IF NOT EXISTS idx_pl_path ON playlists(path);"
#define I_PL_DISABLED \
"CREATE INDEX IF NOT EXISTS idx_pl_disabled ON playlists(disabled, type, virtual_path, db_timestamp);"
#define I_PL_DIR \
"CREATE INDEX IF NOT EXISTS idx_pl_dir ON files(disabled, directory_id);"
#define I_FILEPATH \
"CREATE INDEX IF NOT EXISTS idx_filepath ON playlistitems(filepath ASC);"
#define I_PLITEMID \
"CREATE INDEX IF NOT EXISTS idx_playlistid ON playlistitems(playlistid, filepath);"
#define I_GRP_PERSIST \
"CREATE INDEX IF NOT EXISTS idx_grp_persist ON groups(persistentid);"
#define I_PAIRING \
"CREATE INDEX IF NOT EXISTS idx_pairingguid ON pairings(guid);"
#define I_DIR_VPATH \
"CREATE INDEX IF NOT EXISTS idx_dir_vpath ON directories(disabled, virtual_path);"
#define I_DIR_PARENT \
"CREATE INDEX IF NOT EXISTS idx_dir_parentid ON directories(parent_id);"
static const struct db_init_query db_init_index_queries[] =
{
{ I_RESCAN, "create rescan index" },
{ I_SONGARTISTID, "create songartistid index" },
{ I_SONGALBUMID, "create songalbumid index" },
{ I_STATEMKINDSARI, "create state/mkind/sari index" },
{ I_STATEMKINDSALI, "create state/mkind/sali index" },
{ I_ARTIST, "create artist index" },
{ I_ALBUMARTIST, "create album_artist index" },
{ I_COMPOSER, "create composer index" },
{ I_GENRE, "create genre index" },
{ I_TITLE, "create title index" },
{ I_ALBUM, "create album index" },
{ I_FILELIST, "create filelist index" },
{ I_FILE_DIR, "create file dir index" },
{ I_PL_PATH, "create playlist path index" },
{ I_PL_DISABLED, "create playlist state index" },
{ I_PL_DIR, "create playlist dir index" },
{ I_FILEPATH, "create file path index" },
{ I_PLITEMID, "create playlist id index" },
{ I_GRP_PERSIST, "create groups persistentid index" },
{ I_PAIRING, "create pairing guid index" },
{ I_DIR_VPATH, "create directories disabled_virtualpath index" },
{ I_DIR_PARENT, "create directories parentid index" },
};
int
db_init_indices(sqlite3 *hdl)
{
char *errmsg;
int i;
int ret;
for (i = 0; i < (sizeof(db_init_index_queries) / sizeof(db_init_index_queries[0])); i++)
{
DPRINTF(E_DBG, L_DB, "DB init index query: %s\n", db_init_index_queries[i].desc);
ret = sqlite3_exec(hdl, db_init_index_queries[i].query, NULL, NULL, &errmsg);
if (ret != SQLITE_OK)
{
DPRINTF(E_FATAL, L_DB, "DB init error: %s\n", errmsg);
sqlite3_free(errmsg);
return -1;
}
}
return 0;
}
int
db_init_tables(sqlite3 *hdl)
{
char *query;
char *errmsg;
int i;
int ret;
for (i = 0; i < (sizeof(db_init_table_queries) / sizeof(db_init_table_queries[0])); i++)
{
DPRINTF(E_DBG, L_DB, "DB init table query: %s\n", db_init_table_queries[i].desc);
ret = sqlite3_exec(hdl, db_init_table_queries[i].query, NULL, NULL, &errmsg);
if (ret != SQLITE_OK)
{
DPRINTF(E_FATAL, L_DB, "DB init error: %s\n", errmsg);
sqlite3_free(errmsg);
return -1;
}
}
query = sqlite3_mprintf(Q_SCVER_MAJOR, SCHEMA_VERSION_MAJOR);
DPRINTF(E_DBG, L_DB, "DB init table query: %s\n", query);
ret = sqlite3_exec(hdl, query, NULL, NULL, &errmsg);
sqlite3_free(query);
if (ret != SQLITE_OK)
{
DPRINTF(E_FATAL, L_DB, "DB init error: %s\n", errmsg);
sqlite3_free(errmsg);
return -1;
}
query = sqlite3_mprintf(Q_SCVER_MINOR, SCHEMA_VERSION_MINOR);
DPRINTF(E_DBG, L_DB, "DB init table query: %s\n", query);
ret = sqlite3_exec(hdl, query, NULL, NULL, &errmsg);
sqlite3_free(query);
if (ret != SQLITE_OK)
{
DPRINTF(E_FATAL, L_DB, "DB init error: %s\n", errmsg);
sqlite3_free(errmsg);
return -1;
}
ret = db_init_indices(hdl);
return ret;
}

37
src/db_init.h Normal file
View File

@ -0,0 +1,37 @@
/*
* Copyright (C) 2015 Christian Meffert <christian.meffert@googlemail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef SRC_DB_INIT_H_
#define SRC_DB_INIT_H_
#include <sqlite3.h>
/* Rule of thumb: Will the current version of forked-daapd work with the new
* version of the database? If yes, then it is a minor upgrade, if no, then it
* is a major upgrade. In other words minor version upgrades permit downgrading
* forked-daapd after the database was upgraded. */
#define SCHEMA_VERSION_MAJOR 19
#define SCHEMA_VERSION_MINOR 00
int
db_init_indices(sqlite3 *hdl);
int
db_init_tables(sqlite3 *hdl);
#endif /* SRC_DB_INIT_H_ */