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 Affero 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.
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 * @file datacache/plugin_datacache_sqlite.c
21 * @brief sqlite for an implementation of a database backend for the datacache
22 * @author Christian Grothoff
25 #include "gnunet_util_lib.h"
26 #include "gnunet_datacache_plugin.h"
27 #include "gnunet_sq_lib.h"
30 #define LOG(kind,...) GNUNET_log_from (kind, "datacache-sqlite", __VA_ARGS__)
32 #define LOG_STRERROR_FILE(kind,op,fn) GNUNET_log_from_strerror_file (kind, "datacache-sqlite", op, fn)
36 * How much overhead do we assume per entry in the
39 #define OVERHEAD (sizeof(struct GNUNET_HashCode) + 36)
42 * Context for all functions in this plugin.
47 * Our execution environment.
49 struct GNUNET_DATACACHE_PluginEnvironment *env;
52 * Handle to the sqlite database.
57 * Filename used for the DB.
62 * Prepared statement for #sqlite_plugin_put.
64 sqlite3_stmt *insert_stmt;
67 * Prepared statement for #sqlite_plugin_get.
69 sqlite3_stmt *get_count_stmt;
72 * Prepared statement for #sqlite_plugin_get.
74 sqlite3_stmt *get_stmt;
77 * Prepared statement for #sqlite_plugin_del.
79 sqlite3_stmt *del_select_stmt;
82 * Prepared statement for #sqlite_plugin_del.
84 sqlite3_stmt *del_expired_stmt;
87 * Prepared statement for #sqlite_plugin_del.
89 sqlite3_stmt *del_stmt;
92 * Prepared statement for #sqlite_plugin_get_random.
94 sqlite3_stmt *get_random_stmt;
97 * Prepared statement for #sqlite_plugin_get_closest.
99 sqlite3_stmt *get_closest_stmt;
102 * Number of key-value pairs in the database.
104 unsigned int num_items;
109 * Log an error message at log-level @a level that indicates
110 * a failure of the command @a cmd with the error from the database @a db
112 * @param db database handle
113 * @param level log level
114 * @param cmd failed command
116 #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)
120 * Execute SQL statement.
122 * @param db database handle
123 * @param cmd SQL command to execute
125 #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)
129 * @brief Prepare a SQL statement
131 * @param dbh database handle
132 * @param zsql SQL statement text
133 * @param[out] ppStmt set to the prepared statement
134 * @return 0 on success
137 sq_prepare (sqlite3 *dbh,
138 const char *zSql, /* SQL statement, UTF-8 encoded */
139 sqlite3_stmt **ppStmt)
140 { /* OUT: Statement handle */
143 return sqlite3_prepare (dbh,
147 (const char **) &dummy);
152 * Store an item in the datastore.
154 * @param cls closure (our `struct Plugin`)
155 * @param key key to store @a data under
156 * @param xor_distance how close is @a key to our PID?
157 * @param size number of bytes in @a data
158 * @param data data to store
159 * @param type type of the value
160 * @param discard_time when to discard the value in any case
161 * @param path_info_len number of entries in @a path_info
162 * @param path_info array of peers that have processed the request
163 * @return 0 if duplicate, -1 on error, number of bytes used otherwise
166 sqlite_plugin_put (void *cls,
167 const struct GNUNET_HashCode *key,
168 uint32_t xor_distance,
171 enum GNUNET_BLOCK_Type type,
172 struct GNUNET_TIME_Absolute discard_time,
173 unsigned int path_info_len,
174 const struct GNUNET_PeerIdentity *path_info)
176 struct Plugin *plugin = cls;
177 uint32_t type32 = type;
178 struct GNUNET_SQ_QueryParam params[] = {
179 GNUNET_SQ_query_param_uint32 (&type32),
180 GNUNET_SQ_query_param_absolute_time (&discard_time),
181 GNUNET_SQ_query_param_auto_from_type (key),
182 GNUNET_SQ_query_param_uint32 (&xor_distance),
183 GNUNET_SQ_query_param_fixed_size (data, size),
184 GNUNET_SQ_query_param_fixed_size (path_info,
185 path_info_len * sizeof (struct GNUNET_PeerIdentity)),
186 GNUNET_SQ_query_param_end
189 LOG (GNUNET_ERROR_TYPE_DEBUG,
190 "Processing PUT of %u bytes with key `%s' and expiration %s\n",
193 GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_remaining (discard_time),
196 GNUNET_SQ_bind (plugin->insert_stmt,
199 LOG_SQLITE (plugin->dbh,
200 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
202 GNUNET_SQ_reset (plugin->dbh,
203 plugin->insert_stmt);
207 sqlite3_step (plugin->insert_stmt))
209 LOG_SQLITE (plugin->dbh,
210 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
212 GNUNET_SQ_reset (plugin->dbh,
213 plugin->insert_stmt);
217 GNUNET_SQ_reset (plugin->dbh,
218 plugin->insert_stmt);
219 return size + OVERHEAD;
224 * Iterate over the results for a particular key
227 * @param cls closure (our `struct Plugin`)
229 * @param type entries of which type are relevant?
230 * @param iter maybe NULL (to just count)
231 * @param iter_cls closure for @a iter
232 * @return the number of results found
235 sqlite_plugin_get (void *cls,
236 const struct GNUNET_HashCode *key,
237 enum GNUNET_BLOCK_Type type,
238 GNUNET_DATACACHE_Iterator iter,
241 struct Plugin *plugin = cls;
242 uint32_t type32 = type;
243 struct GNUNET_TIME_Absolute now;
244 struct GNUNET_TIME_Absolute exp;
251 struct GNUNET_PeerIdentity *path;
252 struct GNUNET_SQ_QueryParam params_count[] = {
253 GNUNET_SQ_query_param_auto_from_type (key),
254 GNUNET_SQ_query_param_uint32 (&type32),
255 GNUNET_SQ_query_param_absolute_time (&now),
256 GNUNET_SQ_query_param_end
258 struct GNUNET_SQ_QueryParam params_select[] = {
259 GNUNET_SQ_query_param_auto_from_type (key),
260 GNUNET_SQ_query_param_uint32 (&type32),
261 GNUNET_SQ_query_param_absolute_time (&now),
262 GNUNET_SQ_query_param_uint32 (&off),
263 GNUNET_SQ_query_param_end
265 struct GNUNET_SQ_ResultSpec rs[] = {
266 GNUNET_SQ_result_spec_variable_size (&dat,
268 GNUNET_SQ_result_spec_absolute_time (&exp),
269 GNUNET_SQ_result_spec_variable_size ((void **) &path,
271 GNUNET_SQ_result_spec_end
274 now = GNUNET_TIME_absolute_get ();
275 LOG (GNUNET_ERROR_TYPE_DEBUG,
276 "Processing GET for key `%s'\n",
280 GNUNET_SQ_bind (plugin->get_count_stmt,
283 LOG_SQLITE (plugin->dbh,
284 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
286 GNUNET_SQ_reset (plugin->dbh,
287 plugin->get_count_stmt);
291 sqlite3_step (plugin->get_count_stmt))
293 LOG_SQLITE (plugin->dbh, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
295 GNUNET_SQ_reset (plugin->dbh,
296 plugin->get_count_stmt);
297 LOG (GNUNET_ERROR_TYPE_DEBUG,
298 "No content found when processing GET for key `%s'\n",
302 total = sqlite3_column_int (plugin->get_count_stmt,
304 GNUNET_SQ_reset (plugin->dbh,
305 plugin->get_count_stmt);
310 LOG (GNUNET_ERROR_TYPE_DEBUG,
311 "No content found when processing GET for key `%s'\n",
317 off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
321 off = (off + 1) % total;
323 GNUNET_SQ_bind (plugin->get_stmt,
326 LOG_SQLITE (plugin->dbh,
327 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
329 GNUNET_SQ_reset (plugin->dbh,
334 sqlite3_step (plugin->get_stmt))
337 GNUNET_SQ_extract_result (plugin->get_stmt,
341 GNUNET_SQ_reset (plugin->dbh,
345 if (0 != psize % sizeof (struct GNUNET_PeerIdentity))
351 psize /= sizeof (struct GNUNET_PeerIdentity);
353 LOG (GNUNET_ERROR_TYPE_DEBUG,
354 "Found %u-byte result when processing GET for key `%s'\n",
357 if (GNUNET_OK != iter (iter_cls,
366 GNUNET_SQ_cleanup_result (rs);
367 GNUNET_SQ_reset (plugin->dbh,
371 GNUNET_SQ_cleanup_result (rs);
372 GNUNET_SQ_reset (plugin->dbh,
375 GNUNET_SQ_reset (plugin->dbh,
382 * Delete the entry with the lowest expiration value
383 * from the datacache right now.
385 * @param cls closure (our `struct Plugin`)
386 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
389 sqlite_plugin_del (void *cls)
391 struct Plugin *plugin = cls;
395 struct GNUNET_HashCode hc;
396 struct GNUNET_TIME_Absolute now;
397 struct GNUNET_SQ_ResultSpec rs[] = {
398 GNUNET_SQ_result_spec_uint64 (&rowid),
399 GNUNET_SQ_result_spec_auto_from_type (&hc),
400 GNUNET_SQ_result_spec_variable_size ((void **) &data,
402 GNUNET_SQ_result_spec_end
404 struct GNUNET_SQ_QueryParam params[] = {
405 GNUNET_SQ_query_param_uint64 (&rowid),
406 GNUNET_SQ_query_param_end
408 struct GNUNET_SQ_QueryParam time_params[] = {
409 GNUNET_SQ_query_param_absolute_time (&now),
410 GNUNET_SQ_query_param_end
413 LOG (GNUNET_ERROR_TYPE_DEBUG,
415 now = GNUNET_TIME_absolute_get ();
417 GNUNET_SQ_bind (plugin->del_expired_stmt,
420 LOG_SQLITE (plugin->dbh,
421 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
423 GNUNET_SQ_reset (plugin->dbh,
424 plugin->del_expired_stmt);
425 return GNUNET_SYSERR;
428 sqlite3_step (plugin->del_expired_stmt)) ||
430 GNUNET_SQ_extract_result (plugin->del_expired_stmt,
433 GNUNET_SQ_reset (plugin->dbh,
434 plugin->del_expired_stmt);
436 sqlite3_step (plugin->del_select_stmt))
438 LOG_SQLITE (plugin->dbh,
439 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
441 GNUNET_SQ_reset (plugin->dbh,
442 plugin->del_select_stmt);
443 return GNUNET_SYSERR;
446 GNUNET_SQ_extract_result (plugin->del_select_stmt,
449 GNUNET_SQ_reset (plugin->dbh,
450 plugin->del_select_stmt);
452 return GNUNET_SYSERR;
455 GNUNET_SQ_cleanup_result (rs);
456 GNUNET_SQ_reset (plugin->dbh,
457 plugin->del_select_stmt);
459 GNUNET_SQ_bind (plugin->del_stmt,
462 LOG_SQLITE (plugin->dbh,
463 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
465 GNUNET_SQ_reset (plugin->dbh,
467 return GNUNET_SYSERR;
470 sqlite3_step (plugin->del_stmt))
472 LOG_SQLITE (plugin->dbh,
473 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
475 GNUNET_SQ_reset (plugin->dbh,
477 return GNUNET_SYSERR;
480 plugin->env->delete_notify (plugin->env->cls,
483 GNUNET_SQ_reset (plugin->dbh,
490 * Obtain a random key-value pair from the datacache.
492 * @param cls closure (our `struct Plugin`)
493 * @param iter maybe NULL (to just count)
494 * @param iter_cls closure for @a iter
495 * @return the number of results found, zero (datacache empty) or one
498 sqlite_plugin_get_random (void *cls,
499 GNUNET_DATACACHE_Iterator iter,
502 struct Plugin *plugin = cls;
503 struct GNUNET_TIME_Absolute exp;
509 struct GNUNET_PeerIdentity *path;
510 struct GNUNET_HashCode key;
511 struct GNUNET_SQ_QueryParam params[] = {
512 GNUNET_SQ_query_param_uint32 (&off),
513 GNUNET_SQ_query_param_end
515 struct GNUNET_SQ_ResultSpec rs[] = {
516 GNUNET_SQ_result_spec_variable_size (&dat,
518 GNUNET_SQ_result_spec_absolute_time (&exp),
519 GNUNET_SQ_result_spec_variable_size ((void **) &path,
521 GNUNET_SQ_result_spec_auto_from_type (&key),
522 GNUNET_SQ_result_spec_uint32 (&type),
523 GNUNET_SQ_result_spec_end
526 if (0 == plugin->num_items)
530 off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
533 GNUNET_SQ_bind (plugin->get_random_stmt,
539 sqlite3_step (plugin->get_random_stmt))
542 GNUNET_SQ_reset (plugin->dbh,
543 plugin->get_random_stmt);
547 GNUNET_SQ_extract_result (plugin->get_random_stmt,
551 GNUNET_SQ_reset (plugin->dbh,
552 plugin->get_random_stmt);
555 if (0 != psize % sizeof (struct GNUNET_PeerIdentity))
561 psize /= sizeof (struct GNUNET_PeerIdentity);
562 LOG (GNUNET_ERROR_TYPE_DEBUG,
563 "Found %u-byte result with key %s when processing GET-RANDOM\n",
566 (void) iter (iter_cls,
570 (enum GNUNET_BLOCK_Type) type,
574 GNUNET_SQ_cleanup_result (rs);
575 GNUNET_SQ_reset (plugin->dbh,
576 plugin->get_random_stmt);
582 * Iterate over the results that are "close" to a particular key in
583 * the datacache. "close" is defined as numerically larger than @a
584 * key (when interpreted as a circular address space), with small
587 * @param cls closure (internal context for the plugin)
588 * @param key area of the keyspace to look into
589 * @param num_results number of results that should be returned to @a iter
590 * @param iter maybe NULL (to just count)
591 * @param iter_cls closure for @a iter
592 * @return the number of results found
595 sqlite_plugin_get_closest (void *cls,
596 const struct GNUNET_HashCode *key,
597 unsigned int num_results,
598 GNUNET_DATACACHE_Iterator iter,
601 struct Plugin *plugin = cls;
602 uint32_t num_results32 = num_results;
603 struct GNUNET_TIME_Absolute now;
604 struct GNUNET_TIME_Absolute exp;
610 struct GNUNET_HashCode hc;
611 struct GNUNET_PeerIdentity *path;
612 struct GNUNET_SQ_QueryParam params[] = {
613 GNUNET_SQ_query_param_auto_from_type (key),
614 GNUNET_SQ_query_param_absolute_time (&now),
615 GNUNET_SQ_query_param_uint32 (&num_results32),
616 GNUNET_SQ_query_param_end
618 struct GNUNET_SQ_ResultSpec rs[] = {
619 GNUNET_SQ_result_spec_variable_size (&dat,
621 GNUNET_SQ_result_spec_absolute_time (&exp),
622 GNUNET_SQ_result_spec_variable_size ((void **) &path,
624 GNUNET_SQ_result_spec_uint32 (&type),
625 GNUNET_SQ_result_spec_auto_from_type (&hc),
626 GNUNET_SQ_result_spec_end
629 now = GNUNET_TIME_absolute_get ();
630 LOG (GNUNET_ERROR_TYPE_DEBUG,
631 "Processing GET_CLOSEST for key `%s'\n",
634 GNUNET_SQ_bind (plugin->get_closest_stmt,
637 LOG_SQLITE (plugin->dbh,
638 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
640 GNUNET_SQ_reset (plugin->dbh,
641 plugin->get_closest_stmt);
646 sqlite3_step (plugin->get_closest_stmt))
649 GNUNET_SQ_extract_result (plugin->get_closest_stmt,
655 if (0 != psize % sizeof (struct GNUNET_PeerIdentity))
661 psize /= sizeof (struct GNUNET_PeerIdentity);
663 LOG (GNUNET_ERROR_TYPE_DEBUG,
664 "Found %u-byte result at %s when processing GET_CLOSE\n",
667 if (GNUNET_OK != iter (iter_cls,
676 GNUNET_SQ_cleanup_result (rs);
679 GNUNET_SQ_cleanup_result (rs);
681 GNUNET_SQ_reset (plugin->dbh,
682 plugin->get_closest_stmt);
688 * Entry point for the plugin.
690 * @param cls closure (the `struct GNUNET_DATACACHE_PluginEnvironment`)
691 * @return the plugin's closure (our `struct Plugin`)
694 libgnunet_plugin_datacache_sqlite_init (void *cls)
696 struct GNUNET_DATACACHE_PluginEnvironment *env = cls;
697 struct GNUNET_DATACACHE_PluginFunctions *api;
698 struct Plugin *plugin;
705 GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
709 if (SQLITE_OK != sqlite3_open (":memory:", &dbh))
715 fn = GNUNET_DISK_mktemp ("gnunet-datacache");
721 /* fn should be UTF-8-encoded. If it isn't, it's a bug. */
722 fn_utf8 = GNUNET_strdup (fn);
723 if (SQLITE_OK != sqlite3_open (fn_utf8, &dbh))
726 GNUNET_free (fn_utf8);
732 SQLITE3_EXEC (dbh, "PRAGMA temp_store=MEMORY");
733 SQLITE3_EXEC (dbh, "PRAGMA locking_mode=EXCLUSIVE");
734 SQLITE3_EXEC (dbh, "PRAGMA journal_mode=OFF");
735 SQLITE3_EXEC (dbh, "PRAGMA synchronous=OFF");
736 SQLITE3_EXEC (dbh, "PRAGMA page_size=4092");
738 GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
741 SQLITE3_EXEC (dbh, "PRAGMA sqlite_temp_store=3");
744 "CREATE TABLE ds091 ("
745 " type INTEGER NOT NULL DEFAULT 0,"
746 " expire INTEGER NOT NULL,"
747 " key BLOB NOT NULL DEFAULT '',"
748 " prox INTEGER NOT NULL,"
749 " value BLOB NOT NULL,"
750 " path BLOB DEFAULT '')");
751 SQLITE3_EXEC (dbh, "CREATE INDEX idx_hashidx ON ds091 (key,type,expire)");
752 SQLITE3_EXEC (dbh, "CREATE INDEX idx_prox_expire ON ds091 (prox,expire)");
753 SQLITE3_EXEC (dbh, "CREATE INDEX idx_expire_only ON ds091 (expire)");
754 plugin = GNUNET_new (struct Plugin);
757 plugin->fn = fn_utf8;
760 sq_prepare (plugin->dbh,
761 "INSERT INTO ds091 (type, expire, key, prox, value, path) "
762 "VALUES (?, ?, ?, ?, ?, ?)",
763 &plugin->insert_stmt)) ||
765 sq_prepare (plugin->dbh,
766 "SELECT count(*) FROM ds091 "
767 "WHERE key=? AND type=? AND expire >= ?",
768 &plugin->get_count_stmt)) ||
770 sq_prepare (plugin->dbh,
771 "SELECT value,expire,path FROM ds091"
772 " WHERE key=? AND type=? AND expire >= ? LIMIT 1 OFFSET ?",
773 &plugin->get_stmt)) ||
775 sq_prepare (plugin->dbh,
776 "SELECT _ROWID_,key,value FROM ds091"
778 " ORDER BY expire ASC LIMIT 1",
779 &plugin->del_expired_stmt)) ||
781 sq_prepare (plugin->dbh,
782 "SELECT _ROWID_,key,value FROM ds091"
783 " ORDER BY prox ASC, expire ASC LIMIT 1",
784 &plugin->del_select_stmt)) ||
786 sq_prepare (plugin->dbh,
787 "DELETE FROM ds091 WHERE _ROWID_=?",
788 &plugin->del_stmt)) ||
790 sq_prepare (plugin->dbh,
791 "SELECT value,expire,path,key,type FROM ds091 "
792 "ORDER BY key LIMIT 1 OFFSET ?",
793 &plugin->get_random_stmt)) ||
795 sq_prepare (plugin->dbh,
796 "SELECT value,expire,path,type,key FROM ds091 "
797 "WHERE key>=? AND expire >= ? ORDER BY KEY ASC LIMIT ?",
798 &plugin->get_closest_stmt))
801 LOG_SQLITE (plugin->dbh,
802 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
804 GNUNET_break (SQLITE_OK ==
805 sqlite3_close (plugin->dbh));
806 GNUNET_free (plugin);
810 api = GNUNET_new (struct GNUNET_DATACACHE_PluginFunctions);
812 api->get = &sqlite_plugin_get;
813 api->put = &sqlite_plugin_put;
814 api->del = &sqlite_plugin_del;
815 api->get_random = &sqlite_plugin_get_random;
816 api->get_closest = &sqlite_plugin_get_closest;
817 LOG (GNUNET_ERROR_TYPE_INFO,
818 "Sqlite datacache running\n");
824 * Exit point from the plugin.
826 * @param cls closure (our `struct Plugin`)
830 libgnunet_plugin_datacache_sqlite_done (void *cls)
832 struct GNUNET_DATACACHE_PluginFunctions *api = cls;
833 struct Plugin *plugin = api->cls;
836 #if SQLITE_VERSION_NUMBER >= 3007000
840 #if !WINDOWS || defined(__CYGWIN__)
841 if ( (NULL != plugin->fn) &&
842 (0 != UNLINK (plugin->fn)) )
843 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING,
846 GNUNET_free_non_null (plugin->fn);
848 sqlite3_finalize (plugin->insert_stmt);
849 sqlite3_finalize (plugin->get_count_stmt);
850 sqlite3_finalize (plugin->get_stmt);
851 sqlite3_finalize (plugin->del_select_stmt);
852 sqlite3_finalize (plugin->del_expired_stmt);
853 sqlite3_finalize (plugin->del_stmt);
854 sqlite3_finalize (plugin->get_random_stmt);
855 sqlite3_finalize (plugin->get_closest_stmt);
856 result = sqlite3_close (plugin->dbh);
857 #if SQLITE_VERSION_NUMBER >= 3007000
858 if (SQLITE_BUSY == result)
860 LOG (GNUNET_ERROR_TYPE_WARNING,
861 _("Tried to close sqlite without finalizing all prepared statements.\n"));
862 stmt = sqlite3_next_stmt (plugin->dbh, NULL);
865 result = sqlite3_finalize (stmt);
866 if (result != SQLITE_OK)
867 LOG (GNUNET_ERROR_TYPE_WARNING,
868 "Failed to close statement %p: %d\n",
871 stmt = sqlite3_next_stmt (plugin->dbh, NULL);
873 result = sqlite3_close (plugin->dbh);
876 if (SQLITE_OK != result)
877 LOG_SQLITE (plugin->dbh,
878 GNUNET_ERROR_TYPE_ERROR,
881 #if WINDOWS && !defined(__CYGWIN__)
882 if ( (NULL != plugin->fn) &&
883 (0 != UNLINK (plugin->fn)) )
884 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING,
887 GNUNET_free_non_null (plugin->fn);
889 GNUNET_free (plugin);
896 /* end of plugin_datacache_sqlite.c */