Issue #69: continue work on multi-bind varargs

Revise sqlite_prepare() macro et al and underlying functions to use bind
varargs instead of sprintf(3)-style varargs.

Convert all SQL function calls in rhizome_database.c
This commit is contained in:
Andrew Bettison 2013-10-03 01:16:10 +09:30
parent 772e1bf9d6
commit 8f7d600216
2 changed files with 224 additions and 150 deletions

View File

@ -294,34 +294,60 @@ int (*sqlite_set_tracefunc(int (*newfunc)()))();
int is_debug_rhizome(); int is_debug_rhizome();
int is_debug_rhizome_ads(); int is_debug_rhizome_ads();
sqlite3_stmt *_sqlite_prepare_loglevel(struct __sourceloc, int log_level, sqlite_retry_state *retry, const char *sqltext); enum sqlbind_type {
END = 0xbabecafe,
NUL = 0xbeef, // int index
INT, // int index, int value
INT64, // int index, int64_t value
STATIC_TEXT, // int index, const char *text,
STATIC_TEXT_LEN, // int index, const char *text, int bytes
STATIC_BLOB, // int index, const void *blob, int bytes
SID_T, // int index, const sid_t *sidp
BUNDLE_ID_T, // int index, const unsigned char bid_binary[RHIZOME_BUNDLE_ID_BYTES]
FILEHASH_T, // int index, const unsigned char hash_binary[RHIZOME_FILEHASH_BYTES]
TOHEX, // int index, const unsigned char *binary, unsigned bytes
TEXT_TOUPPER, // int index, const char *text,
TEXT_LEN_TOUPPER, // int index, const char *text, unsigned bytes
INDEX = 0xfade0000, // INDEX|INT, int index, ...
NAMED = 0xdead0000 // NAMED|INT, const char *label, ...
};
sqlite3_stmt *_sqlite_prepare_bind_loglevel(struct __sourceloc, int log_level, sqlite_retry_state *retry, const char *sqltext, ...);
int _sqlite_bind(struct __sourceloc __whence, int log_level, sqlite_retry_state *retry, sqlite3_stmt *statement, ...);
int _sqlite_vbind(struct __sourceloc __whence, int log_level, sqlite_retry_state *retry, sqlite3_stmt *statement, va_list ap);
int _sqlite_retry(struct __sourceloc, sqlite_retry_state *retry, const char *action); int _sqlite_retry(struct __sourceloc, sqlite_retry_state *retry, const char *action);
void _sqlite_retry_done(struct __sourceloc, sqlite_retry_state *retry, const char *action); void _sqlite_retry_done(struct __sourceloc, sqlite_retry_state *retry, const char *action);
int _sqlite_step_retry(struct __sourceloc, int log_level, sqlite_retry_state *retry, sqlite3_stmt *statement); int _sqlite_step_retry(struct __sourceloc, int log_level, sqlite_retry_state *retry, sqlite3_stmt *statement);
int _sqlite_exec_void(struct __sourceloc, const char *sqlformat, ...); int _sqlite_exec_void(struct __sourceloc, const char *sqltext, ...);
int _sqlite_exec_void_loglevel(struct __sourceloc, int log_level, const char *sqlformat, ...); int _sqlite_exec_void_loglevel(struct __sourceloc, int log_level, const char *sqltext, ...);
int _sqlite_exec_void_retry(struct __sourceloc, sqlite_retry_state *retry, const char *sqlformat, ...); int _sqlite_exec_void_retry(struct __sourceloc, sqlite_retry_state *retry, const char *sqltext, ...);
int _sqlite_exec_void_retry_loglevel(struct __sourceloc, int log_level, sqlite_retry_state *retry, const char *sqlformat, ...); int _sqlite_exec_void_retry_loglevel(struct __sourceloc, int log_level, sqlite_retry_state *retry, const char *sqltext, ...);
int _sqlite_exec_int64(struct __sourceloc, int64_t *result, const char *sqlformat, ...); int _sqlite_exec_int64(struct __sourceloc, int64_t *result, const char *sqltext, ...);
int _sqlite_exec_int64_retry(struct __sourceloc, sqlite_retry_state *retry, int64_t *result, const char *sqlformat, ...); int _sqlite_exec_int64_retry(struct __sourceloc, sqlite_retry_state *retry, int64_t *result, const char *sqltext, ...);
int _sqlite_exec_strbuf(struct __sourceloc, strbuf sb, const char *sqlformat, ...); int _sqlite_exec_strbuf(struct __sourceloc, strbuf sb, const char *sqltext, ...);
int _sqlite_exec_strbuf_retry(struct __sourceloc, sqlite_retry_state *retry, strbuf sb, const char *sqlformat, ...); int _sqlite_exec_strbuf_retry(struct __sourceloc, sqlite_retry_state *retry, strbuf sb, const char *sqltext, ...);
int _sqlite_vexec_strbuf_retry(struct __sourceloc, sqlite_retry_state *retry, strbuf sb, const char *sqlformat, va_list ap); int _sqlite_vexec_strbuf_retry(struct __sourceloc, sqlite_retry_state *retry, strbuf sb, const char *sqltext, va_list ap);
#define sqlite_prepare(rs,text) _sqlite_prepare_loglevel(__WHENCE__, LOG_LEVEL_ERROR, (rs), (text)) // The 'arg' arguments in the following macros appear to be unnecessary, but
#define sqlite_prepare_loglevel(ll,rs,text) _sqlite_prepare_loglevel(__WHENCE__, (ll), (rs), (text)) // they serve a very useful purpose, so don't remove them! They ensure that
#define sqlite_retry(rs,action) _sqlite_retry(__WHENCE__, (rs), (action)) // programmers do not forget the bind args, of which there must be at least
#define sqlite_retry_done(rs,action) _sqlite_retry_done(__WHENCE__, (rs), (action)) // one, even if it is only 'END' to make no bindings at all.
#define sqlite_step(stmt) _sqlite_step_retry(__WHENCE__, LOG_LEVEL_ERROR, NULL, (stmt)) #define sqlite_prepare(rs,sql) _sqlite_prepare_bind_loglevel(__WHENCE__, LOG_LEVEL_ERROR, (rs), (sql), END)
#define sqlite_step_retry(rs,stmt) _sqlite_step_retry(__WHENCE__, LOG_LEVEL_ERROR, (rs), (stmt)) #define sqlite_prepare_loglevel(ll,rs,sql) _sqlite_prepare_bind_loglevel(__WHENCE__, (ll), (rs), (sql), END)
#define sqlite_exec_void(fmt,...) _sqlite_exec_void(__WHENCE__, (fmt), ##__VA_ARGS__) #define sqlite_prepare_bind(rs,sql,arg,...) _sqlite_prepare_bind_loglevel(__WHENCE__, LOG_LEVEL_ERROR, (rs), (sql), arg, ##__VA_ARGS__)
#define sqlite_exec_void_loglevel(ll,fmt,...) _sqlite_exec_void_loglevel(__WHENCE__, (ll), (fmt), ##__VA_ARGS__) #define sqlite_prepare_bind_loglevel(ll,rs,sql,arg,...) _sqlite_prepare_bind_loglevel(__WHENCE__, (ll), (rs), (sql), arg, ##__VA_ARGS__)
#define sqlite_exec_void_retry(rs,fmt,...) _sqlite_exec_void_retry(__WHENCE__, (rs), (fmt), ##__VA_ARGS__) #define sqlite_retry(rs,action) _sqlite_retry(__WHENCE__, (rs), (action))
#define sqlite_exec_void_retry_loglevel(ll,rs,fmt,...) _sqlite_exec_void_retry_loglevel(__WHENCE__, (ll), (rs), (fmt), ##__VA_ARGS__) #define sqlite_retry_done(rs,action) _sqlite_retry_done(__WHENCE__, (rs), (action))
#define sqlite_exec_int64(res,fmt,...) _sqlite_exec_int64(__WHENCE__, (res), (fmt), ##__VA_ARGS__) #define sqlite_step(stmt) _sqlite_step_retry(__WHENCE__, LOG_LEVEL_ERROR, NULL, (stmt))
#define sqlite_exec_int64_retry(rs,res,fmt,...) _sqlite_exec_int64_retry(__WHENCE__, (rs), (res), (fmt), ##__VA_ARGS__) #define sqlite_step_retry(rs,stmt) _sqlite_step_retry(__WHENCE__, LOG_LEVEL_ERROR, (rs), (stmt))
#define sqlite_exec_strbuf(sb,fmt,...) _sqlite_exec_strbuf(__WHENCE__, (sb), (fmt), ##__VA_ARGS__) #define sqlite_exec_void(sql,arg,...) _sqlite_exec_void(__WHENCE__, (sql), ##__VA_ARGS__)
#define sqlite_exec_strbuf_retry(rs,sb,fmt,...) _sqlite_exec_strbuf_retry(__WHENCE__, (rs), (sb), (fmt), ##__VA_ARGS__) #define sqlite_exec_void_loglevel(ll,sql,arg,...) _sqlite_exec_void_loglevel(__WHENCE__, (ll), (sql), arg, ##__VA_ARGS__)
#define sqlite_exec_void_retry(rs,sql,arg,...) _sqlite_exec_void_retry(__WHENCE__, (rs), (sql), arg, ##__VA_ARGS__)
#define sqlite_exec_void_retry_loglevel(ll,rs,sql,arg,...) _sqlite_exec_void_retry_loglevel(__WHENCE__, (ll), (rs), (sql), arg, ##__VA_ARGS__)
#define sqlite_exec_int64(res,sql,arg,...) _sqlite_exec_int64(__WHENCE__, (res), (sql), arg, ##__VA_ARGS__)
#define sqlite_exec_int64_retry(rs,res,sql,arg,...) _sqlite_exec_int64_retry(__WHENCE__, (rs), (res), (sql), arg, ##__VA_ARGS__)
#define sqlite_exec_strbuf(sb,sql,arg,...) _sqlite_exec_strbuf(__WHENCE__, (sb), (sql), arg, ##__VA_ARGS__)
#define sqlite_exec_strbuf_retry(rs,sb,sql,arg,...) _sqlite_exec_strbuf_retry(__WHENCE__, (rs), (sb), (sql), arg, ##__VA_ARGS__)
double rhizome_manifest_get_double(rhizome_manifest *m,char *var,double default_value); double rhizome_manifest_get_double(rhizome_manifest *m,char *var,double default_value);
int rhizome_manifest_extract_signature(rhizome_manifest *m,int *ofs); int rhizome_manifest_extract_signature(rhizome_manifest *m,int *ofs);

