В SQLite, если я подготовлю оператор SELECT
и начинаю переходить через него, то до достижения последней строки результатов я выполняю другой оператор, который влияет на оператор SELECT
, который я перешагиваю, каков ожидаемый результат?Что такое определенное поведение SQLite при перемежении операторов, которые влияют друг на друга?
Я не могу найти что-либо в документации SQLite о том, что должно произойти, но это кажется очень распространенным случаем при программировании в многопоточной среде.
Ниже приведен файл C++, который можно скомпилировать и запустить в Windows, чтобы продемонстрировать ситуацию.
#include "stdafx.h"
#include "sqlite3.h"
#include <Windows.h>
#include <iostream>
#include <Knownfolders.h>
#include <Shlobj.h>
#include <wchar.h>
#include <comdef.h>
using namespace std;
int exec_sql(sqlite3 *db, const char* sql)
{
char *errmsg;
int result = sqlite3_exec(db, sql, NULL, NULL, &errmsg);
if (result != SQLITE_OK) {
cout << errmsg << endl;
return -1;
}
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
cout << "Running jsqltst with SQLite version: ";
cout << sqlite3_libversion();
cout << endl;
PWSTR userhome;
if (!SUCCEEDED(SHGetKnownFolderPath(FOLDERID_Profile, NULL, NULL, &userhome))) {
cout << "Failed getting user home dir\n";
return -1;
}
wcout << "User home: " << userhome << endl;
wchar_t *ws1 = userhome, *ws2 = L"\\test.sqlite";
wstring dbpath_str(ws1);
dbpath_str += wstring(ws2);
_bstr_t dbpath(dbpath_str.c_str());
cout << "DB path: " << dbpath << endl;
sqlite3 *db;
int result = sqlite3_open_v2(dbpath, &db, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, NULL);
if (result != SQLITE_OK) {
cout << sqlite3_errmsg(db) << endl;
return -1;
}
const char * create_stmt = "CREATE TABLE IF NOT EXISTS atable (id INTEGER PRIMARY KEY, name TEXT, number INTEGER);";
if (exec_sql(db, create_stmt) != 0) {
return -1;
}
const char * delete_stmt = "DELETE FROM atable;";
if (exec_sql(db, delete_stmt) != 0) {
return -1;
}
const char * insert_stmt = "INSERT INTO atable (name,number) VALUES ('Beta',77),('Alpha',99);";
if (exec_sql(db, insert_stmt) != 0) {
return -1;
}
sqlite3_stmt* select_ss;
const char * select_stmt = "SELECT * FROM atable;";
result = sqlite3_prepare_v2(db, select_stmt, -1, &select_ss, NULL);
if (result != SQLITE_OK) {
cout << sqlite3_errmsg(db) << endl;
return -1;
}
int i = 0;
boolean gotrow;
do {
result = sqlite3_step(select_ss);
gotrow = result == SQLITE_ROW;
if (gotrow) {
i++;
cout << "I got a row!" << endl;
if (i == 1) {
if (exec_sql(db, insert_stmt) != 0) {
return -1;
}
}
}
} while (gotrow);
cout << "Last result: " << result << ", errstr: " << sqlite3_errstr(result) << endl;
result = sqlite3_finalize(select_ss);
if (result != SQLITE_OK) {
cout << sqlite3_errmsg(db) << endl;
return -1;
}
return 0;
}
Возможные ответы: http://www.sqlite.org/transactional.html http://www.sqlite.org/atomiccommit.html http://www.sqlite.org/faq.html#q6 – Patashu
Спасибо за ссылки. Я уже смотрел на обоих. Первый просто объясняет, как SQLite гарантирует, что БД никогда не повреждается и не обрабатывает ошибки при совершении изменений, а второй просто говорит: «yup это потокобезопасно», но не объясняет ожидаемое поведение. – satur9nine
Эта страница кажется немного более полезной, и она содержит несколько интересных моментов в конце о временных таблицах, мне нужно будет узнать больше об этих проблемах и посмотреть, обеспечивают ли они решение этой проблемы: http: //www.sqlite. org/cvstrac/wiki? p = MultiThreading – satur9nine