| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/sync/syncable/directory_backing_store.h" | 5 #include "chrome/browser/sync/syncable/directory_backing_store.h" |
| 6 | 6 |
| 7 #include "build/build_config.h" | 7 #include "build/build_config.h" |
| 8 | 8 |
| 9 #if defined(OS_MACOSX) | 9 #if defined(OS_MACOSX) |
| 10 #include <CoreFoundation/CoreFoundation.h> | 10 #include <CoreFoundation/CoreFoundation.h> |
| (...skipping 22 matching lines...) Expand all Loading... |
| 33 using std::string; | 33 using std::string; |
| 34 | 34 |
| 35 namespace syncable { | 35 namespace syncable { |
| 36 | 36 |
| 37 // This just has to be big enough to hold an UPDATE or INSERT statement that | 37 // This just has to be big enough to hold an UPDATE or INSERT statement that |
| 38 // modifies all the columns in the entry table. | 38 // modifies all the columns in the entry table. |
| 39 static const string::size_type kUpdateStatementBufferSize = 2048; | 39 static const string::size_type kUpdateStatementBufferSize = 2048; |
| 40 | 40 |
| 41 // Increment this version whenever updating DB tables. | 41 // Increment this version whenever updating DB tables. |
| 42 extern const int32 kCurrentDBVersion; // Global visibility for our unittest. | 42 extern const int32 kCurrentDBVersion; // Global visibility for our unittest. |
| 43 const int32 kCurrentDBVersion = 71; | 43 const int32 kCurrentDBVersion = 72; |
| 44 | 44 |
| 45 namespace { | 45 namespace { |
| 46 | 46 |
| 47 int ExecQuery(sqlite3* dbhandle, const char* query) { | 47 int ExecQuery(sqlite3* dbhandle, const char* query) { |
| 48 SQLStatement statement; | 48 SQLStatement statement; |
| 49 int result = statement.prepare(dbhandle, query); | 49 int result = statement.prepare(dbhandle, query); |
| 50 if (SQLITE_OK != result) | 50 if (SQLITE_OK != result) |
| 51 return result; | 51 return result; |
| 52 do { | 52 do { |
| 53 result = statement.step(); | 53 result = statement.step(); |
| (...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 208 SetFileAttributes(backing_filepath_.value().c_str(), | 208 SetFileAttributes(backing_filepath_.value().c_str(), |
| 209 attrs | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED); | 209 attrs | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED); |
| 210 #endif | 210 #endif |
| 211 | 211 |
| 212 return true; | 212 return true; |
| 213 } | 213 } |
| 214 return false; | 214 return false; |
| 215 } | 215 } |
| 216 | 216 |
| 217 DirOpenResult DirectoryBackingStore::Load(MetahandlesIndex* entry_bucket, | 217 DirOpenResult DirectoryBackingStore::Load(MetahandlesIndex* entry_bucket, |
| 218 ExtendedAttributes* xattrs_bucket, | |
| 219 Directory::KernelLoadInfo* kernel_load_info) { | 218 Directory::KernelLoadInfo* kernel_load_info) { |
| 220 if (!BeginLoad()) | 219 if (!BeginLoad()) |
| 221 return FAILED_OPEN_DATABASE; | 220 return FAILED_OPEN_DATABASE; |
| 222 | 221 |
| 223 DirOpenResult result = InitializeTables(); | 222 DirOpenResult result = InitializeTables(); |
| 224 if (OPENED != result) | 223 if (OPENED != result) |
| 225 return result; | 224 return result; |
| 226 | 225 |
| 227 if (!DropDeletedEntries() || | 226 if (!DropDeletedEntries() || |
| 228 !LoadEntries(entry_bucket) || | 227 !LoadEntries(entry_bucket) || |
| 229 !LoadExtendedAttributes(xattrs_bucket) || | |
| 230 !LoadInfo(kernel_load_info)) { | 228 !LoadInfo(kernel_load_info)) { |
| 231 return FAILED_DATABASE_CORRUPT; | 229 return FAILED_DATABASE_CORRUPT; |
| 232 } | 230 } |
| 233 | 231 |
| 234 EndLoad(); | 232 EndLoad(); |
| 235 return OPENED; | 233 return OPENED; |
| 236 } | 234 } |
| 237 | 235 |
| 238 bool DirectoryBackingStore::BeginLoad() { | 236 bool DirectoryBackingStore::BeginLoad() { |
| 239 DCHECK(load_dbhandle_ == NULL); | 237 DCHECK(load_dbhandle_ == NULL); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 254 | 252 |
| 255 bool DirectoryBackingStore::SaveChanges( | 253 bool DirectoryBackingStore::SaveChanges( |
| 256 const Directory::SaveChangesSnapshot& snapshot) { | 254 const Directory::SaveChangesSnapshot& snapshot) { |
| 257 sqlite3* dbhandle = LazyGetSaveHandle(); | 255 sqlite3* dbhandle = LazyGetSaveHandle(); |
| 258 | 256 |
| 259 // SQLTransaction::BeginExclusive causes a disk write to occur. This is not | 257 // SQLTransaction::BeginExclusive causes a disk write to occur. This is not |
| 260 // something that should happen every 10 seconds when this function runs, so | 258 // something that should happen every 10 seconds when this function runs, so |
| 261 // just stop here if there's nothing to save. | 259 // just stop here if there's nothing to save. |
| 262 bool save_info = | 260 bool save_info = |
| 263 (Directory::KERNEL_SHARE_INFO_DIRTY == snapshot.kernel_info_status); | 261 (Directory::KERNEL_SHARE_INFO_DIRTY == snapshot.kernel_info_status); |
| 264 if (snapshot.dirty_metas.size() < 1 && snapshot.dirty_xattrs.size() < 1 && | 262 if (snapshot.dirty_metas.size() < 1 && !save_info) |
| 265 !save_info) | |
| 266 return true; | 263 return true; |
| 267 | 264 |
| 268 SQLTransaction transaction(dbhandle); | 265 SQLTransaction transaction(dbhandle); |
| 269 if (SQLITE_OK != transaction.BeginExclusive()) | 266 if (SQLITE_OK != transaction.BeginExclusive()) |
| 270 return false; | 267 return false; |
| 271 | 268 |
| 272 for (OriginalEntries::const_iterator i = snapshot.dirty_metas.begin(); | 269 for (OriginalEntries::const_iterator i = snapshot.dirty_metas.begin(); |
| 273 i != snapshot.dirty_metas.end(); ++i) { | 270 i != snapshot.dirty_metas.end(); ++i) { |
| 274 DCHECK(i->is_dirty()); | 271 DCHECK(i->is_dirty()); |
| 275 if (!SaveEntryToDB(*i)) | 272 if (!SaveEntryToDB(*i)) |
| 276 return false; | 273 return false; |
| 277 } | 274 } |
| 278 | 275 |
| 279 for (ExtendedAttributes::const_iterator i = snapshot.dirty_xattrs.begin(); | |
| 280 i != snapshot.dirty_xattrs.end(); ++i) { | |
| 281 DCHECK(i->second.dirty); | |
| 282 if (i->second.is_deleted) { | |
| 283 if (!DeleteExtendedAttributeFromDB(i)) | |
| 284 return false; | |
| 285 } else { | |
| 286 if (!SaveExtendedAttributeToDB(i)) | |
| 287 return false; | |
| 288 } | |
| 289 } | |
| 290 | |
| 291 if (save_info) { | 276 if (save_info) { |
| 292 const Directory::PersistedKernelInfo& info = snapshot.kernel_info; | 277 const Directory::PersistedKernelInfo& info = snapshot.kernel_info; |
| 293 SQLStatement update; | 278 SQLStatement update; |
| 294 update.prepare(dbhandle, "UPDATE share_info " | 279 update.prepare(dbhandle, "UPDATE share_info " |
| 295 "SET store_birthday = ?, " | 280 "SET store_birthday = ?, " |
| 296 "next_id = ?"); | 281 "next_id = ?"); |
| 297 update.bind_string(0, info.store_birthday); | 282 update.bind_string(0, info.store_birthday); |
| 298 update.bind_int64(1, info.next_id); | 283 update.bind_int64(1, info.next_id); |
| 299 | 284 |
| 300 if (!(SQLITE_DONE == update.step() && | 285 if (!(SQLITE_DONE == update.step() && |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 348 if (MigrateVersion69To70()) | 333 if (MigrateVersion69To70()) |
| 349 version_on_disk = 70; | 334 version_on_disk = 70; |
| 350 } | 335 } |
| 351 | 336 |
| 352 // Version 71 changed the sync progress information to be per-datatype. | 337 // Version 71 changed the sync progress information to be per-datatype. |
| 353 if (version_on_disk == 70) { | 338 if (version_on_disk == 70) { |
| 354 if (MigrateVersion70To71()) | 339 if (MigrateVersion70To71()) |
| 355 version_on_disk = 71; | 340 version_on_disk = 71; |
| 356 } | 341 } |
| 357 | 342 |
| 343 // Version 72 removed extended attributes, a legacy way to do extensible |
| 344 // key/value information, stored in their own table. |
| 345 if (version_on_disk == 71) { |
| 346 if (MigrateVersion71To72()) |
| 347 version_on_disk = 72; |
| 348 } |
| 349 |
| 358 // If one of the migrations requested it, drop columns that aren't current. | 350 // If one of the migrations requested it, drop columns that aren't current. |
| 359 // It's only safe to do this after migrating all the way to the current | 351 // It's only safe to do this after migrating all the way to the current |
| 360 // version. | 352 // version. |
| 361 if (version_on_disk == kCurrentDBVersion && needs_column_refresh_) { | 353 if (version_on_disk == kCurrentDBVersion && needs_column_refresh_) { |
| 362 if (!RefreshColumns()) | 354 if (!RefreshColumns()) |
| 363 version_on_disk = 0; | 355 version_on_disk = 0; |
| 364 } | 356 } |
| 365 | 357 |
| 366 // A final, alternative catch-all migration to simply re-sync everything. | 358 // A final, alternative catch-all migration to simply re-sync everything. |
| 367 if (version_on_disk != kCurrentDBVersion) { | 359 if (version_on_disk != kCurrentDBVersion) { |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 443 base::hash_set<int64> handles; | 435 base::hash_set<int64> handles; |
| 444 EntryKernel* kernel = NULL; | 436 EntryKernel* kernel = NULL; |
| 445 int query_result; | 437 int query_result; |
| 446 while (SQLITE_ROW == (query_result = UnpackEntry(&statement, &kernel))) { | 438 while (SQLITE_ROW == (query_result = UnpackEntry(&statement, &kernel))) { |
| 447 DCHECK(handles.insert(kernel->ref(META_HANDLE)).second); // Only in debug. | 439 DCHECK(handles.insert(kernel->ref(META_HANDLE)).second); // Only in debug. |
| 448 entry_bucket->insert(kernel); | 440 entry_bucket->insert(kernel); |
| 449 } | 441 } |
| 450 return SQLITE_DONE == query_result; | 442 return SQLITE_DONE == query_result; |
| 451 } | 443 } |
| 452 | 444 |
| 453 bool DirectoryBackingStore::LoadExtendedAttributes( | |
| 454 ExtendedAttributes* xattrs_bucket) { | |
| 455 SQLStatement statement; | |
| 456 statement.prepare( | |
| 457 load_dbhandle_, | |
| 458 "SELECT metahandle, key, value FROM extended_attributes"); | |
| 459 int step_result = statement.step(); | |
| 460 while (SQLITE_ROW == step_result) { | |
| 461 int64 metahandle = statement.column_int64(0); | |
| 462 | |
| 463 string path_string_key; | |
| 464 statement.column_string(1, &path_string_key); | |
| 465 | |
| 466 ExtendedAttributeValue val; | |
| 467 statement.column_blob_as_vector(2, &(val.value)); | |
| 468 val.is_deleted = false; | |
| 469 | |
| 470 ExtendedAttributeKey key(metahandle, path_string_key); | |
| 471 xattrs_bucket->insert(std::make_pair(key, val)); | |
| 472 step_result = statement.step(); | |
| 473 } | |
| 474 | |
| 475 return SQLITE_DONE == step_result; | |
| 476 } | |
| 477 | |
| 478 bool DirectoryBackingStore::LoadInfo(Directory::KernelLoadInfo* info) { | 445 bool DirectoryBackingStore::LoadInfo(Directory::KernelLoadInfo* info) { |
| 479 { | 446 { |
| 480 SQLStatement query; | 447 SQLStatement query; |
| 481 query.prepare(load_dbhandle_, | 448 query.prepare(load_dbhandle_, |
| 482 "SELECT store_birthday, next_id, cache_guid " | 449 "SELECT store_birthday, next_id, cache_guid " |
| 483 "FROM share_info"); | 450 "FROM share_info"); |
| 484 if (SQLITE_ROW != query.step()) | 451 if (SQLITE_ROW != query.step()) |
| 485 return false; | 452 return false; |
| 486 info->kernel_info.store_birthday = query.column_string(0); | 453 info->kernel_info.store_birthday = query.column_string(0); |
| 487 info->kernel_info.next_id = query.column_int64(1); | 454 info->kernel_info.next_id = query.column_int64(1); |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 535 values.append(" )"); | 502 values.append(" )"); |
| 536 query.append(values); | 503 query.append(values); |
| 537 SQLStatement statement; | 504 SQLStatement statement; |
| 538 statement.prepare(save_dbhandle_, query.c_str()); | 505 statement.prepare(save_dbhandle_, query.c_str()); |
| 539 BindFields(entry, &statement); | 506 BindFields(entry, &statement); |
| 540 return (SQLITE_DONE == statement.step() && | 507 return (SQLITE_DONE == statement.step() && |
| 541 SQLITE_OK == statement.reset() && | 508 SQLITE_OK == statement.reset() && |
| 542 1 == statement.changes()); | 509 1 == statement.changes()); |
| 543 } | 510 } |
| 544 | 511 |
| 545 bool DirectoryBackingStore::SaveExtendedAttributeToDB( | |
| 546 ExtendedAttributes::const_iterator i) { | |
| 547 DCHECK(save_dbhandle_); | |
| 548 SQLStatement insert; | |
| 549 insert.prepare(save_dbhandle_, | |
| 550 "INSERT INTO extended_attributes " | |
| 551 "(metahandle, key, value) " | |
| 552 "values ( ?, ?, ? )"); | |
| 553 insert.bind_int64(0, i->first.metahandle); | |
| 554 insert.bind_string(1, i->first.key); | |
| 555 insert.bind_blob(2, &i->second.value.at(0), i->second.value.size()); | |
| 556 return (SQLITE_DONE == insert.step() && | |
| 557 SQLITE_OK == insert.reset() && | |
| 558 1 == insert.changes()); | |
| 559 } | |
| 560 | |
| 561 bool DirectoryBackingStore::DeleteExtendedAttributeFromDB( | |
| 562 ExtendedAttributes::const_iterator i) { | |
| 563 DCHECK(save_dbhandle_); | |
| 564 SQLStatement delete_attribute; | |
| 565 delete_attribute.prepare(save_dbhandle_, | |
| 566 "DELETE FROM extended_attributes " | |
| 567 "WHERE metahandle = ? AND key = ? "); | |
| 568 delete_attribute.bind_int64(0, i->first.metahandle); | |
| 569 delete_attribute.bind_string(1, i->first.key); | |
| 570 if (!(SQLITE_DONE == delete_attribute.step() && | |
| 571 SQLITE_OK == delete_attribute.reset() && | |
| 572 1 == delete_attribute.changes())) { | |
| 573 LOG(ERROR) << "DeleteExtendedAttributeFromDB(),StepDone() failed " | |
| 574 << "for metahandle: " << i->first.metahandle << " key: " | |
| 575 << i->first.key; | |
| 576 return false; | |
| 577 } | |
| 578 // The attribute may have never been saved to the database if it was | |
| 579 // created and then immediately deleted. So don't check that we | |
| 580 // deleted exactly 1 row. | |
| 581 return true; | |
| 582 } | |
| 583 | |
| 584 bool DirectoryBackingStore::DropDeletedEntries() { | 512 bool DirectoryBackingStore::DropDeletedEntries() { |
| 585 static const char delete_extended_attributes[] = | |
| 586 "DELETE FROM extended_attributes WHERE metahandle IN " | |
| 587 "(SELECT metahandle from death_row)"; | |
| 588 static const char delete_metas[] = "DELETE FROM metas WHERE metahandle IN " | 513 static const char delete_metas[] = "DELETE FROM metas WHERE metahandle IN " |
| 589 "(SELECT metahandle from death_row)"; | 514 "(SELECT metahandle from death_row)"; |
| 590 // Put all statements into a transaction for better performance | 515 // Put all statements into a transaction for better performance |
| 591 SQLTransaction transaction(load_dbhandle_); | 516 SQLTransaction transaction(load_dbhandle_); |
| 592 transaction.Begin(); | 517 transaction.Begin(); |
| 593 if (SQLITE_DONE != ExecQuery( | 518 if (SQLITE_DONE != ExecQuery( |
| 594 load_dbhandle_, | 519 load_dbhandle_, |
| 595 "CREATE TEMP TABLE death_row (metahandle BIGINT)")) { | 520 "CREATE TEMP TABLE death_row (metahandle BIGINT)")) { |
| 596 return false; | 521 return false; |
| 597 } | 522 } |
| 598 if (SQLITE_DONE != ExecQuery(load_dbhandle_, | 523 if (SQLITE_DONE != ExecQuery(load_dbhandle_, |
| 599 "INSERT INTO death_row " | 524 "INSERT INTO death_row " |
| 600 "SELECT metahandle from metas WHERE is_del > 0 " | 525 "SELECT metahandle from metas WHERE is_del > 0 " |
| 601 " AND is_unsynced < 1" | 526 " AND is_unsynced < 1" |
| 602 " AND is_unapplied_update < 1")) { | 527 " AND is_unapplied_update < 1")) { |
| 603 return false; | 528 return false; |
| 604 } | 529 } |
| 605 if (SQLITE_DONE != ExecQuery(load_dbhandle_, delete_extended_attributes)) { | |
| 606 return false; | |
| 607 } | |
| 608 if (SQLITE_DONE != ExecQuery(load_dbhandle_, delete_metas)) { | 530 if (SQLITE_DONE != ExecQuery(load_dbhandle_, delete_metas)) { |
| 609 return false; | 531 return false; |
| 610 } | 532 } |
| 611 if (SQLITE_DONE != ExecQuery(load_dbhandle_, "DROP TABLE death_row")) { | 533 if (SQLITE_DONE != ExecQuery(load_dbhandle_, "DROP TABLE death_row")) { |
| 612 return false; | 534 return false; |
| 613 } | 535 } |
| 614 transaction.Commit(); | 536 transaction.Commit(); |
| 615 return true; | 537 return true; |
| 616 } | 538 } |
| 617 | 539 |
| 618 int DirectoryBackingStore::SafeDropTable(const char* table_name) { | 540 int DirectoryBackingStore::SafeDropTable(const char* table_name) { |
| 619 string query = "DROP TABLE IF EXISTS "; | 541 string query = "DROP TABLE IF EXISTS "; |
| 620 query.append(table_name); | 542 query.append(table_name); |
| 621 SQLStatement statement; | 543 SQLStatement statement; |
| 622 int result = statement.prepare(load_dbhandle_, query.data(), | 544 int result = statement.prepare(load_dbhandle_, query.data(), |
| 623 query.size()); | 545 query.size()); |
| 624 if (SQLITE_OK == result) { | 546 if (SQLITE_OK == result) { |
| 625 result = statement.step(); | 547 result = statement.step(); |
| 626 if (SQLITE_DONE == result) | 548 if (SQLITE_DONE == result) |
| 627 statement.finalize(); | 549 statement.finalize(); |
| 628 } | 550 } |
| 629 | 551 |
| 630 return result; | 552 return result; |
| 631 } | 553 } |
| 632 | 554 |
| 633 int DirectoryBackingStore::CreateExtendedAttributeTable() { | |
| 634 int result = SafeDropTable("extended_attributes"); | |
| 635 if (result != SQLITE_DONE) | |
| 636 return result; | |
| 637 LOG(INFO) << "CreateExtendedAttributeTable"; | |
| 638 return ExecQuery(load_dbhandle_, | |
| 639 "CREATE TABLE extended_attributes(" | |
| 640 "metahandle bigint, " | |
| 641 "key varchar(127), " | |
| 642 "value blob, " | |
| 643 "PRIMARY KEY(metahandle, key) ON CONFLICT REPLACE)"); | |
| 644 } | |
| 645 | |
| 646 void DirectoryBackingStore::DropAllTables() { | 555 void DirectoryBackingStore::DropAllTables() { |
| 647 SafeDropTable("metas"); | 556 SafeDropTable("metas"); |
| 648 SafeDropTable("temp_metas"); | 557 SafeDropTable("temp_metas"); |
| 649 SafeDropTable("share_info"); | 558 SafeDropTable("share_info"); |
| 650 SafeDropTable("temp_share_info"); | 559 SafeDropTable("temp_share_info"); |
| 651 SafeDropTable("share_version"); | 560 SafeDropTable("share_version"); |
| 652 SafeDropTable("extended_attributes"); | 561 SafeDropTable("extended_attributes"); |
| 653 SafeDropTable("models"); | 562 SafeDropTable("models"); |
| 654 needs_column_refresh_ = false; | 563 needs_column_refresh_ = false; |
| 655 } | 564 } |
| (...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 882 return false; | 791 return false; |
| 883 SafeDropTable("share_info"); | 792 SafeDropTable("share_info"); |
| 884 result = ExecQuery(load_dbhandle_, | 793 result = ExecQuery(load_dbhandle_, |
| 885 "ALTER TABLE temp_share_info RENAME TO share_info"); | 794 "ALTER TABLE temp_share_info RENAME TO share_info"); |
| 886 if (result != SQLITE_DONE) | 795 if (result != SQLITE_DONE) |
| 887 return false; | 796 return false; |
| 888 SetVersion(71); | 797 SetVersion(71); |
| 889 return true; | 798 return true; |
| 890 } | 799 } |
| 891 | 800 |
| 801 bool DirectoryBackingStore::MigrateVersion71To72() { |
| 802 SafeDropTable("extended_attributes"); |
| 803 SetVersion(72); |
| 804 return true; |
| 805 } |
| 806 |
| 892 int DirectoryBackingStore::CreateTables() { | 807 int DirectoryBackingStore::CreateTables() { |
| 893 LOG(INFO) << "First run, creating tables"; | 808 LOG(INFO) << "First run, creating tables"; |
| 894 // Create two little tables share_version and share_info | 809 // Create two little tables share_version and share_info |
| 895 int result = ExecQuery(load_dbhandle_, | 810 int result = ExecQuery(load_dbhandle_, |
| 896 "CREATE TABLE share_version (" | 811 "CREATE TABLE share_version (" |
| 897 "id VARCHAR(128) primary key, data INT)"); | 812 "id VARCHAR(128) primary key, data INT)"); |
| 898 if (result != SQLITE_DONE) | 813 if (result != SQLITE_DONE) |
| 899 return result; | 814 return result; |
| 900 { | 815 { |
| 901 SQLStatement statement; | 816 SQLStatement statement; |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 943 const int64 now = Now(); | 858 const int64 now = Now(); |
| 944 SQLStatement statement; | 859 SQLStatement statement; |
| 945 statement.prepare(load_dbhandle_, | 860 statement.prepare(load_dbhandle_, |
| 946 "INSERT INTO metas " | 861 "INSERT INTO metas " |
| 947 "( id, metahandle, is_dir, ctime, mtime) " | 862 "( id, metahandle, is_dir, ctime, mtime) " |
| 948 "VALUES ( \"r\", 1, 1, ?, ?)"); | 863 "VALUES ( \"r\", 1, 1, ?, ?)"); |
| 949 statement.bind_int64(0, now); | 864 statement.bind_int64(0, now); |
| 950 statement.bind_int64(1, now); | 865 statement.bind_int64(1, now); |
| 951 result = statement.step(); | 866 result = statement.step(); |
| 952 } | 867 } |
| 953 if (result != SQLITE_DONE) | |
| 954 return result; | |
| 955 result = CreateExtendedAttributeTable(); | |
| 956 return result; | 868 return result; |
| 957 } | 869 } |
| 958 | 870 |
| 959 sqlite3* DirectoryBackingStore::LazyGetSaveHandle() { | 871 sqlite3* DirectoryBackingStore::LazyGetSaveHandle() { |
| 960 if (!save_dbhandle_ && !OpenAndConfigureHandleHelper(&save_dbhandle_)) { | 872 if (!save_dbhandle_ && !OpenAndConfigureHandleHelper(&save_dbhandle_)) { |
| 961 DCHECK(FALSE) << "Unable to open handle for saving"; | 873 DCHECK(FALSE) << "Unable to open handle for saving"; |
| 962 return NULL; | 874 return NULL; |
| 963 } | 875 } |
| 964 return save_dbhandle_; | 876 return save_dbhandle_; |
| 965 } | 877 } |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 998 "name TEXT, " | 910 "name TEXT, " |
| 999 "store_birthday TEXT, " | 911 "store_birthday TEXT, " |
| 1000 "db_create_version TEXT, " | 912 "db_create_version TEXT, " |
| 1001 "db_create_time INT, " | 913 "db_create_time INT, " |
| 1002 "next_id INT default -2, " | 914 "next_id INT default -2, " |
| 1003 "cache_guid TEXT)"); | 915 "cache_guid TEXT)"); |
| 1004 return ExecQuery(load_dbhandle_, query.c_str()); | 916 return ExecQuery(load_dbhandle_, query.c_str()); |
| 1005 } | 917 } |
| 1006 | 918 |
| 1007 } // namespace syncable | 919 } // namespace syncable |
| OLD | NEW |