modernc.org/cc@v1.0.1/v2/testdata/_sqlite/ext/repair/checkfreelist.c (about) 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. 10 ** 11 ************************************************************************* 12 ** 13 ** This module exports a single C function: 14 ** 15 ** int sqlite3_check_freelist(sqlite3 *db, const char *zDb); 16 ** 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. 22 ** 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: 26 ** 27 ** SELECT checkfreelist(<database-name>); 28 ** 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. 33 ** 34 ** To compile this module for use as an SQLite loadable extension: 35 ** 36 ** gcc -Os -fPIC -shared checkfreelist.c -o checkfreelist.so 37 */ 38 39 #include "sqlite3ext.h" 40 SQLITE_EXTENSION_INIT1 41 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])) \ 57 ) 58 #endif 59 60 /* 61 ** Execute a single PRAGMA statement and return the integer value returned 62 ** via output parameter (*pnOut). 63 ** 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. 67 ** 68 ** sqlGetInteger(db, "main", "PRAGMA %s.page_count", pnOut) 69 ** 70 ** executes "PRAGMA main.page_count" and stores the results in (*pnOut). 71 */ 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 */ 77 ){ 78 int rc, rc2; 79 char *zSql; 80 sqlite3_stmt *pStmt = 0; 81 int bOk = 0; 82 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); 89 } 90 91 if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ 92 *pnOut = (u32)sqlite3_column_int(pStmt, 0); 93 bOk = 1; 94 } 95 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; 100 } 101 102 /* 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). 108 */ 109 static int checkFreelistError(char **pzOut, const char *zFmt, ...){ 110 int rc = SQLITE_OK; 111 char *zErr = 0; 112 va_list ap; 113 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); 124 } 125 sqlite3_free(zErr); 126 } 127 va_end(ap); 128 return rc; 129 } 130 131 static int checkFreelist( 132 sqlite3 *db, 133 const char *zDb, 134 char **pzOut 135 ){ 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 " 145 ")" 146 "SELECT i, d FROM freelist_trunk WHERE i!=1;"; 147 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 */ 153 154 if( zDb==0 ) zDb = "main"; 155 156 if( (rc = sqlGetInteger(db, zDb, "PRAGMA %s.page_count", &nPage)) 157 || (rc = sqlGetInteger(db, zDb, "PRAGMA %s.freelist_count", &nExpected)) 158 ){ 159 return rc; 160 } 161 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 int nData = sqlite3_column_bytes(pTrunk, 1); 170 u32 iNext = get4byte(&aData[0]); 171 u32 nLeaf = get4byte(&aData[4]); 172 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 177 ); 178 nLeaf = (nData/4) - 2 - 6; 179 } 180 181 nFree += 1+nLeaf; 182 if( iNext>nPage ){ 183 rc = checkFreelistError(pzOut, 184 "trunk page %d is out of range", (int)iNext 185 ); 186 } 187 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 194 ); 195 } 196 } 197 } 198 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 203 ); 204 } 205 206 rc2 = sqlite3_finalize(pTrunk); 207 if( rc==SQLITE_OK ) rc = rc2; 208 return rc; 209 } 210 211 int sqlite3_check_freelist(sqlite3 *db, const char *zDb){ 212 return checkFreelist(db, zDb, 0); 213 } 214 215 static void checkfreelist_function( 216 sqlite3_context *pCtx, 217 int nArg, 218 sqlite3_value **apArg 219 ){ 220 const char *zDb; 221 int rc; 222 char *zOut = 0; 223 sqlite3 *db = sqlite3_context_db_handle(pCtx); 224 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); 232 } 233 234 sqlite3_free(zOut); 235 } 236 237 /* 238 ** An SQL function invoked as follows: 239 ** 240 ** sqlite_readint32(BLOB) -- Decode 32-bit integer from start of blob 241 */ 242 static void readint_function( 243 sqlite3_context *pCtx, 244 int nArg, 245 sqlite3_value **apArg 246 ){ 247 const u8 *zBlob; 248 int nBlob; 249 int iOff = 0; 250 u32 iRet = 0; 251 252 if( nArg!=1 && nArg!=2 ){ 253 sqlite3_result_error( 254 pCtx, "wrong number of arguments to function sqlite_readint32()", -1 255 ); 256 return; 257 } 258 if( nArg==2 ){ 259 iOff = sqlite3_value_int(apArg[1]); 260 } 261 262 zBlob = sqlite3_value_blob(apArg[0]); 263 nBlob = sqlite3_value_bytes(apArg[0]); 264 265 if( nBlob>=(iOff+4) ){ 266 iRet = get4byte(&zBlob[iOff]); 267 } 268 269 sqlite3_result_int64(pCtx, (sqlite3_int64)iRet); 270 } 271 272 /* 273 ** Register the SQL functions. 274 */ 275 static int cflRegister(sqlite3 *db){ 276 int rc = sqlite3_create_function( 277 db, "sqlite_readint32", -1, SQLITE_UTF8, 0, readint_function, 0, 0 278 ); 279 if( rc!=SQLITE_OK ) return rc; 280 rc = sqlite3_create_function( 281 db, "checkfreelist", 1, SQLITE_UTF8, 0, checkfreelist_function, 0, 0 282 ); 283 return rc; 284 } 285 286 /* 287 ** Extension load function. 288 */ 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 296 ){ 297 SQLITE_EXTENSION_INIT2(pApi); 298 return cflRegister(db); 299 }