btreeinfo.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431
  1. /*
  2. ** 2017-10-24
  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 file contains an implementation of the "sqlite_btreeinfo" virtual table.
  14. **
  15. ** The sqlite_btreeinfo virtual table is a read-only eponymous-only virtual
  16. ** table that shows information about all btrees in an SQLite database file.
  17. ** The schema is like this:
  18. **
  19. ** CREATE TABLE sqlite_btreeinfo(
  20. ** type TEXT, -- "table" or "index"
  21. ** name TEXT, -- Name of table or index for this btree.
  22. ** tbl_name TEXT, -- Associated table
  23. ** rootpage INT, -- The root page of the btree
  24. ** sql TEXT, -- SQL for this btree - from sqlite_schema
  25. ** hasRowid BOOLEAN, -- True if the btree has a rowid
  26. ** nEntry INT, -- Estimated number of entries
  27. ** nPage INT, -- Estimated number of pages
  28. ** depth INT, -- Depth of the btree
  29. ** szPage INT, -- Size of each page in bytes
  30. ** zSchema TEXT HIDDEN -- The schema to which this btree belongs
  31. ** );
  32. **
  33. ** The first 5 fields are taken directly from the sqlite_schema table.
  34. ** Considering only the first 5 fields, the only difference between
  35. ** this virtual table and the sqlite_schema table is that this virtual
  36. ** table omits all entries that have a 0 or NULL rowid - in other words
  37. ** it omits triggers and views.
  38. **
  39. ** The value added by this table comes in the next 5 fields.
  40. **
  41. ** Note that nEntry and nPage are *estimated*. They are computed doing
  42. ** a single search from the root to a leaf, counting the number of cells
  43. ** at each level, and assuming that unvisited pages have a similar number
  44. ** of cells.
  45. **
  46. ** The sqlite_dbpage virtual table must be available for this virtual table
  47. ** to operate.
  48. **
  49. ** USAGE EXAMPLES:
  50. **
  51. ** Show the table btrees in a schema order with the tables with the most
  52. ** rows occuring first:
  53. **
  54. ** SELECT name, nEntry
  55. ** FROM sqlite_btreeinfo
  56. ** WHERE type='table'
  57. ** ORDER BY nEntry DESC, name;
  58. **
  59. ** Show the names of all WITHOUT ROWID tables:
  60. **
  61. ** SELECT name FROM sqlite_btreeinfo
  62. ** WHERE type='table' AND NOT hasRowid;
  63. */
  64. #if !defined(SQLITEINT_H)
  65. #include "sqlite3ext.h"
  66. #endif
  67. SQLITE_EXTENSION_INIT1
  68. #include <string.h>
  69. #include <assert.h>
  70. /* Columns available in this virtual table */
  71. #define BINFO_COLUMN_TYPE 0
  72. #define BINFO_COLUMN_NAME 1
  73. #define BINFO_COLUMN_TBL_NAME 2
  74. #define BINFO_COLUMN_ROOTPAGE 3
  75. #define BINFO_COLUMN_SQL 4
  76. #define BINFO_COLUMN_HASROWID 5
  77. #define BINFO_COLUMN_NENTRY 6
  78. #define BINFO_COLUMN_NPAGE 7
  79. #define BINFO_COLUMN_DEPTH 8
  80. #define BINFO_COLUMN_SZPAGE 9
  81. #define BINFO_COLUMN_SCHEMA 10
  82. /* Forward declarations */
  83. typedef struct BinfoTable BinfoTable;
  84. typedef struct BinfoCursor BinfoCursor;
  85. /* A cursor for the sqlite_btreeinfo table */
  86. struct BinfoCursor {
  87. sqlite3_vtab_cursor base; /* Base class. Must be first */
  88. sqlite3_stmt *pStmt; /* Query against sqlite_schema */
  89. int rc; /* Result of previous sqlite_step() call */
  90. int hasRowid; /* hasRowid value. Negative if unknown. */
  91. sqlite3_int64 nEntry; /* nEntry value */
  92. int nPage; /* nPage value */
  93. int depth; /* depth value */
  94. int szPage; /* size of a btree page. 0 if unknown */
  95. char *zSchema; /* Schema being interrogated */
  96. };
  97. /* The sqlite_btreeinfo table */
  98. struct BinfoTable {
  99. sqlite3_vtab base; /* Base class. Must be first */
  100. sqlite3 *db; /* The databse connection */
  101. };
  102. /*
  103. ** Connect to the sqlite_btreeinfo virtual table.
  104. */
  105. static int binfoConnect(
  106. sqlite3 *db,
  107. void *pAux,
  108. int argc, const char *const*argv,
  109. sqlite3_vtab **ppVtab,
  110. char **pzErr
  111. ){
  112. BinfoTable *pTab = 0;
  113. int rc = SQLITE_OK;
  114. rc = sqlite3_declare_vtab(db,
  115. "CREATE TABLE x(\n"
  116. " type TEXT,\n"
  117. " name TEXT,\n"
  118. " tbl_name TEXT,\n"
  119. " rootpage INT,\n"
  120. " sql TEXT,\n"
  121. " hasRowid BOOLEAN,\n"
  122. " nEntry INT,\n"
  123. " nPage INT,\n"
  124. " depth INT,\n"
  125. " szPage INT,\n"
  126. " zSchema TEXT HIDDEN\n"
  127. ")");
  128. if( rc==SQLITE_OK ){
  129. pTab = (BinfoTable *)sqlite3_malloc64(sizeof(BinfoTable));
  130. if( pTab==0 ) rc = SQLITE_NOMEM;
  131. }
  132. assert( rc==SQLITE_OK || pTab==0 );
  133. if( pTab ){
  134. pTab->db = db;
  135. }
  136. *ppVtab = (sqlite3_vtab*)pTab;
  137. return rc;
  138. }
  139. /*
  140. ** Disconnect from or destroy a btreeinfo virtual table.
  141. */
  142. static int binfoDisconnect(sqlite3_vtab *pVtab){
  143. sqlite3_free(pVtab);
  144. return SQLITE_OK;
  145. }
  146. /*
  147. ** idxNum:
  148. **
  149. ** 0 Use "main" for the schema
  150. ** 1 Schema identified by parameter ?1
  151. */
  152. static int binfoBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
  153. int i;
  154. pIdxInfo->estimatedCost = 10000.0; /* Cost estimate */
  155. pIdxInfo->estimatedRows = 100;
  156. for(i=0; i<pIdxInfo->nConstraint; i++){
  157. struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[i];
  158. if( p->usable
  159. && p->iColumn==BINFO_COLUMN_SCHEMA
  160. && p->op==SQLITE_INDEX_CONSTRAINT_EQ
  161. ){
  162. pIdxInfo->estimatedCost = 1000.0;
  163. pIdxInfo->idxNum = 1;
  164. pIdxInfo->aConstraintUsage[i].argvIndex = 1;
  165. pIdxInfo->aConstraintUsage[i].omit = 1;
  166. break;
  167. }
  168. }
  169. return SQLITE_OK;
  170. }
  171. /*
  172. ** Open a new btreeinfo cursor.
  173. */
  174. static int binfoOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
  175. BinfoCursor *pCsr;
  176. pCsr = (BinfoCursor *)sqlite3_malloc64(sizeof(BinfoCursor));
  177. if( pCsr==0 ){
  178. return SQLITE_NOMEM;
  179. }else{
  180. memset(pCsr, 0, sizeof(BinfoCursor));
  181. pCsr->base.pVtab = pVTab;
  182. }
  183. *ppCursor = (sqlite3_vtab_cursor *)pCsr;
  184. return SQLITE_OK;
  185. }
  186. /*
  187. ** Close a btreeinfo cursor.
  188. */
  189. static int binfoClose(sqlite3_vtab_cursor *pCursor){
  190. BinfoCursor *pCsr = (BinfoCursor *)pCursor;
  191. sqlite3_finalize(pCsr->pStmt);
  192. sqlite3_free(pCsr->zSchema);
  193. sqlite3_free(pCsr);
  194. return SQLITE_OK;
  195. }
  196. /*
  197. ** Move a btreeinfo cursor to the next entry in the file.
  198. */
  199. static int binfoNext(sqlite3_vtab_cursor *pCursor){
  200. BinfoCursor *pCsr = (BinfoCursor *)pCursor;
  201. pCsr->rc = sqlite3_step(pCsr->pStmt);
  202. pCsr->hasRowid = -1;
  203. return pCsr->rc==SQLITE_ERROR ? SQLITE_ERROR : SQLITE_OK;
  204. }
  205. /* We have reached EOF if previous sqlite3_step() returned
  206. ** anything other than SQLITE_ROW;
  207. */
  208. static int binfoEof(sqlite3_vtab_cursor *pCursor){
  209. BinfoCursor *pCsr = (BinfoCursor *)pCursor;
  210. return pCsr->rc!=SQLITE_ROW;
  211. }
  212. /* Position a cursor back to the beginning.
  213. */
  214. static int binfoFilter(
  215. sqlite3_vtab_cursor *pCursor,
  216. int idxNum, const char *idxStr,
  217. int argc, sqlite3_value **argv
  218. ){
  219. BinfoCursor *pCsr = (BinfoCursor *)pCursor;
  220. BinfoTable *pTab = (BinfoTable *)pCursor->pVtab;
  221. char *zSql;
  222. int rc;
  223. sqlite3_free(pCsr->zSchema);
  224. if( idxNum==1 && sqlite3_value_type(argv[0])!=SQLITE_NULL ){
  225. pCsr->zSchema = sqlite3_mprintf("%s", sqlite3_value_text(argv[0]));
  226. }else{
  227. pCsr->zSchema = sqlite3_mprintf("main");
  228. }
  229. zSql = sqlite3_mprintf(
  230. "SELECT 0, 'table','sqlite_schema','sqlite_schema',1,NULL "
  231. "UNION ALL "
  232. "SELECT rowid, type, name, tbl_name, rootpage, sql"
  233. " FROM \"%w\".sqlite_schema WHERE rootpage>=1",
  234. pCsr->zSchema);
  235. sqlite3_finalize(pCsr->pStmt);
  236. pCsr->pStmt = 0;
  237. pCsr->hasRowid = -1;
  238. rc = sqlite3_prepare_v2(pTab->db, zSql, -1, &pCsr->pStmt, 0);
  239. sqlite3_free(zSql);
  240. if( rc==SQLITE_OK ){
  241. rc = binfoNext(pCursor);
  242. }
  243. return rc;
  244. }
  245. /* Decode big-endian integers */
  246. static unsigned int get_uint16(unsigned char *a){
  247. return (a[0]<<8)|a[1];
  248. }
  249. static unsigned int get_uint32(unsigned char *a){
  250. return (a[0]<<24)|(a[1]<<16)|(a[2]<<8)|a[3];
  251. }
  252. /* Examine the b-tree rooted at pgno and estimate its size.
  253. ** Return non-zero if anything goes wrong.
  254. */
  255. static int binfoCompute(sqlite3 *db, int pgno, BinfoCursor *pCsr){
  256. sqlite3_int64 nEntry = 1;
  257. int nPage = 1;
  258. unsigned char *aData;
  259. sqlite3_stmt *pStmt = 0;
  260. int rc = SQLITE_OK;
  261. int pgsz = 0;
  262. int nCell;
  263. int iCell;
  264. rc = sqlite3_prepare_v2(db,
  265. "SELECT data FROM sqlite_dbpage('main') WHERE pgno=?1", -1,
  266. &pStmt, 0);
  267. if( rc ) return rc;
  268. pCsr->depth = 1;
  269. while(1){
  270. sqlite3_bind_int(pStmt, 1, pgno);
  271. rc = sqlite3_step(pStmt);
  272. if( rc!=SQLITE_ROW ){
  273. rc = SQLITE_ERROR;
  274. break;
  275. }
  276. pCsr->szPage = pgsz = sqlite3_column_bytes(pStmt, 0);
  277. aData = (unsigned char*)sqlite3_column_blob(pStmt, 0);
  278. if( aData==0 ){
  279. rc = SQLITE_NOMEM;
  280. break;
  281. }
  282. if( pgno==1 ){
  283. aData += 100;
  284. pgsz -= 100;
  285. }
  286. pCsr->hasRowid = aData[0]!=2 && aData[0]!=10;
  287. nCell = get_uint16(aData+3);
  288. nEntry *= (nCell+1);
  289. if( aData[0]==10 || aData[0]==13 ) break;
  290. nPage *= (nCell+1);
  291. if( nCell<=1 ){
  292. pgno = get_uint32(aData+8);
  293. }else{
  294. iCell = get_uint16(aData+12+2*(nCell/2));
  295. if( pgno==1 ) iCell -= 100;
  296. if( iCell<=12 || iCell>=pgsz-4 ){
  297. rc = SQLITE_CORRUPT;
  298. break;
  299. }
  300. pgno = get_uint32(aData+iCell);
  301. }
  302. pCsr->depth++;
  303. sqlite3_reset(pStmt);
  304. }
  305. sqlite3_finalize(pStmt);
  306. pCsr->nPage = nPage;
  307. pCsr->nEntry = nEntry;
  308. if( rc==SQLITE_ROW ) rc = SQLITE_OK;
  309. return rc;
  310. }
  311. /* Return a column for the sqlite_btreeinfo table */
  312. static int binfoColumn(
  313. sqlite3_vtab_cursor *pCursor,
  314. sqlite3_context *ctx,
  315. int i
  316. ){
  317. BinfoCursor *pCsr = (BinfoCursor *)pCursor;
  318. if( i>=BINFO_COLUMN_HASROWID && i<=BINFO_COLUMN_SZPAGE && pCsr->hasRowid<0 ){
  319. int pgno = sqlite3_column_int(pCsr->pStmt, BINFO_COLUMN_ROOTPAGE+1);
  320. sqlite3 *db = sqlite3_context_db_handle(ctx);
  321. int rc = binfoCompute(db, pgno, pCsr);
  322. if( rc ){
  323. pCursor->pVtab->zErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(db));
  324. return SQLITE_ERROR;
  325. }
  326. }
  327. switch( i ){
  328. case BINFO_COLUMN_NAME:
  329. case BINFO_COLUMN_TYPE:
  330. case BINFO_COLUMN_TBL_NAME:
  331. case BINFO_COLUMN_ROOTPAGE:
  332. case BINFO_COLUMN_SQL: {
  333. sqlite3_result_value(ctx, sqlite3_column_value(pCsr->pStmt, i+1));
  334. break;
  335. }
  336. case BINFO_COLUMN_HASROWID: {
  337. sqlite3_result_int(ctx, pCsr->hasRowid);
  338. break;
  339. }
  340. case BINFO_COLUMN_NENTRY: {
  341. sqlite3_result_int64(ctx, pCsr->nEntry);
  342. break;
  343. }
  344. case BINFO_COLUMN_NPAGE: {
  345. sqlite3_result_int(ctx, pCsr->nPage);
  346. break;
  347. }
  348. case BINFO_COLUMN_DEPTH: {
  349. sqlite3_result_int(ctx, pCsr->depth);
  350. break;
  351. }
  352. case BINFO_COLUMN_SCHEMA: {
  353. sqlite3_result_text(ctx, pCsr->zSchema, -1, SQLITE_STATIC);
  354. break;
  355. }
  356. }
  357. return SQLITE_OK;
  358. }
  359. /* Return the ROWID for the sqlite_btreeinfo table */
  360. static int binfoRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
  361. BinfoCursor *pCsr = (BinfoCursor *)pCursor;
  362. *pRowid = sqlite3_column_int64(pCsr->pStmt, 0);
  363. return SQLITE_OK;
  364. }
  365. /*
  366. ** Invoke this routine to register the "sqlite_btreeinfo" virtual table module
  367. */
  368. int sqlite3BinfoRegister(sqlite3 *db){
  369. static sqlite3_module binfo_module = {
  370. 0, /* iVersion */
  371. 0, /* xCreate */
  372. binfoConnect, /* xConnect */
  373. binfoBestIndex, /* xBestIndex */
  374. binfoDisconnect, /* xDisconnect */
  375. 0, /* xDestroy */
  376. binfoOpen, /* xOpen - open a cursor */
  377. binfoClose, /* xClose - close a cursor */
  378. binfoFilter, /* xFilter - configure scan constraints */
  379. binfoNext, /* xNext - advance a cursor */
  380. binfoEof, /* xEof - check for end of scan */
  381. binfoColumn, /* xColumn - read data */
  382. binfoRowid, /* xRowid - read data */
  383. 0, /* xUpdate */
  384. 0, /* xBegin */
  385. 0, /* xSync */
  386. 0, /* xCommit */
  387. 0, /* xRollback */
  388. 0, /* xFindMethod */
  389. 0, /* xRename */
  390. 0, /* xSavepoint */
  391. 0, /* xRelease */
  392. 0, /* xRollbackTo */
  393. 0, /* xShadowName */
  394. 0 /* xIntegrity */
  395. };
  396. return sqlite3_create_module(db, "sqlite_btreeinfo", &binfo_module, 0);
  397. }
  398. #ifdef _WIN32
  399. __declspec(dllexport)
  400. #endif
  401. int sqlite3_btreeinfo_init(
  402. sqlite3 *db,
  403. char **pzErrMsg,
  404. const sqlite3_api_routines *pApi
  405. ){
  406. SQLITE_EXTENSION_INIT2(pApi);
  407. return sqlite3BinfoRegister(db);
  408. }