View File

@ -81,11 +81,11 @@ int rhizome_manifest_priority(sqlite_retry_state *retry, const char *id)
{ {
int64_t result = 0; int64_t result = 0;
if (sqlite_exec_int64_retry(retry, &result, if (sqlite_exec_int64_retry(retry, &result,
"select max(grouplist.priorty) from grouplist,manifests,groupmemberships" "SELECT max(grouplist.priorty) FROM GROUPLIST,MANIFESTS,GROUPMEMBERSHIPS"
" where manifests.id='%s'" " WHERE MANIFESTS.id = ?"
" and grouplist.id=groupmemberships.groupid" " AND GROUPLIST.id = GROUPMEMBERSHIPS.groupid"
" and groupmemberships.manifestid=manifests.id;", " AND GROUPMEMBERSHIPS.manifestid = MANIFESTS.id;",
id TEXT_TOUPPER, id, END
) == -1 ) == -1
) )
return -1; return -1;
@ -166,7 +166,7 @@ void verify_bundles(){
} }
if (ret!=0){ if (ret!=0){
DEBUGF("Removing invalid manifest entry @%lld", rowid); DEBUGF("Removing invalid manifest entry @%lld", rowid);
sqlite_exec_void_retry(&retry, "DELETE FROM MANIFESTS WHERE ROWID=%lld;", rowid); sqlite_exec_void_retry(&retry, "DELETE FROM MANIFESTS WHERE ROWID = ?;", INT64, rowid, END);
} }
rhizome_manifest_free(m); rhizome_manifest_free(m);
} }
@ -234,47 +234,47 @@ int rhizome_opendb()
sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT; sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT;
int64_t version; int64_t version;
if (sqlite_exec_int64_retry(&retry, &version, "PRAGMA user_version;") == -1) if (sqlite_exec_int64_retry(&retry, &version, "PRAGMA user_version;", END) == -1)
RETURN(-1); RETURN(-1);
if (version<1){ if (version<1){
/* Create tables as required */ /* Create tables as required */
sqlite_exec_void_loglevel(loglevel, "PRAGMA auto_vacuum=2;"); sqlite_exec_void_loglevel(loglevel, "PRAGMA auto_vacuum=2;", END);
if ( sqlite_exec_void_retry(&retry, "CREATE TABLE IF NOT EXISTS GROUPLIST(id text not null primary key, closed integer,ciphered integer,priority integer);") == -1 if ( sqlite_exec_void_retry(&retry, "CREATE TABLE IF NOT EXISTS GROUPLIST(id text not null primary key, closed integer,ciphered integer,priority integer);", END) == -1
|| sqlite_exec_void_retry(&retry, "CREATE TABLE IF NOT EXISTS MANIFESTS(id text not null primary key, version integer,inserttime integer, filesize integer, filehash text, author text, bar blob, manifest blob);") == -1 || sqlite_exec_void_retry(&retry, "CREATE TABLE IF NOT EXISTS MANIFESTS(id text not null primary key, version integer,inserttime integer, filesize integer, filehash text, author text, bar blob, manifest blob);", END) == -1
|| sqlite_exec_void_retry(&retry, "CREATE TABLE IF NOT EXISTS FILES(id text not null primary key, length integer, highestpriority integer, datavalid integer, inserttime integer);") == -1 || sqlite_exec_void_retry(&retry, "CREATE TABLE IF NOT EXISTS FILES(id text not null primary key, length integer, highestpriority integer, datavalid integer, inserttime integer);", END) == -1
|| sqlite_exec_void_retry(&retry, "CREATE TABLE IF NOT EXISTS FILEBLOBS(id text not null primary key, data blob);") == -1 || sqlite_exec_void_retry(&retry, "CREATE TABLE IF NOT EXISTS FILEBLOBS(id text not null primary key, data blob);", END) == -1
|| sqlite_exec_void_retry(&retry, "DROP TABLE IF EXISTS FILEMANIFESTS;") == -1 || sqlite_exec_void_retry(&retry, "DROP TABLE IF EXISTS FILEMANIFESTS;", END) == -1
|| sqlite_exec_void_retry(&retry, "CREATE TABLE IF NOT EXISTS GROUPMEMBERSHIPS(manifestid text not null, groupid text not null);") == -1 || sqlite_exec_void_retry(&retry, "CREATE TABLE IF NOT EXISTS GROUPMEMBERSHIPS(manifestid text not null, groupid text not null);", END) == -1
|| sqlite_exec_void_retry(&retry, "CREATE TABLE IF NOT EXISTS VERIFICATIONS(sid text not null, did text, name text, starttime integer, endtime integer, signature blob);") == -1 || sqlite_exec_void_retry(&retry, "CREATE TABLE IF NOT EXISTS VERIFICATIONS(sid text not null, did text, name text, starttime integer, endtime integer, signature blob);", END) == -1
) { ) {
RETURN(WHY("Failed to create schema")); RETURN(WHY("Failed to create schema"));
} }
/* Create indexes if they don't already exist */ /* Create indexes if they don't already exist */
sqlite_exec_void_loglevel(LOG_LEVEL_WARN, "CREATE INDEX IF NOT EXISTS bundlesizeindex ON manifests (filesize);"); sqlite_exec_void_loglevel(LOG_LEVEL_WARN, "CREATE INDEX IF NOT EXISTS bundlesizeindex ON manifests (filesize);", END);
sqlite_exec_void_loglevel(LOG_LEVEL_WARN, "CREATE INDEX IF NOT EXISTS IDX_MANIFESTS_HASH ON MANIFESTS(filehash);"); sqlite_exec_void_loglevel(LOG_LEVEL_WARN, "CREATE INDEX IF NOT EXISTS IDX_MANIFESTS_HASH ON MANIFESTS(filehash);", END);
sqlite_exec_void_loglevel(LOG_LEVEL_WARN, "PRAGMA user_version=1;"); sqlite_exec_void_loglevel(LOG_LEVEL_WARN, "PRAGMA user_version=1;", END);
} }
if (version<2){ if (version<2){
sqlite_exec_void_loglevel(LOG_LEVEL_WARN, "ALTER TABLE MANIFESTS ADD COLUMN service text;"); sqlite_exec_void_loglevel(LOG_LEVEL_WARN, "ALTER TABLE MANIFESTS ADD COLUMN service text;", END);
sqlite_exec_void_loglevel(LOG_LEVEL_WARN, "ALTER TABLE MANIFESTS ADD COLUMN name text;"); sqlite_exec_void_loglevel(LOG_LEVEL_WARN, "ALTER TABLE MANIFESTS ADD COLUMN name text;", END);
sqlite_exec_void_loglevel(LOG_LEVEL_WARN, "ALTER TABLE MANIFESTS ADD COLUMN sender text collate nocase;"); sqlite_exec_void_loglevel(LOG_LEVEL_WARN, "ALTER TABLE MANIFESTS ADD COLUMN sender text collate nocase;", END);
sqlite_exec_void_loglevel(LOG_LEVEL_WARN, "ALTER TABLE MANIFESTS ADD COLUMN recipient text collate nocase;"); sqlite_exec_void_loglevel(LOG_LEVEL_WARN, "ALTER TABLE MANIFESTS ADD COLUMN recipient text collate nocase;", END);
// if more bundle verification is required in later upgrades, move this to the end, don't run it more than once. // if more bundle verification is required in later upgrades, move this to the end, don't run it more than once.
verify_bundles(); verify_bundles();
sqlite_exec_void_loglevel(LOG_LEVEL_WARN, "PRAGMA user_version=2;"); sqlite_exec_void_loglevel(LOG_LEVEL_WARN, "PRAGMA user_version=2;", END);
} }
if (version<3){ if (version<3){
sqlite_exec_void_loglevel(LOG_LEVEL_WARN, "CREATE INDEX IF NOT EXISTS IDX_MANIFESTS_ID_VERSION ON MANIFESTS(id, version);"); sqlite_exec_void_loglevel(LOG_LEVEL_WARN, "CREATE INDEX IF NOT EXISTS IDX_MANIFESTS_ID_VERSION ON MANIFESTS(id, version);", END);
sqlite_exec_void_loglevel(LOG_LEVEL_WARN, "PRAGMA user_version=3;"); sqlite_exec_void_loglevel(LOG_LEVEL_WARN, "PRAGMA user_version=3;", END);
} }
if (version<4){ if (version<4){
sqlite_exec_void_loglevel(LOG_LEVEL_WARN, "ALTER TABLE MANIFESTS ADD COLUMN tail integer;"); sqlite_exec_void_loglevel(LOG_LEVEL_WARN, "ALTER TABLE MANIFESTS ADD COLUMN tail integer;", END);
sqlite_exec_void_loglevel(LOG_LEVEL_WARN, "PRAGMA user_version=4;"); sqlite_exec_void_loglevel(LOG_LEVEL_WARN, "PRAGMA user_version=4;", END);
} }
// TODO recreate tables with collate nocase on hex columns // TODO recreate tables with collate nocase on hex columns
@ -298,7 +298,7 @@ int rhizome_close_db()
if (!sqlite3_get_autocommit(rhizome_db)){ if (!sqlite3_get_autocommit(rhizome_db)){
WHY("Uncommitted transaction!"); WHY("Uncommitted transaction!");
sqlite_exec_void("ROLLBACK;"); sqlite_exec_void("ROLLBACK;", END);
} }
sqlite3_stmt *stmt = NULL; sqlite3_stmt *stmt = NULL;
while ((stmt = sqlite3_next_stmt(rhizome_db, stmt))) { while ((stmt = sqlite3_next_stmt(rhizome_db, stmt))) {
@ -418,10 +418,11 @@ void _sqlite_retry_done(struct __sourceloc __whence, sqlite_retry_state *retry,
* methods, because those are susceptible to SQL injection attacks. Instead, use bound parameters * methods, because those are susceptible to SQL injection attacks. Instead, use bound parameters
* and bind them using the sqlite_bind() function below. * and bind them using the sqlite_bind() function below.
* *
* IN PARTICULAR, do not add sprintf(3)-like functionality to this method. It used to take * ALSO! Do not add sprintf(3)-like functionality to this method. It used to take sprintf(3)-style
* sprintf(3)-style varargs and these were deliberately removed. It is vital to discourage bad * varargs and these were deliberately removed. It is vital to discourage bad practice, and adding
* practice, and adding sprintf(3)-style args to this function would be a step in the wrong * sprintf(3)-style args to this function would be a step in the wrong direction.
* direction. *
* See GitHub issue #69.
* *
* @author Andrew Bettison <andrew@servalproject.com> * @author Andrew Bettison <andrew@servalproject.com>
*/ */
@ -449,90 +450,101 @@ sqlite3_stmt *_sqlite_prepare_loglevel(struct __sourceloc __whence, int log_leve
} }
} }
enum sqlbind_type { int _sqlite_vbind(struct __sourceloc __whence, int log_level, sqlite_retry_state *retry, sqlite3_stmt *statement, va_list ap)
END = 0,
NUL,
INT, // int value
INT64, // int64_t value
STATIC_TEXT, // const char *text,
STATIC_TEXT_LEN, // const char *text, int bytes
STATIC_BLOB, // const void *blob, int bytes
SID_T, // const sid_t *sidp
BUNDLE_ID_T, // const unsigned char bid_binary[RHIZOME_BUNDLE_ID_BYTES]
FILEHASH_T, // const unsigned char hash_binary[RHIZOME_FILEHASH_BYTES]
TOHEX, // const unsigned char *binary, unsigned bytes
TEXT_TOUPPER, // const char *text,
TEXT_LEN_TOUPPER, // const char *text, unsigned bytes
NAMED = (1 << 12)
};
int _sqlite_bind(struct __sourceloc __whence, int log_level, sqlite_retry_state *retry, sqlite3_stmt *statement, ...)
{ {
int ret = 0; const int index_limit = 50; // for safety checks
va_list ap;
va_start(ap, statement);
enum sqlbind_type typ; enum sqlbind_type typ;
int index_counter = 0;
do { do {
typ = va_arg(ap, int); typ = va_arg(ap, int);
const char *name = NULL;
int index; int index;
if (typ & NAMED) { if ((typ & 0xffff0000) == INDEX) {
typ |= ~NAMED; typ &= 0xffff;
name = va_arg(ap, const char *); index = va_arg(ap, int);
if (index < 1 || index > index_limit) {
LOGF(log_level, "illegal index %d: %s", index, sqlite3_sql(statement));
return -1;
}
} else if ((typ & 0xffff0000) == NAMED) {
typ &= 0xffff;
const char *name = va_arg(ap, const char *);
index = sqlite3_bind_parameter_index(statement, name); index = sqlite3_bind_parameter_index(statement, name);
if (index == 0) { if (index == 0) {
LOGF(log_level, "no parameter %s in query: %s", alloca_str_toprint(name), sqlite3_sql(statement)); LOGF(log_level, "no parameter %s in query: %s", alloca_str_toprint(name), sqlite3_sql(statement));
ret = -1; return -1;
} }
} else } else
index = va_arg(ap, int); index = ++index_counter;
#define BIND_RETRY(FUNC, ...) \
do { \
switch (FUNC(statement, index, ##__VA_ARGS__)) { \
case SQLITE_OK: \
break; \
case SQLITE_BUSY: \
case SQLITE_LOCKED: \
if (retry && _sqlite_retry(__whence, retry, #FUNC "()")) \
continue; \
default: \
LOGF(log_level, #FUNC "(%d) failed, %s: %s", index, sqlite3_errmsg(rhizome_db), sqlite3_sql(statement)); \
sqlite3_finalize(statement); \
return -1; \
} \
break; \
} while (1)
switch (typ) { switch (typ) {
case END: break; case END: break;
case NUL: case NUL:
ret = sqlite3_bind_null(statement, index); BIND_RETRY(sqlite3_bind_null);
break; break;
case INT: case INT: {
ret = sqlite3_bind_int(statement, index, va_arg(ap, int)); int value = va_arg(ap, int);
BIND_RETRY(sqlite3_bind_int, value);
}
break; break;
case INT64: case INT64: {
ret = sqlite3_bind_int64(statement, index, va_arg(ap, int64_t)); int64_t value = va_arg(ap, int64_t);
BIND_RETRY(sqlite3_bind_int64, value);
}
break; break;
case STATIC_TEXT: case STATIC_TEXT: {
ret = sqlite3_bind_text(statement, index, va_arg(ap, const char *), -1, SQLITE_STATIC); const char *text = va_arg(ap, const char *);
BIND_RETRY(sqlite3_bind_text, text, -1, SQLITE_STATIC);
}
break; break;
case STATIC_TEXT_LEN: { case STATIC_TEXT_LEN: {
const char *text = va_arg(ap, const char *); const char *text = va_arg(ap, const char *);
int bytes = va_arg(ap, int); int bytes = va_arg(ap, int);
ret = sqlite3_bind_text(statement, index, text, bytes, SQLITE_STATIC); BIND_RETRY(sqlite3_bind_text, text, bytes, SQLITE_STATIC);
} }
break; break;
case STATIC_BLOB: { case STATIC_BLOB: {
const void *blob = va_arg(ap, const void *); const void *blob = va_arg(ap, const void *);
int bytes = va_arg(ap, int); int bytes = va_arg(ap, int);
ret = sqlite3_bind_blob(statement, index, blob, bytes, SQLITE_STATIC); BIND_RETRY(sqlite3_bind_blob, blob, bytes, SQLITE_STATIC);
}; };
break; break;
case SID_T: { case SID_T: {
const sid_t *sidp = va_arg(ap, const sid_t *); const sid_t *sidp = va_arg(ap, const sid_t *);
const char *sid_hex = alloca_tohex_sid_t(*sidp); const char *sid_hex = alloca_tohex_sid_t(*sidp);
ret = sqlite3_bind_text(statement, index, sid_hex, SID_STRLEN, SQLITE_TRANSIENT); BIND_RETRY(sqlite3_bind_text, sid_hex, SID_STRLEN, SQLITE_TRANSIENT);
} }
break; break;
case BUNDLE_ID_T: { case BUNDLE_ID_T: {
const char *bid_hex = alloca_tohex(va_arg(ap, const unsigned char *), RHIZOME_MANIFEST_ID_BYTES); const char *bid_hex = alloca_tohex(va_arg(ap, const unsigned char *), RHIZOME_MANIFEST_ID_BYTES);
ret = sqlite3_bind_text(statement, index, bid_hex, RHIZOME_MANIFEST_ID_STRLEN, SQLITE_TRANSIENT); BIND_RETRY(sqlite3_bind_text, bid_hex, RHIZOME_MANIFEST_ID_STRLEN, SQLITE_TRANSIENT);
} }
break; break;
case FILEHASH_T: { case FILEHASH_T: {
const char *hash_hex = alloca_tohex(va_arg(ap, const unsigned char *), RHIZOME_FILEHASH_BYTES); const char *hash_hex = alloca_tohex(va_arg(ap, const unsigned char *), RHIZOME_FILEHASH_BYTES);
ret = sqlite3_bind_text(statement, index, hash_hex, RHIZOME_FILEHASH_STRLEN, SQLITE_TRANSIENT); BIND_RETRY(sqlite3_bind_text, hash_hex, RHIZOME_FILEHASH_STRLEN, SQLITE_TRANSIENT);
} }
break; break;
case TOHEX: { case TOHEX: {
const unsigned char *binary = va_arg(ap, const unsigned char *); const unsigned char *binary = va_arg(ap, const unsigned char *);
unsigned bytes = va_arg(ap, unsigned); unsigned bytes = va_arg(ap, unsigned);
ret = sqlite3_bind_text(statement, index, alloca_tohex(binary, bytes), bytes * 2, SQLITE_TRANSIENT); char hex[bytes * 2];
tohex(hex, binary, bytes);
BIND_RETRY(sqlite3_bind_text, hex, bytes * 2, SQLITE_TRANSIENT);
} }
break; break;
case TEXT_TOUPPER: { case TEXT_TOUPPER: {
@ -542,7 +554,7 @@ int _sqlite_bind(struct __sourceloc __whence, int log_level, sqlite_retry_state
unsigned i; unsigned i;
for (i = 0; i != bytes; ++i) for (i = 0; i != bytes; ++i)
upper[i] = toupper(text[i]); upper[i] = toupper(text[i]);
ret = sqlite3_bind_text(statement, index, upper, bytes, SQLITE_TRANSIENT); BIND_RETRY(sqlite3_bind_text, upper, bytes, SQLITE_TRANSIENT);
} }
break; break;
case TEXT_LEN_TOUPPER: { case TEXT_LEN_TOUPPER: {
@ -552,13 +564,21 @@ int _sqlite_bind(struct __sourceloc __whence, int log_level, sqlite_retry_state
unsigned i; unsigned i;
for (i = 0; i != bytes; ++i) for (i = 0; i != bytes; ++i)
upper[i] = toupper(text[i]); upper[i] = toupper(text[i]);
ret = sqlite3_bind_text(statement, index, upper, bytes, SQLITE_TRANSIENT); BIND_RETRY(sqlite3_bind_text, upper, bytes, SQLITE_TRANSIENT);
} }
break; break;
default: default:
FATALF("unsupported bind code %d", typ); FATALF("unsupported bind code %d", typ);
} }
} while (typ != END); } while (typ != END);
return 0;
}
int _sqlite_bind(struct __sourceloc __whence, int log_level, sqlite_retry_state *retry, sqlite3_stmt *statement, ...)
{
va_list ap;
va_start(ap, statement);
int ret = _sqlite_vbind(__whence, log_level, retry, statement, ap);
va_end(ap); va_end(ap);
return ret; return ret;
} }
@ -632,11 +652,14 @@ static int _sqlite_exec_prepared(struct __sourceloc __whence, int log_level, sql
* *
* @author Andrew Bettison <andrew@servalproject.com> * @author Andrew Bettison <andrew@servalproject.com>
*/ */
static int _sqlite_vexec_void(struct __sourceloc __whence, int log_level, sqlite_retry_state *retry, const char *sqlformat, va_list ap) static int _sqlite_vexec_void(struct __sourceloc __whence, int log_level, sqlite_retry_state *retry, const char *sqltext, va_list ap)
{ {
strbuf stmt = strbuf_alloca(8192); sqlite3_stmt *statement = _sqlite_prepare_loglevel(__whence, log_level, retry, sqltext);
strbuf_vsprintf(stmt, sqlformat, ap); if (!statement)
int rowcount = _sqlite_exec_prepared(__whence, log_level, retry, _sqlite_prepare_loglevel(__whence, log_level, retry, stmt)); return -1;
if (_sqlite_vbind(__whence, log_level, retry, statement, ap) == -1)
return -1;
int rowcount = _sqlite_exec_prepared(__whence, log_level, retry, statement);
if (rowcount == -1) if (rowcount == -1)
return -1; return -1;
if (rowcount) if (rowcount)
@ -650,12 +673,12 @@ static int _sqlite_vexec_void(struct __sourceloc __whence, int log_level, sqlite
* *
* @author Andrew Bettison <andrew@servalproject.com> * @author Andrew Bettison <andrew@servalproject.com>
*/ */
int _sqlite_exec_void(struct __sourceloc __whence, const char *sqlformat, ...) int _sqlite_exec_void(struct __sourceloc __whence, const char *sqltext, ...)
{ {
va_list ap; va_list ap;
va_start(ap, sqlformat); va_start(ap, sqltext);
sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT; sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT;
int ret = _sqlite_vexec_void(__whence, LOG_LEVEL_ERROR, &retry, sqlformat, ap); int ret = _sqlite_vexec_void(__whence, LOG_LEVEL_ERROR, &retry, sqltext, ap);
va_end(ap); va_end(ap);
return ret; return ret;
} }
@ -664,12 +687,12 @@ int _sqlite_exec_void(struct __sourceloc __whence, const char *sqlformat, ...)
* *
* @author Andrew Bettison <andrew@servalproject.com> * @author Andrew Bettison <andrew@servalproject.com>
*/ */
int _sqlite_exec_void_loglevel(struct __sourceloc __whence, int log_level, const char *sqlformat, ...) int _sqlite_exec_void_loglevel(struct __sourceloc __whence, int log_level, const char *sqltext, ...)
{ {
va_list ap; va_list ap;
va_start(ap, sqlformat); va_start(ap, sqltext);
sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT; sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT;
int ret = _sqlite_vexec_void(__whence, log_level, &retry, sqlformat, ap); int ret = _sqlite_vexec_void(__whence, log_level, &retry, sqltext, ap);
va_end(ap); va_end(ap);
return ret; return ret;
} }
@ -681,11 +704,11 @@ int _sqlite_exec_void_loglevel(struct __sourceloc __whence, int log_level, const
* *
* @author Andrew Bettison <andrew@servalproject.com> * @author Andrew Bettison <andrew@servalproject.com>
*/ */
int _sqlite_exec_void_retry(struct __sourceloc __whence, sqlite_retry_state *retry, const char *sqlformat, ...) int _sqlite_exec_void_retry(struct __sourceloc __whence, sqlite_retry_state *retry, const char *sqltext, ...)
{ {
va_list ap; va_list ap;
va_start(ap, sqlformat); va_start(ap, sqltext);
int ret = _sqlite_vexec_void(__whence, LOG_LEVEL_ERROR, retry, sqlformat, ap); int ret = _sqlite_vexec_void(__whence, LOG_LEVEL_ERROR, retry, sqltext, ap);
va_end(ap); va_end(ap);
return ret; return ret;
} }
@ -694,22 +717,22 @@ int _sqlite_exec_void_retry(struct __sourceloc __whence, sqlite_retry_state *ret
* *
* @author Andrew Bettison <andrew@servalproject.com> * @author Andrew Bettison <andrew@servalproject.com>
*/ */
int _sqlite_exec_void_retry_loglevel(struct __sourceloc __whence, int log_level, sqlite_retry_state *retry, const char *sqlformat, ...) int _sqlite_exec_void_retry_loglevel(struct __sourceloc __whence, int log_level, sqlite_retry_state *retry, const char *sqltext, ...)
{ {
va_list ap; va_list ap;
va_start(ap, sqlformat); va_start(ap, sqltext);
int ret = _sqlite_vexec_void(__whence, log_level, retry, sqlformat, ap); int ret = _sqlite_vexec_void(__whence, log_level, retry, sqltext, ap);
va_end(ap); va_end(ap);
return ret; return ret;
} }
static int _sqlite_vexec_int64(struct __sourceloc __whence, sqlite_retry_state *retry, int64_t *result, const char *sqlformat, va_list ap) static int _sqlite_vexec_int64(struct __sourceloc __whence, sqlite_retry_state *retry, int64_t *result, const char *sqltext, va_list ap)
{ {
strbuf stmt = strbuf_alloca(8192); sqlite3_stmt *statement = _sqlite_prepare_loglevel(__whence, LOG_LEVEL_ERROR, retry, sqltext);
strbuf_vsprintf(stmt, sqlformat, ap);
sqlite3_stmt *statement = _sqlite_prepare_loglevel(__whence, LOG_LEVEL_ERROR, retry, stmt);
if (!statement) if (!statement)
return -1; return -1;
if (_sqlite_vbind(__whence, LOG_LEVEL_ERROR, retry, statement, ap) == -1)
return -1;
int ret = 0; int ret = 0;
int rowcount = 0; int rowcount = 0;
int stepcode; int stepcode;
@ -793,13 +816,13 @@ int _sqlite_exec_strbuf_retry(struct __sourceloc __whence, sqlite_retry_state *r
return ret; return ret;
} }
int _sqlite_vexec_strbuf_retry(struct __sourceloc __whence, sqlite_retry_state *retry, strbuf sb, const char *sqlformat, va_list ap) int _sqlite_vexec_strbuf_retry(struct __sourceloc __whence, sqlite_retry_state *retry, strbuf sb, const char *sqltext, va_list ap)
{ {
strbuf stmt = strbuf_alloca(8192); sqlite3_stmt *statement = _sqlite_prepare_loglevel(__whence, LOG_LEVEL_ERROR, retry, sqltext);
strbuf_vsprintf(stmt, sqlformat, ap);
sqlite3_stmt *statement = _sqlite_prepare_loglevel(__whence, LOG_LEVEL_ERROR, retry, stmt);
if (!statement) if (!statement)
return -1; return -1;
if (_sqlite_vbind(__whence, LOG_LEVEL_ERROR, retry, statement, ap) == -1)
return -1;
int ret = 0; int ret = 0;
int rowcount = 0; int rowcount = 0;
int stepcode; int stepcode;
@ -821,9 +844,9 @@ int64_t rhizome_database_used_bytes()
int64_t db_page_size; int64_t db_page_size;
int64_t db_page_count; int64_t db_page_count;
int64_t db_free_page_count; int64_t db_free_page_count;
if ( sqlite_exec_int64(&db_page_size, "PRAGMA page_size;") == -1LL if ( sqlite_exec_int64(&db_page_size, "PRAGMA page_size;", END) == -1LL
|| sqlite_exec_int64(&db_page_count, "PRAGMA page_count;") == -1LL || sqlite_exec_int64(&db_page_count, "PRAGMA page_count;", END) == -1LL
|| sqlite_exec_int64(&db_free_page_count, "PRAGMA free_count;") == -1LL || sqlite_exec_int64(&db_free_page_count, "PRAGMA free_count;", END) == -1LL
) )
return WHY("Cannot measure database used bytes"); return WHY("Cannot measure database used bytes");
return db_page_size * (db_page_count - db_free_page_count); return db_page_size * (db_page_count - db_free_page_count);
@ -849,15 +872,25 @@ static int rhizome_delete_external(const char *fileid)
static int rhizome_delete_orphan_fileblobs_retry(sqlite_retry_state *retry) static int rhizome_delete_orphan_fileblobs_retry(sqlite_retry_state *retry)
{ {
return sqlite_exec_void_retry_loglevel(LOG_LEVEL_WARN, retry, "DELETE FROM FILEBLOBS WHERE NOT EXISTS( SELECT 1 FROM FILES WHERE FILES.id = FILEBLOBS.id );"); return sqlite_exec_void_retry_loglevel(LOG_LEVEL_WARN, retry,
"DELETE FROM FILEBLOBS WHERE NOT EXISTS( SELECT 1 FROM FILES WHERE FILES.id = FILEBLOBS.id );",
END);
} }
int rhizome_remove_file_datainvalid(sqlite_retry_state *retry, const char *fileid) int rhizome_remove_file_datainvalid(sqlite_retry_state *retry, const char *fileid)
{ {
int ret = 0; int ret = 0;
if (sqlite_exec_void_retry_loglevel(LOG_LEVEL_WARN, retry, "DELETE FROM FILES WHERE id='%s' and datavalid=0;", fileid) == -1) if (sqlite_exec_void_retry_loglevel(LOG_LEVEL_WARN, retry,
"DELETE FROM FILES WHERE id = ? and datavalid = 0;",
TEXT_TOUPPER, fileid, END
) == -1
)
ret = -1; ret = -1;
if (sqlite_exec_void_retry_loglevel(LOG_LEVEL_WARN, retry, "DELETE FROM FILEBLOBS WHERE id='%s' AND NOT EXISTS( SELECT 1 FROM FILES WHERE FILES.id=FILEBLOBS.id );", fileid) == -1) if (sqlite_exec_void_retry_loglevel(LOG_LEVEL_WARN, retry,
"DELETE FROM FILEBLOBS WHERE id = ? AND NOT EXISTS( SELECT 1 FROM FILES WHERE FILES.id = FILEBLOBS.id );",
TEXT_TOUPPER, fileid, END
) == -1
)
ret = -1; ret = -1;
return ret; return ret;
} }
@ -875,7 +908,9 @@ int rhizome_cleanup(struct rhizome_cleanup_report *report)
int candidates=0; int candidates=0;
if (report) if (report)
report->deleted_orphan_fileblobs = 0; report->deleted_orphan_fileblobs = 0;
sqlite3_stmt *statement = sqlite_prepare(&retry, "SELECT id FROM FILES WHERE inserttime < %lld AND datavalid=0;", insert_horizon); sqlite3_stmt *statement = sqlite_prepare_bind(&retry,
"SELECT id FROM FILES WHERE inserttime < ? AND datavalid = 0;",
INT64, insert_horizon, END);
while (sqlite_step_retry(&retry, statement) == SQLITE_ROW) { while (sqlite_step_retry(&retry, statement) == SQLITE_ROW) {
candidates++; candidates++;
const char *id = (const char *) sqlite3_column_text(statement, 0); const char *id = (const char *) sqlite3_column_text(statement, 0);
@ -884,7 +919,9 @@ int rhizome_cleanup(struct rhizome_cleanup_report *report)
} }
sqlite3_finalize(statement); sqlite3_finalize(statement);
statement = sqlite_prepare(&retry, "SELECT id FROM FILES WHERE inserttime < %lld AND datavalid=1 AND NOT EXISTS( SELECT 1 FROM MANIFESTS WHERE MANIFESTS.filehash = FILES.id);", insert_horizon_no_manifest); statement = sqlite_prepare_bind(&retry,
"SELECT id FROM FILES WHERE inserttime < ? AND datavalid = 1 AND NOT EXISTS( SELECT 1 FROM MANIFESTS WHERE MANIFESTS.filehash = FILES.id);",
INT64, insert_horizon_no_manifest, END);
while (sqlite_step_retry(&retry, statement) == SQLITE_ROW) { while (sqlite_step_retry(&retry, statement) == SQLITE_ROW) {
candidates++; candidates++;
const char *id = (const char *) sqlite3_column_text(statement, 0); const char *id = (const char *) sqlite3_column_text(statement, 0);
@ -896,10 +933,14 @@ int rhizome_cleanup(struct rhizome_cleanup_report *report)
int ret; int ret;
if (candidates) { if (candidates) {
// clean out unreferenced files // clean out unreferenced files
ret = sqlite_exec_void_retry_loglevel(LOG_LEVEL_WARN, &retry, "DELETE FROM FILES WHERE inserttime < %lld AND datavalid=0;", insert_horizon); ret = sqlite_exec_void_retry_loglevel(LOG_LEVEL_WARN, &retry,
"DELETE FROM FILES WHERE inserttime < ? AND datavalid = 0;",
INT64, insert_horizon, END);
if (report) if (report)
report->deleted_stale_incoming_files = ret; report->deleted_stale_incoming_files = ret;
ret = sqlite_exec_void_retry_loglevel(LOG_LEVEL_WARN, &retry, "DELETE FROM FILES WHERE inserttime < %lld AND datavalid=1 AND NOT EXISTS( SELECT 1 FROM MANIFESTS WHERE MANIFESTS.filehash = FILES.id);", insert_horizon_no_manifest); ret = sqlite_exec_void_retry_loglevel(LOG_LEVEL_WARN, &retry,
"DELETE FROM FILES WHERE inserttime < ? AND datavalid=1 AND NOT EXISTS( SELECT 1 FROM MANIFESTS WHERE MANIFESTS.filehash = FILES.id);",
INT64, insert_horizon_no_manifest, END);
if (report) if (report)
report->deleted_orphan_files = ret; report->deleted_orphan_files = ret;
} }
@ -929,7 +970,9 @@ int rhizome_make_space(int group_priority, long long bytes)
/* Okay, not enough space, so free up some. */ /* Okay, not enough space, so free up some. */
sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT; sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT;
sqlite3_stmt *statement = sqlite_prepare(&retry, "select id,length from files where highestpriority < %d order by descending length", group_priority); sqlite3_stmt *statement = sqlite_prepare_bind(&retry,
"SELECT id,length FROM FILES WHERE highestpriority < ? ORDER BY DESCENDING LENGTH",
INT, group_priority, END);
if (!statement) if (!statement)
return -1; return -1;
while (bytes > (config.rhizome.database_size - 65536 - rhizome_database_used_bytes()) while (bytes > (config.rhizome.database_size - 65536 - rhizome_database_used_bytes())
@ -973,9 +1016,9 @@ int rhizome_make_space(int group_priority, long long bytes)
int rhizome_drop_stored_file(const char *id,int maximum_priority) int rhizome_drop_stored_file(const char *id,int maximum_priority)
{ {
if (!rhizome_str_is_file_hash(id)) if (!rhizome_str_is_file_hash(id))
return WHYF("invalid file hash id=%s", alloca_toprint(-1, id, strlen(id))); return WHYF("invalid file hash id=%s", alloca_str_toprint(id));
sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT; sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT;
sqlite3_stmt *statement = sqlite_prepare(&retry, "select id from manifests where filehash='%s'", id); sqlite3_stmt *statement = sqlite_prepare_bind(&retry, "SELECT id FROM MANIFESTS WHERE filehash = ?", TEXT_TOUPPER, id, END);
if (!statement) if (!statement)
return WHYF("Could not drop stored file id=%s", id); return WHYF("Could not drop stored file id=%s", id);
int can_drop = 1; int can_drop = 1;
@ -999,9 +1042,9 @@ int rhizome_drop_stored_file(const char *id,int maximum_priority)
} else { } else {
if (config.debug.rhizome) if (config.debug.rhizome)
DEBUGF("removing stale manifests, groupmemberships"); DEBUGF("removing stale manifests, groupmemberships");
sqlite_exec_void_retry(&retry, "delete from manifests where id='%s';", manifestId); sqlite_exec_void_retry(&retry, "delete from manifests where id = ?;", TEXT_TOUPPER, manifestId, END);
sqlite_exec_void_retry(&retry, "delete from keypairs where public='%s';", manifestId); sqlite_exec_void_retry(&retry, "delete from keypairs where public = ?;", TEXT_TOUPPER, manifestId, END);
sqlite_exec_void_retry(&retry, "delete from groupmemberships where manifestid='%s';", manifestId); sqlite_exec_void_retry(&retry, "delete from groupmemberships where manifestid = ?;", TEXT_TOUPPER, manifestId, END);
} }
} }
sqlite3_finalize(statement); sqlite3_finalize(statement);
@ -1072,7 +1115,7 @@ int rhizome_store_bundle(rhizome_manifest *m)
const char *service = rhizome_manifest_get(m, "service", NULL, 0); const char *service = rhizome_manifest_get(m, "service", NULL, 0);
sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT; sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT;
if (sqlite_exec_void_retry(&retry, "BEGIN TRANSACTION;") == -1) if (sqlite_exec_void_retry(&retry, "BEGIN TRANSACTION;", END) == -1)
return WHY("Failed to begin transaction"); return WHY("Failed to begin transaction");
sqlite3_stmt *stmt; sqlite3_stmt *stmt;
@ -1161,7 +1204,7 @@ int rhizome_store_bundle(rhizome_manifest *m)
sqlite3_finalize(stmt); sqlite3_finalize(stmt);
stmt = NULL; stmt = NULL;
} }
if (sqlite_exec_void_retry(&retry, "COMMIT;") != -1){ if (sqlite_exec_void_retry(&retry, "COMMIT;", END) != -1){
// This message used in tests; do not modify or remove. // This message used in tests; do not modify or remove.
const char *service = rhizome_manifest_get(m, "service", NULL, 0); const char *service = rhizome_manifest_get(m, "service", NULL, 0);
INFOF("RHIZOME ADD MANIFEST service=%s bid=%s version=%"PRId64, INFOF("RHIZOME ADD MANIFEST service=%s bid=%s version=%"PRId64,
@ -1178,7 +1221,7 @@ rollback:
if (stmt) if (stmt)
sqlite3_finalize(stmt); sqlite3_finalize(stmt);
WHYF("Failed to store bundle bid=%s", manifestid); WHYF("Failed to store bundle bid=%s", manifestid);
sqlite_exec_void_retry(&retry, "ROLLBACK;"); sqlite_exec_void_retry(&retry, "ROLLBACK;", END);
return -1; return -1;
} }
@ -1208,7 +1251,7 @@ int rhizome_list_manifests(struct cli_context *context, const char *service, con
RETURN(WHYF("SQL command too long: %s", strbuf_str(b))); RETURN(WHYF("SQL command too long: %s", strbuf_str(b)));
sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT; sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT;
sqlite3_stmt *statement = sqlite_prepare(&retry, "%s", strbuf_str(b)); sqlite3_stmt *statement = sqlite_prepare(&retry, strbuf_str(b));
if (!statement) if (!statement)
RETURN(-1); RETURN(-1);
@ -1371,13 +1414,18 @@ int rhizome_update_file_priority(const char *fileid)
int64_t highestPriority = -1; int64_t highestPriority = -1;
sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT; sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT;
if (sqlite_exec_int64_retry(&retry, &highestPriority, if (sqlite_exec_int64_retry(&retry, &highestPriority,
"SELECT max(grouplist.priority) FROM MANIFESTS,GROUPMEMBERSHIPS,GROUPLIST" "SELECT max(grouplist.priority) FROM MANIFESTS, GROUPMEMBERSHIPS, GROUPLIST"
" where manifests.filehash='%s'" " WHERE MANIFESTS.filehash = ?"
" AND groupmemberships.manifestid=manifests.id" " AND GROUPMEMBERSHIPS.manifestid = MANIFESTS.id"
" AND groupmemberships.groupid=grouplist.id;", " AND GROUPMEMBERSHIPS.groupid = GROUPLIST.id;",
fileid) == -1) TEXT_TOUPPER, fileid, END) == -1)
return -1; return -1;
if (highestPriority >= 0 && sqlite_exec_void_retry(&retry, "UPDATE files set highestPriority=%lld WHERE id='%s';", highestPriority, fileid) == -1) if ( highestPriority >= 0
&& sqlite_exec_void_retry(&retry,
"UPDATE files SET highestPriority = ? WHERE id = ?;",
INT, highestPriority, TEXT_TOUPPER, fileid, END
) == -1
)
return WHYF("cannot update priority for fileid=%s", fileid); return WHYF("cannot update priority for fileid=%s", fileid);
return 0; return 0;
} }
@ -1417,7 +1465,7 @@ int rhizome_find_duplicate(const rhizome_manifest *m, rhizome_manifest **found)
int ret = 0; int ret = 0;
sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT; sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT;
sqlite3_stmt *statement = sqlite_prepare(&retry, "%s", strbuf_str(b)); sqlite3_stmt *statement = sqlite_prepare(&retry, strbuf_str(b));
if (!statement) if (!statement)
return -1; return -1;