/** * Entry point for the plugin. * * @param cls the "struct GNUNET_DATASTORE_PluginEnvironment*" * @return NULL on error, othrewise the plugin context */ void * libgnunet_plugin_datastore_sqlite_init (void *cls) { static struct Plugin plugin; struct GNUNET_DATASTORE_PluginEnvironment *env = cls; struct GNUNET_DATASTORE_PluginFunctions *api; if (plugin.env != NULL) return NULL; /* can only initialize once! */ memset (&plugin, 0, sizeof (struct Plugin)); plugin.env = env; if (GNUNET_OK != database_setup (env->cfg, &plugin)) { database_shutdown (&plugin); return NULL; } api = GNUNET_malloc (sizeof (struct GNUNET_DATASTORE_PluginFunctions)); api->cls = &plugin; api->estimate_size = &sqlite_plugin_estimate_size; api->put = &sqlite_plugin_put; api->update = &sqlite_plugin_update; api->get_key = &sqlite_plugin_get_key; api->get_replication = &sqlite_plugin_get_replication; api->get_expiration = &sqlite_plugin_get_expiration; api->get_zero_anonymity = &sqlite_plugin_get_zero_anonymity; api->get_keys = &sqlite_plugin_get_keys; api->drop = &sqlite_plugin_drop; GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "sqlite", _("Sqlite database running\n")); return api; }
/* ** verify succesful insertion of a molecular signature into a newly created ** rdtree virtual table. */ int main(int argc, char *argv[]) { int rc = SQLITE_OK; char *errMsg = 0; sqlite3 *db = 0; int closedb = 1; int rowid_count; int parent_count; int node_count; char sql1[] = "select count(*) from xyz_rowid"; char sql2[] = "select count(*) from xyz_parent"; char sql3[] = "select count(*) from xyz_node"; if ((rc = database_setup(":memory:", argv[1], &db, &errMsg)) != SQLITE_OK) { closedb = 0; printf("Failed database initialization\n"); } else if ((rc = create_rdtree(db, "xyz", 4, &errMsg)) != SQLITE_OK) { printf("Failed creation of virtual rdtree table\n"); } else if ((rc = insert_bitstring(db, "xyz", -1, "\x01\x02\x04\x08", 4)) != SQLITE_OK) { printf("Failed insertion\n"); } else if ((rc = select_integer(db, sql1, &rowid_count)) != SQLITE_OK) { printf("Couldn't query rowid table\n"); } else if ((rc = select_integer(db, sql2, &parent_count)) != SQLITE_OK) { printf("Couldn't query parent table\n"); } else if ((rc = select_integer(db, sql3, &node_count)) != SQLITE_OK) { printf("Couldn't query node table\n"); } else if (rowid_count != 1) { printf("Unexpected number of rowid records\n"); rc = SQLITE_MISMATCH; } else if (parent_count != 0) { printf("Unexpected number of parent records\n"); rc = SQLITE_MISMATCH; } else if (node_count != 1) { printf("Unexpected number of node records\n"); rc = SQLITE_MISMATCH; } if (closedb) { int rc2 = sqlite3_close(db); if (SQLITE_OK == rc) { rc = rc2; } } if (errMsg) { printf("%s\n", errMsg); sqlite3_free(errMsg); } return rc; }
/** * Entry point for the plugin. * * @param cls The struct GNUNET_CONFIGURATION_Handle. * @return NULL on error, otherwise the plugin context */ void * libgnunet_plugin_peerstore_sqlite_init (void *cls) { static struct Plugin plugin; const struct GNUNET_CONFIGURATION_Handle *cfg = cls; struct GNUNET_PEERSTORE_PluginFunctions *api; if (NULL != plugin.cfg) return NULL; /* can only initialize once! */ memset (&plugin, 0, sizeof (struct Plugin)); plugin.cfg = cfg; if (GNUNET_OK != database_setup (&plugin)) { database_shutdown (&plugin); return NULL; } api = GNUNET_new (struct GNUNET_PEERSTORE_PluginFunctions); api->cls = &plugin; api->store_record = &peerstore_sqlite_store_record; api->iterate_records = &peerstore_sqlite_iterate_records; api->expire_records = &peerstore_sqlite_expire_records; LOG (GNUNET_ERROR_TYPE_DEBUG, "Sqlite plugin is running\n"); return api; }
/** * Entry point for the plugin. * * @param cls the "struct GNUNET_NAMECACHE_PluginEnvironment*" * @return NULL on error, otherwise the plugin context */ void * libgnunet_plugin_namecache_sqlite_init (void *cls) { static struct Plugin plugin; const struct GNUNET_CONFIGURATION_Handle *cfg = cls; struct GNUNET_NAMECACHE_PluginFunctions *api; if (NULL != plugin.cfg) return NULL; /* can only initialize once! */ memset (&plugin, 0, sizeof (struct Plugin)); plugin.cfg = cfg; if (GNUNET_OK != database_setup (&plugin)) { database_shutdown (&plugin); return NULL; } api = GNUNET_new (struct GNUNET_NAMECACHE_PluginFunctions); api->cls = &plugin; api->cache_block = &namecache_sqlite_cache_block; api->lookup_block = &namecache_sqlite_lookup_block; LOG (GNUNET_ERROR_TYPE_INFO, _("Sqlite database running\n")); return api; }
/** * Execute statement that gets a row and call the callback * with the result. Resets the statement afterwards. * * @param plugin the plugin * @param stmt the statement * @param proc processor to call * @param proc_cls closure for 'proc' */ static void execute_get (struct Plugin *plugin, sqlite3_stmt * stmt, PluginDatumProcessor proc, void *proc_cls) { int n; struct GNUNET_TIME_Absolute expiration; unsigned long long rowid; unsigned int size; int ret; n = sqlite3_step (stmt); switch (n) { case SQLITE_ROW: size = sqlite3_column_bytes (stmt, 5); rowid = sqlite3_column_int64 (stmt, 6); if (sqlite3_column_bytes (stmt, 4) != sizeof (GNUNET_HashCode)) { GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "sqlite", _ ("Invalid data in database. Trying to fix (by deletion).\n")); if (SQLITE_OK != sqlite3_reset (stmt)) LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_reset"); if (GNUNET_OK == delete_by_rowid (plugin, rowid)) plugin->env->duc (plugin->env->cls, -(size + GNUNET_DATASTORE_ENTRY_OVERHEAD)); break; } expiration.abs_value = sqlite3_column_int64 (stmt, 3); GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", "Found reply in database with expiration %llu\n", (unsigned long long) expiration.abs_value); ret = proc (proc_cls, sqlite3_column_blob (stmt, 4) /* key */ , size, sqlite3_column_blob (stmt, 5) /* data */ , sqlite3_column_int (stmt, 0) /* type */ , sqlite3_column_int (stmt, 1) /* priority */ , sqlite3_column_int (stmt, 2) /* anonymity */ , expiration, rowid); if (SQLITE_OK != sqlite3_reset (stmt)) LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_reset"); if ((GNUNET_NO == ret) && (GNUNET_OK == delete_by_rowid (plugin, rowid))) plugin->env->duc (plugin->env->cls, -(size + GNUNET_DATASTORE_ENTRY_OVERHEAD)); return; case SQLITE_DONE: /* database must be empty */ if (SQLITE_OK != sqlite3_reset (stmt)) LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_reset"); break; case SQLITE_BUSY: case SQLITE_ERROR: case SQLITE_MISUSE: default: LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_step"); if (SQLITE_OK != sqlite3_reset (stmt)) LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_reset"); GNUNET_break (0); database_shutdown (plugin); database_setup (plugin->env->cfg, plugin); break; } if (SQLITE_OK != sqlite3_reset (stmt)) LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_reset"); proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); }
/** * Store an item in the datastore. * * @param cls closure * @param key key for the item * @param size number of bytes in data * @param data content stored * @param type type of the content * @param priority priority of the content * @param anonymity anonymity-level for the content * @param replication replication-level for the content * @param expiration expiration time for the content * @param msg set to an error message * @return GNUNET_OK on success */ static int sqlite_plugin_put (void *cls, const GNUNET_HashCode * key, uint32_t size, const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority, uint32_t anonymity, uint32_t replication, struct GNUNET_TIME_Absolute expiration, char **msg) { struct Plugin *plugin = cls; int n; int ret; sqlite3_stmt *stmt; GNUNET_HashCode vhash; uint64_t rvalue; if (size > MAX_ITEM_SIZE) return GNUNET_SYSERR; GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", "Storing in database block with type %u/key `%s'/priority %u/expiration in %llu ms (%lld).\n", type, GNUNET_h2s (key), priority, (unsigned long long) GNUNET_TIME_absolute_get_remaining (expiration).rel_value, (long long) expiration.abs_value); GNUNET_CRYPTO_hash (data, size, &vhash); stmt = plugin->insertContent; rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX); if ((SQLITE_OK != sqlite3_bind_int (stmt, 1, replication)) || (SQLITE_OK != sqlite3_bind_int (stmt, 2, type)) || (SQLITE_OK != sqlite3_bind_int (stmt, 3, priority)) || (SQLITE_OK != sqlite3_bind_int (stmt, 4, anonymity)) || (SQLITE_OK != sqlite3_bind_int64 (stmt, 5, expiration.abs_value)) || (SQLITE_OK != sqlite3_bind_int64 (stmt, 6, rvalue)) || (SQLITE_OK != sqlite3_bind_blob (stmt, 7, key, sizeof (GNUNET_HashCode), SQLITE_TRANSIENT)) || (SQLITE_OK != sqlite3_bind_blob (stmt, 8, &vhash, sizeof (GNUNET_HashCode), SQLITE_TRANSIENT)) || (SQLITE_OK != sqlite3_bind_blob (stmt, 9, data, size, SQLITE_TRANSIENT))) { LOG_SQLITE (plugin, msg, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_bind_XXXX"); if (SQLITE_OK != sqlite3_reset (stmt)) LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_reset"); return GNUNET_SYSERR; } n = sqlite3_step (stmt); switch (n) { case SQLITE_DONE: plugin->env->duc (plugin->env->cls, size + GNUNET_DATASTORE_ENTRY_OVERHEAD); GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", "Stored new entry (%u bytes)\n", size + GNUNET_DATASTORE_ENTRY_OVERHEAD); ret = GNUNET_OK; break; case SQLITE_BUSY: GNUNET_break (0); LOG_SQLITE (plugin, msg, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_step"); ret = GNUNET_SYSERR; break; default: LOG_SQLITE (plugin, msg, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_step"); if (SQLITE_OK != sqlite3_reset (stmt)) LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_reset"); database_shutdown (plugin); database_setup (plugin->env->cfg, plugin); return GNUNET_SYSERR; } if (SQLITE_OK != sqlite3_reset (stmt)) LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_reset"); return ret; }