# # patch "ChangeLog" # from [033b5fcc67eead39c3efad6b7314ef1c15525d6d] # to [eae32b0ac132ce4c767df1c4697a43ff2898764a] # # patch "database.cc" # from [c81a8c8cfaf1f6e1257d85470af1cd1f19b98e11] # to [9fdad7cd836e53714c0a49fd1ac5510116525d72] # # patch "schema.sql" # from [bd96fb52f2c501654f10445a6b8a7cfb6ea01019] # to [ac99524347304a61fe2d857bc45d1bcca73adb6e] # # patch "schema_migration.cc" # from [454fd869cecba6ce84ee4da05463441a2500f02b] # to [dbe70c577761111a22e6bc47649411c335399bdf] # # patch "tests/t_migrate_schema.at" # from [7e974a62fd0095b4a95d09eb1780d4744fe506e9] # to [a5021d066df05e23620346dbc5cf480377af160f] # --- ChangeLog +++ ChangeLog @@ -1,7 +1,19 @@ +2005-07-09 Nathaniel Smith + + * schema.sql (revision_ancestry__child, revision_certs__id, + revision_certs__name_value): New indexes. + * database.cc (dump, dump_table_cb, dump_index_cb): Include + indexes in dumps. + (database::database): + * schema_migration.cc (migrate_monotone_schema) + (migrate_client_to_add_indexes): + * tests/t_migrate_schema.at: Corresponding migration gunk. + 2005-07-09 Jordan Breeding * Makefile.am (monotone_CPPFLAGS, unit_tests_CPPFLAGS): - * configure.ac (BOOST_FIX_VERSION): + * configure.ac (BOOST_FIX_VERSION): Restrict boost compile kluges + to boost 1.32. 2005-07-10 Matthew Gregan --- database.cc +++ database.cc @@ -118,7 +118,7 @@ // 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("e372b508bea9b991816d1c74680f7ae10d2a6d94"), + schema("1509fd75019aebef5ac3da3a5edf1312393b70e9"), __sql(NULL), transaction_level(0) {} @@ -305,16 +305,30 @@ I(vals[1] != NULL); I(vals[2] != NULL); I(n == 3); - if (string(vals[1]) == "table") - { - *(dump->out) << vals[2] << ";\n"; - dump->table_name = string(vals[0]); - sqlite3_exec_printf(dump->sql, "SELECT * FROM '%q'", - dump_row_cb, data, NULL, vals[0]); - } + I(string(vals[1]) == "table"); + *(dump->out) << vals[2] << ";\n"; + dump->table_name = string(vals[0]); + sqlite3_exec_printf(dump->sql, "SELECT * FROM '%q'", + dump_row_cb, data, NULL, vals[0]); return 0; } +static int +dump_index_cb(void *data, int n, char **vals, char **cols) +{ + dump_request *dump = reinterpret_cast(data); + I(dump != NULL); + I(dump->sql != NULL); + I(vals != NULL); + I(vals[0] != NULL); + I(vals[1] != NULL); + I(vals[2] != NULL); + I(n == 3); + I(string(vals[1]) == "index"); + *(dump->out) << vals[2] << ";\n"; + return 0; +} + void database::dump(ostream & out) { @@ -322,12 +336,19 @@ req.out = &out; req.sql = sql(); out << "BEGIN TRANSACTION;\n"; - int res = sqlite3_exec(req.sql, + int res; + res = sqlite3_exec(req.sql, "SELECT name, type, sql FROM sqlite_master " "WHERE type='table' AND sql NOT NULL " - "ORDER BY substr(type,2,1), name", + "ORDER BY name", dump_table_cb, &req, NULL); I(res == SQLITE_OK); + res = sqlite3_exec(req.sql, + "SELECT name, type, sql FROM sqlite_master " + "WHERE type='index' AND sql NOT NULL " + "ORDER BY name", + dump_index_cb, &req, NULL); + I(res == SQLITE_OK); out << "COMMIT;\n"; } --- schema.sql +++ schema.sql @@ -58,6 +58,8 @@ unique(parent, child) ); +CREATE INDEX revision_ancestry__child ON revision_ancestry (child); + -- structures for managing RSA keys and file / manifest certs CREATE TABLE public_keys @@ -96,6 +98,9 @@ unique(name, id, value, keypair, signature) ); +CREATE INDEX revision_certs__id ON revision_certs (id); +CREATE INDEX revision_certs__name_value ON revision_certs (name, value); + CREATE TABLE branch_epochs ( hash not null unique, -- hash of remaining fields separated by ":" --- schema_migration.cc +++ schema_migration.cc @@ -718,6 +718,36 @@ return true; } +static bool +migrate_client_to_add_indexes(sqlite3 * sql, + char ** errmsg) +{ + int res; + + res = sqlite3_exec_printf(sql, + "CREATE INDEX revision_ancestry__child " + "ON revision_ancestry (child)", + NULL, NULL, errmsg); + if (res != SQLITE_OK) + return false; + + res = sqlite3_exec_printf(sql, + "CREATE INDEX revision_certs__id " + "ON revision_certs (id);", + NULL, NULL, errmsg); + if (res != SQLITE_OK) + return false; + + res = sqlite3_exec_printf(sql, + "CREATE INDEX revision_certs__name_value " + "ON revision_certs (name, value);", + NULL, NULL, errmsg); + if (res != SQLITE_OK) + return false; + + return true; +} + void migrate_monotone_schema(sqlite3 *sql) { @@ -739,11 +769,14 @@ m.add("40369a7bda66463c5785d160819ab6398b9d44f4", &migrate_client_to_vars); + m.add("e372b508bea9b991816d1c74680f7ae10d2a6d94", + &migrate_client_to_add_indexes); + // 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, "e372b508bea9b991816d1c74680f7ae10d2a6d94"); + m.migrate(sql, "1509fd75019aebef5ac3da3a5edf1312393b70e9"); if (sqlite3_exec(sql, "VACUUM", NULL, NULL, NULL) != SQLITE_OK) throw runtime_error("error vacuuming after migration"); --- tests/t_migrate_schema.at +++ tests/t_migrate_schema.at @@ -19,10 +19,10 @@ # this will cause autotest to leave behind the temporary files the # test generates. You want 'testsuite.dir/073/latest.db.dump'. Gzip # it, base64 it, and stick it in this file with the id of its schema. -# (E.g., gzip -c latest.db | mimencode > foo, then copy the contents -# of foo into this file. Make sure when you do that that you put a -# newline between the end of the base64'd text and the closing ], or -# autotest will get very weirdly confused.) +# (E.g., gzip -c latest.db.dump | mimencode > foo, then copy the +# contents of foo into this file. Make sure when you do that that you +# put a newline between the end of the base64'd text and the closing +# ], or autotest will get very weirdly confused.) ###################################################################### ## Do not touch this code; you'll have to regenerate all the test @@ -555,4 +555,152 @@ dRaSpiDUOiwLrVwURaqtJBHUjCgUc8BscXJrLqC4yEX3CNWGT2AikQWB7a4bJTGEZKsmUwxz ixPhjyXgfnuC3tA02frPzf8CKk8cw5M9AAA= ]) + +CHECK_MIGRATE_FROM([1509fd75019aebef5ac3da3a5edf1312393b70e9], +[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 +]) + AT_CLEANUP