mirror of
https://github.com/servalproject/serval-dna.git
synced 2025-01-29 15:43:56 +00:00
Issue #69: refactor all Rhizome SQL queries to use binding
Remove all uses of sprintf(3) and its ilk to form SQL query commands. Use the new sqlite_bind() and sqlite_prepare_bind() functions instead.
This commit is contained in:
parent
41c862ea30
commit
7e3a552011
@ -140,7 +140,7 @@ int rhizome_bundle_import_files(rhizome_manifest *m, const char *manifest_path,
|
||||
/* Do we already have this manifest or newer? */
|
||||
int64_t dbVersion = -1;
|
||||
const char *id=rhizome_manifest_get(m, "id", NULL, 0);
|
||||
if (sqlite_exec_int64(&dbVersion, "SELECT version FROM MANIFESTS WHERE id='%s';", id) == -1)
|
||||
if (sqlite_exec_int64(&dbVersion, "SELECT version FROM MANIFESTS WHERE id = ?;", TEXT_TOUPPER, id, END) == -1)
|
||||
return WHY("Select failure");
|
||||
|
||||
if (dbVersion>=m->version)
|
||||
@ -266,10 +266,9 @@ int rhizome_add_manifest(rhizome_manifest *m_in,int ttl)
|
||||
/* no manifest ID */
|
||||
return WHY("Manifest does not have an ID");
|
||||
|
||||
str_toupper_inplace(id);
|
||||
/* Discard the new manifest unless it is newer than the most recent known version with the same ID */
|
||||
int64_t storedversion = -1;
|
||||
switch (sqlite_exec_int64(&storedversion, "SELECT version from manifests where id='%s';", id)) {
|
||||
switch (sqlite_exec_int64(&storedversion, "SELECT version FROM MANIFESTS WHERE id = ?;", TEXT_TOUPPER, id, END)) {
|
||||
case -1:
|
||||
return WHY("Select failed");
|
||||
case 0:
|
||||
|
62
rhizome.h
62
rhizome.h
@ -296,32 +296,36 @@ int is_debug_rhizome_ads();
|
||||
|
||||
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
|
||||
NUL = 0xbeef, // (no arg)
|
||||
INT, // int value
|
||||
INT_TOSTR, // int value
|
||||
UINT_TOSTR, // unsigned value
|
||||
INT64, // int64_t value
|
||||
INT64_TOSTR, // int64_t value
|
||||
UINT64_TOSTR, // uint64_t value
|
||||
STATIC_TEXT, // const char *text,
|
||||
STATIC_TEXT_LEN, // const char *text, int bytes
|
||||
STATIC_BLOB, // const void *blob, int bytes
|
||||
ZEROBLOB, // 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
|
||||
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, ...);
|
||||
sqlite3_stmt *_sqlite_prepare(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);
|
||||
sqlite3_stmt *_sqlite_prepare_bind(struct __sourceloc, int log_level, sqlite_retry_state *retry, const char *sqltext, ...);
|
||||
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);
|
||||
int _sqlite_step_retry(struct __sourceloc, int log_level, sqlite_retry_state *retry, sqlite3_stmt *statement);
|
||||
int _sqlite_exec_void(struct __sourceloc, const char *sqltext, ...);
|
||||
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 *sqltext, ...);
|
||||
int _sqlite_exec_void_retry_loglevel(struct __sourceloc, int log_level, sqlite_retry_state *retry, const char *sqltext, ...);
|
||||
int _sqlite_step(struct __sourceloc, int log_level, sqlite_retry_state *retry, sqlite3_stmt *statement);
|
||||
int _sqlite_exec_void(struct __sourceloc, int log_level, const char *sqltext, ...);
|
||||
int _sqlite_exec_void_retry(struct __sourceloc, int log_level, sqlite_retry_state *retry, const char *sqltext, ...);
|
||||
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 *sqltext, ...);
|
||||
int _sqlite_exec_strbuf(struct __sourceloc, strbuf sb, const char *sqltext, ...);
|
||||
@ -332,18 +336,20 @@ int _sqlite_vexec_strbuf_retry(struct __sourceloc, sqlite_retry_state *retry, st
|
||||
// they serve a very useful purpose, so don't remove them! They ensure that
|
||||
// programmers do not forget the bind args, of which there must be at least
|
||||
// one, even if it is only 'END' to make no bindings at all.
|
||||
#define sqlite_prepare(rs,sql) _sqlite_prepare_bind_loglevel(__WHENCE__, LOG_LEVEL_ERROR, (rs), (sql), END)
|
||||
#define sqlite_prepare_loglevel(ll,rs,sql) _sqlite_prepare_bind_loglevel(__WHENCE__, (ll), (rs), (sql), END)
|
||||
#define sqlite_prepare_bind(rs,sql,arg,...) _sqlite_prepare_bind_loglevel(__WHENCE__, LOG_LEVEL_ERROR, (rs), (sql), arg, ##__VA_ARGS__)
|
||||
#define sqlite_prepare_bind_loglevel(ll,rs,sql,arg,...) _sqlite_prepare_bind_loglevel(__WHENCE__, (ll), (rs), (sql), arg, ##__VA_ARGS__)
|
||||
#define sqlite_prepare(rs,sql) _sqlite_prepare(__WHENCE__, LOG_LEVEL_ERROR, (rs), (sql))
|
||||
#define sqlite_prepare_loglevel(ll,rs,sql) _sqlite_prepare(__WHENCE__, (ll), (rs), (sql))
|
||||
#define sqlite_prepare_bind(rs,sql,arg,...) _sqlite_prepare_bind(__WHENCE__, LOG_LEVEL_ERROR, (rs), (sql), arg, ##__VA_ARGS__)
|
||||
#define sqlite_prepare_bind_loglevel(ll,rs,sql,arg,...) _sqlite_prepare_bind(__WHENCE__, (ll), (rs), (sql), arg, ##__VA_ARGS__)
|
||||
#define sqlite_bind(rs,stmt,arg,...) _sqlite_bind(__WHENCE__, LOG_LEVEL_ERROR, (rs), (stmt), arg, ##__VA_ARGS__)
|
||||
#define sqlite_bind_loglevel(ll,rs,stmt,arg,...) _sqlite_bind(__WHENCE__, (ll), (rs), (stmt), arg, ##__VA_ARGS__)
|
||||
#define sqlite_retry(rs,action) _sqlite_retry(__WHENCE__, (rs), (action))
|
||||
#define sqlite_retry_done(rs,action) _sqlite_retry_done(__WHENCE__, (rs), (action))
|
||||
#define sqlite_step(stmt) _sqlite_step_retry(__WHENCE__, LOG_LEVEL_ERROR, NULL, (stmt))
|
||||
#define sqlite_step_retry(rs,stmt) _sqlite_step_retry(__WHENCE__, LOG_LEVEL_ERROR, (rs), (stmt))
|
||||
#define sqlite_exec_void(sql,arg,...) _sqlite_exec_void(__WHENCE__, (sql), ##__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_step(stmt) _sqlite_step(__WHENCE__, LOG_LEVEL_ERROR, NULL, (stmt))
|
||||
#define sqlite_step_retry(rs,stmt) _sqlite_step(__WHENCE__, LOG_LEVEL_ERROR, (rs), (stmt))
|
||||
#define sqlite_exec_void(sql,arg,...) _sqlite_exec_void(__WHENCE__, LOG_LEVEL_ERROR, (sql), arg, ##__VA_ARGS__)
|
||||
#define sqlite_exec_void_loglevel(ll,sql,arg,...) _sqlite_exec_void(__WHENCE__, (ll), (sql), arg, ##__VA_ARGS__)
|
||||
#define sqlite_exec_void_retry(rs,sql,arg,...) _sqlite_exec_void_retry(__WHENCE__, LOG_LEVEL_ERROR, (rs), (sql), arg, ##__VA_ARGS__)
|
||||
#define sqlite_exec_void_retry_loglevel(ll,rs,sql,arg,...) _sqlite_exec_void_retry(__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__)
|
||||
|
@ -373,10 +373,9 @@ int rhizome_find_bundle_author(rhizome_manifest *m)
|
||||
DEBUGF("found bundle author sid=%s", alloca_tohex_sid(m->author));
|
||||
|
||||
// if this bundle is already in the database, update the author.
|
||||
if (m->inserttime){
|
||||
if (m->inserttime) {
|
||||
const char *id = rhizome_manifest_get(m, "id", NULL, 0);
|
||||
if (sqlite_exec_void("UPDATE MANIFESTS SET author='%s' WHERE id='%s';", alloca_tohex_sid(m->author), id) == -1)
|
||||
WARN("Error updating MANIFESTS author column");
|
||||
sqlite_exec_void_loglevel(LOG_LEVEL_WARN, "UPDATE MANIFESTS SET author = ? WHERE id = ?;", SID_T, (sid_t*)m->author, TEXT_TOUPPER, id, END);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -178,7 +178,7 @@ void verify_bundles(){
|
||||
* that has write permission on the bundle, ie, possesses the Rhizome secret key that generated the
|
||||
* BID, and hence can derive the Bundle Secret from the bundle's BK field:
|
||||
* - The MANIFESTS table 'author' column is set to the author SID when a bundle is created
|
||||
* locally bu a non-secret identity, so no verification need ever be performed for one's own
|
||||
* locally by a non-secret identity, so no verification need be performed for one's own
|
||||
* bundles while they remain in the Rhizome store.
|
||||
* - When a bundle is imported, the 'author' column is set to NULL to indicate that no
|
||||
* verification has passed yet. This includes one's own bundles that have been purged from
|
||||
@ -411,22 +411,23 @@ void _sqlite_retry_done(struct __sourceloc __whence, sqlite_retry_state *retry,
|
||||
retry->start = -1;
|
||||
}
|
||||
|
||||
/* Prepare an SQL command from a simple string. Returns -1 if an error occurs (logged as an error),
|
||||
* otherwise zero with the prepared statement in *statement.
|
||||
/* Prepare an SQL command from a simple string. Returns NULL if an error occurs (logged as an
|
||||
* error), otherwise returns a pointer to the prepared SQLite statement.
|
||||
*
|
||||
* IMPORTANT! Do not form statement strings using sprintf(3) or strbuf_sprintf() or similar
|
||||
* 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.
|
||||
*
|
||||
* ALSO! Do not add sprintf(3)-like functionality to this method. It used to take sprintf(3)-style
|
||||
* varargs and these were deliberately removed. It is vital to discourage bad practice, and adding
|
||||
* sprintf(3)-style args to this function would be a step in the wrong direction.
|
||||
* IMPORTANT! Do not add sprintf(3)-like functionality to this method. It used to take
|
||||
* sprintf(3)-style varargs and these were deliberately removed. It is vital to discourage bad
|
||||
* practice, and adding sprintf(3)-style args to this function would be a step in the wrong
|
||||
* direction.
|
||||
*
|
||||
* See GitHub issue #69.
|
||||
*
|
||||
* @author Andrew Bettison <andrew@servalproject.com>
|
||||
*/
|
||||
sqlite3_stmt *_sqlite_prepare_loglevel(struct __sourceloc __whence, int log_level, sqlite_retry_state *retry, const char *sqltext)
|
||||
sqlite3_stmt *_sqlite_prepare(struct __sourceloc __whence, int log_level, sqlite_retry_state *retry, const char *sqltext)
|
||||
{
|
||||
IN();
|
||||
sqlite3_stmt *statement = NULL;
|
||||
@ -450,14 +451,23 @@ sqlite3_stmt *_sqlite_prepare_loglevel(struct __sourceloc __whence, int log_leve
|
||||
}
|
||||
}
|
||||
|
||||
/* Bind some parameters to a prepared SQL statement. Returns -1 if an error occurs (logged as an
|
||||
* error), otherwise zero with the prepared statement in *statement.
|
||||
*
|
||||
* Developed as part of GitHub issue #69.
|
||||
*
|
||||
* @author Andrew Bettison <andrew@servalproject.com>
|
||||
*/
|
||||
int _sqlite_vbind(struct __sourceloc __whence, int log_level, sqlite_retry_state *retry, sqlite3_stmt *statement, va_list ap)
|
||||
{
|
||||
const int index_limit = 50; // for safety checks
|
||||
const int index_limit = sqlite3_limit(rhizome_db, SQLITE_LIMIT_VARIABLE_NUMBER, -1);
|
||||
enum sqlbind_type typ;
|
||||
int index_counter = 0;
|
||||
strbuf ext = NULL;
|
||||
do {
|
||||
typ = va_arg(ap, int);
|
||||
int index;
|
||||
const char *name = NULL;
|
||||
if ((typ & 0xffff0000) == INDEX) {
|
||||
typ &= 0xffff;
|
||||
index = va_arg(ap, int);
|
||||
@ -465,16 +475,29 @@ int _sqlite_vbind(struct __sourceloc __whence, int log_level, sqlite_retry_state
|
||||
LOGF(log_level, "illegal index %d: %s", index, sqlite3_sql(statement));
|
||||
return -1;
|
||||
}
|
||||
if (config.debug.rhizome)
|
||||
strbuf_sprintf((ext = strbuf_alloca(25)), "|INDEX index=%d", index);
|
||||
} else if ((typ & 0xffff0000) == NAMED) {
|
||||
typ &= 0xffff;
|
||||
const char *name = va_arg(ap, const char *);
|
||||
name = va_arg(ap, const char *);
|
||||
index = sqlite3_bind_parameter_index(statement, name);
|
||||
if (index == 0) {
|
||||
LOGF(log_level, "no parameter %s in query: %s", alloca_str_toprint(name), sqlite3_sql(statement));
|
||||
return -1;
|
||||
}
|
||||
} else
|
||||
if (config.debug.rhizome) {
|
||||
ext = strbuf_alloca(20 + toprint_str_len(name, "\"\""));
|
||||
strbuf_puts(ext, "|NAMED name=");
|
||||
strbuf_toprint_quoted(ext, "\"\"", name);
|
||||
}
|
||||
} else {
|
||||
index = ++index_counter;
|
||||
if (config.debug.rhizome)
|
||||
ext = strbuf_alloca(1);
|
||||
}
|
||||
#define BIND_DEBUG(TYP,FUNC,ARGFMT,...) \
|
||||
if (config.debug.rhizome) \
|
||||
DEBUGF("%s%s %s(%d," ARGFMT ") %s", #TYP, strbuf_str(ext), #FUNC, index, ##__VA_ARGS__, sqlite3_sql(statement))
|
||||
#define BIND_RETRY(FUNC, ...) \
|
||||
do { \
|
||||
switch (FUNC(statement, index, ##__VA_ARGS__)) { \
|
||||
@ -492,68 +515,115 @@ int _sqlite_vbind(struct __sourceloc __whence, int log_level, sqlite_retry_state
|
||||
break; \
|
||||
} while (1)
|
||||
switch (typ) {
|
||||
case END: break;
|
||||
case END:
|
||||
break;
|
||||
case NUL:
|
||||
BIND_DEBUG(NUL, sqlite3_bind_null, "");
|
||||
BIND_RETRY(sqlite3_bind_null);
|
||||
break;
|
||||
case INT: {
|
||||
int value = va_arg(ap, int);
|
||||
BIND_DEBUG(INT, sqlite3_bind_int, "%d", value);
|
||||
BIND_RETRY(sqlite3_bind_int, value);
|
||||
}
|
||||
break;
|
||||
case INT_TOSTR: {
|
||||
int value = va_arg(ap, int);
|
||||
char str[25];
|
||||
sprintf(str, "%d", value);
|
||||
BIND_DEBUG(INT_TOSTR, sqlite3_bind_text, "%s,-1,SQLITE_TRANSIENT", alloca_str_toprint(str));
|
||||
BIND_RETRY(sqlite3_bind_text, str, -1, SQLITE_TRANSIENT);
|
||||
}
|
||||
break;
|
||||
case UINT_TOSTR: {
|
||||
unsigned value = va_arg(ap, unsigned);
|
||||
char str[25];
|
||||
sprintf(str, "%u", value);
|
||||
BIND_DEBUG(UINT_TOSTR, sqlite3_bind_text, "%s,-1,SQLITE_TRANSIENT", alloca_str_toprint(str));
|
||||
BIND_RETRY(sqlite3_bind_text, str, -1, SQLITE_TRANSIENT);
|
||||
}
|
||||
break;
|
||||
case INT64: {
|
||||
int64_t value = va_arg(ap, int64_t);
|
||||
BIND_DEBUG(INT64, sqlite3_bind_int64, "%"PRId64, value);
|
||||
BIND_RETRY(sqlite3_bind_int64, value);
|
||||
}
|
||||
break;
|
||||
case INT64_TOSTR: {
|
||||
int64_t value = va_arg(ap, int64_t);
|
||||
char str[35];
|
||||
sprintf(str, "%"PRId64, value);
|
||||
BIND_DEBUG(INT64_TOSTR, sqlite3_bind_text, "%s,-1,SQLITE_TRANSIENT", alloca_str_toprint(str));
|
||||
BIND_RETRY(sqlite3_bind_text, str, -1, SQLITE_TRANSIENT);
|
||||
}
|
||||
break;
|
||||
case UINT64_TOSTR: {
|
||||
uint64_t value = va_arg(ap, uint64_t);
|
||||
char str[35];
|
||||
sprintf(str, "%"PRIu64, value);
|
||||
BIND_DEBUG(UINT64_TOSTR, sqlite3_bind_text, "%s,-1,SQLITE_TRANSIENT", alloca_str_toprint(str));
|
||||
BIND_RETRY(sqlite3_bind_text, str, -1, SQLITE_TRANSIENT);
|
||||
}
|
||||
break;
|
||||
case STATIC_TEXT: {
|
||||
const char *text = va_arg(ap, const char *);
|
||||
BIND_DEBUG(STATIC_TEXT, sqlite3_bind_text, "%s,-1,SQLITE_STATIC", alloca_str_toprint(text));
|
||||
BIND_RETRY(sqlite3_bind_text, text, -1, SQLITE_STATIC);
|
||||
}
|
||||
break;
|
||||
case STATIC_TEXT_LEN: {
|
||||
const char *text = va_arg(ap, const char *);
|
||||
int bytes = va_arg(ap, int);
|
||||
BIND_DEBUG(STATIC_TEXT_LEN, sqlite3_bind_text, "%s,%d,SQLITE_STATIC", alloca_str_toprint(text), bytes);
|
||||
BIND_RETRY(sqlite3_bind_text, text, bytes, SQLITE_STATIC);
|
||||
}
|
||||
break;
|
||||
case STATIC_BLOB: {
|
||||
const void *blob = va_arg(ap, const void *);
|
||||
int bytes = va_arg(ap, int);
|
||||
BIND_DEBUG(STATIC_BLOB, sqlite3_bind_blob, "%s,%d,SQLITE_STATIC", alloca_toprint(20, blob, bytes), bytes);
|
||||
BIND_RETRY(sqlite3_bind_blob, blob, bytes, SQLITE_STATIC);
|
||||
};
|
||||
break;
|
||||
case ZEROBLOB: {
|
||||
int bytes = va_arg(ap, int);
|
||||
BIND_DEBUG(ZEROBLOB, sqlite3_bind_zeroblob, "%d,SQLITE_STATIC", bytes);
|
||||
BIND_RETRY(sqlite3_bind_zeroblob, bytes);
|
||||
};
|
||||
break;
|
||||
case SID_T: {
|
||||
const sid_t *sidp = va_arg(ap, const sid_t *);
|
||||
const char *sid_hex = alloca_tohex_sid_t(*sidp);
|
||||
BIND_DEBUG(SID_T, sqlite3_bind_text, "%s,%d,SQLITE_TRANSIENT", sid_hex, SID_STRLEN);
|
||||
BIND_RETRY(sqlite3_bind_text, sid_hex, SID_STRLEN, SQLITE_TRANSIENT);
|
||||
}
|
||||
break;
|
||||
case BUNDLE_ID_T: {
|
||||
const char *bid_hex = alloca_tohex(va_arg(ap, const unsigned char *), RHIZOME_MANIFEST_ID_BYTES);
|
||||
BIND_DEBUG(BUNDLE_ID_T, sqlite3_bind_text, "%s,%d,SQLITE_TRANSIENT", bid_hex, RHIZOME_MANIFEST_ID_STRLEN);
|
||||
BIND_RETRY(sqlite3_bind_text, bid_hex, RHIZOME_MANIFEST_ID_STRLEN, SQLITE_TRANSIENT);
|
||||
}
|
||||
break;
|
||||
case FILEHASH_T: {
|
||||
const char *hash_hex = alloca_tohex(va_arg(ap, const unsigned char *), RHIZOME_FILEHASH_BYTES);
|
||||
BIND_DEBUG(FILEHASH_T, sqlite3_bind_text, "%s,%d,SQLITE_TRANSIENT", hash_hex, RHIZOME_FILEHASH_STRLEN);
|
||||
BIND_RETRY(sqlite3_bind_text, hash_hex, RHIZOME_FILEHASH_STRLEN, SQLITE_TRANSIENT);
|
||||
}
|
||||
break;
|
||||
case TOHEX: {
|
||||
const unsigned char *binary = va_arg(ap, const unsigned char *);
|
||||
unsigned bytes = va_arg(ap, unsigned);
|
||||
char hex[bytes * 2];
|
||||
tohex(hex, binary, bytes);
|
||||
const char *hex = alloca_tohex(binary, bytes);
|
||||
BIND_DEBUG(TOHEX, sqlite3_bind_text, "%s,%d,SQLITE_TRANSIENT", hex, bytes * 2);
|
||||
BIND_RETRY(sqlite3_bind_text, hex, bytes * 2, SQLITE_TRANSIENT);
|
||||
}
|
||||
break;
|
||||
case TEXT_TOUPPER: {
|
||||
const char *text = va_arg(ap, const char *);
|
||||
unsigned bytes = strlen(text);
|
||||
char upper[bytes];
|
||||
unsigned i;
|
||||
for (i = 0; i != bytes; ++i)
|
||||
upper[i] = toupper(text[i]);
|
||||
char upper[bytes + 1];
|
||||
str_toupper_inplace(strcpy(upper, text));
|
||||
BIND_DEBUG(TEXT_TOUPPER, sqlite3_bind_text, "%s,%d,SQLITE_TRANSIENT", alloca_toprint(-1, upper, bytes), bytes);
|
||||
BIND_RETRY(sqlite3_bind_text, upper, bytes, SQLITE_TRANSIENT);
|
||||
}
|
||||
break;
|
||||
@ -564,11 +634,13 @@ int _sqlite_vbind(struct __sourceloc __whence, int log_level, sqlite_retry_state
|
||||
unsigned i;
|
||||
for (i = 0; i != bytes; ++i)
|
||||
upper[i] = toupper(text[i]);
|
||||
BIND_DEBUG(TEXT_LEN_TOUPPER, sqlite3_bind_text, "%s,%d,SQLITE_TRANSIENT", alloca_toprint(-1, upper, bytes), bytes);
|
||||
BIND_RETRY(sqlite3_bind_text, upper, bytes, SQLITE_TRANSIENT);
|
||||
}
|
||||
break;
|
||||
#undef BIND_RETRY
|
||||
default:
|
||||
FATALF("unsupported bind code %d", typ);
|
||||
FATALF("unsupported bind code, index=%d typ=0x%08x: %s", index, typ, sqlite3_sql(statement));
|
||||
}
|
||||
} while (typ != END);
|
||||
return 0;
|
||||
@ -583,7 +655,28 @@ int _sqlite_bind(struct __sourceloc __whence, int log_level, sqlite_retry_state
|
||||
return ret;
|
||||
}
|
||||
|
||||
int _sqlite_step_retry(struct __sourceloc __whence, int log_level, sqlite_retry_state *retry, sqlite3_stmt *statement)
|
||||
/* Prepare an SQL statement and bind some parameters. Returns a pointer to the SQLite statement if
|
||||
* successful or NULL if an error occurs (which is logged at the given log level).
|
||||
*
|
||||
* @author Andrew Bettison <andrew@servalproject.com>
|
||||
*/
|
||||
sqlite3_stmt *_sqlite_prepare_bind(struct __sourceloc __whence, int log_level, sqlite_retry_state *retry, const char *sqltext, ...)
|
||||
{
|
||||
sqlite3_stmt *statement = _sqlite_prepare(__whence, log_level, retry, sqltext);
|
||||
if (statement != NULL) {
|
||||
va_list ap;
|
||||
va_start(ap, sqltext);
|
||||
int ret = _sqlite_vbind(__whence, log_level, retry, statement, ap);
|
||||
va_end(ap);
|
||||
if (ret == -1) {
|
||||
sqlite3_finalize(statement);
|
||||
statement = NULL;
|
||||
}
|
||||
}
|
||||
return statement;
|
||||
}
|
||||
|
||||
int _sqlite_step(struct __sourceloc __whence, int log_level, sqlite_retry_state *retry, sqlite3_stmt *statement)
|
||||
{
|
||||
IN();
|
||||
int ret = -1;
|
||||
@ -633,13 +726,13 @@ int _sqlite_step_retry(struct __sourceloc __whence, int log_level, sqlite_retry_
|
||||
*
|
||||
* @author Andrew Bettison <andrew@servalproject.com>
|
||||
*/
|
||||
static int _sqlite_exec_prepared(struct __sourceloc __whence, int log_level, sqlite_retry_state *retry, sqlite3_stmt *statement)
|
||||
static int _sqlite_exec(struct __sourceloc __whence, int log_level, sqlite_retry_state *retry, sqlite3_stmt *statement)
|
||||
{
|
||||
if (!statement)
|
||||
return -1;
|
||||
int rowcount = 0;
|
||||
int stepcode;
|
||||
while ((stepcode = _sqlite_step_retry(__whence, log_level, retry, statement)) == SQLITE_ROW)
|
||||
while ((stepcode = _sqlite_step(__whence, log_level, retry, statement)) == SQLITE_ROW)
|
||||
++rowcount;
|
||||
sqlite3_finalize(statement);
|
||||
if (sqlite_trace_func())
|
||||
@ -654,12 +747,12 @@ static int _sqlite_exec_prepared(struct __sourceloc __whence, int log_level, sql
|
||||
*/
|
||||
static int _sqlite_vexec_void(struct __sourceloc __whence, int log_level, sqlite_retry_state *retry, const char *sqltext, va_list ap)
|
||||
{
|
||||
sqlite3_stmt *statement = _sqlite_prepare_loglevel(__whence, log_level, retry, sqltext);
|
||||
sqlite3_stmt *statement = _sqlite_prepare(__whence, log_level, retry, sqltext);
|
||||
if (!statement)
|
||||
return -1;
|
||||
if (_sqlite_vbind(__whence, log_level, retry, statement, ap) == -1)
|
||||
return -1;
|
||||
int rowcount = _sqlite_exec_prepared(__whence, log_level, retry, statement);
|
||||
int rowcount = _sqlite_exec(__whence, log_level, retry, statement);
|
||||
if (rowcount == -1)
|
||||
return -1;
|
||||
if (rowcount)
|
||||
@ -673,21 +766,7 @@ static int _sqlite_vexec_void(struct __sourceloc __whence, int log_level, sqlite
|
||||
*
|
||||
* @author Andrew Bettison <andrew@servalproject.com>
|
||||
*/
|
||||
int _sqlite_exec_void(struct __sourceloc __whence, const char *sqltext, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, sqltext);
|
||||
sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT;
|
||||
int ret = _sqlite_vexec_void(__whence, LOG_LEVEL_ERROR, &retry, sqltext, ap);
|
||||
va_end(ap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Same as sqlite_exec_void(), but logs any error at the given level instead of ERROR.
|
||||
*
|
||||
* @author Andrew Bettison <andrew@servalproject.com>
|
||||
*/
|
||||
int _sqlite_exec_void_loglevel(struct __sourceloc __whence, int log_level, const char *sqltext, ...)
|
||||
int _sqlite_exec_void(struct __sourceloc __whence, int log_level, const char *sqltext, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, sqltext);
|
||||
@ -704,20 +783,7 @@ int _sqlite_exec_void_loglevel(struct __sourceloc __whence, int log_level, const
|
||||
*
|
||||
* @author Andrew Bettison <andrew@servalproject.com>
|
||||
*/
|
||||
int _sqlite_exec_void_retry(struct __sourceloc __whence, sqlite_retry_state *retry, const char *sqltext, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, sqltext);
|
||||
int ret = _sqlite_vexec_void(__whence, LOG_LEVEL_ERROR, retry, sqltext, ap);
|
||||
va_end(ap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Same as sqlite_exec_void_retry(), but logs any error at the given level instead of ERROR.
|
||||
*
|
||||
* @author Andrew Bettison <andrew@servalproject.com>
|
||||
*/
|
||||
int _sqlite_exec_void_retry_loglevel(struct __sourceloc __whence, int log_level, sqlite_retry_state *retry, const char *sqltext, ...)
|
||||
int _sqlite_exec_void_retry(struct __sourceloc __whence, int log_level, sqlite_retry_state *retry, const char *sqltext, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, sqltext);
|
||||
@ -728,7 +794,7 @@ int _sqlite_exec_void_retry_loglevel(struct __sourceloc __whence, int log_level,
|
||||
|
||||
static int _sqlite_vexec_int64(struct __sourceloc __whence, sqlite_retry_state *retry, int64_t *result, const char *sqltext, va_list ap)
|
||||
{
|
||||
sqlite3_stmt *statement = _sqlite_prepare_loglevel(__whence, LOG_LEVEL_ERROR, retry, sqltext);
|
||||
sqlite3_stmt *statement = _sqlite_prepare(__whence, LOG_LEVEL_ERROR, retry, sqltext);
|
||||
if (!statement)
|
||||
return -1;
|
||||
if (_sqlite_vbind(__whence, LOG_LEVEL_ERROR, retry, statement, ap) == -1)
|
||||
@ -736,7 +802,7 @@ static int _sqlite_vexec_int64(struct __sourceloc __whence, sqlite_retry_state *
|
||||
int ret = 0;
|
||||
int rowcount = 0;
|
||||
int stepcode;
|
||||
while ((stepcode = _sqlite_step_retry(__whence, LOG_LEVEL_ERROR, retry, statement)) == SQLITE_ROW) {
|
||||
while ((stepcode = _sqlite_step(__whence, LOG_LEVEL_ERROR, retry, statement)) == SQLITE_ROW) {
|
||||
int columncount = sqlite3_column_count(statement);
|
||||
if (columncount != 1)
|
||||
ret = WHYF("incorrect column count %d (should be 1): %s", columncount, sqlite3_sql(statement));
|
||||
@ -818,7 +884,7 @@ int _sqlite_exec_strbuf_retry(struct __sourceloc __whence, sqlite_retry_state *r
|
||||
|
||||
int _sqlite_vexec_strbuf_retry(struct __sourceloc __whence, sqlite_retry_state *retry, strbuf sb, const char *sqltext, va_list ap)
|
||||
{
|
||||
sqlite3_stmt *statement = _sqlite_prepare_loglevel(__whence, LOG_LEVEL_ERROR, retry, sqltext);
|
||||
sqlite3_stmt *statement = _sqlite_prepare(__whence, LOG_LEVEL_ERROR, retry, sqltext);
|
||||
if (!statement)
|
||||
return -1;
|
||||
if (_sqlite_vbind(__whence, LOG_LEVEL_ERROR, retry, statement, ap) == -1)
|
||||
@ -826,7 +892,7 @@ int _sqlite_vexec_strbuf_retry(struct __sourceloc __whence, sqlite_retry_state *
|
||||
int ret = 0;
|
||||
int rowcount = 0;
|
||||
int stepcode;
|
||||
while ((stepcode = _sqlite_step_retry(__whence, LOG_LEVEL_ERROR, retry, statement)) == SQLITE_ROW) {
|
||||
while ((stepcode = _sqlite_step(__whence, LOG_LEVEL_ERROR, retry, statement)) == SQLITE_ROW) {
|
||||
int columncount = sqlite3_column_count(statement);
|
||||
if (columncount != 1)
|
||||
ret - WHYF("incorrect column count %d (should be 1): %s", columncount, sqlite3_sql(statement));
|
||||
@ -856,8 +922,8 @@ int rhizome_database_filehash_from_id(const char *id, uint64_t version, char has
|
||||
{
|
||||
IN();
|
||||
strbuf hash_sb = strbuf_local(hash, SHA512_DIGEST_STRING_LENGTH);
|
||||
RETURN(sqlite_exec_strbuf(hash_sb, "SELECT filehash FROM MANIFESTS WHERE manifests.version=%lld AND manifests.id='%s';",
|
||||
version,id));
|
||||
RETURN(sqlite_exec_strbuf(hash_sb, "SELECT filehash FROM MANIFESTS WHERE manifests.version = ? AND manifests.id = ?;",
|
||||
INT64, version, TEXT_TOUPPER, id, END));
|
||||
OUT();
|
||||
}
|
||||
|
||||
@ -1589,7 +1655,7 @@ static int rhizome_delete_manifest_retry(sqlite_retry_state *retry, const char *
|
||||
if (!statement)
|
||||
return -1;
|
||||
sqlite3_bind_text(statement, 1, manifestid, -1, SQLITE_STATIC);
|
||||
if (_sqlite_exec_prepared(__WHENCE__, LOG_LEVEL_ERROR, retry, statement) == -1)
|
||||
if (_sqlite_exec(__WHENCE__, LOG_LEVEL_ERROR, retry, statement) == -1)
|
||||
return -1;
|
||||
return sqlite3_changes(rhizome_db) ? 0 : 1;
|
||||
}
|
||||
@ -1605,7 +1671,7 @@ static int rhizome_delete_file_retry(sqlite_retry_state *retry, const char *file
|
||||
ret = -1;
|
||||
else {
|
||||
sqlite3_bind_text(statement, 1, fileid, -1, SQLITE_STATIC);
|
||||
if (_sqlite_exec_prepared(__WHENCE__, LOG_LEVEL_ERROR, retry, statement) == -1)
|
||||
if (_sqlite_exec(__WHENCE__, LOG_LEVEL_ERROR, retry, statement) == -1)
|
||||
ret = -1;
|
||||
}
|
||||
statement = sqlite_prepare(retry, "DELETE FROM fileblobs WHERE id = ?");
|
||||
@ -1613,7 +1679,7 @@ static int rhizome_delete_file_retry(sqlite_retry_state *retry, const char *file
|
||||
ret = -1;
|
||||
else {
|
||||
sqlite3_bind_text(statement, 1, fileid, -1, SQLITE_STATIC);
|
||||
if (_sqlite_exec_prepared(__WHENCE__, LOG_LEVEL_ERROR, retry, statement) == -1)
|
||||
if (_sqlite_exec(__WHENCE__, LOG_LEVEL_ERROR, retry, statement) == -1)
|
||||
ret = -1;
|
||||
}
|
||||
return ret == -1 ? -1 : sqlite3_changes(rhizome_db) ? 0 : 1;
|
||||
@ -1622,7 +1688,7 @@ static int rhizome_delete_file_retry(sqlite_retry_state *retry, const char *file
|
||||
static int rhizome_delete_payload_retry(sqlite_retry_state *retry, const char *manifestid)
|
||||
{
|
||||
strbuf fh = strbuf_alloca(RHIZOME_FILEHASH_STRLEN + 1);
|
||||
int rows = sqlite_exec_strbuf_retry(retry, fh, "SELECT filehash FROM manifests WHERE id = '%s'", manifestid);
|
||||
int rows = sqlite_exec_strbuf_retry(retry, fh, "SELECT filehash FROM manifests WHERE id = ?", TEXT_TOUPPER, manifestid, END);
|
||||
if (rows == -1)
|
||||
return -1;
|
||||
if (rows && rhizome_delete_file_retry(retry, strbuf_str(fh)) == -1)
|
||||
|
@ -421,14 +421,13 @@ rhizome_manifest *rhizome_direct_get_manifest(unsigned char *bid_prefix,int pref
|
||||
bcopy(bid_prefix,low,prefix_length);
|
||||
bcopy(bid_prefix,high,prefix_length);
|
||||
|
||||
char query[1024];
|
||||
snprintf(query,1024,"SELECT MANIFEST,ROWID FROM MANIFESTS WHERE ID>='%s' AND ID<='%s'",
|
||||
alloca_tohex(low,RHIZOME_MANIFEST_ID_BYTES),
|
||||
alloca_tohex(high,RHIZOME_MANIFEST_ID_BYTES));
|
||||
|
||||
sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT;
|
||||
sqlite3_stmt *statement = sqlite_prepare(&retry, query);
|
||||
sqlite3_blob *blob=NULL;
|
||||
sqlite3_stmt *statement = sqlite_prepare_bind(&retry,
|
||||
"SELECT manifest, rowid FROM MANIFESTS WHERE id >= ? AND id <= ?",
|
||||
BUNDLE_ID_T, low,
|
||||
BUNDLE_ID_T, high,
|
||||
END);
|
||||
sqlite3_blob *blob=NULL;
|
||||
if (sqlite_step_retry(&retry, statement) == SQLITE_ROW)
|
||||
{
|
||||
int ret;
|
||||
@ -751,23 +750,20 @@ int rhizome_direct_get_bars(const unsigned char bid_low[RHIZOME_MANIFEST_ID_BYTE
|
||||
int bars_requested)
|
||||
{
|
||||
sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT;
|
||||
char query[1024];
|
||||
|
||||
snprintf(query,1024,
|
||||
"SELECT BAR,ROWID,ID,FILESIZE FROM MANIFESTS"
|
||||
" WHERE"
|
||||
" FILESIZE BETWEEN %" PRId64 " AND %" PRId64
|
||||
" AND ID>='%s' AND ID<='%s'"
|
||||
// The following formulation doesn't remove the weird returning of
|
||||
// bundles with out of range filesize values
|
||||
// " WHERE ID>='%s' AND ID<='%s' AND FILESIZE > %lld AND FILESIZE < %lld"
|
||||
" ORDER BY BAR LIMIT %d;",
|
||||
size_low, size_high,
|
||||
alloca_tohex(bid_low,RHIZOME_MANIFEST_ID_BYTES),
|
||||
alloca_tohex(bid_max,RHIZOME_MANIFEST_ID_BYTES),
|
||||
bars_requested);
|
||||
|
||||
sqlite3_stmt *statement=sqlite_prepare(&retry, query);
|
||||
sqlite3_stmt *statement = sqlite_prepare_bind(&retry,
|
||||
"SELECT bar, rowid, id, filesize FROM MANIFESTS"
|
||||
" WHERE filesize BETWEEN ? AND ? AND id >= ? AND id <= ?"
|
||||
" ORDER BY bar LIMIT ?;",
|
||||
INT64, size_low,
|
||||
INT64, size_high,
|
||||
BUNDLE_ID_T, bid_low,
|
||||
BUNDLE_ID_T, bid_high,
|
||||
INT, bars_requested,
|
||||
// The following formulation doesn't remove the weird returning of
|
||||
// bundles with out of range filesize values
|
||||
// " WHERE id >= ? AND id <= ? AND filesize > ? AND filesize < ?"
|
||||
END);
|
||||
sqlite3_blob *blob=NULL;
|
||||
|
||||
int bars_written=0;
|
||||
@ -784,8 +780,7 @@ int rhizome_direct_get_bars(const unsigned char bid_low[RHIZOME_MANIFEST_ID_BYTE
|
||||
int ret;
|
||||
int64_t filesize = sqlite3_column_int64(statement, 3);
|
||||
if (filesize<size_low||filesize>size_high) {
|
||||
DEBUGF("WEIRDNESS ALERT: filesize=%"PRId64", but query was: %s",
|
||||
filesize,query);
|
||||
DEBUGF("WEIRDNESS ALERT: filesize=%"PRId64", but query was: %s", filesize, sqlite3_sql(statement));
|
||||
break;
|
||||
}
|
||||
int64_t rowid = sqlite3_column_int64(statement, 1);
|
||||
|
@ -857,11 +857,10 @@ int rhizome_suggest_queue_manifest_import(rhizome_manifest *m, const struct sock
|
||||
RETURN(0);
|
||||
}
|
||||
|
||||
const char *bid = alloca_tohex_bid(m->cryptoSignPublic);
|
||||
int priority=100; /* normal priority */
|
||||
|
||||
if (config.debug.rhizome_rx)
|
||||
DEBUGF("Considering import bid=%s version=%"PRId64" size=%"PRId64" priority=%d:", bid, m->version, m->fileLength, priority);
|
||||
DEBUGF("Considering import bid=%s version=%"PRId64" size=%"PRId64" priority=%d:", alloca_tohex_bid(m->cryptoSignPublic), m->version, m->fileLength, priority);
|
||||
|
||||
if (!rhizome_is_manifest_interesting(m)) {
|
||||
if (config.debug.rhizome_rx)
|
||||
@ -872,7 +871,7 @@ int rhizome_suggest_queue_manifest_import(rhizome_manifest *m, const struct sock
|
||||
|
||||
if (config.debug.rhizome_rx) {
|
||||
int64_t stored_version;
|
||||
if (sqlite_exec_int64(&stored_version, "select version from manifests where id='%s'", bid) > 0)
|
||||
if (sqlite_exec_int64(&stored_version, "SELECT version FROM MANIFESTS WHERE id = ?", BUNDLE_ID_T, m->cryptoSignPublic, END) > 0)
|
||||
DEBUGF(" is new (have version %"PRId64")", stored_version);
|
||||
}
|
||||
|
||||
|
@ -134,38 +134,43 @@ uint64_t rhizome_bar_bidprefix_ll(unsigned char *bar)
|
||||
return bidprefix;
|
||||
}
|
||||
|
||||
static int append_bars(struct overlay_buffer *e, sqlite_retry_state *retry, const char *sql, int64_t *last_rowid){
|
||||
int count=0;
|
||||
|
||||
sqlite3_stmt *statement=sqlite_prepare(retry, sql, *last_rowid);
|
||||
|
||||
static int append_bars(struct overlay_buffer *e, sqlite_retry_state *retry, const char *sql, int64_t *last_rowid)
|
||||
{
|
||||
sqlite3_stmt *statement = sqlite_prepare(retry, sql);
|
||||
if (statement == NULL)
|
||||
return -1;
|
||||
int params = sqlite3_bind_parameter_count(statement);
|
||||
switch (params) {
|
||||
case 0: break;
|
||||
case 1:
|
||||
if (sqlite_bind(retry, statement, INT64, *last_rowid, END) == -1)
|
||||
return -1;
|
||||
break;
|
||||
default:
|
||||
return WHYF("query has invalid number of parameters (%d): %s", params, sqlite3_sql(statement));
|
||||
}
|
||||
int count = 0;
|
||||
while(sqlite_step_retry(retry, statement) == SQLITE_ROW) {
|
||||
count++;
|
||||
if (sqlite3_column_type(statement, 0)!=SQLITE_BLOB)
|
||||
continue;
|
||||
|
||||
const void *data = sqlite3_column_blob(statement, 0);
|
||||
int blob_bytes = sqlite3_column_bytes(statement, 0);
|
||||
int64_t rowid = sqlite3_column_int64(statement, 1);
|
||||
|
||||
if (blob_bytes!=RHIZOME_BAR_BYTES) {
|
||||
if (config.debug.rhizome_ads)
|
||||
DEBUG("Found a BAR that is the wrong size - ignoring");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ob_append_bytes(e, (unsigned char *)data, blob_bytes)){
|
||||
// out of room
|
||||
count--;
|
||||
break;
|
||||
}
|
||||
|
||||
*last_rowid=rowid;
|
||||
}
|
||||
|
||||
if (statement)
|
||||
sqlite3_finalize(statement);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
@ -191,7 +196,7 @@ void overlay_rhizome_advertise(struct sched_ent *alarm){
|
||||
goto end;
|
||||
|
||||
/* Get number of bundles available */
|
||||
if (sqlite_exec_int64_retry(&retry, &bundles_available, "SELECT COUNT(BAR) FROM MANIFESTS;") != 1){
|
||||
if (sqlite_exec_int64_retry(&retry, &bundles_available, "SELECT COUNT(BAR) FROM MANIFESTS;", END) != 1){
|
||||
WHY("Could not count BARs for advertisement");
|
||||
goto end;
|
||||
}
|
||||
@ -221,7 +226,7 @@ void overlay_rhizome_advertise(struct sched_ent *alarm){
|
||||
bundle_last_rowid=rowid;
|
||||
|
||||
count = append_bars(frame->payload, &retry,
|
||||
"SELECT BAR,ROWID FROM MANIFESTS WHERE ROWID < %lld ORDER BY ROWID DESC LIMIT 17",
|
||||
"SELECT BAR,ROWID FROM MANIFESTS WHERE ROWID < ? ORDER BY ROWID DESC LIMIT 17",
|
||||
&bundle_last_rowid);
|
||||
if (count<17)
|
||||
bundle_last_rowid=INT64_MAX;
|
||||
|
114
rhizome_store.c
114
rhizome_store.c
@ -8,12 +8,13 @@
|
||||
int rhizome_exists(const char *fileHash)
|
||||
{
|
||||
int64_t gotfile = 0;
|
||||
if (sqlite_exec_int64(&gotfile, "SELECT COUNT(*) FROM FILES WHERE ID='%s' and datavalid=1;", fileHash) != 1)
|
||||
if (sqlite_exec_int64(&gotfile, "SELECT COUNT(*) FROM FILES WHERE id = ? and datavalid = 1;", TEXT_TOUPPER, fileHash, END) != 1)
|
||||
return 0;
|
||||
return gotfile;
|
||||
}
|
||||
|
||||
int rhizome_open_write(struct rhizome_write *write, char *expectedFileHash, int64_t file_length, int priority){
|
||||
int rhizome_open_write(struct rhizome_write *write, char *expectedFileHash, int64_t file_length, int priority)
|
||||
{
|
||||
write->blob_fd=-1;
|
||||
|
||||
if (expectedFileHash){
|
||||
@ -24,15 +25,16 @@ int rhizome_open_write(struct rhizome_write *write, char *expectedFileHash, int6
|
||||
}else{
|
||||
write->id_known=0;
|
||||
}
|
||||
time_ms_t now = gettime_ms();
|
||||
static uint64_t last_id=0;
|
||||
write->temp_id = gettime_ms();
|
||||
if (write->temp_id<last_id)
|
||||
write->temp_id=last_id+1;
|
||||
last_id=write->temp_id;
|
||||
write->temp_id = now;
|
||||
if (write->temp_id < last_id)
|
||||
write->temp_id = last_id + 1;
|
||||
last_id = write->temp_id;
|
||||
|
||||
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");
|
||||
|
||||
/*
|
||||
@ -45,10 +47,15 @@ int rhizome_open_write(struct rhizome_write *write, char *expectedFileHash, int6
|
||||
*/
|
||||
|
||||
sqlite3_stmt *statement = NULL;
|
||||
int ret=sqlite_exec_void_retry(&retry,
|
||||
"INSERT OR REPLACE INTO FILES(id,length,highestpriority,datavalid,inserttime) "
|
||||
"VALUES('%"PRId64"',%"PRId64",%d,0,%"PRId64");",
|
||||
write->temp_id, file_length, priority, gettime_ms());
|
||||
int ret = sqlite_exec_void_retry(
|
||||
&retry,
|
||||
"INSERT OR REPLACE INTO FILES(id,length,highestpriority,datavalid,inserttime) VALUES(?,?,?,0,?);",
|
||||
UINT64_TOSTR, write->temp_id,
|
||||
INT64, file_length,
|
||||
INT, priority,
|
||||
INT64, now,
|
||||
END
|
||||
);
|
||||
if (ret==-1)
|
||||
goto insert_row_fail;
|
||||
|
||||
@ -61,8 +68,7 @@ int rhizome_open_write(struct rhizome_write *write, char *expectedFileHash, int6
|
||||
}
|
||||
|
||||
if (config.debug.externalblobs)
|
||||
DEBUGF("Attempting to put blob for %"PRId64" in %s",
|
||||
write->temp_id,blob_path);
|
||||
DEBUGF("Attempting to put blob for id='%"PRId64"' in %s", write->temp_id, blob_path);
|
||||
|
||||
write->blob_fd=open(blob_path, O_CREAT | O_TRUNC | O_WRONLY, 0664);
|
||||
if (write->blob_fd<0)
|
||||
@ -72,45 +78,39 @@ int rhizome_open_write(struct rhizome_write *write, char *expectedFileHash, int6
|
||||
DEBUGF("Writing to new blob file %s (fd=%d)", blob_path, write->blob_fd);
|
||||
|
||||
}else{
|
||||
statement = sqlite_prepare(&retry,"INSERT OR REPLACE INTO FILEBLOBS(id,data) VALUES('%"PRId64"',?)",write->temp_id);
|
||||
if (!statement) {
|
||||
WHYF("Failed to insert into fileblobs: %s", sqlite3_errmsg(rhizome_db));
|
||||
statement = sqlite_prepare_bind(
|
||||
&retry,
|
||||
"INSERT OR REPLACE INTO FILEBLOBS(id,data) VALUES(?,?)",
|
||||
UINT64_TOSTR, write->temp_id,
|
||||
ZEROBLOB, (int)file_length,
|
||||
END);
|
||||
if (statement == NULL)
|
||||
goto insert_row_fail;
|
||||
}
|
||||
|
||||
/* Bind appropriate sized zero-filled blob to data field */
|
||||
if (sqlite3_bind_zeroblob(statement, 1, file_length) != SQLITE_OK) {
|
||||
WHYF("sqlite3_bind_zeroblob() failed: %s: %s", sqlite3_errmsg(rhizome_db), sqlite3_sql(statement));
|
||||
goto insert_row_fail;
|
||||
}
|
||||
|
||||
/* Do actual insert, and abort if it fails */
|
||||
int rowcount = 0;
|
||||
int stepcode;
|
||||
while ((stepcode = _sqlite_step_retry(__WHENCE__, LOG_LEVEL_ERROR, &retry, statement)) == SQLITE_ROW)
|
||||
while ((stepcode = sqlite_step_retry(&retry, statement)) == SQLITE_ROW)
|
||||
++rowcount;
|
||||
if (rowcount)
|
||||
WARNF("void query unexpectedly returned %d row%s", rowcount, rowcount == 1 ? "" : "s");
|
||||
|
||||
if (!sqlite_code_ok(stepcode)){
|
||||
insert_row_fail:
|
||||
WHYF("Failed to insert row for fileid=%"PRId64, write->temp_id);
|
||||
WHYF("Failed to insert row for id='%"PRId64"'", write->temp_id);
|
||||
if (statement) sqlite3_finalize(statement);
|
||||
sqlite_exec_void_retry(&retry, "ROLLBACK;");
|
||||
sqlite_exec_void_retry(&retry, "ROLLBACK;", END);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sqlite3_finalize(statement);
|
||||
statement=NULL;
|
||||
|
||||
/* Get rowid for inserted row, so that we can modify the blob */
|
||||
write->blob_rowid = sqlite3_last_insert_rowid(rhizome_db);
|
||||
if (config.debug.rhizome_rx)
|
||||
DEBUGF("Got rowid %"PRId64" for %"PRId64, write->blob_rowid, write->temp_id);
|
||||
DEBUGF("Got rowid=%"PRId64" for id='%"PRId64"'", write->blob_rowid, write->temp_id);
|
||||
|
||||
}
|
||||
|
||||
if (sqlite_exec_void_retry(&retry, "COMMIT;") == -1){
|
||||
if (sqlite_exec_void_retry(&retry, "COMMIT;", END) == -1){
|
||||
if (write->blob_fd>=0){
|
||||
if (config.debug.externalblobs)
|
||||
DEBUGF("Cancel write to fd %d", write->blob_fd);
|
||||
@ -167,7 +167,7 @@ static int write_get_lock(struct rhizome_write *write_state){
|
||||
sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT;
|
||||
|
||||
// use an explicit transaction so we can delay I/O failures until COMMIT so they can be retried.
|
||||
if (sqlite_exec_void_retry(&retry, "BEGIN TRANSACTION;") == -1)
|
||||
if (sqlite_exec_void_retry(&retry, "BEGIN TRANSACTION;", END) == -1)
|
||||
return -1;
|
||||
|
||||
while(1){
|
||||
@ -243,7 +243,7 @@ static int write_release_lock(struct rhizome_write *write_state){
|
||||
sqlite3_errmsg(rhizome_db));
|
||||
|
||||
sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT;
|
||||
if (sqlite_exec_void_retry(&retry, "COMMIT;") == -1)
|
||||
if (sqlite_exec_void_retry(&retry, "COMMIT;", END) == -1)
|
||||
ret=-1;
|
||||
}
|
||||
write_state->sql_blob=NULL;
|
||||
@ -477,21 +477,27 @@ int rhizome_finish_write(struct rhizome_write *write)
|
||||
rhizome_remove_file_datainvalid(&retry, write->id);
|
||||
if (rhizome_exists(write->id)) {
|
||||
// we've already got that payload, delete the new copy
|
||||
sqlite_exec_void_retry_loglevel(LOG_LEVEL_WARN, &retry,"DELETE FROM FILEBLOBS WHERE id='%"PRId64"';", write->temp_id);
|
||||
sqlite_exec_void_retry_loglevel(LOG_LEVEL_WARN, &retry,"DELETE FROM FILES WHERE id='%"PRId64"';", write->temp_id);
|
||||
sqlite_exec_void_retry_loglevel(LOG_LEVEL_WARN, &retry, "DELETE FROM FILEBLOBS WHERE id = ?;", UINT64_TOSTR, write->temp_id, END);
|
||||
sqlite_exec_void_retry_loglevel(LOG_LEVEL_WARN, &retry, "DELETE FROM FILES WHERE id = ?;", UINT64_TOSTR, write->temp_id, END);
|
||||
if (config.debug.rhizome)
|
||||
DEBUGF("File id='%s' already present, removed id='%"PRId64"'", write->id, write->temp_id);
|
||||
} else {
|
||||
if (sqlite_exec_void_retry(&retry, "BEGIN TRANSACTION;") == -1)
|
||||
if (sqlite_exec_void_retry(&retry, "BEGIN TRANSACTION;", END) == -1)
|
||||
goto dbfailure;
|
||||
|
||||
// delete any half finished records
|
||||
sqlite_exec_void_retry_loglevel(LOG_LEVEL_WARN, &retry,"DELETE FROM FILEBLOBS WHERE id='%s';",hash_out);
|
||||
sqlite_exec_void_retry_loglevel(LOG_LEVEL_WARN, &retry,"DELETE FROM FILES WHERE id='%s';",hash_out);
|
||||
sqlite_exec_void_retry_loglevel(LOG_LEVEL_WARN, &retry, "DELETE FROM FILEBLOBS WHERE id = ?;", STATIC_TEXT, write->id, END);
|
||||
sqlite_exec_void_retry_loglevel(LOG_LEVEL_WARN, &retry, "DELETE FROM FILES WHERE id = ?;", STATIC_TEXT, write->id, END);
|
||||
|
||||
if (sqlite_exec_void_retry(&retry,
|
||||
"UPDATE FILES SET id='%s', inserttime=%lld, datavalid=1 WHERE id='%"PRId64"'",
|
||||
hash_out, gettime_ms(), write->temp_id) == -1)
|
||||
if (sqlite_exec_void_retry(
|
||||
&retry,
|
||||
"UPDATE FILES SET id = ?, inserttime = ?, datavalid = 1 WHERE id = ?",
|
||||
STATIC_TEXT, write->id,
|
||||
INT64, gettime_ms(),
|
||||
UINT64_TOSTR, write->temp_id,
|
||||
END
|
||||
) == -1
|
||||
)
|
||||
goto dbfailure;
|
||||
|
||||
if (fd>=0){
|
||||
@ -501,7 +507,7 @@ int rhizome_finish_write(struct rhizome_write *write)
|
||||
WHYF("Failed to generate file path");
|
||||
goto dbfailure;
|
||||
}
|
||||
if (!FORM_RHIZOME_DATASTORE_PATH(dest_path, hash_out)){
|
||||
if (!FORM_RHIZOME_DATASTORE_PATH(dest_path, write->id)){
|
||||
WHYF("Failed to generate file path");
|
||||
goto dbfailure;
|
||||
}
|
||||
@ -512,13 +518,17 @@ int rhizome_finish_write(struct rhizome_write *write)
|
||||
}
|
||||
|
||||
}else{
|
||||
if (sqlite_exec_void_retry(&retry,
|
||||
"UPDATE FILEBLOBS SET id='%s' WHERE rowid=%lld",
|
||||
hash_out, write->blob_rowid) == -1){
|
||||
goto dbfailure;
|
||||
}
|
||||
if (sqlite_exec_void_retry(
|
||||
&retry,
|
||||
"UPDATE FILEBLOBS SET id = ? WHERE rowid = ?",
|
||||
STATIC_TEXT, write->id,
|
||||
INT64, write->blob_rowid,
|
||||
END
|
||||
) == -1
|
||||
)
|
||||
goto dbfailure;
|
||||
}
|
||||
if (sqlite_exec_void_retry(&retry, "COMMIT;") == -1)
|
||||
if (sqlite_exec_void_retry(&retry, "COMMIT;", END) == -1)
|
||||
goto dbfailure;
|
||||
if (config.debug.rhizome)
|
||||
DEBUGF("Stored file %s", write->id);
|
||||
@ -527,7 +537,7 @@ int rhizome_finish_write(struct rhizome_write *write)
|
||||
return 0;
|
||||
|
||||
dbfailure:
|
||||
sqlite_exec_void_retry(&retry, "ROLLBACK;");
|
||||
sqlite_exec_void_retry(&retry, "ROLLBACK;", END);
|
||||
failure:
|
||||
rhizome_fail_write(write);
|
||||
return -1;
|
||||
@ -687,9 +697,9 @@ int rhizome_open_read(struct rhizome_read *read, const char *fileid)
|
||||
if (sqlite_exec_int64(&read->blob_rowid,
|
||||
"SELECT FILEBLOBS.rowid "
|
||||
"FROM FILEBLOBS, FILES "
|
||||
"WHERE FILEBLOBS.id = FILES.id "
|
||||
"AND FILES.id = '%s' "
|
||||
"AND FILES.datavalid != 0", read->id) == -1)
|
||||
"WHERE FILEBLOBS.id = FILES.id"
|
||||
" AND FILES.id = ?"
|
||||
" AND FILES.datavalid != 0", STATIC_TEXT, read->id, END) == -1)
|
||||
return -1;
|
||||
if (read->blob_rowid != -1) {
|
||||
read->length = -1; // discover the length on opening the db BLOB
|
||||
|
Loading…
x
Reference in New Issue
Block a user