1
0
forked from GitHub/gf-core

add the initial sketches of the semantic graph storage

This commit is contained in:
krasimir
2015-08-20 13:31:43 +00:00
parent 2ff7e829dc
commit 2f9704a624

View File

@@ -0,0 +1,423 @@
#include "sqlite3.c"
#include "pgf/pgf.h"
#include "gu/file.h"
#define SG_EXPRS "sg_exprs"
#define SG_PAIRS "sg_pairs"
#define SG_IDENTS "sg_idents"
#define SG_RELS "sg_rels"
#define SG_TRIPLES "sg_triples"
typedef struct {
sqlite3 *db;
BtCursor* crsExprs;
BtCursor* crsPairs;
BtCursor* crsIdents;
i64 key_seed;
int file_format;
} StoreContext;
int
sg_create_tables(sqlite3 *db)
{
return 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 unique index if not exists " SG_PAIRS " on " SG_EXPRS "(fun,arg) where arg is not null;"
"create table if not exists " SG_RELS "(rel varchar);"
"create table if not exists " SG_TRIPLES "(subj integer, rel integer, obj integer);",
NULL, NULL, NULL);
}
static int
store_expr(StoreContext* ctxt, PgfExpr expr, i64* pKey)
{
int rc = SQLITE_OK;
GuVariantInfo ei = gu_variant_open(expr);
switch (ei.tag) {
case PGF_EXPR_ABS: {
break;
}
case PGF_EXPR_APP: {
PgfExprApp* app = ei.data;
Mem mem[3];
mem[0].flags = MEM_Int;
rc = store_expr(ctxt, app->fun, &mem[0].u.i);
if (rc != SQLITE_OK)
return rc;
mem[1].flags = MEM_Int;
rc = store_expr(ctxt, app->arg, &mem[1].u.i);
if (rc != SQLITE_OK)
return rc;
UnpackedRecord idxKey;
idxKey.pKeyInfo = ctxt->crsPairs->pKeyInfo;
idxKey.nField = 2;
idxKey.default_rc = 0;
idxKey.aMem = mem;
int res = 0;
rc = sqlite3BtreeMovetoUnpacked(ctxt->crsPairs,
&idxKey, 0, 0, &res);
if (rc != SQLITE_OK) {
return rc;
}
if (res == 0) {
rc = sqlite3VdbeIdxRowid(ctxt->db, ctxt->crsPairs, pKey);
} else {
*pKey = ++ctxt->key_seed;
unsigned char buf[32]; // enough for record with three integers
buf[1] = 3;
u32 serial_type;
unsigned char* p = buf+4;
serial_type = sqlite3VdbeSerialType(&mem[0], ctxt->file_format);
buf[2] = serial_type;
p += sqlite3VdbeSerialPut(p, &mem[0], serial_type);
serial_type = sqlite3VdbeSerialType(&mem[1], ctxt->file_format);
buf[3] = serial_type;
p += sqlite3VdbeSerialPut(p, &mem[1], serial_type);
rc = sqlite3BtreeInsert(ctxt->crsExprs, 0, *pKey,
buf+1, p-(buf+1), 0,
0, 0);
if (rc != SQLITE_OK) {
return rc;
}
buf[0] = 4;
buf[1] = buf[2];
buf[2] = buf[3];
mem[2].flags = MEM_Int;
mem[2].u.i = *pKey;
serial_type = sqlite3VdbeSerialType(&mem[2], ctxt->file_format);
buf[3] = serial_type;
p += sqlite3VdbeSerialPut(p, &mem[2], serial_type);
rc = sqlite3BtreeInsert(ctxt->crsPairs, buf, p-buf,
0, *pKey, 0,
0, 0);
}
break;
}
case PGF_EXPR_LIT: {
break;
}
case PGF_EXPR_META: {
}
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(ctxt->db, ctxt->crsIdents, pKey);
} else {
*pKey = ++ctxt->key_seed;
int serial_type_fun = sqlite3VdbeSerialType(&mem[0], ctxt->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], ctxt->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);
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);
}
break;
}
case PGF_EXPR_VAR: {
break;
}
case PGF_EXPR_TYPED: {
break;
}
case PGF_EXPR_IMPL_ARG: {
break;
}
default:
gu_impossible();
}
return rc;
}
int
sg_insert_expr(sqlite3 *db, PgfExpr expr, i64* pKey)
{
Table *exprsTbl =
sqlite3HashFind(&db->aDb[0].pSchema->tblHash, SG_EXPRS);
if (!exprsTbl) return SQLITE_ERROR;
Index *pairsIdx = sqlite3HashFind(&db->aDb[0].pSchema->idxHash, SG_PAIRS);
if (!pairsIdx) return SQLITE_ERROR;
Index *identsIdx = sqlite3HashFind(&db->aDb[0].pSchema->idxHash, SG_IDENTS);
if (!identsIdx) return SQLITE_ERROR;
int rc;
rc = sqlite3BtreeBeginTrans(db->aDb[0].pBt, 1);
if (rc != SQLITE_OK) {
return rc;
}
BtCursor crsExprs;
memset(&crsExprs, 0, sizeof(crsExprs));
rc = sqlite3BtreeCursor(db->aDb[0].pBt, exprsTbl->tnum, 1, NULL, &crsExprs);
if (rc != SQLITE_OK) {
goto rollback;
}
BtCursor crsPairs;
memset(&crsPairs, 0, sizeof(crsPairs));
KeyInfo *infPairs = sqlite3KeyInfoAlloc(db, 2, 0);
rc = sqlite3BtreeCursor(db->aDb[0].pBt, pairsIdx->tnum, 1, infPairs, &crsPairs);
if (rc != SQLITE_OK) {
goto close1;
}
BtCursor crsIdents;
memset(&crsIdents, 0, sizeof(crsIdents));
KeyInfo *infIdents = sqlite3KeyInfoAlloc(db, 1, 1);
rc = sqlite3BtreeCursor(db->aDb[0].pBt, identsIdx->tnum, 1, infIdents, &crsIdents);
if (rc != SQLITE_OK) {
goto close2;
}
int res;
rc = sqlite3BtreeLast(&crsExprs, &res);
if (rc != SQLITE_OK) {
goto close;
}
i64 key = 0;
rc = sqlite3BtreeKeySize(&crsExprs, &key);
if (rc != SQLITE_OK) {
goto close;
}
StoreContext ctxt;
ctxt.db = db;
ctxt.crsExprs = &crsExprs;
ctxt.crsPairs = &crsPairs;
ctxt.crsIdents = &crsIdents;
ctxt.key_seed = key;
ctxt.file_format = db->aDb[0].pSchema->file_format;
rc = store_expr(&ctxt, expr, pKey);
if (rc != SQLITE_OK) {
goto close;
}
sqlite3KeyInfoUnref(infIdents);
rc = sqlite3BtreeCloseCursor(&crsIdents);
if (rc != SQLITE_OK) {
goto close2;
}
sqlite3KeyInfoUnref(infPairs);
rc = sqlite3BtreeCloseCursor(&crsPairs);
if (rc != SQLITE_OK) {
goto close1;
}
rc = sqlite3BtreeCloseCursor(&crsExprs);
if (rc != SQLITE_OK) {
goto rollback;
}
rc = sqlite3BtreeCommit(db->aDb[0].pBt);
return rc;
close:
sqlite3KeyInfoUnref(infIdents);
sqlite3BtreeCloseCursor(&crsIdents);
close2:
sqlite3KeyInfoUnref(infPairs);
sqlite3BtreeCloseCursor(&crsPairs);
close1:
sqlite3BtreeCloseCursor(&crsExprs);
rollback:
sqlite3BtreeRollback(db->aDb[0].pBt, SQLITE_ABORT_ROLLBACK, 0);
return rc;
}
static int
load_expr(BtCursor* crsExprs, i64 key, PgfExpr *pExpr, GuPool* out_pool)
{
int res;
int rc = sqlite3BtreeMovetoUnpacked(crsExprs, 0, key, 0, &res);
if (rc != SQLITE_OK)
return rc;
if (res != 0) {
*pExpr = gu_null_variant;
return SQLITE_OK;
}
int payloadSize;
rc = sqlite3BtreeDataSize(crsExprs, &payloadSize);
if (rc != SQLITE_OK)
return rc;
u32 avail = 0;
const unsigned char* row = sqlite3BtreeDataFetch(crsExprs, &avail);
row++;
int serial_type_fun, serial_type_arg;
row += getVarint32(row, serial_type_fun);
row += getVarint32(row, serial_type_arg);
Mem mem[2];
row += sqlite3VdbeSerialGet(row, serial_type_fun, &mem[0]);
row += sqlite3VdbeSerialGet(row, serial_type_arg, &mem[1]);
if (serial_type_arg == 0) {
u32 len = sqlite3VdbeSerialTypeLen(serial_type_fun);
PgfExprFun *efun =
gu_new_flex_variant(PGF_EXPR_FUN,
PgfExprFun,
fun, len+1,
pExpr, out_pool);
memcpy(efun->fun, mem[0].z, len);
efun->fun[len] = 0;
} else {
PgfExprApp* papp =
gu_new_variant(PGF_EXPR_APP, PgfExprApp, pExpr, out_pool);
rc = load_expr(crsExprs, mem[0].u.i, &papp->fun, out_pool);
if (rc != SQLITE_OK)
return rc;
rc = load_expr(crsExprs, mem[1].u.i, &papp->arg, out_pool);
if (rc != SQLITE_OK)
return rc;
}
return SQLITE_OK;
}
int
sg_select_expr(sqlite3 *db, i64 key, PgfExpr* pExpr, GuPool* out_pool)
{
Table *exprsTbl =
sqlite3HashFind(&db->aDb[0].pSchema->tblHash, SG_EXPRS);
if (!exprsTbl) return SQLITE_ERROR;
int rc;
rc = sqlite3BtreeBeginTrans(db->aDb[0].pBt, 0);
if (rc != SQLITE_OK) {
return rc;
}
BtCursor crsExprs;
memset(&crsExprs, 0, sizeof(crsExprs));
rc = sqlite3BtreeCursor(db->aDb[0].pBt, exprsTbl->tnum, 1, NULL, &crsExprs);
if (rc != SQLITE_OK) {
goto rollback;
}
rc = load_expr(&crsExprs, key, pExpr, out_pool);
if (rc != SQLITE_OK) {
goto close;
}
rc = sqlite3BtreeCloseCursor(&crsExprs);
if (rc != SQLITE_OK) {
goto rollback;
}
rc = sqlite3BtreeCommit(db->aDb[0].pBt);
return rc;
close:
sqlite3BtreeCloseCursor(&crsExprs);
rollback:
sqlite3BtreeRollback(db->aDb[0].pBt, SQLITE_ABORT_ROLLBACK, 0);
return rc;
}
void main()
{
sqlite3 *db = NULL;
sqlite3_open("test.db", &db);
sg_create_tables(db);
char* str = "f x (g y)";
GuPool* tmp_pool = gu_local_pool();
GuExn* err = gu_exn(tmp_pool);
GuIn* in = gu_data_in((uint8_t*) str, strlen(str), tmp_pool);
GuOut* out = gu_file_out(stdout, tmp_pool);
PgfExpr e = pgf_read_expr(in, tmp_pool, err);
i64 key;
sg_insert_expr(db, e, &key);
sg_select_expr(db, key, &e, tmp_pool);
pgf_print_expr(e, NULL, 0, out, err);
printf("\n");
gu_pool_free(tmp_pool);
sqlite3_close(db);
}