4 ** The author disclaims copyright to this source code. In place of
5 ** a legal notice, here is a blessing:
7 ** May you do good and not evil.
8 ** May you find forgiveness for yourself and forgive others.
9 ** May you share freely, never taking more than you give.
11 *************************************************************************
13 ** This module exports a single C function:
15 ** int sqlite3_check_freelist(sqlite3 *db, const char *zDb);
17 ** This function checks the free-list in database zDb (one of "main",
18 ** "temp", etc.) and reports any errors by invoking the sqlite3_log()
19 ** function. It returns SQLITE_OK if successful, or an SQLite error
20 ** code otherwise. It is not an error if the free-list is corrupted but
21 ** no IO or OOM errors occur.
23 ** If this file is compiled and loaded as an SQLite loadable extension,
24 ** it adds an SQL function "checkfreelist" to the database handle, to
25 ** be invoked as follows:
27 ** SELECT checkfreelist(<database-name>);
29 ** This function performs the same checks as sqlite3_check_freelist(),
30 ** except that it returns all error messages as a single text value,
31 ** separated by newline characters. If the freelist is not corrupted
32 ** in any way, an empty string is returned.
34 ** To compile this module for use as an SQLite loadable extension:
36 ** gcc -Os -fPIC -shared checkfreelist.c -o checkfreelist.so
39 #include "sqlite3ext.h"
40 SQLITE_EXTENSION_INIT1
42 #ifndef SQLITE_AMALGAMATION
47 # if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST)
48 # define SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS 1
50 # if defined(SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS)
51 # define ALWAYS(X) (1)
53 # elif !defined(NDEBUG)
54 # define ALWAYS(X) ((X)?1:(assert(0),0))
55 # define NEVER(X) ((X)?(assert(0),1):0)
57 # define ALWAYS(X) (X)
60 typedef unsigned char u8
;
61 typedef unsigned short u16
;
62 typedef unsigned int u32
;
63 #define get4byte(x) ( \
64 ((u32)((x)[0])<<24) + \
65 ((u32)((x)[1])<<16) + \
66 ((u32)((x)[2])<<8) + \
72 ** Execute a single PRAGMA statement and return the integer value returned
73 ** via output parameter (*pnOut).
75 ** The SQL statement passed as the third argument should be a printf-style
76 ** format string containing a single "%s" which will be replace by the
77 ** value passed as the second argument. e.g.
79 ** sqlGetInteger(db, "main", "PRAGMA %s.page_count", pnOut)
81 ** executes "PRAGMA main.page_count" and stores the results in (*pnOut).
83 static int sqlGetInteger(
84 sqlite3
*db
, /* Database handle */
85 const char *zDb
, /* Database name ("main", "temp" etc.) */
86 const char *zFmt
, /* SQL statement format */
87 u32
*pnOut
/* OUT: Integer value */
91 sqlite3_stmt
*pStmt
= 0;
94 zSql
= sqlite3_mprintf(zFmt
, zDb
);
98 rc
= sqlite3_prepare_v2(db
, zSql
, -1, &pStmt
, 0);
102 if( rc
==SQLITE_OK
&& SQLITE_ROW
==sqlite3_step(pStmt
) ){
103 *pnOut
= (u32
)sqlite3_column_int(pStmt
, 0);
107 rc2
= sqlite3_finalize(pStmt
);
108 if( rc
==SQLITE_OK
) rc
= rc2
;
109 if( rc
==SQLITE_OK
&& bOk
==0 ) rc
= SQLITE_ERROR
;
114 ** Argument zFmt must be a printf-style format string and must be
115 ** followed by its required arguments. If argument pzOut is NULL,
116 ** then the results of printf()ing the format string are passed to
117 ** sqlite3_log(). Otherwise, they are appended to the string
120 static int checkFreelistError(char **pzOut
, const char *zFmt
, ...){
126 zErr
= sqlite3_vmprintf(zFmt
, ap
);
131 *pzOut
= sqlite3_mprintf("%s%z%s", *pzOut
?"\n":"", *pzOut
, zErr
);
132 if( *pzOut
==0 ) rc
= SQLITE_NOMEM
;
134 sqlite3_log(SQLITE_ERROR
, "checkfreelist: %s", zErr
);
142 static int checkFreelist(
147 /* This query returns one row for each page on the free list. Each row has
148 ** two columns - the page number and page content. */
150 "WITH freelist_trunk(i, d, n) AS ("
151 "SELECT 1, NULL, sqlite_readint32(data, 32) "
152 "FROM sqlite_dbpage(:1) WHERE pgno=1 "
154 "SELECT n, data, sqlite_readint32(data) "
155 "FROM freelist_trunk, sqlite_dbpage(:1) WHERE pgno=n "
157 "SELECT i, d FROM freelist_trunk WHERE i!=1;";
159 int rc
, rc2
; /* Return code */
160 sqlite3_stmt
*pTrunk
= 0; /* Compilation of zTrunk */
161 u32 nPage
= 0; /* Number of pages in db */
162 u32 nExpected
= 0; /* Expected number of free pages */
163 u32 nFree
= 0; /* Number of pages on free list */
165 if( zDb
==0 ) zDb
= "main";
167 if( (rc
= sqlGetInteger(db
, zDb
, "PRAGMA %s.page_count", &nPage
))
168 || (rc
= sqlGetInteger(db
, zDb
, "PRAGMA %s.freelist_count", &nExpected
))
173 rc
= sqlite3_prepare_v2(db
, zTrunk
, -1, &pTrunk
, 0);
174 if( rc
!=SQLITE_OK
) return rc
;
175 sqlite3_bind_text(pTrunk
, 1, zDb
, -1, SQLITE_STATIC
);
176 while( rc
==SQLITE_OK
&& sqlite3_step(pTrunk
)==SQLITE_ROW
){
178 u32 iTrunk
= (u32
)sqlite3_column_int(pTrunk
, 0);
179 const u8
*aData
= (const u8
*)sqlite3_column_blob(pTrunk
, 1);
180 u32 nData
= (u32
)sqlite3_column_bytes(pTrunk
, 1);
181 u32 iNext
= get4byte(&aData
[0]);
182 u32 nLeaf
= get4byte(&aData
[4]);
184 if( nLeaf
>((nData
/4)-2-6) ){
185 rc
= checkFreelistError(pzOut
,
186 "leaf count out of range (%d) on trunk page %d",
187 (int)nLeaf
, (int)iTrunk
189 nLeaf
= (nData
/4) - 2 - 6;
194 rc
= checkFreelistError(pzOut
,
195 "trunk page %d is out of range", (int)iNext
199 for(i
=0; rc
==SQLITE_OK
&& i
<nLeaf
; i
++){
200 u32 iLeaf
= get4byte(&aData
[8 + 4*i
]);
201 if( iLeaf
==0 || iLeaf
>nPage
){
202 rc
= checkFreelistError(pzOut
,
203 "leaf page %d is out of range (child %d of trunk page %d)",
204 (int)iLeaf
, (int)i
, (int)iTrunk
210 if( rc
==SQLITE_OK
&& nFree
!=nExpected
){
211 rc
= checkFreelistError(pzOut
,
212 "free-list count mismatch: actual=%d header=%d",
213 (int)nFree
, (int)nExpected
217 rc2
= sqlite3_finalize(pTrunk
);
218 if( rc
==SQLITE_OK
) rc
= rc2
;
222 int sqlite3_check_freelist(sqlite3
*db
, const char *zDb
){
223 return checkFreelist(db
, zDb
, 0);
226 static void checkfreelist_function(
227 sqlite3_context
*pCtx
,
229 sqlite3_value
**apArg
234 sqlite3
*db
= sqlite3_context_db_handle(pCtx
);
237 zDb
= (const char*)sqlite3_value_text(apArg
[0]);
238 rc
= checkFreelist(db
, zDb
, &zOut
);
240 sqlite3_result_text(pCtx
, zOut
?zOut
:"ok", -1, SQLITE_TRANSIENT
);
242 sqlite3_result_error_code(pCtx
, rc
);
249 ** An SQL function invoked as follows:
251 ** sqlite_readint32(BLOB) -- Decode 32-bit integer from start of blob
253 static void readint_function(
254 sqlite3_context
*pCtx
,
256 sqlite3_value
**apArg
263 if( nArg
!=1 && nArg
!=2 ){
264 sqlite3_result_error(
265 pCtx
, "wrong number of arguments to function sqlite_readint32()", -1
270 iOff
= sqlite3_value_int(apArg
[1]);
273 zBlob
= sqlite3_value_blob(apArg
[0]);
274 nBlob
= sqlite3_value_bytes(apArg
[0]);
276 if( nBlob
>=(iOff
+4) ){
277 iRet
= get4byte(&zBlob
[iOff
]);
280 sqlite3_result_int64(pCtx
, (sqlite3_int64
)iRet
);
284 ** Register the SQL functions.
286 static int cflRegister(sqlite3
*db
){
287 int rc
= sqlite3_create_function(
288 db
, "sqlite_readint32", -1, SQLITE_UTF8
, 0, readint_function
, 0, 0
290 if( rc
!=SQLITE_OK
) return rc
;
291 rc
= sqlite3_create_function(
292 db
, "checkfreelist", 1, SQLITE_UTF8
, 0, checkfreelist_function
, 0, 0
298 ** Extension load function.
301 __declspec(dllexport
)
303 int sqlite3_checkfreelist_init(
306 const sqlite3_api_routines
*pApi
308 SQLITE_EXTENSION_INIT2(pApi
);
309 return cflRegister(db
);