mirror of
https://github.com/GrammaticalFramework/gf-core.git
synced 2026-10-30 02:13:18 -06:00
added a primitive full-text search index in libsg. This can be use for finding an abstract tree whose linearization matches given keywords
This commit is contained in:
1 parent
0b9395fd70
commit
bef9d8c5fc
6 files changed
+413
-102
No files matched your search
+366
-100
@@ -2,11 +2,13 @@
|
||||
#include "sqlite3.c"
|
||||
|
||||
#include "sg/sg.h"
|
||||
#include "pgf/data.h"
|
||||
|
||||
#define SG_EXPRS "sg_exprs"
|
||||
#define SG_PAIRS "sg_pairs"
|
||||
#define SG_IDENTS "sg_idents"
|
||||
#define SG_LITERALS "sg_literals"
|
||||
#define SG_TOKENS "sg_tokens"
|
||||
#define SG_TRIPLES "sg_triples"
|
||||
#define SG_TRIPLES_SPO "sg_triples_spo"
|
||||
#define SG_TRIPLES_PO "sg_triples_po"
|
||||
@@ -48,6 +50,7 @@ sg_open(const char *filename,
|
||||
|
||||
rc = sqlite3_exec(db, "create table if not exists " SG_EXPRS "(fun not null, arg integer);"
|
||||
"create unique index if not exists " SG_IDENTS " on " SG_EXPRS "(fun) where arg is null;"
|
||||
"create index if not exists " SG_TOKENS " on " SG_EXPRS "(fun) where arg <> arg;" // actually used for full text search
|
||||
"create unique index if not exists " SG_LITERALS " on " SG_EXPRS "(fun) where arg = 0;"
|
||||
"create unique index if not exists " SG_PAIRS " on " SG_EXPRS "(fun,arg) where arg > 0;"
|
||||
"create table if not exists " SG_TRIPLES "(subj integer, pred integer, obj integer, state integer);"
|
||||
@@ -123,14 +126,15 @@ sg_rollback(SgSG* sg, GuExn* err)
|
||||
typedef struct {
|
||||
int n_cursors;
|
||||
BtCursor crsExprs;
|
||||
BtCursor crsPairs;
|
||||
BtCursor crsIdents;
|
||||
BtCursor crsLiterals;
|
||||
BtCursor crsPairs;
|
||||
SgId key_seed;
|
||||
} ExprContext;
|
||||
|
||||
static int
|
||||
open_exprs(sqlite3 *db, int wrFlag, ExprContext* ctxt, GuExn* err)
|
||||
open_exprs(sqlite3 *db, int wrFlag, bool identsOnly,
|
||||
ExprContext* ctxt, GuExn* err)
|
||||
{
|
||||
ctxt->n_cursors = 0;
|
||||
|
||||
@@ -140,12 +144,6 @@ open_exprs(sqlite3 *db, int wrFlag, ExprContext* ctxt, GuExn* err)
|
||||
sg_raise_err("Table " SG_EXPRS " is missing", err);
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
|
||||
Index *pairsIdx = sqlite3HashFind(&db->aDb[0].pSchema->idxHash, SG_PAIRS);
|
||||
if (!pairsIdx) {
|
||||
sg_raise_err("Index " SG_PAIRS " is missing", err);
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
|
||||
Index *identsIdx = sqlite3HashFind(&db->aDb[0].pSchema->idxHash, SG_IDENTS);
|
||||
if (!identsIdx) {
|
||||
@@ -159,6 +157,12 @@ open_exprs(sqlite3 *db, int wrFlag, ExprContext* ctxt, GuExn* err)
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
|
||||
Index *pairsIdx = sqlite3HashFind(&db->aDb[0].pSchema->idxHash, SG_PAIRS);
|
||||
if (!pairsIdx) {
|
||||
sg_raise_err("Index " SG_PAIRS " is missing", err);
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
|
||||
int rc;
|
||||
|
||||
memset(&ctxt->crsExprs, 0, sizeof(ctxt->crsExprs));
|
||||
@@ -169,15 +173,6 @@ open_exprs(sqlite3 *db, int wrFlag, ExprContext* ctxt, GuExn* err)
|
||||
}
|
||||
ctxt->n_cursors++;
|
||||
|
||||
memset(&ctxt->crsPairs, 0, sizeof(ctxt->crsPairs));
|
||||
KeyInfo *infPairs = sqlite3KeyInfoAlloc(db, 2, 0);
|
||||
rc = sqlite3BtreeCursor(db->aDb[0].pBt, pairsIdx->tnum, wrFlag, infPairs, &ctxt->crsPairs);
|
||||
if (rc != SQLITE_OK) {
|
||||
sg_raise_sqlite(db, err);
|
||||
return rc;
|
||||
}
|
||||
ctxt->n_cursors++;
|
||||
|
||||
memset(&ctxt->crsIdents, 0, sizeof(ctxt->crsIdents));
|
||||
KeyInfo *infIdents = sqlite3KeyInfoAlloc(db, 1, 1);
|
||||
rc = sqlite3BtreeCursor(db->aDb[0].pBt, identsIdx->tnum, wrFlag, infIdents, &ctxt->crsIdents);
|
||||
@@ -187,14 +182,25 @@ open_exprs(sqlite3 *db, int wrFlag, ExprContext* ctxt, GuExn* err)
|
||||
}
|
||||
ctxt->n_cursors++;
|
||||
|
||||
memset(&ctxt->crsLiterals, 0, sizeof(ctxt->crsLiterals));
|
||||
KeyInfo *infLiterals = sqlite3KeyInfoAlloc(db, 1, 1);
|
||||
rc = sqlite3BtreeCursor(db->aDb[0].pBt, literalsIdx->tnum, wrFlag, infLiterals, &ctxt->crsLiterals);
|
||||
if (rc != SQLITE_OK) {
|
||||
sg_raise_sqlite(db, err);
|
||||
return rc;
|
||||
if (!identsOnly) {
|
||||
memset(&ctxt->crsLiterals, 0, sizeof(ctxt->crsLiterals));
|
||||
KeyInfo *infLiterals = sqlite3KeyInfoAlloc(db, 1, 1);
|
||||
rc = sqlite3BtreeCursor(db->aDb[0].pBt, literalsIdx->tnum, wrFlag, infLiterals, &ctxt->crsLiterals);
|
||||
if (rc != SQLITE_OK) {
|
||||
sg_raise_sqlite(db, err);
|
||||
return rc;
|
||||
}
|
||||
ctxt->n_cursors++;
|
||||
|
||||
memset(&ctxt->crsPairs, 0, sizeof(ctxt->crsPairs));
|
||||
KeyInfo *infPairs = sqlite3KeyInfoAlloc(db, 2, 0);
|
||||
rc = sqlite3BtreeCursor(db->aDb[0].pBt, pairsIdx->tnum, wrFlag, infPairs, &ctxt->crsPairs);
|
||||
if (rc != SQLITE_OK) {
|
||||
sg_raise_sqlite(db, err);
|
||||
return rc;
|
||||
}
|
||||
ctxt->n_cursors++;
|
||||
}
|
||||
ctxt->n_cursors++;
|
||||
|
||||
if (wrFlag) {
|
||||
int res;
|
||||
@@ -220,20 +226,20 @@ static void
|
||||
close_exprs(ExprContext* ctxt)
|
||||
{
|
||||
if (ctxt->n_cursors >= 4) {
|
||||
sqlite3KeyInfoUnref(ctxt->crsPairs.pKeyInfo);
|
||||
sqlite3BtreeCloseCursor(&ctxt->crsPairs);
|
||||
}
|
||||
|
||||
if (ctxt->n_cursors >= 3) {
|
||||
sqlite3KeyInfoUnref(ctxt->crsLiterals.pKeyInfo);
|
||||
sqlite3BtreeCloseCursor(&ctxt->crsLiterals);
|
||||
}
|
||||
|
||||
if (ctxt->n_cursors >= 3) {
|
||||
if (ctxt->n_cursors >= 2) {
|
||||
sqlite3KeyInfoUnref(ctxt->crsIdents.pKeyInfo);
|
||||
sqlite3BtreeCloseCursor(&ctxt->crsIdents);
|
||||
}
|
||||
|
||||
if (ctxt->n_cursors >= 2) {
|
||||
sqlite3KeyInfoUnref(ctxt->crsPairs.pKeyInfo);
|
||||
sqlite3BtreeCloseCursor(&ctxt->crsPairs);
|
||||
}
|
||||
|
||||
if (ctxt->n_cursors >= 1) {
|
||||
sqlite3BtreeCloseCursor(&ctxt->crsExprs);
|
||||
}
|
||||
@@ -241,6 +247,83 @@ close_exprs(ExprContext* ctxt)
|
||||
ctxt->n_cursors = 0;
|
||||
}
|
||||
|
||||
static int
|
||||
find_function_rowid(sqlite3* db, ExprContext* ctxt,
|
||||
GuString fun, SgId* pKey, int wrFlag)
|
||||
{
|
||||
int rc = SQLITE_OK;
|
||||
int file_format = db->aDb[0].pSchema->file_format;
|
||||
|
||||
Mem mem[2];
|
||||
mem[0].flags = MEM_Str;
|
||||
mem[0].n = strlen(fun);
|
||||
mem[0].z = (void*) fun;
|
||||
|
||||
UnpackedRecord idxKey;
|
||||
idxKey.pKeyInfo = ctxt->crsIdents.pKeyInfo;
|
||||
idxKey.nField = 1;
|
||||
idxKey.default_rc = 0;
|
||||
idxKey.aMem = mem;
|
||||
|
||||
int res = 0;
|
||||
rc = sqlite3BtreeMovetoUnpacked(&ctxt->crsIdents,
|
||||
&idxKey, 0, 0, &res);
|
||||
if (rc != SQLITE_OK) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (res == 0) {
|
||||
rc = sqlite3VdbeIdxRowid(db, &ctxt->crsIdents, pKey);
|
||||
} else {
|
||||
if (wrFlag == 0) {
|
||||
*pKey = 0;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
*pKey = ++ctxt->key_seed;
|
||||
|
||||
int serial_type_fun = sqlite3VdbeSerialType(&mem[0], file_format);
|
||||
int serial_type_fun_hdr_len = sqlite3VarintLen(serial_type_fun);
|
||||
|
||||
mem[1].flags = MEM_Int;
|
||||
mem[1].u.i = *pKey;
|
||||
|
||||
int serial_type_key = sqlite3VdbeSerialType(&mem[1], file_format);
|
||||
int serial_type_key_hdr_len = sqlite3VarintLen(serial_type_key);
|
||||
|
||||
unsigned char* buf = malloc(1+serial_type_fun_hdr_len+MAX(1,serial_type_key_hdr_len)+mem[0].n+8);
|
||||
unsigned char* p = buf;
|
||||
*p++ = 1+serial_type_fun_hdr_len+1;
|
||||
p += putVarint32(p, serial_type_fun);
|
||||
*p++ = 0;
|
||||
memcpy(p, fun, mem[0].n);
|
||||
p += mem[0].n;
|
||||
|
||||
rc = sqlite3BtreeInsert(&ctxt->crsExprs, 0, *pKey,
|
||||
buf, p-buf, 0,
|
||||
0, 0);
|
||||
if (rc != SQLITE_OK) {
|
||||
goto free;
|
||||
}
|
||||
|
||||
p = buf;
|
||||
*p++ = 1+serial_type_fun_hdr_len+serial_type_key_hdr_len;
|
||||
p += putVarint32(p, serial_type_fun);
|
||||
p += putVarint32(p, serial_type_key);
|
||||
memcpy(p, fun, mem[0].n);
|
||||
p += mem[0].n;
|
||||
p += sqlite3VdbeSerialPut(p, &mem[1], serial_type_key);
|
||||
rc = sqlite3BtreeInsert(&ctxt->crsIdents, buf, p-buf,
|
||||
0, *pKey, 0,
|
||||
0, 0);
|
||||
|
||||
free:
|
||||
free(buf);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
store_expr(sqlite3* db,
|
||||
ExprContext* ctxt, PgfExpr expr, SgId* pKey, int wrFlag)
|
||||
@@ -439,73 +522,7 @@ store_expr(sqlite3* db,
|
||||
}
|
||||
case PGF_EXPR_FUN: {
|
||||
PgfExprFun* fun = ei.data;
|
||||
|
||||
Mem mem[2];
|
||||
mem[0].flags = MEM_Str;
|
||||
mem[0].n = strlen(fun->fun);
|
||||
mem[0].z = fun->fun;
|
||||
|
||||
UnpackedRecord idxKey;
|
||||
idxKey.pKeyInfo = ctxt->crsIdents.pKeyInfo;
|
||||
idxKey.nField = 1;
|
||||
idxKey.default_rc = 0;
|
||||
idxKey.aMem = mem;
|
||||
|
||||
int res = 0;
|
||||
rc = sqlite3BtreeMovetoUnpacked(&ctxt->crsIdents,
|
||||
&idxKey, 0, 0, &res);
|
||||
if (rc != SQLITE_OK) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (res == 0) {
|
||||
rc = sqlite3VdbeIdxRowid(db, &ctxt->crsIdents, pKey);
|
||||
} else {
|
||||
if (wrFlag == 0) {
|
||||
*pKey = 0;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
*pKey = ++ctxt->key_seed;
|
||||
|
||||
int serial_type_fun = sqlite3VdbeSerialType(&mem[0], file_format);
|
||||
int serial_type_fun_hdr_len = sqlite3VarintLen(serial_type_fun);
|
||||
|
||||
mem[1].flags = MEM_Int;
|
||||
mem[1].u.i = *pKey;
|
||||
|
||||
int serial_type_key = sqlite3VdbeSerialType(&mem[1], file_format);
|
||||
int serial_type_key_hdr_len = sqlite3VarintLen(serial_type_key);
|
||||
|
||||
unsigned char* buf = malloc(1+serial_type_fun_hdr_len+MAX(1,serial_type_key_hdr_len)+mem[0].n+8);
|
||||
unsigned char* p = buf;
|
||||
*p++ = 1+serial_type_fun_hdr_len+1;
|
||||
p += putVarint32(p, serial_type_fun);
|
||||
*p++ = 0;
|
||||
memcpy(p, fun->fun, mem[0].n);
|
||||
p += mem[0].n;
|
||||
|
||||
rc = sqlite3BtreeInsert(&ctxt->crsExprs, 0, *pKey,
|
||||
buf, p-buf, 0,
|
||||
0, 0);
|
||||
if (rc != SQLITE_OK) {
|
||||
goto free;
|
||||
}
|
||||
|
||||
p = buf;
|
||||
*p++ = 1+serial_type_fun_hdr_len+serial_type_key_hdr_len;
|
||||
p += putVarint32(p, serial_type_fun);
|
||||
p += putVarint32(p, serial_type_key);
|
||||
memcpy(p, fun->fun, mem[0].n);
|
||||
p += mem[0].n;
|
||||
p += sqlite3VdbeSerialPut(p, &mem[1], serial_type_key);
|
||||
rc = sqlite3BtreeInsert(&ctxt->crsIdents, buf, p-buf,
|
||||
0, *pKey, 0,
|
||||
0, 0);
|
||||
|
||||
free:
|
||||
free(buf);
|
||||
}
|
||||
rc = find_function_rowid(db, ctxt, fun->fun, pKey, wrFlag);
|
||||
break;
|
||||
}
|
||||
case PGF_EXPR_VAR: {
|
||||
@@ -545,7 +562,7 @@ sg_insert_expr(SgSG *sg, PgfExpr expr, GuExn* err)
|
||||
}
|
||||
|
||||
ExprContext ctxt;
|
||||
rc = open_exprs(db, 1, &ctxt, err);
|
||||
rc = open_exprs(db, 1, false, &ctxt, err);
|
||||
if (rc != SQLITE_OK)
|
||||
goto close;
|
||||
|
||||
@@ -726,6 +743,255 @@ rollback:
|
||||
return gu_null_variant;
|
||||
}
|
||||
|
||||
static int
|
||||
insert_token(sqlite3 *db, BtCursor* crsTokens, GuString tok, SgId key)
|
||||
{
|
||||
int rc = SQLITE_OK;
|
||||
int file_format = db->aDb[0].pSchema->file_format;
|
||||
|
||||
Mem mem[2];
|
||||
mem[0].flags = MEM_Str;
|
||||
mem[0].n = strlen(tok);
|
||||
mem[0].z = (void*) tok;
|
||||
|
||||
int serial_type_tok = sqlite3VdbeSerialType(&mem[0], file_format);
|
||||
int serial_type_tok_hdr_len = sqlite3VarintLen(serial_type_tok);
|
||||
|
||||
mem[1].flags = MEM_Int;
|
||||
mem[1].u.i = key;
|
||||
|
||||
int serial_type_key = sqlite3VdbeSerialType(&mem[1], file_format);
|
||||
int serial_type_key_hdr_len = sqlite3VarintLen(serial_type_key);
|
||||
|
||||
unsigned char* buf = malloc(1+serial_type_tok_hdr_len+serial_type_key_hdr_len+mem[0].n+8);
|
||||
unsigned char* p = buf;
|
||||
*p++ = 1+serial_type_tok_hdr_len+serial_type_key_hdr_len;
|
||||
p += putVarint32(p, serial_type_tok);
|
||||
p += putVarint32(p, serial_type_key);
|
||||
memcpy(p, tok, mem[0].n);
|
||||
p += mem[0].n;
|
||||
p += sqlite3VdbeSerialPut(p, &mem[1], serial_type_key);
|
||||
rc = sqlite3BtreeInsert(crsTokens, buf, p-buf,
|
||||
0, key, 0,
|
||||
0, 0);
|
||||
free(buf);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
insert_syms(sqlite3 *db, BtCursor* crsTokens, PgfSymbols* syms, SgId key)
|
||||
{
|
||||
int rc;
|
||||
size_t n_syms = gu_seq_length(syms);
|
||||
for (size_t sym_idx = 0; sym_idx < n_syms; sym_idx++) {
|
||||
PgfSymbol sym = gu_seq_get(syms, PgfSymbol, sym_idx);
|
||||
GuVariantInfo sym_i = gu_variant_open(sym);
|
||||
switch (sym_i.tag) {
|
||||
case PGF_SYMBOL_KS: {
|
||||
PgfSymbolKS* ks = sym_i.data;
|
||||
rc = insert_token(db, crsTokens, ks->token, key);
|
||||
if (rc != SQLITE_OK)
|
||||
return rc;
|
||||
break;
|
||||
}
|
||||
case PGF_SYMBOL_KP: {
|
||||
PgfSymbolKP* kp = sym_i.data;
|
||||
rc = insert_syms(db, crsTokens, kp->default_form, key);
|
||||
if (rc != SQLITE_OK)
|
||||
return rc;
|
||||
|
||||
for (size_t i = 0; i < kp->n_forms; i++) {
|
||||
rc = insert_syms(db, crsTokens, kp->forms[i].form, key);
|
||||
if (rc != SQLITE_OK)
|
||||
return rc;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
void
|
||||
sg_update_fts_index(SgSG* sg, PgfPGF* pgf, GuExn* err)
|
||||
{
|
||||
int rc = SQLITE_OK;
|
||||
sqlite3 *db = (sqlite3 *) sg;
|
||||
|
||||
if (db->autoCommit) {
|
||||
rc = sqlite3BtreeBeginTrans(db->aDb[0].pBt, 1);
|
||||
if (rc != SQLITE_OK) {
|
||||
sg_raise_sqlite(db, err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ExprContext ctxt;
|
||||
rc = open_exprs(db, 1, true, &ctxt, err);
|
||||
if (rc != SQLITE_OK) {
|
||||
sg_raise_sqlite(db, err);
|
||||
goto close;
|
||||
}
|
||||
|
||||
Index *tokensIdx = sqlite3HashFind(&db->aDb[0].pSchema->idxHash, SG_TOKENS);
|
||||
if (!tokensIdx) {
|
||||
sg_raise_err("Index " SG_TOKENS " is missing", err);
|
||||
return;
|
||||
}
|
||||
|
||||
rc = sqlite3BtreeClearTable(db->aDb[0].pBt, tokensIdx->tnum, NULL);
|
||||
if (rc != SQLITE_OK) {
|
||||
sg_raise_sqlite(db, err);
|
||||
return;
|
||||
}
|
||||
|
||||
BtCursor crsTokens;
|
||||
memset(&crsTokens, 0, sizeof(crsTokens));
|
||||
KeyInfo *infTokens = sqlite3KeyInfoAlloc(db, 1, 1);
|
||||
rc = sqlite3BtreeCursor(db->aDb[0].pBt, tokensIdx->tnum, 1, infTokens, &crsTokens);
|
||||
if (rc != SQLITE_OK) {
|
||||
sg_raise_sqlite(db, err);
|
||||
}
|
||||
ctxt.n_cursors++;
|
||||
|
||||
size_t n_concrs = gu_seq_length(pgf->concretes);
|
||||
for (size_t i = 0; i < n_concrs; i++) {
|
||||
PgfConcr* concr = gu_seq_index(pgf->concretes, PgfConcr, i);
|
||||
|
||||
size_t n_funs = gu_seq_length(concr->cncfuns);
|
||||
for (size_t funid = 0; funid < n_funs; funid++) {
|
||||
PgfCncFun* cncfun = gu_seq_get(concr->cncfuns, PgfCncFun*, funid);
|
||||
|
||||
SgId key = 0;
|
||||
rc = find_function_rowid(db, &ctxt, cncfun->absfun->name, &key, 1);
|
||||
if (rc != SQLITE_OK) {
|
||||
sg_raise_sqlite(db, err);
|
||||
goto close;
|
||||
}
|
||||
|
||||
for (size_t lin_idx = 0; lin_idx < cncfun->n_lins; lin_idx++) {
|
||||
PgfSequence* seq = cncfun->lins[lin_idx];
|
||||
rc = insert_syms(db, &crsTokens, seq->syms, key);
|
||||
if (rc != SQLITE_OK) {
|
||||
sg_raise_sqlite(db, err);
|
||||
goto close;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ctxt.n_cursors >= 3) {
|
||||
sqlite3KeyInfoUnref(crsTokens.pKeyInfo);
|
||||
sqlite3BtreeCloseCursor(&crsTokens);
|
||||
ctxt.n_cursors--;
|
||||
}
|
||||
|
||||
close_exprs(&ctxt);
|
||||
|
||||
if (db->autoCommit) {
|
||||
rc = sqlite3BtreeCommit(db->aDb[0].pBt);
|
||||
if (rc != SQLITE_OK) {
|
||||
sg_raise_sqlite(db, err);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
close:
|
||||
if (ctxt.n_cursors >= 3) {
|
||||
sqlite3KeyInfoUnref(crsTokens.pKeyInfo);
|
||||
sqlite3BtreeCloseCursor(&crsTokens);
|
||||
ctxt.n_cursors--;
|
||||
}
|
||||
|
||||
close_exprs(&ctxt);
|
||||
|
||||
if (db->autoCommit) {
|
||||
sqlite3BtreeRollback(db->aDb[0].pBt, SQLITE_ABORT_ROLLBACK, 0);
|
||||
}
|
||||
}
|
||||
|
||||
GuSeq*
|
||||
sg_query_linearization(SgSG *sg, GuString tok, GuPool *pool, GuExn* err)
|
||||
{
|
||||
int rc;
|
||||
sqlite3 *db = (sqlite3 *) sg;
|
||||
|
||||
Index *tokensIdx = sqlite3HashFind(&db->aDb[0].pSchema->idxHash, SG_TOKENS);
|
||||
if (!tokensIdx) {
|
||||
sg_raise_err("Index " SG_TOKENS " is missing", err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BtCursor crsTokens;
|
||||
memset(&crsTokens, 0, sizeof(crsTokens));
|
||||
KeyInfo *infTokens = sqlite3KeyInfoAlloc(db, 1, 1);
|
||||
rc = sqlite3BtreeCursor(db->aDb[0].pBt, tokensIdx->tnum, 1, infTokens, &crsTokens);
|
||||
if (rc != SQLITE_OK) {
|
||||
sg_raise_sqlite(db, err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Mem mem[1];
|
||||
mem[0].flags = MEM_Str;
|
||||
mem[0].n = strlen(tok);
|
||||
mem[0].z = (void*) tok;
|
||||
|
||||
UnpackedRecord idxKey;
|
||||
idxKey.pKeyInfo = crsTokens.pKeyInfo;
|
||||
idxKey.nField = 1;
|
||||
idxKey.default_rc = 0;
|
||||
idxKey.aMem = mem;
|
||||
|
||||
int res = 0;
|
||||
rc = sqlite3BtreeMovetoUnpacked(&crsTokens,
|
||||
&idxKey, 0, 0, &res);
|
||||
if (rc != SQLITE_OK) {
|
||||
sg_raise_sqlite(db, err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GuBuf* ids = gu_new_buf(SgId, pool);
|
||||
|
||||
while (res == 0) {
|
||||
SgId key;
|
||||
rc = sqlite3VdbeIdxRowid(db, &crsTokens, &key);
|
||||
if (rc != SQLITE_OK) {
|
||||
sg_raise_sqlite(db, err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gu_buf_push(ids, SgId, key);
|
||||
|
||||
sqlite3BtreeNext(&crsTokens, &res);
|
||||
if (rc != SQLITE_OK) {
|
||||
sg_raise_sqlite(db, err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
i64 szData;
|
||||
const unsigned char *zData;
|
||||
rc = sqlite3BtreeKeySize(&crsTokens, &szData);
|
||||
if (rc != SQLITE_OK) {
|
||||
sg_raise_sqlite(db, err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
u32 available = 0;
|
||||
zData = sqlite3BtreeKeyFetch(&crsTokens, &available);
|
||||
if (szData > available)
|
||||
gu_impossible();
|
||||
|
||||
res = sqlite3VdbeRecordCompare(available, zData, &idxKey);
|
||||
if (res != 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return gu_buf_data_seq(ids);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
int n_cursors;
|
||||
BtCursor cursor[4];
|
||||
@@ -820,7 +1086,7 @@ sg_insert_triple(SgSG *sg, SgTriple triple, GuExn* err)
|
||||
Mem mem[4];
|
||||
|
||||
ExprContext ectxt;
|
||||
rc = open_exprs(db, 1, &ectxt, err);
|
||||
rc = open_exprs(db, 1, false, &ectxt, err);
|
||||
if (rc != SQLITE_OK)
|
||||
goto close;
|
||||
|
||||
@@ -1151,7 +1417,7 @@ sg_query_triple(SgSG *sg, SgTriple triple, GuExn* err)
|
||||
if (rc != SQLITE_OK)
|
||||
goto close;
|
||||
|
||||
rc = open_exprs(db, 0, &tres->ectxt, err);
|
||||
rc = open_exprs(db, 0, false, &tres->ectxt, err);
|
||||
if (rc != SQLITE_OK)
|
||||
goto close;
|
||||
|
||||
|
||||
@@ -30,6 +30,12 @@ sg_insert_expr(SgSG *sg, PgfExpr expr, GuExn* err);
|
||||
PgfExpr
|
||||
sg_get_expr(SgSG *sg, SgId key, GuPool* out_pool, GuExn* err);
|
||||
|
||||
void
|
||||
sg_update_fts_index(SgSG* sg, PgfPGF* pgf, GuExn* err);
|
||||
|
||||
GuSeq*
|
||||
sg_query_linearization(SgSG *sg, GuString tok, GuPool* pool, GuExn* err);
|
||||
|
||||
|
||||
typedef PgfExpr SgTriple[3];
|
||||
|
||||
|
||||
@@ -59,8 +59,6 @@ import Data.Function(on)
|
||||
-- the foreign pointer in case if the application still has a reference
|
||||
-- to Concr but has lost its reference to PGF.
|
||||
|
||||
data PGF = PGF {pgf :: Ptr PgfPGF, pgfMaster :: ForeignPtr GuPool}
|
||||
data Concr = Concr {concr :: Ptr PgfConcr, concrMaster :: PGF}
|
||||
|
||||
type AbsName = String -- ^ Name of abstract syntax
|
||||
type ConcName = String -- ^ Name of concrete syntax
|
||||
|
||||
@@ -9,6 +9,9 @@ import Foreign.ForeignPtr
|
||||
import Control.Exception
|
||||
import GHC.Ptr
|
||||
|
||||
data PGF = PGF {pgf :: Ptr PgfPGF, pgfMaster :: ForeignPtr GuPool}
|
||||
data Concr = Concr {concr :: Ptr PgfConcr, concrMaster :: PGF}
|
||||
|
||||
------------------------------------------------------------------
|
||||
-- libgu API
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@ module SG( SG, openSG, closeSG
|
||||
, beginTrans, commit, rollback, inTransaction
|
||||
, SgId
|
||||
, insertExpr, getExpr
|
||||
, updateFtsIndex
|
||||
, queryLinearization
|
||||
, readTriple, showTriple
|
||||
, insertTriple, getTriple
|
||||
, queryTriple
|
||||
@@ -106,6 +108,36 @@ getExpr (SG sg) id = do
|
||||
return Nothing
|
||||
else do return $ Just (Expr c_expr exprFPl)
|
||||
|
||||
updateFtsIndex :: SG -> PGF -> IO ()
|
||||
updateFtsIndex (SG sg) p = do
|
||||
withGuPool $ \tmpPl -> do
|
||||
exn <- gu_new_exn tmpPl
|
||||
sg_update_fts_index sg (pgf p) exn
|
||||
handle_sg_exn exn
|
||||
|
||||
queryLinearization :: SG -> String -> IO [Expr]
|
||||
queryLinearization (SG sg) query = do
|
||||
exprPl <- gu_new_pool
|
||||
exprFPl <- newForeignPtr gu_pool_finalizer exprPl
|
||||
(withCString query $ \c_query ->
|
||||
withGuPool $ \tmpPl -> do
|
||||
exn <- gu_new_exn tmpPl
|
||||
seq <- sg_query_linearization sg c_query tmpPl exn
|
||||
handle_sg_exn exn
|
||||
len <- (#peek GuSeq, len) seq
|
||||
ids <- peekArray (fromIntegral (len :: CInt)) (seq `plusPtr` (#offset GuSeq, data))
|
||||
getExprs exprFPl exprPl exn ids)
|
||||
where
|
||||
getExprs exprFPl exprPl exn [] = return []
|
||||
getExprs exprFPl exprPl exn (id:ids) = do
|
||||
c_expr <- sg_get_expr sg id exprPl exn
|
||||
handle_sg_exn exn
|
||||
if c_expr == nullPtr
|
||||
then getExprs exprFPl exprPl exn ids
|
||||
else do let e = Expr c_expr exprFPl
|
||||
es <- getExprs exprFPl exprPl exn ids
|
||||
return (e:es)
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
-- Triples
|
||||
|
||||
|
||||
@@ -32,6 +32,12 @@ foreign import ccall "sg/sg.h sg_insert_expr"
|
||||
foreign import ccall "sg/sg.h sg_get_expr"
|
||||
sg_get_expr :: Ptr SgSG -> SgId -> Ptr GuPool -> Ptr GuExn -> IO PgfExpr
|
||||
|
||||
foreign import ccall "sg/sg.h sg_update_fts_index"
|
||||
sg_update_fts_index :: Ptr SgSG -> Ptr PgfPGF -> Ptr GuExn -> IO ()
|
||||
|
||||
foreign import ccall "sg/sg.h sg_query_linearization"
|
||||
sg_query_linearization :: Ptr SgSG -> CString -> Ptr GuPool -> Ptr GuExn -> IO (Ptr GuSeq)
|
||||
|
||||
foreign import ccall "sg/sg.h sg_insert_triple"
|
||||
sg_insert_triple :: Ptr SgSG -> SgTriple -> Ptr GuExn -> IO SgId
|
||||
|
||||
|
||||
Reference in new issue
Block a user