[M85 Migration] Add an evas gl option for rotation
[platform/framework/web/chromium-efl.git] / sql / recovery.h
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
3 // found in the LICENSE file.
4
5 #ifndef SQL_RECOVERY_H_
6 #define SQL_RECOVERY_H_
7
8 #include <stddef.h>
9
10 #include <memory>
11
12 #include "base/component_export.h"
13 #include "base/macros.h"
14 #include "sql/database.h"
15 #include "sql/internal_api_token.h"
16
17 namespace base {
18 class FilePath;
19 }
20
21 namespace sql {
22
23 // Recovery module for sql/.  The basic idea is to create a fresh database and
24 // populate it with the recovered contents of the original database.  If
25 // recovery is successful, the recovered database is backed up over the original
26 // database.  If recovery is not successful, the original database is razed.  In
27 // either case, the original handle is poisoned so that operations on the stack
28 // do not accidentally disrupt the restored data.
29 //
30 // RecoverDatabase() automates this, including recoverying the schema of from
31 // the suspect database.  If a database requires special handling, such as
32 // recovering between different schema, or tables requiring post-processing,
33 // then the module can be used manually like:
34 //
35 // {
36 //   std::unique_ptr<sql::Recovery> r =
37 //       sql::Recovery::Begin(orig_db, orig_db_path);
38 //   if (r) {
39 //     // Create the schema to recover to.  On failure, clear the
40 //     // database.
41 //     if (!r.db()->Execute(kCreateSchemaSql)) {
42 //       sql::Recovery::Unrecoverable(std::move(r));
43 //       return;
44 //     }
45 //
46 //     // Recover data in "mytable".
47 //     size_t rows_recovered = 0;
48 //     if (!r.AutoRecoverTable("mytable", 0, &rows_recovered)) {
49 //       sql::Recovery::Unrecoverable(std::move(r));
50 //       return;
51 //     }
52 //
53 //     // Manually cleanup additional constraints.
54 //     if (!r.db()->Execute(kCleanupSql)) {
55 //       sql::Recovery::Unrecoverable(std::move(r));
56 //       return;
57 //     }
58 //
59 //     // Commit the recovered data to the original database file.
60 //     sql::Recovery::Recovered(std::move(r));
61 //   }
62 // }
63 //
64 // If Recovered() is not called, then RazeAndClose() is called on
65 // orig_db.
66
67 class COMPONENT_EXPORT(SQL) Recovery {
68  public:
69   ~Recovery();
70
71   // Begin the recovery process by opening a temporary database handle
72   // and attach the existing database to it at "corrupt".  To prevent
73   // deadlock, all transactions on |database| are rolled back.
74   //
75   // Returns nullptr in case of failure, with no cleanup done on the
76   // original database (except for breaking the transactions).  The
77   // caller should Raze() or otherwise cleanup as appropriate.
78   //
79   // TODO(shess): Later versions of SQLite allow extracting the path
80   // from the database.
81   // TODO(shess): Allow specifying the connection point?
82   static std::unique_ptr<Recovery> Begin(Database* database,
83                                          const base::FilePath& db_path)
84       WARN_UNUSED_RESULT;
85
86   // Mark recovery completed by replicating the recovery database over
87   // the original database, then closing the recovery database.  The
88   // original database handle is poisoned, causing future calls
89   // against it to fail.
90   //
91   // If Recovered() is not called, the destructor will call
92   // Unrecoverable().
93   //
94   // TODO(shess): At this time, this function can fail while leaving
95   // the original database intact.  Figure out which failure cases
96   // should go to RazeAndClose() instead.
97   static bool Recovered(std::unique_ptr<Recovery> r) WARN_UNUSED_RESULT;
98
99   // Indicate that the database is unrecoverable.  The original
100   // database is razed, and the handle poisoned.
101   static void Unrecoverable(std::unique_ptr<Recovery> r);
102
103   // When initially developing recovery code, sometimes the possible
104   // database states are not well-understood without further
105   // diagnostics.  Abandon recovery but do not raze the original
106   // database.
107   // NOTE(shess): Only call this when adding recovery support.  In the
108   // steady state, all databases should progress to recovered or razed.
109   static void Rollback(std::unique_ptr<Recovery> r);
110
111   // Handle to the temporary recovery database.
112   sql::Database* db() { return &recover_db_; }
113
114   // Attempt to recover the named table from the corrupt database into
115   // the recovery database using a temporary recover virtual table.
116   // The virtual table schema is derived from the named table's schema
117   // in database [main].  Data is copied using INSERT OR IGNORE, so
118   // duplicates are dropped.
119   //
120   // If the source table has fewer columns than the target, the target
121   // DEFAULT value will be used for those columns.
122   //
123   // Returns true if all operations succeeded, with the number of rows
124   // recovered in |*rows_recovered|.
125   //
126   // NOTE(shess): Due to a flaw in the recovery virtual table, at this
127   // time this code injects the DEFAULT value of the target table in
128   // locations where the recovery table returns nullptr.  This is not
129   // entirely correct, because it happens both when there is a short
130   // row (correct) but also where there is an actual NULL value
131   // (incorrect).
132   //
133   // TODO(shess): Flag for INSERT OR REPLACE vs IGNORE.
134   // TODO(shess): Handle extended table names.
135   bool AutoRecoverTable(const char* table_name, size_t* rows_recovered);
136
137   // Setup a recover virtual table at temp.recover_meta, reading from
138   // corrupt.meta.  Returns true if created.
139   // TODO(shess): Perhaps integrate into Begin().
140   // TODO(shess): Add helpers to fetch additional items from the meta
141   // table as needed.
142   bool SetupMeta();
143
144   // Fetch the version number from temp.recover_meta.  Returns false
145   // if the query fails, or if there is no version row.  Otherwise
146   // returns true, with the version in |*version_number|.
147   //
148   // Only valid to call after successful SetupMeta().
149   bool GetMetaVersionNumber(int* version_number);
150
151   // Attempt to recover the database by creating a new database with schema from
152   // |db|, then copying over as much data as possible.  If successful, the
153   // recovery handle is returned to allow the caller to make additional changes,
154   // such as validating constraints not expressed in the schema.
155   //
156   // In case of SQLITE_NOTADB, the database is deemed unrecoverable and deleted.
157   static std::unique_ptr<Recovery> BeginRecoverDatabase(
158       Database* db,
159       const base::FilePath& db_path) WARN_UNUSED_RESULT;
160
161   // Call BeginRecoverDatabase() to recover the database, then commit the
162   // changes using Recovered().  After this call, the |db| handle will be
163   // poisoned (though technically remaining open) so that future calls will
164   // return errors until the handle is re-opened.
165   static void RecoverDatabase(Database* db, const base::FilePath& db_path);
166
167   // Variant on RecoverDatabase() which requires that the database have a valid
168   // meta table with a version value.  The meta version value is used by some
169   // clients to make assertions about the database schema.  If this information
170   // cannot be determined, the database is considered unrecoverable.
171   static void RecoverDatabaseWithMetaVersion(Database* db,
172                                              const base::FilePath& db_path);
173
174   // Returns true for SQLite errors which RecoverDatabase() can plausibly fix.
175   // This does not guarantee that RecoverDatabase() will successfully recover
176   // the database.
177   static bool ShouldRecover(int extended_error);
178
179   // Enables the "recover" SQLite extension for a database connection.
180   //
181   // Returns a SQLite error code.
182   static int EnableRecoveryExtension(Database* db, InternalApiToken);
183
184  private:
185   explicit Recovery(Database* database);
186
187   // Setup the recovery database handle for Begin().  Returns false in
188   // case anything failed.
189   bool Init(const base::FilePath& db_path) WARN_UNUSED_RESULT;
190
191   // Copy the recovered database over the original database.
192   bool Backup() WARN_UNUSED_RESULT;
193
194   // Close the recovery database, and poison the original handle.
195   // |raze| controls whether the original database is razed or just
196   // poisoned.
197   enum Disposition {
198     RAZE_AND_POISON,
199     POISON,
200   };
201   void Shutdown(Disposition raze);
202
203   Database* db_;         // Original Database connection.
204   Database recover_db_;  // Recovery Database connection.
205
206   DISALLOW_COPY_AND_ASSIGN(Recovery);
207 };
208
209 }  // namespace sql
210
211 #endif  // SQL_RECOVERY_H_