#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.