Commit cfdbaf33 authored by Max Kellermann's avatar Max Kellermann

sticker/Database: add wrapper for sqlite3_step()

parent 052d350b
...@@ -77,4 +77,84 @@ BindAll(sqlite3_stmt *stmt, Args&&... args) ...@@ -77,4 +77,84 @@ BindAll(sqlite3_stmt *stmt, Args&&... args)
return BindAll2(stmt, 1, std::forward<Args>(args)...); return BindAll2(stmt, 1, std::forward<Args>(args)...);
} }
/**
* Call sqlite3_stmt() repepatedly until something other than
* SQLITE_BUSY is returned.
*/
static int
ExecuteBusy(sqlite3_stmt *stmt)
{
int result;
do {
result = sqlite3_step(stmt);
} while (result == SQLITE_BUSY);
return result;
}
/**
* Wrapper for ExecuteBusy() that returns true on SQLITE_ROW.
*/
static bool
ExecuteRow(sqlite3_stmt *stmt)
{
int result = ExecuteBusy(stmt);
if (result == SQLITE_ROW)
return true;
if (result != SQLITE_DONE)
LogError(sqlite_domain, "sqlite3_step() failed");
return false;
}
/**
* Wrapper for ExecuteBusy() that interprets everything other than
* SQLITE_DONE as error.
*/
static bool
ExecuteCommand(sqlite3_stmt *stmt)
{
int result = ExecuteBusy(stmt);
if (result != SQLITE_DONE) {
LogError(stmt, "sqlite3_step() failed");
return false;
}
return true;
}
/**
* Wrapper for ExecuteCommand() that returns the number of rows
* modified via sqlite3_changes(). Returns -1 on error.
*/
static inline int
ExecuteChanges(sqlite3_stmt *stmt)
{
if (!ExecuteCommand(stmt))
return -1;
return sqlite3_changes(sqlite3_db_handle(stmt));
}
template<typename F>
static inline bool
ExecuteForEach(sqlite3_stmt *stmt, F &&f)
{
while (true) {
switch (ExecuteBusy(stmt)) {
case SQLITE_ROW:
f();
break;
case SQLITE_DONE:
return true;
default:
LogError(sqlite_domain, "sqlite3_step() failed");
return false;
}
}
}
#endif #endif
...@@ -172,21 +172,9 @@ sticker_load_value(const char *type, const char *uri, const char *name) ...@@ -172,21 +172,9 @@ sticker_load_value(const char *type, const char *uri, const char *name)
if (!BindAll(stmt, type, uri, name)) if (!BindAll(stmt, type, uri, name))
return std::string(); return std::string();
int ret;
do {
ret = sqlite3_step(stmt);
} while (ret == SQLITE_BUSY);
std::string value; std::string value;
if (ret == SQLITE_ROW) { if (ExecuteRow(stmt))
/* record found */
value = (const char*)sqlite3_column_text(stmt, 0); value = (const char*)sqlite3_column_text(stmt, 0);
} else if (ret == SQLITE_DONE) {
/* no record found */
} else {
/* error */
LogError(sticker_db, "sqlite3_step() failed");
}
sqlite3_reset(stmt); sqlite3_reset(stmt);
sqlite3_clear_bindings(stmt); sqlite3_clear_bindings(stmt);
...@@ -207,33 +195,16 @@ sticker_list_values(std::map<std::string, std::string> &table, ...@@ -207,33 +195,16 @@ sticker_list_values(std::map<std::string, std::string> &table,
if (!BindAll(stmt, type, uri)) if (!BindAll(stmt, type, uri))
return false; return false;
int ret; const bool success = ExecuteForEach(stmt, [stmt, &table](){
do { const char *name = (const char *)sqlite3_column_text(stmt, 0);
ret = sqlite3_step(stmt); const char *value = (const char *)sqlite3_column_text(stmt, 1);
switch (ret) {
const char *name, *value;
case SQLITE_ROW:
name = (const char*)sqlite3_column_text(stmt, 0);
value = (const char*)sqlite3_column_text(stmt, 1);
table.insert(std::make_pair(name, value)); table.insert(std::make_pair(name, value));
break; });
case SQLITE_DONE:
break;
case SQLITE_BUSY:
/* no op */
break;
default:
LogError(sticker_db, "sqlite3_step() failed");
return false;
}
} while (ret != SQLITE_DONE);
sqlite3_reset(stmt); sqlite3_reset(stmt);
sqlite3_clear_bindings(stmt); sqlite3_clear_bindings(stmt);
return true; return success;
} }
static bool static bool
...@@ -253,17 +224,9 @@ sticker_update_value(const char *type, const char *uri, ...@@ -253,17 +224,9 @@ sticker_update_value(const char *type, const char *uri,
if (!BindAll(stmt, value, type, uri, name)) if (!BindAll(stmt, value, type, uri, name))
return false; return false;
int ret; int ret = ExecuteChanges(stmt);
do { if (ret < 0)
ret = sqlite3_step(stmt);
} while (ret == SQLITE_BUSY);
if (ret != SQLITE_DONE) {
LogError(sticker_db, "sqlite3_step() failed");
return false; return false;
}
ret = sqlite3_changes(sticker_db);
sqlite3_reset(stmt); sqlite3_reset(stmt);
sqlite3_clear_bindings(stmt); sqlite3_clear_bindings(stmt);
...@@ -289,20 +252,12 @@ sticker_insert_value(const char *type, const char *uri, ...@@ -289,20 +252,12 @@ sticker_insert_value(const char *type, const char *uri,
if (!BindAll(stmt, type, uri, name, value)) if (!BindAll(stmt, type, uri, name, value))
return false; return false;
int ret; if (!ExecuteCommand(stmt))
do {
ret = sqlite3_step(stmt);
} while (ret == SQLITE_BUSY);
if (ret != SQLITE_DONE) {
LogError(sticker_db, "sqlite3_step() failed");
return false; return false;
}
sqlite3_reset(stmt); sqlite3_reset(stmt);
sqlite3_clear_bindings(stmt); sqlite3_clear_bindings(stmt);
idle_add(IDLE_STICKER); idle_add(IDLE_STICKER);
return true; return true;
} }
...@@ -336,15 +291,8 @@ sticker_delete(const char *type, const char *uri) ...@@ -336,15 +291,8 @@ sticker_delete(const char *type, const char *uri)
if (!BindAll(stmt, type, uri)) if (!BindAll(stmt, type, uri))
return false; return false;
int ret; if (!ExecuteCommand(stmt))
do {
ret = sqlite3_step(stmt);
} while (ret == SQLITE_BUSY);
if (ret != SQLITE_DONE) {
LogError(sticker_db, "sqlite3_step() failed");
return false; return false;
}
sqlite3_reset(stmt); sqlite3_reset(stmt);
sqlite3_clear_bindings(stmt); sqlite3_clear_bindings(stmt);
...@@ -365,17 +313,9 @@ sticker_delete_value(const char *type, const char *uri, const char *name) ...@@ -365,17 +313,9 @@ sticker_delete_value(const char *type, const char *uri, const char *name)
if (!BindAll(stmt, type, uri, name)) if (!BindAll(stmt, type, uri, name))
return false; return false;
int ret; int ret = ExecuteChanges(stmt);
do { if (ret < 0)
ret = sqlite3_step(stmt);
} while (ret == SQLITE_BUSY);
if (ret != SQLITE_DONE) {
LogError(sticker_db, "sqlite3_step() failed");
return false; return false;
}
ret = sqlite3_changes(sticker_db);
sqlite3_reset(stmt); sqlite3_reset(stmt);
sqlite3_clear_bindings(stmt); sqlite3_clear_bindings(stmt);
...@@ -444,28 +384,14 @@ sticker_find(const char *type, const char *base_uri, const char *name, ...@@ -444,28 +384,14 @@ sticker_find(const char *type, const char *base_uri, const char *name,
if (!BindAll(stmt, type, base_uri, name)) if (!BindAll(stmt, type, base_uri, name))
return false; return false;
int ret; const bool success = ExecuteForEach(stmt, [stmt, func, user_data](){
do {
ret = sqlite3_step(stmt);
switch (ret) {
case SQLITE_ROW:
func((const char*)sqlite3_column_text(stmt, 0), func((const char*)sqlite3_column_text(stmt, 0),
(const char*)sqlite3_column_text(stmt, 1), (const char*)sqlite3_column_text(stmt, 1),
user_data); user_data);
break; });
case SQLITE_DONE:
break;
case SQLITE_BUSY:
/* no op */
break;
default:
LogError(sticker_db, "sqlite3_step() failed");
return false;
}
} while (ret != SQLITE_DONE);
sqlite3_reset(stmt); sqlite3_reset(stmt);
sqlite3_clear_bindings(stmt); sqlite3_clear_bindings(stmt);
return true; return success;
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment