1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
|
<!DOCTYPE html>
<html><head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<link href="sqlite.css" rel="stylesheet">
<title>Recovering Data From A Corrupt SQLite Database</title>
<!-- path= -->
</head>
<body>
<div class=nosearch>
<a href="index.html">
<img class="logo" src="images/sqlite370_banner.gif" alt="SQLite" border="0">
</a>
<div><!-- IE hack to prevent disappearing logo --></div>
<div class="tagline desktoponly">
Small. Fast. Reliable.<br>Choose any three.
</div>
<div class="menu mainmenu">
<ul>
<li><a href="index.html">Home</a>
<li class='mobileonly'><a href="javascript:void(0)" onclick='toggle_div("submenu")'>Menu</a>
<li class='wideonly'><a href='about.html'>About</a>
<li class='desktoponly'><a href="docs.html">Documentation</a>
<li class='desktoponly'><a href="download.html">Download</a>
<li class='wideonly'><a href='copyright.html'>License</a>
<li class='desktoponly'><a href="support.html">Support</a>
<li class='desktoponly'><a href="prosupport.html">Purchase</a>
<li class='search' id='search_menubutton'>
<a href="javascript:void(0)" onclick='toggle_search()'>Search</a>
</ul>
</div>
<div class="menu submenu" id="submenu">
<ul>
<li><a href='about.html'>About</a>
<li><a href='docs.html'>Documentation</a>
<li><a href='download.html'>Download</a>
<li><a href='support.html'>Support</a>
<li><a href='prosupport.html'>Purchase</a>
</ul>
</div>
<div class="searchmenu" id="searchmenu">
<form method="GET" action="search">
<select name="s" id="searchtype">
<option value="d">Search Documentation</option>
<option value="c">Search Changelog</option>
</select>
<input type="text" name="q" id="searchbox" value="">
<input type="submit" value="Go">
</form>
</div>
</div>
<script>
function toggle_div(nm) {
var w = document.getElementById(nm);
if( w.style.display=="block" ){
w.style.display = "none";
}else{
w.style.display = "block";
}
}
function toggle_search() {
var w = document.getElementById("searchmenu");
if( w.style.display=="block" ){
w.style.display = "none";
} else {
w.style.display = "block";
setTimeout(function(){
document.getElementById("searchbox").focus()
}, 30);
}
}
function div_off(nm){document.getElementById(nm).style.display="none";}
window.onbeforeunload = function(e){div_off("submenu");}
/* Disable the Search feature if we are not operating from CGI, since */
/* Search is accomplished using CGI and will not work without it. */
if( !location.origin || !location.origin.match || !location.origin.match(/http/) ){
document.getElementById("search_menubutton").style.display = "none";
}
/* Used by the Hide/Show button beside syntax diagrams, to toggle the */
function hideorshow(btn,obj){
var x = document.getElementById(obj);
var b = document.getElementById(btn);
if( x.style.display!='none' ){
x.style.display = 'none';
b.innerHTML='show';
}else{
x.style.display = '';
b.innerHTML='hide';
}
return false;
}
var antiRobot = 0;
function antiRobotGo(){
if( antiRobot!=3 ) return;
antiRobot = 7;
var j = document.getElementById("mtimelink");
if(j && j.hasAttribute("data-href")) j.href=j.getAttribute("data-href");
}
function antiRobotDefense(){
document.body.onmousedown=function(){
antiRobot |= 2;
antiRobotGo();
document.body.onmousedown=null;
}
document.body.onmousemove=function(){
antiRobot |= 2;
antiRobotGo();
document.body.onmousemove=null;
}
setTimeout(function(){
antiRobot |= 1;
antiRobotGo();
}, 100)
antiRobotGo();
}
antiRobotDefense();
</script>
<div class=fancy>
<div class=nosearch>
<div class="fancy_title">
Recovering Data From A Corrupt SQLite Database
</div>
<div class="fancy_toc">
<a onclick="toggle_toc()">
<span class="fancy_toc_mark" id="toc_mk">►</span>
Table Of Contents
</a>
<div id="toc_sub"><div class="fancy-toc1"><a href="#recovering_some_data_from_a_corrupt_sqlite_database">1. Recovering (Some) Data From A Corrupt SQLite Database</a></div>
<div class="fancy-toc2"><a href="#limitations">1.1. Limitations</a></div>
<div class="fancy-toc1"><a href="#recovery_using_the_recover_command_in_the_cli">2. Recovery Using The ".recover" Command In The CLI</a></div>
<div class="fancy-toc1"><a href="#building_the_recovery_api_into_an_application">3. Building The Recovery API Into An Application</a></div>
<div class="fancy-toc2"><a href="#source_code_files">3.1. Source Code Files</a></div>
<div class="fancy-toc2"><a href="#how_to_implement_recovery">3.2. How To Implement Recovery</a></div>
<div class="fancy-toc2"><a href="#example_implementations">3.3. Example Implementations</a></div>
</div>
</div>
<script>
function toggle_toc(){
var sub = document.getElementById("toc_sub")
var mk = document.getElementById("toc_mk")
if( sub.style.display!="block" ){
sub.style.display = "block";
mk.innerHTML = "▼";
} else {
sub.style.display = "none";
mk.innerHTML = "►";
}
}
</script>
</div>
<h1 id="recovering_some_data_from_a_corrupt_sqlite_database"><span>1. </span>Recovering (Some) Data From A Corrupt SQLite Database</h1>
<p>
SQLite databases are remarkably rebust. Application faults and
power failures typically leave the content of the database intact.
However, it is possible to <a href="howtocorrupt.html">corrupt an SQLite database</a>.
For example, hardware malfunctions can damage the database file, or a
rogue process can open the database and overwrite parts of it.
</p><p>
Given a corrupt database file, it is sometimes desirable to try to
salvage as much data from the file as possible. The recovery API
is designed to facilitate this.
</p><h2 id="limitations"><span>1.1. </span>Limitations</h2>
<p>
It is sometimes possible to perfectly restore a database that has
gone corrupt, but that is the exception. Usually
the recovered database will be defective in a number of ways:
</p><ul>
<li><p>
Some content might be permanently deleted and unrecoverable.
This can happen, for example, if a rogue process overwrites part
of the database file.
</p></li><li><p>
Previously deleted content might reappear. Normally when SQLite
does a DELETE operation, it does not actually overwrite the old content
but instead remembers that space is available for reuse during the next
INSERT. If such deleted content is still in the file when a recovery
is attempted, it might be extracted and "resurrected".
</p></li><li><p>
Recovered content might be altered.
For example, the value stored in a particular row
might change from 48 to 49. Or it might change from an integer into
a string or blob. A value that was NULL might become an integer.
A string value might become a BLOB. And so forth.
</p></li><li><p>
Constraints may not be valid after recovery. CHECK constraints,
FOREIGN KEY constraints, UNIQUE constraints, type constraints on
<a href="stricttables.html">STRICT tables</a> - any of these might be violated in the recovered
database.
</p></li><li><p>
Content might be moved from one table into another.
</p></li></ul>
<p>
The recovery API does as good of a job as it can at restoring a database,
but the results will always be suspect. Sometimes (for example if the
corruption is restricted to indexes) the recovery will perfectly restore
the database content. However in other cases, the recovery will be imperfect.
The impact of this imperfection depends on the application. A database that
holds a list of bookmarks is still a list of bookmarks after recovery.
A few bookmarks might be missing or added or altered after recovery, but
the list is "fuzzy" and imperfect to begin with so adding a bit more
uncertainty will not be fatal to the application. But if an accounting
database goes corrupt and is subsequently recovered, the books might be
out of balance.
</p><p>
It is best to think of the recovery API as a salvage undertaking.
Recovery will extract as much usable data as it can from the wreck
of the old database, but some parts may be damaged beyond repair and
some rework and testing should be performed prior to returning the
recovered database to service.
</p><h1 id="recovery_using_the_recover_command_in_the_cli"><span>2. </span>Recovery Using The ".recover" Command In The CLI</h1>
<p>
The easiest way to manually recover a corrupt database is using
the <a href="cli.html">Command Line Interface</a> or "CLI" for SQLite. The CLI is a program
named "sqlite3". Use it to recover a corrupt database file using
a command similar to the following:
</p><div class="codeblock"><pre>sqlite3 corrupt.db .recover >data.sql
</pre></div>
<p>
This will generate SQL text in the file named "data.sql" that can be used
to reconstruct the original database:
</p><div class="codeblock"><pre>sqlite3 recovered.db <data.sql
</pre></div>
<p>
The ".recover" option is actually a command that is issued to the
CLI. That command can accept arguments. For example, by running:
</p><div class="codeblock"><pre>sqlite3 corruptdb ".recover --ignore-freelist" >data.sql
</pre></div>
<p>
Notice that the ".recover" command and its arguments must be contained
in quotes. The following options are supported:
</p><p>
</p><blockquote>
<dt>--ignore-freelist</dt>
<dd><p>
Ignore pages of the database that appear to be part of the
freelist. Normally the freelist is scanned, and if it contains
pages that look like they have content, that content is output.
But if the page really is on the freelist, that can mean that
previously deleted information is reintroduced into the database.
</p></dd>
<dt>--lost-and-found <i>TABLE</i></dt>
<dd><p>
If content is found during recovery that cannot be associated
with a particular table, it is put into the "lost_and_found"
table. Use this option to change the name of the
"lost_and_found" table to "TABLE".
</p></dd>
<dt>--no-rowids</dt>
<dd><p>
If this option is provided, then rowid values that are not also
INTEGER PRIMARY KEY values are not extracted from the
corrupt database.
</p></dd>
</blockquote>
<h1 id="building_the_recovery_api_into_an_application"><span>3. </span>Building The Recovery API Into An Application</h1>
<h2 id="source_code_files"><span>3.1. </span>Source Code Files</h2>
<p>If you want to build the recovery API into your application, you will
need to add some source files to your build, above and beyond the usual
"sqlite3.c" and "sqlite3.h" source files. You will need:
</p><p>
</p><blockquote>
<table border="0" cellpadding="20">
<tr>
<td>
<a href="https://sqlite.org/src/file/ext/recover/sqlite3recover.c">sqlite3recover.c</a>
</td><td>
This is the main source file that implements the recovery API.
</td>
</tr>
<tr>
<td>
<a href="https://sqlite.org/src/file/ext/recover/sqlite3recover.h">sqlite3recover.h</a>
</td><td>
This is the header file that goes with sqlite3recover.h.
</td>
</tr>
<tr>
<td>
<a href="https://sqlite.org/src/file/ext/recover/dbdata.c">dbdata.c</a>
</td><td>
This file implements two virtual tables name "sqlite_dbdata" and
"sqlite_dbptr" that required by sqlite3recover.c.
</td>
</tr>
</table>
</blockquote>
<p>
The two C source file above need to be linked into your application in the
same way as "sqlite3.c" is linked in. And the header file needs to be
accessible to the compiler when the C files are being compiled.
</p><p>
Additionally, the application, or more specifically the sqlite3.c linked
into the application, must be compiled with the following option:
</p><pre>
-DSQLITE_ENABLE_DBPAGE_VTAB
</pre>
<h2 id="how_to_implement_recovery"><span>3.2. </span>How To Implement Recovery</h2>
<p>These are the basic steps needed to recover content from a corrupt
Database:
</p><ol>
<li><p>
Creates an sqlite3_recover handle by calling either
sqlite3_recover_init() or sqlite3_recover_init_sql().
Use sqlite3_recover_init() to store the recovered content
in a separate database and use sqlite3_recover_init_sql()
to generate SQL text that will reconstruct the database.
</p></li><li><p>
Make zero or more calls to sqlite3_recover_config() to set
options on the new sqlite3_recovery handle.
</p></li><li><p>
Invoke sqlite3_recover_step() repeatedly
until it returns something other than SQLITE_OK. If it
returns SQLITE_DONE, then the recovery operation completed without
error. If it returns some other non-SQLITE_OK value, then an error
has occurred. The sqlite3_recover_run() interface is also
available as a convenience wrapper that simply invokes
sqlite3_recover_step() repeatedly until it returns something other
than SQLITE_DONE.
</p></li><li><p>
Retrieves any error code and English language error message using the
sqlite3_recover_errcode() and sqlite3_recover_errmsg() interfaces,
respectively.
</p></li><li><p>
Invoke sqlite3_recover_finish() to destroy the sqlite3_recover object.
</p></li></ol>
<p>
Details of the interface are described in comments in the
<a href="https://sqlite.org/src/file/ext/recover/sqlite3recover.h">sqlite3_recover.h header file</a>.
</p><h2 id="example_implementations"><span>3.3. </span>Example Implementations</h2>
<p>
Examples of how the recovery extension is used by SQLite itself
can be seen at the following links:
</p><ul>
<li><p><a href="https://sqlite.org/src/info/30475c820dc5ab8a8?ln=999,1026">https://sqlite.org/src/info/30475c820dc5ab8a8?ln=999,1026</a>
</p><p>
An example of the recovery extension found in the
"fuzzcheck" testing utility in the SQLite tree.
</p></li><li><p><a href="https://sqlite.org/src/info/84bb08d8762920285f08f1c0?ln=7299,7361">https://sqlite.org/src/info/84bb08d8762920285f08f1c0?ln=7299,7361</a>
</p><p>
The code that implements the ".recover" command in the <a href="cli.html">CLI</a>.
</p></li></ul>
<p align="center"><small><i>This page last modified on <a href="https://sqlite.org/docsrc/honeypot" id="mtimelink" data-href="https://sqlite.org/docsrc/finfo/pages/recovery.in?m=846399393d">2023-02-28 11:22:37</a> UTC </small></i></p>
|