meta_table.cc 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. // Copyright (c) 2012 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "sql/meta_table.h"
  5. #include <cstdint>
  6. #include <string>
  7. #include "base/check_op.h"
  8. #include "base/strings/string_piece.h"
  9. #include "sql/database.h"
  10. #include "sql/statement.h"
  11. #include "sql/statement_id.h"
  12. #include "sql/transaction.h"
  13. namespace sql {
  14. namespace {
  15. // Keys understood directly by sql:MetaTable.
  16. constexpr char kVersionKey[] = "version";
  17. constexpr char kCompatibleVersionKey[] = "last_compatible_version";
  18. constexpr char kMmapStatusKey[] = "mmap_status";
  19. void PrepareSetStatement(base::StringPiece key,
  20. Database& db,
  21. Statement& insert_statement) {
  22. insert_statement.Assign(db.GetCachedStatement(
  23. SQL_FROM_HERE, "INSERT OR REPLACE INTO meta(key,value) VALUES(?,?)"));
  24. insert_statement.BindString(0, key);
  25. }
  26. bool PrepareGetStatement(base::StringPiece key,
  27. Database& db,
  28. Statement& select_statement) {
  29. select_statement.Assign(db.GetCachedStatement(
  30. SQL_FROM_HERE, "SELECT value FROM meta WHERE key=?"));
  31. if (!select_statement.is_valid())
  32. return false;
  33. select_statement.BindString(0, key);
  34. return select_statement.Step();
  35. }
  36. } // namespace
  37. MetaTable::MetaTable() = default;
  38. MetaTable::~MetaTable() = default;
  39. // static
  40. constexpr int64_t MetaTable::kMmapFailure;
  41. constexpr int64_t MetaTable::kMmapSuccess;
  42. // static
  43. bool MetaTable::DoesTableExist(sql::Database* db) {
  44. DCHECK(db);
  45. return db->DoesTableExist("meta");
  46. }
  47. // static
  48. bool MetaTable::DeleteTableForTesting(sql::Database* db) {
  49. DCHECK(db);
  50. return db->Execute("DROP TABLE IF EXISTS meta");
  51. }
  52. // static
  53. bool MetaTable::GetMmapStatus(Database* db, int64_t* status) {
  54. DCHECK(db);
  55. DCHECK(status);
  56. // It is fine for the status to be missing entirely, but any error prevents
  57. // memory-mapping.
  58. Statement select;
  59. if (!PrepareGetStatement(kMmapStatusKey, *db, select)) {
  60. *status = 0;
  61. return true;
  62. }
  63. *status = select.ColumnInt64(0);
  64. return select.Succeeded();
  65. }
  66. // static
  67. bool MetaTable::SetMmapStatus(Database* db, int64_t status) {
  68. DCHECK(db);
  69. DCHECK(status == kMmapFailure || status == kMmapSuccess || status >= 0);
  70. Statement insert;
  71. PrepareSetStatement(kMmapStatusKey, *db, insert);
  72. insert.BindInt64(1, status);
  73. return insert.Run();
  74. }
  75. // static
  76. void MetaTable::RazeIfIncompatible(Database* db,
  77. int lowest_supported_version,
  78. int current_version) {
  79. DCHECK(db);
  80. if (!DoesTableExist(db))
  81. return;
  82. sql::Statement select;
  83. if (!PrepareGetStatement(kVersionKey, *db, select))
  84. return;
  85. int64_t on_disk_schema_version = select.ColumnInt64(0);
  86. if (!PrepareGetStatement(kCompatibleVersionKey, *db, select))
  87. return;
  88. int64_t on_disk_compatible_version = select.ColumnInt(0);
  89. select.Clear(); // Clear potential automatic transaction for Raze().
  90. if ((lowest_supported_version != kNoLowestSupportedVersion &&
  91. lowest_supported_version > on_disk_schema_version) ||
  92. (current_version < on_disk_compatible_version)) {
  93. db->Raze();
  94. return;
  95. }
  96. }
  97. bool MetaTable::Init(Database* db, int version, int compatible_version) {
  98. DCHECK(!db_ && db);
  99. db_ = db;
  100. // If values stored are nullptr or missing entirely, 0 will be reported.
  101. // Require new clients to start with a greater initial version.
  102. DCHECK_GT(version, 0);
  103. DCHECK_GT(compatible_version, 0);
  104. // Make sure the table is created an populated atomically.
  105. sql::Transaction transaction(db_);
  106. if (!transaction.Begin())
  107. return false;
  108. if (!DoesTableExist(db)) {
  109. if (!db_->Execute("CREATE TABLE meta"
  110. "(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, value "
  111. "LONGVARCHAR)")) {
  112. return false;
  113. }
  114. // Newly-created databases start out with mmap'ed I/O, but have no place to
  115. // store the setting. Set here so that later opens don't need to validate.
  116. SetMmapStatus(db_, kMmapSuccess);
  117. // Note: there is no index over the meta table. We currently only have a
  118. // couple of keys, so it doesn't matter. If we start storing more stuff in
  119. // there, we should create an index.
  120. SetVersionNumber(version);
  121. SetCompatibleVersionNumber(compatible_version);
  122. }
  123. return transaction.Commit();
  124. }
  125. void MetaTable::Reset() {
  126. db_ = nullptr;
  127. }
  128. void MetaTable::SetVersionNumber(int version) {
  129. DCHECK_GT(version, 0);
  130. SetValue(kVersionKey, version);
  131. }
  132. int MetaTable::GetVersionNumber() {
  133. int64_t version = 0;
  134. return GetValue(kVersionKey, &version) ? version : 0;
  135. }
  136. void MetaTable::SetCompatibleVersionNumber(int version) {
  137. DCHECK_GT(version, 0);
  138. SetValue(kCompatibleVersionKey, version);
  139. }
  140. int MetaTable::GetCompatibleVersionNumber() {
  141. int version = 0;
  142. return GetValue(kCompatibleVersionKey, &version) ? version : 0;
  143. }
  144. bool MetaTable::SetValue(base::StringPiece key, const std::string& value) {
  145. DCHECK(db_);
  146. Statement insert;
  147. PrepareSetStatement(key, *db_, insert);
  148. insert.BindString(1, value);
  149. return insert.Run();
  150. }
  151. bool MetaTable::SetValue(base::StringPiece key, int64_t value) {
  152. DCHECK(db_);
  153. Statement insert;
  154. PrepareSetStatement(key, *db_, insert);
  155. insert.BindInt64(1, value);
  156. return insert.Run();
  157. }
  158. bool MetaTable::GetValue(base::StringPiece key, std::string* value) {
  159. DCHECK(value);
  160. DCHECK(db_);
  161. Statement select;
  162. if (!PrepareGetStatement(key, *db_, select))
  163. return false;
  164. *value = select.ColumnString(0);
  165. return true;
  166. }
  167. bool MetaTable::GetValue(base::StringPiece key, int* value) {
  168. DCHECK(value);
  169. DCHECK(db_);
  170. Statement select;
  171. if (!PrepareGetStatement(key, *db_, select))
  172. return false;
  173. *value = select.ColumnInt64(0);
  174. return true;
  175. }
  176. bool MetaTable::GetValue(base::StringPiece key, int64_t* value) {
  177. DCHECK(value);
  178. DCHECK(db_);
  179. Statement select;
  180. if (!PrepareGetStatement(key, *db_, select))
  181. return false;
  182. *value = select.ColumnInt64(0);
  183. return true;
  184. }
  185. bool MetaTable::DeleteKey(base::StringPiece key) {
  186. DCHECK(db_);
  187. Statement delete_statement(
  188. db_->GetUniqueStatement("DELETE FROM meta WHERE key=?"));
  189. delete_statement.BindString(0, key);
  190. return delete_statement.Run();
  191. }
  192. } // namespace sql