1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "sql/meta_table.h"
10 #include "base/check_op.h"
11 #include "base/strings/string_piece.h"
12 #include "sql/database.h"
13 #include "sql/statement.h"
14 #include "sql/statement_id.h"
15 #include "sql/transaction.h"
21 // Keys understood directly by sql:MetaTable.
22 constexpr char kVersionKey[] = "version";
23 constexpr char kCompatibleVersionKey[] = "last_compatible_version";
24 constexpr char kMmapStatusKey[] = "mmap_status";
26 void PrepareSetStatement(base::StringPiece key,
28 Statement& insert_statement) {
29 insert_statement.Assign(db.GetCachedStatement(
30 SQL_FROM_HERE, "INSERT OR REPLACE INTO meta(key,value) VALUES(?,?)"));
31 insert_statement.BindString(0, key);
34 bool PrepareGetStatement(base::StringPiece key,
36 Statement& select_statement) {
37 select_statement.Assign(db.GetCachedStatement(
38 SQL_FROM_HERE, "SELECT value FROM meta WHERE key=?"));
39 if (!select_statement.is_valid())
42 select_statement.BindString(0, key);
43 return select_statement.Step();
48 MetaTable::MetaTable() = default;
50 MetaTable::~MetaTable() = default;
53 constexpr int64_t MetaTable::kMmapFailure;
54 constexpr int64_t MetaTable::kMmapSuccess;
57 bool MetaTable::DoesTableExist(sql::Database* db) {
59 return db->DoesTableExist("meta");
63 bool MetaTable::DeleteTableForTesting(sql::Database* db) {
65 return db->Execute("DROP TABLE IF EXISTS meta");
69 bool MetaTable::GetMmapStatus(Database* db, int64_t* status) {
73 // It is fine for the status to be missing entirely, but any error prevents
76 if (!PrepareGetStatement(kMmapStatusKey, *db, select)) {
81 *status = select.ColumnInt64(0);
82 return select.Succeeded();
86 bool MetaTable::SetMmapStatus(Database* db, int64_t status) {
88 DCHECK(status == kMmapFailure || status == kMmapSuccess || status >= 0);
91 PrepareSetStatement(kMmapStatusKey, *db, insert);
92 insert.BindInt64(1, status);
97 void MetaTable::RazeIfIncompatible(Database* db,
98 int lowest_supported_version,
99 int current_version) {
102 if (!DoesTableExist(db))
105 sql::Statement select;
106 if (!PrepareGetStatement(kVersionKey, *db, select))
108 int64_t on_disk_schema_version = select.ColumnInt64(0);
110 if (!PrepareGetStatement(kCompatibleVersionKey, *db, select))
112 int64_t on_disk_compatible_version = select.ColumnInt(0);
114 select.Clear(); // Clear potential automatic transaction for Raze().
116 if ((lowest_supported_version != kNoLowestSupportedVersion &&
117 lowest_supported_version > on_disk_schema_version) ||
118 (current_version < on_disk_compatible_version)) {
124 bool MetaTable::Init(Database* db, int version, int compatible_version) {
128 // If values stored are nullptr or missing entirely, 0 will be reported.
129 // Require new clients to start with a greater initial version.
130 DCHECK_GT(version, 0);
131 DCHECK_GT(compatible_version, 0);
133 // Make sure the table is created an populated atomically.
134 sql::Transaction transaction(db_);
135 if (!transaction.Begin())
138 if (!DoesTableExist(db)) {
139 if (!db_->Execute("CREATE TABLE meta"
140 "(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, value "
145 // Newly-created databases start out with mmap'ed I/O, but have no place to
146 // store the setting. Set here so that later opens don't need to validate.
147 SetMmapStatus(db_, kMmapSuccess);
149 // Note: there is no index over the meta table. We currently only have a
150 // couple of keys, so it doesn't matter. If we start storing more stuff in
151 // there, we should create an index.
152 SetVersionNumber(version);
153 SetCompatibleVersionNumber(compatible_version);
155 return transaction.Commit();
158 void MetaTable::Reset() {
162 void MetaTable::SetVersionNumber(int version) {
163 DCHECK_GT(version, 0);
164 SetValue(kVersionKey, version);
167 int MetaTable::GetVersionNumber() {
169 return GetValue(kVersionKey, &version) ? version : 0;
172 void MetaTable::SetCompatibleVersionNumber(int version) {
173 DCHECK_GT(version, 0);
174 SetValue(kCompatibleVersionKey, version);
177 int MetaTable::GetCompatibleVersionNumber() {
179 return GetValue(kCompatibleVersionKey, &version) ? version : 0;
182 bool MetaTable::SetValue(base::StringPiece key, const std::string& value) {
186 PrepareSetStatement(key, *db_, insert);
187 insert.BindString(1, value);
191 bool MetaTable::SetValue(base::StringPiece key, int64_t value) {
195 PrepareSetStatement(key, *db_, insert);
196 insert.BindInt64(1, value);
200 bool MetaTable::GetValue(base::StringPiece key, std::string* value) {
205 if (!PrepareGetStatement(key, *db_, select))
208 *value = select.ColumnString(0);
212 bool MetaTable::GetValue(base::StringPiece key, int* value) {
217 if (!PrepareGetStatement(key, *db_, select))
220 *value = select.ColumnInt64(0);
224 bool MetaTable::GetValue(base::StringPiece key, int64_t* value) {
229 if (!PrepareGetStatement(key, *db_, select))
232 *value = select.ColumnInt64(0);
236 bool MetaTable::DeleteKey(base::StringPiece key) {
239 Statement delete_statement(
240 db_->GetUniqueStatement("DELETE FROM meta WHERE key=?"));
241 delete_statement.BindString(0, key);
242 return delete_statement.Run();