Merge the store-sqlite branch back onto trunk
This commit is contained in:
+161
-28
@@ -15,12 +15,22 @@
|
||||
#include <msgapi.h>
|
||||
#include <sqlite3.h>
|
||||
|
||||
// #define DEBUG(x,y) printf("sql3: " x, y);
|
||||
#define DEBUG(x,y) ;
|
||||
|
||||
MsgSQLHandle *
|
||||
MsgSQLOpen(char *path, BongoMemStack *memstack, int locktimeoutms)
|
||||
{
|
||||
MsgSQLHandle *handle = NULL;
|
||||
int create = 0;
|
||||
|
||||
#if 0
|
||||
if (! sqlite3_threadsafe()) {
|
||||
XplConsolePrintf("msgapi: SQLite needs to be compiled thread-safe. Cannot run.\n");
|
||||
abort();
|
||||
}
|
||||
#endif
|
||||
|
||||
create = access(path, 0);
|
||||
|
||||
if (!(handle = MemMalloc(sizeof(MsgSQLHandle))) ||
|
||||
@@ -31,28 +41,23 @@ MsgSQLOpen(char *path, BongoMemStack *memstack, int locktimeoutms)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
DEBUG("open handle %ld\n", handle->db)
|
||||
|
||||
handle->memstack = memstack;
|
||||
handle->lockTimeoutMs = locktimeoutms;
|
||||
XplMutexInit(handle->transactionLock);
|
||||
|
||||
// FIXME
|
||||
/* if (create && DStoreCreateDB(handle)) {
|
||||
printf("Couldn't open db");
|
||||
goto fail;
|
||||
if (create) {
|
||||
handle->isNew = TRUE;
|
||||
} else {
|
||||
handle->isNew = FALSE;
|
||||
}
|
||||
|
||||
if (UpgradeDB(handle)) {
|
||||
goto fail;
|
||||
}
|
||||
*/
|
||||
return handle;
|
||||
|
||||
fail:
|
||||
if (handle) {
|
||||
if (handle->db) {
|
||||
sqlite3_close(handle->db);
|
||||
}
|
||||
|
||||
MemFree(handle);
|
||||
MsgSQLClose(handle);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@@ -61,19 +66,37 @@ void
|
||||
MsgSQLClose(MsgSQLHandle *handle)
|
||||
{
|
||||
MsgSQLReset(handle);
|
||||
XplMutexDestroy(handle->transactionLock);
|
||||
if (SQLITE_BUSY == sqlite3_close(handle->db)) {
|
||||
// FIXME logging
|
||||
XplConsolePrintf ("msgapi: couldn't close database\r\n");
|
||||
}
|
||||
DEBUG("close handle %ld\n\n", handle->db)
|
||||
|
||||
MemFree(handle);
|
||||
}
|
||||
|
||||
void
|
||||
MsgSQLEndStatement(MsgSQLStatement *_stmt)
|
||||
{
|
||||
int result;
|
||||
if (_stmt && _stmt->stmt) {
|
||||
result = sqlite3_reset(_stmt->stmt);
|
||||
if (result != SQLITE_OK)
|
||||
printf("Error ending statement: %d\n", result);
|
||||
DEBUG("reset stmt %ld\n", _stmt->stmt)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MsgSQLFinalize(MsgSQLStatement *stmt)
|
||||
{
|
||||
int result;
|
||||
if (stmt->stmt) {
|
||||
sqlite3_finalize(stmt->stmt);
|
||||
result = sqlite3_finalize(stmt->stmt);
|
||||
if (result != SQLITE_OK)
|
||||
printf("Error finalizing statement: %d\n", result);
|
||||
DEBUG("final stmt %ld\n", stmt->stmt)
|
||||
stmt->stmt = NULL;
|
||||
}
|
||||
}
|
||||
@@ -87,10 +110,7 @@ MsgSQLReset(MsgSQLHandle *handle)
|
||||
stmt <= &handle->stmts.end;
|
||||
stmt++)
|
||||
{
|
||||
if (stmt->stmt) {
|
||||
sqlite3_finalize(stmt->stmt);
|
||||
stmt->stmt = NULL;
|
||||
}
|
||||
MsgSQLFinalize(stmt);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,16 +138,29 @@ int
|
||||
MsgSQLBeginTransaction(MsgSQLHandle *handle)
|
||||
{
|
||||
MsgSQLStatement *stmt;
|
||||
int result;
|
||||
int result, reset;
|
||||
int count = 1 + handle->lockTimeoutMs / MSGSQL_STMT_SLEEP_MS;
|
||||
|
||||
BOOL locked = FALSE;
|
||||
|
||||
// acquire the transaction lock to prevent other people doing stuff
|
||||
if (handle->transactionDepth) {
|
||||
/* FIXME: ensure it's an exclusive transaction */
|
||||
DEBUG("* Need to acquire lock already taken\n", NULL)
|
||||
locked = TRUE;
|
||||
}
|
||||
XplMutexLock(handle->transactionLock);
|
||||
if (locked) {
|
||||
DEBUG("* Acquired lock successfully\n", NULL)
|
||||
}
|
||||
/*
|
||||
if (handle->transactionDepth) {
|
||||
// FIXME: ensure it's an exclusive transaction
|
||||
XplConsolePrintf("IMMEDIATE ERROR: transaction started on handler in use\n");
|
||||
abort ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
stmt = MsgSQLPrepare(handle, "BEGIN EXCLUSIVE TRANSACTION;", &handle->stmts.begin);
|
||||
*/
|
||||
|
||||
stmt = MsgSQLPrepare(handle, "BEGIN TRANSACTION;", &handle->stmts.begin);
|
||||
if (!stmt) {
|
||||
//DStoreStmtError(handle, stmt);
|
||||
return -1;
|
||||
@@ -135,16 +168,19 @@ MsgSQLBeginTransaction(MsgSQLHandle *handle)
|
||||
|
||||
do {
|
||||
result = sqlite3_step(stmt->stmt);
|
||||
sqlite3_reset(stmt->stmt);
|
||||
DEBUG("BEGIN TRAN stmt %ld\n", stmt->stmt)
|
||||
reset = sqlite3_reset(stmt->stmt);
|
||||
DEBUG(" - bt reset stmt %ld\n", stmt->stmt)
|
||||
} while (SQLITE_BUSY == result && --count && (XplDelay(MSGSQL_STMT_SLEEP_MS), 1));
|
||||
|
||||
switch (result) {
|
||||
case SQLITE_DONE:
|
||||
++handle->transactionDepth;
|
||||
++(handle->transactionDepth);
|
||||
return 0;
|
||||
case SQLITE_BUSY:
|
||||
return -2;
|
||||
default:
|
||||
printf("Database error %d : %s\n", result, sqlite3_errmsg(stmt->stmt));
|
||||
//DStoreStmtError(handle, stmt);
|
||||
return -1;
|
||||
}
|
||||
@@ -166,13 +202,17 @@ MsgSQLCommitTransaction(MsgSQLHandle *handle)
|
||||
|
||||
do {
|
||||
result = sqlite3_step(stmt->stmt);
|
||||
DEBUG("COMMIT stmt %ld\n", stmt->stmt)
|
||||
sqlite3_reset(stmt->stmt);
|
||||
DEBUG(" - ct reset stmt %ld\n", stmt->stmt)
|
||||
} while (SQLITE_BUSY == result && --count && (XplDelay(MSGSQL_STMT_SLEEP_MS), 1));
|
||||
|
||||
--handle->transactionDepth;
|
||||
XplMutexUnlock(handle->transactionLock);
|
||||
|
||||
if (SQLITE_DONE != result) {
|
||||
// DStoreStmtError(handle, stmt);
|
||||
printf("Database commit error %d: %s\n", result, sqlite3_errmsg(stmt->stmt));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
@@ -195,8 +235,12 @@ MsgSQLAbortTransaction(MsgSQLHandle *handle)
|
||||
if (SQLITE_DONE != result) {
|
||||
// DStoreStmtError(handle, stmt);
|
||||
}
|
||||
DEBUG("ABORT stmt %ld\n", stmt->stmt)
|
||||
sqlite3_reset(stmt->stmt);
|
||||
DEBUG(" - at reset stmt %ld\n", stmt->stmt)
|
||||
--handle->transactionDepth;
|
||||
XplMutexUnlock(handle->transactionLock);
|
||||
|
||||
return SQLITE_DONE == result ? 0 : -1;
|
||||
}
|
||||
|
||||
@@ -214,15 +258,23 @@ MsgSQLCancelTransactions(MsgSQLHandle *handle)
|
||||
MsgSQLStatement *
|
||||
MsgSQLPrepare(MsgSQLHandle *handle, const char *statement, MsgSQLStatement *stmt)
|
||||
{
|
||||
int ret;
|
||||
int count = 1 + handle->lockTimeoutMs / MSGSQL_STMT_SLEEP_MS;
|
||||
|
||||
DEBUG("PREPARE '%s'\n", statement)
|
||||
// stmt->filter = NULL;
|
||||
if (stmt->stmt) {
|
||||
if (stmt == NULL) return NULL; // we need an output
|
||||
|
||||
if (stmt && stmt->stmt) {
|
||||
return stmt;
|
||||
}
|
||||
stmt->query = statement;
|
||||
|
||||
while (count--) {
|
||||
switch (sqlite3_prepare(handle->db, statement, -1, &stmt->stmt, NULL)) {
|
||||
ret = sqlite3_prepare(handle->db, statement, -1, &stmt->stmt, NULL);
|
||||
DEBUG(" - new statement %ld\n", stmt->stmt)
|
||||
|
||||
switch (ret) {
|
||||
case SQLITE_OK:
|
||||
return stmt;
|
||||
case SQLITE_BUSY:
|
||||
@@ -239,9 +291,17 @@ MsgSQLPrepare(MsgSQLHandle *handle, const char *statement, MsgSQLStatement *stmt
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
MsgSQLBindNull(MsgSQLStatement *stmt, int var)
|
||||
{
|
||||
DEBUG(" - bind null stmt %ld\n", stmt->stmt)
|
||||
return sqlite3_bind_null(stmt->stmt, var);
|
||||
}
|
||||
|
||||
int
|
||||
MsgSQLBindString(MsgSQLStatement *stmt, int var, const char *str, BOOL nullify)
|
||||
{
|
||||
DEBUG(" - bind str stmt %ld\n", stmt->stmt)
|
||||
if (str) {
|
||||
return sqlite3_bind_text(stmt->stmt, var, str, strlen(str), SQLITE_STATIC);
|
||||
} else {
|
||||
@@ -253,6 +313,20 @@ MsgSQLBindString(MsgSQLStatement *stmt, int var, const char *str, BOOL nullify)
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
MsgSQLBindInt(MsgSQLStatement *stmt, int var, int value)
|
||||
{
|
||||
DEBUG(" - bind int stmt %ld\n", stmt->stmt)
|
||||
return sqlite3_bind_int(stmt->stmt, var, value);
|
||||
}
|
||||
|
||||
int
|
||||
MsgSQLBindInt64(MsgSQLStatement *stmt, int var, uint64_t value)
|
||||
{
|
||||
DEBUG(" - bind in64 stmt %ld\n", stmt->stmt)
|
||||
return sqlite3_bind_int64(stmt->stmt, var, value);
|
||||
}
|
||||
|
||||
int
|
||||
MsgSQLExecute(MsgSQLHandle *handle, MsgSQLStatement *_stmt)
|
||||
{
|
||||
@@ -261,14 +335,31 @@ MsgSQLExecute(MsgSQLHandle *handle, MsgSQLStatement *_stmt)
|
||||
int result;
|
||||
|
||||
result = sqlite3_step(stmt);
|
||||
DEBUG("EXEC stmt %ld\n", stmt)
|
||||
// FIXME - do I need to reset this??
|
||||
if (SQLITE_DONE == result) {
|
||||
return 0;
|
||||
} else {
|
||||
XplConsolePrintf("Sql (%d): %s\r\n", result, sqlite3_errmsg(handle->db));
|
||||
XplConsolePrintf("Sql (%d): %s. Query: %s\r\n", result, sqlite3_errmsg(handle->db), _stmt->query);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
MsgSQLQuickExecute(MsgSQLHandle *handle, const char *query)
|
||||
{
|
||||
int result;
|
||||
char *error;
|
||||
|
||||
result = sqlite3_exec(handle->db, query, NULL, NULL, &error);
|
||||
DEBUG("QUICK EXEC\n", NULL)
|
||||
if (result == SQLITE_OK) return 0;
|
||||
|
||||
XplConsolePrintf("Sql QE: %s\r\n", error);
|
||||
sqlite3_free(error);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
MsgSQLStatementStep(MsgSQLHandle *handle, MsgSQLStatement *_stmt)
|
||||
{
|
||||
@@ -276,6 +367,7 @@ MsgSQLStatementStep(MsgSQLHandle *handle, MsgSQLStatement *_stmt)
|
||||
int count = 1 + handle->lockTimeoutMs / MSGSQL_STMT_SLEEP_MS;
|
||||
int dbg;
|
||||
while (count--) {
|
||||
DEBUG(" - f stmt step %ld\n", stmt)
|
||||
switch ((dbg = sqlite3_step(stmt))) {
|
||||
case SQLITE_ROW:
|
||||
return 1;
|
||||
@@ -302,6 +394,7 @@ MsgSQLResults(MsgSQLHandle *handle, MsgSQLStatement *_stmt)
|
||||
|
||||
while (count--) {
|
||||
result = sqlite3_step(stmt);
|
||||
DEBUG(" - f stmt results %ld\n", stmt)
|
||||
switch (result) {
|
||||
case SQLITE_DONE:
|
||||
return 0; // no more results
|
||||
@@ -322,3 +415,43 @@ MsgSQLResults(MsgSQLHandle *handle, MsgSQLStatement *_stmt)
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
MsgSQLLastRowID(MsgSQLHandle *handle)
|
||||
{
|
||||
return sqlite3_last_insert_rowid(handle->db);
|
||||
}
|
||||
|
||||
int
|
||||
MsgSQLResultInt(MsgSQLStatement *_stmt, int column)
|
||||
{
|
||||
DEBUG(" - result int %ld\n", _stmt->stmt)
|
||||
return sqlite3_column_int(_stmt->stmt, column);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
MsgSQLResultInt64(MsgSQLStatement *_stmt, int column)
|
||||
{
|
||||
DEBUG(" - result int64 %ld\n", _stmt->stmt)
|
||||
return (uint64_t) sqlite3_column_int64(_stmt->stmt, column);
|
||||
}
|
||||
|
||||
// FIXME : need a sensible API to detect errors
|
||||
int
|
||||
MsgSQLResultText(MsgSQLStatement *_stmt, int column, char *result, size_t result_size)
|
||||
{
|
||||
char *out;
|
||||
|
||||
DEBUG(" - result text %ld\n", _stmt->stmt)
|
||||
out = sqlite3_column_text(_stmt->stmt, column);
|
||||
if (out != NULL)
|
||||
strncpy(result, out, result_size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
MsgSQLResultTextPtr(MsgSQLStatement *_stmt, int column, char **ptr)
|
||||
{
|
||||
*ptr = sqlite3_column_text(_stmt->stmt, column);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user