summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/runtime/c/sg/sg.c437
-rw-r--r--src/runtime/c/sg/sg.h16
2 files changed, 345 insertions, 108 deletions
diff --git a/src/runtime/c/sg/sg.c b/src/runtime/c/sg/sg.c
index 355033dba..f13026d68 100644
--- a/src/runtime/c/sg/sg.c
+++ b/src/runtime/c/sg/sg.c
@@ -547,14 +547,14 @@ store_expr(sqlite3* db,
}
SgId
-sg_insert_expr(SgSG *sg, PgfExpr expr, GuExn* err)
+sg_insert_expr(SgSG *sg, PgfExpr expr, int wrFlag, GuExn* err)
{
sqlite3 *db = (sqlite3 *) sg;
int rc;
if (db->autoCommit) {
- rc = sqlite3BtreeBeginTrans(db->aDb[0].pBt, 1);
+ rc = sqlite3BtreeBeginTrans(db->aDb[0].pBt, wrFlag);
if (rc != SQLITE_OK) {
sg_raise_sqlite(db, err);
return 0;
@@ -562,12 +562,12 @@ sg_insert_expr(SgSG *sg, PgfExpr expr, GuExn* err)
}
ExprContext ctxt;
- rc = open_exprs(db, 1, false, &ctxt, err);
+ rc = open_exprs(db, wrFlag, false, &ctxt, err);
if (rc != SQLITE_OK)
goto close;
SgId key;
- rc = store_expr(db, &ctxt, expr, &key, 1);
+ rc = store_expr(db, &ctxt, expr, &key, wrFlag);
if (rc != SQLITE_OK) {
sg_raise_sqlite(db, err);
goto close;
@@ -1378,11 +1378,7 @@ rollback:
return false;
}
-struct SgTripleResult {
- sqlite3 *db;
- SgTriple triple;
-
- ExprContext ectxt;
+typedef struct {
TripleContext tctxt;
BtCursor* cursor;
@@ -1390,8 +1386,66 @@ struct SgTripleResult {
int res;
Mem mem[3];
UnpackedRecord idxKey;
+} SgTripleResultInt;
+
+struct SgTripleResult {
+ sqlite3 *db;
+ SgTriple triple;
+ ExprContext ectxt;
+
+ SgTripleResultInt i;
};
+static int
+init_triple_result_int(sqlite3 *db, SgTripleResultInt* tresi, GuExn* err)
+{
+ int rc;
+
+ rc = open_triples(db, 0, &tresi->tctxt, err);
+ if (rc != SQLITE_OK)
+ return rc;
+
+ int i = 0;
+ while (i < 3) {
+ if (tresi->mem[i].flags != MEM_Null)
+ break;
+ i++;
+ }
+
+ tresi->cursor = &tresi->tctxt.cursor[i];
+ tresi->idxKey.pKeyInfo = tresi->cursor->pKeyInfo;
+ tresi->idxKey.nField = 0;
+ tresi->idxKey.aMem = &tresi->mem[i];
+ tresi->res = 0;
+
+ while (i+tresi->idxKey.nField < 3) {
+ tresi->idxKey.nField++;
+
+ if (tresi->mem[i+tresi->idxKey.nField].flags == MEM_Null)
+ break;
+ }
+
+ if (tresi->idxKey.nField > 0) {
+ tresi->idxKey.default_rc = 1;
+ rc = sqlite3BtreeMovetoUnpacked(tresi->cursor,
+ &tresi->idxKey, 0, 0, &tresi->res);
+ if (rc == SQLITE_OK) {
+ if (tresi->res < 0) {
+ rc = sqlite3BtreeNext(tresi->cursor, &tresi->res);
+ }
+ tresi->res = 0;
+ }
+ } else {
+ rc = sqlite3BtreeFirst(tresi->cursor, &tresi->res);
+ }
+
+ if (rc != SQLITE_OK) {
+ sg_raise_sqlite(db, err);
+ }
+
+ return rc;
+}
+
SgTripleResult*
sg_query_triple(SgSG *sg, SgTriple triple, GuExn* err)
{
@@ -1413,73 +1467,35 @@ sg_query_triple(SgSG *sg, SgTriple triple, GuExn* err)
tres->triple[1] = triple[1];
tres->triple[2] = triple[2];
- rc = open_triples(db, 0, &tres->tctxt, err);
- if (rc != SQLITE_OK)
- goto close;
-
rc = open_exprs(db, 0, false, &tres->ectxt, err);
if (rc != SQLITE_OK)
goto close;
for (int i = 0; i < 3; i++) {
if (gu_variant_is_null(triple[i]))
- tres->mem[i].flags = MEM_Null;
+ tres->i.mem[i].flags = MEM_Null;
else {
- tres->mem[i].flags = MEM_Int;
- rc = store_expr(db, &tres->ectxt, triple[i], &tres->mem[i].u.i, 0);
+ tres->i.mem[i].flags = MEM_Int;
+ rc = store_expr(db, &tres->ectxt, triple[i], &tres->i.mem[i].u.i, 0);
if (rc != SQLITE_OK)
goto close;
- if (tres->mem[i].u.i == 0) {
- tres->res = 1;
+ if (tres->i.mem[i].u.i == 0) {
+ tres->i.res = 1;
return tres;
}
}
}
- int i = 0;
- while (i < 3) {
- if (!gu_variant_is_null(triple[i]))
- break;
- i++;
- }
-
- tres->cursor = &tres->tctxt.cursor[i];
- tres->idxKey.pKeyInfo = tres->cursor->pKeyInfo;
- tres->idxKey.nField = 0;
- tres->idxKey.aMem = &tres->mem[i];
- tres->res = 0;
-
- while (i+tres->idxKey.nField < 3) {
- tres->idxKey.nField++;
-
- if (triple[i+tres->idxKey.nField] == 0)
- break;
- }
-
- if (tres->idxKey.nField > 0) {
- tres->idxKey.default_rc = 1;
- rc = sqlite3BtreeMovetoUnpacked(tres->cursor,
- &tres->idxKey, 0, 0, &tres->res);
- if (rc == SQLITE_OK) {
- if (tres->res < 0) {
- rc = sqlite3BtreeNext(tres->cursor, &tres->res);
- }
- tres->res = 0;
- }
- } else {
- rc = sqlite3BtreeFirst(tres->cursor, &tres->res);
- }
-
+ rc = init_triple_result_int(db, &tres->i, err);
if (rc != SQLITE_OK) {
- sg_raise_sqlite(db, err);
- goto close;
+ return NULL;
}
return tres;
close:
close_exprs(&tres->ectxt);
- close_triples(&tres->tctxt);
+ close_triples(&tres->i.tctxt);
if (db->autoCommit) {
sqlite3BtreeRollback(db->aDb[0].pBt, SQLITE_ABORT_ROLLBACK, 0);
@@ -1489,6 +1505,81 @@ close:
return NULL;
}
+static bool
+triple_result_fetch_int(sqlite3* db, SgTripleResultInt* tresi,
+ SgId* pKey, GuExn* err)
+{
+ while (tresi->res == 0) {
+ int rc;
+
+ if (tresi->idxKey.nField > 0) {
+ i64 szData;
+ const unsigned char *zData;
+ rc = sqlite3BtreeKeySize(tresi->cursor, &szData);
+ if (rc != SQLITE_OK) {
+ sg_raise_sqlite(db, err);
+ return false;
+ }
+
+ u32 available = 0;
+ zData = sqlite3BtreeKeyFetch(tresi->cursor, &available);
+ if (szData > available)
+ gu_impossible();
+
+ tresi->idxKey.default_rc = 0;
+ tresi->res = sqlite3VdbeRecordCompare(available, zData, &tresi->idxKey);
+ if (tresi->res != 0)
+ return false;
+
+ if (tresi->idxKey.aMem == &tresi->mem[0] &&
+ tresi->idxKey.nField == 1 &&
+ tresi->mem[2].flags != MEM_Null) {
+ int offset =
+ zData[0] +
+ sqlite3VdbeSerialTypeLen(zData[1]) +
+ sqlite3VdbeSerialTypeLen(zData[2]);
+ zData+offset;
+ Mem mem;
+ sqlite3VdbeSerialGet(zData+offset, zData[3], &mem);
+ if (mem.u.i != tresi->mem[2].u.i) {
+ sqlite3BtreeNext(tresi->cursor, &tresi->res);
+ if (rc != SQLITE_OK) {
+ sg_raise_sqlite(db, err);
+ return false;
+ }
+ continue;
+ }
+ }
+ }
+
+ if (tresi->idxKey.nField > 0) {
+ rc = sqlite3VdbeIdxRowid(db, tresi->cursor, pKey);
+ if (rc != SQLITE_OK) {
+ sg_raise_sqlite(db, err);
+ return false;
+ }
+
+ rc = sqlite3BtreeMovetoUnpacked(&tresi->tctxt.cursor[3], 0, *pKey, 0, &tresi->res);
+ } else {
+ rc = sqlite3BtreeKeySize(tresi->cursor, pKey);
+ }
+ if (rc != SQLITE_OK) {
+ sg_raise_sqlite(db, err);
+ return false;
+ }
+
+ sqlite3BtreeNext(tresi->cursor, &tresi->res);
+ if (rc != SQLITE_OK) {
+ sg_raise_sqlite(db, err);
+ return false;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
int
sg_triple_result_fetch(SgTripleResult* tres, SgId* pKey, SgTriple triple,
GuPool* out_pool, GuExn* err)
@@ -1497,31 +1588,31 @@ sg_triple_result_fetch(SgTripleResult* tres, SgId* pKey, SgTriple triple,
triple[1] = tres->triple[1];
triple[2] = tres->triple[2];
- while (tres->res == 0) {
+ while (tres->i.res == 0) {
int rc;
- if (tres->idxKey.nField > 0) {
+ if (tres->i.idxKey.nField > 0) {
i64 szData;
const unsigned char *zData;
- rc = sqlite3BtreeKeySize(tres->cursor, &szData);
+ rc = sqlite3BtreeKeySize(tres->i.cursor, &szData);
if (rc != SQLITE_OK) {
sg_raise_sqlite(tres->db, err);
return false;
}
u32 available = 0;
- zData = sqlite3BtreeKeyFetch(tres->cursor, &available);
+ zData = sqlite3BtreeKeyFetch(tres->i.cursor, &available);
if (szData > available)
gu_impossible();
- tres->idxKey.default_rc = 0;
- tres->res = sqlite3VdbeRecordCompare(available, zData, &tres->idxKey);
- if (tres->res != 0)
+ tres->i.idxKey.default_rc = 0;
+ tres->i.res = sqlite3VdbeRecordCompare(available, zData, &tres->i.idxKey);
+ if (tres->i.res != 0)
return false;
- if (tres->idxKey.aMem == &tres->mem[0] &&
- tres->idxKey.nField == 1 &&
- tres->mem[2].flags != MEM_Null) {
+ if (tres->i.idxKey.aMem == &tres->i.mem[0] &&
+ tres->i.idxKey.nField == 1 &&
+ tres->i.mem[2].flags != MEM_Null) {
int offset =
zData[0] +
sqlite3VdbeSerialTypeLen(zData[1]) +
@@ -1529,8 +1620,8 @@ sg_triple_result_fetch(SgTripleResult* tres, SgId* pKey, SgTriple triple,
zData+offset;
Mem mem;
sqlite3VdbeSerialGet(zData+offset, zData[3], &mem);
- if (mem.u.i != tres->mem[2].u.i) {
- sqlite3BtreeNext(tres->cursor, &tres->res);
+ if (mem.u.i != tres->i.mem[2].u.i) {
+ sqlite3BtreeNext(tres->i.cursor, &tres->i.res);
if (rc != SQLITE_OK) {
sg_raise_sqlite(tres->db, err);
return false;
@@ -1540,30 +1631,30 @@ sg_triple_result_fetch(SgTripleResult* tres, SgId* pKey, SgTriple triple,
}
}
- if (tres->idxKey.nField > 0) {
- rc = sqlite3VdbeIdxRowid(tres->db, tres->cursor, pKey);
+ if (tres->i.idxKey.nField > 0) {
+ rc = sqlite3VdbeIdxRowid(tres->db, tres->i.cursor, pKey);
if (rc != SQLITE_OK) {
sg_raise_sqlite(tres->db, err);
return false;
}
- rc = sqlite3BtreeMovetoUnpacked(&tres->tctxt.cursor[3], 0, *pKey, 0, &tres->res);
+ rc = sqlite3BtreeMovetoUnpacked(&tres->i.tctxt.cursor[3], 0, *pKey, 0, &tres->i.res);
} else {
- rc = sqlite3BtreeKeySize(tres->cursor, pKey);
+ rc = sqlite3BtreeKeySize(tres->i.cursor, pKey);
}
if (rc != SQLITE_OK) {
sg_raise_sqlite(tres->db, err);
return false;
}
- rc = load_triple(&tres->tctxt.cursor[3], &tres->ectxt.crsExprs,
+ rc = load_triple(&tres->i.tctxt.cursor[3], &tres->ectxt.crsExprs,
triple, out_pool);
if (rc != SQLITE_OK) {
sg_raise_sqlite(tres->db, err);
return false;
}
- sqlite3BtreeNext(tres->cursor, &tres->res);
+ sqlite3BtreeNext(tres->i.cursor, &tres->i.res);
if (rc != SQLITE_OK) {
sg_raise_sqlite(tres->db, err);
return false;
@@ -1587,7 +1678,7 @@ void
sg_triple_result_close(SgTripleResult* tres, GuExn* err)
{
close_exprs(&tres->ectxt);
- close_triples(&tres->tctxt);
+ close_triples(&tres->i.tctxt);
if (tres->db->autoCommit) {
int rc = sqlite3BtreeCommit(tres->db->aDb[0].pBt);
@@ -1600,66 +1691,216 @@ sg_triple_result_close(SgTripleResult* tres, GuExn* err)
free(tres);
}
+typedef int SgPattern[3];
+
+struct SgQuery {
+ size_t n_vars;
+ struct {
+ SgId id;
+ PgfExpr expr;
+ }* vars;
+
+ size_t n_sels;
+ int* sel;
+
+ size_t n_patterns;
+ SgPattern patterns[];
+};
+
struct SgQueryResult {
- sqlite3 *db;
+ sqlite3* db;
SgQuery* query;
+ ExprContext ectxt;
+
+ bool is_empty;
int n_results;
- SgTripleResult* results[];
+ SgTripleResultInt results[];
};
+SgQuery*
+sg_prepare_query(SgSG *sg, size_t n_triples, SgTriple* triples,
+ GuPool* pool, GuExn* err)
+{
+ sqlite3 *db = (sqlite3 *) sg;
+
+ int rc;
+
+ if (db->autoCommit) {
+ rc = sqlite3BtreeBeginTrans(db->aDb[0].pBt, 0);
+ if (rc != SQLITE_OK) {
+ sg_raise_sqlite(db, err);
+ return NULL;
+ }
+ }
+
+ ExprContext ectxt;
+ rc = open_exprs(db, 0, false, &ectxt, err);
+ if (rc != SQLITE_OK)
+ goto close;
+
+ SgQuery* query = gu_new_flex(pool, SgQuery, patterns, n_triples);
+ query->n_vars = 0;
+ query->vars = gu_malloc(pool, sizeof(query->vars[0])*n_triples*3);
+
+ query->n_patterns = n_triples;
+ for (size_t i = 0; i < n_triples; i++) {
+ for (int k = 0; k < 3; k++) {
+ PgfExpr expr = triples[i][k];
+
+ size_t j = 0;
+ while (j < query->n_vars) {
+ if (pgf_expr_eq(expr, query->vars[j].expr))
+ break;
+ j++;
+ }
+ if (j >= query->n_vars) {
+ query->vars[j].expr = expr;
+
+ if (gu_variant_tag(expr) == PGF_EXPR_META)
+ query->vars[j].id = 0;
+ else {
+ rc = store_expr(db, &ectxt, expr, &query->vars[j].id, 0);
+ if (rc != SQLITE_OK) {
+ sg_raise_sqlite(db, err);
+ goto close;
+ }
+
+ if (query->vars[j].id == 0)
+ goto close;
+ }
+
+ query->n_vars++;
+ }
+
+ query->patterns[i][k] = j;
+ }
+ }
+
+ close_exprs(&ectxt);
+
+ if (db->autoCommit) {
+ rc = sqlite3BtreeCommit(db->aDb[0].pBt);
+ if (rc != SQLITE_OK) {
+ sg_raise_sqlite(db, err);
+ return 0;
+ }
+ }
+
+ return query;
+
+close:
+ close_exprs(&ectxt);
+
+ if (db->autoCommit) {
+ sqlite3BtreeRollback(db->aDb[0].pBt, SQLITE_ABORT_ROLLBACK, 0);
+ }
+
+ return NULL;
+}
+
SgQueryResult*
sg_query(SgSG *sg, SgQuery* query, GuExn* err)
{
sqlite3 *db = (sqlite3 *) sg;
+ int rc;
+
+ if (db->autoCommit) {
+ rc = sqlite3BtreeBeginTrans(db->aDb[0].pBt, 0);
+ if (rc != SQLITE_OK) {
+ sg_raise_sqlite(db, err);
+ return NULL;
+ }
+ }
+
SgQueryResult* qres =
malloc(sizeof(SgQueryResult)+
- sizeof(SgTripleResult*)*query->n_patterns);
+ sizeof(SgTripleResultInt)*query->n_patterns);
qres->db = db;
+ qres->is_empty = false;
qres->query = query;
qres->n_results = 0;
-
+
+ rc = open_exprs(db, 0, false, &qres->ectxt, err);
+ if (rc != SQLITE_OK)
+ goto close;
+
return qres;
+
+close:
+ return NULL;
}
bool
-sg_query_result_fetch(SgQueryResult* qres, SgId* res, GuExn* err)
+sg_query_result_fetch(SgQueryResult* qres, PgfExpr* res, GuPool* out_pool, GuExn* err)
{
+ if (qres->is_empty)
+ return false;
+
+ int rc;
+
size_t i = 0;
while (i < qres->query->n_patterns) {
+ for (int k = 0; k < 3; k++) {
+ if (qres->query->vars[qres->query->patterns[i][k]].id == 0)
+ qres->results[i].mem[k].flags = MEM_Null;
+ else {
+ qres->results[i].mem[k].flags = MEM_Int;
+ qres->results[i].mem[i].u.i = qres->query->vars[qres->query->patterns[i][k]].id;
+ }
+ }
+
+ rc = init_triple_result_int(qres->db, &qres->results[i], err);
+ if (rc != SQLITE_OK)
+ goto close;
+
SgTriple triple;
- triple[0] = qres->query->vars[qres->query->patterns[i][0]];
- triple[1] = qres->query->vars[qres->query->patterns[i][1]];
- triple[2] = qres->query->vars[qres->query->patterns[i][2]];
- qres->results[i] = sg_query_triple((SgSG *) qres->db, triple, err);
SgId key;
for (;;) {
- bool found = sg_triple_result_fetch(qres->results[i], &key, triple, NULL, err);
+ bool found =
+ triple_result_fetch_int(qres->db, &qres->results[i],
+ &key, err);
if (gu_exn_is_raised(err)) {
return false;
}
- if (!found) {
- sg_triple_result_close(qres->results[i], err);
- if (gu_exn_is_raised(err)) {
- return false;
- }
-
- if (i == 0)
- break;
-
- i--;
- }
+ if (found)
+ break;
+
+ close_triples(&qres->results[i].tctxt);
+
+ if (i == 0)
+ return false;
+
+ i--;
}
- qres->query->vars[qres->query->patterns[i][0]] = triple[0];
- qres->query->vars[qres->query->patterns[i][1]] = triple[1];
- qres->query->vars[qres->query->patterns[i][2]] = triple[2];
+ qres->query->vars[qres->query->patterns[i][0]].id = triple[0];
+ qres->query->vars[qres->query->patterns[i][1]].id = triple[1];
+ qres->query->vars[qres->query->patterns[i][2]].id = triple[2];
i++;
}
+
+ for (size_t i = 0; i < qres->query->n_sels; i++) {
+ res[i] = qres->query->vars[qres->query->sel[i]].expr;
+ if (gu_variant_is_null(res[i])) {
+ rc = load_expr(&qres->ectxt.crsExprs,
+ qres->query->vars[qres->query->sel[i]].id,
+ &res[i], out_pool);
+ if (rc != SQLITE_OK) {
+ sg_raise_sqlite(qres->db, err);
+ goto close;
+ }
+
+ qres->query->vars[qres->query->sel[i]].expr = res[i];
+ }
+ }
+
+ return true;
+close:
return false;
}
diff --git a/src/runtime/c/sg/sg.h b/src/runtime/c/sg/sg.h
index 6ef57584d..a94c28cb7 100644
--- a/src/runtime/c/sg/sg.h
+++ b/src/runtime/c/sg/sg.h
@@ -25,7 +25,7 @@ sg_rollback(SgSG* sg, GuExn* err);
SgId
-sg_insert_expr(SgSG *sg, PgfExpr expr, GuExn* err);
+sg_insert_expr(SgSG *sg, PgfExpr expr, int wrFlag, GuExn* err);
PgfExpr
sg_get_expr(SgSG *sg, SgId key, GuPool* out_pool, GuExn* err);
@@ -61,17 +61,13 @@ sg_triple_result_get_query(SgTripleResult* tres, SgTriple triple);
void
sg_triple_result_close(SgTripleResult* tres, GuExn* err);
-typedef int SgPattern[3];
-
-typedef struct {
- SgId* sel;
- SgId* vars;
- size_t n_patterns;
- SgPattern patterns[];
-} SgQuery;
-
+typedef struct SgQuery SgQuery;
typedef struct SgQueryResult SgQueryResult;
+SgQuery*
+sg_prepare_query(SgSG *sg, size_t n_triples, SgTriple* triples,
+ GuPool* pool, GuExn* err);
+
SgQueryResult*
sg_query(SgSG *sg, SgQuery* query, GuExn* err);