[M108 Migration][HBBTV] Implement ewk_context_register_jsplugin_mime_types API
[platform/framework/web/chromium-efl.git] / sql / recovery.h
1 // Copyright 2013 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.
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/memory/raw_ptr.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(const Recovery&) = delete;
70   Recovery& operator=(const Recovery&) = delete;
71   ~Recovery();
72
73   // Begin the recovery process by opening a temporary database handle
74   // and attach the existing database to it at "corrupt".  To prevent
75   // deadlock, all transactions on |database| are rolled back.
76   //
77   // Returns nullptr in case of failure, with no cleanup done on the
78   // original database (except for breaking the transactions).  The
79   // caller should Raze() or otherwise cleanup as appropriate.
80   //
81   // TODO(shess): Later versions of SQLite allow extracting the path
82   // from the database.
83   // TODO(shess): Allow specifying the connection point?
84   [[nodiscard]] static std::unique_ptr<Recovery> Begin(
85       Database* database,
86       const base::FilePath& db_path);
87
88   // Mark recovery completed by replicating the recovery database over
89   // the original database, then closing the recovery database.  The
90   // original database handle is poisoned, causing future calls
91   // against it to fail.
92   //
93   // If Recovered() is not called, the destructor will call
94   // Unrecoverable().
95   //
96   // TODO(shess): At this time, this function can fail while leaving
97   // the original database intact.  Figure out which failure cases
98   // should go to RazeAndClose() instead.
99   [[nodiscard]] static bool Recovered(std::unique_ptr<Recovery> r);
100
101   // Indicate that the database is unrecoverable.  The original
102   // database is razed, and the handle poisoned.
103   static void Unrecoverable(std::unique_ptr<Recovery> r);
104
105   // When initially developing recovery code, sometimes the possible
106   // database states are not well-understood without further
107   // diagnostics.  Abandon recovery but do not raze the original
108   // database.
109   // NOTE(shess): Only call this when adding recovery support.  In the
110   // steady state, all databases should progress to recovered or razed.
111   static void Rollback(std::unique_ptr<Recovery> r);
112
113   // Handle to the temporary recovery database.
114   sql::Database* db() { return &recover_db_; }
115
116   // Attempt to recover the named table from the corrupt database into
117   // the recovery database using a temporary recover virtual table.
118   // The virtual table schema is derived from the named table's schema
119   // in database [main].  Data is copied using INSERT OR IGNORE, so
120   // duplicates are dropped.
121   //
122   // If the source table has fewer columns than the target, the target
123   // DEFAULT value will be used for those columns.
124   //
125   // Returns true if all operations succeeded, with the number of rows
126   // recovered in |*rows_recovered|.
127   //
128   // NOTE(shess): Due to a flaw in the recovery virtual table, at this
129   // time this code injects the DEFAULT value of the target table in
130   // locations where the recovery table returns nullptr.  This is not
131   // entirely correct, because it happens both when there is a short
132   // row (correct) but also where there is an actual NULL value
133   // (incorrect).
134   //
135   // TODO(shess): Flag for INSERT OR REPLACE vs IGNORE.
136   // TODO(shess): Handle extended table names.
137   bool AutoRecoverTable(const char* table_name, size_t* rows_recovered);
138
139   // Setup a recover virtual table at temp.recover_meta, reading from
140   // corrupt.meta.  Returns true if created.
141   // TODO(shess): Perhaps integrate into Begin().
142   // TODO(shess): Add helpers to fetch additional items from the meta
143   // table as needed.
144   bool SetupMeta();
145
146   // Fetch the version number from temp.recover_meta.  Returns false
147   // if the query fails, or if there is no version row.  Otherwise
148   // returns true, with the version in |*version_number|.
149   //
150   // Only valid to call after successful SetupMeta().
151   bool GetMetaVersionNumber(int* version_number);
152
153   // Attempt to recover the database by creating a new database with schema from
154   // |db|, then copying over as much data as possible.  If successful, the
155   // recovery handle is returned to allow the caller to make additional changes,
156   // such as validating constraints not expressed in the schema.
157   //
158   // In case of SQLITE_NOTADB, the database is deemed unrecoverable and deleted.
159   [[nodiscard]] static std::unique_ptr<Recovery> BeginRecoverDatabase(
160       Database* db,
161       const base::FilePath& db_path);
162
163   // Call BeginRecoverDatabase() to recover the database, then commit the
164   // changes using Recovered().  After this call, the |db| handle will be
165   // poisoned (though technically remaining open) so that future calls will
166   // return errors until the handle is re-opened.
167   static void RecoverDatabase(Database* db, const base::FilePath& db_path);
168
169   // Variant on RecoverDatabase() which requires that the database have a valid
170   // meta table with a version value.  The meta version value is used by some
171   // clients to make assertions about the database schema.  If this information
172   // cannot be determined, the database is considered unrecoverable.
173   static void RecoverDatabaseWithMetaVersion(Database* db,
174                                              const base::FilePath& db_path);
175
176   // Returns true for SQLite errors which RecoverDatabase() can plausibly fix.
177   // This does not guarantee that RecoverDatabase() will successfully recover
178   // the database.
179   static bool ShouldRecover(int extended_error);
180
181   // Enables the "recover" SQLite extension for a database connection.
182   //
183   // Returns a SQLite error code.
184   static int EnableRecoveryExtension(Database* db, InternalApiToken);
185
186  private:
187   explicit Recovery(Database* database);
188
189   // Setup the recovery database handle for Begin().  Returns false in
190   // case anything failed.
191   [[nodiscard]] bool Init(const base::FilePath& db_path);
192
193   // Copy the recovered database over the original database.
194   [[nodiscard]] bool Backup();
195
196   // Close the recovery database, and poison the original handle.
197   // |raze| controls whether the original database is razed or just
198   // poisoned.
199   enum Disposition {
200     RAZE_AND_POISON,
201     POISON,
202   };
203   void Shutdown(Disposition raze);
204
205   raw_ptr<Database> db_;  // Original Database connection.
206   Database recover_db_;  // Recovery Database connection.
207 };
208
209 }  // namespace sql
210
211 #endif  // SQL_RECOVERY_H_