rdf_storage_sqlite_mro.c 73 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875
  1. //
  2. // rdf_storage_sqlite_mro.c
  3. //
  4. // Created by Marcus Rohrmoser on 19.05.14.
  5. //
  6. // Copyright (c) 2014-2018, Marcus Rohrmoser mobile Software, http://mro.name/~me
  7. // All rights reserved.
  8. //
  9. // Redistribution and use in source and binary forms, with or without modification, are permitted
  10. // provided that the following conditions are met:
  11. //
  12. // 1. Redistributions of source code must retain the above copyright notice, this list of conditions
  13. // and the following disclaimer.
  14. //
  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/ .
  17. //
  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.
  26. //
  27. #include "rdf_storage_sqlite_mro.h"
  28. #define NAMESPACE "http://purl.mro.name/librdf.sqlite/"
  29. const char *LIBRDF_STORAGE_SQLITE_MRO = NAMESPACE;
  30. const unsigned char *LIBRDF_STORAGE_SQLITE_MRO_FEATURE_SQL_CACHE_MASK = (unsigned char *)NAMESPACE "feature/sql/cache/mask";
  31. const unsigned char *LIBRDF_STORAGE_SQLITE_MRO_FEATURE_SQLITE3_PROFILE = (unsigned char *)NAMESPACE "feature/sqlite3/profile";
  32. const unsigned char *LIBRDF_STORAGE_SQLITE_MRO_FEATURE_SQLITE3_EXPLAIN_QUERY_PLAN = (unsigned char *)NAMESPACE "feature/sqlite3/explain_query_plan";
  33. #define LIBRDF_NAMESPACE_XSD "http://www.w3.org/2000/10/XMLSchema#"
  34. #include <stdlib.h>
  35. // #include <stdio.h>
  36. #include <string.h>
  37. #include <unistd.h>
  38. #include <redland.h>
  39. #include <rdf_storage.h>
  40. #include <sqlite3.h>
  41. #include <stdint.h>
  42. #include <stdbool.h>
  43. #include <errno.h>
  44. #if DEBUG
  45. #undef NDEBUG
  46. #else
  47. #define NDEBUG 1
  48. #endif
  49. #include <assert.h>
  50. #define array_length(a) ( sizeof(a) / sizeof( (a)[0] ) )
  51. #pragma mark Basic Types & Constants
  52. typedef sqlite3_uint64 hash_t;
  53. static const hash_t NULL_ID = 0;
  54. static inline bool isNULL_ID(const hash_t x)
  55. {
  56. return NULL_ID == x;
  57. }
  58. #define RET_ERROR 1
  59. #define RET_OK 0
  60. /** C-String type for URIs. */
  61. typedef unsigned char *str_uri_t;
  62. /** C-String type for blank identifiers. */
  63. typedef unsigned char *str_blank_t;
  64. /** C-String type for literal values. */
  65. typedef unsigned char *str_lit_val_t;
  66. /** C-String type for (xml) language ids. */
  67. typedef char *str_lang_t;
  68. /** index into synchronous_flags */
  69. typedef enum {
  70. SYNC_UNKONWN = -1,
  71. SYNC_OFF = 0,
  72. SYNC_NORMAL = 1,
  73. SYNC_FULL = 2
  74. } syncronous_flag_t;
  75. static const char *const synchronous_flags[4] = {
  76. "off", "normal", "full", NULL
  77. };
  78. typedef enum {
  79. P_S_URI = 1 << 0,
  80. P_S_BLANK = 1 << 1,
  81. P_P_URI = 1 << 2,
  82. P_O_URI = 1 << 3,
  83. P_O_BLANK = 1 << 4,
  84. P_O_TEXT = 1 << 5,
  85. P_O_LANGUAGE = 1 << 6,
  86. P_O_DATATYPE = 1 << 7,
  87. P_C_URI = 1 << 8
  88. } sql_find_param_t;
  89. #define ALL_PARAMS ( (P_C_URI << 1) - 1 )
  90. typedef struct
  91. {
  92. sqlite3 *db;
  93. librdf_digest *digest;
  94. const char *name;
  95. bool is_new;
  96. syncronous_flag_t synchronous;
  97. bool in_transaction;
  98. bool do_profile;
  99. bool do_explain_query_plan;
  100. sql_find_param_t sql_cache_mask;
  101. // compiled statements, lazy init
  102. sqlite3_stmt *stmt_txn_start;
  103. sqlite3_stmt *stmt_txn_commit;
  104. sqlite3_stmt *stmt_txn_rollback;
  105. sqlite3_stmt *stmt_triple_find; // complete triples
  106. sqlite3_stmt *stmt_triple_insert;
  107. sqlite3_stmt *stmt_triple_delete;
  108. sqlite3_stmt *stmt_size;
  109. }
  110. instance_t;
  111. #pragma mark librdf convenience
  112. #define LIBRDF_MALLOC(type, size) (type)malloc(size)
  113. #define LIBRDF_CALLOC(type, size, count) (type)calloc(count, size)
  114. #define LIBRDF_FREE(type, ptr) free( (type)ptr )
  115. // #define LIBRDF_BAD_CAST(t, v) (t)(v)
  116. static inline instance_t *get_instance(librdf_storage *storage)
  117. {
  118. return (instance_t *)librdf_storage_get_instance(storage);
  119. }
  120. static inline librdf_world *get_world(librdf_storage *storage)
  121. {
  122. return librdf_storage_get_world(storage);
  123. }
  124. static inline void free_hash(librdf_hash *hash)
  125. {
  126. if( hash )
  127. librdf_free_hash(hash);
  128. }
  129. static inline librdf_node_type node_type(librdf_node *node)
  130. {
  131. return NULL == node ? LIBRDF_NODE_TYPE_UNKNOWN : librdf_node_get_type(node);
  132. }
  133. static inline librdf_uri *literal_type_uri(librdf_node *o)
  134. {
  135. if( NULL == o || LIBRDF_NODE_TYPE_LITERAL != node_type(o) )
  136. return NULL;
  137. return librdf_node_get_literal_value_datatype_uri(o);
  138. }
  139. static inline char *literal_language(librdf_node *o)
  140. {
  141. if( NULL == o || LIBRDF_NODE_TYPE_LITERAL != node_type(o) )
  142. return NULL;
  143. return librdf_node_get_literal_value_language(o);
  144. }
  145. /* Copy first 8 bytes of digest into 64bit using a method portable across big/little endianness.
  146. */
  147. static hash_t digest_hash(librdf_digest *digest)
  148. {
  149. assert(digest && "must be set");
  150. librdf_digest_final(digest);
  151. assert(librdf_digest_get_digest_length(digest) >= sizeof(hash_t) && "digest length too small");
  152. const int byte_count = 8;
  153. const int bit_per_byte = 8;
  154. assert(byte_count == sizeof(hash_t) && "made for 8-byte (64-bit) hashes");
  155. uint8_t *diges = (uint8_t *)librdf_digest_get_digest(digest);
  156. sqlite3_uint64 ret = 0; // enforce unsigned
  157. for( int i = byte_count - 1; i >= 0; i-- ) {
  158. ret <<= bit_per_byte;
  159. ret += diges[i];
  160. }
  161. assert(!isNULL_ID(ret) && "null hash");
  162. return (hash_t)ret;
  163. }
  164. static hash_t hash_uri(librdf_uri *uri, librdf_digest *digest)
  165. {
  166. if( !uri )
  167. return NULL_ID;
  168. assert(digest && "digest must be set.");
  169. size_t len = 0;
  170. const unsigned char *s = librdf_uri_as_counted_string(uri, &len);
  171. assert(s && "uri NULL");
  172. assert(len && "uri length 0");
  173. librdf_digest_init(digest);
  174. librdf_digest_update(digest, s, len);
  175. return digest_hash(digest);
  176. }
  177. static hash_t node_hash_uri(librdf_node *node, librdf_digest *digest)
  178. {
  179. return hash_uri(LIBRDF_NODE_TYPE_RESOURCE == node_type(node) ? librdf_node_get_uri(node) : NULL, digest);
  180. }
  181. static hash_t node_hash_blank(librdf_node *node, librdf_digest *digest)
  182. {
  183. if( LIBRDF_NODE_TYPE_BLANK != node_type(node) )
  184. return NULL_ID;
  185. assert(digest && "digest must be set.");
  186. size_t len = 0;
  187. unsigned char *b = librdf_node_get_counted_blank_identifier(node, &len);
  188. assert(b && "blank NULL");
  189. assert(len && "blank len 0");
  190. librdf_digest_init(digest);
  191. librdf_digest_update(digest, b, len);
  192. return digest_hash(digest);
  193. }
  194. static hash_t node_hash_literal(librdf_node *node, librdf_digest *digest)
  195. {
  196. if( LIBRDF_NODE_TYPE_LITERAL != node_type(node) )
  197. return NULL_ID;
  198. assert(digest && "digest must be set.");
  199. librdf_digest_init(digest);
  200. {
  201. size_t len = 0;
  202. unsigned char *str = librdf_node_get_literal_value_as_counted_string(node, &len);
  203. assert(str && "literal without value");
  204. assert(strlen( (char *)str ) == len && "TODO: NUL terminate or limit length!");
  205. librdf_digest_update(digest, str, len);
  206. }
  207. librdf_uri *uri = librdf_node_get_literal_value_datatype_uri(node);
  208. if( uri ) {
  209. size_t len = 0;
  210. const unsigned char *str = librdf_uri_as_counted_string(uri, &len);
  211. librdf_digest_update(digest, str, len);
  212. }
  213. const char *l = librdf_node_get_literal_value_language(node);
  214. if( l )
  215. librdf_digest_update( digest, (unsigned char *)l, strlen(l) );
  216. return digest_hash(digest);
  217. }
  218. /** https://stackoverflow.com/questions/2590677/how-do-i-combine-hash-values-in-c0x
  219. */
  220. static inline hash_t hash_combine(const hash_t seed, const hash_t b)
  221. {
  222. // return seed ^ ( b + 0x9e3779b9 + (seed << 6) + (seed >> 2) );
  223. // http://stackoverflow.com/a/4948967 and https://stackoverflow.com/questions/4948780/magic-number-in-boosthash-combine#comment35569848_4948967
  224. // $ python -c "import math; print hex(int(2**64 / ((1 + math.sqrt(5)) / 2)))"
  225. return seed ^ ( b + 0x9e3779b97f4a7800L + (seed << 6) + (seed >> 2) );
  226. }
  227. 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)
  228. {
  229. hash_t stmt_id = NULL_ID;
  230. stmt_id = hash_combine(stmt_id, s_uri_id);
  231. stmt_id = hash_combine(stmt_id, s_blank_id);
  232. stmt_id = hash_combine(stmt_id, p_uri_id);
  233. stmt_id = hash_combine(stmt_id, o_uri_id);
  234. stmt_id = hash_combine(stmt_id, o_blank_id);
  235. stmt_id = hash_combine(stmt_id, o_lit_id);
  236. // stmt_id ^= o_type_id;
  237. stmt_id = hash_combine(stmt_id, c_uri_id);
  238. return stmt_id;
  239. }
  240. static hash_t stmt_hash(librdf_statement *stmt, librdf_node *context_node, librdf_digest *digest)
  241. {
  242. if( !stmt )
  243. return NULL_ID;
  244. librdf_node *s = librdf_statement_get_subject(stmt);
  245. librdf_node *p = librdf_statement_get_predicate(stmt);
  246. librdf_node *o = librdf_statement_get_object(stmt);
  247. 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) );
  248. }
  249. #pragma mark Sqlite Debug/Profile
  250. /* https://sqlite.org/eqp.html#section_2
  251. ** Argument pStmt is a prepared SQL statement. This function compiles
  252. ** an EXPLAIN QUERY PLAN command to report on the prepared statement,
  253. ** and prints the report to stdout using printf().
  254. */
  255. static int printExplainQueryPlan(sqlite3_stmt *pStmt)
  256. {
  257. const char *zSql = sqlite3_sql(pStmt);
  258. if( NULL == zSql ) return SQLITE_ERROR;
  259. char *zExplain = sqlite3_mprintf("EXPLAIN QUERY PLAN %s", zSql);
  260. if( NULL == zExplain ) return SQLITE_NOMEM;
  261. sqlite3_stmt *pExplain; /* Compiled EXPLAIN QUERY PLAN command */
  262. const int rc = sqlite3_prepare_v2(sqlite3_db_handle(pStmt), zExplain, -1, &pExplain, 0);
  263. sqlite3_free(zExplain);
  264. if( SQLITE_OK != rc ) return rc;
  265. while( SQLITE_ROW == sqlite3_step(pExplain) ) {
  266. const int iSelectid = sqlite3_column_int(pExplain, 0);
  267. const int iOrder = sqlite3_column_int(pExplain, 1);
  268. const int iFrom = sqlite3_column_int(pExplain, 2);
  269. const char *zDetail = (const char *)sqlite3_column_text(pExplain, 3);
  270. printf("%d %d %d %s\n", iSelectid, iOrder, iFrom, zDetail);
  271. }
  272. return sqlite3_finalize(pExplain);
  273. }
  274. #if 0
  275. // http://stackoverflow.com/a/6618833
  276. static void trace(void *context, const char *sql)
  277. {
  278. fprintf(stderr, "Query SQL: %s\n", sql);
  279. }
  280. #endif
  281. // http://stackoverflow.com/a/6618833
  282. static void profile(void *context, const char *sql, const sqlite3_uint64 ns)
  283. {
  284. // librdf_storage *storage = (librdf_storage *)context;
  285. // instance_t *db_ctx = get_instance(storage);
  286. fprintf(stderr, "dt=%llu ns Query SQL: %s\n", ns, sql);
  287. }
  288. #pragma mark Sqlite Convenience
  289. /** Sqlite Result Code, e.g. SQLITE_OK */
  290. typedef int sqlite_rc_t;
  291. static sqlite_rc_t log_error(sqlite3 *db, const char *sql, const sqlite_rc_t rc)
  292. {
  293. if( SQLITE_OK != rc ) {
  294. const char *errmsg = sqlite3_errmsg(db);
  295. librdf_log(NULL, 0, LIBRDF_LOG_ERROR, LIBRDF_FROM_STORAGE, NULL, "SQLite SQL error - %s (%d)\n%s", errmsg, rc, sql);
  296. }
  297. return rc;
  298. }
  299. static sqlite3_stmt *prep_stmt(sqlite3 *db, sqlite3_stmt **stmt_p, const char *zSql)
  300. {
  301. assert(db && "db handle is NULL");
  302. assert(stmt_p && "statement is NULL");
  303. assert(zSql && "SQL is NULL");
  304. if( *stmt_p ) {
  305. assert(0 == strcmp(sqlite3_sql(*stmt_p), zSql) && "sql changed during compilation.");
  306. const sqlite_rc_t rc0 = sqlite3_reset(*stmt_p);
  307. assert(SQLITE_OK == rc0 && "couldn't reset SQL statement");
  308. const sqlite_rc_t rc1 = sqlite3_clear_bindings(*stmt_p);
  309. assert(SQLITE_OK == rc1 && "couldn't reset SQL statement");
  310. } else {
  311. const char *remainder = NULL;
  312. const int len_zSql = (int)strlen(zSql) + 1;
  313. const sqlite_rc_t rc0 = log_error( db, zSql, sqlite3_prepare_v2(db, zSql, len_zSql, stmt_p, &remainder) );
  314. assert(SQLITE_OK == rc0 && "couldn't compile SQL statement");
  315. assert('\0' == *remainder && "had remainder");
  316. }
  317. assert(*stmt_p && "statement is NULL");
  318. return *stmt_p;
  319. }
  320. static void finalize_stmt(sqlite3_stmt **pStmt)
  321. {
  322. if( NULL == *pStmt )
  323. return;
  324. sqlite3_reset(*pStmt);
  325. const sqlite_rc_t rc = sqlite3_finalize(*pStmt);
  326. assert(SQLITE_OK == rc && "couldn't properly sqlite3_finalize");
  327. *pStmt = NULL;
  328. }
  329. static sqlite_rc_t exec_stmt(sqlite3 *db, const char *sql)
  330. {
  331. char *errmsg = NULL;
  332. const sqlite_rc_t rc = sqlite3_exec(db, sql, NULL, NULL, &errmsg);
  333. sqlite3_free(errmsg);
  334. return rc;
  335. }
  336. static inline sqlite_rc_t bind_int(sqlite3_stmt *stmt, const char *name, const hash_t _id)
  337. {
  338. assert(stmt && "stmt mandatory");
  339. assert(name && "name mandatory");
  340. const int idx = sqlite3_bind_parameter_index(stmt, name);
  341. return 0 == idx ? SQLITE_OK : sqlite3_bind_int64(stmt, idx, _id);
  342. }
  343. static inline sqlite_rc_t bind_text(sqlite3_stmt *stmt, const char *name, const unsigned char *text, const size_t text_len)
  344. {
  345. assert(stmt && "stmt mandatory");
  346. assert(name && "name mandatory");
  347. const int idx = sqlite3_bind_parameter_index(stmt, name);
  348. 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) );
  349. }
  350. static inline sqlite_rc_t bind_null(sqlite3_stmt *stmt, const char *name)
  351. {
  352. return bind_text(stmt, name, NULL, 0);
  353. }
  354. static sqlite_rc_t bind_uri_id(sqlite3_stmt *stmt, librdf_digest *digest, const char *name, librdf_uri *uri, hash_t *value)
  355. {
  356. if( uri ) {
  357. const hash_t v = hash_uri(uri, digest);
  358. if( value ) *value = v;
  359. return bind_int(stmt, name, v);
  360. }
  361. return bind_null(stmt, name);
  362. }
  363. static sqlite_rc_t bind_uri(sqlite3_stmt *stmt, const char *name, librdf_uri *uri)
  364. {
  365. if( uri ) {
  366. size_t len = 0;
  367. const unsigned char *str = librdf_uri_as_counted_string(uri, &len);
  368. return bind_text(stmt, name, str, len);
  369. }
  370. return bind_null(stmt, name);
  371. }
  372. static sqlite_rc_t bind_node_uri_id(sqlite3_stmt *stmt, librdf_digest *digest, const char *name, librdf_node *node, hash_t *value)
  373. {
  374. return bind_uri_id(stmt, digest, name, LIBRDF_NODE_TYPE_RESOURCE == node_type(node) ? librdf_node_get_uri(node) : NULL, value);
  375. }
  376. static sqlite_rc_t bind_node_uri(sqlite3_stmt *stmt, const char *name, librdf_node *node)
  377. {
  378. return bind_uri(stmt, name, LIBRDF_NODE_TYPE_RESOURCE == node_type(node) ? librdf_node_get_uri(node) : NULL);
  379. }
  380. static sqlite_rc_t bind_node_blank_id(sqlite3_stmt *stmt, librdf_digest *digest, const char *name, librdf_node *node, hash_t *value)
  381. {
  382. if( LIBRDF_NODE_TYPE_BLANK == node_type(node) ) {
  383. const hash_t v = node_hash_blank(node, digest);
  384. if( value ) *value = v;
  385. return bind_int(stmt, name, v);
  386. }
  387. return bind_null(stmt, name);
  388. }
  389. static sqlite_rc_t bind_node_blank(sqlite3_stmt *stmt, const char *name, librdf_node *node)
  390. {
  391. if( LIBRDF_NODE_TYPE_BLANK == node_type(node) ) {
  392. size_t len = 0;
  393. const unsigned char *str = librdf_node_get_counted_blank_identifier(node, &len);
  394. return bind_text(stmt, name, str, len);
  395. }
  396. return bind_null(stmt, name);
  397. }
  398. static sqlite_rc_t bind_node_lit_id(sqlite3_stmt *stmt, librdf_digest *digest, const char *name, librdf_node *node, hash_t *value)
  399. {
  400. if( LIBRDF_NODE_TYPE_LITERAL == node_type(node) ) {
  401. const hash_t v = node_hash_literal(node, digest);
  402. if( value ) *value = v;
  403. return bind_int(stmt, name, v);
  404. }
  405. return bind_null(stmt, name);
  406. }
  407. static sqlite_rc_t bind_stmt(instance_t *db_ctx, librdf_statement *statement, librdf_node *context_node, sqlite3_stmt *stmt)
  408. {
  409. librdf_node *s = librdf_statement_get_subject(statement);
  410. librdf_node *p = librdf_statement_get_predicate(statement);
  411. librdf_node *o = librdf_statement_get_object(statement);
  412. sqlite_rc_t rc = SQLITE_OK;
  413. hash_t s_uri_id = NULL_ID;
  414. hash_t s_blank_id = NULL_ID;
  415. hash_t p_uri_id = NULL_ID;
  416. hash_t o_uri_id = NULL_ID;
  417. hash_t o_blank_id = NULL_ID;
  418. hash_t o_lit_id = NULL_ID;
  419. hash_t o_type_id = NULL_ID;
  420. hash_t c_uri_id = NULL_ID;
  421. if( SQLITE_OK != ( rc = bind_node_uri_id(stmt, db_ctx->digest, ":s_uri_id", s, &s_uri_id) ) ) return rc;
  422. if( SQLITE_OK != ( rc = bind_node_uri(stmt, ":s_uri", s) ) ) return rc;
  423. if( SQLITE_OK != ( rc = bind_node_blank_id(stmt, db_ctx->digest, ":s_blank_id", s, &s_blank_id) ) ) return rc;
  424. if( SQLITE_OK != ( rc = bind_node_blank(stmt, ":s_blank", s) ) ) return rc;
  425. if( SQLITE_OK != ( rc = bind_node_uri_id(stmt, db_ctx->digest, ":p_uri_id", p, &p_uri_id) ) ) return rc;
  426. if( SQLITE_OK != ( rc = bind_node_uri(stmt, ":p_uri", p) ) ) return rc;
  427. if( SQLITE_OK != ( rc = bind_node_uri_id(stmt, db_ctx->digest, ":o_uri_id", o, &o_uri_id) ) ) return rc;
  428. if( SQLITE_OK != ( rc = bind_node_uri(stmt, ":o_uri", o) ) ) return rc;
  429. if( SQLITE_OK != ( rc = bind_node_blank_id(stmt, db_ctx->digest, ":o_blank_id", o, &o_blank_id) ) ) return rc;
  430. if( SQLITE_OK != ( rc = bind_node_blank(stmt, ":o_blank", o) ) ) return rc;
  431. if( SQLITE_OK != ( rc = bind_node_lit_id(stmt, db_ctx->digest, ":o_lit_id", o, &o_lit_id) ) ) return rc;
  432. if( LIBRDF_NODE_TYPE_LITERAL == node_type(o) ) {
  433. 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;
  434. if( SQLITE_OK != ( rc = bind_uri( stmt, ":o_datatype", librdf_node_get_literal_value_datatype_uri(o) ) ) ) return rc;
  435. char *l = librdf_node_get_literal_value_language(o);
  436. if( l )
  437. if( SQLITE_OK != ( rc = bind_text( stmt, ":o_language", (unsigned char *)l, strlen(l) ) ) ) return rc;
  438. size_t len = 0;
  439. const unsigned char *str = librdf_node_get_literal_value_as_counted_string(o, &len);
  440. assert(strlen( (char *)str ) == len && "TODO: NUL terminate or limit length!");
  441. if( SQLITE_OK != ( rc = bind_text(stmt, ":o_text", str, len) ) ) return rc;
  442. }
  443. if( SQLITE_OK != ( rc = bind_node_uri_id(stmt, db_ctx->digest, ":c_uri_id", context_node, &c_uri_id) ) ) return rc;
  444. if( SQLITE_OK != ( rc = bind_node_uri(stmt, ":c_uri", context_node) ) ) return rc;
  445. if( !librdf_statement_is_complete(statement) )
  446. return SQLITE_OK;
  447. 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);
  448. assert(stmt_hash(statement, context_node, db_ctx->digest) == stmt_id && "statement hash computation mismatch");
  449. if( SQLITE_OK != ( rc = bind_int(stmt, ":stmt_id", stmt_id) ) ) return rc;
  450. return SQLITE_OK;
  451. }
  452. static inline const str_uri_t column_uri_string(sqlite3_stmt *stmt, const int iCol)
  453. {
  454. return (str_uri_t)sqlite3_column_text(stmt, iCol);
  455. }
  456. static inline const str_blank_t column_blank_string(sqlite3_stmt *stmt, const int iCol)
  457. {
  458. return (str_blank_t)sqlite3_column_text(stmt, iCol);
  459. }
  460. static inline const str_lang_t column_language(sqlite3_stmt *stmt, const int iCol)
  461. {
  462. return (str_lang_t)sqlite3_column_text(stmt, iCol);
  463. }
  464. static sqlite_rc_t transaction_start(librdf_storage *storage)
  465. {
  466. instance_t *db_ctx = get_instance(storage);
  467. if( db_ctx->in_transaction )
  468. return SQLITE_MISUSE;
  469. const sqlite_rc_t rc = sqlite3_step( prep_stmt(db_ctx->db, &(db_ctx->stmt_txn_start), "BEGIN IMMEDIATE TRANSACTION") );
  470. db_ctx->in_transaction = SQLITE_DONE == rc;
  471. assert(false != db_ctx->in_transaction && "transaction was not properly started");
  472. return SQLITE_DONE == rc ? SQLITE_OK : rc;
  473. }
  474. static sqlite_rc_t transaction_commit(librdf_storage *storage, const sqlite_rc_t begin)
  475. {
  476. if( begin != SQLITE_OK )
  477. return SQLITE_OK;
  478. instance_t *db_ctx = get_instance(storage);
  479. if( false == db_ctx->in_transaction )
  480. return SQLITE_MISUSE;
  481. const sqlite_rc_t rc = sqlite3_step( prep_stmt(db_ctx->db, &(db_ctx->stmt_txn_commit), "COMMIT TRANSACTION") );
  482. db_ctx->in_transaction = !(SQLITE_DONE == rc);
  483. assert(false == db_ctx->in_transaction && "transaction was not properly committed");
  484. return SQLITE_DONE == rc ? SQLITE_OK : rc;
  485. }
  486. static sqlite_rc_t transaction_rollback(librdf_storage *storage, const sqlite_rc_t begin)
  487. {
  488. if( SQLITE_OK != begin )
  489. return SQLITE_OK;
  490. instance_t *db_ctx = get_instance(storage);
  491. if( false == db_ctx->in_transaction )
  492. return SQLITE_MISUSE;
  493. const sqlite_rc_t rc = sqlite3_step( prep_stmt(db_ctx->db, &(db_ctx->stmt_txn_rollback), "ROLLBACK TRANSACTION") );
  494. db_ctx->in_transaction = !(SQLITE_DONE == rc);
  495. assert(false == db_ctx->in_transaction && "transaction was not properly rolled back");
  496. return SQLITE_DONE == rc ? SQLITE_OK : rc;
  497. }
  498. #pragma mark -
  499. #pragma mark Internal Implementation
  500. /** insert_triple_sql + find_triples_sql
  501. */
  502. typedef enum {
  503. IDX_S_URI = 9,
  504. IDX_S_BLANK,
  505. IDX_P_URI,
  506. IDX_O_URI,
  507. IDX_O_BLANK,
  508. IDX_O_TEXT,
  509. IDX_O_LANGUAGE,
  510. IDX_O_DATATYPE,
  511. IDX_C_URI
  512. }
  513. idx_triple_column_t;
  514. static librdf_statement *find_statement(librdf_storage *storage, librdf_node *context_node, librdf_statement *statement, const bool create)
  515. {
  516. assert(statement && "statement must be set.");
  517. assert(librdf_statement_is_complete(statement) && "statement must be complete.");
  518. instance_t *db_ctx = get_instance(storage);
  519. if( !create ) {
  520. const hash_t stmt_id = stmt_hash(statement, context_node, db_ctx->digest);
  521. assert(!isNULL_ID(stmt_id) && "mustn't be nil");
  522. sqlite3_stmt *stmt = prep_stmt(db_ctx->db, &(db_ctx->stmt_triple_find), "SELECT id FROM triple_relations WHERE id = :stmt_id");
  523. if( SQLITE_OK != bind_int(stmt, ":stmt_id", stmt_id) )
  524. return NULL;
  525. return SQLITE_ROW == sqlite3_step(stmt) ? statement : NULL;
  526. }
  527. const char insert_triple_sql[] = // generated via tools/sql2c.sh insert_triple.sql
  528. "INSERT OR IGNORE INTO triples(" "\n" \
  529. " id," "\n" \
  530. " s_uri_id, s_uri," "\n" \
  531. " s_blank_id, s_blank," "\n" \
  532. " p_uri_id, p_uri," "\n" \
  533. " o_uri_id, o_uri," "\n" \
  534. " o_blank_id, o_blank," "\n" \
  535. " o_lit_id, o_datatype_id, o_datatype, o_language, o_text," "\n" \
  536. " c_uri_id, c_uri" "\n" \
  537. ") VALUES (" "\n" \
  538. " :stmt_id," "\n" \
  539. " :s_uri_id, :s_uri," "\n" \
  540. " :s_blank_id, :s_blank," "\n" \
  541. " :p_uri_id, :p_uri," "\n" \
  542. " :o_uri_id, :o_uri," "\n" \
  543. " :o_blank_id, :o_blank," "\n" \
  544. " :o_lit_id, :o_datatype_id, :o_datatype, :o_language, :o_text," "\n" \
  545. " :c_uri_id, :c_uri" "\n" \
  546. ")" "\n" \
  547. ;
  548. sqlite3_stmt *stmt = prep_stmt(db_ctx->db, &(db_ctx->stmt_triple_insert), insert_triple_sql);
  549. if( SQLITE_OK != bind_stmt(db_ctx, statement, context_node, stmt) )
  550. return NULL;
  551. if( db_ctx->do_explain_query_plan )
  552. printExplainQueryPlan(stmt);
  553. const sqlite_rc_t rc = sqlite3_step(stmt);
  554. return SQLITE_DONE == rc ? statement : NULL;
  555. }
  556. #pragma mark -
  557. #pragma mark Public Interface
  558. int librdf_storage_set_feature_mro_bool(librdf_storage *storage, const unsigned char *feature, const bool value)
  559. {
  560. assert(storage && "storage must be set.");
  561. assert(feature && "feature must be set.");
  562. librdf_world *world = librdf_storage_get_world(storage);
  563. assert(world && "world must be set.");
  564. librdf_uri *uri_xsd_boolean = librdf_new_uri(world, (str_uri_t)LIBRDF_NAMESPACE_XSD "boolean");
  565. assert(uri_xsd_boolean && "uri_xsd_boolean must be set.");
  566. librdf_uri *uri_f = librdf_new_uri(world, feature);
  567. assert(uri_f && "uri_f must be set.");
  568. const str_lit_val_t v = (str_lit_val_t)(value ? "true" : "false");
  569. // librdf_log(get_world(storage), 0, LIBRDF_LOG_DEBUG, LIBRDF_FROM_STORAGE, NULL, "librdf_storage_set_feature_mro_bool sets '%s'", v);
  570. librdf_node *n = librdf_new_node_from_typed_literal(world, v, NULL, uri_xsd_boolean);
  571. const int ret = librdf_storage_set_feature(storage, uri_f, n);
  572. librdf_free_node(n);
  573. librdf_free_uri(uri_f);
  574. librdf_free_uri(uri_xsd_boolean);
  575. return ret;
  576. }
  577. int librdf_storage_set_feature_mro_int(librdf_storage *storage, const unsigned char *feature, const int value)
  578. {
  579. assert(storage && "storage must be set.");
  580. assert(feature && "feature must be set.");
  581. librdf_world *world = librdf_storage_get_world(storage);
  582. assert(world && "world must be set.");
  583. librdf_uri *uri_xsd_integer = librdf_new_uri(world, (str_uri_t)LIBRDF_NAMESPACE_XSD "integer");
  584. assert(uri_xsd_integer && "uri_xsd_integer must be set.");
  585. librdf_uri *uri_f = librdf_new_uri(world, feature);
  586. assert(uri_f && "uri_f must be set.");
  587. char v[20];
  588. snprintf(v, sizeof(v), "%d", value);
  589. librdf_node *n = librdf_new_node_from_typed_literal(world, (str_lit_val_t)v, NULL, uri_xsd_integer);
  590. const int ret = librdf_storage_set_feature(storage, uri_f, n);
  591. librdf_free_node(n);
  592. librdf_free_uri(uri_f);
  593. librdf_free_uri(uri_xsd_integer);
  594. return ret;
  595. }
  596. int librdf_storage_get_feature_mro_bool(librdf_storage *storage, const unsigned char *feature, bool *value)
  597. {
  598. assert(storage && "storage must be set.");
  599. assert(feature && "feature must be set.");
  600. librdf_world *world = librdf_storage_get_world(storage);
  601. assert(world && "world must be set.");
  602. librdf_uri *uri_f = librdf_new_uri(world, feature);
  603. int err = RET_OK;
  604. bool ret = false;
  605. if( uri_f ) {
  606. librdf_node *node = librdf_storage_get_feature(storage, uri_f);
  607. if( node ) {
  608. if( LIBRDF_NODE_TYPE_LITERAL == node_type(node) ) {
  609. size_t len = 0;
  610. const char *v = (char *)librdf_node_get_literal_value_as_counted_string(node, &len);
  611. if( v ) {
  612. // librdf_log(get_world(storage), 0, LIBRDF_LOG_DEBUG, LIBRDF_FROM_STORAGE, NULL, "librdf_storage_get_feature_mro_bool return '%s'", v);
  613. if( 0 == strncmp("true", v, len) || 0 == strncmp("1", v, len) )
  614. ret = true;
  615. else if( 0 == strncmp("false", v, len) || 0 == strncmp("0", v, len) )
  616. ret = false;
  617. else
  618. err = 4;
  619. } else
  620. err = 3;
  621. } else
  622. err = 2;
  623. librdf_free_node(node);
  624. } else
  625. err = 1;
  626. librdf_free_uri(uri_f);
  627. }
  628. if( value )
  629. *value = ret;
  630. return err;
  631. }
  632. int librdf_storage_get_feature_mro_int(librdf_storage *storage, const unsigned char *feature, int *value)
  633. {
  634. assert(storage && "storage must be set.");
  635. assert(feature && "feature must be set.");
  636. librdf_world *world = librdf_storage_get_world(storage);
  637. assert(world && "world must be set.");
  638. librdf_uri *uri_f = librdf_new_uri(world, feature);
  639. int err = RET_OK;
  640. long ret = RET_OK;
  641. if( uri_f ) {
  642. librdf_node *node = librdf_storage_get_feature(storage, uri_f);
  643. if( node ) {
  644. if( LIBRDF_NODE_TYPE_LITERAL == node_type(node) ) {
  645. size_t len = 0;
  646. const char *str = (char *)librdf_node_get_literal_value_as_counted_string(node, &len);
  647. if( str ) {
  648. assert(strlen(str) == len && "TODO: NUL terminate or limit length!");
  649. char *end = NULL;
  650. ret = strtol(str, &end, 10);
  651. if( '\0' != *end )
  652. err = 4;
  653. } else
  654. err = 3;
  655. } else
  656. err = 2;
  657. librdf_free_node(node);
  658. } else
  659. err = 1;
  660. librdf_free_uri(uri_f);
  661. }
  662. if( value )
  663. *value = ret;
  664. return err;
  665. }
  666. #pragma mark Lifecycle & Housekeeping
  667. /** Create a new storage.
  668. *
  669. * Setup SQLIte connection instance but don't open yet.
  670. */
  671. static int pub_init(librdf_storage *storage, const char *name, librdf_hash *options)
  672. {
  673. if( !name ) {
  674. free_hash(options);
  675. return RET_ERROR;
  676. }
  677. instance_t *db_ctx = LIBRDF_CALLOC(instance_t *, sizeof(*db_ctx), 1);
  678. if( !db_ctx ) {
  679. free_hash(options);
  680. return RET_ERROR;
  681. }
  682. // feature defaults
  683. db_ctx->do_profile = false;
  684. db_ctx->do_explain_query_plan = false;
  685. db_ctx->sql_cache_mask = ALL_PARAMS;
  686. librdf_storage_set_instance(storage, db_ctx);
  687. const size_t name_len = strlen(name);
  688. char *name_copy = LIBRDF_MALLOC(char *, name_len + 1);
  689. if( !name_copy ) {
  690. free_hash(options);
  691. return RET_ERROR;
  692. }
  693. strncpy(name_copy, name, name_len + 1);
  694. db_ctx->name = name_copy;
  695. if( !( db_ctx->digest = librdf_new_digest(get_world(storage), "MD5") ) ) {
  696. free_hash(options);
  697. return RET_ERROR;
  698. }
  699. if( false != librdf_hash_get_as_boolean(options, "new") )
  700. db_ctx->is_new = true; /* default is NOT NEW */
  701. /* Redland default is "PRAGMA synchronous normal" */
  702. db_ctx->synchronous = SYNC_NORMAL;
  703. char *synchronous = synchronous = librdf_hash_get(options, "synchronous");
  704. if( synchronous ) {
  705. for( int i = 0; synchronous_flags[i]; i++ ) {
  706. if( !strcmp(synchronous, synchronous_flags[i]) ) {
  707. db_ctx->synchronous = i;
  708. break;
  709. }
  710. }
  711. LIBRDF_FREE(char *, synchronous);
  712. }
  713. free_hash(options);
  714. return RET_OK;
  715. }
  716. static void pub_terminate(librdf_storage *storage)
  717. {
  718. instance_t *db_ctx = get_instance(storage);
  719. if( NULL == db_ctx )
  720. return;
  721. if( db_ctx->name )
  722. LIBRDF_FREE(char *, (void *)db_ctx->name);
  723. if( db_ctx->digest )
  724. librdf_free_digest(db_ctx->digest);
  725. LIBRDF_FREE(instance_t *, db_ctx);
  726. }
  727. static int pub_close(librdf_storage *storage)
  728. {
  729. instance_t *db_ctx = get_instance(storage);
  730. if( !db_ctx->db )
  731. return RET_OK;
  732. finalize_stmt( &(db_ctx->stmt_txn_start) );
  733. finalize_stmt( &(db_ctx->stmt_txn_commit) );
  734. finalize_stmt( &(db_ctx->stmt_txn_rollback) );
  735. finalize_stmt( &(db_ctx->stmt_triple_find) );
  736. finalize_stmt( &(db_ctx->stmt_triple_insert) );
  737. finalize_stmt( &(db_ctx->stmt_triple_delete) );
  738. finalize_stmt( &(db_ctx->stmt_size) );
  739. const sqlite_rc_t rc = sqlite3_close(db_ctx->db);
  740. if( SQLITE_OK == rc ) {
  741. db_ctx->db = NULL;
  742. return RET_OK;
  743. }
  744. char *errmsg = (char *)sqlite3_errmsg(db_ctx->db);
  745. librdf_log(get_world(storage), 0, LIBRDF_LOG_ERROR, LIBRDF_FROM_STORAGE, NULL, "SQLite database %s close failed - %s", db_ctx->name, errmsg);
  746. return rc;
  747. }
  748. static int pub_open(librdf_storage *storage, librdf_model *model)
  749. {
  750. instance_t *db_ctx = get_instance(storage);
  751. const bool file_exists = ( 0 == access(db_ctx->name, F_OK) );
  752. if( db_ctx->is_new && file_exists )
  753. unlink(db_ctx->name);
  754. // open DB
  755. assert( (NULL == db_ctx->db) && "db handle mustn't be set by now" );
  756. db_ctx->db = NULL;
  757. {
  758. const sqlite_rc_t rc = sqlite3_open(db_ctx->name, &db_ctx->db);
  759. if( SQLITE_OK != rc ) {
  760. const char *errmsg = sqlite3_errmsg(db_ctx->db);
  761. librdf_log(get_world(storage), 0, LIBRDF_LOG_ERROR, LIBRDF_FROM_STORAGE, NULL, "SQLite database %s open failed - %s", db_ctx->name, errmsg);
  762. return rc;
  763. }
  764. // http://stackoverflow.com/a/6618833
  765. if( db_ctx->do_profile ) {
  766. sqlite3_profile(db_ctx->db, &profile, NULL);
  767. // sqlite3_trace(db_ctx->db, &trace, NULL);
  768. }
  769. }
  770. // set DB session PRAGMAs
  771. if( SYNC_OFF <= db_ctx->synchronous ) {
  772. char sql[250];
  773. const size_t len = snprintf(sql, sizeof(sql) - 1, "PRAGMA synchronous=%s;", synchronous_flags[db_ctx->synchronous]);
  774. assert(len < sizeof(sql) && "buffer too small.");
  775. const sqlite_rc_t rc = exec_stmt(db_ctx->db, sql);
  776. if( SQLITE_OK != rc ) {
  777. pub_close(storage);
  778. return rc;
  779. }
  780. }
  781. {
  782. const char *const sqls[] = {
  783. "PRAGMA foreign_keys = ON;",
  784. "PRAGMA recursive_triggers = ON;",
  785. "PRAGMA encoding = 'UTF-8';",
  786. NULL
  787. };
  788. for( int v = 0; sqls[v]; v++ ) {
  789. const sqlite_rc_t rc = exec_stmt(db_ctx->db, sqls[v]);
  790. if( SQLITE_OK != rc ) {
  791. pub_close(storage);
  792. return rc;
  793. }
  794. }
  795. }
  796. // check & update schema (run migrations)
  797. {
  798. sqlite_rc_t rc = SQLITE_OK;
  799. sqlite3_stmt *stmt = NULL;
  800. prep_stmt(db_ctx->db, &stmt, "PRAGMA user_version;");
  801. if( SQLITE_ROW != ( rc = sqlite3_step(stmt) ) ) {
  802. sqlite3_finalize(stmt);
  803. pub_close(storage);
  804. return rc;
  805. }
  806. const int schema_version = sqlite3_column_int(stmt, 0);
  807. if( SQLITE_DONE != ( rc = sqlite3_step(stmt) ) ) {
  808. sqlite3_finalize(stmt);
  809. pub_close(storage);
  810. return rc;
  811. }
  812. sqlite3_finalize(stmt);
  813. const char *const migrations[] = {
  814. // generated via tools/sql2c.sh sql/schema_mig_to_1.sql
  815. "PRAGMA foreign_keys = ON;" "\n" \
  816. "PRAGMA recursive_triggers = ON;" "\n" \
  817. "PRAGMA encoding = 'UTF-8';" "\n" \
  818. " -- URIs for subjects and objects" "\n" \
  819. "CREATE TABLE so_uris (" "\n" \
  820. " id INTEGER PRIMARY KEY" "\n" \
  821. " ,uri TEXT NOT NULL -- UNIQUE -- redundant constraint (hash should do), could be dropped to save space" "\n" \
  822. ");" "\n" \
  823. " -- blank node IDs for subjects and objects" "\n" \
  824. "CREATE TABLE so_blanks (" "\n" \
  825. " id INTEGER PRIMARY KEY" "\n" \
  826. " ,blank TEXT NOT NULL -- UNIQUE -- redundant constraint (hash should do), could be dropped to save space" "\n" \
  827. ");" "\n" \
  828. " -- URIs for predicates" "\n" \
  829. "CREATE TABLE p_uris (" "\n" \
  830. " id INTEGER PRIMARY KEY" "\n" \
  831. " ,uri TEXT NOT NULL -- UNIQUE -- redundant constraint (hash should do), could be dropped to save space" "\n" \
  832. ");" "\n" \
  833. " -- URIs for literal types" "\n" \
  834. "CREATE TABLE t_uris (" "\n" \
  835. " id INTEGER PRIMARY KEY" "\n" \
  836. " ,uri TEXT NOT NULL -- UNIQUE -- redundant constraint (hash should do), could be dropped to save space" "\n" \
  837. ");" "\n" \
  838. " -- literal values" "\n" \
  839. "CREATE TABLE o_literals (" "\n" \
  840. " id INTEGER PRIMARY KEY" "\n" \
  841. " ,datatype_id INTEGER NULL REFERENCES t_uris(id)" "\n" \
  842. " ,language TEXT NULL" "\n" \
  843. " ,text TEXT NOT NULL" "\n" \
  844. ");" "\n" \
  845. " -- 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" \
  846. " -- URIs for context" "\n" \
  847. "CREATE TABLE c_uris (" "\n" \
  848. " id INTEGER PRIMARY KEY" "\n" \
  849. " ,uri TEXT NOT NULL -- UNIQUE -- redundant constraint (hash should do), could be dropped to save space" "\n" \
  850. ");" "\n" \
  851. "CREATE TABLE triple_relations (" "\n" \
  852. " id INTEGER PRIMARY KEY" "\n" \
  853. " ,s_uri_id INTEGER NULL REFERENCES so_uris(id)" "\n" \
  854. " ,s_blank_id INTEGER NULL REFERENCES so_blanks(id)" "\n" \
  855. " ,p_uri_id INTEGER NOT NULL REFERENCES p_uris(id)" "\n" \
  856. " ,o_uri_id INTEGER NULL REFERENCES so_uris(id)" "\n" \
  857. " ,o_blank_id INTEGER NULL REFERENCES so_blanks(id)" "\n" \
  858. " ,o_lit_id INTEGER NULL REFERENCES o_literals(id)" "\n" \
  859. " ,c_uri_id INTEGER NULL REFERENCES c_uris(id)" "\n" \
  860. " , CONSTRAINT null_subject CHECK ( -- ensure uri/blank are mutually exclusive" "\n" \
  861. " (s_uri_id IS NOT NULL AND s_blank_id IS NULL) OR" "\n" \
  862. " (s_uri_id IS NULL AND s_blank_id IS NOT NULL)" "\n" \
  863. " )" "\n" \
  864. " , CONSTRAINT null_object CHECK ( -- ensure uri/blank/literal are mutually exclusive" "\n" \
  865. " (o_uri_id IS NOT NULL AND o_blank_id IS NULL AND o_lit_id IS NULL) OR" "\n" \
  866. " (o_uri_id IS NULL AND o_blank_id IS NOT NULL AND o_lit_id IS NULL) OR" "\n" \
  867. " (o_uri_id IS NULL AND o_blank_id IS NULL AND o_lit_id IS NOT NULL)" "\n" \
  868. " )" "\n" \
  869. ");" "\n" \
  870. " -- redundant constraint (hash should do), could be dropped to save space:" "\n" \
  871. " -- 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" \
  872. " -- optional indexes for lookup performance, mostly on DELETE." "\n" \
  873. "CREATE INDEX triple_relations_index_s_uri_id ON triple_relations(s_uri_id); -- WHERE s_uri_id IS NOT NULL;" "\n" \
  874. "CREATE INDEX triple_relations_index_s_blank_id ON triple_relations(s_blank_id); -- WHERE s_blank_id IS NOT NULL;" "\n" \
  875. "CREATE INDEX triple_relations_index_p_uri_id ON triple_relations(p_uri_id); -- WHERE p_uri_id IS NOT NULL;" "\n" \
  876. "CREATE INDEX triple_relations_index_o_uri_id ON triple_relations(o_uri_id); -- WHERE o_uri_id IS NOT NULL;" "\n" \
  877. "CREATE INDEX triple_relations_index_o_blank_id ON triple_relations(o_blank_id); -- WHERE s_blank_id IS NOT NULL;" "\n" \
  878. "CREATE INDEX triple_relations_index_o_lit_id ON triple_relations(o_lit_id); -- WHERE o_lit_id IS NOT NULL;" "\n" \
  879. "CREATE INDEX o_literals_index_datatype_id ON o_literals(datatype_id); -- WHERE datatype_id IS NOT NULL;" "\n" \
  880. "PRAGMA user_version=1;" "\n" \
  881. ,
  882. // generated via tools/sql2c.sh sql/schema_mig_to_2.sql
  883. "CREATE VIEW triples AS" "\n" \
  884. "SELECT" "\n" \
  885. " -- all *_id (hashes):" "\n" \
  886. " triple_relations.id AS id" "\n" \
  887. " ,s_uri_id" "\n" \
  888. " ,s_blank_id" "\n" \
  889. " ,p_uri_id" "\n" \
  890. " ,o_uri_id" "\n" \
  891. " ,o_blank_id" "\n" \
  892. " ,o_lit_id" "\n" \
  893. " ,o_literals.datatype_id AS o_datatype_id" "\n" \
  894. " ,c_uri_id" "\n" \
  895. " -- all joined values:" "\n" \
  896. " ,s_uris.uri AS s_uri" "\n" \
  897. " ,s_blanks.blank AS s_blank" "\n" \
  898. " ,p_uris.uri AS p_uri" "\n" \
  899. " ,o_uris.uri AS o_uri" "\n" \
  900. " ,o_blanks.blank AS o_blank" "\n" \
  901. " ,o_literals.text AS o_text" "\n" \
  902. " ,o_literals.language AS o_language" "\n" \
  903. " ,o_lit_uris.uri AS o_datatype" "\n" \
  904. " ,c_uris.uri AS c_uri" "\n" \
  905. "FROM triple_relations" "\n" \
  906. "LEFT OUTER JOIN so_uris AS s_uris ON triple_relations.s_uri_id = s_uris.id" "\n" \
  907. "LEFT OUTER JOIN so_blanks AS s_blanks ON triple_relations.s_blank_id = s_blanks.id" "\n" \
  908. "INNER JOIN p_uris AS p_uris ON triple_relations.p_uri_id = p_uris.id" "\n" \
  909. "LEFT OUTER JOIN so_uris AS o_uris ON triple_relations.o_uri_id = o_uris.id" "\n" \
  910. "LEFT OUTER JOIN so_blanks AS o_blanks ON triple_relations.o_blank_id = o_blanks.id" "\n" \
  911. "LEFT OUTER JOIN o_literals AS o_literals ON triple_relations.o_lit_id = o_literals.id" "\n" \
  912. "LEFT OUTER JOIN t_uris AS o_lit_uris ON o_literals.datatype_id = o_lit_uris.id" "\n" \
  913. "LEFT OUTER JOIN c_uris AS c_uris ON triple_relations.c_uri_id = c_uris.id" "\n" \
  914. ";" "\n" \
  915. "CREATE TRIGGER triples_insert INSTEAD OF INSERT ON triples" "\n" \
  916. "FOR EACH ROW BEGIN" "\n" \
  917. " -- subject uri/blank" "\n" \
  918. " INSERT OR IGNORE INTO so_uris (id,uri) VALUES (NEW.s_uri_id, NEW.s_uri);" "\n" \
  919. " INSERT OR IGNORE INTO so_blanks (id,blank) VALUES (NEW.s_blank_id, NEW.s_blank);" "\n" \
  920. " -- predicate uri" "\n" \
  921. " INSERT OR IGNORE INTO p_uris (id,uri) VALUES (NEW.p_uri_id, NEW.p_uri);" "\n" \
  922. " -- object uri/blank" "\n" \
  923. " INSERT OR IGNORE INTO so_uris (id,uri) VALUES (NEW.o_uri_id, NEW.o_uri);" "\n" \
  924. " INSERT OR IGNORE INTO so_blanks (id,blank) VALUES (NEW.o_blank_id, NEW.o_blank);" "\n" \
  925. " -- object literal" "\n" \
  926. " INSERT OR IGNORE INTO t_uris (id,uri) VALUES (NEW.o_datatype_id, NEW.o_datatype);" "\n" \
  927. " 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" \
  928. " -- context uri" "\n" \
  929. " INSERT OR IGNORE INTO c_uris (id,uri) VALUES (NEW.c_uri_id, NEW.c_uri);" "\n" \
  930. " -- triple" "\n" \
  931. " 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" \
  932. " 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" \
  933. "END;" "\n" \
  934. "CREATE TRIGGER triples_delete INSTEAD OF DELETE ON triples" "\n" \
  935. "FOR EACH ROW BEGIN" "\n" \
  936. " -- triple" "\n" \
  937. " DELETE FROM triple_relations WHERE id = OLD.id;" "\n" \
  938. " -- subject uri/blank" "\n" \
  939. " 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" \
  940. " 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" \
  941. " -- predicate uri" "\n" \
  942. " 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" \
  943. " -- object uri/blank" "\n" \
  944. " 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" \
  945. " 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" \
  946. " -- object literal" "\n" \
  947. " 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" \
  948. " 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" \
  949. " -- context uri" "\n" \
  950. " 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" \
  951. "END;" "\n" \
  952. "PRAGMA user_version=2;" "\n" \
  953. ,
  954. // generated via tools/sql2c.sh sql/schema_mig_to_3.sql
  955. "DROP TRIGGER triples_delete;" "\n" \
  956. "CREATE TRIGGER triples_delete INSTEAD OF DELETE ON triples" "\n" \
  957. "FOR EACH ROW BEGIN" "\n" \
  958. " -- subject uri/blank" "\n" \
  959. " 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" \
  960. " 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" \
  961. " -- predicate uri" "\n" \
  962. " 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" \
  963. " -- object uri/blank" "\n" \
  964. " 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" \
  965. " 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" \
  966. " -- object literal" "\n" \
  967. " 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" \
  968. " 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" \
  969. " -- context uri" "\n" \
  970. " 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" \
  971. " -- triple" "\n" \
  972. " DELETE FROM triple_relations WHERE id = OLD.id;" "\n" \
  973. "END;" "\n" \
  974. "PRAGMA user_version=3;" "\n" \
  975. ,
  976. NULL
  977. };
  978. {
  979. const size_t mig_count = array_length(migrations) - 1;
  980. assert(3 == mig_count && "migrations count wrong.");
  981. assert(!migrations[mig_count] && "migrations must be NULL terminated.");
  982. if( mig_count < schema_version ) {
  983. // schema is more recent than this source file knows to handle.
  984. pub_close(storage);
  985. return RET_ERROR;
  986. }
  987. }
  988. const sqlite_rc_t begin = transaction_start(storage);
  989. for( int v = schema_version; migrations[v]; v++ ) {
  990. if( SQLITE_OK != ( rc = exec_stmt(db_ctx->db, migrations[v]) ) ) {
  991. transaction_rollback(storage, begin);
  992. pub_close(storage);
  993. return rc;
  994. }
  995. {
  996. // assert new schema version
  997. sqlite3_stmt *stmt = NULL;
  998. prep_stmt(db_ctx->db, &stmt, "PRAGMA user_version");
  999. if( SQLITE_ROW != ( rc = sqlite3_step(stmt) ) ) {
  1000. sqlite3_finalize(stmt);
  1001. pub_close(storage);
  1002. return rc;
  1003. }
  1004. const int v_new = sqlite3_column_int(stmt, 0);
  1005. if( SQLITE_DONE != ( rc = sqlite3_step(stmt) ) ) {
  1006. sqlite3_finalize(stmt);
  1007. pub_close(storage);
  1008. return rc;
  1009. }
  1010. sqlite3_finalize(stmt);
  1011. assert(v + 1 == v_new && "invalid schema version after migration.");
  1012. }
  1013. }
  1014. if( SQLITE_OK != ( rc = transaction_commit(storage, begin) ) ) {
  1015. pub_close(storage);
  1016. return rc;
  1017. }
  1018. }
  1019. return RET_OK;
  1020. }
  1021. /**
  1022. * librdf_storage_sqlite_get_feature:
  1023. * @storage: #librdf_storage object
  1024. * @feature: #librdf_uri feature property
  1025. *
  1026. * Get the value of a storage feature.
  1027. *
  1028. * Return value: #librdf_node feature value or NULL if no such feature
  1029. * exists or the value is empty.
  1030. **/
  1031. static librdf_node *pub_get_feature(librdf_storage *storage, librdf_uri *feature)
  1032. {
  1033. assert(storage && "storage must be set");
  1034. if( !feature )
  1035. return NULL;
  1036. const char *feat = (char *)librdf_uri_as_string(feature);
  1037. if( !feat )
  1038. return NULL;
  1039. instance_t *db_ctx = get_instance(storage);
  1040. librdf_node *ret = NULL;
  1041. librdf_uri *uri_xsd_boolean = librdf_new_uri(get_world(storage), (str_uri_t)"http://www.w3.org/2000/10/XMLSchema#" "boolean");
  1042. librdf_uri *uri_xsd_unsignedShort = librdf_new_uri(get_world(storage), (str_uri_t)"http://www.w3.org/2000/10/XMLSchema#" "unsignedShort");
  1043. if( !ret && 0 == strcmp(LIBRDF_MODEL_FEATURE_CONTEXTS, feat) )
  1044. ret = librdf_new_node_from_typed_literal(get_world(storage), (str_lit_val_t)(true ? "1" : "0"), NULL, uri_xsd_boolean);
  1045. if( !ret && 0 == strcmp( (char *)LIBRDF_STORAGE_SQLITE_MRO_FEATURE_SQLITE3_PROFILE, feat ) )
  1046. ret = librdf_new_node_from_typed_literal(get_world(storage), (str_lit_val_t)(db_ctx->do_profile ? "true" : "false"), NULL, uri_xsd_boolean);
  1047. if( !ret && 0 == strcmp( (char *)LIBRDF_STORAGE_SQLITE_MRO_FEATURE_SQLITE3_EXPLAIN_QUERY_PLAN, (char *)feat ) )
  1048. 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);
  1049. if( !ret && 0 == strcmp( (char *)LIBRDF_STORAGE_SQLITE_MRO_FEATURE_SQL_CACHE_MASK, feat ) ) {
  1050. char buf[10];
  1051. snprintf(buf, sizeof(buf) - 1, "%d", db_ctx->sql_cache_mask);
  1052. ret = librdf_new_node_from_typed_literal(get_world(storage), (str_uri_t)buf, NULL, uri_xsd_unsignedShort);
  1053. }
  1054. librdf_free_uri(uri_xsd_boolean);
  1055. librdf_free_uri(uri_xsd_unsignedShort);
  1056. return ret;
  1057. }
  1058. /**
  1059. * librdf_storage_set_feature:
  1060. * @storage: #librdf_storage object
  1061. * @feature: #librdf_uri feature property
  1062. * @value: #librdf_node feature property value
  1063. *
  1064. * Set the value of a storage feature.
  1065. *
  1066. * Return value: non 0 on failure (negative if no such feature)
  1067. **/
  1068. static int pub_set_feature(librdf_storage *storage, librdf_uri *feature, librdf_node *value)
  1069. {
  1070. assert(storage && "storage must be set");
  1071. if( !feature )
  1072. return -1;
  1073. const char *feat = (char *)librdf_uri_as_string(feature);
  1074. if( !feat )
  1075. return -1;
  1076. const char *val = (char *)librdf_node_get_literal_value(value);
  1077. // librdf_log(get_world(storage), 0, LIBRDF_LOG_DEBUG, LIBRDF_FROM_STORAGE, NULL, "pub_set_feature('%s', '%s')", feat, val);
  1078. instance_t *db_ctx = get_instance(storage);
  1079. if( 0 == strcmp( (char *)LIBRDF_STORAGE_SQLITE_MRO_FEATURE_SQL_CACHE_MASK, feat ) ) {
  1080. if( 0 == strcmp("0", val) ) {
  1081. db_ctx->sql_cache_mask = 0;
  1082. } else {
  1083. char *end = NULL;
  1084. const long i = strtol(val, &end, 10);
  1085. if( NULL == end || '\0' != *end ) {
  1086. librdf_log(NULL, 0, LIBRDF_LOG_ERROR, LIBRDF_FROM_STORAGE, NULL, "invalid value: <%s> \"%s\"^^xsd:unsignedShort", feat, val);
  1087. return 3;
  1088. }
  1089. db_ctx->sql_cache_mask = ALL_PARAMS & i; // clip range
  1090. }
  1091. // librdf_log(NULL, 0, LIBRDF_LOG_DEBUG, LIBRDF_FROM_STORAGE, NULL, "good value: <%s> \"%d\"^^xsd:unsignedShort", feat, db_ctx->sql_cache_mask);
  1092. return 0;
  1093. }
  1094. if( 0 == strcmp( (char *)LIBRDF_STORAGE_SQLITE_MRO_FEATURE_SQLITE3_PROFILE, feat ) ) {
  1095. if( 0 == strcmp("1", val) || 0 == strcmp("true", val) ) {
  1096. db_ctx->do_profile = true;
  1097. if( db_ctx->db )
  1098. sqlite3_profile(db_ctx->db, &profile, storage);
  1099. } else if( 0 == strcmp("0", val) || 0 == strcmp("false", val) ) {
  1100. db_ctx->do_profile = false;
  1101. if( db_ctx->db )
  1102. sqlite3_profile(db_ctx->db, NULL, NULL);
  1103. } else {
  1104. librdf_log(NULL, 0, LIBRDF_LOG_ERROR, LIBRDF_FROM_STORAGE, NULL, "invalid value: <%s> \"%s\"^^xsd:boolean", feat, val);
  1105. return 2;
  1106. }
  1107. return 0;
  1108. }
  1109. if( 0 == strcmp( (char *)LIBRDF_STORAGE_SQLITE_MRO_FEATURE_SQLITE3_EXPLAIN_QUERY_PLAN, feat ) ) {
  1110. if( 0 == strcmp("1", val) || 0 == strcmp("true", val) )
  1111. db_ctx->do_explain_query_plan = true;
  1112. else if( 0 == strcmp("0", val) || 0 == strcmp("false", val) )
  1113. db_ctx->do_explain_query_plan = false;
  1114. else {
  1115. librdf_log(NULL, 0, LIBRDF_LOG_ERROR, LIBRDF_FROM_STORAGE, NULL, "invalid value: <%s> \"%s\"^^xsd:boolean", feat, val);
  1116. return 2;
  1117. }
  1118. return 0;
  1119. }
  1120. return 1;
  1121. }
  1122. #pragma mark Transactions
  1123. static sqlite_rc_t pub_transaction_start(librdf_storage *storage)
  1124. {
  1125. return transaction_start(storage);
  1126. }
  1127. static sqlite_rc_t pub_transaction_commit(librdf_storage *storage)
  1128. {
  1129. return transaction_commit(storage, SQLITE_OK);
  1130. }
  1131. static sqlite_rc_t pub_transaction_rollback(librdf_storage *storage)
  1132. {
  1133. return transaction_rollback(storage, SQLITE_OK);
  1134. }
  1135. #pragma mark Iterator
  1136. typedef struct
  1137. {
  1138. librdf_storage *storage;
  1139. librdf_statement *pattern;
  1140. librdf_statement *statement;
  1141. librdf_node *context;
  1142. sqlite3_stmt *stmt;
  1143. sqlite_rc_t txn;
  1144. sqlite_rc_t rc;
  1145. bool dirty;
  1146. }
  1147. iterator_t;
  1148. static int pub_iter_end_of_stream(void *_ctx)
  1149. {
  1150. assert(_ctx && "context mustn't be NULL");
  1151. iterator_t *ctx = (iterator_t *)_ctx;
  1152. return SQLITE_ROW != ctx->rc;
  1153. }
  1154. static int pub_iter_next_statement(void *_ctx)
  1155. {
  1156. assert(_ctx && "context mustn't be NULL");
  1157. iterator_t *ctx = (iterator_t *)_ctx;
  1158. if( pub_iter_end_of_stream(ctx) )
  1159. return RET_ERROR;
  1160. ctx->dirty = true;
  1161. ctx->rc = sqlite3_step(ctx->stmt);
  1162. if( pub_iter_end_of_stream(ctx) )
  1163. return RET_ERROR;
  1164. return RET_OK;
  1165. }
  1166. static void *pub_iter_get_statement(void *_ctx, const int _flags)
  1167. {
  1168. assert(_ctx && "context mustn't be NULL");
  1169. const librdf_iterator_get_method_flags flags = (librdf_iterator_get_method_flags)_flags;
  1170. iterator_t *ctx = (iterator_t *)_ctx;
  1171. switch( flags ) {
  1172. case LIBRDF_ITERATOR_GET_METHOD_GET_OBJECT: {
  1173. if( ctx->dirty && !pub_iter_end_of_stream(_ctx) ) {
  1174. assert(ctx->statement && "statement mustn't be NULL");
  1175. librdf_world *w = get_world(ctx->storage);
  1176. librdf_statement *st = ctx->statement;
  1177. sqlite3_stmt *stm = ctx->stmt;
  1178. librdf_statement_clear(st);
  1179. // stmt columns refer to find_triples_sql
  1180. {
  1181. /* subject */
  1182. librdf_node *node = NULL;
  1183. const str_uri_t uri = column_uri_string(stm, IDX_S_URI);
  1184. if( uri ) {
  1185. assert('\0' != uri[0] && "empty uri");
  1186. node = librdf_new_node_from_uri_string(w, uri);
  1187. }
  1188. if( !node ) {
  1189. const str_blank_t blank = column_blank_string(stm, IDX_S_BLANK);
  1190. if( blank ) {
  1191. assert('\0' != blank[0] && "empty blank");
  1192. node = librdf_new_node_from_blank_identifier(w, blank);
  1193. }
  1194. }
  1195. if( !node )
  1196. return NULL;
  1197. librdf_statement_set_subject(st, node);
  1198. }
  1199. {
  1200. /* predicate */
  1201. librdf_node *node = NULL;
  1202. const str_uri_t uri = column_uri_string(stm, IDX_P_URI);
  1203. if( uri )
  1204. node = librdf_new_node_from_uri_string(w, uri);
  1205. if( !node )
  1206. return NULL;
  1207. librdf_statement_set_predicate(st, node);
  1208. }
  1209. {
  1210. /* object */
  1211. librdf_node *node = NULL;
  1212. const str_uri_t uri = column_uri_string(stm, IDX_O_URI);
  1213. if( uri )
  1214. node = librdf_new_node_from_uri_string(w, uri);
  1215. if( !node ) {
  1216. const str_blank_t blank = column_blank_string(stm, IDX_O_BLANK);
  1217. if( blank )
  1218. node = librdf_new_node_from_blank_identifier(w, blank);
  1219. }
  1220. if( !node ) {
  1221. const str_lit_val_t val = (str_lit_val_t)sqlite3_column_text(stm, IDX_O_TEXT);
  1222. const str_lang_t lang = (str_lang_t)column_language(stm, IDX_O_LANGUAGE);
  1223. const str_uri_t uri = column_uri_string(stm, IDX_O_DATATYPE);
  1224. librdf_uri *t = uri ? librdf_new_uri(w, uri) : NULL;
  1225. node = librdf_new_node_from_typed_literal(w, val, lang, t);
  1226. librdf_free_uri(t);
  1227. }
  1228. if( !node )
  1229. return NULL;
  1230. librdf_statement_set_object(st, node);
  1231. }
  1232. assert(librdf_statement_is_complete(st) && "found statement must be complete");
  1233. assert( ( (NULL == ctx->pattern) || librdf_statement_match(st, ctx->pattern) ) && "match candidate doesn't match." );
  1234. assert(st == ctx->statement && "mismatch.");
  1235. ctx->dirty = false;
  1236. }
  1237. assert(librdf_statement_is_complete(ctx->statement) && "found statement must be complete");
  1238. assert( ( (NULL == ctx->pattern) || librdf_statement_match(ctx->statement, ctx->pattern) ) && "match candidate doesn't match." );
  1239. return ctx->statement;
  1240. }
  1241. case LIBRDF_ITERATOR_GET_METHOD_GET_CONTEXT:
  1242. return ctx->context;
  1243. default:
  1244. librdf_log(get_world(ctx->storage), 0, LIBRDF_LOG_ERROR, LIBRDF_FROM_STORAGE, NULL, "Unknown iterator method flag %d", flags);
  1245. return NULL;
  1246. }
  1247. return NULL;
  1248. }
  1249. static void pub_iter_finished(void *_ctx)
  1250. {
  1251. assert(_ctx && "context mustn't be NULL");
  1252. iterator_t *ctx = (iterator_t *)_ctx;
  1253. if( ctx->pattern )
  1254. librdf_free_statement(ctx->pattern);
  1255. if( ctx->statement )
  1256. librdf_free_statement(ctx->statement);
  1257. librdf_storage_remove_reference(ctx->storage);
  1258. transaction_rollback(ctx->storage, ctx->txn);
  1259. sqlite3_finalize(ctx->stmt);
  1260. LIBRDF_FREE(iterator_t *, ctx);
  1261. }
  1262. typedef struct
  1263. {
  1264. librdf_storage *storage;
  1265. librdf_node *context;
  1266. sqlite3_stmt *stmt;
  1267. sqlite_rc_t rc;
  1268. bool dirty;
  1269. }
  1270. context_iterator_t;
  1271. static int context_iter_is_end(void *_ctx)
  1272. {
  1273. assert(_ctx && "context mustn't be NULL");
  1274. context_iterator_t *ctx = (context_iterator_t *)_ctx;
  1275. return SQLITE_ROW != ctx->rc;
  1276. }
  1277. static int context_iter_get_next(void *_ctx)
  1278. {
  1279. assert(_ctx && "context mustn't be NULL");
  1280. context_iterator_t *ctx = (context_iterator_t *)_ctx;
  1281. if( context_iter_is_end(ctx) )
  1282. return RET_ERROR;
  1283. ctx->dirty = true;
  1284. ctx->rc = sqlite3_step(ctx->stmt);
  1285. if( context_iter_is_end(ctx) )
  1286. return RET_ERROR;
  1287. return RET_OK;
  1288. }
  1289. static void *context_iter_get_context(void *_ctx, const int _flags)
  1290. {
  1291. assert(_ctx && "context mustn't be NULL");
  1292. const librdf_iterator_get_method_flags flags = (librdf_iterator_get_method_flags)_flags;
  1293. context_iterator_t *ctx = (context_iterator_t *)_ctx;
  1294. switch( flags ) {
  1295. case LIBRDF_ITERATOR_GET_METHOD_GET_OBJECT:
  1296. break;
  1297. case LIBRDF_ITERATOR_GET_METHOD_GET_CONTEXT:
  1298. return NULL;
  1299. default:
  1300. librdf_log(get_world(ctx->storage), 0, LIBRDF_LOG_ERROR, LIBRDF_FROM_STORAGE, NULL, "Unknown iterator method flag %d", flags);
  1301. return NULL;
  1302. }
  1303. if( ctx->dirty && !context_iter_is_end(_ctx) ) {
  1304. assert(ctx->context && "context mustn't be NULL");
  1305. librdf_world *w = get_world(ctx->storage);
  1306. sqlite3_stmt *stm = ctx->stmt;
  1307. librdf_node *node = NULL;
  1308. const str_uri_t uri = column_uri_string(stm, 0);
  1309. if( uri )
  1310. node = librdf_new_node_from_uri_string(w, uri);
  1311. if( ctx->context )
  1312. librdf_free_node(ctx->context);
  1313. ctx->context = node;
  1314. ctx->dirty = false;
  1315. }
  1316. return ctx->context;
  1317. }
  1318. static void context_iter_finished(void *_ctx)
  1319. {
  1320. assert(_ctx && "context mustn't be NULL");
  1321. context_iterator_t *ctx = (context_iterator_t *)_ctx;
  1322. if( ctx->context )
  1323. librdf_free_node(ctx->context);
  1324. librdf_storage_remove_reference(ctx->storage);
  1325. sqlite3_finalize(ctx->stmt);
  1326. LIBRDF_FREE(iterator_t *, ctx);
  1327. }
  1328. #pragma mark Query & Iterate
  1329. static int pub_size(librdf_storage *storage)
  1330. {
  1331. instance_t *db_ctx = get_instance(storage);
  1332. sqlite3_stmt *stmt = prep_stmt(db_ctx->db, &(db_ctx->stmt_size), "SELECT COUNT(id) FROM triple_relations");
  1333. const sqlite_rc_t rc = sqlite3_step(stmt);
  1334. return SQLITE_ROW == rc ? sqlite3_column_int(stmt, 0) : -1;
  1335. }
  1336. static librdf_iterator *pub_get_contexts(librdf_storage *storage)
  1337. {
  1338. instance_t *db_ctx = get_instance(storage);
  1339. context_iterator_t *iter = LIBRDF_CALLOC(context_iterator_t*, sizeof(context_iterator_t), 1);
  1340. iter->storage = storage;
  1341. iter->stmt = prep_stmt(db_ctx->db, &(iter->stmt), "SELECT uri FROM c_uris");
  1342. if( !iter->stmt ) {
  1343. LIBRDF_FREE(context_iterator_t*, iter);
  1344. return NULL;
  1345. }
  1346. iter->rc = sqlite3_step(iter->stmt);
  1347. iter->dirty = true;
  1348. librdf_storage_add_reference(iter->storage);
  1349. 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);
  1350. if( !iterator ) {
  1351. context_iter_finished(iter);
  1352. }
  1353. return iterator;
  1354. }
  1355. static int pub_contains_statement(librdf_storage *storage, librdf_statement *statement)
  1356. {
  1357. return NULL != find_statement(storage, NULL, statement, false);
  1358. }
  1359. static librdf_stream *pub_context_find_statements(librdf_storage *storage, librdf_statement *statement, librdf_node *context_node)
  1360. {
  1361. librdf_node *s = librdf_statement_get_subject(statement);
  1362. librdf_node *p = librdf_statement_get_predicate(statement);
  1363. librdf_node *o = librdf_statement_get_object(statement);
  1364. // build the bitmask of parameters to set (non-NULL)
  1365. const int params = 0
  1366. | (LIBRDF_NODE_TYPE_RESOURCE == node_type(s) ? P_S_URI : 0)
  1367. | (LIBRDF_NODE_TYPE_BLANK == node_type(s) ? P_S_BLANK : 0)
  1368. | (LIBRDF_NODE_TYPE_RESOURCE == node_type(p) ? P_P_URI : 0)
  1369. | (LIBRDF_NODE_TYPE_RESOURCE == node_type(o) ? P_O_URI : 0)
  1370. | (LIBRDF_NODE_TYPE_BLANK == node_type(o) ? P_O_BLANK : 0)
  1371. | (LIBRDF_NODE_TYPE_LITERAL == node_type(o) ? P_O_TEXT : 0)
  1372. | (NULL != literal_type_uri(o) ? P_O_DATATYPE : 0)
  1373. | (NULL != literal_language(o) ? P_O_LANGUAGE : 0)
  1374. | (context_node ? P_C_URI : 0)
  1375. ;
  1376. assert(params <= ALL_PARAMS && "params bitmask overflow");
  1377. const sqlite_rc_t begin = RET_ERROR; // transaction_start(storage);
  1378. instance_t *db_ctx = get_instance(storage);
  1379. sqlite3_stmt *stmt = NULL;
  1380. {
  1381. const char find_triples_sql[] = // generated via tools/sql2c.sh find_triples.sql
  1382. " -- result columns must match as in enum idx_triple_column_t" "\n" \
  1383. "SELECT" "\n" \
  1384. " -- all *_id (hashes):" "\n" \
  1385. " id" "\n" \
  1386. " ,s_uri_id" "\n" \
  1387. " ,s_blank_id" "\n" \
  1388. " ,p_uri_id" "\n" \
  1389. " ,o_uri_id" "\n" \
  1390. " ,o_blank_id" "\n" \
  1391. " ,o_lit_id" "\n" \
  1392. " ,o_datatype_id" "\n" \
  1393. " ,c_uri_id" "\n" \
  1394. " -- all values:" "\n" \
  1395. " ,s_uri" "\n" \
  1396. " ,s_blank" "\n" \
  1397. " ,p_uri" "\n" \
  1398. " ,o_uri" "\n" \
  1399. " ,o_blank" "\n" \
  1400. " ,o_text" "\n" \
  1401. " ,o_language" "\n" \
  1402. " ,o_datatype" "\n" \
  1403. " ,c_uri" "\n" \
  1404. "FROM triples" "\n" \
  1405. "WHERE 1" "\n" \
  1406. " -- subject" "\n" \
  1407. "AND s_uri_id = :s_uri_id" "\n" \
  1408. "AND s_blank_id = :s_blank_id" "\n" \
  1409. "AND p_uri_id = :p_uri_id" "\n" \
  1410. " -- object" "\n" \
  1411. "AND o_uri_id = :o_uri_id" "\n" \
  1412. "AND o_blank_id = :o_blank_id" "\n" \
  1413. "AND o_lit_id = :o_lit_id" "\n" \
  1414. " -- context node" "\n" \
  1415. "AND c_uri_id = :c_uri_id" "\n" \
  1416. ;
  1417. // create a SQL working copy (on stack) to fiddle with.
  1418. const size_t siz = sizeof(find_triples_sql);
  1419. char sql[siz];
  1420. strncpy(sql, find_triples_sql, siz);
  1421. // sculpt the SQL instead building it: comment out the NULL parameter terms
  1422. if( 0 == (P_S_URI & params) )
  1423. strncpy(strstr(sql, "AND s_uri_id"), "-- ", 3);
  1424. assert('-' != sql[0] && "'AND s_uri_id' not found in find_triples.sql");
  1425. if( 0 == (P_S_BLANK & params) )
  1426. strncpy(strstr(sql, "AND s_blank_id"), "-- ", 3);
  1427. assert('-' != sql[0] && "'AND s_blank_id' not found in find_triples.sql");
  1428. if( 0 == (P_P_URI & params) )
  1429. strncpy(strstr(sql, "AND p_uri_id"), "-- ", 3);
  1430. assert('-' != sql[0] && "'AND p_uri_id' not found in find_triples.sql");
  1431. if( 0 == (P_O_URI & params) )
  1432. strncpy(strstr(sql, "AND o_uri_id"), "-- ", 3);
  1433. assert('-' != sql[0] && "'AND o_uri_id' not found in find_triples.sql");
  1434. if( 0 == (P_O_BLANK & params) )
  1435. strncpy(strstr(sql, "AND o_blank_id"), "-- ", 3);
  1436. assert('-' != sql[0] && "'AND o_blank_id' not found in find_triples.sql");
  1437. if( 0 == (P_O_TEXT & params) )
  1438. strncpy(strstr(sql, "AND o_lit_id"), "-- ", 3);
  1439. assert('-' != sql[0] && "'AND o_lit_id' not found in find_triples.sql");
  1440. if( 0 == (P_C_URI & params) )
  1441. strncpy(strstr(sql, "AND c_uri_id"), "-- ", 3);
  1442. assert('-' != sql[0] && "'AND c_uri_id' not found in find_triples.sql");
  1443. librdf_log(librdf_storage_get_world(storage), 0, LIBRDF_LOG_INFO, LIBRDF_FROM_STORAGE, NULL, "Created SQL statement #%d", params);
  1444. prep_stmt(db_ctx->db, &stmt, sql);
  1445. } // else if( false ) {
  1446. // toggle via "profile" feature?
  1447. // librdf_log( librdf_storage_get_world(storage), 0, LIBRDF_LOG_INFO, LIBRDF_FROM_STORAGE, NULL, "%s", librdf_statement_to_string(statement) );
  1448. // }
  1449. const sqlite_rc_t rc = bind_stmt(db_ctx, statement, context_node, stmt);
  1450. assert(SQLITE_OK == rc && "find_statements: failed to bind SQL parameters");
  1451. if( db_ctx->do_explain_query_plan ) {
  1452. librdf_log(librdf_storage_get_world(storage), 0, LIBRDF_LOG_INFO, LIBRDF_FROM_STORAGE, NULL, "Execute SQL statement #%d", params);
  1453. printExplainQueryPlan(stmt);
  1454. }
  1455. librdf_world *w = get_world(storage);
  1456. // create iterator
  1457. iterator_t *iter = LIBRDF_CALLOC(iterator_t *, sizeof(iterator_t), 1);
  1458. iter->storage = storage;
  1459. iter->context = context_node;
  1460. iter->pattern = librdf_new_statement_from_statement(statement);
  1461. iter->stmt = stmt;
  1462. iter->txn = begin;
  1463. iter->rc = sqlite3_step(stmt);
  1464. iter->statement = librdf_new_statement(w);
  1465. iter->dirty = true;
  1466. librdf_storage_add_reference(iter->storage);
  1467. librdf_stream *stream = librdf_new_stream(w, iter, &pub_iter_end_of_stream, &pub_iter_next_statement, &pub_iter_get_statement, &pub_iter_finished);
  1468. return stream;
  1469. }
  1470. static librdf_stream *pub_find_statements(librdf_storage *storage, librdf_statement *statement)
  1471. {
  1472. return pub_context_find_statements(storage, statement, NULL);
  1473. }
  1474. static librdf_stream *pub_context_serialise(librdf_storage *storage, librdf_node *context_node)
  1475. {
  1476. return pub_context_find_statements(storage, NULL, context_node);
  1477. }
  1478. static librdf_stream *pub_serialise(librdf_storage *storage)
  1479. {
  1480. return pub_context_serialise(storage, NULL);
  1481. }
  1482. #pragma mark Add
  1483. static int pub_context_add_statement(librdf_storage *storage, librdf_node *context_node, librdf_statement *statement)
  1484. {
  1485. if( !storage )
  1486. return RET_ERROR;
  1487. if( !statement )
  1488. return RET_OK;
  1489. // librdf_log( librdf_storage_get_world(storage), 0, LIBRDF_LOG_ERROR, LIBRDF_FROM_STORAGE, NULL, "%s", librdf_statement_to_string(statement) );
  1490. return NULL == find_statement(storage, context_node, statement, true) ? RET_ERROR : RET_OK;
  1491. }
  1492. static int pub_context_add_statements(librdf_storage *storage, librdf_node *context_node, librdf_stream *statement_stream)
  1493. {
  1494. const sqlite_rc_t txn = transaction_start(storage);
  1495. for( ; !librdf_stream_end(statement_stream); librdf_stream_next(statement_stream) ) {
  1496. librdf_statement *stmt = librdf_stream_get_object(statement_stream);
  1497. const int rc = pub_context_add_statement(storage, context_node, stmt);
  1498. if( RET_OK != rc ) {
  1499. transaction_rollback(storage, txn);
  1500. return rc;
  1501. }
  1502. }
  1503. return transaction_commit(storage, txn);
  1504. }
  1505. static int pub_add_statement(librdf_storage *storage, librdf_statement *statement)
  1506. {
  1507. return pub_context_add_statement(storage, NULL, statement);
  1508. }
  1509. static int pub_add_statements(librdf_storage *storage, librdf_stream *statement_stream)
  1510. {
  1511. return pub_context_add_statements(storage, NULL, statement_stream);
  1512. }
  1513. #pragma mark Remove
  1514. static int pub_context_remove_statement(librdf_storage *storage, librdf_node *context_node, librdf_statement *statement)
  1515. {
  1516. if( !statement )
  1517. return RET_OK;
  1518. if( !librdf_statement_is_complete(statement) )
  1519. return RET_ERROR;
  1520. assert(storage && "must be set");
  1521. instance_t *db_ctx = get_instance(storage);
  1522. const hash_t stmt_id = stmt_hash(statement, context_node, db_ctx->digest);
  1523. assert(!isNULL_ID(stmt_id) && "mustn't be nil");
  1524. sqlite3_stmt *stmt = prep_stmt(db_ctx->db, &(db_ctx->stmt_triple_delete), "DELETE FROM triples WHERE id = :stmt_id");
  1525. {
  1526. const sqlite_rc_t rc = bind_int(stmt, ":stmt_id", stmt_id);
  1527. if( SQLITE_OK != rc )
  1528. return rc;
  1529. }
  1530. const sqlite_rc_t rc = sqlite3_step(stmt);
  1531. return SQLITE_DONE == rc ? RET_OK : rc;
  1532. }
  1533. static int pub_remove_statement(librdf_storage *storage, librdf_statement *statement)
  1534. {
  1535. return pub_context_remove_statement(storage, NULL, statement);
  1536. }
  1537. #if 0
  1538. static int pub_context_remove_statements(librdf_storage *storage, librdf_node *context_node)
  1539. {
  1540. const sqlite_rc_t txn = transaction_start(storage);
  1541. for( librdf_statement *stmt = librdf_stream_get_object(statement_stream); !librdf_stream_end(statement_stream); librdf_stream_next(statement_stream) ) {
  1542. const int rc = pub_context_remove_statement(storage, context_node, stmt);
  1543. if( RET_OK != rc ) {
  1544. transaction_rollback(storage, txn);
  1545. return rc;
  1546. }
  1547. }
  1548. return transaction_commit(storage, txn);
  1549. }
  1550. #endif
  1551. #pragma mark Register Storage Factory
  1552. static void register_factory(librdf_storage_factory *factory)
  1553. {
  1554. assert(!strcmp(factory->name, LIBRDF_STORAGE_SQLITE_MRO) && "wrong factory name");
  1555. factory->version = LIBRDF_STORAGE_INTERFACE_VERSION;
  1556. factory->init = pub_init;
  1557. factory->terminate = pub_terminate;
  1558. factory->open = pub_open;
  1559. factory->close = pub_close;
  1560. factory->size = pub_size;
  1561. factory->add_statement = pub_add_statement;
  1562. factory->add_statements = pub_add_statements;
  1563. factory->remove_statement = pub_remove_statement;
  1564. factory->contains_statement = pub_contains_statement;
  1565. factory->serialise = pub_serialise;
  1566. factory->find_statements = pub_find_statements;
  1567. factory->context_add_statement = pub_context_add_statement;
  1568. factory->context_add_statements = pub_context_add_statements;
  1569. factory->context_remove_statement = pub_context_remove_statement;
  1570. // factory->context_remove_statements = pub_context_remove_statements; is this a 'clear' ?
  1571. factory->context_serialise = pub_context_serialise;
  1572. factory->find_statements_in_context = pub_context_find_statements;
  1573. factory->get_contexts = pub_get_contexts;
  1574. factory->get_feature = pub_get_feature;
  1575. factory->set_feature = pub_set_feature;
  1576. factory->transaction_start = pub_transaction_start;
  1577. factory->transaction_commit = pub_transaction_commit;
  1578. factory->transaction_rollback = pub_transaction_rollback;
  1579. }
  1580. int librdf_init_storage_sqlite_mro(librdf_world *world)
  1581. {
  1582. return librdf_storage_register_factory(world, LIBRDF_STORAGE_SQLITE_MRO, "SQLite", &register_factory);
  1583. }