Skip to content
Extraits de code Groupes Projets
Sélectionner une révision Git
  • 3673505dba0931ac210132320c89d2d8c85d4811
  • master par défaut protégée
  • rust-playlist-sync
  • rust
  • fix-qt-deprecated-qvariant-type
  • fix-mpris-qtwindow-race-condition
  • rust-appimage-wayland
  • windows-build-rebased
  • v2.5 protégée
  • v2.4 protégée
  • v2.3-1 protégée
  • v2.3 protégée
  • v2.2 protégée
  • v2.1 protégée
  • v2.0 protégée
  • v1.8-3 protégée
  • v1.8-2 protégée
  • v1.8-1 protégée
  • v1.8 protégée
  • v1.7 protégée
  • v1.6 protégée
  • v1.5 protégée
  • v1.4 protégée
  • v1.3 protégée
  • v1.2 protégée
  • v1.1 protégée
  • v1.0 protégée
27 résultats

queue.c

Blame
  • queue.c 22,74 Kio
    #define _POSIX_C_SOURCE 200809L
    
    #include <lektor/database.h>
    #include <lektor/macro.h>
    
    #include <linux/limits.h>
    #include <stdio.h>
    #include <string.h>
    
    /* Find in in database/open.c */
    extern int is_sql_str_invalid(const char *);
    
    bool
    database_queue_state(sqlite3 *db, struct lkt_queue_state *res)
    {
        static const char *SQL_STMT =
            "SELECT"
            "  volume, paused, random, repeat, single, current, duration, consume, "
            "  (SELECT COUNT(*) FROM queue) AS length "
            "FROM queue_state;\n";
        sqlite3_stmt *stmt = 0;
        bool ret = false;
    
        SQLITE_PREPARE(db, stmt, SQL_STMT, error);
    
        if (sqlite3_step(stmt) != SQLITE_ROW) {
            fprintf(stderr, " ! database_queue_state: queue_state has no row.\n");
            goto error;
        }
    
        res->volume = sqlite3_column_int(stmt, 0);
        res->paused = sqlite3_column_int(stmt, 1);
        res->random = sqlite3_column_int(stmt, 2);
        res->repeat = sqlite3_column_int(stmt, 3);
        res->single = sqlite3_column_int(stmt, 4);
    
        if (sqlite3_column_type(stmt, 5) == SQLITE_NULL)
            res->current = -1;
        else
            res->current = sqlite3_column_int(stmt, 5);
    
        if (sqlite3_column_type(stmt, 6) == SQLITE_NULL)
            res->duration = 0;
        else
            res->duration = sqlite3_column_int(stmt, 6);
    
        res->consume = sqlite3_column_int(stmt, 7);
        res->length = sqlite3_column_int(stmt, 8);
        ret = true;
    error:
        sqlite3_finalize(stmt);
        return ret;
    }
    
    bool
    database_queue_current_kara(sqlite3 *db, struct kara_metadata *res, int *id)
    {
        static const char *SQL_STMT =
            "SELECT song_name, source_name, category, language, author_name, song_type, song_number, kara_id"
            " FROM kara"
            " JOIN queue_ ON kara_id = kara.id"
            " JOIN queue_state ON current = position";
        sqlite3_stmt *stmt = 0;
        int ret = false;
    
        SQLITE_PREPARE(db, stmt, SQL_STMT, error);
    
        if (sqlite3_step(stmt) == SQLITE_ROW) {
            /* Here use gotos because of optimisations done by compilators.
               Most of the time it won't be NULL. */
            if (!res)
                goto no_metadata;
            strncpy(res->song_name, (const char *) sqlite3_column_text(stmt, 0), LEKTOR_TAG_MAX - 1);
            strncpy(res->source_name, (const char *) sqlite3_column_text(stmt, 1), LEKTOR_TAG_MAX - 1);
            strncpy(res->category, (const char *) sqlite3_column_text(stmt, 2), LEKTOR_TAG_MAX - 1);
            strncpy(res->language, (const char *) sqlite3_column_text(stmt, 3), LEKTOR_TAG_MAX - 1);
            strncpy(res->author_name, (const char *) sqlite3_column_text(stmt, 4), LEKTOR_TAG_MAX - 1);
            strncpy(res->song_type, (const char *) sqlite3_column_text(stmt, 5), LEKTOR_TAG_MAX - 1);
            res->song_number = sqlite3_column_int(stmt, 6);
    no_metadata:
            /* Most of the time this will be NULL. */
            if (id)
                *id = sqlite3_column_int(stmt, 7);
        } else {
            fprintf(stderr, " ! database_queue_current_kara: failed: %s\n",
                    sqlite3_errmsg(db));
            goto error;
        }
    
        ret = true;
    error:
        sqlite3_finalize(stmt);
        return ret;
    }
    
    static bool
    queue_add_with_col_like_str(sqlite3 *db, const char *col, const char *val, int priority)
    {
        if (is_sql_str_invalid(col)) {
            fprintf(stderr, " ! queue_add_with_col_like_str: Column name %s is invalid\n", col);
            return false;
        }
    
        char SQL[LKT_MAX_SQLITE_STATEMENT];
        static const char *SQL_STMT =
            "INSERT INTO queue (kara_id, priority)"
            "  SELECT id, ?"
            "  FROM kara"
            "  WHERE %s LIKE ? AND available = 1"
            "  ORDER BY RANDOM();";
        bool status = false;
        sqlite3_stmt *stmt = NULL;
    
        snprintf(SQL, LKT_MAX_SQLITE_STATEMENT - 1, SQL_STMT, col);
        SQL[LKT_MAX_SQLITE_STATEMENT - 1] = 0;
        SQLITE_PREPARE(db, stmt, SQL, error);
        SQLITE_BIND_INT(db, stmt, 1, priority, error);
        SQLITE_BIND_TEXT(db, stmt, 2, val, error);
    
        if (sqlite3_step(stmt) != SQLITE_DONE) {
            fprintf(stderr, " ! queue_add_with_col_like_str: Failed to insert: %s\n",
                    sqlite3_errmsg(db));
            goto error;
        }
    
        status = true;
    error:
        sqlite3_finalize(stmt);
        return status;
    }
    
    static bool
    queue_insert_with_col_like_str(sqlite3 *db, const char *col, const char *val, int pos)
    {
        if (is_sql_str_invalid(col)) {
            fprintf(stderr, " ! queue_insert_with_col_like_str: Column name %s is invalid\n", col);
            return false;
        }
    
        char SQL[LKT_MAX_SQLITE_STATEMENT];
        static const char *SQL_STMT =
            "BEGIN TRANSACTION;"
            "CREATE TEMPORARY TABLE queue_tmp"
            "  ( position_tmp INTEGER PRIMARY KEY AUTOINCREMENT"
            "  , kara_id_tmp INTEGER"
            "  , priority_tmp INTEGER NOT NULL DEFAULT 1 CHECK(priority > 0 AND priority < 6)"
            "  );"
            "INERT INTO queue_tmp (kara_id_tmp, priority_tmp)"
            "  SELECT (kara_id, priority)"
            "  FROM queue"
            "  WHERE position >= ?"
            "  ORDER BY position ASC;"
            "INSERT INTO queue (kara_id, priority)"
            "SELECT id, priority"
            "  FROM kara"
            "  WHERE %s LIKE ? AND available = 1"
            "  ORDER BY RANDOM();"
            "INSERT INTO queue (kara_id, priority)"
            "  SELECT kara_id_tmp, priority"
            "  FROM queue_tmp"
            "  ORDER BY position ASC;"
            "DROP TABLE queue_tmp;"
            "COMMIT TRANSACTION;";
        bool status = false;
        sqlite3_stmt *stmt = NULL;
    
        snprintf(SQL, LKT_MAX_SQLITE_STATEMENT - 1, SQL_STMT, col);
        SQL[LKT_MAX_SQLITE_STATEMENT - 1] = 0;
        SQLITE_PREPARE(db, stmt, SQL, error);
        SQLITE_BIND_INT(db, stmt, 1, pos, error);
        SQLITE_BIND_TEXT(db, stmt, 2, val, error);
    
        if (sqlite3_step(stmt) != SQLITE_DONE) {
            fprintf(stderr, " ! queue_insert_with_col_like_str: Failed to insert: %s\n",
                    sqlite3_errmsg(db));
            goto error;
        }
    
        status = true;
    error:
        sqlite3_finalize(stmt);
        return status;
    }
    
    bool
    database_queue_insert_query(sqlite3 *db, const char *query, int pos)
    {
        bool status = queue_insert_with_col_like_str(db, "string", query, pos);
    
        if (status)
            fprintf(stderr, " * database_queue_insert_query: Successfull add for query '%s'\n", query);
        else
            fprintf(stderr, " ! database_queue_insert_query: Failed to add for query '%s'\n", query);
    
        return status;
    }
    
    bool
    database_queue_add_plt(sqlite3 *db, const char *plt_name, int priority)
    {
        static const char *SQL_STMT =
            "INSERT INTO queue (kara_id, priority) "
            "SELECT kara.id, ?"
            "  FROM kara"
            "  JOIN kara_playlist ON kara_id = kara.id AND kara.available = 1"
            "  JOIN playlist ON playlist_id = playlist.id AND playlist.name = ?"
            "  ORDER BY RANDOM();";
        bool status = false;
        sqlite3_stmt *stmt = NULL;
    
        SQLITE_PREPARE(db, stmt, SQL_STMT, error);
        SQLITE_BIND_INT(db, stmt, 1, priority, error);
        SQLITE_BIND_TEXT(db, stmt, 2, plt_name, error);
    
        if (sqlite3_step(stmt) != SQLITE_DONE) {
            fprintf(stderr, " ! database_queue_add_plt: Failed to insert: %s\n",
                    sqlite3_errmsg(db));
            goto error;
        }
    
        status = true;
    error:
        sqlite3_finalize(stmt);
        return status;
    }
    
    bool
    database_queue_add_query(sqlite3 *db, const char *query, int priority)
    {
        bool status = queue_add_with_col_like_str(db, "string", query, priority);
    
        if (status)
            fprintf(stderr, " * database_queue_add_query: Successfull add for query '%s'\n", query);
        else
            fprintf(stderr, " ! database_queue_add_query: Failed to add for query '%s'\n", query);
    
        return status;
    }
    
    bool
    database_queue_add_author(sqlite3 *db, const char *author, int priority)
    {
        bool status = queue_add_with_col_like_str(db, "author_name", author, priority);
    
        if (status)
            fprintf(stderr, " * database_queue_add_author: Successfull add for author '%s'\n", author);
        else
            fprintf(stderr, " ! database_queue_add_author: Failed to add for author '%s'\n", author);
    
        return status;
    }
    
    bool
    database_queue_add_language(sqlite3 *db, const char *language, int priority)
    {
        bool status = queue_add_with_col_like_str(db, "language", language, priority);
    
        if (status)
            fprintf(stderr, " * database_queue_add_language: Successfull add for language '%s'\n", language);
        else
            fprintf(stderr, " ! database_queue_add_language: Failed to add for language '%s'\n", language);
    
        return status;
    }
    
    bool
    database_queue_add_category(sqlite3 *db, const char *cat, int priority)
    {
        bool status = queue_add_with_col_like_str(db, "song_type", cat, priority);
    
        if (status)
            fprintf(stderr, " * database_queue_add_category: Successfull add for category (lektor song_type) '%s'\n",
                    cat);
        else
            fprintf(stderr, " ! database_queue_add_category: Failed to add for category (lektor song_type) '%s'\n", cat);
    
        return status;
    }
    
    bool
    database_queue_add_type(sqlite3 *db, const char *type, int priority)
    {
        bool status = queue_add_with_col_like_str(db, "category", type, priority);
    
        if (status)
            fprintf(stderr, " * database_queue_add_type: Successfull add for type (lektor category) '%s'\n", type);
        else
            fprintf(stderr, " ! database_queue_add_type: Failed to add for type (lektor category) '%s'\n", type);
    
        return status;
    }
    
    bool
    database_queue_add_id(sqlite3 *db, int id, int priority)
    {
        static const char *SQL_STMT = "INSERT INTO queue (kara_id, priority) VALUES (?,?);";
        bool status = false;
        sqlite3_stmt *stmt = NULL;
    
        SQLITE_PREPARE(db, stmt, SQL_STMT, error);
        SQLITE_BIND_INT(db, stmt, 1, id, error);
        SQLITE_BIND_INT(db, stmt, 2, priority, error);
    
        if (sqlite3_step(stmt) != SQLITE_DONE)
            goto error;
    
        status = true;
    error:
        sqlite3_finalize(stmt);
        return status;
    }
    
    bool
    database_queue_del_id(sqlite3 *db, int id)
    {
        static const char *SQL_TEMPLATE =
            "BEGIN TRANSACTION;"
            "WITH before(pos) AS (SELECT position FROM queue_ JOIN queue_state WHERE position < current ORDER BY position DESC LIMIT 1) "
            "UPDATE queue_state SET current = CASE"
            " WHEN current IS NULL THEN NULL"
            " ELSE (SELECT pos FROM before) "
            "END WHERE current > (SELECT position FROM queue_ WHERE kara_id = %d);"
            "DELETE FROM queue WHERE kara_id = %d LIMIT 1;"
            "COMMIT TRANSACTION;";
        char SQL[LKT_MAX_SQLITE_STATEMENT];
        snprintf(SQL, LKT_MAX_SQLITE_STATEMENT - 1, SQL_TEMPLATE, id, id, id);
        SQL[LKT_MAX_SQLITE_STATEMENT - 1] = '\0';
        SQLITE_EXEC(db, SQL, error);
        return true;
    error:
        return false;
    }
    
    bool
    database_queue_next(sqlite3 *db, char filepath[PATH_MAX])
    {
        static const char *SQL_STMT =
            "SELECT file_path, position, RANDOM()"
            "  FROM kara"
            "  JOIN queue_ ON kara.id = queue_.kara_id"
            "  JOIN queue_state"
            "    ON current IS NULL"
            "    OR (CASE WHEN (SELECT single FROM queue_state LIMIT 1) = 1 THEN position = current"
            "             WHEN (SELECT random FROM queue_state LIMIT 1) = 1 THEN position <> current"
            "             ELSE position > current END)"
            "  ORDER BY CASE WHEN (SELECT random FROM queue_state LIMIT 1) = 1 THEN RANDOM() ELSE 2 END"
            "  LIMIT 1";
        char SQL_UPDATE[LKT_MAX_SQLITE_STATEMENT];
        bool status = false;
        int code = SQLITE_OK, id;
        sqlite3_stmt *stmt = NULL;
    
        SQLITE_PREPARE(db, stmt, SQL_STMT, error);
    
        code = sqlite3_step(stmt);
    
        if (code == SQLITE_ROW) {
            id = MAX(1, sqlite3_column_int(stmt, 1));
            snprintf(SQL_UPDATE, LKT_MAX_SQLITE_STATEMENT - 1, "UPDATE queue_state SET current = %d;", id);
            SQL_UPDATE[LKT_MAX_SQLITE_STATEMENT - 1] = 0;
    
            if (filepath != NULL)
                strncpy(filepath, (const char *) sqlite3_column_text(stmt, 0), PATH_MAX);
            else {
                fprintf(stderr, " ! database_queue_next: Failed to get file, id was %d\n", id);
                goto error;
            }
        }
    
        else if (code == SQLITE_DONE) {
            fprintf(stderr, " * database_queue_next: Failed to get next, no setting current to NULL\n");
            goto error;
        }
    
        else {
            fprintf(stderr, "database_queue_next: Failed to fetch next kara: %s\n",
                    sqlite3_errmsg(db));
            goto error;
        }
    
        SQLITE_EXEC(db, SQL_UPDATE, error);
        status = true;
    error:
        sqlite3_finalize(stmt);
        return status;
    }
    
    bool
    database_queue_toggle_pause(sqlite3 *db)
    {
        static const char *SQL_STMT = "UPDATE queue_state SET paused = 1 - paused";
        SQLITE_EXEC(db, SQL_STMT, error);
        return true;
    error:
        return false;
    }
    
    bool
    database_queue_prev(sqlite3 *db, char filepath[PATH_MAX])
    {
        static const char *SQL_STMT =
            "SELECT file_path, position "
            "  FROM kara"
            "  JOIN queue_ ON kara.id = queue_.kara_id"
            "  JOIN queue_state ON CASE "
            "    WHEN (SELECT single FROM queue_state LIMIT 1) = 1 THEN position = current"
            "    ELSE queue_.position < queue_state.current"
            "  END"
            "  ORDER BY position DESC LIMIT 1;";
        char SQL_UPDATE[LKT_MAX_SQLITE_STATEMENT];
        bool status = false;
        int code = SQLITE_OK, id;
        sqlite3_stmt *stmt = NULL;
    
        SQLITE_PREPARE(db, stmt, SQL_STMT, error);
        code = sqlite3_step(stmt);
    
        if (code == SQLITE_ROW) {
            id = MAX(1, sqlite3_column_int(stmt, 1));
            snprintf(SQL_UPDATE, LKT_MAX_SQLITE_STATEMENT - 1, "UPDATE queue_state SET current = %d;", id);
            SQL_UPDATE[LKT_MAX_SQLITE_STATEMENT - 1] = 0;
    
            if (filepath != NULL)
                strncpy(filepath, (const char *) sqlite3_column_text(stmt, 0), PATH_MAX);
            else {
                fprintf(stderr, " ! database_queue_prev: Failed to get file, position was %d\n", id);
                goto error;
            }
        }
    
        else if (code == SQLITE_DONE) {
            fprintf(stderr, " * database_queue_prev: Failed to get previous, no setting current to NULL\n");
            goto error;
        }
    
        else {
            fprintf(stderr, " ! database_queue_prev: Failed to fetch prev kara: %s\n",
                    sqlite3_errmsg(db));
            goto error;
        }
    
        SQLITE_EXEC(db, SQL_UPDATE, error);
        status = true;
    error:
        sqlite3_finalize(stmt);
        return status;
    }
    
    bool
    database_queue_clear(sqlite3 *db)
    {
        static const char *SQL_STMT =
            "DELETE FROM queue;"
            "DELETE FROM sqlite_sequence WHERE name = 'queue';"
            "UPDATE queue_state SET current = NULL;";
        SQLITE_EXEC(db, SQL_STMT, error);
        return true;
    error:
        return false;
    }
    
    bool
    database_queue_crop(sqlite3 *db)
    {
        static const char *SQL_STMT =
            "DELETE FROM queue WHERE queue.kara_id <> (SELECT current FROM queue_state LIMIT 1);";
        SQLITE_EXEC(db, SQL_STMT, error);
        return true;
    error:
        return false;
    }
    
    bool
    database_queue_move(sqlite3 *db, int from, int to)
    {
        /* stmt arguments in order:
         * 1. to
         * 2. to
         * 3. from
         */
        static const char *SQL_STMT =
            "BEGIN TRANSACTION;"
            "UPDATE queue SET position = position + 1 WHERE position >= ?;"
            "UPDATE queue SET position = ? WHERE position = ?;"
            "COMMIT TRANSACTION;";
        sqlite3_stmt *stmt = 0;
        bool ret = false;
        int code;
    
        SQLITE_PREPARE(db, stmt, SQL_STMT, error);
        SQLITE_BIND_INT(db, stmt, 1, to, error);
        SQLITE_BIND_INT(db, stmt, 2, to, error);
        SQLITE_BIND_INT(db, stmt, 3, from, error);
    
        code = sqlite3_step(stmt);
    
        if (code != SQLITE_ROW && code != SQLITE_DONE && code != SQLITE_OK) {
            fprintf(stderr, " ! database_queue_move: move failed.\n");
            goto error;
        }
    
        ret = true;
    error:
        sqlite3_finalize(stmt);
        return ret;
    }
    
    bool
    database_queue_play(sqlite3 *db, int pos)
    {
        static const char *SQL_STMT =
            "UPDATE queue_state SET current = ?, paused = 0"
            "  WHERE current <= 0 OR current IS NULL";
        int code = SQLITE_OK;
        bool ret = false;
        sqlite3_stmt *stmt = NULL;
    
        SQLITE_PREPARE(db, stmt, SQL_STMT, error);
        SQLITE_BIND_INT(db, stmt, 1, pos, error);
    
        code = sqlite3_step(stmt);
    
        if (code != SQLITE_OK && code != SQLITE_DONE) {
            fprintf(stderr, " ! database_queue_play: Failed to update queue_state: %s\n",
                    sqlite3_errmsg(db));
            goto error;
        }
    
        ret = true;
    error:
        return ret;
    }
    
    bool
    database_queue_stop(sqlite3 *db)
    {
        static const char *SQL_STMT = "UPDATE queue_state SET current = NULL;";
        SQLITE_EXEC(db, SQL_STMT, error);
        return true;
    error:
        return false;
    }
    
    bool
    database_queue_set_current_index(sqlite3 *db, int idx)
    {
        static const char *SQL_GET_TEMPLATE = "UPDATE queue_state SET current = %d;";
        char SQL_GET[LKT_MAX_SQLITE_STATEMENT];
    
        if (idx <= 0) {
            fprintf(stderr, " ! database_queue_set_current_index: an idx of %d is invalid, must be >= 0\n", idx);
            return false;
        }
    
        if (snprintf(SQL_GET, LKT_MAX_SQLITE_STATEMENT - 1, SQL_GET_TEMPLATE, idx) < 0) {
            fprintf(stderr, " ! database_queue_set_current_index: snprintf failed\n");
            return false;
        }
    
        SQL_GET[LKT_MAX_SQLITE_STATEMENT - 1] = 0;
        SQLITE_EXEC(db, SQL_GET, error);
        return true;
    error:
        return false;
    }
    
    bool
    database_queue_get_current_file(sqlite3 *db, char filepath[PATH_MAX])
    {
        static const char *SQL_STMT =
            "SELECT file_path"
            "  FROM kara"
            "  JOIN queue_ ON kara.id = queue_.kara_id"
            "  JOIN queue_state ON queue_.position = queue_state.current";
        bool status = false;
        int code = SQLITE_OK;
        sqlite3_stmt *stmt = NULL;
    
        if (filepath == NULL)
            goto error;
    
        SQLITE_PREPARE(db, stmt, SQL_STMT, error);
        code = sqlite3_step(stmt);
    
        if (code == SQLITE_ROW)
            strncpy(filepath, (const char *) sqlite3_column_text(stmt, 0), PATH_MAX);
    
        else {
            fprintf(stderr, "database_queue_get_current_file: Failed to fetch prev kara: %s\n",
                    sqlite3_errmsg(db));
            goto error;
        }
    
        status = true;
    error:
        sqlite3_finalize(stmt);
        return status;
    }
    
    bool
    database_queue_set_paused(sqlite3 *db, bool paused)
    {
        const char *SQL;
    
        if (paused)
            SQL = "UPDATE queue_state SET paused = 1;";
        else
            SQL = "UPDATE queue_state SET paused = 0;";
    
        SQLITE_EXEC(db, SQL, error);
        return true;
    error:
        return false;
    }
    
    bool
    database_queue_shuffle(sqlite3 *db)
    {
        const char *SQL =
            "BEGIN TRANSACTION;"
            /* Create temporary queue.  */
            "CREATE TEMPORARY TABLE queue_tmp"
            "  ( position INTEGER PRIMARY KEY AUTOINCREMENT CHECK(position > 0)"
            "  , kara_id INTEGER"
            "  , priority INTEGER NOT NULL DEFAULT 1 CHECK(priority > 0 AND priority < 6)"
            "  );"
            /* When current is NULL, that thing is also NULL, so no insertion is done.  */
            "INSERT INTO queue_tmp (kara_id, priority)"
            "  SELECT kara_id, priority"
            "  FROM queue"
            "  JOIN queue_state ON queue.position = queue_state.current;"
            /* Insert Max priority in order.  */
            "INSERT INTO queue_tmp (kara_id, priority)"
            "  SELECT kara_id, priority"
            "  FROM queue"
            "  JOIN queue_state ON"
            "    queue.position <> CASE"
            "      WHEN queue_state.current IS NOT NULL THEN queue_state.current"
            "      ELSE 0 END"
            "    AND queue.priority = 5;"
            /* Insert the others karas, where the priority is < 5.  */
            "INSERT INTO queue_tmp (kara_id, priority)"
            "  SELECT kara_id, priority"
            "  FROM queue"
            "  JOIN queue_state ON"
            "    queue.position <> CASE"
            "      WHEN queue_state.current IS NOT NULL THEN queue_state.current"
            "      ELSE 0 END"
            "    AND queue.priority <> 5"
            "  ORDER BY RANDOM();"
            /* Do the insertion in the other way.  */
            "DELETE FROM queue;"
            "DELETE FROM sqlite_sequence WHERE name = 'queue';"
            "INSERT INTO queue (position, kara_id, priority)"
            "  SELECT position, kara_id, priority"
            "  FROM queue_tmp"
            "  ORDER BY priority, position;"
            "DROP TABLE queue_tmp;"
            "DELETE FROM sqlite_sequence WHERE name = 'queue_tmp';"
            /* Set the current to the right kara when needed.  */
            "UPDATE queue_state"
            "  SET current ="
            "  CASE"
            "    WHEN current NOT NULL THEN 1"
            "    ELSE NULL"
            "  END;"
            "COMMIT;";
    
        SQLITE_EXEC(db, SQL, error);
        return true;
    error:
        return false;
    }
    
    bool
    database_queue_list_abs(sqlite3 *db, unsigned int from, unsigned int to, void *args,
                            database_callback callback)
    {
        const char *SQL_STMT =
            "WITH content AS ("
            " SELECT kara.id AS id, string, LENGTH(CAST(kara.id AS TEXT)) AS len"
            "  FROM queue_"
            "  JOIN kara ON kara_id = kara.id"
            "  WHERE position >= ? AND position <= ?"
            "  GROUP BY position ORDER BY position)"
            "SELECT id, string, (SELECT MAX(len) FROM content)"
            " FROM content;";
        int code, id, id_len;
        const char *row;
        bool ret = false;
        sqlite3_stmt *stmt;
    
        SQLITE_PREPARE(db, stmt, SQL_STMT, error);
        SQLITE_BIND_INT(db, stmt, 1, from, error);
        SQLITE_BIND_INT(db, stmt, 2, to, error);
    
        for (;;) {
            code = sqlite3_step(stmt);
    
    
            if (code == SQLITE_ROW) {
                id = sqlite3_column_int(stmt, 0);
                row = (const char *) sqlite3_column_text(stmt, 1);
                id_len = sqlite3_column_int(stmt, 2);
                if (callback(args, id, id_len, row))
                    continue;
                else
                    break;
            }
    
            else if (code == SQLITE_OK || code == SQLITE_DONE)
                goto done;
    
            else
                break;
        }
    
    done:
        ret = true;
    error:
        sqlite3_finalize(stmt);
        return ret;
    }
    
    bool
    database_queue_list_from(sqlite3 *db, unsigned int count, void *args,
                             database_callback callback)
    {
        const char *SQL_TEMPLATE =
            "WITH content AS ("
            " SELECT kara.id AS id, string, LENGTH(CAST(kara.id AS TEXT)) AS len"
            "  FROM queue_"
            "  JOIN queue_state ON queue_.position >= CASE"
            "    WHEN queue_state.current IS NULL THEN 1"
            "    ELSE queue_state.current END"
            "  JOIN kara ON kara_id = kara.id"
            "  GROUP BY position ORDER BY position LIMIT %d)"
            "SELECT id, string, (SELECT MAX(len) FROM content)"
            " FROM content;";
        static const int stmt_len = 512;
        char SQL_STMT[stmt_len];
        int code, id, id_len;
        const char *row;
        bool ret = false;
        sqlite3_stmt *stmt;
    
        snprintf(SQL_STMT, stmt_len, SQL_TEMPLATE, count);
        SQLITE_PREPARE(db, stmt, SQL_STMT, error);
    
        for (;;) {
            code = sqlite3_step(stmt);
    
    
            if (code == SQLITE_ROW) {
                id = sqlite3_column_int(stmt, 0);
                row = (const char *) sqlite3_column_text(stmt, 1);
                id_len = sqlite3_column_int(stmt, 2);
                if (callback(args, id, id_len, row))
                    continue;
                else
                    break;
            }
    
            else if (code == SQLITE_OK || code == SQLITE_DONE)
                goto done;
    
            else
                break;
        }
    
    done:
        ret = true;
    error:
        sqlite3_finalize(stmt);
        return ret;
    }