monotone

monotone Mtn Source Tree

Root/schema_migration.cc

1// copyright (C) 2002, 2003 graydon hoare <graydon@pobox.com>
2// all rights reserved.
3// licensed to the public under the terms of the GNU GPL (>= 2)
4// see the file COPYING for details
5
6#include <algorithm>
7#include <string>
8#include <vector>
9#include <locale>
10#include <stdexcept>
11#include <iostream>
12#include <map>
13
14#include <boost/tokenizer.hpp>
15
16#include <sqlite3.h>
17
18#include "sanity.hh"
19#include "schema_migration.hh"
20#include "botan/botan.h"
21#include "app_state.hh"
22#include "keys.hh"
23
24// this file knows how to migrate schema databases. the general strategy is
25// to hash each schema we ever use, and make a list of the SQL commands
26// required to get from one hash value to the next. when you do a
27// migration, the migrator locates your current db's state on the list and
28// then runs all the migration functions between that point and the target
29// of the migration.
30
31// you will notice a little bit of duplicated code between here and
32// transforms.cc / database.cc; this was originally to facilitate inclusion of
33// migration capability into the depot code, which did not link against those
34// objects. the depot code is gone, but this isn't the sort of code that
35// should ever be touched after being written, so the duplication currently
36// remains. if it becomes a maintainence burden, however, consider
37// refactoring.
38
39using namespace std;
40
41static int logged_sqlite3_exec(sqlite3* db,
42 const char* sql,
43 sqlite3_callback cb,
44 void* data,
45 char** errmsg)
46{
47 L(F("executing SQL '%s'") % sql);
48 int res = sqlite3_exec(db, sql, cb, data, errmsg);
49 L(F("result: %i (%s)") % res % sqlite3_errmsg(db));
50 if (errmsg)
51 L(F("errmsg: %s") % *errmsg);
52 return res;
53}
54
55typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
56
57extern "C" {
58 const char *sqlite3_value_text_s(sqlite3_value *v);
59}
60
61static string
62lowercase(string const & in)
63{
64 I(40==in.size());
65 const int sz=40;
66 char buf[sz];
67 in.copy(buf, sz);
68 locale loc;
69 use_facet< ctype<char> >(loc).tolower(buf, buf+sz);
70 return string(buf,sz);
71}
72
73static void
74massage_sql_tokens(string const & in,
75 string & out)
76{
77 boost::char_separator<char> sep(" \r\n\t", "(),;");
78 tokenizer tokens(in, sep);
79 out.clear();
80 for (tokenizer::iterator i = tokens.begin();
81 i != tokens.end(); ++i)
82 {
83 if (i != tokens.begin())
84 out += " ";
85 out += *i;
86 }
87}
88
89static void
90calculate_id(string const & in,
91 string & ident)
92{
93 Botan::Pipe p(new Botan::Hash_Filter("SHA-1"), new Botan::Hex_Encoder());
94 p.process_msg(in);
95
96 ident = lowercase(p.read_all_as_string());
97}
98
99
100struct
101is_ws
102{
103 bool operator()(char c) const
104 {
105 return c == '\r' || c == '\n' || c == '\t' || c == ' ';
106 }
107};
108
109static void
110sqlite_sha1_fn(sqlite3_context *f, int nargs, sqlite3_value ** args)
111{
112 string tmp, sha;
113 if (nargs <= 1)
114 {
115 sqlite3_result_error(f, "need at least 1 arg to sha1()", -1);
116 return;
117 }
118
119 if (nargs == 1)
120 {
121 string s = (sqlite3_value_text_s(args[0]));
122 s.erase(remove_if(s.begin(), s.end(), is_ws()),s.end());
123 tmp = s;
124 }
125 else
126 {
127 string sep = string(sqlite3_value_text_s(args[0]));
128 string s = (sqlite3_value_text_s(args[1]));
129 s.erase(remove_if(s.begin(), s.end(), is_ws()),s.end());
130 tmp = s;
131 for (int i = 2; i < nargs; ++i)
132 {
133 s = string(sqlite3_value_text_s(args[i]));
134 s.erase(remove_if(s.begin(), s.end(), is_ws()),s.end());
135 tmp += sep + s;
136 }
137 }
138 calculate_id(tmp, sha);
139 sqlite3_result_text(f,sha.c_str(),sha.size(),SQLITE_TRANSIENT);
140}
141
142int
143append_sql_stmt(void * vp,
144 int ncols,
145 char ** values,
146 char ** colnames)
147{
148 if (ncols != 1)
149 return 1;
150
151 if (vp == NULL)
152 return 1;
153
154 if (values == NULL)
155 return 1;
156
157 if (values[0] == NULL)
158 return 1;
159
160 string *str = reinterpret_cast<string *>(vp);
161 str->append(values[0]);
162 str->append("\n");
163 return 0;
164}
165
166void
167calculate_schema_id(sqlite3 *sql, string & id)
168{
169 id.clear();
170 string tmp, tmp2;
171 int res = logged_sqlite3_exec(sql,
172 "SELECT sql FROM sqlite_master "
173 "WHERE (type = 'table' OR type = 'index') "
174 // filter out NULL sql statements, because
175 // those are auto-generated indices (for
176 // UNIQUE constraints, etc.).
177 "AND sql IS NOT NULL "
178 "AND name not like 'sqlite_stat%' "
179 "ORDER BY name",
180 &append_sql_stmt, &tmp, NULL);
181 if (res != SQLITE_OK)
182 {
183 logged_sqlite3_exec(sql, "ROLLBACK", NULL, NULL, NULL);
184 E(false, F("failure extracting schema from sqlite_master"));
185 }
186 massage_sql_tokens(tmp, tmp2);
187 calculate_id(tmp2, id);
188}
189
190typedef bool (*migrator_cb)(sqlite3 *, char **, app_state *);
191
192struct
193migrator
194{
195 vector< pair<string,migrator_cb> > migration_events;
196 app_state * __app;
197
198 void set_app(app_state *app)
199 {
200 __app = app;
201 }
202
203 void add(string schema_id, migrator_cb cb)
204 {
205 migration_events.push_back(make_pair(schema_id, cb));
206 }
207
208 void migrate(sqlite3 *sql, string target_id)
209 {
210 string init;
211
212 I(sql != NULL);
213
214 calculate_schema_id(sql, init);
215
216 I(!sqlite3_create_function(sql, "sha1", -1, SQLITE_UTF8, NULL,
217 &sqlite_sha1_fn, NULL, NULL));
218
219 bool migrating = false;
220 for (vector< pair<string, migrator_cb> >::const_iterator i = migration_events.begin();
221 i != migration_events.end(); ++i)
222 {
223
224 if (i->first == init)
225 {
226 E(logged_sqlite3_exec(sql, "BEGIN EXCLUSIVE", NULL, NULL, NULL) == SQLITE_OK,
227 F("error at transaction BEGIN statement"));
228 migrating = true;
229 }
230
231 if (migrating)
232 {
233 // confirm that we are where we ought to be
234 string curr;
235 char *errmsg = NULL;
236 calculate_schema_id(sql, curr);
237 if (curr != i->first)
238 {
239 if (migrating)
240 logged_sqlite3_exec(sql, "ROLLBACK", NULL, NULL, NULL);
241 I(false);
242 }
243
244 if (i->second == NULL)
245 {
246 logged_sqlite3_exec(sql, "ROLLBACK", NULL, NULL, NULL);
247 I(false);
248 }
249
250 // do this migration step
251 else if (! i->second(sql, &errmsg, __app))
252 {
253 logged_sqlite3_exec(sql, "ROLLBACK", NULL, NULL, NULL);
254 E(false, F("migration step failed: %s")
255 % (errmsg ? errmsg : "unknown error"));
256 }
257 }
258 }
259
260 // confirm that our target schema was met
261 if (migrating)
262 {
263 string curr;
264 calculate_schema_id(sql, curr);
265 if (curr != target_id)
266 {
267 logged_sqlite3_exec(sql, "ROLLBACK", NULL, NULL, NULL);
268 E(false, F("mismatched result of migration, got %s, wanted %s")
269 % curr % target_id);
270 }
271 P(F("committing changes to database"));
272 E(logged_sqlite3_exec(sql, "COMMIT", NULL, NULL, NULL) == SQLITE_OK,
273 F("failure on COMMIT"));
274
275 P(F("optimizing database"));
276 E(logged_sqlite3_exec(sql, "VACUUM", NULL, NULL, NULL) == SQLITE_OK,
277 F("error vacuuming after migration"));
278
279 E(logged_sqlite3_exec(sql, "ANALYZE", NULL, NULL, NULL) == SQLITE_OK,
280 F("error running analyze after migration"));
281 }
282 else
283 {
284 // if we didn't do anything, make sure that it's because we were
285 // already up to date.
286 E(init == target_id,
287 F("database schema %s is unknown; cannot perform migration") % init);
288 // We really want 'db migrate' on an up-to-date schema to be a no-op
289 // (no vacuum or anything, even), so that automated scripts can fire
290 // one off optimistically and not have to worry about getting their
291 // administrators to do it by hand.
292 P(F("no migration performed; database schema already up-to-date at %s\n") % init);
293 }
294 }
295};
296
297static bool move_table(sqlite3 *sql, char **errmsg,
298 char const * srcname,
299 char const * dstname,
300 char const * dstschema)
301{
302 string create = "CREATE TABLE ";
303 create += dstname;
304 create += " ";
305 create += dstschema;
306
307 int res = logged_sqlite3_exec(sql, create.c_str(), NULL, NULL, errmsg);
308 if (res != SQLITE_OK)
309 return false;
310
311 string insert = "INSERT INTO ";
312 insert += dstname;
313 insert += " SELECT * FROM ";
314 insert += srcname;
315
316 res = logged_sqlite3_exec(sql, insert.c_str(), NULL, NULL, errmsg);
317 if (res != SQLITE_OK)
318 return false;
319
320 string drop = "DROP TABLE ";
321 drop += srcname;
322
323 res = logged_sqlite3_exec(sql, drop.c_str(), NULL, NULL, errmsg);
324 if (res != SQLITE_OK)
325 return false;
326
327 return true;
328}
329
330
331static bool
332migrate_client_merge_url_and_group(sqlite3 * sql,
333 char ** errmsg,
334 app_state *)
335{
336
337 // migrate the posting_queue table
338 if (!move_table(sql, errmsg,
339 "posting_queue",
340 "tmp",
341 "("
342 "url not null,"
343 "groupname not null,"
344 "content not null"
345 ")"))
346 return false;
347
348 int res = logged_sqlite3_exec(sql, "CREATE TABLE posting_queue "
349 "("
350 "url not null, -- URL we are going to send this to\n"
351 "content not null -- the packets we're going to send\n"
352 ")", NULL, NULL, errmsg);
353 if (res != SQLITE_OK)
354 return false;
355
356 res = logged_sqlite3_exec(sql, "INSERT INTO posting_queue "
357 "SELECT "
358 "(url || '/' || groupname), "
359 "content "
360 "FROM tmp", NULL, NULL, errmsg);
361 if (res != SQLITE_OK)
362 return false;
363
364 res = logged_sqlite3_exec(sql, "DROP TABLE tmp", NULL, NULL, errmsg);
365 if (res != SQLITE_OK)
366 return false;
367
368
369 // migrate the incoming_queue table
370 if (!move_table(sql, errmsg,
371 "incoming_queue",
372 "tmp",
373 "("
374 "url not null,"
375 "groupname not null,"
376 "content not null"
377 ")"))
378 return false;
379
380 res = logged_sqlite3_exec(sql, "CREATE TABLE incoming_queue "
381 "("
382 "url not null, -- URL we got this bundle from\n"
383 "content not null -- the packets we're going to read\n"
384 ")", NULL, NULL, errmsg);
385 if (res != SQLITE_OK)
386 return false;
387
388 res = logged_sqlite3_exec(sql, "INSERT INTO incoming_queue "
389 "SELECT "
390 "(url || '/' || groupname), "
391 "content "
392 "FROM tmp", NULL, NULL, errmsg);
393 if (res != SQLITE_OK)
394 return false;
395
396 res = logged_sqlite3_exec(sql, "DROP TABLE tmp", NULL, NULL, errmsg);
397 if (res != SQLITE_OK)
398 return false;
399
400
401 // migrate the sequence_numbers table
402 if (!move_table(sql, errmsg,
403 "sequence_numbers",
404 "tmp",
405 "("
406 "url not null,"
407 "groupname not null,"
408 "major not null,"
409 "minor not null,"
410 "unique(url, groupname)"
411 ")"
412 ))
413 return false;
414
415 res = logged_sqlite3_exec(sql, "CREATE TABLE sequence_numbers "
416 "("
417 "url primary key, -- URL to read from\n"
418 "major not null, -- 0 in news servers, may be higher in depots\n"
419 "minor not null -- last article / packet sequence number we got\n"
420 ")", NULL, NULL, errmsg);
421 if (res != SQLITE_OK)
422 return false;
423
424 res = logged_sqlite3_exec(sql, "INSERT INTO sequence_numbers "
425 "SELECT "
426 "(url || '/' || groupname), "
427 "major, "
428 "minor "
429 "FROM tmp", NULL, NULL, errmsg);
430 if (res != SQLITE_OK)
431 return false;
432
433 res = logged_sqlite3_exec(sql, "DROP TABLE tmp", NULL, NULL, errmsg);
434 if (res != SQLITE_OK)
435 return false;
436
437
438 // migrate the netserver_manifests table
439 if (!move_table(sql, errmsg,
440 "netserver_manifests",
441 "tmp",
442 "("
443 "url not null,"
444 "groupname not null,"
445 "manifest not null,"
446 "unique(url, groupname, manifest)"
447 ")"
448 ))
449 return false;
450
451 res = logged_sqlite3_exec(sql, "CREATE TABLE netserver_manifests "
452 "("
453 "url not null, -- url of some server\n"
454 "manifest not null, -- manifest which exists on url\n"
455 "unique(url, manifest)"
456 ")", NULL, NULL, errmsg);
457 if (res != SQLITE_OK)
458 return false;
459
460 res = logged_sqlite3_exec(sql, "INSERT INTO netserver_manifests "
461 "SELECT "
462 "(url || '/' || groupname), "
463 "manifest "
464 "FROM tmp", NULL, NULL, errmsg);
465 if (res != SQLITE_OK)
466 return false;
467
468 res = logged_sqlite3_exec(sql, "DROP TABLE tmp", NULL, NULL, errmsg);
469 if (res != SQLITE_OK)
470 return false;
471
472 return true;
473}
474
475static bool
476migrate_client_add_hashes_and_merkle_trees(sqlite3 * sql,
477 char ** errmsg,
478 app_state *)
479{
480
481 // add the column to manifest_certs
482 if (!move_table(sql, errmsg,
483 "manifest_certs",
484 "tmp",
485 "("
486 "id not null,"
487 "name not null,"
488 "value not null,"
489 "keypair not null,"
490 "signature not null,"
491 "unique(name, id, value, keypair, signature)"
492 ")"))
493 return false;
494
495 int res = logged_sqlite3_exec(sql, "CREATE TABLE manifest_certs\n"
496 "(\n"
497 "hash not null unique, -- hash of remaining fields separated by \":\"\n"
498 "id not null, -- joins with manifests.id or manifest_deltas.id\n"
499 "name not null, -- opaque string chosen by user\n"
500 "value not null, -- opaque blob\n"
501 "keypair not null, -- joins with public_keys.id\n"
502 "signature not null, -- RSA/SHA1 signature of \"[name@id:val]\"\n"
503 "unique(name, id, value, keypair, signature)\n"
504 ")", NULL, NULL, errmsg);
505 if (res != SQLITE_OK)
506 return false;
507
508 res = logged_sqlite3_exec(sql, "INSERT INTO manifest_certs "
509 "SELECT "
510 "sha1(':', id, name, value, keypair, signature), "
511 "id, name, value, keypair, signature "
512 "FROM tmp", NULL, NULL, errmsg);
513 if (res != SQLITE_OK)
514 return false;
515
516 res = logged_sqlite3_exec(sql, "DROP TABLE tmp", NULL, NULL, errmsg);
517 if (res != SQLITE_OK)
518 return false;
519
520 // add the column to file_certs
521 if (!move_table(sql, errmsg,
522 "file_certs",
523 "tmp",
524 "("
525 "id not null,"
526 "name not null,"
527 "value not null,"
528 "keypair not null,"
529 "signature not null,"
530 "unique(name, id, value, keypair, signature)"
531 ")"))
532 return false;
533
534 res = logged_sqlite3_exec(sql, "CREATE TABLE file_certs\n"
535 "(\n"
536 "hash not null unique, -- hash of remaining fields separated by \":\"\n"
537 "id not null, -- joins with files.id or file_deltas.id\n"
538 "name not null, -- opaque string chosen by user\n"
539 "value not null, -- opaque blob\n"
540 "keypair not null, -- joins with public_keys.id\n"
541 "signature not null, -- RSA/SHA1 signature of \"[name@id:val]\"\n"
542 "unique(name, id, value, keypair, signature)\n"
543 ")", NULL, NULL, errmsg);
544 if (res != SQLITE_OK)
545 return false;
546
547 res = logged_sqlite3_exec(sql, "INSERT INTO file_certs "
548 "SELECT "
549 "sha1(':', id, name, value, keypair, signature), "
550 "id, name, value, keypair, signature "
551 "FROM tmp", NULL, NULL, errmsg);
552 if (res != SQLITE_OK)
553 return false;
554
555 res = logged_sqlite3_exec(sql, "DROP TABLE tmp", NULL, NULL, errmsg);
556 if (res != SQLITE_OK)
557 return false;
558
559 // add the column to public_keys
560 if (!move_table(sql, errmsg,
561 "public_keys",
562 "tmp",
563 "("
564 "id primary key,"
565 "keydata not null"
566 ")"))
567 return false;
568
569 res = logged_sqlite3_exec(sql, "CREATE TABLE public_keys\n"
570 "(\n"
571 "hash not null unique, -- hash of remaining fields separated by \":\"\n"
572 "id primary key, -- key identifier chosen by user\n"
573 "keydata not null -- RSA public params\n"
574 ")", NULL, NULL, errmsg);
575 if (res != SQLITE_OK)
576 return false;
577
578 res = logged_sqlite3_exec(sql, "INSERT INTO public_keys "
579 "SELECT "
580 "sha1(':', id, keydata), "
581 "id, keydata "
582 "FROM tmp", NULL, NULL, errmsg);
583 if (res != SQLITE_OK)
584 return false;
585
586 res = logged_sqlite3_exec(sql, "DROP TABLE tmp", NULL, NULL, errmsg);
587 if (res != SQLITE_OK)
588 return false;
589
590 // add the column to private_keys
591 if (!move_table(sql, errmsg,
592 "private_keys",
593 "tmp",
594 "("
595 "id primary key,"
596 "keydata not null"
597 ")"))
598 return false;
599
600 res = logged_sqlite3_exec(sql, "CREATE TABLE private_keys\n"
601 "(\n"
602 "hash not null unique, -- hash of remaining fields separated by \":\"\n"
603 "id primary key, -- as in public_keys (same identifiers, in fact)\n"
604 "keydata not null -- encrypted RSA private params\n"
605 ")", NULL, NULL, errmsg);
606 if (res != SQLITE_OK)
607 return false;
608
609 res = logged_sqlite3_exec(sql, "INSERT INTO private_keys "
610 "SELECT "
611 "sha1(':', id, keydata), "
612 "id, keydata "
613 "FROM tmp", NULL, NULL, errmsg);
614 if (res != SQLITE_OK)
615 return false;
616
617 res = logged_sqlite3_exec(sql, "DROP TABLE tmp", NULL, NULL, errmsg);
618 if (res != SQLITE_OK)
619 return false;
620
621 // add the merkle tree stuff
622
623 res = logged_sqlite3_exec(sql,
624 "CREATE TABLE merkle_nodes\n"
625 "(\n"
626 "type not null, -- \"key\", \"mcert\", \"fcert\", \"manifest\"\n"
627 "collection not null, -- name chosen by user\n"
628 "level not null, -- tree level this prefix encodes\n"
629 "prefix not null, -- label identifying node in tree\n"
630 "body not null, -- binary, base64'ed node contents\n"
631 "unique(type, collection, level, prefix)\n"
632 ")", NULL, NULL, errmsg);
633 if (res != SQLITE_OK)
634 return false;
635
636 return true;
637}
638
639static bool
640migrate_client_to_revisions(sqlite3 * sql,
641 char ** errmsg,
642 app_state *)
643{
644 int res;
645
646 res = logged_sqlite3_exec(sql, "DROP TABLE schema_version;", NULL, NULL, errmsg);
647 if (res != SQLITE_OK)
648 return false;
649
650 res = logged_sqlite3_exec(sql, "DROP TABLE posting_queue;", NULL, NULL, errmsg);
651 if (res != SQLITE_OK)
652 return false;
653
654 res = logged_sqlite3_exec(sql, "DROP TABLE incoming_queue;", NULL, NULL, errmsg);
655 if (res != SQLITE_OK)
656 return false;
657
658 res = logged_sqlite3_exec(sql, "DROP TABLE sequence_numbers;", NULL, NULL, errmsg);
659 if (res != SQLITE_OK)
660 return false;
661
662 res = logged_sqlite3_exec(sql, "DROP TABLE file_certs;", NULL, NULL, errmsg);
663 if (res != SQLITE_OK)
664 return false;
665
666 res = logged_sqlite3_exec(sql, "DROP TABLE netserver_manifests;", NULL, NULL, errmsg);
667 if (res != SQLITE_OK)
668 return false;
669
670 res = logged_sqlite3_exec(sql, "DROP TABLE merkle_nodes;", NULL, NULL, errmsg);
671 if (res != SQLITE_OK)
672 return false;
673
674 res = logged_sqlite3_exec(sql,
675 "CREATE TABLE merkle_nodes\n"
676 "(\n"
677 "type not null, -- \"key\", \"mcert\", \"fcert\", \"rcert\"\n"
678 "collection not null, -- name chosen by user\n"
679 "level not null, -- tree level this prefix encodes\n"
680 "prefix not null, -- label identifying node in tree\n"
681 "body not null, -- binary, base64'ed node contents\n"
682 "unique(type, collection, level, prefix)\n"
683 ")", NULL, NULL, errmsg);
684 if (res != SQLITE_OK)
685 return false;
686
687 res = logged_sqlite3_exec(sql, "CREATE TABLE revision_certs\n"
688 "(\n"
689 "hash not null unique, -- hash of remaining fields separated by \":\"\n"
690 "id not null, -- joins with revisions.id\n"
691 "name not null, -- opaque string chosen by user\n"
692 "value not null, -- opaque blob\n"
693 "keypair not null, -- joins with public_keys.id\n"
694 "signature not null, -- RSA/SHA1 signature of \"[name@id:val]\"\n"
695 "unique(name, id, value, keypair, signature)\n"
696 ")", NULL, NULL, errmsg);
697 if (res != SQLITE_OK)
698 return false;
699
700 res = logged_sqlite3_exec(sql, "CREATE TABLE revisions\n"
701 "(\n"
702 "id primary key, -- SHA1(text of revision)\n"
703 "data not null -- compressed, encoded contents of a revision\n"
704 ")", NULL, NULL, errmsg);
705 if (res != SQLITE_OK)
706 return false;
707
708 res = logged_sqlite3_exec(sql, "CREATE TABLE revision_ancestry\n"
709 "(\n"
710 "parent not null, -- joins with revisions.id\n"
711 "child not null, -- joins with revisions.id\n"
712 "unique(parent, child)\n"
713 ")", NULL, NULL, errmsg);
714 if (res != SQLITE_OK)
715 return false;
716
717 return true;
718}
719
720
721static bool
722migrate_client_to_epochs(sqlite3 * sql,
723 char ** errmsg,
724 app_state *)
725{
726 int res;
727
728 res = logged_sqlite3_exec(sql, "DROP TABLE merkle_nodes;", NULL, NULL, errmsg);
729 if (res != SQLITE_OK)
730 return false;
731
732
733 res = logged_sqlite3_exec(sql,
734 "CREATE TABLE branch_epochs\n"
735 "(\n"
736 "hash not null unique, -- hash of remaining fields separated by \":\"\n"
737 "branch not null unique, -- joins with revision_certs.value\n"
738 "epoch not null -- random hex-encoded id\n"
739 ");", NULL, NULL, errmsg);
740 if (res != SQLITE_OK)
741 return false;
742
743 return true;
744}
745
746static bool
747migrate_client_to_vars(sqlite3 * sql,
748 char ** errmsg,
749 app_state *)
750{
751 int res;
752
753 res = logged_sqlite3_exec(sql,
754 "CREATE TABLE db_vars\n"
755 "(\n"
756 "domain not null, -- scope of application of a var\n"
757 "name not null, -- var key\n"
758 "value not null, -- var value\n"
759 "unique(domain, name)\n"
760 ");", NULL, NULL, errmsg);
761 if (res != SQLITE_OK)
762 return false;
763
764 return true;
765}
766
767static bool
768migrate_client_to_add_indexes(sqlite3 * sql,
769 char ** errmsg,
770 app_state *)
771{
772 int res;
773
774 res = logged_sqlite3_exec(sql,
775 "CREATE INDEX revision_ancestry__child "
776 "ON revision_ancestry (child)",
777 NULL, NULL, errmsg);
778 if (res != SQLITE_OK)
779 return false;
780
781 res = logged_sqlite3_exec(sql,
782 "CREATE INDEX revision_certs__id "
783 "ON revision_certs (id);",
784 NULL, NULL, errmsg);
785 if (res != SQLITE_OK)
786 return false;
787
788 res = logged_sqlite3_exec(sql,
789 "CREATE INDEX revision_certs__name_value "
790 "ON revision_certs (name, value);",
791 NULL, NULL, errmsg);
792 if (res != SQLITE_OK)
793 return false;
794
795 return true;
796}
797
798static int
799extract_key(void *ptr, int ncols, char **values, char **names)
800{
801 // This is stupid. The cast should not be needed.
802 map<string, string> *out = (map<string, string>*)ptr;
803 I(ncols == 2);
804 out->insert(make_pair(string(values[0]), string(values[1])));
805 return 0;
806}
807static bool
808migrate_client_to_external_privkeys(sqlite3 * sql,
809 char ** errmsg,
810 app_state *app)
811{
812 int res;
813 map<string, string> pub, priv;
814 vector<keypair> pairs;
815
816 res = logged_sqlite3_exec(sql,
817 "SELECT id, keydata FROM private_keys;",
818 &extract_key, &priv, errmsg);
819 if (res != SQLITE_OK)
820 return false;
821
822 res = logged_sqlite3_exec(sql,
823 "SELECT id, keydata FROM public_keys;",
824 &extract_key, &pub, errmsg);
825 if (res != SQLITE_OK)
826 return false;
827
828 for (map<string, string>::const_iterator i = priv.begin();
829 i != priv.end(); ++i)
830 {
831 rsa_keypair_id ident = i->first;
832 base64< arc4<rsa_priv_key> > old_priv = i->second;
833 map<string, string>::const_iterator j = pub.find(i->first);
834 keypair kp;
835 migrate_private_key(*app, ident, old_priv, kp);
836 MM(kp.pub);
837 if (j != pub.end())
838 {
839 base64< rsa_pub_key > pub = j->second;
840 MM(pub);
841 N(keys_match(ident, pub, ident, kp.pub),
842 F("public and private keys for %s don't match") % ident);
843 }
844
845 P(F("moving key '%s' from database to %s")
846 % ident % app->keys.get_key_dir());
847 app->keys.put_key_pair(ident, kp);
848 }
849
850 res = logged_sqlite3_exec(sql, "DROP TABLE private_keys;", NULL, NULL, errmsg);
851 if (res != SQLITE_OK)
852 return false;
853
854 return true;
855}
856
857void
858migrate_monotone_schema(sqlite3 *sql, app_state *app)
859{
860
861 migrator m;
862 m.set_app(app);
863
864 m.add("edb5fa6cef65bcb7d0c612023d267c3aeaa1e57a",
865 &migrate_client_merge_url_and_group);
866
867 m.add("f042f3c4d0a4f98f6658cbaf603d376acf88ff4b",
868 &migrate_client_add_hashes_and_merkle_trees);
869
870 m.add("8929e54f40bf4d3b4aea8b037d2c9263e82abdf4",
871 &migrate_client_to_revisions);
872
873 m.add("c1e86588e11ad07fa53e5d294edc043ce1d4005a",
874 &migrate_client_to_epochs);
875
876 m.add("40369a7bda66463c5785d160819ab6398b9d44f4",
877 &migrate_client_to_vars);
878
879 m.add("e372b508bea9b991816d1c74680f7ae10d2a6d94",
880 &migrate_client_to_add_indexes);
881
882 m.add("1509fd75019aebef5ac3da3a5edf1312393b70e9",
883 &migrate_client_to_external_privkeys);
884
885 // IMPORTANT: whenever you modify this to add a new schema version, you must
886 // also add a new migration test for the new schema version. See
887 // tests/t_migrate_schema.at for details.
888
889 m.migrate(sql, "bd86f9a90b5d552f0be1fa9aee847ea0f317778b");
890}

Archive Download this file

Branches

Tags

Quick Links:     www.monotone.ca    -     Downloads    -     Documentation    -     Wiki    -     Code Forge    -     Build Status