/* ** This routine is called once for each row in the result table. Its job ** is to fill in the TabResult structure appropriately, allocating new ** memory as necessary. */ static public int sqlite3_get_table_cb( object pArg, i64 nCol, object Oargv, object Ocolv ) { string[] argv = (string[])Oargv; string[]colv = (string[])Ocolv; TabResult p = (TabResult)pArg; int need; int i; string z; /* Make sure there is enough space in p.azResult to hold everything ** we need to remember from this invocation of the callback. */ if( p.nRow==0 && argv!=null ){ need = (int)nCol*2; }else{ need = (int)nCol; } if( p.nData + need >= p.nAlloc ){ string[] azNew; p.nAlloc = p.nAlloc*2 + need + 1; azNew = new string[p.nAlloc];//sqlite3_realloc( p.azResult, sizeof(char*)*p.nAlloc ); if( azNew==null ) goto malloc_failed; p.azResult = azNew; } /* If this is the first row, then generate an extra row containing ** the names of all columns. */ if( p.nRow==0 ){ p.nColumn = (int)nCol; for(i=0; i<nCol; i++){ z = sqlite3_mprintf("%s", colv[i]); if( z==null ) goto malloc_failed; p.azResult[p.nData++ -1] = z; } }else if( p.nColumn!=nCol ){ //sqlite3_free(ref p.zErrMsg); p.zErrMsg = sqlite3_mprintf( "sqlite3_get_table() called with two or more incompatible queries" ); p.rc = SQLITE_ERROR; return 1; } /* Copy over the row data */ if( argv!=null ){ for(i=0; i<nCol; i++){ if( argv[i]==null ){ z = null; }else{ int n = sqlite3Strlen30(argv[i])+1; //z = sqlite3_malloc( n ); //if( z==0 ) goto malloc_failed; z= argv[i];//memcpy(z, argv[i], n); } p.azResult[p.nData++ -1] = z; } p.nRow++; } return 0; malloc_failed: p.rc = SQLITE_NOMEM; return 1; }
/* ** pCur points at an index entry created using the OP_MakeRecord opcode. ** Read the rowid (the last field in the record) and store it in *rowid. ** Return SQLITE_OK if everything works, or an error code otherwise. ** ** pCur might be pointing to text obtained from a corrupt database file. ** So the content cannot be trusted. Do appropriate checks on the content. */ static int sqlite3VdbeIdxRowid( sqlite3 db, BtCursor pCur, ref i64 rowid ) { i64 nCellKey = 0; int rc; u32 szHdr = 0; /* Size of the header */ u32 typeRowid = 0; /* Serial type of the rowid */ u32 lenRowid; /* Size of the rowid */ Mem m = null; Mem v = null; v = sqlite3Malloc( v ); UNUSED_PARAMETER( db ); /* Get the size of the index entry. Only indices entries of less ** than 2GiB are support - anything large must be database corruption. ** Any corruption is detected in sqlite3BtreeParseCellPtr(), though, so ** this code can safely assume that nCellKey is 32-bits */ Debug.Assert( sqlite3BtreeCursorIsValid( pCur ) ); rc = sqlite3BtreeKeySize( pCur, ref nCellKey ); Debug.Assert( rc == SQLITE_OK ); /* pCur is always valid so KeySize cannot fail */ Debug.Assert( ( (u32)nCellKey & SQLITE_MAX_U32 ) == (u64)nCellKey ); /* Read in the complete content of the index entry */ m = sqlite3Malloc( m ); // memset(&m, 0, sizeof(m)); rc = sqlite3VdbeMemFromBtree( pCur, 0, (int)nCellKey, true, m ); if ( rc != 0 ) { return rc; } /* The index entry must begin with a header size */ getVarint32( m.zBLOB, 0, ref szHdr ); testcase( szHdr == 3 ); testcase( szHdr == m.n ); if ( unlikely( szHdr < 3 || (int)szHdr > m.n ) ) { goto idx_rowid_corruption; } /* The last field of the index should be an integer - the ROWID. ** Verify that the last entry really is an integer. */ getVarint32( m.zBLOB, szHdr - 1, ref typeRowid ); testcase( typeRowid == 1 ); testcase( typeRowid == 2 ); testcase( typeRowid == 3 ); testcase( typeRowid == 4 ); testcase( typeRowid == 5 ); testcase( typeRowid == 6 ); testcase( typeRowid == 8 ); testcase( typeRowid == 9 ); if ( unlikely( typeRowid < 1 || typeRowid > 9 || typeRowid == 7 ) ) { goto idx_rowid_corruption; } lenRowid = (u32)sqlite3VdbeSerialTypeLen( typeRowid ); testcase( (u32)m.n == szHdr + lenRowid ); if ( unlikely( (u32)m.n < szHdr + lenRowid ) ) { goto idx_rowid_corruption; } /* Fetch the integer off the end of the index record */ sqlite3VdbeSerialGet( m.zBLOB, (int)( m.n - lenRowid ), typeRowid, v ); rowid = v.u.i; sqlite3VdbeMemRelease( m ); return SQLITE_OK; /* Jump here if database corruption is detected after m has been ** allocated. Free the m object and return SQLITE_CORRUPT. */ idx_rowid_corruption: //testcase( m.zMalloc != 0 ); sqlite3VdbeMemRelease( m ); return SQLITE_CORRUPT_BKPT(); }
//P4_INT64 static int sqlite3VdbeAddOp4( Vdbe p, int op, int p1, int p2, int p3, i64 pP4, int p4type ) { union_p4 _p4 = new union_p4(); _p4.pI64 = pP4; int addr = sqlite3VdbeAddOp3( p, op, p1, p2, p3 ); sqlite3VdbeChangeP4( p, addr, _p4, p4type ); return addr; }
static i64 refNULL = 0; //Dummy for C# ref NULL static int checkTreePage( IntegrityCk pCheck, /* Context for the sanity check */ int iPage, /* Page number of the page to check */ string zParentContext, /* Parent context */ ref i64 pnParentMinKey, ref i64 pnParentMaxKey, object _pnParentMinKey, /* C# Needed to determine if content passed*/ object _pnParentMaxKey /* C# Needed to determine if content passed*/ ) { MemPage pPage = new MemPage(); int i, rc, depth, d2, pgno, cnt; int hdr, cellStart; int nCell; u8[] data; BtShared pBt; int usableSize; StringBuilder zContext = new StringBuilder(100); byte[] hit = null; i64 nMinKey = 0; i64 nMaxKey = 0; sqlite3_snprintf(200, zContext, "Page %d: ", iPage); /* Check that the page exists */ pBt = pCheck.pBt; usableSize = (int)pBt.usableSize; if (iPage == 0) { return(0); } if (checkRef(pCheck, (u32)iPage, zParentContext) != 0) { return(0); } if ((rc = btreeGetPage(pBt, (Pgno)iPage, ref pPage, 0)) != 0) { checkAppendMsg(pCheck, zContext.ToString(), "unable to get the page. error code=%d", rc); return(0); } /* Clear MemPage.isInit to make sure the corruption detection code in ** btreeInitPage() is executed. */ pPage.isInit = 0; if ((rc = btreeInitPage(pPage)) != 0) { Debug.Assert(rc == SQLITE_CORRUPT); /* The only possible error from InitPage */ checkAppendMsg(pCheck, zContext.ToString(), "btreeInitPage() returns error code %d", rc); releasePage(pPage); return(0); } /* Check out all the cells. */ depth = 0; for (i = 0; i < pPage.nCell && pCheck.mxErr != 0; i++) { u8[] pCell; u32 sz; CellInfo info = new CellInfo(); /* Check payload overflow pages */ sqlite3_snprintf(200, zContext, "On tree page %d cell %d: ", iPage, i); int iCell = findCell(pPage, i); //pCell = findCell( pPage, i ); pCell = pPage.aData; btreeParseCellPtr(pPage, iCell, ref info); //btreeParseCellPtr( pPage, pCell, info ); sz = info.nData; if (0 == pPage.intKey) { sz += (u32)info.nKey; } /* For intKey pages, check that the keys are in order. */ else if (i == 0) { nMinKey = nMaxKey = info.nKey; } else { if (info.nKey <= nMaxKey) { checkAppendMsg(pCheck, zContext.ToString(), "Rowid %lld out of order (previous was %lld)", info.nKey, nMaxKey); } nMaxKey = info.nKey; } Debug.Assert(sz == info.nPayload); if ((sz > info.nLocal) //&& (pCell[info.iOverflow]<=&pPage.aData[pBt.usableSize]) ) { int nPage = (int)(sz - info.nLocal + usableSize - 5) / (usableSize - 4); Pgno pgnoOvfl = sqlite3Get4byte(pCell, iCell, info.iOverflow); #if !SQLITE_OMIT_AUTOVACUUM if (pBt.autoVacuum) { checkPtrmap(pCheck, pgnoOvfl, PTRMAP_OVERFLOW1, (u32)iPage, zContext.ToString()); } #endif checkList(pCheck, 0, (int)pgnoOvfl, nPage, zContext.ToString()); } /* Check sanity of left child page. */ if (0 == pPage.leaf) { pgno = (int)sqlite3Get4byte(pCell, iCell); //sqlite3Get4byte( pCell ); #if !SQLITE_OMIT_AUTOVACUUM if (pBt.autoVacuum) { checkPtrmap(pCheck, (u32)pgno, PTRMAP_BTREE, (u32)iPage, zContext.ToString()); } #endif if (i == 0) { d2 = checkTreePage(pCheck, pgno, zContext.ToString(), ref nMinKey, ref refNULL, pCheck, null); } else { d2 = checkTreePage(pCheck, pgno, zContext.ToString(), ref nMinKey, ref nMaxKey, pCheck, pCheck); } if (i > 0 && d2 != depth) { checkAppendMsg(pCheck, zContext, "Child page depth differs"); } depth = d2; } } if (0 == pPage.leaf) { pgno = (int)sqlite3Get4byte(pPage.aData, pPage.hdrOffset + 8); sqlite3_snprintf(200, zContext, "On page %d at right child: ", iPage); #if !SQLITE_OMIT_AUTOVACUUM if (pBt.autoVacuum) { checkPtrmap(pCheck, (u32)pgno, PTRMAP_BTREE, (u32)iPage, zContext.ToString()); } #endif // checkTreePage(pCheck, pgno, zContext, NULL, !pPage->nCell ? NULL : &nMaxKey); if (0 == pPage.nCell) { checkTreePage(pCheck, pgno, zContext.ToString(), ref refNULL, ref refNULL, null, null); } else { checkTreePage(pCheck, pgno, zContext.ToString(), ref refNULL, ref nMaxKey, null, pCheck); } } /* For intKey leaf pages, check that the min/max keys are in order ** with any left/parent/right pages. */ if (pPage.leaf != 0 && pPage.intKey != 0) { /* if we are a left child page */ if (_pnParentMinKey != null) { /* if we are the left most child page */ if (_pnParentMaxKey == null) { if (nMaxKey > pnParentMinKey) { checkAppendMsg(pCheck, zContext, "Rowid %lld out of order (max larger than parent min of %lld)", nMaxKey, pnParentMinKey); } } else { if (nMinKey <= pnParentMinKey) { checkAppendMsg(pCheck, zContext, "Rowid %lld out of order (min less than parent min of %lld)", nMinKey, pnParentMinKey); } if (nMaxKey > pnParentMaxKey) { checkAppendMsg(pCheck, zContext, "Rowid %lld out of order (max larger than parent max of %lld)", nMaxKey, pnParentMaxKey); } pnParentMinKey = nMaxKey; } /* else if we're a right child page */ } else if (_pnParentMaxKey != null) { if (nMinKey <= pnParentMaxKey) { checkAppendMsg(pCheck, zContext, "Rowid %lld out of order (min less than parent max of %lld)", nMinKey, pnParentMaxKey); } } } /* Check for complete coverage of the page */ data = pPage.aData; hdr = pPage.hdrOffset; hit = sqlite3Malloc(pBt.pageSize); //if( hit==null ){ // pCheck.mallocFailed = 1; //}else { int contentOffset = get2byteNotZero(data, hdr + 5); Debug.Assert(contentOffset <= usableSize); /* Enforced by btreeInitPage() */ Array.Clear(hit, contentOffset, usableSize - contentOffset); //memset(hit+contentOffset, 0, usableSize-contentOffset); for (int iLoop = contentOffset - 1; iLoop >= 0; iLoop--) { hit[iLoop] = 1;//memset(hit, 1, contentOffset); } nCell = get2byte(data, hdr + 3); cellStart = hdr + 12 - 4 * pPage.leaf; for (i = 0; i < nCell; i++) { int pc = get2byte(data, cellStart + i * 2); u32 size = 65536; int j; if (pc <= usableSize - 4) { size = cellSizePtr(pPage, data, pc); } if ((int)(pc + size - 1) >= usableSize) { checkAppendMsg(pCheck, "", "Corruption detected in cell %d on page %d", i, iPage); } else { for (j = (int)(pc + size - 1); j >= pc; j--) { hit[j]++; } } } i = get2byte(data, hdr + 1); while (i > 0) { int size, j; Debug.Assert(i <= usableSize - 4); /* Enforced by btreeInitPage() */ size = get2byte(data, i + 2); Debug.Assert(i + size <= usableSize); /* Enforced by btreeInitPage() */ for (j = i + size - 1; j >= i; j--) { hit[j]++; } j = get2byte(data, i); Debug.Assert(j == 0 || j > i + size); /* Enforced by btreeInitPage() */ Debug.Assert(j <= usableSize - 4); /* Enforced by btreeInitPage() */ i = j; } for (i = cnt = 0; i < usableSize; i++) { if (hit[i] == 0) { cnt++; } else if (hit[i] > 1) { checkAppendMsg(pCheck, "", "Multiple uses for byte %d of page %d", i, iPage); break; } } if (cnt != data[hdr + 7]) { checkAppendMsg(pCheck, "", "Fragmentation of %d bytes reported as %d on page %d", cnt, data[hdr + 7], iPage); } } sqlite3PageFree(ref hit); releasePage(pPage); return(depth + 1); }