Add unnecessary initializations to some local variables in the rtree module
[sqlite.git] / ext / repair / checkfreelist.c
blob990be4afa7b958b010991788af23da2c52bfc775
1 /*
2 ** 2017 October 11
3 **
4 ** The author disclaims copyright to this source code. In place of
5 ** a legal notice, here is a blessing:
6 **
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
43 # include <string.h>
44 # include <stdio.h>
45 # include <stdlib.h>
46 # include <assert.h>
47 # define ALWAYS(X) 1
48 # define NEVER(X) 0
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) + \
56 ((u32)((x)[3])) \
58 #endif
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 */
78 int rc, rc2;
79 char *zSql;
80 sqlite3_stmt *pStmt = 0;
81 int bOk = 0;
83 zSql = sqlite3_mprintf(zFmt, zDb);
84 if( zSql==0 ){
85 rc = SQLITE_NOMEM;
86 }else{
87 rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
88 sqlite3_free(zSql);
91 if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
92 *pnOut = (u32)sqlite3_column_int(pStmt, 0);
93 bOk = 1;
96 rc2 = sqlite3_finalize(pStmt);
97 if( rc==SQLITE_OK ) rc = rc2;
98 if( rc==SQLITE_OK && bOk==0 ) rc = SQLITE_ERROR;
99 return rc;
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
107 ** at (*pzOut).
109 static int checkFreelistError(char **pzOut, const char *zFmt, ...){
110 int rc = SQLITE_OK;
111 char *zErr = 0;
112 va_list ap;
114 va_start(ap, zFmt);
115 zErr = sqlite3_vmprintf(zFmt, ap);
116 if( zErr==0 ){
117 rc = SQLITE_NOMEM;
118 }else{
119 if( pzOut ){
120 *pzOut = sqlite3_mprintf("%s%z%s", *pzOut?"\n":"", *pzOut, zErr);
121 if( *pzOut==0 ) rc = SQLITE_NOMEM;
122 }else{
123 sqlite3_log(SQLITE_ERROR, "checkfreelist: %s", zErr);
125 sqlite3_free(zErr);
127 va_end(ap);
128 return rc;
131 static int checkFreelist(
132 sqlite3 *db,
133 const char *zDb,
134 char **pzOut
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. */
138 const char *zTrunk =
139 "WITH freelist_trunk(i, d, n) AS ("
140 "SELECT 1, NULL, sqlite_readint32(data, 32) "
141 "FROM sqlite_dbpage(:1) WHERE pgno=1 "
142 "UNION ALL "
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))
159 return rc;
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 ){
166 u32 i;
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;
181 nFree += 1+nLeaf;
182 if( iNext>nPage ){
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;
208 return rc;
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,
217 int nArg,
218 sqlite3_value **apArg
220 const char *zDb;
221 int rc;
222 char *zOut = 0;
223 sqlite3 *db = sqlite3_context_db_handle(pCtx);
225 assert( nArg==1 );
226 zDb = (const char*)sqlite3_value_text(apArg[0]);
227 rc = checkFreelist(db, zDb, &zOut);
228 if( rc==SQLITE_OK ){
229 sqlite3_result_text(pCtx, zOut?zOut:"ok", -1, SQLITE_TRANSIENT);
230 }else{
231 sqlite3_result_error_code(pCtx, rc);
234 sqlite3_free(zOut);
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,
244 int nArg,
245 sqlite3_value **apArg
247 const u8 *zBlob;
248 int nBlob;
249 int iOff = 0;
250 u32 iRet = 0;
252 if( nArg!=1 && nArg!=2 ){
253 sqlite3_result_error(
254 pCtx, "wrong number of arguments to function sqlite_readint32()", -1
256 return;
258 if( nArg==2 ){
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
283 return rc;
287 ** Extension load function.
289 #ifdef _WIN32
290 __declspec(dllexport)
291 #endif
292 int sqlite3_checkfreelist_init(
293 sqlite3 *db,
294 char **pzErrMsg,
295 const sqlite3_api_routines *pApi
297 SQLITE_EXTENSION_INIT2(pApi);
298 return cflRegister(db);