Нужна помощь в хранении значения, которое я получаю из базы данных sqlite3, в переменной C

#c #sqlite

Вопрос:

У меня есть «Data.db» с 3 таблицами в нем, в которых хранятся какие-то «футбольные данные». Одна таблица предназначена для «команд» , а другая-для «игроков». Что я хочу сделать сейчас, так это получить «самый высокий» идентификатор от «Команд», чтобы я мог назначить новых игроков в эту команду. (У каждого игрока есть _teamId)

Я могу распечатать идентификатор, который мне нужен, используя этот запрос и идентификатор обратного вызова, который печатает только то значение, которое мне нужно.

Запрос:

 string query = "SELECT COUNT(ID) FROM TEAMS;";

highest_id = (sqlite3_exec(db, query.c_str(), callback_id, 0, amp;messageError));
 

Обратный звонок:

 int Team::callback_id(void* data, int count, char** values, char** columns) {
    int id = atoi(values[1]);

    std::cout << "callback_id says: " << id << endl;

    return 0;
}
 

Что мне нужно сделать, чтобы сохранить этот идентификатор из моей функции обратного вызова в переменной, которую я могу использовать позже в своей программе? Похоже, я не могу просто вернуть его, и я не могу просто присвоить значение идентификатора своему Team::_id , так как это приводит к ошибке:
'invalid use of member ‘Team::_id’ in static member function'

Помощь была бы очень признательна. Я все еще пытаюсь узнать больше о sqlite3 и, в частности, о функции обратного вызова, но я потратил так много времени на эту проблему, что не знаю, что еще я мог бы попробовать.

Комментарии:

1. Указатель void* часто используется в библиотеках C для предоставления контекста для операции функции. Вы можете считать это расширенной версией this указателя. Вы должны иметь возможность поместить свой объект c туда и сохранить его.

Ответ №1:

У вас есть void* аргумент, в sqlite3_exec котором вы в данный момент настроены 0 . Вместо этого передайте указатель на объект там. Это позволяет хранить то, что вам нравится, в этом объекте при обратном вызове.

Часто передается указатель на объект и вызывается static функция, не являющаяся членом этого объекта, для выполнения обратного вызова.

Пример:

 class Team {
public:
    void func() {
        std::string query = "SELECT COUNT(ID) FROM TEAMS;";
        sqlite3_exec(db, query.c_str(), amp;Team::callback_id_proxy, this, amp;messageError);
        //                                                        ^^^^
    }

    // a static callback proxy, casting `data` to a `Team*`
    static int callback_id_proxy(void* data, int count, char** values, char** columns) {
        return static_cast<Team*>(data)->callback_id(count, values, columns);
    }

    int callback_id(int count, char** values, char** columns) {
        // here you can store what you like in your `Team` object
        if(count > 0) highest_id = atoi(values[0]);
        else highest_id = 0;
        return 0;
    }

    int highest_id;
};
 

Примечание: Возможно, вы захотите использовать SELECT MAX(ID) FROM TEAMS; вместо этого. В противном случае вы можете получить дубликаты, если удалите команду, а затем добавите новую.

Другой вариант-сделать func и highest_id static тоже. Я переименовал highest_id его в number_of_teams «здесь», потому что это то, что есть на самом деле.

 class Team {
public:
    static int get_number_of_teams() {
        std::string query = "SELECT COUNT(ID) FROM TEAMS;";
        if(sqlite3_exec(db, query.c_str(),
                        amp;Team::callback_count,
                        nullptr,    // static function, no "this" available
                        amp;messageError) == SQLITE_ABORT)
            throw std::runtime_error("callback_id returned non-zero");

        return number_of_teams;
    }

    static int callback_count(void* data, int count, char** values, char** columns) {
        if(count > 0) {
            number_of_teams = atoi(values[0]);
            return 0;
        }
        return 1; // indicate error
    }

private:
    inline static int number_of_teams = -1;
};
 

Комментарии:

1. Я действительно ценю ваше время и помощь. Я попробовал сделать это так, как вы предложили, но почему-то я всегда получаю одно и то же значение 7 каким-то образом. Я не знаю, откуда это взялось, но это не меняется, независимо от того, сколько команд хранится в моей таблице «Команды». У вас есть какие-нибудь идеи, что может быть причиной этого?

2. Также я вставил std::cout << "ID in callback_id: " << atoi(values[0]) << std::endl; в свой callback_id, чтобы найти свой msitake, но он никогда ничего не выводит на консоль. Я неправильно вызываю функцию (нужно ли мне что-либо добавлять в ваш обратный вызов_id_proxy?) Я, очевидно, довольно новичок в C и не знаком с static_cast или ‘->’

3. @Embrano Нет, callback_id_proxy в моем ответе должно быть все как есть. Что count будет сказано, если вы напечатаете это в callback_id ? Это должно быть только 1 в том случае, если все работает. Кроме того, распечатайте значения без преобразования: for(int i = 0; i < count; i) std::cout << '>' << values[i] << "<n"; чтобы увидеть, покажет ли это что-нибудь

4. Также: Вы func() превратились в функцию-член Team , верно?

5. о, мой бог… Я чувствую себя так глупо сейчас … граф ничего не сказал, как и мой «идентификатор в callback_id:» ничего не сказал. Я сверил все с некоторыми более ранними набросками этого дерьма, которые я сделал, и понял, что нигде не было ‘sqlite3_open(«Data.db», amp;db)’. Я добавил это в функцию (), и вуаля, все, что вы мне дали, сработало как заклинание. Это дало мне правильный идентификатор, и у новых игроков, которых я сгенерировал, также был правильный идентификатор team_id.