[db] Recreate v20 files table, so that new constraints take effect if upgrading
The constraints on songalbumid and songartistid where changed with v20, so we need to make sure they take effect when upgrading. This commit tries to do the table recreation like sqlite recommends and without manually crafted copy queries that are probably prone to errors. Since we are recreating anyway, this commit also reorders the columns slightly. It also includes auto-drop/recreation of triggers (should really have been its own commit) during upgrade, like is already done with indices.
This commit is contained in:
parent
1de8f39264
commit
a4c254e6e7
54
src/db.c
54
src/db.c
|
@ -144,10 +144,13 @@ static const struct col_type_map mfi_cols_map[] =
|
|||
{
|
||||
{ "id", mfi_offsetof(id), DB_TYPE_INT, DB_FIXUP_STANDARD, DB_FLAG_AUTO },
|
||||
{ "path", mfi_offsetof(path), DB_TYPE_STRING, DB_FIXUP_NO_SANITIZE },
|
||||
{ "virtual_path", mfi_offsetof(virtual_path), DB_TYPE_STRING },
|
||||
{ "fname", mfi_offsetof(fname), DB_TYPE_STRING, DB_FIXUP_NO_SANITIZE },
|
||||
{ "directory_id", mfi_offsetof(directory_id), DB_TYPE_INT },
|
||||
{ "title", mfi_offsetof(title), DB_TYPE_STRING, DB_FIXUP_TITLE },
|
||||
{ "artist", mfi_offsetof(artist), DB_TYPE_STRING, DB_FIXUP_ARTIST },
|
||||
{ "album", mfi_offsetof(album), DB_TYPE_STRING, DB_FIXUP_ALBUM },
|
||||
{ "album_artist", mfi_offsetof(album_artist), DB_TYPE_STRING, DB_FIXUP_ALBUM_ARTIST },
|
||||
{ "genre", mfi_offsetof(genre), DB_TYPE_STRING, DB_FIXUP_GENRE },
|
||||
{ "comment", mfi_offsetof(comment), DB_TYPE_STRING },
|
||||
{ "type", mfi_offsetof(type), DB_TYPE_STRING, DB_FIXUP_TYPE },
|
||||
|
@ -161,6 +164,7 @@ static const struct col_type_map mfi_cols_map[] =
|
|||
{ "song_length", mfi_offsetof(song_length), DB_TYPE_INT },
|
||||
{ "file_size", mfi_offsetof(file_size), DB_TYPE_INT64 },
|
||||
{ "year", mfi_offsetof(year), DB_TYPE_INT },
|
||||
{ "date_released", mfi_offsetof(date_released), DB_TYPE_INT },
|
||||
{ "track", mfi_offsetof(track), DB_TYPE_INT },
|
||||
{ "total_tracks", mfi_offsetof(total_tracks), DB_TYPE_INT },
|
||||
{ "disc", mfi_offsetof(disc), DB_TYPE_INT },
|
||||
|
@ -170,23 +174,24 @@ static const struct col_type_map mfi_cols_map[] =
|
|||
{ "artwork", mfi_offsetof(artwork), DB_TYPE_CHAR },
|
||||
{ "rating", mfi_offsetof(rating), DB_TYPE_INT },
|
||||
{ "play_count", mfi_offsetof(play_count), DB_TYPE_INT },
|
||||
{ "skip_count", mfi_offsetof(skip_count), DB_TYPE_INT },
|
||||
{ "seek", mfi_offsetof(seek), DB_TYPE_INT },
|
||||
{ "data_kind", mfi_offsetof(data_kind), DB_TYPE_INT },
|
||||
{ "media_kind", mfi_offsetof(media_kind), DB_TYPE_INT, DB_FIXUP_MEDIA_KIND },
|
||||
{ "item_kind", mfi_offsetof(item_kind), DB_TYPE_INT },
|
||||
{ "description", mfi_offsetof(description), DB_TYPE_STRING },
|
||||
{ "db_timestamp", mfi_offsetof(db_timestamp), DB_TYPE_INT },
|
||||
{ "time_added", mfi_offsetof(time_added), DB_TYPE_INT, DB_FIXUP_TIME_ADDED },
|
||||
{ "time_modified", mfi_offsetof(time_modified), DB_TYPE_INT, DB_FIXUP_TIME_MODIFIED },
|
||||
{ "time_played", mfi_offsetof(time_played), DB_TYPE_INT },
|
||||
{ "db_timestamp", mfi_offsetof(db_timestamp), DB_TYPE_INT },
|
||||
{ "time_skipped", mfi_offsetof(time_skipped), DB_TYPE_INT },
|
||||
{ "disabled", mfi_offsetof(disabled), DB_TYPE_INT },
|
||||
{ "sample_count", mfi_offsetof(sample_count), DB_TYPE_INT64 },
|
||||
{ "codectype", mfi_offsetof(codectype), DB_TYPE_STRING, DB_FIXUP_CODECTYPE },
|
||||
{ "idx", mfi_offsetof(index), DB_TYPE_INT },
|
||||
{ "idx", mfi_offsetof(idx), DB_TYPE_INT },
|
||||
{ "has_video", mfi_offsetof(has_video), DB_TYPE_INT },
|
||||
{ "contentrating", mfi_offsetof(contentrating), DB_TYPE_INT },
|
||||
{ "bits_per_sample", mfi_offsetof(bits_per_sample), DB_TYPE_INT },
|
||||
{ "album_artist", mfi_offsetof(album_artist), DB_TYPE_STRING, DB_FIXUP_ALBUM_ARTIST },
|
||||
{ "media_kind", mfi_offsetof(media_kind), DB_TYPE_INT, DB_FIXUP_MEDIA_KIND },
|
||||
{ "tv_series_name", mfi_offsetof(tv_series_name), DB_TYPE_STRING },
|
||||
{ "tv_episode_num_str", mfi_offsetof(tv_episode_num_str), DB_TYPE_STRING },
|
||||
{ "tv_network_name", mfi_offsetof(tv_network_name), DB_TYPE_STRING },
|
||||
|
@ -197,13 +202,8 @@ static const struct col_type_map mfi_cols_map[] =
|
|||
{ "title_sort", mfi_offsetof(title_sort), DB_TYPE_STRING, DB_FIXUP_TITLE_SORT },
|
||||
{ "artist_sort", mfi_offsetof(artist_sort), DB_TYPE_STRING, DB_FIXUP_ARTIST_SORT },
|
||||
{ "album_sort", mfi_offsetof(album_sort), DB_TYPE_STRING, DB_FIXUP_ALBUM_SORT },
|
||||
{ "composer_sort", mfi_offsetof(composer_sort), DB_TYPE_STRING, DB_FIXUP_COMPOSER_SORT },
|
||||
{ "album_artist_sort", mfi_offsetof(album_artist_sort), DB_TYPE_STRING, DB_FIXUP_ALBUM_ARTIST_SORT },
|
||||
{ "virtual_path", mfi_offsetof(virtual_path), DB_TYPE_STRING },
|
||||
{ "directory_id", mfi_offsetof(directory_id), DB_TYPE_INT },
|
||||
{ "date_released", mfi_offsetof(date_released), DB_TYPE_INT },
|
||||
{ "skip_count", mfi_offsetof(skip_count), DB_TYPE_INT },
|
||||
{ "time_skipped", mfi_offsetof(time_skipped), DB_TYPE_INT },
|
||||
{ "composer_sort", mfi_offsetof(composer_sort), DB_TYPE_STRING, DB_FIXUP_COMPOSER_SORT },
|
||||
};
|
||||
|
||||
/* This list must be kept in sync with
|
||||
|
@ -271,10 +271,13 @@ static const ssize_t dbmfi_cols_map[] =
|
|||
{
|
||||
dbmfi_offsetof(id),
|
||||
dbmfi_offsetof(path),
|
||||
dbmfi_offsetof(virtual_path),
|
||||
dbmfi_offsetof(fname),
|
||||
dbmfi_offsetof(directory_id),
|
||||
dbmfi_offsetof(title),
|
||||
dbmfi_offsetof(artist),
|
||||
dbmfi_offsetof(album),
|
||||
dbmfi_offsetof(album_artist),
|
||||
dbmfi_offsetof(genre),
|
||||
dbmfi_offsetof(comment),
|
||||
dbmfi_offsetof(type),
|
||||
|
@ -288,6 +291,7 @@ static const ssize_t dbmfi_cols_map[] =
|
|||
dbmfi_offsetof(song_length),
|
||||
dbmfi_offsetof(file_size),
|
||||
dbmfi_offsetof(year),
|
||||
dbmfi_offsetof(date_released),
|
||||
dbmfi_offsetof(track),
|
||||
dbmfi_offsetof(total_tracks),
|
||||
dbmfi_offsetof(disc),
|
||||
|
@ -297,14 +301,17 @@ static const ssize_t dbmfi_cols_map[] =
|
|||
dbmfi_offsetof(artwork),
|
||||
dbmfi_offsetof(rating),
|
||||
dbmfi_offsetof(play_count),
|
||||
dbmfi_offsetof(skip_count),
|
||||
dbmfi_offsetof(seek),
|
||||
dbmfi_offsetof(data_kind),
|
||||
dbmfi_offsetof(media_kind),
|
||||
dbmfi_offsetof(item_kind),
|
||||
dbmfi_offsetof(description),
|
||||
dbmfi_offsetof(db_timestamp),
|
||||
dbmfi_offsetof(time_added),
|
||||
dbmfi_offsetof(time_modified),
|
||||
dbmfi_offsetof(time_played),
|
||||
dbmfi_offsetof(db_timestamp),
|
||||
dbmfi_offsetof(time_skipped),
|
||||
dbmfi_offsetof(disabled),
|
||||
dbmfi_offsetof(sample_count),
|
||||
dbmfi_offsetof(codectype),
|
||||
|
@ -312,8 +319,6 @@ static const ssize_t dbmfi_cols_map[] =
|
|||
dbmfi_offsetof(has_video),
|
||||
dbmfi_offsetof(contentrating),
|
||||
dbmfi_offsetof(bits_per_sample),
|
||||
dbmfi_offsetof(album_artist),
|
||||
dbmfi_offsetof(media_kind),
|
||||
dbmfi_offsetof(tv_series_name),
|
||||
dbmfi_offsetof(tv_episode_num_str),
|
||||
dbmfi_offsetof(tv_network_name),
|
||||
|
@ -324,13 +329,8 @@ static const ssize_t dbmfi_cols_map[] =
|
|||
dbmfi_offsetof(title_sort),
|
||||
dbmfi_offsetof(artist_sort),
|
||||
dbmfi_offsetof(album_sort),
|
||||
dbmfi_offsetof(composer_sort),
|
||||
dbmfi_offsetof(album_artist_sort),
|
||||
dbmfi_offsetof(virtual_path),
|
||||
dbmfi_offsetof(directory_id),
|
||||
dbmfi_offsetof(date_released),
|
||||
dbmfi_offsetof(skip_count),
|
||||
dbmfi_offsetof(time_skipped),
|
||||
dbmfi_offsetof(composer_sort),
|
||||
};
|
||||
|
||||
/* This list must be kept in sync with
|
||||
|
@ -7002,6 +7002,7 @@ db_check_version(void)
|
|||
return -1;
|
||||
}
|
||||
|
||||
// Will drop indices and triggers
|
||||
ret = db_upgrade(hdl, db_ver);
|
||||
if (ret < 0)
|
||||
{
|
||||
|
@ -7032,6 +7033,21 @@ db_check_version(void)
|
|||
return -1;
|
||||
}
|
||||
|
||||
ret = db_init_triggers(hdl);
|
||||
if (ret < 0)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DB, "Database upgrade errored out, rolling back changes ...\n");
|
||||
ret = sqlite3_exec(hdl, "ROLLBACK TRANSACTION;", NULL, NULL, &errmsg);
|
||||
if (ret != SQLITE_OK)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DB, "DB error while running 'ROLLBACK TRANSACTION': %s\n", errmsg);
|
||||
|
||||
sqlite3_free(errmsg);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = sqlite3_exec(hdl, "COMMIT TRANSACTION;", NULL, NULL, &errmsg);
|
||||
if (ret != SQLITE_OK)
|
||||
{
|
||||
|
|
81
src/db.h
81
src/db.h
|
@ -140,12 +140,16 @@ db_data_kind_label(enum data_kind data_kind);
|
|||
|
||||
/* Note that fields marked as integers in the metadata map in filescanner_ffmpeg must be uint32_t here */
|
||||
struct media_file_info {
|
||||
uint32_t id;
|
||||
|
||||
char *path;
|
||||
uint32_t index;
|
||||
char *virtual_path;
|
||||
char *fname;
|
||||
uint32_t directory_id; /* Id of directory */
|
||||
char *title;
|
||||
char *artist;
|
||||
char *album;
|
||||
char *album_artist;
|
||||
char *genre;
|
||||
char *comment;
|
||||
char *type; /* daap.songformat */
|
||||
|
@ -160,6 +164,7 @@ struct media_file_info {
|
|||
uint32_t song_length;
|
||||
int64_t file_size;
|
||||
uint32_t year; /* TDRC */
|
||||
uint32_t date_released;
|
||||
|
||||
uint32_t track; /* TRCK */
|
||||
uint32_t total_tracks;
|
||||
|
@ -167,44 +172,44 @@ struct media_file_info {
|
|||
uint32_t disc; /* TPOS */
|
||||
uint32_t total_discs;
|
||||
|
||||
uint32_t bpm; /* TBPM */
|
||||
uint32_t compilation;
|
||||
char artwork;
|
||||
uint32_t rating;
|
||||
|
||||
uint32_t play_count;
|
||||
uint32_t skip_count;
|
||||
uint32_t seek;
|
||||
|
||||
uint32_t data_kind; /* dmap.datakind (asdk) */
|
||||
uint32_t media_kind;
|
||||
uint32_t item_kind; /* song or movie */
|
||||
|
||||
char *description; /* daap.songdescription */
|
||||
|
||||
uint32_t db_timestamp;
|
||||
uint32_t time_added; /* FIXME: time_t */
|
||||
uint32_t time_modified;
|
||||
uint32_t time_played;
|
||||
|
||||
uint32_t play_count;
|
||||
uint32_t seek;
|
||||
uint32_t rating;
|
||||
uint32_t db_timestamp;
|
||||
uint32_t time_skipped;
|
||||
|
||||
uint32_t disabled;
|
||||
uint32_t bpm; /* TBPM */
|
||||
|
||||
uint32_t id;
|
||||
|
||||
char *description; /* daap.songdescription */
|
||||
uint64_t sample_count; //TODO [unused] sample count is never set and therefor always 0
|
||||
char *codectype; /* song.codectype, 4 chars max (32 bits) */
|
||||
|
||||
uint32_t item_kind; /* song or movie */
|
||||
uint32_t data_kind; /* dmap.datakind (asdk) */
|
||||
uint64_t sample_count; //TODO [unused] sample count is never set and therefor always 0
|
||||
uint32_t compilation;
|
||||
char artwork;
|
||||
uint32_t idx;
|
||||
|
||||
/* iTunes 5+ */
|
||||
uint32_t contentrating;
|
||||
uint32_t has_video; /* iTunes 6.0.2 */
|
||||
uint32_t contentrating;/* iTunes 5+ */
|
||||
|
||||
/* iTunes 6.0.2 */
|
||||
uint32_t has_video;
|
||||
uint32_t bits_per_sample;
|
||||
|
||||
uint32_t media_kind;
|
||||
uint32_t tv_episode_sort;
|
||||
uint32_t tv_season_num;
|
||||
char *tv_series_name;
|
||||
char *tv_episode_num_str; /* com.apple.itunes.episode-num-str, used as a unique episode identifier */
|
||||
char *tv_network_name;
|
||||
|
||||
char *album_artist;
|
||||
uint32_t tv_episode_sort;
|
||||
uint32_t tv_season_num;
|
||||
|
||||
int64_t songartistid;
|
||||
int64_t songalbumid;
|
||||
|
@ -212,16 +217,8 @@ struct media_file_info {
|
|||
char *title_sort;
|
||||
char *artist_sort;
|
||||
char *album_sort;
|
||||
char *composer_sort;
|
||||
char *album_artist_sort;
|
||||
|
||||
char *virtual_path;
|
||||
|
||||
uint32_t directory_id; /* Id of directory */
|
||||
uint32_t date_released;
|
||||
|
||||
uint32_t skip_count;
|
||||
uint32_t time_skipped;
|
||||
char *composer_sort;
|
||||
};
|
||||
|
||||
#define mfi_offsetof(field) offsetof(struct media_file_info, field)
|
||||
|
@ -308,10 +305,13 @@ struct db_group_info {
|
|||
struct db_media_file_info {
|
||||
char *id;
|
||||
char *path;
|
||||
char *virtual_path;
|
||||
char *fname;
|
||||
char *directory_id;
|
||||
char *title;
|
||||
char *artist;
|
||||
char *album;
|
||||
char *album_artist;
|
||||
char *genre;
|
||||
char *comment;
|
||||
char *type;
|
||||
|
@ -325,6 +325,7 @@ struct db_media_file_info {
|
|||
char *song_length;
|
||||
char *file_size;
|
||||
char *year;
|
||||
char *date_released;
|
||||
char *track;
|
||||
char *total_tracks;
|
||||
char *disc;
|
||||
|
@ -334,14 +335,17 @@ struct db_media_file_info {
|
|||
char *artwork;
|
||||
char *rating;
|
||||
char *play_count;
|
||||
char *skip_count;
|
||||
char *seek;
|
||||
char *data_kind;
|
||||
char *media_kind;
|
||||
char *item_kind;
|
||||
char *description;
|
||||
char *db_timestamp;
|
||||
char *time_added;
|
||||
char *time_modified;
|
||||
char *time_played;
|
||||
char *db_timestamp;
|
||||
char *time_skipped;
|
||||
char *disabled;
|
||||
char *sample_count;
|
||||
char *codectype;
|
||||
|
@ -349,8 +353,6 @@ struct db_media_file_info {
|
|||
char *has_video;
|
||||
char *contentrating;
|
||||
char *bits_per_sample;
|
||||
char *album_artist;
|
||||
char *media_kind;
|
||||
char *tv_episode_sort;
|
||||
char *tv_season_num;
|
||||
char *tv_series_name;
|
||||
|
@ -361,13 +363,8 @@ struct db_media_file_info {
|
|||
char *title_sort;
|
||||
char *artist_sort;
|
||||
char *album_sort;
|
||||
char *composer_sort;
|
||||
char *album_artist_sort;
|
||||
char *virtual_path;
|
||||
char *directory_id;
|
||||
char *date_released;
|
||||
char *skip_count;
|
||||
char *time_skipped;
|
||||
char *composer_sort;
|
||||
};
|
||||
|
||||
#define dbmfi_offsetof(field) offsetof(struct db_media_file_info, field)
|
||||
|
|
106
src/db_init.c
106
src/db_init.c
|
@ -36,10 +36,13 @@
|
|||
"CREATE TABLE IF NOT EXISTS files (" \
|
||||
" id INTEGER PRIMARY KEY NOT NULL," \
|
||||
" path VARCHAR(4096) NOT NULL," \
|
||||
" virtual_path VARCHAR(4096) DEFAULT NULL," \
|
||||
" fname VARCHAR(255) NOT NULL," \
|
||||
" directory_id INTEGER DEFAULT 0," \
|
||||
" title VARCHAR(1024) DEFAULT NULL COLLATE DAAP," \
|
||||
" artist VARCHAR(1024) DEFAULT NULL COLLATE DAAP," \
|
||||
" album VARCHAR(1024) NOT NULL COLLATE DAAP," \
|
||||
" album_artist 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," \
|
||||
|
@ -53,6 +56,7 @@
|
|||
" song_length INTEGER DEFAULT 0," \
|
||||
" file_size INTEGER DEFAULT 0," \
|
||||
" year INTEGER DEFAULT 0," \
|
||||
" date_released INTEGER DEFAULT 0," \
|
||||
" track INTEGER DEFAULT 0," \
|
||||
" total_tracks INTEGER DEFAULT 0," \
|
||||
" disc INTEGER DEFAULT 0," \
|
||||
|
@ -62,14 +66,17 @@
|
|||
" artwork INTEGER DEFAULT 0," \
|
||||
" rating INTEGER DEFAULT 0," \
|
||||
" play_count INTEGER DEFAULT 0," \
|
||||
" skip_count INTEGER DEFAULT 0," \
|
||||
" seek INTEGER DEFAULT 0," \
|
||||
" data_kind INTEGER DEFAULT 0," \
|
||||
" media_kind INTEGER DEFAULT 0," \
|
||||
" item_kind INTEGER DEFAULT 0," \
|
||||
" description INTEGER DEFAULT 0," \
|
||||
" db_timestamp INTEGER DEFAULT 0," \
|
||||
" time_added INTEGER DEFAULT 0," \
|
||||
" time_modified INTEGER DEFAULT 0," \
|
||||
" time_played INTEGER DEFAULT 0," \
|
||||
" db_timestamp INTEGER DEFAULT 0," \
|
||||
" time_skipped INTEGER DEFAULT 0," \
|
||||
" disabled INTEGER DEFAULT 0," \
|
||||
" sample_count INTEGER DEFAULT 0," \
|
||||
" codectype VARCHAR(5) DEFAULT NULL," \
|
||||
|
@ -77,8 +84,6 @@
|
|||
" 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," \
|
||||
|
@ -89,13 +94,8 @@
|
|||
" 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," \
|
||||
" skip_count INTEGER DEFAULT 0," \
|
||||
" time_skipped INTEGER DEFAULT 0" \
|
||||
" composer_sort VARCHAR(1024) DEFAULT NULL COLLATE DAAP" \
|
||||
");"
|
||||
|
||||
#define T_PL \
|
||||
|
@ -194,29 +194,6 @@
|
|||
" composer VARCHAR(1024) DEFAULT NULL" \
|
||||
");"
|
||||
|
||||
#define TRG_FILES_INSERT_SONGIDS \
|
||||
"CREATE TRIGGER trg_files_insert_songids AFTER INSERT ON files FOR EACH ROW" \
|
||||
" BEGIN" \
|
||||
" UPDATE files SET songartistid = daap_songalbumid(LOWER(NEW.album_artist), ''), " \
|
||||
" songalbumid = daap_songalbumid(LOWER(NEW.album_artist), LOWER(NEW.album))" \
|
||||
" WHERE id = NEW.id;" \
|
||||
" END;"
|
||||
|
||||
#define TRG_FILES_UPDATE_SONGIDS \
|
||||
"CREATE TRIGGER trg_files_update_songids AFTER UPDATE OF album_artist, album ON files FOR EACH ROW" \
|
||||
" BEGIN" \
|
||||
" UPDATE files SET songartistid = daap_songalbumid(LOWER(NEW.album_artist), ''), " \
|
||||
" songalbumid = daap_songalbumid(LOWER(NEW.album_artist), LOWER(NEW.album))" \
|
||||
" WHERE id = NEW.id;" \
|
||||
" END;"
|
||||
|
||||
#define TRG_GROUPS_UPDATE \
|
||||
"CREATE TRIGGER trg_groups_update AFTER UPDATE OF songartistid, 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);"
|
||||
|
@ -287,20 +264,18 @@ static const struct db_init_query db_init_table_queries[] =
|
|||
{ T_DIRECTORIES, "create table directories" },
|
||||
{ T_QUEUE, "create table queue" },
|
||||
|
||||
{ TRG_FILES_INSERT_SONGIDS, "create trigger trg_files_insert_songids" },
|
||||
{ TRG_FILES_UPDATE_SONGIDS, "create trigger trg_files_update_songids" },
|
||||
{ TRG_GROUPS_UPDATE, "create trigger trg_groups_update" },
|
||||
|
||||
{ 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_QUEUE_VERSION, "initialize queue version" },
|
||||
};
|
||||
|
||||
|
@ -421,6 +396,41 @@ static const struct db_init_query db_init_index_queries[] =
|
|||
{ I_QUEUE_SHUFFLEPOS, "create queue shuffle pos index" },
|
||||
};
|
||||
|
||||
|
||||
/* Triggers must be prefixed with trg_ for db_drop_triggers() to id them */
|
||||
|
||||
#define TRG_FILES_INSERT_SONGIDS \
|
||||
"CREATE TRIGGER trg_files_insert_songids AFTER INSERT ON files FOR EACH ROW" \
|
||||
" BEGIN" \
|
||||
" UPDATE files SET songartistid = daap_songalbumid(LOWER(NEW.album_artist), ''), " \
|
||||
" songalbumid = daap_songalbumid(LOWER(NEW.album_artist), LOWER(NEW.album))" \
|
||||
" WHERE id = NEW.id;" \
|
||||
" END;"
|
||||
|
||||
#define TRG_FILES_UPDATE_SONGIDS \
|
||||
"CREATE TRIGGER trg_files_update_songids AFTER UPDATE OF album_artist, album ON files FOR EACH ROW" \
|
||||
" BEGIN" \
|
||||
" UPDATE files SET songartistid = daap_songalbumid(LOWER(NEW.album_artist), ''), " \
|
||||
" songalbumid = daap_songalbumid(LOWER(NEW.album_artist), LOWER(NEW.album))" \
|
||||
" WHERE id = NEW.id;" \
|
||||
" END;"
|
||||
|
||||
#define TRG_GROUPS_UPDATE \
|
||||
"CREATE TRIGGER trg_groups_update AFTER UPDATE OF songartistid, songalbumid ON files FOR EACH ROW" \
|
||||
" WHEN (NEW.songartistid != 0 AND NEW.songalbumid != 0)" \
|
||||
" 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;"
|
||||
|
||||
static const struct db_init_query db_init_trigger_queries[] =
|
||||
{
|
||||
{ TRG_FILES_INSERT_SONGIDS, "create trigger trg_files_insert_songids" },
|
||||
{ TRG_FILES_UPDATE_SONGIDS, "create trigger trg_files_update_songids" },
|
||||
{ TRG_GROUPS_UPDATE, "create trigger trg_groups_update" },
|
||||
};
|
||||
|
||||
|
||||
int
|
||||
db_init_indices(sqlite3 *hdl)
|
||||
{
|
||||
|
@ -445,6 +455,30 @@ db_init_indices(sqlite3 *hdl)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
db_init_triggers(sqlite3 *hdl)
|
||||
{
|
||||
char *errmsg;
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
for (i = 0; i < (sizeof(db_init_trigger_queries) / sizeof(db_init_trigger_queries[0])); i++)
|
||||
{
|
||||
DPRINTF(E_DBG, L_DB, "DB init trigger query: %s\n", db_init_trigger_queries[i].desc);
|
||||
|
||||
ret = sqlite3_exec(hdl, db_init_trigger_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)
|
||||
{
|
||||
|
|
|
@ -31,6 +31,9 @@
|
|||
int
|
||||
db_init_indices(sqlite3 *hdl);
|
||||
|
||||
int
|
||||
db_init_triggers(sqlite3 *hdl);
|
||||
|
||||
int
|
||||
db_init_tables(sqlite3 *hdl);
|
||||
|
||||
|
|
303
src/db_upgrade.c
303
src/db_upgrade.c
|
@ -108,6 +108,69 @@ db_drop_indices(sqlite3 *hdl)
|
|||
#undef Q_INDEX
|
||||
}
|
||||
|
||||
static int
|
||||
db_drop_triggers(sqlite3 *hdl)
|
||||
{
|
||||
#define Q_TRIGGER "SELECT name FROM sqlite_master WHERE type == 'trigger' AND name LIKE 'trg_%';"
|
||||
#define Q_TMPL "DROP TRIGGER %q;"
|
||||
sqlite3_stmt *stmt;
|
||||
char *errmsg;
|
||||
char *query;
|
||||
char *trigger[256];
|
||||
int ret;
|
||||
int i;
|
||||
int n;
|
||||
|
||||
DPRINTF(E_DBG, L_DB, "Running query '%s'\n", Q_TRIGGER);
|
||||
|
||||
ret = sqlite3_prepare_v2(hdl, Q_TRIGGER, strlen(Q_TRIGGER) + 1, &stmt, NULL);
|
||||
if (ret != SQLITE_OK)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DB, "Could not prepare statement: %s\n", sqlite3_errmsg(hdl));
|
||||
return -1;
|
||||
}
|
||||
|
||||
n = 0;
|
||||
while ((ret = sqlite3_step(stmt)) == SQLITE_ROW)
|
||||
{
|
||||
trigger[n] = strdup((char *)sqlite3_column_text(stmt, 0));
|
||||
n++;
|
||||
}
|
||||
|
||||
if (ret != SQLITE_DONE)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DB, "Could not step: %s\n", sqlite3_errmsg(hdl));
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
query = sqlite3_mprintf(Q_TMPL, trigger[i]);
|
||||
free(trigger[i]);
|
||||
|
||||
DPRINTF(E_DBG, L_DB, "Running query '%s'\n", query);
|
||||
|
||||
ret = sqlite3_exec(hdl, query, NULL, NULL, &errmsg);
|
||||
if (ret != SQLITE_OK)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DB, "DB error while running '%s': %s\n", query, errmsg);
|
||||
|
||||
sqlite3_free(errmsg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sqlite3_free(query);
|
||||
}
|
||||
|
||||
return 0;
|
||||
#undef Q_TMPL
|
||||
#undef Q_TRIGGER
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
db_generic_upgrade(sqlite3 *hdl, const struct db_upgrade_query *queries, unsigned int nqueries)
|
||||
|
@ -133,6 +196,132 @@ db_generic_upgrade(sqlite3 *hdl, const struct db_upgrade_query *queries, unsigne
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* The below implements relevant parts of SQLITE's recommended 12 steps to
|
||||
* altering a table. It is not required to use this function if you just want to
|
||||
* add a column). The steps:
|
||||
* 1. If foreign key constraints are enabled, disable them using PRAGMA
|
||||
* foreign_keys=OFF.
|
||||
* 2. Start a transaction.
|
||||
* 3. Remember the format of all indexes and triggers associated with table X.
|
||||
* This information will be needed in step 8 below. One way to do this is to
|
||||
* run a query like the following: SELECT type, sql FROM sqlite_master WHERE
|
||||
* tbl_name='X'.
|
||||
* 4. Use CREATE TABLE to construct a new table "new_X" that is in the desired
|
||||
* revised format of table X. Make sure that the name "new_X" does not
|
||||
* collide with any existing table name, of course.
|
||||
* 5. Transfer content from X into new_X using a statement like: INSERT INTO
|
||||
* new_X SELECT ... FROM X.
|
||||
* 6. Drop the old table X: DROP TABLE X.
|
||||
* 7. Change the name of new_X to X using: ALTER TABLE new_X RENAME TO X.
|
||||
* 8. Use CREATE INDEX and CREATE TRIGGER to reconstruct indexes and triggers
|
||||
* associated with table X. Perhaps use the old format of the triggers and
|
||||
* indexes saved from step 3 above as a guide, making changes as appropriate
|
||||
* for the alteration.
|
||||
* 9. If any views refer to table X in a way that is affected by the schema
|
||||
* change, then drop those views using DROP VIEW and recreate them with
|
||||
* whatever changes are necessary to accommodate the schema change using
|
||||
* CREATE VIEW.
|
||||
* 10. If foreign key constraints were originally enabled then run PRAGMA
|
||||
* foreign_key_check to verify that the schema change did not break any
|
||||
* foreign key constraints.
|
||||
* 11. Commit the transaction started in step 2.
|
||||
* 12. If foreign keys constraints were originally enabled, reenable them now.
|
||||
* Source: https://www.sqlite.org/lang_altertable.html
|
||||
*/
|
||||
static int
|
||||
db_table_upgrade(sqlite3 *hdl, const char *name, const char *newtablequery)
|
||||
{
|
||||
sqlite3_stmt *stmt;
|
||||
char *query;
|
||||
char *errmsg;
|
||||
int ret;
|
||||
|
||||
DPRINTF(E_LOG, L_DB, "Upgrading %s table...\n", name);
|
||||
|
||||
// Step 1: Skipped, no foreign key constraints
|
||||
// Step 2: Skipped, we are already in a transaction
|
||||
// Step 3: Nothing to do, we already know our indexes and triggers
|
||||
// Step 4: Create the new table using table definition from db_init, but with
|
||||
// new_ prefixed to the name
|
||||
CHECK_NULL(L_DB, query = sqlite3_mprintf(newtablequery));
|
||||
|
||||
ret = sqlite3_exec(hdl, query, NULL, NULL, &errmsg);
|
||||
if (ret != SQLITE_OK)
|
||||
goto error;
|
||||
|
||||
sqlite3_free(query);
|
||||
|
||||
// Step 5: Transfer content - note: no support for changed column names or dropped columns!
|
||||
// This will select the column names from our new table (which where given to us in newtablequery)
|
||||
CHECK_NULL(L_DB, query = sqlite3_mprintf("SELECT group_concat(name) FROM pragma_table_info('new_%s');", name));
|
||||
|
||||
ret = sqlite3_prepare_v2(hdl, query, -1, &stmt, NULL);
|
||||
if (ret != SQLITE_OK)
|
||||
{
|
||||
errmsg = sqlite3_mprintf("%s", sqlite3_errmsg(hdl));
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = sqlite3_step(stmt);
|
||||
if (ret != SQLITE_ROW)
|
||||
{
|
||||
if (ret == SQLITE_DONE)
|
||||
errmsg = sqlite3_mprintf("Getting col names from pragma_table_info returned nothing");
|
||||
else
|
||||
errmsg = sqlite3_mprintf("%s", sqlite3_errmsg(hdl));
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
goto error;
|
||||
}
|
||||
|
||||
sqlite3_free(query);
|
||||
|
||||
CHECK_NULL(L_DB, query = sqlite3_mprintf("INSERT INTO new_%s SELECT %s FROM %s;", name, sqlite3_column_text(stmt, 0), name));
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
|
||||
ret = sqlite3_exec(hdl, query, NULL, NULL, &errmsg);
|
||||
if (ret != SQLITE_OK)
|
||||
goto error;
|
||||
|
||||
sqlite3_free(query);
|
||||
|
||||
// Step 6: Drop old table
|
||||
CHECK_NULL(L_DB, query = sqlite3_mprintf("DROP TABLE %s;", name));
|
||||
|
||||
ret = sqlite3_exec(hdl, query, NULL, NULL, &errmsg);
|
||||
if (ret != SQLITE_OK)
|
||||
goto error;
|
||||
|
||||
sqlite3_free(query);
|
||||
|
||||
// Step 7: Give the new table the final name
|
||||
CHECK_NULL(L_DB, query = sqlite3_mprintf("ALTER TABLE new_%s RENAME TO %s;", name, name));
|
||||
|
||||
ret = sqlite3_exec(hdl, query, NULL, NULL, &errmsg);
|
||||
if (ret != SQLITE_OK)
|
||||
goto error;
|
||||
|
||||
sqlite3_free(query);
|
||||
|
||||
// Step 8: Skipped, will be done by db_check_version in db.c
|
||||
// Step 9: Skipped, no views
|
||||
// Step 10: Skipped, no foreign key constraints
|
||||
// Step 11: Skipped, our caller takes care of COMMIT
|
||||
// Step 12: Skipped, no foreign key constraints
|
||||
|
||||
DPRINTF(E_LOG, L_DB, "Upgrade of %s table complete!\n", name);
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
DPRINTF(E_LOG, L_DB, "DB error %d running query '%s': %s\n", ret, query, errmsg);
|
||||
sqlite3_free(query);
|
||||
sqlite3_free(errmsg);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Upgrade the files table to the new schema by dumping and reloading the
|
||||
* table. A bit tedious.
|
||||
*/
|
||||
|
@ -308,7 +497,7 @@ db_upgrade_files_table(sqlite3 *hdl, const char *dumpquery, const char *newtable
|
|||
/* Not an issue, but takes up space in the database */
|
||||
}
|
||||
|
||||
DPRINTF(E_LOG, L_DB, "Upgrade of files table complete!\n");
|
||||
DPRINTF(E_LOG, L_DB, "Upgrade of files table complete!\n");
|
||||
|
||||
out_munmap:
|
||||
if (dump)
|
||||
|
@ -1728,30 +1917,82 @@ static const struct db_upgrade_query db_upgrade_v1912_queries[] =
|
|||
};
|
||||
|
||||
|
||||
#define U_V2000_DROP_TRG1 \
|
||||
"DROP TRIGGER update_groups_new_file;"
|
||||
#define U_V2000_DROP_TRG2 \
|
||||
"DROP TRIGGER update_groups_update_file;"
|
||||
#define U_V2000_TRG1 \
|
||||
"CREATE TRIGGER trg_files_insert_songids AFTER INSERT ON files FOR EACH ROW" \
|
||||
" BEGIN" \
|
||||
" UPDATE files SET songartistid = daap_songalbumid(LOWER(NEW.album_artist), ''), " \
|
||||
" songalbumid = daap_songalbumid(LOWER(NEW.album_artist), LOWER(NEW.album))" \
|
||||
" WHERE id = NEW.id;" \
|
||||
" END;"
|
||||
#define U_V2000_TRG2 \
|
||||
"CREATE TRIGGER trg_files_update_songids AFTER UPDATE OF album_artist, album ON files FOR EACH ROW" \
|
||||
" BEGIN" \
|
||||
" UPDATE files SET songartistid = daap_songalbumid(LOWER(NEW.album_artist), ''), " \
|
||||
" songalbumid = daap_songalbumid(LOWER(NEW.album_artist), LOWER(NEW.album))" \
|
||||
" WHERE id = NEW.id;" \
|
||||
" END;"
|
||||
#define U_V2000_TRG3 \
|
||||
"CREATE TRIGGER trg_groups_update AFTER UPDATE OF songartistid, 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 U_V20_NEW_FILES_TABLE \
|
||||
"CREATE TABLE new_files (" \
|
||||
" id INTEGER PRIMARY KEY NOT NULL," \
|
||||
" path VARCHAR(4096) NOT NULL," \
|
||||
" virtual_path VARCHAR(4096) DEFAULT NULL," \
|
||||
" fname VARCHAR(255) NOT NULL," \
|
||||
" directory_id INTEGER DEFAULT 0," \
|
||||
" title VARCHAR(1024) DEFAULT NULL COLLATE DAAP," \
|
||||
" artist VARCHAR(1024) DEFAULT NULL COLLATE DAAP," \
|
||||
" album VARCHAR(1024) NOT NULL COLLATE DAAP," \
|
||||
" album_artist 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," \
|
||||
" date_released 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," \
|
||||
" skip_count INTEGER DEFAULT 0," \
|
||||
" seek INTEGER DEFAULT 0," \
|
||||
" data_kind INTEGER DEFAULT 0," \
|
||||
" media_kind INTEGER DEFAULT 0," \
|
||||
" item_kind INTEGER DEFAULT 0," \
|
||||
" description INTEGER DEFAULT 0," \
|
||||
" db_timestamp INTEGER DEFAULT 0," \
|
||||
" time_added INTEGER DEFAULT 0," \
|
||||
" time_modified INTEGER DEFAULT 0," \
|
||||
" time_played INTEGER DEFAULT 0," \
|
||||
" time_skipped 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," \
|
||||
" 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 DEFAULT 0," \
|
||||
" songalbumid INTEGER DEFAULT 0," \
|
||||
" title_sort VARCHAR(1024) DEFAULT NULL COLLATE DAAP," \
|
||||
" artist_sort VARCHAR(1024) DEFAULT NULL COLLATE DAAP," \
|
||||
" album_sort VARCHAR(1024) DEFAULT NULL COLLATE DAAP," \
|
||||
" album_artist_sort VARCHAR(1024) DEFAULT NULL COLLATE DAAP," \
|
||||
" composer_sort VARCHAR(1024) DEFAULT NULL COLLATE DAAP" \
|
||||
");"
|
||||
|
||||
static int
|
||||
db_upgrade_v20(sqlite3 *hdl)
|
||||
{
|
||||
return db_table_upgrade(hdl, "files", U_V20_NEW_FILES_TABLE);
|
||||
}
|
||||
|
||||
#define U_V2000_DROP_TRG1 \
|
||||
"DROP TRIGGER IF EXISTS update_groups_new_file;"
|
||||
#define U_V2000_DROP_TRG2 \
|
||||
"DROP TRIGGER IF EXISTS update_groups_update_file;"
|
||||
|
||||
#define U_V2000_SCVER_MAJOR \
|
||||
"UPDATE admin SET value = '20' WHERE key = 'schema_version_major';"
|
||||
|
@ -1762,9 +2003,6 @@ static const struct db_upgrade_query db_upgrade_v2000_queries[] =
|
|||
{
|
||||
{ U_V2000_DROP_TRG1, "drop trigger update_groups_new_file" },
|
||||
{ U_V2000_DROP_TRG2, "drop trigger update_groups_update_file" },
|
||||
{ U_V2000_TRG1, "create trigger trg_files_insert_songids" },
|
||||
{ U_V2000_TRG2, "create trigger trg_files_update_songids" },
|
||||
{ U_V2000_TRG3, "create trigger trg_groups_update" },
|
||||
|
||||
{ U_V2000_SCVER_MAJOR, "set schema_version_major to 20" },
|
||||
{ U_V2000_SCVER_MINOR, "set schema_version_minor to 00" },
|
||||
|
@ -1780,6 +2018,10 @@ db_upgrade(sqlite3 *hdl, int db_ver)
|
|||
if (ret < 0)
|
||||
return -1;
|
||||
|
||||
ret = db_drop_triggers(hdl);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
|
||||
switch (db_ver)
|
||||
{
|
||||
case 1000:
|
||||
|
@ -1968,9 +2210,14 @@ db_upgrade(sqlite3 *hdl, int db_ver)
|
|||
/* FALLTHROUGH */
|
||||
|
||||
case 1912:
|
||||
ret = db_upgrade_v20(hdl);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
|
||||
ret = db_generic_upgrade(hdl, db_upgrade_v2000_queries, ARRAY_SIZE(db_upgrade_v2000_queries));
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
Loading…
Reference in New Issue