/* ** 2016-10-24 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** This is a utility program that uses the est_count and btree_sample ** pragmas to try to approximate the content of the sqlite_stat1 table ** without doing a full table scan. ** ** To compile, simply link against SQLite. ** ** See the showHelp() routine below for a brief description of how to ** run the utility. */ #include #include #include #include #include #include #include "sqlite3.h" /* ** All global variables are gathered into the "g" singleton. */ struct GlobalVars { const char *zArgv0; /* Name of program */ unsigned fDebug; /* Debug flags */ sqlite3 *db; /* The database connection */ } g; /* ** Allowed values for g.fDebug */ #define DEBUG_NONE 0 /* ** Print an error resulting from faulting command-line arguments and ** abort the program. */ static void cmdlineError(const char *zFormat, ...){ va_list ap; fprintf(stderr, "%s: ", g.zArgv0); va_start(ap, zFormat); vfprintf(stderr, zFormat, ap); va_end(ap); fprintf(stderr, "\n\"%s --help\" for more help\n", g.zArgv0); exit(1); } /* ** Print an error message for an error that occurs at runtime, then ** abort the program. */ static void runtimeError(const char *zFormat, ...){ va_list ap; fprintf(stderr, "%s: ", g.zArgv0); va_start(ap, zFormat); vfprintf(stderr, zFormat, ap); va_end(ap); fprintf(stderr, "\n"); exit(1); } /* ** Prepare a new SQL statement. Print an error and abort if anything ** goes wrong. */ static sqlite3_stmt *db_vprepare(const char *zFormat, va_list ap){ char *zSql; int rc; sqlite3_stmt *pStmt; zSql = sqlite3_vmprintf(zFormat, ap); if( zSql==0 ) runtimeError("out of memory"); rc = sqlite3_prepare_v2(g.db, zSql, -1, &pStmt, 0); if( rc ){ runtimeError("SQL statement error: %s\n\"%s\"", sqlite3_errmsg(g.db), zSql); } sqlite3_free(zSql); return pStmt; } static sqlite3_stmt *db_prepare(const char *zFormat, ...){ va_list ap; sqlite3_stmt *pStmt; va_start(ap, zFormat); pStmt = db_vprepare(zFormat, ap); va_end(ap); return pStmt; } /* ** Estimate the number of rows in the given table or index. */ static sqlite3_int64 estEntryCount(const char *zTabIdx){ double sum = 0.0; int i; int n = 0; sqlite3_stmt *pStmt; # define N_CNT_SAMPLE 10 for(i=0; i<=N_CNT_SAMPLE; i++){ pStmt = db_prepare("PRAGMA est_count(\"%w\",%g)", zTabIdx, ((double)i)/(double)(N_CNT_SAMPLE)); if( sqlite3_step(pStmt)==SQLITE_ROW ){ sum += sqlite3_column_double(pStmt, 0); n++; } sqlite3_finalize(pStmt); } return n==0 ? 0 : (sqlite3_int64)(sum/n); } /* ** Compare the i-th column of pStmt against pValue. Return true if they ** are different. */ static int columnNotEqual(sqlite3_stmt *pStmt, int i, sqlite3_value *pValue){ int n1, n2, n; if( sqlite3_column_type(pStmt,i)!=sqlite3_value_type(pValue) ) return 1; switch( sqlite3_column_type(pStmt,i) ){ case SQLITE_NULL: return 0; /* Nulls compare equal to one another in this context */ case SQLITE_INTEGER: return sqlite3_column_int64(pStmt,i)!=sqlite3_value_int64(pValue); case SQLITE_FLOAT: return sqlite3_column_double(pStmt,i)!=sqlite3_value_double(pValue); case SQLITE_BLOB: n1 = sqlite3_column_bytes(pStmt,i); n2 = sqlite3_value_bytes(pValue); n = n110000 ? 100 : 20000; pStmt = db_prepare("PRAGMA btree_sample(\"%w\",0.0,%lld)", zIdx, n*2); for(i=0; i0" " AND name NOT LIKE 'sqlite_%%'" " ORDER BY name"); while( sqlite3_step(pStmt)==SQLITE_ROW ){ const char *zName = (const char*)sqlite3_column_text(pStmt, 0); analyzeTable(zName); } sqlite3_finalize(pStmt); dump_table("temp.est_stat1","sqlite_stat1"); sqlite3_close(g.db); return 0; }