#c #sql #c #sqlite
#c #sql #c #sqlite
Вопрос:
Я пытаюсь ввести данные, хранящиеся в переменных, из заданий, которые я генерирую, в таблицу SQL через C , хотя я продолжаю получать (нулевое) сообщение об ошибке.
Я пытался прочитать документацию, но я все еще относительно новичок в C , поэтому я не думаю, что полностью понимаю нюансы того, как именно они хотят, чтобы оператор переменной SQL обрабатывался. Я пробовал два разных способа, отличных от того, что я нашел путем поиска, и, похоже, я всегда получаю ошибку SQL = (null).
Первое, что я попробовал, было это: (обратите внимание, что БД открывается в другой функции, и она отлично работает для другого выполнения статического оператора SQL, который у меня был ранее.)
void Access_Database::insertAirportJobs(float pay, int expire, float weight, Airport ap, Airport source)
{
char* zErrMsg = 0; // Error message var
char* sql;
const char* pArg = "Row Tested";
snprintf(sql, sizeof(sql), "INSERT INTO JOBS (airport_ID,dest,pay,expire,weight) "
"VALUES (%i, %i, %f, %i, %f ); ", source.airport_ID, ap.airport_ID, pay, expire, weight);
sql[sizeof(sql) - 1] = '';
int rc = sqlite3_exec(db, sql, jobsCallback, (void*)pArg, amp;zErrMsg); // Execute the SQL statement that was passed in.
if (rc != SQLITE_OK)
{
fprintf(stderr, "nSQL error: %snn", zErrMsg);
sqlite3_free(zErrMsg);
}
else
{
fprintf(stdout, "Operation done successfullyn");
}
}
Это не сработало и выдало сообщение об ошибке, которое я отмечал ранее, поэтому я вернулся к поиску в Google и нашел это решение:
void Access_Database::insertAirportJobs(float pay, int expire, float weight, Airport ap, Airport source)
{
char* zErrMsg = 0; // Error message var
const char* sql = "INSERT INTO JOBS (airport_ID,dest,pay,expire,weight) VALUES (?, ?, ?, ?, ?)";
sqlite3_stmt* stmt;
const char* pszTest;
int rc = sqlite3_prepare_v2(db, sql, strlen(sql), amp;stmt, amp;pszTest);
if (rc == SQLITE_OK)
{
sqlite3_bind_int(stmt, 1, source.airport_ID);
sqlite3_bind_int(stmt, 2, ap.airport_ID);
sqlite3_bind_double(stmt, 3, pay);
sqlite3_bind_int(stmt, 4, expire);
sqlite3_bind_double(stmt, 5, weight);
// Commit the binds
sqlite3_step(stmt);
sqlite3_finalize(stmt);
}
if (rc != SQLITE_OK)
{
fprintf(stderr, "nSQL error: %snn", zErrMsg);
sqlite3_free(zErrMsg);
}
else
{
fprintf(stdout, "Operation done successfullyn");
}
}
Это тоже не сработало и выдало ту же ошибку. Если вместо этого я помещаю код, который отображается, когда я использую точку останова для проверки того, что происходит на сервере, в графический интерфейс, он работает отлично. Я действительно не знаю, что происходит не так, потому что сообщение об ошибке на самом деле не помогло мне найти что-нибудь хорошее в Google. Возможно, кто-нибудь из вас может просто рассказать мне о правильном методе для динамического оператора SQL для SQLite3. Любая помощь будет с благодарностью.
РЕДАКТИРОВАТЬ: по-видимому, я закрывал базу данных ранее в функции, которую я использовал для вызова этой функции. Упс. Второй пример в основном работал с некоторыми незначительными изменениями.
Комментарии:
1. первое решение не работает,
snprintf
не выделяет никакой памяти. Вам необходимо предоставить функции область памяти (пример: char SqlRequest[100] или динамически выделяемая память с помощью malloc)2. во втором решении на первый взгляд все в порядке, но в логике что-то не так. Смысл инструкции в том, чтобы сохранить ее и повторно использовать несколько раз, в вашем примере вы просто используете ее один раз. Вы можете сохранить его в своем классе и инициализировать в начале, уничтожить его в конце.
3. Если вам нужна дополнительная информация об ошибке, вы можете распечатать ошибку с помощью
sqlite3_errmsg(Database)
4. @Robert Для первого примера я попытался сначала инициализировать его как NULL, а затем вместо этого установить его размер, подобный sizeof(* sql), потому что я думал, что это то, что вы имели в виду, хотя я все еще получал сообщение об ошибке, в котором говорилось о неправильном параметре или другом неправильном использовании API. Для второго я просто исправил принтер сообщений об ошибках, и он напечатал ту же ошибку, что и первый. Смысл кода заключается в его повторном использовании. Я действительно не знаю, что вы подразумеваете под этим вторым комментарием, поскольку эта функция вызывается каждый раз, когда в программе создается новое «задание». Есть идеи?
5. ИСПРАВЛЕНО. Очевидно, я ранее закрыл свою базу данных в функции, и именно поэтому она не смогла получить к ней доступ. Упс. @Robert
Ответ №1:
В вашей первой версии sql
неинициализирован, даже если это не так sizeof(sql)
, возвращает размер указателя, а не размер массива.
В вашей второй версии ваше сообщение об ошибке равно нулю, потому что вы никогда не присваиваете ему значение, вы должны вызывать sqlite3_errmsg
, вы не должны вызывать sqlite3_free(zErrMsg);
, поскольку sqlite управляет собственной памятью для сообщений об ошибках.
Комментарии:
1. На самом деле, если
sqlite3_exec()
устанавливается сообщение об ошибке, оно должно быть освобождено,sqlite3_free()
когда вы закончите с ним, как сказано в документации . Конечно, не для второго блока кода OP.2. @Shawn Хорошо, да, я говорил о второй версии
3. Для первого примера я попытался сначала инициализировать его как NULL, а затем вместо этого установить его размер like
sizeof(*sql)
, потому что я думал, что это то, что вы имели в виду, хотя я все еще получал сообщение об ошибке, в котором говорилось о неправильном параметре или другом неправильном использовании API. Для второго я просто исправил принтер сообщений об ошибках, и он напечатал ту же ошибку, что и первый. Есть идеи @AlanBirtles?4. ИСПРАВЛЕНО. Очевидно, я ранее закрыл свою базу данных в функции, и именно поэтому она не смогла получить к ней доступ. Упс. @AlanBirtles