#
# patch "ChangeLog"
# from [10f5571096a56bc32f62bc5e29a88e9181fc68d0]
# to [3f9e3b3d3ba22996b606396005b20ec7cd21226c]
#
# patch "database.cc"
# from [7e793889cee7cbbd201744d7d299e4aac84d42f4]
# to [67dcca6acbccf335730ae029cadfde6adf7a67a5]
#
# patch "database.hh"
# from [3e62dfc435b831ba05a3e7a478d74b73916bc92e]
# to [c908a66fe8da7740c8fe9920cf5e95def4334c71]
#
========================================================================
--- ChangeLog 10f5571096a56bc32f62bc5e29a88e9181fc68d0
+++ ChangeLog 3f9e3b3d3ba22996b606396005b20ec7cd21226c
@@ -1,5 +1,11 @@
2005-10-08 Nathaniel Smith
+ * database.{hh,cc}: Clean-up previous change -- switch to using a
+ cleanup_ptr to hold sqlite3_stmt handles, for proper exception
+ safety.
+
+2005-10-08 Nathaniel Smith
+
* database.cc (fetch): Do not insert prepared statements into the
statement table until they are successfully created, to avoid
segfaults on database teardown.
========================================================================
--- database.cc 7e793889cee7cbbd201744d7d299e4aac84d42f4
+++ database.cc 67dcca6acbccf335730ae029cadfde6adf7a67a5
@@ -531,10 +531,9 @@
for (map::const_iterator i = statement_cache.begin();
i != statement_cache.end(); ++i)
- {
- L(F("%d executions of %s\n") % i->second.count % i->first);
- sqlite3_finalize(i->second.stmt);
- }
+ L(F("%d executions of %s\n") % i->second.count % i->first);
+ // trigger destructors to finalize cached statements
+ statement_cache.clear();
if (__sql)
{
@@ -582,16 +581,12 @@
map::iterator i = statement_cache.find(query);
if (i == statement_cache.end())
{
- statement s;
+ statement_cache.insert(make_pair(query, statement()));
+ i = statement_cache.find(query);
+ I(i != statement_cache.end());
+
const char * tail;
- // this line can throw, which leaves our statement uninitialized. so we
- // insert the statement into the table _after_ running it successfully.
- sqlite3_prepare(sql(), query, -1, &s.stmt, &tail);
- // note that this copies the statement, and thus the statement pointer.
- // But we immediately tear down s, so we still end up with a single
- // unique pointer to the statement, on which sqlite3_finalize will
- // eventually be called by ~database.
- statement_cache.insert(make_pair(query, s));
+ sqlite3_prepare(sql(), query, -1, i->second.stmt.paddr(), &tail);
assert_sqlite3_ok(sql());
L(F("prepared statement %s\n") % query);
@@ -600,14 +595,14 @@
F("multiple statements in query: %s\n") % query);
}
- ncol = sqlite3_column_count(i->second.stmt);
+ ncol = sqlite3_column_count(i->second.stmt());
E(want_cols == any_cols || want_cols == ncol,
F("wanted %d columns got %d in query: %s\n") % want_cols % ncol % query);
// bind parameters for this execution
- int params = sqlite3_bind_parameter_count(i->second.stmt);
+ int params = sqlite3_bind_parameter_count(i->second.stmt());
L(F("binding %d parameters for %s\n") % params % query);
@@ -625,20 +620,20 @@
L(F("binding %d with value '%s'\n") % param % log);
- sqlite3_bind_text(i->second.stmt, param, value, -1, SQLITE_TRANSIENT);
+ sqlite3_bind_text(i->second.stmt(), param, value, -1, SQLITE_TRANSIENT);
assert_sqlite3_ok(sql());
}
// execute and process results
nrow = 0;
- for (rescode = sqlite3_step(i->second.stmt); rescode == SQLITE_ROW;
- rescode = sqlite3_step(i->second.stmt))
+ for (rescode = sqlite3_step(i->second.stmt()); rescode == SQLITE_ROW;
+ rescode = sqlite3_step(i->second.stmt()))
{
vector row;
for (int col = 0; col < ncol; col++)
{
- const char * value = sqlite3_column_text_s(i->second.stmt, col);
+ const char * value = sqlite3_column_text_s(i->second.stmt(), col);
E(value, F("null result in query: %s\n") % query);
row.push_back(value);
//L(F("row %d col %d value='%s'\n") % nrow % col % value);
@@ -649,7 +644,7 @@
if (rescode != SQLITE_DONE)
assert_sqlite3_ok(sql());
- sqlite3_reset(i->second.stmt);
+ sqlite3_reset(i->second.stmt());
assert_sqlite3_ok(sql());
nrow = res.size();
========================================================================
--- database.hh 3e62dfc435b831ba05a3e7a478d74b73916bc92e
+++ database.hh c908a66fe8da7740c8fe9920cf5e95def4334c71
@@ -9,6 +9,7 @@
struct sqlite3;
struct sqlite3_stmt;
struct cert;
+int sqlite3_finalize(sqlite3_stmt *);
#include
@@ -22,6 +23,7 @@
#include "numeric_vocab.hh"
#include "vocab.hh"
#include "paths.hh"
+#include "cleanup.hh"
struct revision_set;
@@ -75,9 +77,9 @@
void check_schema();
struct statement {
+ statement() : count(0), stmt(0, sqlite3_finalize) {}
int count;
- statement() : count(0) {}
- sqlite3_stmt *stmt;
+ cleanup_ptr stmt;
};
std::map statement_cache;