The unified diff between revisions [9b19e788..] and [8846a6b8..] is displayed below. It can also be downloaded as a raw diff.
#
#
# rename "tests/t_sql_unpack.at"
# to "tests/t_sql_gunzip.at"
#
# patch "ChangeLog"
# from [36ddfbc60c098baecae82e3be37bb02055100506]
# to [cf7af27d617c006696a08efcd68a9bd9fd401a7a]
#
# patch "database.cc"
# from [377449cef66018ee4619b66e5c08dae01129df89]
# to [4c830b7b46f89cdc384cae08e54bfeac62335eb7]
#
# patch "schema.sql"
# from [f44144278a4158695818d8f7e1901ac6f89e39bb]
# to [d811d7503305093359874d46f1142861657642c0]
#
# patch "schema_migration.cc"
# from [a13abc3a8c750aadb1ad07114c8f5b0cfc0cc67b]
# to [c802e1820aa8381b39dde2b5fece6c29c5256efd]
#
# patch "tests/t_migrate_schema.at"
# from [9d9a73cc20f8e367f4c828484e78c19224614b93]
# to [e5b24dd9ccc44e36b20d1b1dc89509f0e99896fd]
#
# patch "tests/t_sql_gunzip.at"
# from [1bb994c7c10fcfafc2a0fc9b5dd7c45b5b315174]
# to [1e43988cec90fe9e16a51379b7b832cfc609d122]
#
# patch "testsuite.at"
# from [7f433b14b3bd2a67eeacc49577a64e35d97ed02f]
# to [781e96c61a849b6f628e1aa691189b64f4d1bf08]
#
============================================================
--- ChangeLog 36ddfbc60c098baecae82e3be37bb02055100506
+++ ChangeLog cf7af27d617c006696a08efcd68a9bd9fd401a7a
@@ -517,6 +517,17 @@ 2006-01-14 Nathaniel Smith <njs@pobox.
* keys.cc (require_password): Adjust accordingly.
* cert.cc (priv_key_exists, load_key_pair): Likewise.
+2006-01-14 Christof Petig <christof@petig-baender.de>
+
+ * database.cc, database.h: binary transparent infrastructure,
+ store and retrieve former base64 encoded columns as BLOBs
+
+ * schema_migration.cc: unbase64 changed columns, change comment
+ on files.data which indicates a different database format
+
+ * schema.sql: change comment on file which indicates, that
+ files.data is no longer base64 encoded
+
2006-01-14 Richard Levitte <richard@levitte.org>
* configure.ac: Make sure there's an empty xgettext.opts
============================================================
--- database.cc 377449cef66018ee4619b66e5c08dae01129df89
+++ database.cc 4c830b7b46f89cdc384cae08e54bfeac62335eb7
@@ -107,12 +107,6 @@ struct query
std::string sql_cmd;
};
-extern "C" {
-// some wrappers to ease migration
- const char *sqlite3_value_text_s(sqlite3_value *v);
- const char *sqlite3_column_text_s(sqlite3_stmt*, int col);
-}
-
database::database(system_path const & fn) :
filename(fn),
// nb. update this if you change the schema. unfortunately we are not
@@ -120,7 +114,7 @@ database::database(system_path const & f
// non-alphabetic ordering of tables in sql source files. we could create
// a temporary db, write our intended schema into it, and read it back,
// but this seems like it would be too rude. possibly revisit this issue.
- schema("1db80c7cee8fa966913db1a463ed50bf1b0e5b0e"),
+ schema("9d2b5d7b86df00c30ac34fe87a3c20f1195bb2df"),
__sql(NULL),
transaction_level(0)
{}
@@ -191,43 +185,18 @@ database::check_format()
}
}
-// sqlite3_value_text gives a const unsigned char * but most of the time
-// we need a signed char
-const char *
-sqlite3_value_text_s(sqlite3_value *v)
-{
- return (const char *)(sqlite3_value_text(v));
-}
-
-const char *
-sqlite3_column_text_s(sqlite3_stmt *stmt, int col)
-{
- return (const char *)(sqlite3_column_text(stmt, col));
-}
-
-static void
-sqlite3_unbase64_fn(sqlite3_context *f, int nargs, sqlite3_value ** args)
-{
- if (nargs != 1)
- {
- sqlite3_result_error(f, "need exactly 1 arg to unbase64()", -1);
- return;
- }
- data decoded;
- decode_base64(base64<data>(string(sqlite3_value_text_s(args[0]))), decoded);
- sqlite3_result_blob(f, decoded().c_str(), decoded().size(), SQLITE_TRANSIENT);
-}
-
static void
-sqlite3_unpack_fn(sqlite3_context *f, int nargs, sqlite3_value ** args)
+sqlite3_gunzip_fn(sqlite3_context *f, int nargs, sqlite3_value ** args)
{
if (nargs != 1)
{
- sqlite3_result_error(f, "need exactly 1 arg to unpack()", -1);
+ sqlite3_result_error(f, "need exactly 1 arg to gunzip()", -1);
return;
}
data unpacked;
- unpack(base64< gzip<data> >(string(sqlite3_value_text_s(args[0]))), unpacked);
+ const char *val = (const char*) sqlite3_value_blob(args[0]);
+ int bytes = sqlite3_value_bytes(args[0]);
+ decode_gzip(gzip<data>(std::string(val,val+bytes)), unpacked);
sqlite3_result_blob(f, unpacked().c_str(), unpacked().size(), SQLITE_TRANSIENT);
}
@@ -349,42 +318,49 @@ dump_request
struct
dump_request
{
- dump_request() {};
+ dump_request() : sql(), out() {};
struct sqlite3 *sql;
- string table_name;
ostream *out;
};
-static int
-dump_row_cb(void *data, int n, char **vals, char **cols)
+static void
+dump_row(std::ostream &out, sqlite3_stmt *stmt, std::string const& table_name)
{
- dump_request *dump = reinterpret_cast<dump_request *>(data);
- I(dump != NULL);
- I(vals != NULL);
- I(dump->out != NULL);
- *(dump->out) << boost::format("INSERT INTO %s VALUES(") % dump->table_name;
- for (int i = 0; i < n; ++i)
+ out << boost::format("INSERT INTO %s VALUES(") % table_name;
+ unsigned n = sqlite3_data_count(stmt);
+ for (unsigned i = 0; i < n; ++i)
{
if (i != 0)
- *(dump->out) << ',';
+ out << ',';
- if (vals[i] == NULL)
- *(dump->out) << "NULL";
- else
+ if (sqlite3_column_type(stmt, i) == SQLITE_BLOB)
{
- *(dump->out) << "'";
- for (char *cp = vals[i]; *cp; ++cp)
+ out << "X'";
+ const char *val = (const char*) sqlite3_column_blob(stmt, i);
+ int bytes = sqlite3_column_bytes(stmt, i);
+ out << encode_hexenc(std::string(val,val+bytes));
+ out << "'";
+ }
+ else
+ {
+ const unsigned char *val = sqlite3_column_text(stmt, i);
+ if (val == NULL)
+ out << "NULL";
+ else
{
- if (*cp == '\'')
- *(dump->out) << "''";
- else
- *(dump->out) << *cp;
+ out << "'";
+ for (const unsigned char *cp = val; *cp; ++cp)
+ {
+ if (*cp == '\'')
+ out << "''";
+ else
+ out << *cp;
+ }
+ out << "'";
}
- *(dump->out) << "'";
}
}
- *(dump->out) << ");\n";
- return 0;
+ out << ");\n";
}
static int
@@ -400,10 +376,24 @@ dump_table_cb(void *data, int n, char **
I(n == 3);
I(string(vals[1]) == "table");
*(dump->out) << vals[2] << ";\n";
- dump->table_name = string(vals[0]);
- string query = "SELECT * FROM " + string(vals[0]);
- sqlite3_exec(dump->sql, query.c_str(), dump_row_cb, data, NULL);
+ string table_name(vals[0]);
+ string query = "SELECT * FROM " + table_name;
+ sqlite3_stmt *stmt = 0;
+ sqlite3_prepare(dump->sql, query.c_str(), -1, &stmt, NULL);
assert_sqlite3_ok(dump->sql);
+
+ int stepresult = SQLITE_DONE;
+ do
+ {
+ stepresult = sqlite3_step(stmt);
+ I(stepresult == SQLITE_DONE || stepresult == SQLITE_ROW);
+ if (stepresult == SQLITE_ROW)
+ dump_row(*(dump->out), stmt, table_name);
+ }
+ while (stepresult == SQLITE_ROW);
+
+ sqlite3_finalize(stmt);
+ assert_sqlite3_ok(dump->sql);
return 0;
}
@@ -547,13 +537,14 @@ database::info(ostream & out)
% count("revision_ancestry")
% count("revision_certs")
// bytes
- % SPACE_USAGE("rosters", "id || data")
- % SPACE_USAGE("roster_deltas", "id || base || delta")
- % SPACE_USAGE("files", "id || data")
- % SPACE_USAGE("file_deltas", "id || base || delta")
- % SPACE_USAGE("revisions", "id || data")
- % SPACE_USAGE("revision_ancestry", "parent || child")
- % SPACE_USAGE("revision_certs", "hash || id || name || value || keypair || signature")
+ % SPACE_USAGE("rosters", "length(id) + length(data)")
+ % SPACE_USAGE("roster_deltas", "length(id) + length(base) + length(delta)")
+ % SPACE_USAGE("files", "length(id) + length(data)")
+ % SPACE_USAGE("file_deltas", "length(id) + length(base) + length(delta)")
+ % SPACE_USAGE("revisions", "length(id) + length(data)")
+ % SPACE_USAGE("revision_ancestry", "length(parent) + length(child)")
+ % SPACE_USAGE("revision_certs", "length(hash) + length(id) + length(name)"
+ " + length(value) + length(keypair) + length(signature)")
% total;
#undef SPACE_USAGE
@@ -712,9 +703,10 @@ database::fetch(results & res,
vector<string> row;
for (int col = 0; col < ncol; col++)
{
- const char * value = sqlite3_column_text_s(i->second.stmt(), col);
+ const char * value = (const char*)sqlite3_column_blob(i->second.stmt(), col);
+ int bytes = sqlite3_column_bytes(i->second.stmt(), col);
E(value, F("null result in query: %s\n") % query.sql_cmd);
- row.push_back(value);
+ row.push_back(std::string(value, value + bytes));
//L(FL("row %d col %d value='%s'\n") % nrow % col % value);
}
res.push_back(row);
@@ -823,12 +815,12 @@ unsigned long
}
unsigned long
-database::space_usage(string const & table, string const & concatenated_columns)
+database::space_usage(string const & table, string const & rowspace)
{
results res;
// COALESCE is required since SUM({empty set}) is NULL.
// the sqlite docs for SUM suggest this as a workaround
- query q("SELECT COALESCE(SUM(LENGTH(" + concatenated_columns + ")), 0) FROM " + table);
+ query q("SELECT COALESCE(SUM(" + rowspace + "), 0) FROM " + table);
fetch(res, one_col, one_row, q);
return lexical_cast<unsigned long>(res[0][0]);
}
@@ -856,9 +848,9 @@ database::get(hexenc<id> const & ident,
fetch(res, one_col, one_row, q % text(ident()));
// consistency check
- base64<gzip<data> > rdata(res[0][0]);
+ gzip<data> rdata(res[0][0]);
data rdata_unpacked;
- unpack(rdata, rdata_unpacked);
+ decode_gzip(rdata,rdata_unpacked);
hexenc<id> tid;
calculate_ident(rdata_unpacked, tid);
@@ -879,8 +871,8 @@ database::get_delta(hexenc<id> const & i
query q("SELECT delta FROM " + table + " WHERE id = ? AND base = ?");
fetch(res, one_col, one_row, q % text(ident()) % text(base()));
- base64<gzip<delta> > del_packed = res[0][0];
- unpack(del_packed, del);
+ gzip<delta> del_packed(res[0][0]);
+ decode_gzip(del_packed, del);
}
void
@@ -896,13 +888,13 @@ database::put(hexenc<id> const & ident,
MM(tid);
I(tid == ident);
- base64<gzip<data> > dat_packed;
- pack(dat, dat_packed);
+ gzip<data> dat_packed;
+ encode_gzip(dat, dat_packed);
string insert = "INSERT INTO " + table + " VALUES(?, ?)";
execute(query(insert)
% text(ident())
- % text(dat_packed()));
+ % blob(dat_packed()));
}
void
database::put_delta(hexenc<id> const & ident,
@@ -914,14 +906,14 @@ database::put_delta(hexenc<id> const & i
I(ident() != "");
I(base() != "");
- base64<gzip<delta> > del_packed;
- pack(del, del_packed);
-
+ gzip<delta> del_packed;
+ encode_gzip(del, del_packed);
+
string insert = "INSERT INTO "+table+" VALUES(?, ?, ?)";
execute(query(insert)
% text(ident())
% text(base())
- % text(del_packed()));
+ % blob(del_packed()));
}
// static ticker cache_hits("vcache hits", "h", 1);
@@ -1488,10 +1480,9 @@ database::get_revision(revision_id const
query("SELECT data FROM revisions WHERE id = ?")
% text(id.inner()()));
- base64<gzip<data> > rdat_packed;
- rdat_packed = base64<gzip<data> >(res[0][0]);
+ gzip<data> gzdata(res[0][0]);
data rdat;
- unpack(rdat_packed, rdat);
+ decode_gzip(gzdata,rdat);
// verify that we got a revision with the right id
{
@@ -1656,12 +1647,11 @@ database::put_revision(revision_id const
// Phase 3: Write the revision data
- base64<gzip<data> > d_packed;
- pack(d.inner(), d_packed);
-
- execute(query("INSERT INTO revisions VALUES(?, ?)")
+ gzip<data> d_packed;
+ encode_gzip(d.inner(), d_packed);
+ execute(query("INSERT INTO revisions VALUES(?, ?)")
% text(new_id.inner()())
- % text(d_packed()));
+ % blob(d_packed()));
for (edge_map::const_iterator e = rev.edges.begin();
e != rev.edges.end(); ++e)
@@ -1760,24 +1750,20 @@ database::delete_branch_named(cert_value
void
database::delete_branch_named(cert_value const & branch)
{
- base64<cert_value> encoded;
- encode_base64(branch, encoded);
L(FL("Deleting all references to branch %s\n") % branch);
execute(query("DELETE FROM revision_certs WHERE name='branch' AND value =?")
- % text(encoded()));
+ % blob(branch()));
execute(query("DELETE FROM branch_epochs WHERE branch=?")
- % text(encoded()));
+ % blob(branch()));
}
/// Deletes all certs referring to a particular tag.
void
database::delete_tag_named(cert_value const & tag)
{
- base64<cert_value> encoded;
- encode_base64(tag, encoded);
L(FL("Deleting all references to tag %s\n") % tag);
execute(query("DELETE FROM revision_certs WHERE name='tag' AND value =?")
- % text(encoded()));
+ % blob(tag()));
}
// crypto key management
@@ -1853,7 +1839,7 @@ database::get_pubkey(hexenc<id> const &
query("SELECT id, keydata FROM public_keys WHERE hash = ?")
% text(hash()));
id = res[0][0];
- pub_encoded = res[0][1];
+ encode_base64(rsa_pub_key(res[0][1]), pub_encoded);
}
void
@@ -1864,7 +1850,7 @@ database::get_key(rsa_keypair_id const &
fetch(res, one_col, one_row,
query("SELECT keydata FROM public_keys WHERE id = ?")
% text(pub_id()));
- pub_encoded = res[0][0];
+ encode_base64(rsa_pub_key(res[0][0]), pub_encoded);
}
void
@@ -1876,10 +1862,12 @@ database::put_key(rsa_keypair_id const &
I(!public_key_exists(thash));
E(!public_key_exists(pub_id),
F("another key with name '%s' already exists") % pub_id);
+ rsa_pub_key pub_key;
+ decode_base64(pub_encoded, pub_key);
execute(query("INSERT INTO public_keys VALUES(?, ?, ?)")
% text(thash())
% text(pub_id())
- % text(pub_encoded()));
+ % blob(pub_key()));
}
void
@@ -1896,6 +1884,10 @@ database::cert_exists(cert const & t,
string const & table)
{
results res;
+ cert_value value;
+ decode_base64(t.value, value);
+ rsa_sha1_signature sig;
+ decode_base64(t.sig, sig);
query q = query("SELECT id FROM " + table + " WHERE id = ? "
"AND name = ? "
"AND value = ? "
@@ -1903,10 +1895,10 @@ database::cert_exists(cert const & t,
"AND signature = ?")
% text(t.ident())
% text(t.name())
- % text(t.value())
+ % blob(value())
% text(t.key())
- % text(t.sig());
-
+ % blob(sig());
+
fetch(res, 1, any_rows, q);
I(res.size() == 0 || res.size() == 1);
@@ -1919,6 +1911,10 @@ database::put_cert(cert const & t,
{
hexenc<id> thash;
cert_hash_code(t, thash);
+ cert_value value;
+ decode_base64(t.value, value);
+ rsa_sha1_signature sig;
+ decode_base64(t.sig, sig);
string insert = "INSERT INTO " + table + " VALUES(?, ?, ?, ?, ?, ?)";
@@ -1926,9 +1922,9 @@ database::put_cert(cert const & t,
% text(thash())
% text(t.ident())
% text(t.name())
- % text(t.value())
+ % blob(value())
% text(t.key())
- % text(t.sig()));
+ % blob(sig()));
}
void
@@ -1939,11 +1935,15 @@ database::results_to_certs(results const
for (size_t i = 0; i < res.size(); ++i)
{
cert t;
+ base64<cert_value> value;
+ encode_base64(cert_value(res[i][2]), value);
+ base64<rsa_sha1_signature> sig;
+ encode_base64(rsa_sha1_signature(res[i][4]), sig);
t = cert(hexenc<id>(res[i][0]),
cert_name(res[i][1]),
- base64<cert_value>(res[i][2]),
+ value,
rsa_keypair_id(res[i][3]),
- base64<rsa_sha1_signature>(res[i][4]));
+ sig);
certs.push_back(t);
}
}
@@ -1952,14 +1952,10 @@ database::install_functions(app_state *
database::install_functions(app_state * app)
{
// register any functions we're going to use
- I(sqlite3_create_function(sql(), "unbase64", -1,
+ I(sqlite3_create_function(sql(), "gunzip", -1,
SQLITE_UTF8, NULL,
- &sqlite3_unbase64_fn,
+ &sqlite3_gunzip_fn,
NULL, NULL) == 0);
- I(sqlite3_create_function(sql(), "unpack", -1,
- SQLITE_UTF8, NULL,
- &sqlite3_unpack_fn,
- NULL, NULL) == 0);
}
void
@@ -2048,9 +2044,11 @@ database::get_certs(cert_name const & na
query q("SELECT id, name, value, keypair, signature FROM " + table +
" WHERE name = ? AND value = ?");
- fetch(res, 5, any_rows,
+ cert_value binvalue;
+ decode_base64(val, binvalue);
+ fetch(res, 5, any_rows,
q % text(name())
- % text(val()));
+ % blob(binvalue()));
results_to_certs(res, certs);
}
@@ -2066,10 +2064,12 @@ database::get_certs(hexenc<id> const & i
query q("SELECT id, name, value, keypair, signature FROM " + table +
" WHERE id = ? AND name = ? AND value = ?");
+ cert_value binvalue;
+ decode_base64(value, binvalue);
fetch(res, 5, any_rows,
q % text(ident())
% text(name())
- % text(value()));
+ % blob(binvalue()));
results_to_certs(res, certs);
}
@@ -2386,7 +2386,7 @@ void database::complete(selector_type ty
spot++;
certvalue = i->second.substr(spot);
lim += "SELECT id FROM revision_certs ";
- lim += (boost::format("WHERE name='%s' AND unbase64(value) glob '%s'")
+ lim += (boost::format("WHERE name='%s' AND CAST(value AS TEXT) glob '%s'")
% certname % certvalue).str();
}
else
@@ -2405,7 +2405,7 @@ void database::complete(selector_type ty
% author_cert_name
% tag_cert_name
% branch_cert_name).str();
- lim += (boost::format(" AND unbase64(value) glob '*%s*'")
+ lim += (boost::format(" AND CAST(value AS TEXT) glob '*%s*'")
% i->second).str();
}
else if (i->first == selectors::sel_head)
@@ -2419,15 +2419,13 @@ void database::complete(selector_type ty
}
else
{
- string subquery = (boost::format("SELECT DISTINCT value FROM revision_certs WHERE name='%s' and unbase64(value) glob '%s'")
+ string subquery = (boost::format("SELECT DISTINCT value FROM revision_certs WHERE name='%s' and CAST(value AS TEXT) glob '%s'")
% branch_cert_name % i->second).str();
results res;
fetch(res, one_col, any_rows, query(subquery));
for (size_t i = 0; i < res.size(); ++i)
{
- base64<data> row_encoded(res[i][0]);
- data row_decoded;
- decode_base64(row_encoded, row_decoded);
+ data row_decoded(res[i][0]);
branch_names.push_back(row_decoded());
}
}
@@ -2466,8 +2464,7 @@ void database::complete(selector_type ty
if ((i->first == selectors::sel_branch) && (i->second.size() == 0))
{
__app->require_workspace("the empty branch selector b: refers to the current branch");
- // FIXME: why do we have to glob on the unbase64(value), rather than being able to use == ?
- lim += (boost::format("SELECT id FROM revision_certs WHERE name='%s' AND unbase64(value) glob '%s'")
+ lim += (boost::format("SELECT id FROM revision_certs WHERE name='%s' AND CAST(value AS TEXT) glob '%s'")
% branch_cert_name % __app->branch_name).str();
L(FL("limiting to current branch '%s'\n") % __app->branch_name);
}
@@ -2477,13 +2474,13 @@ void database::complete(selector_type ty
switch (i->first)
{
case selectors::sel_earlier:
- lim += (boost::format("unbase64(value) <= X'%s'") % encode_hexenc(i->second)).str();
+ lim += (boost::format("value <= X'%s'") % encode_hexenc(i->second)).str();
break;
case selectors::sel_later:
- lim += (boost::format("unbase64(value) > X'%s'") % encode_hexenc(i->second)).str();
+ lim += (boost::format("value > X'%s'") % encode_hexenc(i->second)).str();
break;
default:
- lim += (boost::format("unbase64(value) glob '%s%s%s'")
+ lim += (boost::format("CAST(value AS TEXT) glob '%s%s%s'")
% prefix % i->second % suffix).str();
break;
}
@@ -2524,7 +2521,7 @@ void database::complete(selector_type ty
(boost::format(" (name='%s')") % certname).str();
}
- query_str += (boost::format(" AND (unbase64(value) GLOB '%s%s%s')")
+ query_str += (boost::format(" AND (CAST(value AS TEXT) GLOB '%s%s%s')")
% prefix % partial % suffix).str();
query_str += (boost::format(" AND (id IN %s)") % lim).str();
}
@@ -2537,9 +2534,7 @@ void database::complete(selector_type ty
completions.insert(res[i][0]);
else
{
- base64<data> row_encoded(res[i][0]);
- data row_decoded;
- decode_base64(row_encoded, row_decoded);
+ data row_decoded(res[i][0]);
completions.insert(row_decoded());
}
}
@@ -2555,9 +2550,7 @@ database::get_epochs(std::map<cert_value
fetch(res, 2, any_rows, query("SELECT branch, epoch FROM branch_epochs"));
for (results::const_iterator i = res.begin(); i != res.end(); ++i)
{
- base64<cert_value> encoded(idx(*i, 0));
- cert_value decoded;
- decode_base64(encoded, decoded);
+ cert_value decoded(idx(*i, 0));
I(epochs.find(decoded) == epochs.end());
epochs.insert(std::make_pair(decoded, epoch_data(idx(*i, 1))));
}
@@ -2574,8 +2567,7 @@ database::get_epoch(epoch_id const & eid
" WHERE hash = ?")
% text(eid.inner()()));
I(res.size() == 1);
- base64<cert_value> encoded(idx(idx(res, 0), 0));
- decode_base64(encoded, branch);
+ branch = cert_value(idx(idx(res, 0), 0));
epo = epoch_data(idx(idx(res, 0), 1));
}
@@ -2594,23 +2586,19 @@ database::set_epoch(cert_value const & b
database::set_epoch(cert_value const & branch, epoch_data const & epo)
{
epoch_id eid;
- base64<cert_value> encoded;
- encode_base64(branch, encoded);
epoch_hash_code(branch, epo, eid);
I(epo.inner()().size() == constants::epochlen);
execute(query("INSERT OR REPLACE INTO branch_epochs VALUES(?, ?, ?)")
% text(eid.inner()())
- % text(encoded())
+ % blob(branch())
% text(epo.inner()()));
}
void
database::clear_epoch(cert_value const & branch)
{
- base64<cert_value> encoded;
- encode_base64(branch, encoded);
execute(query("DELETE FROM branch_epochs WHERE branch = ?")
- % text(encoded()));
+ % blob(branch()));
}
// vars
@@ -2624,12 +2612,8 @@ database::get_vars(std::map<var_key, var
for (results::const_iterator i = res.begin(); i != res.end(); ++i)
{
var_domain domain(idx(*i, 0));
- base64<var_name> name_encoded(idx(*i, 1));
- var_name name;
- decode_base64(name_encoded, name);
- base64<var_value> value_encoded(idx(*i, 2));
- var_value value;
- decode_base64(value_encoded, value);
+ var_name name(idx(*i, 1));
+ var_value value(idx(*i, 2));
I(vars.find(std::make_pair(domain, name)) == vars.end());
vars.insert(std::make_pair(std::make_pair(domain, name), value));
}
@@ -2659,24 +2643,18 @@ database::set_var(var_key const & key, v
void
database::set_var(var_key const & key, var_value const & value)
{
- base64<var_name> name_encoded;
- encode_base64(key.second, name_encoded);
- base64<var_value> value_encoded;
- encode_base64(value, value_encoded);
execute(query("INSERT OR REPLACE INTO db_vars VALUES(?, ?, ?)")
% text(key.first())
- % text(name_encoded())
- % text(value_encoded()));
+ % blob(key.second())
+ % blob(value()));
}
void
database::clear_var(var_key const & key)
{
- base64<var_name> name_encoded;
- encode_base64(key.second, name_encoded);
execute(query("DELETE FROM db_vars WHERE domain = ? AND name = ?")
% text(key.first())
- % text(name_encoded()));
+ % blob(key.second()));
}
// branches
@@ -2690,10 +2668,7 @@ database::get_branches(vector<string> &
fetch(res, one_col, any_rows, q % text(cert_name));
for (size_t i = 0; i < res.size(); ++i)
{
- base64<data> row_encoded(res[i][0]);
- data name;
- decode_base64(row_encoded, name);
- names.push_back(name());
+ names.push_back(res[i][0]);
}
}
============================================================
--- schema.sql f44144278a4158695818d8f7e1901ac6f89e39bb
+++ schema.sql d811d7503305093359874d46f1142861657642c0
@@ -22,14 +22,14 @@ CREATE TABLE files
CREATE TABLE files
(
id primary key, -- strong hash of file contents
- data not null -- compressed, encoded contents of a file
- );
+ data not null -- compressed contents of a file
+ );
CREATE TABLE file_deltas
- (
+ (
id not null, -- strong hash of file contents
base not null, -- joins with files.id or file_deltas.id
- delta not null, -- rdiff to construct current from base
+ delta not null, -- compressed rdiff to construct current from base
unique(id, base)
);
============================================================
--- schema_migration.cc a13abc3a8c750aadb1ad07114c8f5b0cfc0cc67b
+++ schema_migration.cc c802e1820aa8381b39dde2b5fece6c29c5256efd
@@ -20,6 +20,7 @@
#include "botan/botan.h"
#include "app_state.hh"
#include "keys.hh"
+#include "transforms.hh"
// this file knows how to migrate schema databases. the general strategy is
// to hash each schema we ever use, and make a list of the SQL commands
@@ -54,12 +55,8 @@ typedef boost::tokenizer<boost::char_sep
typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
-extern "C" {
- const char *sqlite3_value_text_s(sqlite3_value *v);
-}
-
static string
-lowercase(string const & in)
+lowercase_facet(string const & in)
{
I(40==in.size());
const int sz=40;
@@ -93,7 +90,7 @@ calculate_id(string const & in,
Botan::Pipe p(new Botan::Hash_Filter("SHA-1"), new Botan::Hex_Encoder());
p.process_msg(in);
- ident = lowercase(p.read_all_as_string());
+ ident = lowercase_facet(p.read_all_as_string());
}
@@ -118,19 +115,19 @@ sqlite_sha1_fn(sqlite3_context *f, int n
if (nargs == 1)
{
- string s = (sqlite3_value_text_s(args[0]));
+ string s = reinterpret_cast<char const*>(sqlite3_value_text(args[0]));
s.erase(remove_if(s.begin(), s.end(), is_ws()),s.end());
tmp = s;
}
else
{
- string sep = string(sqlite3_value_text_s(args[0]));
- string s = (sqlite3_value_text_s(args[1]));
+ string sep = string(reinterpret_cast<char const*>(sqlite3_value_text(args[0])));
+ string s = reinterpret_cast<char const*>(sqlite3_value_text(args[1]));
s.erase(remove_if(s.begin(), s.end(), is_ws()),s.end());
tmp = s;
for (int i = 2; i < nargs; ++i)
{
- s = string(sqlite3_value_text_s(args[i]));
+ s = string(reinterpret_cast<char const*>(sqlite3_value_text(args[i])));
s.erase(remove_if(s.begin(), s.end(), is_ws()),s.end());
tmp += sep + s;
}
@@ -908,6 +905,135 @@ migrate_client_to_add_rosters(sqlite3 *
return true;
}
+static void
+sqlite3_unbase64_fn(sqlite3_context *f, int nargs, sqlite3_value ** args)
+{
+ if (nargs != 1)
+ {
+ sqlite3_result_error(f, "need exactly 1 arg to unbase64()", -1);
+ return;
+ }
+ data decoded;
+ decode_base64(base64<data>(string(reinterpret_cast<char const*>(sqlite3_value_text(args[0])))), decoded);
+ sqlite3_result_blob(f, decoded().c_str(), decoded().size(), SQLITE_TRANSIENT);
+}
+
+// I wish I had a form of ALTER TABLE COMMENT on sqlite3
+static bool
+migrate_files_BLOB(sqlite3 * sql,
+ char ** errmsg,
+ app_state *app)
+{
+ int res;
+ I(sqlite3_create_function(sql, "unbase64", -1,
+ SQLITE_UTF8, NULL,
+ &sqlite3_unbase64_fn,
+ NULL, NULL) == 0);
+ // change the encoding of file(_delta)s
+ if (!move_table(sql, errmsg,
+ "files",
+ "tmp",
+ "("
+ "id primary key,"
+ "data not null"
+ ")"))
+ return false;
+
+ res = logged_sqlite3_exec(sql, "CREATE TABLE files\n"
+ "\t(\n"
+ "\tid primary key, -- strong hash of file contents\n"
+ "\tdata not null -- compressed contents of a file\n"
+ "\t)", NULL, NULL, errmsg);
+ if (res != SQLITE_OK)
+ return false;
+
+ res = logged_sqlite3_exec(sql, "INSERT INTO files "
+ "SELECT id, unbase64(data) "
+ "FROM tmp", NULL, NULL, errmsg);
+ if (res != SQLITE_OK)
+ return false;
+
+ res = logged_sqlite3_exec(sql, "DROP TABLE tmp", NULL, NULL, errmsg);
+ if (res != SQLITE_OK)
+ return false;
+
+ if (!move_table(sql, errmsg,
+ "file_deltas",
+ "tmp",
+ "("
+ "id not null,"
+ "base not null,"
+ "delta not null"
+ ")"))
+ return false;
+
+ res = logged_sqlite3_exec(sql, "CREATE TABLE file_deltas\n"
+ "\t(\n"
+ "\tid not null, -- strong hash of file contents\n"
+ "\tbase not null, -- joins with files.id or file_deltas.id\n"
+ "\tdelta not null, -- compressed rdiff to construct current from base\n"
+ "\tunique(id, base)\n"
+ "\t)", NULL, NULL, errmsg);
+ if (res != SQLITE_OK)
+ return false;
+
+ res = logged_sqlite3_exec(sql, "INSERT INTO file_deltas "
+ "SELECT id, base, unbase64(delta) "
+ "FROM tmp", NULL, NULL, errmsg);
+ if (res != SQLITE_OK)
+ return false;
+
+ res = logged_sqlite3_exec(sql, "DROP TABLE tmp", NULL, NULL, errmsg);
+ if (res != SQLITE_OK)
+ return false;
+
+ // migrate other contents which are accessed by get|put_version
+ res = logged_sqlite3_exec(sql, "UPDATE manifests SET data=unbase64(data)",
+ NULL, NULL, errmsg);
+ if (res != SQLITE_OK)
+ return false;
+ res = logged_sqlite3_exec(sql, "UPDATE manifest_deltas "
+ "SET delta=unbase64(delta)", NULL, NULL, errmsg);
+ if (res != SQLITE_OK)
+ return false;
+ res = logged_sqlite3_exec(sql, "UPDATE rosters SET data=unbase64(data) ",
+ NULL, NULL, errmsg);
+ if (res != SQLITE_OK)
+ return false;
+ res = logged_sqlite3_exec(sql, "UPDATE roster_deltas "
+ "SET delta=unbase64(delta)", NULL, NULL, errmsg);
+ if (res != SQLITE_OK)
+ return false;
+
+ res = logged_sqlite3_exec(sql, "UPDATE db_vars "
+ "SET value=unbase64(value),name=unbase64(name)", NULL, NULL, errmsg);
+ if (res != SQLITE_OK)
+ return false;
+ res = logged_sqlite3_exec(sql, "UPDATE public_keys "
+ "SET keydata=unbase64(keydata)", NULL, NULL, errmsg);
+ if (res != SQLITE_OK)
+ return false;
+ res = logged_sqlite3_exec(sql, "UPDATE revision_certs "
+ "SET value=unbase64(value),signature=unbase64(signature)",
+ NULL, NULL, errmsg);
+ if (res != SQLITE_OK)
+ return false;
+ res = logged_sqlite3_exec(sql, "UPDATE manifest_certs "
+ "SET value=unbase64(value),signature=unbase64(signature) ",
+ NULL, NULL, errmsg);
+ if (res != SQLITE_OK)
+ return false;
+ res = logged_sqlite3_exec(sql, "UPDATE revisions "
+ "SET data=unbase64(data)", NULL, NULL, errmsg);
+ if (res != SQLITE_OK)
+ return false;
+ res = logged_sqlite3_exec(sql, "UPDATE branch_epochs "
+ "SET branch=unbase64(branch)", NULL, NULL, errmsg);
+ if (res != SQLITE_OK)
+ return false;
+ return true;
+}
+
void
migrate_monotone_schema(sqlite3 *sql, app_state *app)
{
@@ -939,9 +1065,12 @@ migrate_monotone_schema(sqlite3 *sql, ap
m.add("bd86f9a90b5d552f0be1fa9aee847ea0f317778b",
&migrate_client_to_add_rosters);
+ m.add("1db80c7cee8fa966913db1a463ed50bf1b0e5b0e",
+ &migrate_files_BLOB);
+
// IMPORTANT: whenever you modify this to add a new schema version, you must
// also add a new migration test for the new schema version. See
// tests/t_migrate_schema.at for details.
- m.migrate(sql, "1db80c7cee8fa966913db1a463ed50bf1b0e5b0e");
+ m.migrate(sql, "9d2b5d7b86df00c30ac34fe87a3c20f1195bb2df");
}
============================================================
--- tests/t_migrate_schema.at 9d9a73cc20f8e367f4c828484e78c19224614b93
+++ tests/t_migrate_schema.at e5b24dd9ccc44e36b20d1b1dc89509f0e99896fd
@@ -284,4 +284,181 @@ 5Zv/XbuXQ1m/fTpA9kr7T0e2Pv780pGhadLlP3b/
5Zv/XbuXQ1m/fTpA9kr7T0e2Pv780pGhadLlP3b/B/9helPJSAAA
])
+CHECK_MIGRATE_FROM([9d2b5d7b86df00c30ac34fe87a3c20f1195bb2df],
+[H4sIANfQ6UMCA+2cW2+dR5aer61fQfSNbEDt1Pkwc9OeiZEY6HEDbc+ggSAQ6tjiRCYVkupp
+//s870dLoiTS3pQyyE2sbomHvb86rfUeqlbtf/r2v333/dm3f/nnP/7rD9/927f/+OSf//zt
+Nz9+e/bjN//0x2/P+lW7GC+er1eX48X1ky++fPLFi3b94uzi8ubs4vXLl2evL87/9+v17OzN
+f7///dnxgst9drV+aucX5xd/Pdvn6+W8Prter9pVu1nzrP989rt/+N2TL26f/tDTeNa/X55f
+XJ/9x/nNCx73t/Pr88uL52Nd3Vx//bf28vV68sXRsXcP+OA/nkAL8/Knsxfr779fF+Ny0vr5
+fPLFVx+Mc/bnf2tX10/evPPLt1/xbobxtolnb598PS5fLQ20vXr18ny0Gzp3fHvGk96+/aL9
+tD588/F2XnT2v9bPb194DOijV/7ywtvRvnnp7TR9eduzZ0cTX7395Ycj2+cv1/O5Xt602/U7
+n/eN5ebqkoV6s3R6z9m4vLhZFze8q7frD3r2/tLo5ddf8+DLq7vNfa2JPr587828d1z+9Opq
+XV+zGFfzfO+zm0s1Ry9ej5uz8frqiobP9hULp7affPHLiM/ns+MHXx0L+N33P3z75x/Pvvv+
+xz/dbfbs3775479++8OXT1sdLRubam6zLZNSr2ma3Frv3mwzkwsxVTeePns6Q3V1u5Cm8y3a
+1VvKtaYSlyu7tm5y7qH49vTZX57aXbop5s5/e28fgzcrhua9G96vsJxxxqw2SnOxmnb7yqcn
+dNunXV0JZo69m3Mmhe7mrMuUUKYNPtL3PKK6veuMtrSwrDdl9FWi8X3OsmMu3aa5QjA5VHtS
+t9u7bvvW+deux3TbVPo3QvK2OdOGTcmHsCPD93stE1oaKaQW6LZdYyXD9Nbda0huLhezTdaa
+nGpv07ZiVpnlpG7Xd92uLeTgqr3b7Y9y4W0WvLo6/6ld/awkfHZKFsx2J5DfJM6dSH7zylsM
+0JvvjdJ3M/a5QRf6L8F2DJ6Z9ExsNPHhNXvXdu+rzV0WM+nKqCt6npPtaNvFEm2oxZu0evrV
+tpemXm1vO+knwXZS258btUfb7c24Y16j9ZlPa/tzQ+9ou75pu4Akw2x3t+33Au6ndnG+1/XN
+LWn9Kn8+jjk/RvH7OPNN82/A+W137gD0/QR1POnyVaNzSgv1Zby4vF4X6sHr63X15Iv7Cevu
+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
+D6TSUF9iWAAA
+])
+
AT_CLEANUP
============================================================
--- tests/t_sql_unpack.at 1bb994c7c10fcfafc2a0fc9b5dd7c45b5b315174
+++ tests/t_sql_gunzip.at 1e43988cec90fe9e16a51379b7b832cfc609d122
@@ -1,13 +1,9 @@
-AT_SETUP([sql functions unpack, unbase64])
+AT_SETUP([sql function gunzip (which replaced unpack)])
MONOTONE_SETUP
-AT_CHECK(MONOTONE db execute "select unpack('H4sIAAAAAAAAAE2RQW4bMQwA7/uKRe5JJEoUyXOu/YFhGJREJgvEq8BetOjvq/bg9EyQMxju9uty1X1zux/riQSbM2lsiZxSzI6qhSVayh0KKSF51XJelvHZLzf7ud23sa8n65KtJSfOkUTcQyRVLMFRIPfgSt4C9vO/vW8gGJVMjiFxCIEqd0rgbowhZ6AOoQAUlQn80qN9rE8v1+NZj+N2f1pWv43rlK6F0MQ6ilnrUnWKZHMGjlLaPCEdVdJ5Wdf1GOvJpRbs4hGpWiVJUCFYVkabg8wkWbTbf9C3D93f7cd4f0Ch6kySCnTiktRQggALCSXClr2TYYnAD2ggDIXD1IyhUmIs3jqyxb9dHG3G6jXH/A1tYz9uW31tm9ZxXK5jH8fY7eXr98NiLnNjT1VxhgR2lQoxSw05okaKyQtJxIcFJ20cerbSySMDzq+CZbKoSVKtmDqgVjgvfwA6AWjaGQIAAA==')", [], [stdout], [ignore])
+AT_CHECK(MONOTONE db execute "select gunzip(X'1f8b08000000000000004d91416e1b310c00effb8a45ee49244a14c973aefd8161189444260bc4abc05eb4e8efabf6e0f44c903318eef6eb72d57d73bb1feb89049b33696c899c52cc8eaa85255aca1d0a292179d5725e96f1d92f37fbb9ddb7b1af27eb92ad2527ce9144dc4324552cc15120f7e04ade02f6f3bfbd6f2018954c8e217108812a774ae06e8c2167a00ea100149509fcd2a37dac4f2fd7e3598fe3767f5a56bf8deb94ae85d0c43a8a59eb52758a6473068e52da3c211d55d27959d7f518ebc9a516ece211a95a254950215856469b83cc2459b4db7fd0b70fdddfedc7787f40a1ea4c920a74e292d45082000b0925c296bd936189c00f68200c85c3d48ca152622cde3ab2c5bf5d1c6dc6ea35c7fc0d6d633f6e5b7d6d9bd6715cae631fc7d8ede5ebf7c3622e73634f5571860476950a314b0d39a2468ac90b49c48705276d1c7ab6d2c92303ceaf8265b2a84952ad983aa056382f7f003a0168da19020000')", [], [stdout], [ignore])
AT_CHECK(QGREP('new_manifest \@<:@795cf87a1c37f7314f5aa6891e34d267a757fba6\@:>@' stdout))
AT_CHECK(QGREP('from \@<:@7b675e9ed59eecd9bac3f4ef828196c2069d5a93\@:>@' stdout))
-AT_CHECK(MONOTONE db execute "select unbase64('aXQncyB0ZW4gcGFjZXMgbm9ydGh3ZXN0IG9mIHRoZSBwYWxtIHRyZWUuICBGT09CQVI=')", [], [stdout], [ignore])
-
-AT_CHECK(QGREP(FOOBAR stdout))
-
AT_CLEANUP
============================================================
--- testsuite.at 7f433b14b3bd2a67eeacc49577a64e35d97ed02f
+++ testsuite.at 781e96c61a849b6f628e1aa691189b64f4d1bf08
@@ -629,7 +629,7 @@ m4_include(tests/t_db_execute.at)
m4_include(tests/t_commit_log_3.at)
m4_include(tests/t_at_sign.at)
m4_include(tests/t_db_execute.at)
-m4_include(tests/t_sql_unpack.at)
+m4_include(tests/t_sql_gunzip.at)
m4_include(tests/t_final_space.at)
m4_include(tests/t_inodeprints.at)
m4_include(tests/t_inodeprints_update.at)