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
49 typedef unsigned char u8
;
50 typedef unsigned short u16
;
51 typedef unsigned int u32
;
52 #define get4byte(x) ( \
53 ((u32)((x)[0])<<24) + \
54 ((u32)((x)[1])<<16) + \
55 ((u32)((x)[2])<<8) + \
61 ** Execute a single PRAGMA statement and return the integer value returned
62 ** via output parameter (*pnOut).
64 ** The SQL statement passed as the third argument should be a printf-style
65 ** format string containing a single "%s" which will be replace by the
66 ** value passed as the second argument. e.g.
68 ** sqlGetInteger(db, "main", "PRAGMA %s.page_count", pnOut)
70 ** executes "PRAGMA main.page_count" and stores the results in (*pnOut).
72 static int sqlGetInteger(
73 sqlite3
*db
, /* Database handle */
74 const char *zDb
, /* Database name ("main", "temp" etc.) */
75 const char *zFmt
, /* SQL statement format */
76 u32
*pnOut
/* OUT: Integer value */
80 sqlite3_stmt
*pStmt
= 0;
83 zSql
= sqlite3_mprintf(zFmt
, zDb
);
87 rc
= sqlite3_prepare_v2(db
, zSql
, -1, &pStmt
, 0);
91 if( rc
==SQLITE_OK
&& SQLITE_ROW
==sqlite3_step(pStmt
) ){
92 *pnOut
= (u32
)sqlite3_column_int(pStmt
, 0);
96 rc2
= sqlite3_finalize(pStmt
);
97 if( rc
==SQLITE_OK
) rc
= rc2
;
98 if( rc
==SQLITE_OK
&& bOk
==0 ) rc
= SQLITE_ERROR
;
103 ** Argument zFmt must be a printf-style format string and must be
104 ** followed by its required arguments. If argument pzOut is NULL,
105 ** then the results of printf()ing the format string are passed to
106 ** sqlite3_log(). Otherwise, they are appended to the string
109 static int checkFreelistError(char **pzOut
, const char *zFmt
, ...){
115 zErr
= sqlite3_vmprintf(zFmt
, ap
);
120 *pzOut
= sqlite3_mprintf("%s%z%s", *pzOut
?"\n":"", *pzOut
, zErr
);
121 if( *pzOut
==0 ) rc
= SQLITE_NOMEM
;
123 sqlite3_log(SQLITE_ERROR
, "checkfreelist: %s", zErr
);
131 static int checkFreelist(
136 /* This query returns one row for each page on the free list. Each row has
137 ** two columns - the page number and page content. */
139 "WITH freelist_trunk(i, d, n) AS ("
140 "SELECT 1, NULL, sqlite_readint32(data, 32) "
141 "FROM sqlite_dbpage(:1) WHERE pgno=1 "
143 "SELECT n, data, sqlite_readint32(data) "
144 "FROM freelist_trunk, sqlite_dbpage(:1) WHERE pgno=n "
146 "SELECT i, d FROM freelist_trunk WHERE i!=1;";
148 int rc
, rc2
; /* Return code */
149 sqlite3_stmt
*pTrunk
= 0; /* Compilation of zTrunk */
150 u32 nPage
= 0; /* Number of pages in db */
151 u32 nExpected
= 0; /* Expected number of free pages */
152 u32 nFree
= 0; /* Number of pages on free list */
154 if( zDb
==0 ) zDb
= "main";
156 if( (rc
= sqlGetInteger(db
, zDb
, "PRAGMA %s.page_count", &nPage
))
157 || (rc
= sqlGetInteger(db
, zDb
, "PRAGMA %s.freelist_count", &nExpected
))
162 rc
= sqlite3_prepare_v2(db
, zTrunk
, -1, &pTrunk
, 0);
163 if( rc
!=SQLITE_OK
) return rc
;
164 sqlite3_bind_text(pTrunk
, 1, zDb
, -1, SQLITE_STATIC
);
165 while( rc
==SQLITE_OK
&& sqlite3_step(pTrunk
)==SQLITE_ROW
){
167 u32 iTrunk
= (u32
)sqlite3_column_int(pTrunk
, 0);
168 const u8
*aData
= (const u8
*)sqlite3_column_blob(pTrunk
, 1);
169 u32 nData
= (u32
)sqlite3_column_bytes(pTrunk
, 1);
170 u32 iNext
= get4byte(&aData
[0]);
171 u32 nLeaf
= get4byte(&aData
[4]);
173 if( nLeaf
>((nData
/4)-2-6) ){
174 rc
= checkFreelistError(pzOut
,
175 "leaf count out of range (%d) on trunk page %d",
176 (int)nLeaf
, (int)iTrunk
178 nLeaf
= (nData
/4) - 2 - 6;
183 rc
= checkFreelistError(pzOut
,
184 "trunk page %d is out of range", (int)iNext
188 for(i
=0; rc
==SQLITE_OK
&& i
<nLeaf
; i
++){
189 u32 iLeaf
= get4byte(&aData
[8 + 4*i
]);
190 if( iLeaf
==0 || iLeaf
>nPage
){
191 rc
= checkFreelistError(pzOut
,
192 "leaf page %d is out of range (child %d of trunk page %d)",
193 (int)iLeaf
, (int)i
, (int)iTrunk
199 if( rc
==SQLITE_OK
&& nFree
!=nExpected
){
200 rc
= checkFreelistError(pzOut
,
201 "free-list count mismatch: actual=%d header=%d",
202 (int)nFree
, (int)nExpected
206 rc2
= sqlite3_finalize(pTrunk
);
207 if( rc
==SQLITE_OK
) rc
= rc2
;
211 int sqlite3_check_freelist(sqlite3
*db
, const char *zDb
){
212 return checkFreelist(db
, zDb
, 0);
215 static void checkfreelist_function(
216 sqlite3_context
*pCtx
,
218 sqlite3_value
**apArg
223 sqlite3
*db
= sqlite3_context_db_handle(pCtx
);
226 zDb
= (const char*)sqlite3_value_text(apArg
[0]);
227 rc
= checkFreelist(db
, zDb
, &zOut
);
229 sqlite3_result_text(pCtx
, zOut
?zOut
:"ok", -1, SQLITE_TRANSIENT
);
231 sqlite3_result_error_code(pCtx
, rc
);
238 ** An SQL function invoked as follows:
240 ** sqlite_readint32(BLOB) -- Decode 32-bit integer from start of blob
242 static void readint_function(
243 sqlite3_context
*pCtx
,
245 sqlite3_value
**apArg
252 if( nArg
!=1 && nArg
!=2 ){
253 sqlite3_result_error(
254 pCtx
, "wrong number of arguments to function sqlite_readint32()", -1
259 iOff
= sqlite3_value_int(apArg
[1]);
262 zBlob
= sqlite3_value_blob(apArg
[0]);
263 nBlob
= sqlite3_value_bytes(apArg
[0]);
265 if( nBlob
>=(iOff
+4) ){
266 iRet
= get4byte(&zBlob
[iOff
]);
269 sqlite3_result_int64(pCtx
, (sqlite3_int64
)iRet
);
273 ** Register the SQL functions.
275 static int cflRegister(sqlite3
*db
){
276 int rc
= sqlite3_create_function(
277 db
, "sqlite_readint32", -1, SQLITE_UTF8
, 0, readint_function
, 0, 0
279 if( rc
!=SQLITE_OK
) return rc
;
280 rc
= sqlite3_create_function(
281 db
, "checkfreelist", 1, SQLITE_UTF8
, 0, checkfreelist_function
, 0, 0
287 ** Extension load function.
290 __declspec(dllexport
)
292 int sqlite3_checkfreelist_init(
295 const sqlite3_api_routines
*pApi
297 SQLITE_EXTENSION_INIT2(pApi
);
298 return cflRegister(db
);