int SLNSessionGetValueForField(SLNSessionRef const session, str_t value[], size_t const max, strarg_t const fileURI, strarg_t const field) { if(!SLNSessionHasPermission(session, SLN_RDONLY)) return DB_EACCES; if(!field) return DB_EINVAL; if(max) value[0] = '\0'; int rc = 0; DB_cursor *metafiles = NULL; DB_cursor *values = NULL; SLNRepoRef const repo = SLNSessionGetRepo(session); DB_env *db = NULL; SLNRepoDBOpen(repo, &db); DB_txn *txn = NULL; rc = db_txn_begin(db, NULL, DB_RDONLY, &txn); if(rc < 0) goto done; rc = db_cursor_open(txn, &metafiles); if(rc < 0) goto done; rc = db_cursor_open(txn, &values); if(rc < 0) goto done; DB_range metaFileIDs[1]; SLNTargetURIAndMetaFileIDRange1(metaFileIDs, txn, fileURI); DB_val metaFileID_key[1]; rc = db_cursor_firstr(metafiles, metaFileIDs, metaFileID_key, NULL, +1); if(rc < 0 && DB_NOTFOUND != rc) goto done; for(; rc >= 0; rc = db_cursor_nextr(metafiles, metaFileIDs, metaFileID_key, NULL, +1)) { strarg_t u; uint64_t metaFileID; SLNTargetURIAndMetaFileIDKeyUnpack(metaFileID_key, txn, &u, &metaFileID); assert(0 == strcmp(fileURI, u)); DB_range vrange[1]; SLNMetaFileIDFieldAndValueRange2(vrange, txn, metaFileID, field); DB_val value_val[1]; rc = db_cursor_firstr(values, vrange, value_val, NULL, +1); if(rc < 0 && DB_NOTFOUND != rc) goto done; for(; rc >= 0; rc = db_cursor_nextr(values, vrange, value_val, NULL, +1)) { uint64_t m; strarg_t f, v; SLNMetaFileIDFieldAndValueKeyUnpack(value_val, txn, &m, &f, &v); assert(metaFileID == m); assert(0 == strcmp(field, f)); if(!v) continue; if(0 == strcmp("", v)) continue; size_t const len = strlen(v); memcpy(value, v, MIN(len, max-1)); value[MIN(len, max-1)] = '\0'; goto done; } } done: db_cursor_close(values); values = NULL; db_cursor_close(metafiles); metafiles = NULL; db_txn_abort(txn); txn = NULL; SLNRepoDBClose(repo, &db); return rc; }
int SLNSessionGetValueForField(SLNSessionRef const session, DB_txn *const txn, strarg_t const fileURI, strarg_t const field, str_t *out, size_t const max) { int rc = 0; DB_cursor *metafiles = NULL; DB_cursor *values = NULL; rc = db_cursor_open(txn, &metafiles); if(rc < 0) goto done; rc = db_cursor_open(txn, &values); if(rc < 0) goto done; DB_range metaFileIDs[1]; SLNTargetURIAndMetaFileIDRange1(metaFileIDs, txn, fileURI); DB_val metaFileID_key[1]; rc = db_cursor_firstr(metafiles, metaFileIDs, metaFileID_key, NULL, +1); if(rc < 0 && DB_NOTFOUND != rc) goto done; for(; rc >= 0; rc = db_cursor_nextr(metafiles, metaFileIDs, metaFileID_key, NULL, +1)) { strarg_t u; uint64_t metaFileID; SLNTargetURIAndMetaFileIDKeyUnpack(metaFileID_key, txn, &u, &metaFileID); assert(0 == strcmp(fileURI, u)); DB_range vrange[1]; SLNMetaFileIDFieldAndValueRange2(vrange, txn, metaFileID, field); DB_val value_val[1]; rc = db_cursor_firstr(values, vrange, value_val, NULL, +1); if(rc < 0 && DB_NOTFOUND != rc) goto done; for(; rc >= 0; rc = db_cursor_nextr(values, vrange, value_val, NULL, +1)) { uint64_t m; strarg_t f, v; SLNMetaFileIDFieldAndValueKeyUnpack(value_val, txn, &m, &f, &v); assert(metaFileID == m); assert(0 == strcmp(field, f)); if(!v || '\0' == v[0]) continue; strlcpy(out, v, max); goto done; } } done: db_cursor_close(values); values = NULL; db_cursor_close(metafiles); metafiles = NULL; return rc; }
int SLNSessionGetNextMetaMapURI(SLNSessionRef const session, strarg_t const targetURI, uint64_t *const metaMapID, str_t *out, size_t const max) { // TODO: We should handle URI synonyms. // That might mean accepting a fileID instead of targetURI... assert(metaMapID); assert(out); uint64_t const sessionID = SLNSessionGetID(session); DB_env *db = NULL; DB_txn *txn = NULL; DB_cursor *cursor = NULL; int rc = 0; size_t count = 0; rc = SLNSessionDBOpen(session, SLN_RDONLY, &db); if(rc < 0) goto cleanup; rc = db_txn_begin(db, NULL, DB_RDONLY, &txn); if(rc < 0) goto cleanup; rc = db_cursor_open(txn, &cursor); if(rc < 0) goto cleanup; DB_range range[1]; DB_val key[1]; SLNTargetURISessionIDAndMetaMapIDRange2(range, txn, targetURI, sessionID); SLNTargetURISessionIDAndMetaMapIDKeyPack(key, txn, targetURI, sessionID, *metaMapID); rc = db_cursor_seekr(cursor, range, key, NULL, +1); if(rc < 0) goto cleanup; strarg_t u; uint64_t s; SLNTargetURISessionIDAndMetaMapIDKeyUnpack(key, txn, &u, &s, metaMapID); DB_val row[1], val[1]; SLNSessionIDAndMetaMapIDToMetaURIAndTargetURIKeyPack(row, txn, sessionID, *metaMapID); rc = db_get(txn, row, val); if(rc < 0) goto cleanup; strarg_t metaURI, t; SLNSessionIDAndMetaMapIDToMetaURIAndTargetURIValUnpack(val, txn, &metaURI, &t); db_assert(metaURI); strlcpy(out, metaURI, max); // TODO: Handle err cleanup: db_cursor_close(cursor); cursor = NULL; db_txn_abort(txn); txn = NULL; SLNSessionDBClose(session, &db); if(rc < 0) return rc; return count; }
static void add_fulltext(DB_txn *const txn, uint64_t const metaFileID, strarg_t const str, size_t const len) { if(0 == len) return; assert(str); int rc; sqlite3_tokenizer_module const *fts = NULL; sqlite3_tokenizer *tokenizer = NULL; fts_get(&fts, &tokenizer); sqlite3_tokenizer_cursor *tcur = NULL; rc = fts->xOpen(tokenizer, str, len, &tcur); assert(SQLITE_OK == rc); DB_cursor *cursor = NULL; rc = db_cursor_open(txn, &cursor); assert(rc >= 0); for(;;) { strarg_t token; int tlen; int tpos; // TODO int ignored1, ignored2; rc = fts->xNext(tcur, &token, &tlen, &ignored1, &ignored2, &tpos); if(SQLITE_OK != rc) break; assert('\0' == token[tlen]); // Assumption DB_val token_val[1]; SLNTermMetaFileIDAndPositionKeyPack(token_val, txn, token, metaFileID, 0); // TODO: Record tpos. Requires changes to SLNFulltextFilter so that each document only gets returned once, no matter how many times the token appears within it. DB_val null = { 0, NULL }; rc = db_cursor_put(cursor, token_val, &null, DB_NOOVERWRITE_FAST); assert(rc >= 0 || DB_KEYEXIST == rc); } db_cursor_close(cursor); cursor = NULL; fts->xClose(tcur); tcur = NULL; }