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
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 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 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
22 * @file datacache/plugin_datacache_sqlite.c
23 * @brief sqlite for an implementation of a database backend for the datacache
24 * @author Christian Grothoff
27 #include "gnunet_util_lib.h"
28 #include "gnunet_datacache_plugin.h"
29 #include "gnunet_sq_lib.h"
32 #define LOG(kind,...) GNUNET_log_from (kind, "datacache-sqlite", __VA_ARGS__)
34 #define LOG_STRERROR_FILE(kind,op,fn) GNUNET_log_from_strerror_file (kind, "datacache-sqlite", op, fn)
38 * How much overhead do we assume per entry in the
41 #define OVERHEAD (sizeof(struct GNUNET_HashCode) + 36)
44 * Context for all functions in this plugin.
49 * Our execution environment.
51 struct GNUNET_DATACACHE_PluginEnvironment *env;
54 * Handle to the sqlite database.
59 * Filename used for the DB.
64 * Prepared statement for #sqlite_plugin_put.
66 sqlite3_stmt *insert_stmt;
69 * Prepared statement for #sqlite_plugin_get.
71 sqlite3_stmt *get_count_stmt;
74 * Prepared statement for #sqlite_plugin_get.
76 sqlite3_stmt *get_stmt;
79 * Prepared statement for #sqlite_plugin_del.
81 sqlite3_stmt *del_select_stmt;
84 * Prepared statement for #sqlite_plugin_del.
86 sqlite3_stmt *del_expired_stmt;
89 * Prepared statement for #sqlite_plugin_del.
91 sqlite3_stmt *del_stmt;
94 * Prepared statement for #sqlite_plugin_get_random.
96 sqlite3_stmt *get_random_stmt;
99 * Prepared statement for #sqlite_plugin_get_closest.
101 sqlite3_stmt *get_closest_stmt;
104 * Number of key-value pairs in the database.
106 unsigned int num_items;
111 * Log an error message at log-level @a level that indicates
112 * a failure of the command @a cmd with the error from the database @a db
114 * @param db database handle
115 * @param level log level
116 * @param cmd failed command
118 #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)
122 * Execute SQL statement.
124 * @param db database handle
125 * @param cmd SQL command to execute
127 #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)
131 * @brief Prepare a SQL statement
133 * @param dbh database handle
134 * @param zsql SQL statement text
135 * @param[out] ppStmt set to the prepared statement
136 * @return 0 on success
139 sq_prepare (sqlite3 *dbh,
140 const char *zSql, /* SQL statement, UTF-8 encoded */
141 sqlite3_stmt **ppStmt)
142 { /* OUT: Statement handle */
145 return sqlite3_prepare (dbh,
149 (const char **) &dummy);
154 * Store an item in the datastore.
156 * @param cls closure (our `struct Plugin`)
157 * @param key key to store @a data under
158 * @param xor_distance how close is @a key to our PID?
159 * @param size number of bytes in @a data
160 * @param data data to store
161 * @param type type of the value
162 * @param discard_time when to discard the value in any case
163 * @param path_info_len number of entries in @a path_info
164 * @param path_info array of peers that have processed the request
165 * @return 0 if duplicate, -1 on error, number of bytes used otherwise
168 sqlite_plugin_put (void *cls,
169 const struct GNUNET_HashCode *key,
170 uint32_t xor_distance,
173 enum GNUNET_BLOCK_Type type,
174 struct GNUNET_TIME_Absolute discard_time,
175 unsigned int path_info_len,
176 const struct GNUNET_PeerIdentity *path_info)
178 struct Plugin *plugin = cls;
179 uint32_t type32 = type;
180 struct GNUNET_SQ_QueryParam params[] = {
181 GNUNET_SQ_query_param_uint32 (&type32),
182 GNUNET_SQ_query_param_absolute_time (&discard_time),
183 GNUNET_SQ_query_param_auto_from_type (key),
184 GNUNET_SQ_query_param_uint32 (&xor_distance),
185 GNUNET_SQ_query_param_fixed_size (data, size),
186 GNUNET_SQ_query_param_fixed_size (path_info,
187 path_info_len * sizeof (struct GNUNET_PeerIdentity)),
188 GNUNET_SQ_query_param_end
191 LOG (GNUNET_ERROR_TYPE_DEBUG,
192 "Processing PUT of %u bytes with key `%s' and expiration %s\n",
195 GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_remaining (discard_time),
198 GNUNET_SQ_bind (plugin->insert_stmt,
201 LOG_SQLITE (plugin->dbh,
202 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
204 GNUNET_SQ_reset (plugin->dbh,
205 plugin->insert_stmt);
209 sqlite3_step (plugin->insert_stmt))
211 LOG_SQLITE (plugin->dbh,
212 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
214 GNUNET_SQ_reset (plugin->dbh,
215 plugin->insert_stmt);
219 GNUNET_SQ_reset (plugin->dbh,
220 plugin->insert_stmt);
221 return size + OVERHEAD;
226 * Iterate over the results for a particular key
229 * @param cls closure (our `struct Plugin`)
231 * @param type entries of which type are relevant?
232 * @param iter maybe NULL (to just count)
233 * @param iter_cls closure for @a iter
234 * @return the number of results found
237 sqlite_plugin_get (void *cls,
238 const struct GNUNET_HashCode *key,
239 enum GNUNET_BLOCK_Type type,
240 GNUNET_DATACACHE_Iterator iter,
243 struct Plugin *plugin = cls;
244 uint32_t type32 = type;
245 struct GNUNET_TIME_Absolute now;
246 struct GNUNET_TIME_Absolute exp;
253 struct GNUNET_PeerIdentity *path;
254 struct GNUNET_SQ_QueryParam params_count[] = {
255 GNUNET_SQ_query_param_auto_from_type (key),
256 GNUNET_SQ_query_param_uint32 (&type32),
257 GNUNET_SQ_query_param_absolute_time (&now),
258 GNUNET_SQ_query_param_end
260 struct GNUNET_SQ_QueryParam params_select[] = {
261 GNUNET_SQ_query_param_auto_from_type (key),
262 GNUNET_SQ_query_param_uint32 (&type32),
263 GNUNET_SQ_query_param_absolute_time (&now),
264 GNUNET_SQ_query_param_uint32 (&off),
265 GNUNET_SQ_query_param_end
267 struct GNUNET_SQ_ResultSpec rs[] = {
268 GNUNET_SQ_result_spec_variable_size (&dat,
270 GNUNET_SQ_result_spec_absolute_time (&exp),
271 GNUNET_SQ_result_spec_variable_size ((void **) &path,
273 GNUNET_SQ_result_spec_end
276 now = GNUNET_TIME_absolute_get ();
277 LOG (GNUNET_ERROR_TYPE_DEBUG,
278 "Processing GET for key `%s'\n",
282 GNUNET_SQ_bind (plugin->get_count_stmt,
285 LOG_SQLITE (plugin->dbh,
286 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
288 GNUNET_SQ_reset (plugin->dbh,
289 plugin->get_count_stmt);
293 sqlite3_step (plugin->get_count_stmt))
295 LOG_SQLITE (plugin->dbh, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
297 GNUNET_SQ_reset (plugin->dbh,
298 plugin->get_count_stmt);
299 LOG (GNUNET_ERROR_TYPE_DEBUG,
300 "No content found when processing GET for key `%s'\n",
304 total = sqlite3_column_int (plugin->get_count_stmt,
306 GNUNET_SQ_reset (plugin->dbh,
307 plugin->get_count_stmt);
312 LOG (GNUNET_ERROR_TYPE_DEBUG,
313 "No content found when processing GET for key `%s'\n",
319 off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
323 off = (off + 1) % total;
325 GNUNET_SQ_bind (plugin->get_stmt,
328 LOG_SQLITE (plugin->dbh,
329 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
331 GNUNET_SQ_reset (plugin->dbh,
336 sqlite3_step (plugin->get_stmt))
339 GNUNET_SQ_extract_result (plugin->get_stmt,
343 GNUNET_SQ_reset (plugin->dbh,
347 if (0 != psize % sizeof (struct GNUNET_PeerIdentity))
353 psize /= sizeof (struct GNUNET_PeerIdentity);
355 LOG (GNUNET_ERROR_TYPE_DEBUG,
356 "Found %u-byte result when processing GET for key `%s'\n",
359 if (GNUNET_OK != iter (iter_cls,
368 GNUNET_SQ_cleanup_result (rs);
369 GNUNET_SQ_reset (plugin->dbh,
373 GNUNET_SQ_cleanup_result (rs);
374 GNUNET_SQ_reset (plugin->dbh,
377 GNUNET_SQ_reset (plugin->dbh,
384 * Delete the entry with the lowest expiration value
385 * from the datacache right now.
387 * @param cls closure (our `struct Plugin`)
388 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
391 sqlite_plugin_del (void *cls)
393 struct Plugin *plugin = cls;
397 struct GNUNET_HashCode hc;
398 struct GNUNET_TIME_Absolute now;
399 struct GNUNET_SQ_ResultSpec rs[] = {
400 GNUNET_SQ_result_spec_uint64 (&rowid),
401 GNUNET_SQ_result_spec_auto_from_type (&hc),
402 GNUNET_SQ_result_spec_variable_size ((void **) &data,
404 GNUNET_SQ_result_spec_end
406 struct GNUNET_SQ_QueryParam params[] = {
407 GNUNET_SQ_query_param_uint64 (&rowid),
408 GNUNET_SQ_query_param_end
410 struct GNUNET_SQ_QueryParam time_params[] = {
411 GNUNET_SQ_query_param_absolute_time (&now),
412 GNUNET_SQ_query_param_end
415 LOG (GNUNET_ERROR_TYPE_DEBUG,
417 now = GNUNET_TIME_absolute_get ();
419 GNUNET_SQ_bind (plugin->del_expired_stmt,
422 LOG_SQLITE (plugin->dbh,
423 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
425 GNUNET_SQ_reset (plugin->dbh,
426 plugin->del_expired_stmt);
427 return GNUNET_SYSERR;
430 sqlite3_step (plugin->del_expired_stmt))
432 LOG_SQLITE (plugin->dbh,
433 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
435 GNUNET_SQ_reset (plugin->dbh,
436 plugin->del_expired_stmt);
437 return GNUNET_SYSERR;
440 GNUNET_SQ_extract_result (plugin->del_expired_stmt,
443 GNUNET_SQ_reset (plugin->dbh,
444 plugin->del_expired_stmt);
447 sqlite3_step (plugin->del_select_stmt))
449 LOG_SQLITE (plugin->dbh,
450 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
452 GNUNET_SQ_reset (plugin->dbh,
453 plugin->del_select_stmt);
454 return GNUNET_SYSERR;
457 GNUNET_SQ_extract_result (plugin->del_select_stmt,
460 GNUNET_SQ_reset (plugin->dbh,
461 plugin->del_select_stmt);
463 return GNUNET_SYSERR;
466 GNUNET_SQ_cleanup_result (rs);
467 GNUNET_SQ_reset (plugin->dbh,
468 plugin->del_select_stmt);
470 GNUNET_SQ_bind (plugin->del_stmt,
473 LOG_SQLITE (plugin->dbh,
474 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
476 GNUNET_SQ_reset (plugin->dbh,
478 return GNUNET_SYSERR;
481 sqlite3_step (plugin->del_stmt))
483 LOG_SQLITE (plugin->dbh,
484 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
486 GNUNET_SQ_reset (plugin->dbh,
488 return GNUNET_SYSERR;
491 plugin->env->delete_notify (plugin->env->cls,
494 GNUNET_SQ_reset (plugin->dbh,
501 * Obtain a random key-value pair from the datacache.
503 * @param cls closure (our `struct Plugin`)
504 * @param iter maybe NULL (to just count)
505 * @param iter_cls closure for @a iter
506 * @return the number of results found, zero (datacache empty) or one
509 sqlite_plugin_get_random (void *cls,
510 GNUNET_DATACACHE_Iterator iter,
513 struct Plugin *plugin = cls;
514 struct GNUNET_TIME_Absolute exp;
520 struct GNUNET_PeerIdentity *path;
521 struct GNUNET_HashCode key;
522 struct GNUNET_SQ_QueryParam params[] = {
523 GNUNET_SQ_query_param_uint32 (&off),
524 GNUNET_SQ_query_param_end
526 struct GNUNET_SQ_ResultSpec rs[] = {
527 GNUNET_SQ_result_spec_variable_size (&dat,
529 GNUNET_SQ_result_spec_absolute_time (&exp),
530 GNUNET_SQ_result_spec_variable_size ((void **) &path,
532 GNUNET_SQ_result_spec_auto_from_type (&key),
533 GNUNET_SQ_result_spec_uint32 (&type),
534 GNUNET_SQ_result_spec_end
537 if (0 == plugin->num_items)
541 off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
544 GNUNET_SQ_bind (plugin->get_random_stmt,
550 sqlite3_step (plugin->get_random_stmt))
553 GNUNET_SQ_reset (plugin->dbh,
554 plugin->get_random_stmt);
558 GNUNET_SQ_extract_result (plugin->get_random_stmt,
562 GNUNET_SQ_reset (plugin->dbh,
563 plugin->get_random_stmt);
566 if (0 != psize % sizeof (struct GNUNET_PeerIdentity))
572 psize /= sizeof (struct GNUNET_PeerIdentity);
573 LOG (GNUNET_ERROR_TYPE_DEBUG,
574 "Found %u-byte result with key %s when processing GET-RANDOM\n",
577 (void) iter (iter_cls,
581 (enum GNUNET_BLOCK_Type) type,
585 GNUNET_SQ_cleanup_result (rs);
586 GNUNET_SQ_reset (plugin->dbh,
587 plugin->get_random_stmt);
593 * Iterate over the results that are "close" to a particular key in
594 * the datacache. "close" is defined as numerically larger than @a
595 * key (when interpreted as a circular address space), with small
598 * @param cls closure (internal context for the plugin)
599 * @param key area of the keyspace to look into
600 * @param num_results number of results that should be returned to @a iter
601 * @param iter maybe NULL (to just count)
602 * @param iter_cls closure for @a iter
603 * @return the number of results found
606 sqlite_plugin_get_closest (void *cls,
607 const struct GNUNET_HashCode *key,
608 unsigned int num_results,
609 GNUNET_DATACACHE_Iterator iter,
612 struct Plugin *plugin = cls;
613 uint32_t num_results32 = num_results;
614 struct GNUNET_TIME_Absolute now;
615 struct GNUNET_TIME_Absolute exp;
621 struct GNUNET_HashCode hc;
622 struct GNUNET_PeerIdentity *path;
623 struct GNUNET_SQ_QueryParam params[] = {
624 GNUNET_SQ_query_param_auto_from_type (key),
625 GNUNET_SQ_query_param_absolute_time (&now),
626 GNUNET_SQ_query_param_uint32 (&num_results32),
627 GNUNET_SQ_query_param_end
629 struct GNUNET_SQ_ResultSpec rs[] = {
630 GNUNET_SQ_result_spec_variable_size (&dat,
632 GNUNET_SQ_result_spec_absolute_time (&exp),
633 GNUNET_SQ_result_spec_variable_size ((void **) &path,
635 GNUNET_SQ_result_spec_uint32 (&type),
636 GNUNET_SQ_result_spec_auto_from_type (&hc),
637 GNUNET_SQ_result_spec_end
640 now = GNUNET_TIME_absolute_get ();
641 LOG (GNUNET_ERROR_TYPE_DEBUG,
642 "Processing GET_CLOSEST for key `%s'\n",
645 GNUNET_SQ_bind (plugin->get_closest_stmt,
648 LOG_SQLITE (plugin->dbh,
649 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
651 GNUNET_SQ_reset (plugin->dbh,
652 plugin->get_closest_stmt);
657 sqlite3_step (plugin->get_closest_stmt))
660 GNUNET_SQ_extract_result (plugin->get_closest_stmt,
666 if (0 != psize % sizeof (struct GNUNET_PeerIdentity))
672 psize /= sizeof (struct GNUNET_PeerIdentity);
674 LOG (GNUNET_ERROR_TYPE_DEBUG,
675 "Found %u-byte result at %s when processing GET_CLOSE\n",
678 if (GNUNET_OK != iter (iter_cls,
687 GNUNET_SQ_cleanup_result (rs);
690 GNUNET_SQ_cleanup_result (rs);
692 GNUNET_SQ_reset (plugin->dbh,
693 plugin->get_closest_stmt);
699 * Entry point for the plugin.
701 * @param cls closure (the `struct GNUNET_DATACACHE_PluginEnvironment`)
702 * @return the plugin's closure (our `struct Plugin`)
705 libgnunet_plugin_datacache_sqlite_init (void *cls)
707 struct GNUNET_DATACACHE_PluginEnvironment *env = cls;
708 struct GNUNET_DATACACHE_PluginFunctions *api;
709 struct Plugin *plugin;
716 GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
720 if (SQLITE_OK != sqlite3_open (":memory:", &dbh))
726 fn = GNUNET_DISK_mktemp ("gnunet-datacache");
732 /* fn should be UTF-8-encoded. If it isn't, it's a bug. */
733 fn_utf8 = GNUNET_strdup (fn);
734 if (SQLITE_OK != sqlite3_open (fn_utf8, &dbh))
737 GNUNET_free (fn_utf8);
743 SQLITE3_EXEC (dbh, "PRAGMA temp_store=MEMORY");
744 SQLITE3_EXEC (dbh, "PRAGMA locking_mode=EXCLUSIVE");
745 SQLITE3_EXEC (dbh, "PRAGMA journal_mode=OFF");
746 SQLITE3_EXEC (dbh, "PRAGMA synchronous=OFF");
747 SQLITE3_EXEC (dbh, "PRAGMA page_size=4092");
749 GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
752 SQLITE3_EXEC (dbh, "PRAGMA sqlite_temp_store=3");
755 "CREATE TABLE ds091 ("
756 " type INTEGER NOT NULL DEFAULT 0,"
757 " expire INTEGER NOT NULL,"
758 " key BLOB NOT NULL DEFAULT '',"
759 " prox INTEGER NOT NULL,"
760 " value BLOB NOT NULL,"
761 " path BLOB DEFAULT '')");
762 SQLITE3_EXEC (dbh, "CREATE INDEX idx_hashidx ON ds091 (key,type,expire)");
763 SQLITE3_EXEC (dbh, "CREATE INDEX idx_expire ON ds091 (prox,expire)");
764 plugin = GNUNET_new (struct Plugin);
767 plugin->fn = fn_utf8;
770 sq_prepare (plugin->dbh,
771 "INSERT INTO ds091 (type, expire, key, prox, value, path) "
772 "VALUES (?, ?, ?, ?, ?, ?)",
773 &plugin->insert_stmt)) ||
775 sq_prepare (plugin->dbh,
776 "SELECT count(*) FROM ds091 "
777 "WHERE key=? AND type=? AND expire >= ?",
778 &plugin->get_count_stmt)) ||
780 sq_prepare (plugin->dbh,
781 "SELECT value,expire,path FROM ds091"
782 " WHERE key=? AND type=? AND expire >= ? LIMIT 1 OFFSET ?",
783 &plugin->get_stmt)) ||
785 sq_prepare (plugin->dbh,
786 "SELECT _ROWID_,key,value FROM ds091"
788 " ORDER BY expire ASC LIMIT 1",
789 &plugin->del_expired_stmt)) ||
791 sq_prepare (plugin->dbh,
792 "SELECT _ROWID_,key,value FROM ds091"
793 " ORDER BY prox ASC, expire ASC LIMIT 1",
794 &plugin->del_select_stmt)) ||
796 sq_prepare (plugin->dbh,
797 "DELETE FROM ds091 WHERE _ROWID_=?",
798 &plugin->del_stmt)) ||
800 sq_prepare (plugin->dbh,
801 "SELECT value,expire,path,key,type FROM ds091 "
802 "ORDER BY key LIMIT 1 OFFSET ?",
803 &plugin->get_random_stmt)) ||
805 sq_prepare (plugin->dbh,
806 "SELECT value,expire,path,type,key FROM ds091 "
807 "WHERE key>=? AND expire >= ? ORDER BY KEY ASC LIMIT ?",
808 &plugin->get_closest_stmt))
811 LOG_SQLITE (plugin->dbh,
812 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
814 GNUNET_break (SQLITE_OK ==
815 sqlite3_close (plugin->dbh));
816 GNUNET_free (plugin);
820 api = GNUNET_new (struct GNUNET_DATACACHE_PluginFunctions);
822 api->get = &sqlite_plugin_get;
823 api->put = &sqlite_plugin_put;
824 api->del = &sqlite_plugin_del;
825 api->get_random = &sqlite_plugin_get_random;
826 api->get_closest = &sqlite_plugin_get_closest;
827 LOG (GNUNET_ERROR_TYPE_INFO,
828 "Sqlite datacache running\n");
834 * Exit point from the plugin.
836 * @param cls closure (our `struct Plugin`)
840 libgnunet_plugin_datacache_sqlite_done (void *cls)
842 struct GNUNET_DATACACHE_PluginFunctions *api = cls;
843 struct Plugin *plugin = api->cls;
846 #if SQLITE_VERSION_NUMBER >= 3007000
850 #if !WINDOWS || defined(__CYGWIN__)
851 if ( (NULL != plugin->fn) &&
852 (0 != UNLINK (plugin->fn)) )
853 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING,
856 GNUNET_free_non_null (plugin->fn);
858 sqlite3_finalize (plugin->insert_stmt);
859 sqlite3_finalize (plugin->get_count_stmt);
860 sqlite3_finalize (plugin->get_stmt);
861 sqlite3_finalize (plugin->del_select_stmt);
862 sqlite3_finalize (plugin->del_expired_stmt);
863 sqlite3_finalize (plugin->del_stmt);
864 sqlite3_finalize (plugin->get_random_stmt);
865 sqlite3_finalize (plugin->get_closest_stmt);
866 result = sqlite3_close (plugin->dbh);
867 #if SQLITE_VERSION_NUMBER >= 3007000
868 if (SQLITE_BUSY == result)
870 LOG (GNUNET_ERROR_TYPE_WARNING,
871 _("Tried to close sqlite without finalizing all prepared statements.\n"));
872 stmt = sqlite3_next_stmt (plugin->dbh, NULL);
875 result = sqlite3_finalize (stmt);
876 if (result != SQLITE_OK)
877 LOG (GNUNET_ERROR_TYPE_WARNING,
878 "Failed to close statement %p: %d\n",
881 stmt = sqlite3_next_stmt (plugin->dbh, NULL);
883 result = sqlite3_close (plugin->dbh);
886 if (SQLITE_OK != result)
887 LOG_SQLITE (plugin->dbh,
888 GNUNET_ERROR_TYPE_ERROR,
891 #if WINDOWS && !defined(__CYGWIN__)
892 if ( (NULL != plugin->fn) &&
893 (0 != UNLINK (plugin->fn)) )
894 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING,
897 GNUNET_free_non_null (plugin->fn);
899 GNUNET_free (plugin);
906 /* end of plugin_datacache_sqlite.c */