Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(392)

Side by Side Diff: trunk/src/sql/recovery.cc

Issue 74953002: Revert 235595 "Revert 235492 "[sql] Recover Favicons v5 database..." (Closed) Base URL: svn://svn.chromium.org/chrome/
Patch Set: Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « trunk/src/sql/recovery.h ('k') | trunk/src/sql/recovery_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 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 "sql/recovery.h" 5 #include "sql/recovery.h"
6 6
7 #include "base/files/file_path.h" 7 #include "base/files/file_path.h"
8 #include "base/format_macros.h"
8 #include "base/logging.h" 9 #include "base/logging.h"
9 #include "base/metrics/sparse_histogram.h" 10 #include "base/metrics/sparse_histogram.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/stringprintf.h"
10 #include "sql/connection.h" 13 #include "sql/connection.h"
14 #include "sql/statement.h"
11 #include "third_party/sqlite/sqlite3.h" 15 #include "third_party/sqlite/sqlite3.h"
12 16
13 namespace sql { 17 namespace sql {
14 18
15 // static 19 // static
16 bool Recovery::FullRecoverySupported() { 20 bool Recovery::FullRecoverySupported() {
17 // TODO(shess): See comment in Init(). 21 // TODO(shess): See comment in Init().
18 #if defined(USE_SYSTEM_SQLITE) 22 #if defined(USE_SYSTEM_SQLITE)
19 return false; 23 return false;
20 #else 24 #else
(...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after
226 230
227 recover_db_.Close(); 231 recover_db_.Close();
228 if (raze == RAZE_AND_POISON) { 232 if (raze == RAZE_AND_POISON) {
229 db_->RazeAndClose(); 233 db_->RazeAndClose();
230 } else if (raze == POISON) { 234 } else if (raze == POISON) {
231 db_->Poison(); 235 db_->Poison();
232 } 236 }
233 db_ = NULL; 237 db_ = NULL;
234 } 238 }
235 239
240 bool Recovery::AutoRecoverTable(const char* table_name,
241 size_t extend_columns,
242 size_t* rows_recovered) {
243 // Query the info for the recovered table in database [main].
244 std::string query(
245 base::StringPrintf("PRAGMA main.table_info(%s)", table_name));
246 Statement s(db()->GetUniqueStatement(query.c_str()));
247
248 // The columns of the recover virtual table.
249 std::vector<std::string> create_column_decls;
250
251 // The columns to select from the recover virtual table when copying
252 // to the recovered table.
253 std::vector<std::string> insert_columns;
254
255 // If PRIMARY KEY is a single INTEGER column, then it is an alias
256 // for ROWID. The primary key can be compound, so this can only be
257 // determined after processing all column data and tracking what is
258 // seen. |pk_column_count| counts the columns in the primary key.
259 // |rowid_decl| stores the ROWID version of the last INTEGER column
260 // seen, which is at |rowid_ofs| in |create_column_decls|.
261 size_t pk_column_count = 0;
262 size_t rowid_ofs; // Only valid if rowid_decl is set.
263 std::string rowid_decl; // ROWID version of column |rowid_ofs|.
264
265 while (s.Step()) {
266 const std::string column_name(s.ColumnString(1));
267 const std::string column_type(s.ColumnString(2));
268 const bool not_null = s.ColumnBool(3);
269 const int default_type = s.ColumnType(4);
270 const bool default_is_null = (default_type == COLUMN_TYPE_NULL);
271 const int pk_column = s.ColumnInt(5);
272
273 if (pk_column > 0) {
274 // TODO(shess): http://www.sqlite.org/pragma.html#pragma_table_info
275 // documents column 5 as the index of the column in the primary key
276 // (zero for not in primary key). I find that it is always 1 for
277 // columns in the primary key. Since this code is very dependent on
278 // that pragma, review if the implementation changes.
279 DCHECK_EQ(pk_column, 1);
280 ++pk_column_count;
281 }
282
283 // Construct column declaration as "name type [optional constraint]".
284 std::string column_decl = column_name;
285
286 // SQLite's affinity detection is documented at:
287 // http://www.sqlite.org/datatype3.html#affname
288 // The gist of it is that CHAR, TEXT, and INT use substring matches.
289 if (column_type.find("INT") != std::string::npos) {
290 if (pk_column == 1) {
291 rowid_ofs = create_column_decls.size();
292 rowid_decl = column_name + " ROWID";
293 }
294 column_decl += " INTEGER";
295 } else if (column_type.find("CHAR") != std::string::npos ||
296 column_type.find("TEXT") != std::string::npos) {
297 column_decl += " TEXT";
298 } else if (column_type == "BLOB") {
299 column_decl += " BLOB";
300 } else {
301 // TODO(shess): AFAICT, there remain:
302 // - contains("CLOB") -> TEXT
303 // - contains("REAL") -> REAL
304 // - contains("FLOA") -> REAL
305 // - contains("DOUB") -> REAL
306 // - other -> "NUMERIC"
307 // Just code those in as they come up.
308 NOTREACHED() << " Unsupported type " << column_type;
309 return false;
310 }
311
312 // If column has constraint "NOT NULL", then inserting NULL into
313 // that column will fail. If the column has a non-NULL DEFAULT
314 // specified, the INSERT will handle it (see below). If the
315 // DEFAULT is also NULL, the row must be filtered out.
316 // TODO(shess): The above scenario applies to INSERT OR REPLACE,
317 // whereas INSERT OR IGNORE drops such rows.
318 // http://www.sqlite.org/lang_conflict.html
319 if (not_null && default_is_null)
320 column_decl += " NOT NULL";
321
322 create_column_decls.push_back(column_decl);
323
324 // Per the NOTE in the header file, convert NULL values to the
325 // DEFAULT. All columns could be IFNULL(column_name,default), but
326 // the NULL case would require special handling either way.
327 if (default_is_null) {
328 insert_columns.push_back(column_name);
329 } else {
330 // The default value appears to be pre-quoted, as if it is
331 // literally from the sqlite_master CREATE statement.
332 std::string default_value = s.ColumnString(4);
333 insert_columns.push_back(base::StringPrintf(
334 "IFNULL(%s,%s)", column_name.c_str(), default_value.c_str()));
335 }
336 }
337
338 // Receiving no column information implies that the table doesn't exist.
339 if (create_column_decls.empty())
340 return false;
341
342 // If the PRIMARY KEY was a single INTEGER column, convert it to ROWID.
343 if (pk_column_count == 1 && !rowid_decl.empty())
344 create_column_decls[rowid_ofs] = rowid_decl;
345
346 // Additional columns accept anything.
347 // TODO(shess): ignoreN isn't well namespaced. But it will fail to
348 // execute in case of conflicts.
349 for (size_t i = 0; i < extend_columns; ++i) {
350 create_column_decls.push_back(
351 base::StringPrintf("ignore%" PRIuS " ANY", i));
352 }
353
354 std::string recover_create(base::StringPrintf(
355 "CREATE VIRTUAL TABLE temp.recover_%s USING recover(corrupt.%s, %s)",
356 table_name,
357 table_name,
358 JoinString(create_column_decls, ',').c_str()));
359
360 std::string recover_insert(base::StringPrintf(
361 "INSERT OR REPLACE INTO main.%s SELECT %s FROM temp.recover_%s",
362 table_name,
363 JoinString(insert_columns, ',').c_str(),
364 table_name));
365
366 std::string recover_drop(base::StringPrintf(
367 "DROP TABLE temp.recover_%s", table_name));
368
369 if (!db()->Execute(recover_create.c_str()))
370 return false;
371
372 if (!db()->Execute(recover_insert.c_str())) {
373 ignore_result(db()->Execute(recover_drop.c_str()));
374 return false;
375 }
376
377 *rows_recovered = db()->GetLastChangeCount();
378
379 // TODO(shess): Is leaving the recover table around a breaker?
380 return db()->Execute(recover_drop.c_str());
381 }
382
383 bool Recovery::SetupMeta() {
384 const char kCreateSql[] =
385 "CREATE VIRTUAL TABLE temp.recover_meta USING recover"
386 "("
387 "corrupt.meta,"
388 "key TEXT NOT NULL,"
389 "value ANY" // Whatever is stored.
390 ")";
391 return db()->Execute(kCreateSql);
392 }
393
394 bool Recovery::GetMetaVersionNumber(int* version) {
395 DCHECK(version);
396 // TODO(shess): DCHECK(db()->DoesTableExist("temp.recover_meta"));
397 // Unfortunately, DoesTableExist() queries sqlite_master, not
398 // sqlite_temp_master.
399
400 const char kVersionSql[] =
401 "SELECT value FROM temp.recover_meta WHERE key = 'version'";
402 sql::Statement recovery_version(db()->GetUniqueStatement(kVersionSql));
403 if (!recovery_version.Step())
404 return false;
405
406 *version = recovery_version.ColumnInt(0);
407 return true;
408 }
409
236 } // namespace sql 410 } // namespace sql
OLDNEW
« no previous file with comments | « trunk/src/sql/recovery.h ('k') | trunk/src/sql/recovery_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698