2 This file is part of GNUnet
3 Copyright (C) 2006, 2009, 2015 GNUnet e.V.
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
17 * @file datacache/plugin_datacache_sqlite.c
18 * @brief sqlite for an implementation of a database backend for the datacache
19 * @author Christian Grothoff
22 #include "gnunet_util_lib.h"
23 #include "gnunet_datacache_plugin.h"
24 #include "gnunet_sq_lib.h"
27 #define LOG(kind,...) GNUNET_log_from (kind, "datacache-sqlite", __VA_ARGS__)
29 #define LOG_STRERROR_FILE(kind,op,fn) GNUNET_log_from_strerror_file (kind, "datacache-sqlite", op, fn)
33 * How much overhead do we assume per entry in the
36 #define OVERHEAD (sizeof(struct GNUNET_HashCode) + 36)
39 * Context for all functions in this plugin.
44 * Our execution environment.
46 struct GNUNET_DATACACHE_PluginEnvironment *env;
49 * Handle to the sqlite database.
54 * Filename used for the DB.
59 * Prepared statement for #sqlite_plugin_put.
61 sqlite3_stmt *insert_stmt;
64 * Prepared statement for #sqlite_plugin_get.
66 sqlite3_stmt *get_count_stmt;
69 * Prepared statement for #sqlite_plugin_get.
71 sqlite3_stmt *get_stmt;
74 * Prepared statement for #sqlite_plugin_del.
76 sqlite3_stmt *del_select_stmt;
79 * Prepared statement for #sqlite_plugin_del.
81 sqlite3_stmt *del_expired_stmt;
84 * Prepared statement for #sqlite_plugin_del.
86 sqlite3_stmt *del_stmt;
89 * Prepared statement for #sqlite_plugin_get_random.
91 sqlite3_stmt *get_random_stmt;
94 * Prepared statement for #sqlite_plugin_get_closest.
96 sqlite3_stmt *get_closest_stmt;
99 * Number of key-value pairs in the database.
101 unsigned int num_items;
106 * Log an error message at log-level @a level that indicates
107 * a failure of the command @a cmd with the error from the database @a db
109 * @param db database handle
110 * @param level log level
111 * @param cmd failed command
113 #define LOG_SQLITE(db, level, cmd) do { LOG (level, _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, sqlite3_errmsg(db)); } while(0)
117 * Execute SQL statement.
119 * @param db database handle
120 * @param cmd SQL command to execute
122 #define SQLITE3_EXEC(db, cmd) do { emsg = NULL; if (SQLITE_OK != sqlite3_exec(db, cmd, NULL, NULL, &emsg)) { LOG (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, _("`%s' failed at %s:%d with error: %s\n"), "sqlite3_exec", __FILE__, __LINE__, emsg); sqlite3_free(emsg); } } while(0)
126 * @brief Prepare a SQL statement
128 * @param dbh database handle
129 * @param zsql SQL statement text
130 * @param[out] ppStmt set to the prepared statement
131 * @return 0 on success
134 sq_prepare (sqlite3 *dbh,
135 const char *zSql, /* SQL statement, UTF-8 encoded */
136 sqlite3_stmt **ppStmt)
137 { /* OUT: Statement handle */
140 return sqlite3_prepare (dbh,
144 (const char **) &dummy);
149 * Store an item in the datastore.
151 * @param cls closure (our `struct Plugin`)
152 * @param key key to store @a data under
153 * @param xor_distance how close is @a key to our PID?
154 * @param size number of bytes in @a data
155 * @param data data to store
156 * @param type type of the value
157 * @param discard_time when to discard the value in any case
158 * @param path_info_len number of entries in @a path_info
159 * @param path_info array of peers that have processed the request
160 * @return 0 if duplicate, -1 on error, number of bytes used otherwise
163 sqlite_plugin_put (void *cls,
164 const struct GNUNET_HashCode *key,
165 uint32_t xor_distance,
168 enum GNUNET_BLOCK_Type type,
169 struct GNUNET_TIME_Absolute discard_time,
170 unsigned int path_info_len,
171 const struct GNUNET_PeerIdentity *path_info)
173 struct Plugin *plugin = cls;
174 uint32_t type32 = type;
175 struct GNUNET_SQ_QueryParam params[] = {
176 GNUNET_SQ_query_param_uint32 (&type32),
177 GNUNET_SQ_query_param_absolute_time (&discard_time),
178 GNUNET_SQ_query_param_auto_from_type (key),
179 GNUNET_SQ_query_param_uint32 (&xor_distance),
180 GNUNET_SQ_query_param_fixed_size (data, size),
181 GNUNET_SQ_query_param_fixed_size (path_info,
182 path_info_len * sizeof (struct GNUNET_PeerIdentity)),
183 GNUNET_SQ_query_param_end
186 LOG (GNUNET_ERROR_TYPE_DEBUG,
187 "Processing PUT of %u bytes with key `%s' and expiration %s\n",
190 GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_remaining (discard_time),
193 GNUNET_SQ_bind (plugin->insert_stmt,
196 LOG_SQLITE (plugin->dbh,
197 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
199 GNUNET_SQ_reset (plugin->dbh,
200 plugin->insert_stmt);
204 sqlite3_step (plugin->insert_stmt))
206 LOG_SQLITE (plugin->dbh,
207 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
209 GNUNET_SQ_reset (plugin->dbh,
210 plugin->insert_stmt);
214 GNUNET_SQ_reset (plugin->dbh,
215 plugin->insert_stmt);
216 return size + OVERHEAD;
221 * Iterate over the results for a particular key
224 * @param cls closure (our `struct Plugin`)
226 * @param type entries of which type are relevant?
227 * @param iter maybe NULL (to just count)
228 * @param iter_cls closure for @a iter
229 * @return the number of results found
232 sqlite_plugin_get (void *cls,
233 const struct GNUNET_HashCode *key,
234 enum GNUNET_BLOCK_Type type,
235 GNUNET_DATACACHE_Iterator iter,
238 struct Plugin *plugin = cls;
239 uint32_t type32 = type;
240 struct GNUNET_TIME_Absolute now;
241 struct GNUNET_TIME_Absolute exp;
248 struct GNUNET_PeerIdentity *path;
249 struct GNUNET_SQ_QueryParam params_count[] = {
250 GNUNET_SQ_query_param_auto_from_type (key),
251 GNUNET_SQ_query_param_uint32 (&type32),
252 GNUNET_SQ_query_param_absolute_time (&now),
253 GNUNET_SQ_query_param_end
255 struct GNUNET_SQ_QueryParam params_select[] = {
256 GNUNET_SQ_query_param_auto_from_type (key),
257 GNUNET_SQ_query_param_uint32 (&type32),
258 GNUNET_SQ_query_param_absolute_time (&now),
259 GNUNET_SQ_query_param_uint32 (&off),
260 GNUNET_SQ_query_param_end
262 struct GNUNET_SQ_ResultSpec rs[] = {
263 GNUNET_SQ_result_spec_variable_size (&dat,
265 GNUNET_SQ_result_spec_absolute_time (&exp),
266 GNUNET_SQ_result_spec_variable_size ((void **) &path,
268 GNUNET_SQ_result_spec_end
271 now = GNUNET_TIME_absolute_get ();
272 LOG (GNUNET_ERROR_TYPE_DEBUG,
273 "Processing GET for key `%s'\n",
277 GNUNET_SQ_bind (plugin->get_count_stmt,
280 LOG_SQLITE (plugin->dbh,
281 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
283 GNUNET_SQ_reset (plugin->dbh,
284 plugin->get_count_stmt);
288 sqlite3_step (plugin->get_count_stmt))
290 LOG_SQLITE (plugin->dbh, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
292 GNUNET_SQ_reset (plugin->dbh,
293 plugin->get_count_stmt);
294 LOG (GNUNET_ERROR_TYPE_DEBUG,
295 "No content found when processing GET for key `%s'\n",
299 total = sqlite3_column_int (plugin->get_count_stmt,
301 GNUNET_SQ_reset (plugin->dbh,
302 plugin->get_count_stmt);
307 LOG (GNUNET_ERROR_TYPE_DEBUG,
308 "No content found when processing GET for key `%s'\n",
314 off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
318 off = (off + 1) % total;
320 GNUNET_SQ_bind (plugin->get_stmt,
323 LOG_SQLITE (plugin->dbh,
324 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
326 GNUNET_SQ_reset (plugin->dbh,
331 sqlite3_step (plugin->get_stmt))
334 GNUNET_SQ_extract_result (plugin->get_stmt,
338 GNUNET_SQ_reset (plugin->dbh,
342 if (0 != psize % sizeof (struct GNUNET_PeerIdentity))
348 psize /= sizeof (struct GNUNET_PeerIdentity);
350 LOG (GNUNET_ERROR_TYPE_DEBUG,
351 "Found %u-byte result when processing GET for key `%s'\n",
354 if (GNUNET_OK != iter (iter_cls,
363 GNUNET_SQ_cleanup_result (rs);
364 GNUNET_SQ_reset (plugin->dbh,
368 GNUNET_SQ_cleanup_result (rs);
369 GNUNET_SQ_reset (plugin->dbh,
372 GNUNET_SQ_reset (plugin->dbh,
379 * Delete the entry with the lowest expiration value
380 * from the datacache right now.
382 * @param cls closure (our `struct Plugin`)
383 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
386 sqlite_plugin_del (void *cls)
388 struct Plugin *plugin = cls;
392 struct GNUNET_HashCode hc;
393 struct GNUNET_TIME_Absolute now;
394 struct GNUNET_SQ_ResultSpec rs[] = {
395 GNUNET_SQ_result_spec_uint64 (&rowid),
396 GNUNET_SQ_result_spec_auto_from_type (&hc),
397 GNUNET_SQ_result_spec_variable_size ((void **) &data,
399 GNUNET_SQ_result_spec_end
401 struct GNUNET_SQ_QueryParam params[] = {
402 GNUNET_SQ_query_param_uint64 (&rowid),
403 GNUNET_SQ_query_param_end
405 struct GNUNET_SQ_QueryParam time_params[] = {
406 GNUNET_SQ_query_param_absolute_time (&now),
407 GNUNET_SQ_query_param_end
410 LOG (GNUNET_ERROR_TYPE_DEBUG,
412 now = GNUNET_TIME_absolute_get ();
414 GNUNET_SQ_bind (plugin->del_expired_stmt,
417 LOG_SQLITE (plugin->dbh,
418 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
420 GNUNET_SQ_reset (plugin->dbh,
421 plugin->del_expired_stmt);
422 return GNUNET_SYSERR;
425 sqlite3_step (plugin->del_expired_stmt)) ||
427 GNUNET_SQ_extract_result (plugin->del_expired_stmt,
430 GNUNET_SQ_reset (plugin->dbh,
431 plugin->del_expired_stmt);
433 sqlite3_step (plugin->del_select_stmt))
435 LOG_SQLITE (plugin->dbh,
436 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
438 GNUNET_SQ_reset (plugin->dbh,
439 plugin->del_select_stmt);
440 return GNUNET_SYSERR;
443 GNUNET_SQ_extract_result (plugin->del_select_stmt,
446 GNUNET_SQ_reset (plugin->dbh,
447 plugin->del_select_stmt);
449 return GNUNET_SYSERR;
452 GNUNET_SQ_cleanup_result (rs);
453 GNUNET_SQ_reset (plugin->dbh,
454 plugin->del_select_stmt);
456 GNUNET_SQ_bind (plugin->del_stmt,
459 LOG_SQLITE (plugin->dbh,
460 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
462 GNUNET_SQ_reset (plugin->dbh,
464 return GNUNET_SYSERR;
467 sqlite3_step (plugin->del_stmt))
469 LOG_SQLITE (plugin->dbh,
470 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
472 GNUNET_SQ_reset (plugin->dbh,
474 return GNUNET_SYSERR;
477 plugin->env->delete_notify (plugin->env->cls,
480 GNUNET_SQ_reset (plugin->dbh,
487 * Obtain a random key-value pair from the datacache.
489 * @param cls closure (our `struct Plugin`)
490 * @param iter maybe NULL (to just count)
491 * @param iter_cls closure for @a iter
492 * @return the number of results found, zero (datacache empty) or one
495 sqlite_plugin_get_random (void *cls,
496 GNUNET_DATACACHE_Iterator iter,
499 struct Plugin *plugin = cls;
500 struct GNUNET_TIME_Absolute exp;
506 struct GNUNET_PeerIdentity *path;
507 struct GNUNET_HashCode key;
508 struct GNUNET_SQ_QueryParam params[] = {
509 GNUNET_SQ_query_param_uint32 (&off),
510 GNUNET_SQ_query_param_end
512 struct GNUNET_SQ_ResultSpec rs[] = {
513 GNUNET_SQ_result_spec_variable_size (&dat,
515 GNUNET_SQ_result_spec_absolute_time (&exp),
516 GNUNET_SQ_result_spec_variable_size ((void **) &path,
518 GNUNET_SQ_result_spec_auto_from_type (&key),
519 GNUNET_SQ_result_spec_uint32 (&type),
520 GNUNET_SQ_result_spec_end
523 if (0 == plugin->num_items)
527 off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
530 GNUNET_SQ_bind (plugin->get_random_stmt,
536 sqlite3_step (plugin->get_random_stmt))
539 GNUNET_SQ_reset (plugin->dbh,
540 plugin->get_random_stmt);
544 GNUNET_SQ_extract_result (plugin->get_random_stmt,
548 GNUNET_SQ_reset (plugin->dbh,
549 plugin->get_random_stmt);
552 if (0 != psize % sizeof (struct GNUNET_PeerIdentity))
558 psize /= sizeof (struct GNUNET_PeerIdentity);
559 LOG (GNUNET_ERROR_TYPE_DEBUG,
560 "Found %u-byte result with key %s when processing GET-RANDOM\n",
563 (void) iter (iter_cls,
567 (enum GNUNET_BLOCK_Type) type,
571 GNUNET_SQ_cleanup_result (rs);
572 GNUNET_SQ_reset (plugin->dbh,
573 plugin->get_random_stmt);
579 * Iterate over the results that are "close" to a particular key in
580 * the datacache. "close" is defined as numerically larger than @a
581 * key (when interpreted as a circular address space), with small
584 * @param cls closure (internal context for the plugin)
585 * @param key area of the keyspace to look into
586 * @param num_results number of results that should be returned to @a iter
587 * @param iter maybe NULL (to just count)
588 * @param iter_cls closure for @a iter
589 * @return the number of results found
592 sqlite_plugin_get_closest (void *cls,
593 const struct GNUNET_HashCode *key,
594 unsigned int num_results,
595 GNUNET_DATACACHE_Iterator iter,
598 struct Plugin *plugin = cls;
599 uint32_t num_results32 = num_results;
600 struct GNUNET_TIME_Absolute now;
601 struct GNUNET_TIME_Absolute exp;
607 struct GNUNET_HashCode hc;
608 struct GNUNET_PeerIdentity *path;
609 struct GNUNET_SQ_QueryParam params[] = {
610 GNUNET_SQ_query_param_auto_from_type (key),
611 GNUNET_SQ_query_param_absolute_time (&now),
612 GNUNET_SQ_query_param_uint32 (&num_results32),
613 GNUNET_SQ_query_param_end
615 struct GNUNET_SQ_ResultSpec rs[] = {
616 GNUNET_SQ_result_spec_variable_size (&dat,
618 GNUNET_SQ_result_spec_absolute_time (&exp),
619 GNUNET_SQ_result_spec_variable_size ((void **) &path,
621 GNUNET_SQ_result_spec_uint32 (&type),
622 GNUNET_SQ_result_spec_auto_from_type (&hc),
623 GNUNET_SQ_result_spec_end
626 now = GNUNET_TIME_absolute_get ();
627 LOG (GNUNET_ERROR_TYPE_DEBUG,
628 "Processing GET_CLOSEST for key `%s'\n",
631 GNUNET_SQ_bind (plugin->get_closest_stmt,
634 LOG_SQLITE (plugin->dbh,
635 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
637 GNUNET_SQ_reset (plugin->dbh,
638 plugin->get_closest_stmt);
643 sqlite3_step (plugin->get_closest_stmt))
646 GNUNET_SQ_extract_result (plugin->get_closest_stmt,
652 if (0 != psize % sizeof (struct GNUNET_PeerIdentity))
658 psize /= sizeof (struct GNUNET_PeerIdentity);
660 LOG (GNUNET_ERROR_TYPE_DEBUG,
661 "Found %u-byte result at %s when processing GET_CLOSE\n",
664 if (GNUNET_OK != iter (iter_cls,
673 GNUNET_SQ_cleanup_result (rs);
676 GNUNET_SQ_cleanup_result (rs);
678 GNUNET_SQ_reset (plugin->dbh,
679 plugin->get_closest_stmt);
685 * Entry point for the plugin.
687 * @param cls closure (the `struct GNUNET_DATACACHE_PluginEnvironment`)
688 * @return the plugin's closure (our `struct Plugin`)
691 libgnunet_plugin_datacache_sqlite_init (void *cls)
693 struct GNUNET_DATACACHE_PluginEnvironment *env = cls;
694 struct GNUNET_DATACACHE_PluginFunctions *api;
695 struct Plugin *plugin;
702 GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
706 if (SQLITE_OK != sqlite3_open (":memory:", &dbh))
712 fn = GNUNET_DISK_mktemp ("gnunet-datacache");
718 /* fn should be UTF-8-encoded. If it isn't, it's a bug. */
719 fn_utf8 = GNUNET_strdup (fn);
720 if (SQLITE_OK != sqlite3_open (fn_utf8, &dbh))
723 GNUNET_free (fn_utf8);
729 SQLITE3_EXEC (dbh, "PRAGMA temp_store=MEMORY");
730 SQLITE3_EXEC (dbh, "PRAGMA locking_mode=EXCLUSIVE");
731 SQLITE3_EXEC (dbh, "PRAGMA journal_mode=OFF");
732 SQLITE3_EXEC (dbh, "PRAGMA synchronous=OFF");
733 SQLITE3_EXEC (dbh, "PRAGMA page_size=4092");
735 GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
738 SQLITE3_EXEC (dbh, "PRAGMA sqlite_temp_store=3");
741 "CREATE TABLE ds091 ("
742 " type INTEGER NOT NULL DEFAULT 0,"
743 " expire INTEGER NOT NULL,"
744 " key BLOB NOT NULL DEFAULT '',"
745 " prox INTEGER NOT NULL,"
746 " value BLOB NOT NULL,"
747 " path BLOB DEFAULT '')");
748 SQLITE3_EXEC (dbh, "CREATE INDEX idx_hashidx ON ds091 (key,type,expire)");
749 SQLITE3_EXEC (dbh, "CREATE INDEX idx_expire ON ds091 (prox,expire)");
750 plugin = GNUNET_new (struct Plugin);
753 plugin->fn = fn_utf8;
756 sq_prepare (plugin->dbh,
757 "INSERT INTO ds091 (type, expire, key, prox, value, path) "
758 "VALUES (?, ?, ?, ?, ?, ?)",
759 &plugin->insert_stmt)) ||
761 sq_prepare (plugin->dbh,
762 "SELECT count(*) FROM ds091 "
763 "WHERE key=? AND type=? AND expire >= ?",
764 &plugin->get_count_stmt)) ||
766 sq_prepare (plugin->dbh,
767 "SELECT value,expire,path FROM ds091"
768 " WHERE key=? AND type=? AND expire >= ? LIMIT 1 OFFSET ?",
769 &plugin->get_stmt)) ||
771 sq_prepare (plugin->dbh,
772 "SELECT _ROWID_,key,value FROM ds091"
774 " ORDER BY expire ASC LIMIT 1",
775 &plugin->del_expired_stmt)) ||
777 sq_prepare (plugin->dbh,
778 "SELECT _ROWID_,key,value FROM ds091"
779 " ORDER BY prox ASC, expire ASC LIMIT 1",
780 &plugin->del_select_stmt)) ||
782 sq_prepare (plugin->dbh,
783 "DELETE FROM ds091 WHERE _ROWID_=?",
784 &plugin->del_stmt)) ||
786 sq_prepare (plugin->dbh,
787 "SELECT value,expire,path,key,type FROM ds091 "
788 "ORDER BY key LIMIT 1 OFFSET ?",
789 &plugin->get_random_stmt)) ||
791 sq_prepare (plugin->dbh,
792 "SELECT value,expire,path,type,key FROM ds091 "
793 "WHERE key>=? AND expire >= ? ORDER BY KEY ASC LIMIT ?",
794 &plugin->get_closest_stmt))
797 LOG_SQLITE (plugin->dbh,
798 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
800 GNUNET_break (SQLITE_OK ==
801 sqlite3_close (plugin->dbh));
802 GNUNET_free (plugin);
806 api = GNUNET_new (struct GNUNET_DATACACHE_PluginFunctions);
808 api->get = &sqlite_plugin_get;
809 api->put = &sqlite_plugin_put;
810 api->del = &sqlite_plugin_del;
811 api->get_random = &sqlite_plugin_get_random;
812 api->get_closest = &sqlite_plugin_get_closest;
813 LOG (GNUNET_ERROR_TYPE_INFO,
814 "Sqlite datacache running\n");
820 * Exit point from the plugin.
822 * @param cls closure (our `struct Plugin`)
826 libgnunet_plugin_datacache_sqlite_done (void *cls)
828 struct GNUNET_DATACACHE_PluginFunctions *api = cls;
829 struct Plugin *plugin = api->cls;
832 #if SQLITE_VERSION_NUMBER >= 3007000
836 #if !WINDOWS || defined(__CYGWIN__)
837 if ( (NULL != plugin->fn) &&
838 (0 != UNLINK (plugin->fn)) )
839 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING,
842 GNUNET_free_non_null (plugin->fn);
844 sqlite3_finalize (plugin->insert_stmt);
845 sqlite3_finalize (plugin->get_count_stmt);
846 sqlite3_finalize (plugin->get_stmt);
847 sqlite3_finalize (plugin->del_select_stmt);
848 sqlite3_finalize (plugin->del_expired_stmt);
849 sqlite3_finalize (plugin->del_stmt);
850 sqlite3_finalize (plugin->get_random_stmt);
851 sqlite3_finalize (plugin->get_closest_stmt);
852 result = sqlite3_close (plugin->dbh);
853 #if SQLITE_VERSION_NUMBER >= 3007000
854 if (SQLITE_BUSY == result)
856 LOG (GNUNET_ERROR_TYPE_WARNING,
857 _("Tried to close sqlite without finalizing all prepared statements.\n"));
858 stmt = sqlite3_next_stmt (plugin->dbh, NULL);
861 result = sqlite3_finalize (stmt);
862 if (result != SQLITE_OK)
863 LOG (GNUNET_ERROR_TYPE_WARNING,
864 "Failed to close statement %p: %d\n",
867 stmt = sqlite3_next_stmt (plugin->dbh, NULL);
869 result = sqlite3_close (plugin->dbh);
872 if (SQLITE_OK != result)
873 LOG_SQLITE (plugin->dbh,
874 GNUNET_ERROR_TYPE_ERROR,
877 #if WINDOWS && !defined(__CYGWIN__)
878 if ( (NULL != plugin->fn) &&
879 (0 != UNLINK (plugin->fn)) )
880 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING,
883 GNUNET_free_non_null (plugin->fn);
885 GNUNET_free (plugin);
892 /* end of plugin_datacache_sqlite.c */