2 // rdf_storage_sqlite_mro.c
4 // Created by Marcus Rohrmoser on 19.05.14.
6 // Copyright (c) 2014-2018, Marcus Rohrmoser mobile Software, http://mro.name/~me
7 // All rights reserved.
9 // Redistribution and use in source and binary forms, with or without modification, are permitted
10 // provided that the following conditions are met:
12 // 1. Redistributions of source code must retain the above copyright notice, this list of conditions
13 // and the following disclaimer.
15 // 2. The software must not be used for military or intelligence or related purposes nor
16 // anything that's in conflict with human rights as declared in http://www.un.org/en/documents/udhr/ .
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
19 // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20 // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
21 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
24 // IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
25 // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #include "rdf_storage_sqlite_mro.h"
30 #define NAMESPACE "http://purl.mro.name/librdf.sqlite/"
31 const char *LIBRDF_STORAGE_SQLITE_MRO
= NAMESPACE
;
33 const unsigned char *LIBRDF_STORAGE_SQLITE_MRO_FEATURE_SQL_CACHE_MASK
= (unsigned char *)NAMESPACE
"feature/sql/cache/mask";
34 const unsigned char *LIBRDF_STORAGE_SQLITE_MRO_FEATURE_SQLITE3_PROFILE
= (unsigned char *)NAMESPACE
"feature/sqlite3/profile";
35 const unsigned char *LIBRDF_STORAGE_SQLITE_MRO_FEATURE_SQLITE3_EXPLAIN_QUERY_PLAN
= (unsigned char *)NAMESPACE
"feature/sqlite3/explain_query_plan";
37 #define LIBRDF_NAMESPACE_XSD "http://www.w3.org/2000/10/XMLSchema#"
44 #include <rdf_storage.h>
57 #define array_length(a) ( sizeof(a) / sizeof( (a)[0] ) )
59 #pragma mark Basic Types & Constants
61 typedef sqlite3_uint64 hash_t
;
62 static const hash_t NULL_ID
= 0;
63 static inline bool isNULL_ID(const hash_t x
)
72 /** C-String type for URIs. */
73 typedef unsigned char *str_uri_t
;
74 /** C-String type for blank identifiers. */
75 typedef unsigned char *str_blank_t
;
76 /** C-String type for literal values. */
77 typedef unsigned char *str_lit_val_t
;
78 /** C-String type for (xml) language ids. */
79 typedef char *str_lang_t
;
82 /** index into synchronous_flags */
89 static const char *const synchronous_flags
[4] = {
90 "off", "normal", "full", NULL
100 P_O_LANGUAGE
= 1 << 6,
101 P_O_DATATYPE
= 1 << 7,
105 #define ALL_PARAMS ( (P_C_URI << 1) - 1 )
110 librdf_digest
*digest
;
114 syncronous_flag_t synchronous
;
118 bool do_explain_query_plan
;
119 sql_find_param_t sql_cache_mask
;
121 // compiled statements, lazy init
122 sqlite3_stmt
*stmt_txn_start
;
123 sqlite3_stmt
*stmt_txn_commit
;
124 sqlite3_stmt
*stmt_txn_rollback
;
125 sqlite3_stmt
*stmt_triple_find
; // complete triples
126 sqlite3_stmt
*stmt_triple_insert
;
127 sqlite3_stmt
*stmt_triple_delete
;
129 sqlite3_stmt
*stmt_size
;
134 #pragma mark librdf convenience
137 #define LIBRDF_MALLOC(type, size) (type)malloc(size)
138 #define LIBRDF_CALLOC(type, size, count) (type)calloc(count, size)
139 #define LIBRDF_FREE(type, ptr) free( (type)ptr )
140 // #define LIBRDF_BAD_CAST(t, v) (t)(v)
143 static inline instance_t
*get_instance(librdf_storage
*storage
)
145 return (instance_t
*)librdf_storage_get_instance(storage
);
149 static inline librdf_world
*get_world(librdf_storage
*storage
)
151 return librdf_storage_get_world(storage
);
155 static inline void free_hash(librdf_hash
*hash
)
158 librdf_free_hash(hash
);
162 static inline librdf_node_type
node_type(librdf_node
*node
)
164 return NULL
== node
? LIBRDF_NODE_TYPE_UNKNOWN
: librdf_node_get_type(node
);
168 static inline librdf_uri
*literal_type_uri(librdf_node
*o
)
170 if( NULL
== o
|| LIBRDF_NODE_TYPE_LITERAL
!= node_type(o
) )
172 return librdf_node_get_literal_value_datatype_uri(o
);
176 static inline char *literal_language(librdf_node
*o
)
178 if( NULL
== o
|| LIBRDF_NODE_TYPE_LITERAL
!= node_type(o
) )
180 return librdf_node_get_literal_value_language(o
);
184 /* Copy first 8 bytes of digest into 64bit using a method portable across big/little endianness.
186 static hash_t
digest_hash(librdf_digest
*digest
)
188 assert(digest
&& "must be set");
189 librdf_digest_final(digest
);
191 assert(librdf_digest_get_digest_length(digest
) >= sizeof(hash_t
) && "digest length too small");
192 const int byte_count
= 8;
193 const int bit_per_byte
= 8;
194 assert(byte_count
== sizeof(hash_t
) && "made for 8-byte (64-bit) hashes");
195 uint8_t *diges
= (uint8_t *)librdf_digest_get_digest(digest
);
196 sqlite3_uint64 ret
= 0; // enforce unsigned
197 for( int i
= byte_count
- 1; i
>= 0; i
-- ) {
198 ret
<<= bit_per_byte
;
201 assert(!isNULL_ID(ret
) && "null hash");
206 static hash_t
hash_uri(librdf_uri
*uri
, librdf_digest
*digest
)
210 assert(digest
&& "digest must be set.");
212 const unsigned char *s
= librdf_uri_as_counted_string(uri
, &len
);
213 assert(s
&& "uri NULL");
214 assert(len
&& "uri length 0");
215 librdf_digest_init(digest
);
216 librdf_digest_update(digest
, s
, len
);
217 return digest_hash(digest
);
221 static hash_t
node_hash_uri(librdf_node
*node
, librdf_digest
*digest
)
223 return hash_uri(LIBRDF_NODE_TYPE_RESOURCE
== node_type(node
) ? librdf_node_get_uri(node
) : NULL
, digest
);
227 static hash_t
node_hash_blank(librdf_node
*node
, librdf_digest
*digest
)
229 if( LIBRDF_NODE_TYPE_BLANK
!= node_type(node
) )
231 assert(digest
&& "digest must be set.");
233 unsigned char *b
= librdf_node_get_counted_blank_identifier(node
, &len
);
234 assert(b
&& "blank NULL");
235 assert(len
&& "blank len 0");
236 librdf_digest_init(digest
);
237 librdf_digest_update(digest
, b
, len
);
238 return digest_hash(digest
);
242 static hash_t
node_hash_literal(librdf_node
*node
, librdf_digest
*digest
)
244 if( LIBRDF_NODE_TYPE_LITERAL
!= node_type(node
) )
246 assert(digest
&& "digest must be set.");
247 librdf_digest_init(digest
);
250 unsigned char *str
= librdf_node_get_literal_value_as_counted_string(node
, &len
);
251 assert(str
&& "literal without value");
252 assert(strlen( (char *)str
) == len
&& "TODO: NUL terminate or limit length!");
253 librdf_digest_update(digest
, str
, len
);
255 librdf_uri
*uri
= librdf_node_get_literal_value_datatype_uri(node
);
258 const unsigned char *str
= librdf_uri_as_counted_string(uri
, &len
);
259 librdf_digest_update(digest
, str
, len
);
261 const char *l
= librdf_node_get_literal_value_language(node
);
263 librdf_digest_update( digest
, (unsigned char *)l
, strlen(l
) );
264 return digest_hash(digest
);
268 /** https://stackoverflow.com/questions/2590677/how-do-i-combine-hash-values-in-c0x
270 static inline hash_t
hash_combine(const hash_t seed
, const hash_t b
)
272 // return seed ^ ( b + 0x9e3779b9 + (seed << 6) + (seed >> 2) );
273 // http://stackoverflow.com/a/4948967 and https://stackoverflow.com/questions/4948780/magic-number-in-boosthash-combine#comment35569848_4948967
274 // $ python -c "import math; print hex(int(2**64 / ((1 + math.sqrt(5)) / 2)))"
275 return seed
^ ( b
+ 0x9e3779b97f4a7800L
+ (seed
<< 6) + (seed
>> 2) );
279 static hash_t
hash_combine_stmt(const hash_t s_uri_id
, const hash_t s_blank_id
, const hash_t p_uri_id
, const hash_t o_uri_id
, const hash_t o_blank_id
, const hash_t o_lit_id
, const hash_t c_uri_id
)
281 hash_t stmt_id
= NULL_ID
;
282 stmt_id
= hash_combine(stmt_id
, s_uri_id
);
283 stmt_id
= hash_combine(stmt_id
, s_blank_id
);
284 stmt_id
= hash_combine(stmt_id
, p_uri_id
);
285 stmt_id
= hash_combine(stmt_id
, o_uri_id
);
286 stmt_id
= hash_combine(stmt_id
, o_blank_id
);
287 stmt_id
= hash_combine(stmt_id
, o_lit_id
);
288 // stmt_id ^= o_type_id;
289 stmt_id
= hash_combine(stmt_id
, c_uri_id
);
294 static hash_t
stmt_hash(librdf_statement
*stmt
, librdf_node
*context_node
, librdf_digest
*digest
)
299 librdf_node
*s
= librdf_statement_get_subject(stmt
);
300 librdf_node
*p
= librdf_statement_get_predicate(stmt
);
301 librdf_node
*o
= librdf_statement_get_object(stmt
);
303 return hash_combine_stmt( node_hash_uri(s
, digest
), node_hash_blank(s
, digest
), node_hash_uri(p
, digest
), node_hash_uri(o
, digest
), node_hash_blank(o
, digest
), node_hash_literal(o
, digest
), node_hash_uri(context_node
, digest
) );
307 #pragma mark Sqlite Debug/Profile
310 /* https://sqlite.org/eqp.html#section_2
311 ** Argument pStmt is a prepared SQL statement. This function compiles
312 ** an EXPLAIN QUERY PLAN command to report on the prepared statement,
313 ** and prints the report to stdout using printf().
315 static int printExplainQueryPlan(sqlite3_stmt
*pStmt
)
317 const char *zSql
= sqlite3_sql(pStmt
);
318 if( NULL
== zSql
) return SQLITE_ERROR
;
320 char *zExplain
= sqlite3_mprintf("EXPLAIN QUERY PLAN %s", zSql
);
321 if( NULL
== zExplain
) return SQLITE_NOMEM
;
323 sqlite3_stmt
*pExplain
; /* Compiled EXPLAIN QUERY PLAN command */
324 const int rc
= sqlite3_prepare_v2(sqlite3_db_handle(pStmt
), zExplain
, -1, &pExplain
, 0);
325 sqlite3_free(zExplain
);
326 if( SQLITE_OK
!= rc
) return rc
;
328 while( SQLITE_ROW
== sqlite3_step(pExplain
) ) {
329 const int iSelectid
= sqlite3_column_int(pExplain
, 0);
330 const int iOrder
= sqlite3_column_int(pExplain
, 1);
331 const int iFrom
= sqlite3_column_int(pExplain
, 2);
332 const char *zDetail
= (const char *)sqlite3_column_text(pExplain
, 3);
334 printf("%d %d %d %s\n", iSelectid
, iOrder
, iFrom
, zDetail
);
337 return sqlite3_finalize(pExplain
);
342 // http://stackoverflow.com/a/6618833
343 static void trace(void *context
, const char *sql
)
345 fprintf(stderr
, "Query SQL: %s\n", sql
);
352 // http://stackoverflow.com/a/6618833
353 static void profile(void *context
, const char *sql
, const sqlite3_uint64 ns
)
355 // librdf_storage *storage = (librdf_storage *)context;
356 // instance_t *db_ctx = get_instance(storage);
357 fprintf(stderr
, "dt=%llu ns Query SQL: %s\n", ns
, sql
);
361 #pragma mark Sqlite Convenience
364 /** Sqlite Result Code, e.g. SQLITE_OK */
365 typedef int sqlite_rc_t
;
367 static sqlite_rc_t
log_error(sqlite3
*db
, const char *sql
, const sqlite_rc_t rc
)
369 if( SQLITE_OK
!= rc
) {
370 const char *errmsg
= sqlite3_errmsg(db
);
371 librdf_log(NULL
, 0, LIBRDF_LOG_ERROR
, LIBRDF_FROM_STORAGE
, NULL
, "SQLite SQL error - %s (%d)\n%s", errmsg
, rc
, sql
);
377 static sqlite3_stmt
*prep_stmt(sqlite3
*db
, sqlite3_stmt
**stmt_p
, const char *zSql
)
379 assert(db
&& "db handle is NULL");
380 assert(stmt_p
&& "statement is NULL");
381 assert(zSql
&& "SQL is NULL");
383 assert(0 == strcmp(sqlite3_sql(*stmt_p
), zSql
) && "sql changed during compilation.");
384 const sqlite_rc_t rc0
= sqlite3_reset(*stmt_p
);
385 assert(SQLITE_OK
== rc0
&& "couldn't reset SQL statement");
386 const sqlite_rc_t rc1
= sqlite3_clear_bindings(*stmt_p
);
387 assert(SQLITE_OK
== rc1
&& "couldn't reset SQL statement");
389 const char *remainder
= NULL
;
390 const int len_zSql
= (int)strlen(zSql
) + 1;
391 const sqlite_rc_t rc0
= log_error( db
, zSql
, sqlite3_prepare_v2(db
, zSql
, len_zSql
, stmt_p
, &remainder
) );
392 assert(SQLITE_OK
== rc0
&& "couldn't compile SQL statement");
393 assert('\0' == *remainder
&& "had remainder");
395 assert(*stmt_p
&& "statement is NULL");
400 static void finalize_stmt(sqlite3_stmt
**pStmt
)
404 sqlite3_reset(*pStmt
);
405 const sqlite_rc_t rc
= sqlite3_finalize(*pStmt
);
406 assert(SQLITE_OK
== rc
&& "couldn't properly sqlite3_finalize");
411 static sqlite_rc_t
exec_stmt(sqlite3
*db
, const char *sql
)
414 const sqlite_rc_t rc
= sqlite3_exec(db
, sql
, NULL
, NULL
, &errmsg
);
415 sqlite3_free(errmsg
);
420 static inline sqlite_rc_t
bind_int(sqlite3_stmt
*stmt
, const char *name
, const hash_t _id
)
422 assert(stmt
&& "stmt mandatory");
423 assert(name
&& "name mandatory");
424 const int idx
= sqlite3_bind_parameter_index(stmt
, name
);
425 return 0 == idx
? SQLITE_OK
: sqlite3_bind_int64(stmt
, idx
, _id
);
429 static inline sqlite_rc_t
bind_text(sqlite3_stmt
*stmt
, const char *name
, const unsigned char *text
, const size_t text_len
)
431 assert(stmt
&& "stmt mandatory");
432 assert(name
&& "name mandatory");
433 const int idx
= sqlite3_bind_parameter_index(stmt
, name
);
434 return 0 == idx
? SQLITE_OK
: ( NULL
== text
? sqlite3_bind_null(stmt
, idx
) : sqlite3_bind_text(stmt
, idx
, (const char *)text
, (int)text_len
, SQLITE_STATIC
) );
438 static inline sqlite_rc_t
bind_null(sqlite3_stmt
*stmt
, const char *name
)
440 return bind_text(stmt
, name
, NULL
, 0);
444 static sqlite_rc_t
bind_uri_id(sqlite3_stmt
*stmt
, librdf_digest
*digest
, const char *name
, librdf_uri
*uri
, hash_t
*value
)
447 const hash_t v
= hash_uri(uri
, digest
);
448 if( value
) *value
= v
;
449 return bind_int(stmt
, name
, v
);
451 return bind_null(stmt
, name
);
455 static sqlite_rc_t
bind_uri(sqlite3_stmt
*stmt
, const char *name
, librdf_uri
*uri
)
459 const unsigned char *str
= librdf_uri_as_counted_string(uri
, &len
);
460 return bind_text(stmt
, name
, str
, len
);
462 return bind_null(stmt
, name
);
466 static sqlite_rc_t
bind_node_uri_id(sqlite3_stmt
*stmt
, librdf_digest
*digest
, const char *name
, librdf_node
*node
, hash_t
*value
)
468 return bind_uri_id(stmt
, digest
, name
, LIBRDF_NODE_TYPE_RESOURCE
== node_type(node
) ? librdf_node_get_uri(node
) : NULL
, value
);
472 static sqlite_rc_t
bind_node_uri(sqlite3_stmt
*stmt
, const char *name
, librdf_node
*node
)
474 return bind_uri(stmt
, name
, LIBRDF_NODE_TYPE_RESOURCE
== node_type(node
) ? librdf_node_get_uri(node
) : NULL
);
478 static sqlite_rc_t
bind_node_blank_id(sqlite3_stmt
*stmt
, librdf_digest
*digest
, const char *name
, librdf_node
*node
, hash_t
*value
)
480 if( LIBRDF_NODE_TYPE_BLANK
== node_type(node
) ) {
481 const hash_t v
= node_hash_blank(node
, digest
);
482 if( value
) *value
= v
;
483 return bind_int(stmt
, name
, v
);
485 return bind_null(stmt
, name
);
489 static sqlite_rc_t
bind_node_blank(sqlite3_stmt
*stmt
, const char *name
, librdf_node
*node
)
491 if( LIBRDF_NODE_TYPE_BLANK
== node_type(node
) ) {
493 const unsigned char *str
= librdf_node_get_counted_blank_identifier(node
, &len
);
494 return bind_text(stmt
, name
, str
, len
);
496 return bind_null(stmt
, name
);
500 static sqlite_rc_t
bind_node_lit_id(sqlite3_stmt
*stmt
, librdf_digest
*digest
, const char *name
, librdf_node
*node
, hash_t
*value
)
502 if( LIBRDF_NODE_TYPE_LITERAL
== node_type(node
) ) {
503 const hash_t v
= node_hash_literal(node
, digest
);
504 if( value
) *value
= v
;
505 return bind_int(stmt
, name
, v
);
507 return bind_null(stmt
, name
);
511 static sqlite_rc_t
bind_stmt(instance_t
*db_ctx
, librdf_statement
*statement
, librdf_node
*context_node
, sqlite3_stmt
*stmt
)
513 librdf_node
*s
= librdf_statement_get_subject(statement
);
514 librdf_node
*p
= librdf_statement_get_predicate(statement
);
515 librdf_node
*o
= librdf_statement_get_object(statement
);
517 sqlite_rc_t rc
= SQLITE_OK
;
518 hash_t s_uri_id
= NULL_ID
;
519 hash_t s_blank_id
= NULL_ID
;
520 hash_t p_uri_id
= NULL_ID
;
521 hash_t o_uri_id
= NULL_ID
;
522 hash_t o_blank_id
= NULL_ID
;
523 hash_t o_lit_id
= NULL_ID
;
524 hash_t o_type_id
= NULL_ID
;
525 hash_t c_uri_id
= NULL_ID
;
526 if( SQLITE_OK
!= ( rc
= bind_node_uri_id(stmt
, db_ctx
->digest
, ":s_uri_id", s
, &s_uri_id
) ) ) return rc
;
527 if( SQLITE_OK
!= ( rc
= bind_node_uri(stmt
, ":s_uri", s
) ) ) return rc
;
528 if( SQLITE_OK
!= ( rc
= bind_node_blank_id(stmt
, db_ctx
->digest
, ":s_blank_id", s
, &s_blank_id
) ) ) return rc
;
529 if( SQLITE_OK
!= ( rc
= bind_node_blank(stmt
, ":s_blank", s
) ) ) return rc
;
530 if( SQLITE_OK
!= ( rc
= bind_node_uri_id(stmt
, db_ctx
->digest
, ":p_uri_id", p
, &p_uri_id
) ) ) return rc
;
531 if( SQLITE_OK
!= ( rc
= bind_node_uri(stmt
, ":p_uri", p
) ) ) return rc
;
532 if( SQLITE_OK
!= ( rc
= bind_node_uri_id(stmt
, db_ctx
->digest
, ":o_uri_id", o
, &o_uri_id
) ) ) return rc
;
533 if( SQLITE_OK
!= ( rc
= bind_node_uri(stmt
, ":o_uri", o
) ) ) return rc
;
534 if( SQLITE_OK
!= ( rc
= bind_node_blank_id(stmt
, db_ctx
->digest
, ":o_blank_id", o
, &o_blank_id
) ) ) return rc
;
535 if( SQLITE_OK
!= ( rc
= bind_node_blank(stmt
, ":o_blank", o
) ) ) return rc
;
536 if( SQLITE_OK
!= ( rc
= bind_node_lit_id(stmt
, db_ctx
->digest
, ":o_lit_id", o
, &o_lit_id
) ) ) return rc
;
537 if( LIBRDF_NODE_TYPE_LITERAL
== node_type(o
) ) {
538 if( SQLITE_OK
!= ( rc
= bind_uri_id(stmt
, db_ctx
->digest
, ":o_datatype_id", librdf_node_get_literal_value_datatype_uri(o
), &o_type_id
) ) ) return rc
;
539 if( SQLITE_OK
!= ( rc
= bind_uri( stmt
, ":o_datatype", librdf_node_get_literal_value_datatype_uri(o
) ) ) ) return rc
;
540 char *l
= librdf_node_get_literal_value_language(o
);
542 if( SQLITE_OK
!= ( rc
= bind_text( stmt
, ":o_language", (unsigned char *)l
, strlen(l
) ) ) ) return rc
;
544 const unsigned char *str
= librdf_node_get_literal_value_as_counted_string(o
, &len
);
545 assert(strlen( (char *)str
) == len
&& "TODO: NUL terminate or limit length!");
546 if( SQLITE_OK
!= ( rc
= bind_text(stmt
, ":o_text", str
, len
) ) ) return rc
;
549 if( SQLITE_OK
!= ( rc
= bind_node_uri_id(stmt
, db_ctx
->digest
, ":c_uri_id", context_node
, &c_uri_id
) ) ) return rc
;
550 if( SQLITE_OK
!= ( rc
= bind_node_uri(stmt
, ":c_uri", context_node
) ) ) return rc
;
552 if( !librdf_statement_is_complete(statement
) )
555 const hash_t stmt_id
= hash_combine_stmt(s_uri_id
, s_blank_id
, p_uri_id
, o_uri_id
, o_blank_id
, o_lit_id
, c_uri_id
);
557 assert(stmt_hash(statement
, context_node
, db_ctx
->digest
) == stmt_id
&& "statement hash computation mismatch");
558 if( SQLITE_OK
!= ( rc
= bind_int(stmt
, ":stmt_id", stmt_id
) ) ) return rc
;
564 static inline const str_uri_t
column_uri_string(sqlite3_stmt
*stmt
, const int iCol
)
566 return (str_uri_t
)sqlite3_column_text(stmt
, iCol
);
570 static inline const str_blank_t
column_blank_string(sqlite3_stmt
*stmt
, const int iCol
)
572 return (str_blank_t
)sqlite3_column_text(stmt
, iCol
);
576 static inline const str_lang_t
column_language(sqlite3_stmt
*stmt
, const int iCol
)
578 return (str_lang_t
)sqlite3_column_text(stmt
, iCol
);
582 static sqlite_rc_t
transaction_start(librdf_storage
*storage
)
584 instance_t
*db_ctx
= get_instance(storage
);
585 if( db_ctx
->in_transaction
)
586 return SQLITE_MISUSE
;
587 const sqlite_rc_t rc
= sqlite3_step( prep_stmt(db_ctx
->db
, &(db_ctx
->stmt_txn_start
), "BEGIN IMMEDIATE TRANSACTION") );
588 db_ctx
->in_transaction
= SQLITE_DONE
== rc
;
589 assert(false != db_ctx
->in_transaction
&& "transaction was not properly started");
590 return SQLITE_DONE
== rc
? SQLITE_OK
: rc
;
594 static sqlite_rc_t
transaction_commit(librdf_storage
*storage
, const sqlite_rc_t begin
)
596 if( begin
!= SQLITE_OK
)
598 instance_t
*db_ctx
= get_instance(storage
);
599 if( false == db_ctx
->in_transaction
)
600 return SQLITE_MISUSE
;
601 const sqlite_rc_t rc
= sqlite3_step( prep_stmt(db_ctx
->db
, &(db_ctx
->stmt_txn_commit
), "COMMIT TRANSACTION") );
602 db_ctx
->in_transaction
= !(SQLITE_DONE
== rc
);
603 assert(false == db_ctx
->in_transaction
&& "transaction was not properly committed");
604 return SQLITE_DONE
== rc
? SQLITE_OK
: rc
;
608 static sqlite_rc_t
transaction_rollback(librdf_storage
*storage
, const sqlite_rc_t begin
)
610 if( SQLITE_OK
!= begin
)
612 instance_t
*db_ctx
= get_instance(storage
);
613 if( false == db_ctx
->in_transaction
)
614 return SQLITE_MISUSE
;
615 const sqlite_rc_t rc
= sqlite3_step( prep_stmt(db_ctx
->db
, &(db_ctx
->stmt_txn_rollback
), "ROLLBACK TRANSACTION") );
616 db_ctx
->in_transaction
= !(SQLITE_DONE
== rc
);
617 assert(false == db_ctx
->in_transaction
&& "transaction was not properly rolled back");
618 return SQLITE_DONE
== rc
? SQLITE_OK
: rc
;
625 #pragma mark Internal Implementation
628 /** insert_triple_sql + find_triples_sql
644 static librdf_statement
*find_statement(librdf_storage
*storage
, librdf_node
*context_node
, librdf_statement
*statement
, const bool create
)
646 assert(statement
&& "statement must be set.");
647 assert(librdf_statement_is_complete(statement
) && "statement must be complete.");
649 instance_t
*db_ctx
= get_instance(storage
);
652 const hash_t stmt_id
= stmt_hash(statement
, context_node
, db_ctx
->digest
);
653 assert(!isNULL_ID(stmt_id
) && "mustn't be nil");
655 sqlite3_stmt
*stmt
= prep_stmt(db_ctx
->db
, &(db_ctx
->stmt_triple_find
), "SELECT id FROM triple_relations WHERE id = :stmt_id");
657 if( SQLITE_OK
!= bind_int(stmt
, ":stmt_id", stmt_id
) )
659 return SQLITE_ROW
== sqlite3_step(stmt
) ? statement
: NULL
;
661 const char insert_triple_sql
[] = // generated via tools/sql2c.sh insert_triple.sql
662 "INSERT OR IGNORE INTO triples(" "\n" \
664 " s_uri_id, s_uri," "\n" \
665 " s_blank_id, s_blank," "\n" \
666 " p_uri_id, p_uri," "\n" \
667 " o_uri_id, o_uri," "\n" \
668 " o_blank_id, o_blank," "\n" \
669 " o_lit_id, o_datatype_id, o_datatype, o_language, o_text," "\n" \
670 " c_uri_id, c_uri" "\n" \
673 " :s_uri_id, :s_uri," "\n" \
674 " :s_blank_id, :s_blank," "\n" \
675 " :p_uri_id, :p_uri," "\n" \
676 " :o_uri_id, :o_uri," "\n" \
677 " :o_blank_id, :o_blank," "\n" \
678 " :o_lit_id, :o_datatype_id, :o_datatype, :o_language, :o_text," "\n" \
679 " :c_uri_id, :c_uri" "\n" \
683 sqlite3_stmt
*stmt
= prep_stmt(db_ctx
->db
, &(db_ctx
->stmt_triple_insert
), insert_triple_sql
);
684 if( SQLITE_OK
!= bind_stmt(db_ctx
, statement
, context_node
, stmt
) )
686 if( db_ctx
->do_explain_query_plan
)
687 printExplainQueryPlan(stmt
);
688 const sqlite_rc_t rc
= sqlite3_step(stmt
);
689 return SQLITE_DONE
== rc
? statement
: NULL
;
695 #pragma mark Public Interface
698 int librdf_storage_set_feature_mro_bool(librdf_storage
*storage
, const unsigned char *feature
, const bool value
)
700 assert(storage
&& "storage must be set.");
701 assert(feature
&& "feature must be set.");
702 librdf_world
*world
= librdf_storage_get_world(storage
);
703 assert(world
&& "world must be set.");
705 librdf_uri
*uri_xsd_boolean
= librdf_new_uri(world
, (str_uri_t
)LIBRDF_NAMESPACE_XSD
"boolean");
706 assert(uri_xsd_boolean
&& "uri_xsd_boolean must be set.");
707 librdf_uri
*uri_f
= librdf_new_uri(world
, feature
);
708 assert(uri_f
&& "uri_f must be set.");
709 const str_lit_val_t v
= (str_lit_val_t
)(value
? "true" : "false");
710 // librdf_log(get_world(storage), 0, LIBRDF_LOG_DEBUG, LIBRDF_FROM_STORAGE, NULL, "librdf_storage_set_feature_mro_bool sets '%s'", v);
711 librdf_node
*n
= librdf_new_node_from_typed_literal(world
, v
, NULL
, uri_xsd_boolean
);
713 const int ret
= librdf_storage_set_feature(storage
, uri_f
, n
);
716 librdf_free_uri(uri_f
);
717 librdf_free_uri(uri_xsd_boolean
);
723 int librdf_storage_set_feature_mro_int(librdf_storage
*storage
, const unsigned char *feature
, const int value
)
725 assert(storage
&& "storage must be set.");
726 assert(feature
&& "feature must be set.");
727 librdf_world
*world
= librdf_storage_get_world(storage
);
728 assert(world
&& "world must be set.");
730 librdf_uri
*uri_xsd_integer
= librdf_new_uri(world
, (str_uri_t
)LIBRDF_NAMESPACE_XSD
"integer");
731 assert(uri_xsd_integer
&& "uri_xsd_integer must be set.");
732 librdf_uri
*uri_f
= librdf_new_uri(world
, feature
);
733 assert(uri_f
&& "uri_f must be set.");
735 snprintf(v
, sizeof(v
), "%d", value
);
736 librdf_node
*n
= librdf_new_node_from_typed_literal(world
, (str_lit_val_t
)v
, NULL
, uri_xsd_integer
);
738 const int ret
= librdf_storage_set_feature(storage
, uri_f
, n
);
741 librdf_free_uri(uri_f
);
742 librdf_free_uri(uri_xsd_integer
);
748 int librdf_storage_get_feature_mro_bool(librdf_storage
*storage
, const unsigned char *feature
, bool *value
)
750 assert(storage
&& "storage must be set.");
751 assert(feature
&& "feature must be set.");
752 librdf_world
*world
= librdf_storage_get_world(storage
);
753 assert(world
&& "world must be set.");
755 librdf_uri
*uri_f
= librdf_new_uri(world
, feature
);
759 librdf_node
*node
= librdf_storage_get_feature(storage
, uri_f
);
761 if( LIBRDF_NODE_TYPE_LITERAL
== node_type(node
) ) {
763 const char *v
= (char *)librdf_node_get_literal_value_as_counted_string(node
, &len
);
765 // librdf_log(get_world(storage), 0, LIBRDF_LOG_DEBUG, LIBRDF_FROM_STORAGE, NULL, "librdf_storage_get_feature_mro_bool return '%s'", v);
766 if( 0 == strncmp("true", v
, len
) || 0 == strncmp("1", v
, len
) )
768 else if( 0 == strncmp("false", v
, len
) || 0 == strncmp("0", v
, len
) )
776 librdf_free_node(node
);
779 librdf_free_uri(uri_f
);
787 int librdf_storage_get_feature_mro_int(librdf_storage
*storage
, const unsigned char *feature
, int *value
)
789 assert(storage
&& "storage must be set.");
790 assert(feature
&& "feature must be set.");
791 librdf_world
*world
= librdf_storage_get_world(storage
);
792 assert(world
&& "world must be set.");
794 librdf_uri
*uri_f
= librdf_new_uri(world
, feature
);
798 librdf_node
*node
= librdf_storage_get_feature(storage
, uri_f
);
800 if( LIBRDF_NODE_TYPE_LITERAL
== node_type(node
) ) {
802 const char *str
= (char *)librdf_node_get_literal_value_as_counted_string(node
, &len
);
804 assert(strlen(str
) == len
&& "TODO: NUL terminate or limit length!");
806 ret
= strtol(str
, &end
, 10);
813 librdf_free_node(node
);
816 librdf_free_uri(uri_f
);
824 #pragma mark Lifecycle & Housekeeping
827 /** Create a new storage.
829 * Setup SQLIte connection instance but don't open yet.
831 static int pub_init(librdf_storage
*storage
, const char *name
, librdf_hash
*options
)
838 instance_t
*db_ctx
= LIBRDF_CALLOC(instance_t
*, sizeof(*db_ctx
), 1);
844 db_ctx
->do_profile
= false;
845 db_ctx
->do_explain_query_plan
= false;
846 db_ctx
->sql_cache_mask
= ALL_PARAMS
;
848 librdf_storage_set_instance(storage
, db_ctx
);
849 const size_t name_len
= strlen(name
);
850 char *name_copy
= LIBRDF_MALLOC(char *, name_len
+ 1);
856 strncpy(name_copy
, name
, name_len
+ 1);
857 db_ctx
->name
= name_copy
;
859 if( !( db_ctx
->digest
= librdf_new_digest(get_world(storage
), "MD5") ) ) {
864 if( false != librdf_hash_get_as_boolean(options
, "new") )
865 db_ctx
->is_new
= true; /* default is NOT NEW */
867 /* Redland default is "PRAGMA synchronous normal" */
868 db_ctx
->synchronous
= SYNC_NORMAL
;
870 char *synchronous
= synchronous
= librdf_hash_get(options
, "synchronous");
872 for( int i
= 0; synchronous_flags
[i
]; i
++ ) {
873 if( !strcmp(synchronous
, synchronous_flags
[i
]) ) {
874 db_ctx
->synchronous
= i
;
878 LIBRDF_FREE(char *, synchronous
);
886 static void pub_terminate(librdf_storage
*storage
)
888 instance_t
*db_ctx
= get_instance(storage
);
892 LIBRDF_FREE(char *, (void *)db_ctx
->name
);
894 librdf_free_digest(db_ctx
->digest
);
896 LIBRDF_FREE(instance_t
*, db_ctx
);
900 static int pub_close(librdf_storage
*storage
)
902 instance_t
*db_ctx
= get_instance(storage
);
906 finalize_stmt( &(db_ctx
->stmt_txn_start
) );
907 finalize_stmt( &(db_ctx
->stmt_txn_commit
) );
908 finalize_stmt( &(db_ctx
->stmt_txn_rollback
) );
909 finalize_stmt( &(db_ctx
->stmt_triple_find
) );
910 finalize_stmt( &(db_ctx
->stmt_triple_insert
) );
911 finalize_stmt( &(db_ctx
->stmt_triple_delete
) );
913 finalize_stmt( &(db_ctx
->stmt_size
) );
915 const sqlite_rc_t rc
= sqlite3_close(db_ctx
->db
);
916 if( SQLITE_OK
== rc
) {
920 char *errmsg
= (char *)sqlite3_errmsg(db_ctx
->db
);
921 librdf_log(get_world(storage
), 0, LIBRDF_LOG_ERROR
, LIBRDF_FROM_STORAGE
, NULL
, "SQLite database %s close failed - %s", db_ctx
->name
, errmsg
);
926 static int pub_open(librdf_storage
*storage
, librdf_model
*model
)
928 instance_t
*db_ctx
= get_instance(storage
);
930 const bool file_exists
= ( 0 == access(db_ctx
->name
, F_OK
) );
931 if( db_ctx
->is_new
&& file_exists
)
932 unlink(db_ctx
->name
);
935 assert( (NULL
== db_ctx
->db
) && "db handle mustn't be set by now" );
938 const sqlite_rc_t rc
= sqlite3_open(db_ctx
->name
, &db_ctx
->db
);
939 if( SQLITE_OK
!= rc
) {
940 const char *errmsg
= sqlite3_errmsg(db_ctx
->db
);
941 librdf_log(get_world(storage
), 0, LIBRDF_LOG_ERROR
, LIBRDF_FROM_STORAGE
, NULL
, "SQLite database %s open failed - %s", db_ctx
->name
, errmsg
);
945 // http://stackoverflow.com/a/6618833
946 if( db_ctx
->do_profile
) {
947 sqlite3_profile(db_ctx
->db
, &profile
, NULL
);
948 // sqlite3_trace(db_ctx->db, &trace, NULL);
952 // set DB session PRAGMAs
953 if( SYNC_OFF
<= db_ctx
->synchronous
) {
955 const size_t len
= snprintf(sql
, sizeof(sql
) - 1, "PRAGMA synchronous=%s;", synchronous_flags
[db_ctx
->synchronous
]);
956 assert(len
< sizeof(sql
) && "buffer too small.");
957 const sqlite_rc_t rc
= exec_stmt(db_ctx
->db
, sql
);
958 if( SQLITE_OK
!= rc
) {
964 const char *const sqls
[] = {
965 "PRAGMA foreign_keys = ON;",
966 "PRAGMA recursive_triggers = ON;",
967 "PRAGMA encoding = 'UTF-8';",
970 for( int v
= 0; sqls
[v
]; v
++ ) {
971 const sqlite_rc_t rc
= exec_stmt(db_ctx
->db
, sqls
[v
]);
972 if( SQLITE_OK
!= rc
) {
979 // check & update schema (run migrations)
981 sqlite_rc_t rc
= SQLITE_OK
;
982 sqlite3_stmt
*stmt
= NULL
;
983 prep_stmt(db_ctx
->db
, &stmt
, "PRAGMA user_version;");
984 if( SQLITE_ROW
!= ( rc
= sqlite3_step(stmt
) ) ) {
985 sqlite3_finalize(stmt
);
989 const int schema_version
= sqlite3_column_int(stmt
, 0);
990 if( SQLITE_DONE
!= ( rc
= sqlite3_step(stmt
) ) ) {
991 sqlite3_finalize(stmt
);
995 sqlite3_finalize(stmt
);
997 const char *const migrations
[] = {
998 // generated via tools/sql2c.sh sql/schema_mig_to_1.sql
999 "PRAGMA foreign_keys = ON;" "\n" \
1000 "PRAGMA recursive_triggers = ON;" "\n" \
1001 "PRAGMA encoding = 'UTF-8';" "\n" \
1002 " -- URIs for subjects and objects" "\n" \
1003 "CREATE TABLE so_uris (" "\n" \
1004 " id INTEGER PRIMARY KEY" "\n" \
1005 " ,uri TEXT NOT NULL -- UNIQUE -- redundant constraint (hash should do), could be dropped to save space" "\n" \
1007 " -- blank node IDs for subjects and objects" "\n" \
1008 "CREATE TABLE so_blanks (" "\n" \
1009 " id INTEGER PRIMARY KEY" "\n" \
1010 " ,blank TEXT NOT NULL -- UNIQUE -- redundant constraint (hash should do), could be dropped to save space" "\n" \
1012 " -- URIs for predicates" "\n" \
1013 "CREATE TABLE p_uris (" "\n" \
1014 " id INTEGER PRIMARY KEY" "\n" \
1015 " ,uri TEXT NOT NULL -- UNIQUE -- redundant constraint (hash should do), could be dropped to save space" "\n" \
1017 " -- URIs for literal types" "\n" \
1018 "CREATE TABLE t_uris (" "\n" \
1019 " id INTEGER PRIMARY KEY" "\n" \
1020 " ,uri TEXT NOT NULL -- UNIQUE -- redundant constraint (hash should do), could be dropped to save space" "\n" \
1022 " -- literal values" "\n" \
1023 "CREATE TABLE o_literals (" "\n" \
1024 " id INTEGER PRIMARY KEY" "\n" \
1025 " ,datatype_id INTEGER NULL REFERENCES t_uris(id)" "\n" \
1026 " ,language TEXT NULL" "\n" \
1027 " ,text TEXT NOT NULL" "\n" \
1029 " -- CREATE UNIQUE INDEX o_literals_index ON o_literals (text,language,datatype_id); -- redundant constraint (hash should do), could be dropped to save space" "\n" \
1030 " -- URIs for context" "\n" \
1031 "CREATE TABLE c_uris (" "\n" \
1032 " id INTEGER PRIMARY KEY" "\n" \
1033 " ,uri TEXT NOT NULL -- UNIQUE -- redundant constraint (hash should do), could be dropped to save space" "\n" \
1035 "CREATE TABLE triple_relations (" "\n" \
1036 " id INTEGER PRIMARY KEY" "\n" \
1037 " ,s_uri_id INTEGER NULL REFERENCES so_uris(id)" "\n" \
1038 " ,s_blank_id INTEGER NULL REFERENCES so_blanks(id)" "\n" \
1039 " ,p_uri_id INTEGER NOT NULL REFERENCES p_uris(id)" "\n" \
1040 " ,o_uri_id INTEGER NULL REFERENCES so_uris(id)" "\n" \
1041 " ,o_blank_id INTEGER NULL REFERENCES so_blanks(id)" "\n" \
1042 " ,o_lit_id INTEGER NULL REFERENCES o_literals(id)" "\n" \
1043 " ,c_uri_id INTEGER NULL REFERENCES c_uris(id)" "\n" \
1044 " , CONSTRAINT null_subject CHECK ( -- ensure uri/blank are mutually exclusive" "\n" \
1045 " (s_uri_id IS NOT NULL AND s_blank_id IS NULL) OR" "\n" \
1046 " (s_uri_id IS NULL AND s_blank_id IS NOT NULL)" "\n" \
1048 " , CONSTRAINT null_object CHECK ( -- ensure uri/blank/literal are mutually exclusive" "\n" \
1049 " (o_uri_id IS NOT NULL AND o_blank_id IS NULL AND o_lit_id IS NULL) OR" "\n" \
1050 " (o_uri_id IS NULL AND o_blank_id IS NOT NULL AND o_lit_id IS NULL) OR" "\n" \
1051 " (o_uri_id IS NULL AND o_blank_id IS NULL AND o_lit_id IS NOT NULL)" "\n" \
1054 " -- redundant constraint (hash should do), could be dropped to save space:" "\n" \
1055 " -- CREATE UNIQUE INDEX triple_relations_index ON triple_relations(s_uri_id,s_blank_id,p_uri_id,o_uri_id,o_blank_id,o_lit_id,c_uri_id);" "\n" \
1056 " -- optional indexes for lookup performance, mostly on DELETE." "\n" \
1057 "CREATE INDEX triple_relations_index_s_uri_id ON triple_relations(s_uri_id); -- WHERE s_uri_id IS NOT NULL;" "\n" \
1058 "CREATE INDEX triple_relations_index_s_blank_id ON triple_relations(s_blank_id); -- WHERE s_blank_id IS NOT NULL;" "\n" \
1059 "CREATE INDEX triple_relations_index_p_uri_id ON triple_relations(p_uri_id); -- WHERE p_uri_id IS NOT NULL;" "\n" \
1060 "CREATE INDEX triple_relations_index_o_uri_id ON triple_relations(o_uri_id); -- WHERE o_uri_id IS NOT NULL;" "\n" \
1061 "CREATE INDEX triple_relations_index_o_blank_id ON triple_relations(o_blank_id); -- WHERE s_blank_id IS NOT NULL;" "\n" \
1062 "CREATE INDEX triple_relations_index_o_lit_id ON triple_relations(o_lit_id); -- WHERE o_lit_id IS NOT NULL;" "\n" \
1063 "CREATE INDEX o_literals_index_datatype_id ON o_literals(datatype_id); -- WHERE datatype_id IS NOT NULL;" "\n" \
1064 "PRAGMA user_version=1;" "\n" \
1066 // generated via tools/sql2c.sh sql/schema_mig_to_2.sql
1067 "CREATE VIEW triples AS" "\n" \
1069 " -- all *_id (hashes):" "\n" \
1070 " triple_relations.id AS id" "\n" \
1072 " ,s_blank_id" "\n" \
1075 " ,o_blank_id" "\n" \
1077 " ,o_literals.datatype_id AS o_datatype_id" "\n" \
1079 " -- all joined values:" "\n" \
1080 " ,s_uris.uri AS s_uri" "\n" \
1081 " ,s_blanks.blank AS s_blank" "\n" \
1082 " ,p_uris.uri AS p_uri" "\n" \
1083 " ,o_uris.uri AS o_uri" "\n" \
1084 " ,o_blanks.blank AS o_blank" "\n" \
1085 " ,o_literals.text AS o_text" "\n" \
1086 " ,o_literals.language AS o_language" "\n" \
1087 " ,o_lit_uris.uri AS o_datatype" "\n" \
1088 " ,c_uris.uri AS c_uri" "\n" \
1089 "FROM triple_relations" "\n" \
1090 "LEFT OUTER JOIN so_uris AS s_uris ON triple_relations.s_uri_id = s_uris.id" "\n" \
1091 "LEFT OUTER JOIN so_blanks AS s_blanks ON triple_relations.s_blank_id = s_blanks.id" "\n" \
1092 "INNER JOIN p_uris AS p_uris ON triple_relations.p_uri_id = p_uris.id" "\n" \
1093 "LEFT OUTER JOIN so_uris AS o_uris ON triple_relations.o_uri_id = o_uris.id" "\n" \
1094 "LEFT OUTER JOIN so_blanks AS o_blanks ON triple_relations.o_blank_id = o_blanks.id" "\n" \
1095 "LEFT OUTER JOIN o_literals AS o_literals ON triple_relations.o_lit_id = o_literals.id" "\n" \
1096 "LEFT OUTER JOIN t_uris AS o_lit_uris ON o_literals.datatype_id = o_lit_uris.id" "\n" \
1097 "LEFT OUTER JOIN c_uris AS c_uris ON triple_relations.c_uri_id = c_uris.id" "\n" \
1099 "CREATE TRIGGER triples_insert INSTEAD OF INSERT ON triples" "\n" \
1100 "FOR EACH ROW BEGIN" "\n" \
1101 " -- subject uri/blank" "\n" \
1102 " INSERT OR IGNORE INTO so_uris (id,uri) VALUES (NEW.s_uri_id, NEW.s_uri);" "\n" \
1103 " INSERT OR IGNORE INTO so_blanks (id,blank) VALUES (NEW.s_blank_id, NEW.s_blank);" "\n" \
1104 " -- predicate uri" "\n" \
1105 " INSERT OR IGNORE INTO p_uris (id,uri) VALUES (NEW.p_uri_id, NEW.p_uri);" "\n" \
1106 " -- object uri/blank" "\n" \
1107 " INSERT OR IGNORE INTO so_uris (id,uri) VALUES (NEW.o_uri_id, NEW.o_uri);" "\n" \
1108 " INSERT OR IGNORE INTO so_blanks (id,blank) VALUES (NEW.o_blank_id, NEW.o_blank);" "\n" \
1109 " -- object literal" "\n" \
1110 " INSERT OR IGNORE INTO t_uris (id,uri) VALUES (NEW.o_datatype_id, NEW.o_datatype);" "\n" \
1111 " INSERT OR IGNORE INTO o_literals(id,datatype_id,language,text) VALUES (NEW.o_lit_id, NEW.o_datatype_id, NEW.o_language, NEW.o_text);" "\n" \
1112 " -- context uri" "\n" \
1113 " INSERT OR IGNORE INTO c_uris (id,uri) VALUES (NEW.c_uri_id, NEW.c_uri);" "\n" \
1115 " INSERT INTO triple_relations(id, s_uri_id, s_blank_id, p_uri_id, o_uri_id, o_blank_id, o_lit_id, c_uri_id)" "\n" \
1116 " VALUES (NEW.id, NEW.s_uri_id, NEW.s_blank_id, NEW.p_uri_id, NEW.o_uri_id, NEW.o_blank_id, NEW.o_lit_id, NEW.c_uri_id);" "\n" \
1118 "CREATE TRIGGER triples_delete INSTEAD OF DELETE ON triples" "\n" \
1119 "FOR EACH ROW BEGIN" "\n" \
1121 " DELETE FROM triple_relations WHERE id = OLD.id;" "\n" \
1122 " -- subject uri/blank" "\n" \
1123 " DELETE FROM so_uris WHERE (OLD.s_uri_id IS NOT NULL) AND (0 == (SELECT COUNT(id) FROM triple_relations WHERE s_uri_id = OLD.s_uri_id)) AND (id = OLD.s_uri_id);" "\n" \
1124 " DELETE FROM so_blanks WHERE (OLD.s_blank_id IS NOT NULL) AND (0 == (SELECT COUNT(id) FROM triple_relations WHERE s_blank_id = OLD.s_blank_id)) AND (id = OLD.s_blank_id);" "\n" \
1125 " -- predicate uri" "\n" \
1126 " DELETE FROM p_uris WHERE (OLD.p_uri_id IS NOT NULL) AND (0 == (SELECT COUNT(id) FROM triple_relations WHERE p_uri_id = OLD.p_uri_id)) AND (id = OLD.p_uri_id);" "\n" \
1127 " -- object uri/blank" "\n" \
1128 " DELETE FROM so_uris WHERE (OLD.o_uri_id IS NOT NULL) AND (0 == (SELECT COUNT(id) FROM triple_relations WHERE o_uri_id = OLD.o_uri_id)) AND (id = OLD.o_uri_id);" "\n" \
1129 " DELETE FROM so_blanks WHERE (OLD.o_blank_id IS NOT NULL) AND (0 == (SELECT COUNT(id) FROM triple_relations WHERE o_blank_id = OLD.o_blank_id)) AND (id = OLD.o_blank_id);" "\n" \
1130 " -- object literal" "\n" \
1131 " DELETE FROM o_literals WHERE (OLD.o_lit_id IS NOT NULL) AND (0 == (SELECT COUNT(id) FROM triple_relations WHERE o_lit_id = OLD.o_lit_id)) AND (id = OLD.o_lit_id);" "\n" \
1132 " DELETE FROM t_uris WHERE (OLD.o_datatype_id IS NOT NULL) AND (0 == (SELECT COUNT(id) FROM o_literals WHERE datatype_id = OLD.o_datatype_id)) AND (id = OLD.o_datatype_id);" "\n" \
1133 " -- context uri" "\n" \
1134 " DELETE FROM c_uris WHERE (OLD.c_uri_id IS NOT NULL) AND (0 == (SELECT COUNT(id) FROM triple_relations WHERE c_uri_id = OLD.c_uri_id)) AND (id = OLD.c_uri_id);" "\n" \
1136 "PRAGMA user_version=2;" "\n" \
1138 // generated via tools/sql2c.sh sql/schema_mig_to_3.sql
1139 "DROP TRIGGER triples_delete;" "\n" \
1140 "CREATE TRIGGER triples_delete INSTEAD OF DELETE ON triples" "\n" \
1141 "FOR EACH ROW BEGIN" "\n" \
1142 " -- subject uri/blank" "\n" \
1143 " DELETE FROM so_uris WHERE (OLD.s_uri_id IS NOT NULL) AND (0 == (SELECT COUNT(id) FROM triple_relations WHERE s_uri_id = OLD.s_uri_id)) AND (id = OLD.s_uri_id);" "\n" \
1144 " DELETE FROM so_blanks WHERE (OLD.s_blank_id IS NOT NULL) AND (0 == (SELECT COUNT(id) FROM triple_relations WHERE s_blank_id = OLD.s_blank_id)) AND (id = OLD.s_blank_id);" "\n" \
1145 " -- predicate uri" "\n" \
1146 " DELETE FROM p_uris WHERE (OLD.p_uri_id IS NOT NULL) AND (0 == (SELECT COUNT(id) FROM triple_relations WHERE p_uri_id = OLD.p_uri_id)) AND (id = OLD.p_uri_id);" "\n" \
1147 " -- object uri/blank" "\n" \
1148 " DELETE FROM so_uris WHERE (OLD.o_uri_id IS NOT NULL) AND (0 == (SELECT COUNT(id) FROM triple_relations WHERE o_uri_id = OLD.o_uri_id)) AND (id = OLD.o_uri_id);" "\n" \
1149 " DELETE FROM so_blanks WHERE (OLD.o_blank_id IS NOT NULL) AND (0 == (SELECT COUNT(id) FROM triple_relations WHERE o_blank_id = OLD.o_blank_id)) AND (id = OLD.o_blank_id);" "\n" \
1150 " -- object literal" "\n" \
1151 " DELETE FROM o_literals WHERE (OLD.o_lit_id IS NOT NULL) AND (0 == (SELECT COUNT(id) FROM triple_relations WHERE o_lit_id = OLD.o_lit_id)) AND (id = OLD.o_lit_id);" "\n" \
1152 " DELETE FROM t_uris WHERE (OLD.o_datatype_id IS NOT NULL) AND (0 == (SELECT COUNT(id) FROM o_literals WHERE datatype_id = OLD.o_datatype_id)) AND (id = OLD.o_datatype_id);" "\n" \
1153 " -- context uri" "\n" \
1154 " DELETE FROM c_uris WHERE (OLD.c_uri_id IS NOT NULL) AND (0 == (SELECT COUNT(id) FROM triple_relations WHERE c_uri_id = OLD.c_uri_id)) AND (id = OLD.c_uri_id);" "\n" \
1156 " DELETE FROM triple_relations WHERE id = OLD.id;" "\n" \
1158 "PRAGMA user_version=3;" "\n" \
1163 const size_t mig_count
= array_length(migrations
) - 1;
1164 assert(3 == mig_count
&& "migrations count wrong.");
1165 assert(!migrations
[mig_count
] && "migrations must be NULL terminated.");
1166 if( mig_count
< schema_version
) {
1167 // schema is more recent than this source file knows to handle.
1172 const sqlite_rc_t begin
= transaction_start(storage
);
1173 for( int v
= schema_version
; migrations
[v
]; v
++ ) {
1174 if( SQLITE_OK
!= ( rc
= exec_stmt(db_ctx
->db
, migrations
[v
]) ) ) {
1175 transaction_rollback(storage
, begin
);
1180 // assert new schema version
1181 sqlite3_stmt
*stmt
= NULL
;
1182 prep_stmt(db_ctx
->db
, &stmt
, "PRAGMA user_version");
1183 if( SQLITE_ROW
!= ( rc
= sqlite3_step(stmt
) ) ) {
1184 sqlite3_finalize(stmt
);
1188 const int v_new
= sqlite3_column_int(stmt
, 0);
1189 if( SQLITE_DONE
!= ( rc
= sqlite3_step(stmt
) ) ) {
1190 sqlite3_finalize(stmt
);
1194 sqlite3_finalize(stmt
);
1195 assert(v
+ 1 == v_new
&& "invalid schema version after migration.");
1198 if( SQLITE_OK
!= ( rc
= transaction_commit(storage
, begin
) ) ) {
1208 * librdf_storage_sqlite_get_feature:
1209 * @storage: #librdf_storage object
1210 * @feature: #librdf_uri feature property
1212 * Get the value of a storage feature.
1214 * Return value: #librdf_node feature value or NULL if no such feature
1215 * exists or the value is empty.
1217 static librdf_node
*pub_get_feature(librdf_storage
*storage
, librdf_uri
*feature
)
1219 assert(storage
&& "storage must be set");
1222 const char *feat
= (char *)librdf_uri_as_string(feature
);
1225 instance_t
*db_ctx
= get_instance(storage
);
1227 librdf_node
*ret
= NULL
;
1228 librdf_uri
*uri_xsd_boolean
= librdf_new_uri(get_world(storage
), (str_uri_t
)"http://www.w3.org/2000/10/XMLSchema#" "boolean");
1229 librdf_uri
*uri_xsd_unsignedShort
= librdf_new_uri(get_world(storage
), (str_uri_t
)"http://www.w3.org/2000/10/XMLSchema#" "unsignedShort");
1231 if( !ret
&& 0 == strcmp(LIBRDF_MODEL_FEATURE_CONTEXTS
, feat
) )
1232 ret
= librdf_new_node_from_typed_literal(get_world(storage
), (str_lit_val_t
)(true ? "1" : "0"), NULL
, uri_xsd_boolean
);
1233 if( !ret
&& 0 == strcmp( (char *)LIBRDF_STORAGE_SQLITE_MRO_FEATURE_SQLITE3_PROFILE
, feat
) )
1234 ret
= librdf_new_node_from_typed_literal(get_world(storage
), (str_lit_val_t
)(db_ctx
->do_profile
? "true" : "false"), NULL
, uri_xsd_boolean
);
1235 if( !ret
&& 0 == strcmp( (char *)LIBRDF_STORAGE_SQLITE_MRO_FEATURE_SQLITE3_EXPLAIN_QUERY_PLAN
, (char *)feat
) )
1236 ret
= librdf_new_node_from_typed_literal(get_world(storage
), (str_lit_val_t
)(db_ctx
->do_explain_query_plan
? "true" : "false"), NULL
, uri_xsd_boolean
);
1237 if( !ret
&& 0 == strcmp( (char *)LIBRDF_STORAGE_SQLITE_MRO_FEATURE_SQL_CACHE_MASK
, feat
) ) {
1239 snprintf(buf
, sizeof(buf
) - 1, "%d", db_ctx
->sql_cache_mask
);
1240 ret
= librdf_new_node_from_typed_literal(get_world(storage
), (str_uri_t
)buf
, NULL
, uri_xsd_unsignedShort
);
1243 librdf_free_uri(uri_xsd_boolean
);
1244 librdf_free_uri(uri_xsd_unsignedShort
);
1250 * librdf_storage_set_feature:
1251 * @storage: #librdf_storage object
1252 * @feature: #librdf_uri feature property
1253 * @value: #librdf_node feature property value
1255 * Set the value of a storage feature.
1257 * Return value: non 0 on failure (negative if no such feature)
1259 static int pub_set_feature(librdf_storage
*storage
, librdf_uri
*feature
, librdf_node
*value
)
1261 assert(storage
&& "storage must be set");
1264 const char *feat
= (char *)librdf_uri_as_string(feature
);
1267 const char *val
= (char *)librdf_node_get_literal_value(value
);
1268 // librdf_log(get_world(storage), 0, LIBRDF_LOG_DEBUG, LIBRDF_FROM_STORAGE, NULL, "pub_set_feature('%s', '%s')", feat, val);
1270 instance_t
*db_ctx
= get_instance(storage
);
1271 if( 0 == strcmp( (char *)LIBRDF_STORAGE_SQLITE_MRO_FEATURE_SQL_CACHE_MASK
, feat
) ) {
1272 if( 0 == strcmp("0", val
) ) {
1273 db_ctx
->sql_cache_mask
= 0;
1276 const long i
= strtol(val
, &end
, 10);
1277 if( NULL
== end
|| '\0' != *end
) {
1278 librdf_log(NULL
, 0, LIBRDF_LOG_ERROR
, LIBRDF_FROM_STORAGE
, NULL
, "invalid value: <%s> \"%s\"^^xsd:unsignedShort", feat
, val
);
1281 db_ctx
->sql_cache_mask
= ALL_PARAMS
& i
; // clip range
1283 // librdf_log(NULL, 0, LIBRDF_LOG_DEBUG, LIBRDF_FROM_STORAGE, NULL, "good value: <%s> \"%d\"^^xsd:unsignedShort", feat, db_ctx->sql_cache_mask);
1287 if( 0 == strcmp( (char *)LIBRDF_STORAGE_SQLITE_MRO_FEATURE_SQLITE3_PROFILE
, feat
) ) {
1288 if( 0 == strcmp("1", val
) || 0 == strcmp("true", val
) ) {
1289 db_ctx
->do_profile
= true;
1291 sqlite3_profile(db_ctx
->db
, &profile
, storage
);
1292 } else if( 0 == strcmp("0", val
) || 0 == strcmp("false", val
) ) {
1293 db_ctx
->do_profile
= false;
1295 sqlite3_profile(db_ctx
->db
, NULL
, NULL
);
1297 librdf_log(NULL
, 0, LIBRDF_LOG_ERROR
, LIBRDF_FROM_STORAGE
, NULL
, "invalid value: <%s> \"%s\"^^xsd:boolean", feat
, val
);
1303 if( 0 == strcmp( (char *)LIBRDF_STORAGE_SQLITE_MRO_FEATURE_SQLITE3_EXPLAIN_QUERY_PLAN
, feat
) ) {
1304 if( 0 == strcmp("1", val
) || 0 == strcmp("true", val
) )
1305 db_ctx
->do_explain_query_plan
= true;
1306 else if( 0 == strcmp("0", val
) || 0 == strcmp("false", val
) )
1307 db_ctx
->do_explain_query_plan
= false;
1309 librdf_log(NULL
, 0, LIBRDF_LOG_ERROR
, LIBRDF_FROM_STORAGE
, NULL
, "invalid value: <%s> \"%s\"^^xsd:boolean", feat
, val
);
1318 #pragma mark Transactions
1321 static sqlite_rc_t
pub_transaction_start(librdf_storage
*storage
)
1323 return transaction_start(storage
);
1327 static sqlite_rc_t
pub_transaction_commit(librdf_storage
*storage
)
1329 return transaction_commit(storage
, SQLITE_OK
);
1333 static sqlite_rc_t
pub_transaction_rollback(librdf_storage
*storage
)
1335 return transaction_rollback(storage
, SQLITE_OK
);
1339 #pragma mark Iterator
1344 librdf_storage
*storage
;
1345 librdf_statement
*pattern
;
1346 librdf_statement
*statement
;
1347 librdf_node
*context
;
1357 static int pub_iter_end_of_stream(void *_ctx
)
1359 assert(_ctx
&& "context mustn't be NULL");
1360 iterator_t
*ctx
= (iterator_t
*)_ctx
;
1361 return SQLITE_ROW
!= ctx
->rc
;
1365 static int pub_iter_next_statement(void *_ctx
)
1367 assert(_ctx
&& "context mustn't be NULL");
1368 iterator_t
*ctx
= (iterator_t
*)_ctx
;
1369 if( pub_iter_end_of_stream(ctx
) )
1372 ctx
->rc
= sqlite3_step(ctx
->stmt
);
1373 if( pub_iter_end_of_stream(ctx
) )
1379 static void *pub_iter_get_statement(void *_ctx
, const int _flags
)
1381 assert(_ctx
&& "context mustn't be NULL");
1382 const librdf_iterator_get_method_flags flags
= (librdf_iterator_get_method_flags
)_flags
;
1383 iterator_t
*ctx
= (iterator_t
*)_ctx
;
1386 case LIBRDF_ITERATOR_GET_METHOD_GET_OBJECT
: {
1387 if( ctx
->dirty
&& !pub_iter_end_of_stream(_ctx
) ) {
1388 assert(ctx
->statement
&& "statement mustn't be NULL");
1389 librdf_world
*w
= get_world(ctx
->storage
);
1390 librdf_statement
*st
= ctx
->statement
;
1391 sqlite3_stmt
*stm
= ctx
->stmt
;
1392 librdf_statement_clear(st
);
1393 // stmt columns refer to find_triples_sql
1396 librdf_node
*node
= NULL
;
1397 const str_uri_t uri
= column_uri_string(stm
, IDX_S_URI
);
1399 assert('\0' != uri
[0] && "empty uri");
1400 node
= librdf_new_node_from_uri_string(w
, uri
);
1403 const str_blank_t blank
= column_blank_string(stm
, IDX_S_BLANK
);
1405 assert('\0' != blank
[0] && "empty blank");
1406 node
= librdf_new_node_from_blank_identifier(w
, blank
);
1411 librdf_statement_set_subject(st
, node
);
1415 librdf_node
*node
= NULL
;
1416 const str_uri_t uri
= column_uri_string(stm
, IDX_P_URI
);
1418 node
= librdf_new_node_from_uri_string(w
, uri
);
1421 librdf_statement_set_predicate(st
, node
);
1425 librdf_node
*node
= NULL
;
1426 const str_uri_t uri
= column_uri_string(stm
, IDX_O_URI
);
1428 node
= librdf_new_node_from_uri_string(w
, uri
);
1430 const str_blank_t blank
= column_blank_string(stm
, IDX_O_BLANK
);
1432 node
= librdf_new_node_from_blank_identifier(w
, blank
);
1435 const str_lit_val_t val
= (str_lit_val_t
)sqlite3_column_text(stm
, IDX_O_TEXT
);
1436 const str_lang_t lang
= (str_lang_t
)column_language(stm
, IDX_O_LANGUAGE
);
1437 const str_uri_t uri
= column_uri_string(stm
, IDX_O_DATATYPE
);
1438 librdf_uri
*t
= uri
? librdf_new_uri(w
, uri
) : NULL
;
1439 node
= librdf_new_node_from_typed_literal(w
, val
, lang
, t
);
1444 librdf_statement_set_object(st
, node
);
1446 assert(librdf_statement_is_complete(st
) && "found statement must be complete");
1447 assert( ( (NULL
== ctx
->pattern
) || librdf_statement_match(st
, ctx
->pattern
) ) && "match candidate doesn't match." );
1448 assert(st
== ctx
->statement
&& "mismatch.");
1451 assert(librdf_statement_is_complete(ctx
->statement
) && "found statement must be complete");
1452 assert( ( (NULL
== ctx
->pattern
) || librdf_statement_match(ctx
->statement
, ctx
->pattern
) ) && "match candidate doesn't match." );
1453 return ctx
->statement
;
1455 case LIBRDF_ITERATOR_GET_METHOD_GET_CONTEXT
:
1456 return ctx
->context
;
1458 librdf_log(get_world(ctx
->storage
), 0, LIBRDF_LOG_ERROR
, LIBRDF_FROM_STORAGE
, NULL
, "Unknown iterator method flag %d", flags
);
1465 static void pub_iter_finished(void *_ctx
)
1467 assert(_ctx
&& "context mustn't be NULL");
1468 iterator_t
*ctx
= (iterator_t
*)_ctx
;
1470 librdf_free_statement(ctx
->pattern
);
1471 if( ctx
->statement
)
1472 librdf_free_statement(ctx
->statement
);
1473 librdf_storage_remove_reference(ctx
->storage
);
1474 transaction_rollback(ctx
->storage
, ctx
->txn
);
1475 sqlite3_finalize(ctx
->stmt
);
1477 LIBRDF_FREE(iterator_t
*, ctx
);
1483 librdf_storage
*storage
;
1484 librdf_node
*context
;
1493 static int context_iter_is_end(void *_ctx
)
1495 assert(_ctx
&& "context mustn't be NULL");
1496 context_iterator_t
*ctx
= (context_iterator_t
*)_ctx
;
1497 return SQLITE_ROW
!= ctx
->rc
;
1501 static int context_iter_get_next(void *_ctx
)
1503 assert(_ctx
&& "context mustn't be NULL");
1504 context_iterator_t
*ctx
= (context_iterator_t
*)_ctx
;
1505 if( context_iter_is_end(ctx
) )
1508 ctx
->rc
= sqlite3_step(ctx
->stmt
);
1509 if( context_iter_is_end(ctx
) )
1515 static void *context_iter_get_context(void *_ctx
, const int _flags
)
1517 assert(_ctx
&& "context mustn't be NULL");
1518 const librdf_iterator_get_method_flags flags
= (librdf_iterator_get_method_flags
)_flags
;
1519 context_iterator_t
*ctx
= (context_iterator_t
*)_ctx
;
1522 case LIBRDF_ITERATOR_GET_METHOD_GET_OBJECT
:
1524 case LIBRDF_ITERATOR_GET_METHOD_GET_CONTEXT
:
1527 librdf_log(get_world(ctx
->storage
), 0, LIBRDF_LOG_ERROR
, LIBRDF_FROM_STORAGE
, NULL
, "Unknown iterator method flag %d", flags
);
1531 if( ctx
->dirty
&& !context_iter_is_end(_ctx
) ) {
1532 assert(ctx
->context
&& "context mustn't be NULL");
1533 librdf_world
*w
= get_world(ctx
->storage
);
1534 sqlite3_stmt
*stm
= ctx
->stmt
;
1535 librdf_node
*node
= NULL
;
1536 const str_uri_t uri
= column_uri_string(stm
, 0);
1538 node
= librdf_new_node_from_uri_string(w
, uri
);
1540 librdf_free_node(ctx
->context
);
1542 ctx
->context
= node
;
1546 return ctx
->context
;
1550 static void context_iter_finished(void *_ctx
)
1552 assert(_ctx
&& "context mustn't be NULL");
1553 context_iterator_t
*ctx
= (context_iterator_t
*)_ctx
;
1555 librdf_free_node(ctx
->context
);
1557 librdf_storage_remove_reference(ctx
->storage
);
1558 sqlite3_finalize(ctx
->stmt
);
1560 LIBRDF_FREE(iterator_t
*, ctx
);
1564 #pragma mark Query & Iterate
1567 static int pub_size(librdf_storage
*storage
)
1569 instance_t
*db_ctx
= get_instance(storage
);
1570 sqlite3_stmt
*stmt
= prep_stmt(db_ctx
->db
, &(db_ctx
->stmt_size
), "SELECT COUNT(id) FROM triple_relations");
1571 const sqlite_rc_t rc
= sqlite3_step(stmt
);
1572 return SQLITE_ROW
== rc
? sqlite3_column_int(stmt
, 0) : -1;
1576 static librdf_iterator
*pub_get_contexts(librdf_storage
*storage
)
1578 instance_t
*db_ctx
= get_instance(storage
);
1580 context_iterator_t
*iter
= LIBRDF_CALLOC(context_iterator_t
*, sizeof(context_iterator_t
), 1);
1581 iter
->storage
= storage
;
1582 iter
->stmt
= prep_stmt(db_ctx
->db
, &(iter
->stmt
), "SELECT uri FROM c_uris");
1584 LIBRDF_FREE(context_iterator_t
*, iter
);
1587 iter
->rc
= sqlite3_step(iter
->stmt
);
1589 librdf_storage_add_reference(iter
->storage
);
1591 librdf_iterator
*iterator
= librdf_new_iterator(get_world(storage
), iter
, &context_iter_is_end
, &context_iter_get_next
, &context_iter_get_context
, &context_iter_finished
);
1593 context_iter_finished(iter
);
1599 static int pub_contains_statement(librdf_storage
*storage
, librdf_statement
*statement
)
1601 return NULL
!= find_statement(storage
, NULL
, statement
, false);
1605 static librdf_stream
*pub_context_find_statements(librdf_storage
*storage
, librdf_statement
*statement
, librdf_node
*context_node
)
1607 librdf_node
*s
= librdf_statement_get_subject(statement
);
1608 librdf_node
*p
= librdf_statement_get_predicate(statement
);
1609 librdf_node
*o
= librdf_statement_get_object(statement
);
1611 // build the bitmask of parameters to set (non-NULL)
1612 const int params
= 0
1613 | (LIBRDF_NODE_TYPE_RESOURCE
== node_type(s
) ? P_S_URI
: 0)
1614 | (LIBRDF_NODE_TYPE_BLANK
== node_type(s
) ? P_S_BLANK
: 0)
1615 | (LIBRDF_NODE_TYPE_RESOURCE
== node_type(p
) ? P_P_URI
: 0)
1616 | (LIBRDF_NODE_TYPE_RESOURCE
== node_type(o
) ? P_O_URI
: 0)
1617 | (LIBRDF_NODE_TYPE_BLANK
== node_type(o
) ? P_O_BLANK
: 0)
1618 | (LIBRDF_NODE_TYPE_LITERAL
== node_type(o
) ? P_O_TEXT
: 0)
1619 | (NULL
!= literal_type_uri(o
) ? P_O_DATATYPE
: 0)
1620 | (NULL
!= literal_language(o
) ? P_O_LANGUAGE
: 0)
1621 | (context_node
? P_C_URI
: 0)
1623 assert(params
<= ALL_PARAMS
&& "params bitmask overflow");
1625 const sqlite_rc_t begin
= RET_ERROR
; // transaction_start(storage);
1626 instance_t
*db_ctx
= get_instance(storage
);
1628 sqlite3_stmt
*stmt
= NULL
;
1630 const char find_triples_sql
[] = // generated via tools/sql2c.sh find_triples.sql
1631 " -- result columns must match as in enum idx_triple_column_t" "\n" \
1633 " -- all *_id (hashes):" "\n" \
1636 " ,s_blank_id" "\n" \
1639 " ,o_blank_id" "\n" \
1641 " ,o_datatype_id" "\n" \
1643 " -- all values:" "\n" \
1650 " ,o_language" "\n" \
1651 " ,o_datatype" "\n" \
1653 "FROM triples" "\n" \
1655 " -- subject" "\n" \
1656 "AND s_uri_id = :s_uri_id" "\n" \
1657 "AND s_blank_id = :s_blank_id" "\n" \
1658 "AND p_uri_id = :p_uri_id" "\n" \
1660 "AND o_uri_id = :o_uri_id" "\n" \
1661 "AND o_blank_id = :o_blank_id" "\n" \
1662 "AND o_lit_id = :o_lit_id" "\n" \
1663 " -- context node" "\n" \
1664 "AND c_uri_id = :c_uri_id" "\n" \
1667 // create a SQL working copy (on stack) to fiddle with.
1668 const size_t siz
= sizeof(find_triples_sql
);
1670 strncpy(sql
, find_triples_sql
, siz
);
1671 // sculpt the SQL instead building it: comment out the NULL parameter terms
1672 if( 0 == (P_S_URI
& params
) )
1673 strncpy(strstr(sql
, "AND s_uri_id"), "-- ", 3);
1674 assert('-' != sql
[0] && "'AND s_uri_id' not found in find_triples.sql");
1675 if( 0 == (P_S_BLANK
& params
) )
1676 strncpy(strstr(sql
, "AND s_blank_id"), "-- ", 3);
1677 assert('-' != sql
[0] && "'AND s_blank_id' not found in find_triples.sql");
1678 if( 0 == (P_P_URI
& params
) )
1679 strncpy(strstr(sql
, "AND p_uri_id"), "-- ", 3);
1680 assert('-' != sql
[0] && "'AND p_uri_id' not found in find_triples.sql");
1681 if( 0 == (P_O_URI
& params
) )
1682 strncpy(strstr(sql
, "AND o_uri_id"), "-- ", 3);
1683 assert('-' != sql
[0] && "'AND o_uri_id' not found in find_triples.sql");
1684 if( 0 == (P_O_BLANK
& params
) )
1685 strncpy(strstr(sql
, "AND o_blank_id"), "-- ", 3);
1686 assert('-' != sql
[0] && "'AND o_blank_id' not found in find_triples.sql");
1687 if( 0 == (P_O_TEXT
& params
) )
1688 strncpy(strstr(sql
, "AND o_lit_id"), "-- ", 3);
1689 assert('-' != sql
[0] && "'AND o_lit_id' not found in find_triples.sql");
1690 if( 0 == (P_C_URI
& params
) )
1691 strncpy(strstr(sql
, "AND c_uri_id"), "-- ", 3);
1692 assert('-' != sql
[0] && "'AND c_uri_id' not found in find_triples.sql");
1694 librdf_log(librdf_storage_get_world(storage
), 0, LIBRDF_LOG_INFO
, LIBRDF_FROM_STORAGE
, NULL
, "Created SQL statement #%d", params
);
1695 prep_stmt(db_ctx
->db
, &stmt
, sql
);
1696 } // else if( false ) {
1697 // toggle via "profile" feature?
1698 // librdf_log( librdf_storage_get_world(storage), 0, LIBRDF_LOG_INFO, LIBRDF_FROM_STORAGE, NULL, "%s", librdf_statement_to_string(statement) );
1701 const sqlite_rc_t rc
= bind_stmt(db_ctx
, statement
, context_node
, stmt
);
1702 assert(SQLITE_OK
== rc
&& "find_statements: failed to bind SQL parameters");
1704 if( db_ctx
->do_explain_query_plan
) {
1705 librdf_log(librdf_storage_get_world(storage
), 0, LIBRDF_LOG_INFO
, LIBRDF_FROM_STORAGE
, NULL
, "Execute SQL statement #%d", params
);
1706 printExplainQueryPlan(stmt
);
1708 librdf_world
*w
= get_world(storage
);
1710 iterator_t
*iter
= LIBRDF_CALLOC(iterator_t
*, sizeof(iterator_t
), 1);
1711 iter
->storage
= storage
;
1712 iter
->context
= context_node
;
1713 iter
->pattern
= librdf_new_statement_from_statement(statement
);
1716 iter
->rc
= sqlite3_step(stmt
);
1717 iter
->statement
= librdf_new_statement(w
);
1720 librdf_storage_add_reference(iter
->storage
);
1721 librdf_stream
*stream
= librdf_new_stream(w
, iter
, &pub_iter_end_of_stream
, &pub_iter_next_statement
, &pub_iter_get_statement
, &pub_iter_finished
);
1727 static librdf_stream
*pub_find_statements(librdf_storage
*storage
, librdf_statement
*statement
)
1729 return pub_context_find_statements(storage
, statement
, NULL
);
1733 static librdf_stream
*pub_context_serialise(librdf_storage
*storage
, librdf_node
*context_node
)
1735 return pub_context_find_statements(storage
, NULL
, context_node
);
1739 static librdf_stream
*pub_serialise(librdf_storage
*storage
)
1741 return pub_context_serialise(storage
, NULL
);
1748 static int pub_context_add_statement(librdf_storage
*storage
, librdf_node
*context_node
, librdf_statement
*statement
)
1754 // librdf_log( librdf_storage_get_world(storage), 0, LIBRDF_LOG_ERROR, LIBRDF_FROM_STORAGE, NULL, "%s", librdf_statement_to_string(statement) );
1755 return NULL
== find_statement(storage
, context_node
, statement
, true) ? RET_ERROR
: RET_OK
;
1759 static int pub_context_add_statements(librdf_storage
*storage
, librdf_node
*context_node
, librdf_stream
*statement_stream
)
1761 const sqlite_rc_t txn
= transaction_start(storage
);
1762 for( ; !librdf_stream_end(statement_stream
); librdf_stream_next(statement_stream
) ) {
1763 librdf_statement
*stmt
= librdf_stream_get_object(statement_stream
);
1764 const int rc
= pub_context_add_statement(storage
, context_node
, stmt
);
1765 if( RET_OK
!= rc
) {
1766 transaction_rollback(storage
, txn
);
1770 return transaction_commit(storage
, txn
);
1774 static int pub_add_statement(librdf_storage
*storage
, librdf_statement
*statement
)
1776 return pub_context_add_statement(storage
, NULL
, statement
);
1780 static int pub_add_statements(librdf_storage
*storage
, librdf_stream
*statement_stream
)
1782 return pub_context_add_statements(storage
, NULL
, statement_stream
);
1789 static int pub_context_remove_statement(librdf_storage
*storage
, librdf_node
*context_node
, librdf_statement
*statement
)
1793 if( !librdf_statement_is_complete(statement
) )
1795 assert(storage
&& "must be set");
1797 instance_t
*db_ctx
= get_instance(storage
);
1799 const hash_t stmt_id
= stmt_hash(statement
, context_node
, db_ctx
->digest
);
1800 assert(!isNULL_ID(stmt_id
) && "mustn't be nil");
1802 sqlite3_stmt
*stmt
= prep_stmt(db_ctx
->db
, &(db_ctx
->stmt_triple_delete
), "DELETE FROM triples WHERE id = :stmt_id");
1804 const sqlite_rc_t rc
= bind_int(stmt
, ":stmt_id", stmt_id
);
1805 if( SQLITE_OK
!= rc
)
1808 const sqlite_rc_t rc
= sqlite3_step(stmt
);
1809 return SQLITE_DONE
== rc
? RET_OK
: rc
;
1813 static int pub_remove_statement(librdf_storage
*storage
, librdf_statement
*statement
)
1815 return pub_context_remove_statement(storage
, NULL
, statement
);
1820 static int pub_context_remove_statements(librdf_storage
*storage
, librdf_node
*context_node
)
1822 const sqlite_rc_t txn
= transaction_start(storage
);
1823 for( librdf_statement
*stmt
= librdf_stream_get_object(statement_stream
); !librdf_stream_end(statement_stream
); librdf_stream_next(statement_stream
) ) {
1824 const int rc
= pub_context_remove_statement(storage
, context_node
, stmt
);
1825 if( RET_OK
!= rc
) {
1826 transaction_rollback(storage
, txn
);
1830 return transaction_commit(storage
, txn
);
1837 #pragma mark Register Storage Factory
1840 static void register_factory(librdf_storage_factory
*factory
)
1842 assert(!strcmp(factory
->name
, LIBRDF_STORAGE_SQLITE_MRO
) && "wrong factory name");
1844 factory
->version
= LIBRDF_STORAGE_INTERFACE_VERSION
;
1845 factory
->init
= pub_init
;
1846 factory
->terminate
= pub_terminate
;
1847 factory
->open
= pub_open
;
1848 factory
->close
= pub_close
;
1849 factory
->size
= pub_size
;
1850 factory
->add_statement
= pub_add_statement
;
1851 factory
->add_statements
= pub_add_statements
;
1852 factory
->remove_statement
= pub_remove_statement
;
1853 factory
->contains_statement
= pub_contains_statement
;
1854 factory
->serialise
= pub_serialise
;
1855 factory
->find_statements
= pub_find_statements
;
1856 factory
->context_add_statement
= pub_context_add_statement
;
1857 factory
->context_add_statements
= pub_context_add_statements
;
1858 factory
->context_remove_statement
= pub_context_remove_statement
;
1859 // factory->context_remove_statements = pub_context_remove_statements; is this a 'clear' ?
1860 factory
->context_serialise
= pub_context_serialise
;
1861 factory
->find_statements_in_context
= pub_context_find_statements
;
1862 factory
->get_contexts
= pub_get_contexts
;
1863 factory
->get_feature
= pub_get_feature
;
1864 factory
->set_feature
= pub_set_feature
;
1865 factory
->transaction_start
= pub_transaction_start
;
1866 factory
->transaction_commit
= pub_transaction_commit
;
1867 factory
->transaction_rollback
= pub_transaction_rollback
;
1871 int librdf_init_storage_sqlite_mro(librdf_world
*world
)
1873 return librdf_storage_register_factory(world
, LIBRDF_STORAGE_SQLITE_MRO
, "SQLite", ®ister_factory
);