void test_1b_2(void) { int rc; chidb *db; MemPage *page; uint8_t *rawpage; remove(NEWFILE); db = malloc(sizeof(chidb)); rc = chidb_Btree_open(NEWFILE, db, &db->bt); CU_ASSERT(rc == CHIDB_OK); rc = chidb_Pager_readPage(db->bt->pager, 1, &page); CU_ASSERT(rc == CHIDB_OK); rawpage = page->data; if (strcmp((char *) rawpage, "SQLite format 3") || rawpage[18] != 1 || rawpage[19] != 1 || rawpage[20] != 0 || rawpage[21] != 64 || rawpage[22] != 32 || rawpage[23] != 32 || get4byte(&rawpage[32]) != 0 || get4byte(&rawpage[36]) != 0 || get4byte(&rawpage[44]) != 1 || get4byte(&rawpage[52]) != 0 || get4byte(&rawpage[56]) != 1 || get4byte(&rawpage[64]) != 0 || get4byte(&rawpage[48]) != 20000) CU_FAIL("File header is not well-formed."); if (rawpage[100] != PGTYPE_TABLE_LEAF || get2byte(&rawpage[101]) != 108 || get2byte(&rawpage[103]) != 0 || get2byte(&rawpage[105]) != 1024 || rawpage[107] != 0) CU_FAIL("Page 1 header is not well-formed."); rc = chidb_Btree_close(db->bt); remove(NEWFILE); free(db); }
void test_2_3(void) { chidb *db; BTreeNode *btn; db = malloc(sizeof(chidb)); chidb_Btree_open(TESTFILE_1, db, &db->bt); chidb_Btree_getNodeByPage(db->bt, 2, &btn); btn_sanity_check(db->bt, btn, false); CU_ASSERT(btn->page->npage == 2); CU_ASSERT(btn->type == PGTYPE_TABLE_LEAF); CU_ASSERT(btn->n_cells == 4); CU_ASSERT(btn->free_offset == 16); CU_ASSERT(btn->cells_offset == 480); CU_ASSERT(get2byte(&btn->celloffset_array[0]) == 888); CU_ASSERT(get2byte(&btn->celloffset_array[2]) == 752); CU_ASSERT(get2byte(&btn->celloffset_array[4]) == 616); CU_ASSERT(get2byte(&btn->celloffset_array[6]) == 480); chidb_Btree_freeMemNode(db->bt, btn); chidb_Btree_close(db->bt); free(db); }
void test_2_2(void) { chidb *db; BTreeNode *btn; db = malloc(sizeof(chidb)); chidb_Btree_open(TESTFILE_1, db, &db->bt); chidb_Btree_getNodeByPage(db->bt, 1, &btn); btn_sanity_check(db->bt, btn, false); CU_ASSERT(btn->page->npage == 1); CU_ASSERT(btn->type == PGTYPE_TABLE_INTERNAL); CU_ASSERT(btn->n_cells == 3); CU_ASSERT(btn->right_page == 2); CU_ASSERT(btn->free_offset == 118); CU_ASSERT(btn->cells_offset == 1000); CU_ASSERT(get2byte(&btn->celloffset_array[0]) == 1008); CU_ASSERT(get2byte(&btn->celloffset_array[2]) == 1016); CU_ASSERT(get2byte(&btn->celloffset_array[4]) == 1000); chidb_Btree_freeMemNode(db->bt, btn); chidb_Btree_close(db->bt); free(db); }
void btn_sanity_check(BTree *bt, BTreeNode *btn, bool empty) { CU_ASSERT_FATAL(btn->page->npage >= 1); int header_offset = btn->page->npage==1? 100:0; CU_ASSERT_FATAL(btn->type == PGTYPE_TABLE_INTERNAL || btn->type == PGTYPE_TABLE_LEAF || btn->type == PGTYPE_INDEX_INTERNAL || btn->type == PGTYPE_INDEX_LEAF); CU_ASSERT_FATAL(btn->n_cells >= 0); switch (btn->type) { case PGTYPE_TABLE_INTERNAL: case PGTYPE_INDEX_INTERNAL: CU_ASSERT_FATAL(btn->free_offset == header_offset + INTPG_CELLSOFFSET_OFFSET + (btn->n_cells * 2)); CU_ASSERT_FATAL(btn->celloffset_array == btn->page->data + header_offset + INTPG_CELLSOFFSET_OFFSET); break; case PGTYPE_TABLE_LEAF: case PGTYPE_INDEX_LEAF: CU_ASSERT_FATAL(btn->free_offset == header_offset + LEAFPG_CELLSOFFSET_OFFSET + (btn->n_cells * 2)); CU_ASSERT_FATAL(btn->celloffset_array == btn->page->data + header_offset + LEAFPG_CELLSOFFSET_OFFSET); break; } CU_ASSERT_FATAL(btn->cells_offset >= btn->free_offset); CU_ASSERT_FATAL(btn->cells_offset <= bt->pager->page_size); for (int i=0; i<btn->n_cells; i++) { uint16_t cell_offset = get2byte(&btn->celloffset_array[i*2]); CU_ASSERT_FATAL(cell_offset >= btn->cells_offset); CU_ASSERT_FATAL(cell_offset <= bt->pager->page_size); } if (!empty && (btn->type == PGTYPE_TABLE_INTERNAL || btn->type == PGTYPE_INDEX_INTERNAL)) { CU_ASSERT_FATAL(btn->right_page > 1); CU_ASSERT_FATAL(btn->right_page <= bt->pager->n_pages); } }
static int statDecodePage(Btree *pBt, StatPage *p){ int nUnused; int iOff; int nHdr; int isLeaf; int szPage; u8 *aData = sqlite3PagerGetData(p->pPg); u8 *aHdr = &aData[p->iPgno==1 ? 100 : 0]; p->flags = aHdr[0]; p->nCell = get2byte(&aHdr[3]); p->nMxPayload = 0; isLeaf = (p->flags==0x0A || p->flags==0x0D); nHdr = 12 - isLeaf*4 + (p->iPgno==1)*100; nUnused = get2byte(&aHdr[5]) - nHdr - 2*p->nCell; nUnused += (int)aHdr[7]; iOff = get2byte(&aHdr[1]); while( iOff ){ nUnused += get2byte(&aData[iOff+2]); iOff = get2byte(&aData[iOff]); } p->nUnused = nUnused; p->iRightChildPg = isLeaf ? 0 : sqlite3Get4byte(&aHdr[8]); szPage = sqlite3BtreeGetPageSize(pBt); if( p->nCell ){ int i; /* Used to iterate through cells */ int nUsable; /* Usable bytes per page */ sqlite3BtreeEnter(pBt); nUsable = szPage - sqlite3BtreeGetReserveNoMutex(pBt); sqlite3BtreeLeave(pBt); p->aCell = sqlite3_malloc64((p->nCell+1) * sizeof(StatCell)); if( p->aCell==0 ) return SQLITE_NOMEM_BKPT; memset(p->aCell, 0, (p->nCell+1) * sizeof(StatCell)); for(i=0; i<p->nCell; i++){ StatCell *pCell = &p->aCell[i]; iOff = get2byte(&aData[nHdr+i*2]); if( !isLeaf ){ pCell->iChildPg = sqlite3Get4byte(&aData[iOff]); iOff += 4; } if( p->flags==0x05 ){ /* A table interior node. nPayload==0. */ }else{ u32 nPayload; /* Bytes of payload total (local+overflow) */ int nLocal; /* Bytes of payload stored locally */ iOff += getVarint32(&aData[iOff], nPayload); if( p->flags==0x0D ){ u64 dummy; iOff += sqlite3GetVarint(&aData[iOff], &dummy); } if( nPayload>(u32)p->nMxPayload ) p->nMxPayload = nPayload; getLocalPayload(nUsable, p->flags, nPayload, &nLocal); pCell->nLocal = nLocal; assert( nLocal>=0 ); assert( nPayload>=(u32)nLocal ); assert( nLocal<=(nUsable-35) ); if( nPayload>(u32)nLocal ){ int j; int nOvfl = ((nPayload - nLocal) + nUsable-4 - 1) / (nUsable - 4); pCell->nLastOvfl = (nPayload-nLocal) - (nOvfl-1) * (nUsable-4); pCell->nOvfl = nOvfl; pCell->aOvfl = sqlite3_malloc64(sizeof(u32)*nOvfl); if( pCell->aOvfl==0 ) return SQLITE_NOMEM_BKPT; pCell->aOvfl[0] = sqlite3Get4byte(&aData[iOff+nLocal]); for(j=1; j<nOvfl; j++){ int rc; u32 iPrev = pCell->aOvfl[j-1]; DbPage *pPg = 0; rc = sqlite3PagerGet(sqlite3BtreePager(pBt), iPrev, &pPg, 0); if( rc!=SQLITE_OK ){ assert( pPg==0 ); return rc; } pCell->aOvfl[j] = sqlite3Get4byte(sqlite3PagerGetData(pPg)); sqlite3PagerUnref(pPg); } } } } } return SQLITE_OK; }