- /**
- * FIXME.
- */
- sqlite3_stmt *stmt_2;
-
- /**
- * FIXME.
- */
- int is_asc;
-
- /**
- * FIXME.
- */
- int is_prio;
-
- /**
- * FIXME.
- */
- int is_migr;
-
- /**
- * FIXME.
- */
- int limit_nonanonymous;
-
- /**
- * Desired type for blocks returned by this iterator.
- */
- uint32_t type;
-};
-
-
-/**
- * Prepare our SQL query to obtain the next record from the database.
- *
- * @param cls our "struct IterContext"
- * @param nc NULL to terminate the iteration, otherwise our context for
- * getting the next result.
- * @return GNUNET_OK on success, GNUNET_NO if there are no more results,
- * GNUNET_SYSERR on error (or end of iteration)
- */
-static int
-iter_next_prepare (void *cls,
- struct NextContext *nc)
-{
- struct IterContext *ic = cls;
- struct Plugin *plugin;
- int ret;
-
- if (nc == NULL)
- {
-#if DEBUG_SQLITE
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Asked to clean up iterator state.\n");
-#endif
- sqlite3_finalize (ic->stmt_1);
- sqlite3_finalize (ic->stmt_2);
- return GNUNET_SYSERR;
- }
- sqlite3_reset (ic->stmt_1);
- sqlite3_reset (ic->stmt_2);
- plugin = nc->plugin;
- if (ic->is_prio)
- {
-#if DEBUG_SQLITE
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Restricting to results larger than the last priority %u\n",
- nc->lastPriority);
-#endif
- sqlite3_bind_int (ic->stmt_1, 1, nc->lastPriority);
- sqlite3_bind_int (ic->stmt_2, 1, nc->lastPriority);
- }
- else
- {
-#if DEBUG_SQLITE
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Restricting to results larger than the last expiration %llu\n",
- (unsigned long long) nc->lastExpiration.value);
-#endif
- sqlite3_bind_int64 (ic->stmt_1, 1, nc->lastExpiration.value);
- sqlite3_bind_int64 (ic->stmt_2, 1, nc->lastExpiration.value);
- }
-#if DEBUG_SQLITE
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Restricting to results larger than the last key `%s'\n",
- GNUNET_h2s(&nc->lastKey));
-#endif
- sqlite3_bind_blob (ic->stmt_1, 2,
- &nc->lastKey,
- sizeof (GNUNET_HashCode),
- SQLITE_TRANSIENT);
- if (SQLITE_ROW == (ret = sqlite3_step (ic->stmt_1)))
- {
-#if DEBUG_SQLITE
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Result found using iterator 1\n");
-#endif
- nc->stmt = ic->stmt_1;
- return GNUNET_OK;
- }
- if (ret != SQLITE_DONE)
- {
- LOG_SQLITE (plugin, NULL,
- GNUNET_ERROR_TYPE_ERROR |
- GNUNET_ERROR_TYPE_BULK,
- "sqlite3_step");
- return GNUNET_SYSERR;
- }
- if (SQLITE_OK != sqlite3_reset (ic->stmt_1))
- LOG_SQLITE (plugin, NULL,
- GNUNET_ERROR_TYPE_ERROR |
- GNUNET_ERROR_TYPE_BULK,
- "sqlite3_reset");
- if (SQLITE_ROW == (ret = sqlite3_step (ic->stmt_2)))
- {
-#if DEBUG_SQLITE
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Result found using iterator 2\n");
-#endif
- nc->stmt = ic->stmt_2;
- return GNUNET_OK;
- }
- if (ret != SQLITE_DONE)
- {
- LOG_SQLITE (plugin, NULL,
- GNUNET_ERROR_TYPE_ERROR |
- GNUNET_ERROR_TYPE_BULK,
- "sqlite3_step");
- return GNUNET_SYSERR;
- }
- if (SQLITE_OK != sqlite3_reset (ic->stmt_2))
- LOG_SQLITE (plugin, NULL,
- GNUNET_ERROR_TYPE_ERROR |
- GNUNET_ERROR_TYPE_BULK,
- "sqlite3_reset");
-#if DEBUG_SQLITE
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "No result found using either iterator\n");
-#endif
- return GNUNET_NO;
-}
-
-
-/**
- * Call a method for each key in the database and
- * call the callback method on it.
- *
- * @param plugin our plugin context
- * @param type entries of which type should be considered?
- * @param is_asc are we iterating in ascending order?
- * @param is_prio are we iterating by priority (otherwise by expiration)
- * @param is_migr are we iterating in migration order?
- * @param limit_nonanonymous are we restricting results to those with anonymity
- * level zero?
- * @param stmt_str_1 first SQL statement to execute
- * @param stmt_str_2 SQL statement to execute to get "more" results (inner iteration)
- * @param iter function to call on each matching value;
- * will be called once with a NULL value at the end
- * @param iter_cls closure for iter
- */
-static void
-basic_iter (struct Plugin *plugin,
- uint32_t type,
- int is_asc,
- int is_prio,
- int is_migr,
- int limit_nonanonymous,
- const char *stmt_str_1,
- const char *stmt_str_2,
- PluginIterator iter,
- void *iter_cls)
-{
- struct NextContext *nc;
- struct IterContext *ic;
- sqlite3_stmt *stmt_1;
- sqlite3_stmt *stmt_2;
-
-#if DEBUG_SQLITE
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "At %llu, using queries `%s' and `%s'\n",
- (unsigned long long) GNUNET_TIME_absolute_get ().value,
- stmt_str_1,
- stmt_str_2);
-#endif
- if (sq_prepare (plugin->dbh, stmt_str_1, &stmt_1) != SQLITE_OK)
- {
- LOG_SQLITE (plugin, NULL,
- GNUNET_ERROR_TYPE_ERROR |
- GNUNET_ERROR_TYPE_BULK, "sqlite3_prepare");
- iter (iter_cls, NULL, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
- return;
- }
- if (sq_prepare (plugin->dbh, stmt_str_2, &stmt_2) != SQLITE_OK)
- {
- LOG_SQLITE (plugin, NULL,
- GNUNET_ERROR_TYPE_ERROR |
- GNUNET_ERROR_TYPE_BULK, "sqlite3_prepare");
- sqlite3_finalize (stmt_1);
- iter (iter_cls, NULL, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
- return;
- }
- nc = GNUNET_malloc (sizeof(struct NextContext) +
- sizeof(struct IterContext));
- nc->plugin = plugin;
- nc->iter = iter;
- nc->iter_cls = iter_cls;
- nc->stmt = NULL;
- ic = (struct IterContext*) &nc[1];
- ic->stmt_1 = stmt_1;
- ic->stmt_2 = stmt_2;
- ic->type = type;
- ic->is_asc = is_asc;
- ic->is_prio = is_prio;
- ic->is_migr = is_migr;
- ic->limit_nonanonymous = limit_nonanonymous;
- nc->prep = &iter_next_prepare;
- nc->prep_cls = ic;
- if (is_asc)
- {
- nc->lastPriority = 0;
- nc->lastExpiration.value = 0;
- memset (&nc->lastKey, 0, sizeof (GNUNET_HashCode));
- }
- else
- {
- nc->lastPriority = 0x7FFFFFFF;
- nc->lastExpiration.value = 0x7FFFFFFFFFFFFFFFLL;
- memset (&nc->lastKey, 255, sizeof (GNUNET_HashCode));
- }
- sqlite_next_request (nc, GNUNET_NO);
-}
+ 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 (struct 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,
+ 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_us = sqlite3_column_int64 (stmt, 3);
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite",
+ "Found reply in database with expiration %s\n",
+ GNUNET_STRINGS_absolute_time_to_string (expiration));
+ 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,
+ 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,
+ GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+ "sqlite3_reset");
+ break;
+ case SQLITE_BUSY:
+ case SQLITE_ERROR:
+ case SQLITE_MISUSE:
+ default:
+ LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+ "sqlite3_step");
+ if (SQLITE_OK != sqlite3_reset (stmt))
+ LOG_SQLITE (plugin,
+ 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, 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);
+}