+
+/**
+ * Delete records with the given key
+ *
+ * @param cls closure (internal context for the plugin)
+ * @param sub_system name of sub system
+ * @param peer Peer identity (can be NULL)
+ * @param key entry key string (can be NULL)
+ * @return number of deleted records, #GNUNE_SYSERR on error
+ */
+static int
+peerstore_sqlite_delete_records (void *cls,
+ const char *sub_system,
+ const struct GNUNET_PeerIdentity *peer,
+ const char *key)
+{
+ struct Plugin *plugin = cls;
+ sqlite3_stmt *stmt = plugin->delete_peerstoredata;
+ struct GNUNET_SQ_QueryParam params[] = {
+ GNUNET_SQ_query_param_string (sub_system),
+ GNUNET_SQ_query_param_auto_from_type (peer),
+ GNUNET_SQ_query_param_string (key),
+ GNUNET_SQ_query_param_end
+ };
+ int ret;
+
+ if (GNUNET_OK !=
+ GNUNET_SQ_bind (stmt,
+ params))
+ {
+ LOG_SQLITE (plugin,
+ GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+ "sqlite3_bind");
+ GNUNET_SQ_reset (plugin->dbh,
+ stmt);
+ return GNUNET_SYSERR;
+ }
+ if (SQLITE_DONE !=
+ sqlite3_step (stmt))
+ {
+ LOG_SQLITE (plugin,
+ GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+ "sqlite3_step");
+ ret = GNUNET_SYSERR;
+ }
+ else
+ {
+ ret = sqlite3_changes (plugin->dbh);
+ }
+ GNUNET_SQ_reset (plugin->dbh,
+ stmt);
+ return ret;
+}
+
+
+/**
+ * Delete expired records (expiry < now)
+ *
+ * @param cls closure (internal context for the plugin)
+ * @param now time to use as reference
+ * @param cont continuation called with the number of records expired
+ * @param cont_cls continuation closure
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error and cont is not
+ * called
+ */
+static int
+peerstore_sqlite_expire_records (void *cls, struct GNUNET_TIME_Absolute now,
+ GNUNET_PEERSTORE_Continuation cont,
+ void *cont_cls)
+{
+ struct Plugin *plugin = cls;
+ sqlite3_stmt *stmt = plugin->expire_peerstoredata;
+ struct GNUNET_SQ_QueryParam params[] = {
+ GNUNET_SQ_query_param_absolute_time (&now),
+ GNUNET_SQ_query_param_end
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_SQ_bind (stmt,
+ params))
+ {
+ LOG_SQLITE (plugin,
+ GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+ "sqlite3_bind");
+ GNUNET_SQ_reset (plugin->dbh,
+ stmt);
+ return GNUNET_SYSERR;
+ }
+ if (SQLITE_DONE != sqlite3_step (stmt))
+ {
+ LOG_SQLITE (plugin,
+ GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+ "sqlite3_step");
+ GNUNET_SQ_reset (plugin->dbh,
+ stmt);
+ return GNUNET_SYSERR;
+ }
+ if (NULL != cont)
+ cont (cont_cls,
+ sqlite3_changes (plugin->dbh));
+ GNUNET_SQ_reset (plugin->dbh,
+ stmt);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Iterate over the records given an optional peer id
+ * and/or key.
+ *
+ * @param cls closure (internal context for the plugin)
+ * @param sub_system name of sub system
+ * @param peer Peer identity (can be NULL)
+ * @param key entry key string (can be NULL)
+ * @param iter function to call asynchronously with the results, terminated
+ * by a NULL result
+ * @param iter_cls closure for @a iter
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error and iter is not
+ * called
+ */
+static int
+peerstore_sqlite_iterate_records (void *cls,
+ const char *sub_system,
+ const struct GNUNET_PeerIdentity *peer,
+ const char *key,
+ GNUNET_PEERSTORE_Processor iter,
+ void *iter_cls)
+{
+ struct Plugin *plugin = cls;
+ sqlite3_stmt *stmt;
+ int err = 0;
+ int sret;
+ struct GNUNET_PEERSTORE_Record rec;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Executing iterate request on sqlite db.\n");
+ if (NULL == peer)
+ {
+ if (NULL == key)
+ {
+ struct GNUNET_SQ_QueryParam params[] = {
+ GNUNET_SQ_query_param_string (sub_system),
+ GNUNET_SQ_query_param_end
+ };
+
+ stmt = plugin->select_peerstoredata;
+ err = GNUNET_SQ_bind (stmt,
+ params);
+ }
+ else
+ {
+ struct GNUNET_SQ_QueryParam params[] = {
+ GNUNET_SQ_query_param_string (sub_system),
+ GNUNET_SQ_query_param_string (key),
+ GNUNET_SQ_query_param_end
+ };
+
+ stmt = plugin->select_peerstoredata_by_key;
+ err = GNUNET_SQ_bind (stmt,
+ params);
+ }
+ }
+ else
+ {
+ if (NULL == key)
+ {
+ struct GNUNET_SQ_QueryParam params[] = {
+ GNUNET_SQ_query_param_string (sub_system),
+ GNUNET_SQ_query_param_auto_from_type (peer),
+ GNUNET_SQ_query_param_end
+ };
+
+ stmt = plugin->select_peerstoredata_by_pid;
+ err = GNUNET_SQ_bind (stmt,
+ params);
+ }
+ else
+ {
+ struct GNUNET_SQ_QueryParam params[] = {
+ GNUNET_SQ_query_param_string (sub_system),
+ GNUNET_SQ_query_param_auto_from_type (peer),
+ GNUNET_SQ_query_param_string (key),
+ GNUNET_SQ_query_param_end
+ };
+
+ stmt = plugin->select_peerstoredata_by_all;
+ err = GNUNET_SQ_bind (stmt,
+ params);
+ }
+ }
+
+ if (GNUNET_OK != err)
+ {
+ LOG_SQLITE (plugin,
+ GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+ "sqlite3_bind_XXXX");
+ GNUNET_SQ_reset (plugin->dbh,
+ stmt);
+ return GNUNET_SYSERR;
+ }
+
+ err = 0;
+ while (SQLITE_ROW == (sret = sqlite3_step (stmt)))
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Returning a matched record.\n");
+ struct GNUNET_SQ_ResultSpec rs[] = {
+ GNUNET_SQ_result_spec_string (&rec.sub_system),
+ GNUNET_SQ_result_spec_auto_from_type (&rec.peer),
+ GNUNET_SQ_result_spec_string (&rec.key),
+ GNUNET_SQ_result_spec_variable_size (&rec.value, &rec.value_size),
+ GNUNET_SQ_result_spec_absolute_time (&rec.expiry),
+ GNUNET_SQ_result_spec_end
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_SQ_extract_result (stmt,
+ rs))
+ {
+ GNUNET_break (0);
+ break;
+ }
+ if (NULL != iter)
+ iter (iter_cls,
+ &rec,
+ NULL);
+ GNUNET_SQ_cleanup_result (rs);
+ }
+ if (SQLITE_DONE != sret)
+ {
+ LOG_SQLITE (plugin,
+ GNUNET_ERROR_TYPE_ERROR,
+ "sqlite_step");
+ err = 1;
+ }
+ GNUNET_SQ_reset (plugin->dbh,
+ stmt);
+ if (NULL != iter)
+ iter (iter_cls,
+ NULL,
+ err ? "sqlite error" : NULL);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Store a record in the peerstore.
+ * Key is the combination of sub system and peer identity.
+ * One key can store multiple values.
+ *
+ * @param cls closure (internal context for the plugin)
+ * @param sub_system name of the GNUnet sub system responsible
+ * @param peer peer identity
+ * @param key record key string
+ * @param value value to be stored
+ * @param size size of value to be stored
+ * @param expiry absolute time after which the record is (possibly) deleted
+ * @param options options related to the store operation
+ * @param cont continuation called when record is stored
+ * @param cont_cls continuation closure
+ * @return #GNUNET_OK on success, else #GNUNET_SYSERR and cont is not called
+ */
+static int
+peerstore_sqlite_store_record (void *cls,
+ const char *sub_system,
+ const struct GNUNET_PeerIdentity *peer,
+ const char *key,
+ const void *value,
+ size_t size,
+ struct GNUNET_TIME_Absolute expiry,
+ enum GNUNET_PEERSTORE_StoreOption options,
+ GNUNET_PEERSTORE_Continuation cont,
+ void *cont_cls)
+{
+ struct Plugin *plugin = cls;
+ sqlite3_stmt *stmt = plugin->insert_peerstoredata;
+ struct GNUNET_SQ_QueryParam params[] = {
+ GNUNET_SQ_query_param_string (sub_system),
+ GNUNET_SQ_query_param_auto_from_type (peer),
+ GNUNET_SQ_query_param_string (key),
+ GNUNET_SQ_query_param_fixed_size (value, size),
+ GNUNET_SQ_query_param_absolute_time (&expiry),
+ GNUNET_SQ_query_param_end
+ };
+
+ if (GNUNET_PEERSTORE_STOREOPTION_REPLACE == options)
+ {
+ peerstore_sqlite_delete_records (cls,
+ sub_system,
+ peer,
+ key);
+ }
+ if (GNUNET_OK !=
+ GNUNET_SQ_bind (stmt,
+ params))
+ LOG_SQLITE (plugin,
+ GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+ "sqlite3_bind");
+ else if (SQLITE_DONE != sqlite3_step (stmt))
+ {
+ LOG_SQLITE (plugin,
+ GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+ "sqlite3_step");
+ }
+ GNUNET_SQ_reset (plugin->dbh,
+ stmt);
+ if (NULL != cont)
+ cont (cont_cls,
+ GNUNET_OK);
+ return GNUNET_OK;
+}
+
+