/* ** Decode a single doclist and display the results on stdout. */ static void decodeDoclist( const unsigned char *aData, /* Content to print */ int nData /* Number of bytes of content */ ) { sqlite3_int64 iPrevDocid = 0; sqlite3_int64 iDocid; sqlite3_int64 iPos; sqlite3_int64 iPrevPos = 0; sqlite3_int64 iCol; int i = 0; while( i<nData ) { i += getVarint(aData+i, &iDocid); printf("docid %lld col0", iDocid+iPrevDocid); iPrevDocid += iDocid; iPrevPos = 0; while( 1 ) { i += getVarint(aData+i, &iPos); if( iPos==1 ) { i += getVarint(aData+i, &iCol); printf(" col%lld", iCol); iPrevPos = 0; } else if( iPos==0 ) { printf("\n"); break; } else { iPrevPos += iPos - 2; printf(" %lld", iPrevPos); } } } }
static int leafCursorCellColInfo(RecoverLeafCursor *pCursor, unsigned iCol, u64 *piColType, unsigned char **ppBase, int *pbFree){ const unsigned char *pRecordHeader; u64 nRecordHeaderBytes; unsigned nRead; u64 iColEndOffset; unsigned nColsSkipped; u64 iSerialType; if( iCol>=pCursor->nRecordCols ){ *piColType = 0; if( ppBase ){ *ppBase = 0; *pbFree = 0; } return SQLITE_OK; } pRecordHeader = pCursor->pRecordHeader; if( !checkVarint(pRecordHeader, pCursor->nRecordHeaderBytes) ){ return SQLITE_CORRUPT; } nRead = getVarint(pRecordHeader, &nRecordHeaderBytes); assert( nRecordHeaderBytes==pCursor->nRecordHeaderBytes ); iColEndOffset = 0; nColsSkipped = 0; while( nColsSkipped<=iCol && nRead<nRecordHeaderBytes ){ if( !checkVarint(pRecordHeader + nRead, nRecordHeaderBytes - nRead) ){ return SQLITE_CORRUPT; } nRead += getVarint(pRecordHeader + nRead, &iSerialType); iColEndOffset += SerialTypeLength(iSerialType); nColsSkipped++; } if( nRecordHeaderBytes+iColEndOffset>pCursor->nRecordBytes ){ return SQLITE_CORRUPT; } *piColType = iSerialType; if( ppBase ){ const u32 nColBytes = SerialTypeLength(iSerialType); const unsigned iColOffset = nRecordHeaderBytes+iColEndOffset-nColBytes; return overflowGetSegment(pCursor->pPage, pCursor->iRecordOffset, pCursor->nLocalRecordBytes, pCursor->pOverflow, iColOffset, nColBytes, ppBase, pbFree); } return SQLITE_OK; }
static int getVarint32(const char *p, int *pi){ sqlite_int64 i; int ret = getVarint(p, &i); *pi = (int) i; assert( *pi==i ); return ret; }
/* Read the next docid. */ static sqlite_int64 readDocid(DocListReader *pReader){ sqlite_int64 ret; assert( !readerAtEnd(pReader) ); pReader->p += getVarint(pReader->p, &ret); pReader->iLastPos = 0; return ret; }
/* Show the content of the %_stat table */ static void showStat(sqlite3 *db, const char *zTab) { sqlite3_stmt *pStmt; pStmt = prepare(db, "SELECT id, value FROM '%q_stat'", zTab); while( sqlite3_step(pStmt)==SQLITE_ROW ) { printf("stat[%d] =", sqlite3_column_int(pStmt, 0)); switch( sqlite3_column_type(pStmt, 1) ) { case SQLITE_INTEGER: { printf(" %d\n", sqlite3_column_int(pStmt, 1)); break; } case SQLITE_BLOB: { unsigned char *x = (unsigned char*)sqlite3_column_blob(pStmt, 1); int len = sqlite3_column_bytes(pStmt, 1); int i = 0; sqlite3_int64 v; while( i<len ) { i += getVarint(x, &v); printf(" %lld", v); } printf("\n"); break; } } } sqlite3_finalize(pStmt); }
/* ** Decode a single segment block and display the results on stdout. */ static void decodeSegment( const unsigned char *aData, /* Content to print */ int nData /* Number of bytes of content */ ) { sqlite3_int64 iChild = 0; sqlite3_int64 iPrefix; sqlite3_int64 nTerm; sqlite3_int64 n; sqlite3_int64 iDocsz; int iHeight; sqlite3_int64 i = 0; int cnt = 0; char zTerm[1000]; i += getVarint(aData, &n); iHeight = (int)n; printf("height: %d\n", iHeight); if( iHeight>0 ) { i += getVarint(aData+i, &iChild); printf("left-child: %lld\n", iChild); } while( i<nData ) { if( (cnt++)>0 ) { i += getVarint(aData+i, &iPrefix); } else { iPrefix = 0; } i += getVarint(aData+i, &nTerm); if( iPrefix+nTerm+1 >= sizeof(zTerm) ) { fprintf(stderr, "term to long\n"); exit(1); } memcpy(zTerm+iPrefix, aData+i, (size_t)nTerm); zTerm[iPrefix+nTerm] = 0; i += nTerm; if( iHeight==0 ) { i += getVarint(aData+i, &iDocsz); printf("term: %-25s doclist %7lld bytes offset %lld\n", zTerm, iDocsz, i); i += iDocsz; } else { printf("term: %-25s child %lld\n", zTerm, ++iChild); } } }
/* ** Read a single varint from file-descriptor pFile. Return SQLITE_OK if ** successful, or an SQLite error code if some error occurs. ** ** The value of *piOffset when this function is called is used as the ** byte offset in file pFile from whence to read the varint. If successful ** (i.e. if no IO error occurs), then *piOffset is set to the offset of ** the first byte past the end of the varint before returning. *piVal is ** set to the integer value read. If an error occurs, the final values of ** both *piOffset and *piVal are undefined. */ static int vdbeSorterReadVarint( sqlite3_file *pFile, /* File to read from */ i64 *piOffset, /* IN/OUT: Read offset in pFile */ i64 *piVal /* OUT: Value read from file */ ){ u8 aVarint[9]; /* Buffer large enough for a varint */ i64 iOff = *piOffset; /* Offset in file to read from */ int rc; /* Return code */ rc = sqlite3OsRead(pFile, aVarint, 9, iOff); if( rc==SQLITE_OK ){ *piOffset += getVarint(aVarint, (u64 *)piVal); } return rc; }
/* ** usage: varint_test START MULTIPLIER COUNT INCREMENT ** ** This command tests the putVarint() and getVarint() ** routines, both for accuracy and for speed. ** ** An integer is written using putVarint() and read back with ** getVarint() and varified to be unchanged. This repeats COUNT ** times. The first integer is START*MULTIPLIER. Each iteration ** increases the integer by INCREMENT. ** ** This command returns nothing if it works. It returns an error message ** if something goes wrong. */ static int btree_varint_test( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ u32 start, mult, count, incr; u64 in, out; int n1, n2, i, j; unsigned char zBuf[100]; if( argc!=5 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " START MULTIPLIER COUNT INCREMENT\"", 0); return TCL_ERROR; } if( Tcl_GetInt(interp, argv[1], (int*)&start) ) return TCL_ERROR; if( Tcl_GetInt(interp, argv[2], (int*)&mult) ) return TCL_ERROR; if( Tcl_GetInt(interp, argv[3], (int*)&count) ) return TCL_ERROR; if( Tcl_GetInt(interp, argv[4], (int*)&incr) ) return TCL_ERROR; in = start; in *= mult; for(i=0; i<count; i++){ char zErr[200]; n1 = putVarint(zBuf, in); if( n1>9 || n1<1 ){ sprintf(zErr, "putVarint returned %d - should be between 1 and 9", n1); Tcl_AppendResult(interp, zErr, 0); return TCL_ERROR; } n2 = getVarint(zBuf, &out); if( n1!=n2 ){ sprintf(zErr, "putVarint returned %d and getVarint returned %d", n1, n2); Tcl_AppendResult(interp, zErr, 0); return TCL_ERROR; } if( in!=out ){ sprintf(zErr, "Wrote 0x%016llx and got back 0x%016llx", in, out); Tcl_AppendResult(interp, zErr, 0); return TCL_ERROR; } if( (in & 0xffffffff)==in ){ u32 out32; n2 = getVarint32(zBuf, out32); out = out32; if( n1!=n2 ){ sprintf(zErr, "putVarint returned %d and GetVarint32 returned %d", n1, n2); Tcl_AppendResult(interp, zErr, 0); return TCL_ERROR; } if( in!=out ){ sprintf(zErr, "Wrote 0x%016llx and got back 0x%016llx from GetVarint32", in, out); Tcl_AppendResult(interp, zErr, 0); return TCL_ERROR; } } /* In order to get realistic timings, run getVarint 19 more times. ** This is because getVarint is called about 20 times more often ** than putVarint. */ for(j=0; j<19; j++){ getVarint(zBuf, &out); } in += incr; } return TCL_OK; }
/* Peek at the next docid without advancing the read pointer. */ static sqlite_int64 peekDocid(DocListReader *pReader){ sqlite_int64 ret; assert( !readerAtEnd(pReader) ); getVarint(pReader->p, &ret); return ret; }
static int leafCursorCellDecode(RecoverLeafCursor *pCursor){ const unsigned char *pPageHeader; const unsigned char *pCellOffsets; unsigned iCellOffset; const unsigned char *pCell; unsigned nCellMaxBytes; unsigned iEndOffset; u64 nRecordBytes; u64 iRowid; unsigned nRead; unsigned nRecordHeaderRead; u64 nRecordHeaderBytes; unsigned nRecordCols; u64 nRecordColBytes; unsigned i; int rc; assert( pCursor->iCell<pCursor->nCells ); leafCursorDestroyCellData(pCursor); pPageHeader = PageHeader(pCursor->pPage); pCellOffsets = pPageHeader + knPageLeafHeaderBytes; iCellOffset = decodeUnsigned16(pCellOffsets + pCursor->iCell*2); if( iCellOffset>=pCursor->nPageSize ){ return ValidateError(); } pCell = PageData(pCursor->pPage, iCellOffset); nCellMaxBytes = pCursor->nPageSize - iCellOffset; if( !checkVarints(pCell, nCellMaxBytes, 3) ){ return ValidateError(); } nRead = getVarint(pCell, &nRecordBytes); assert( iCellOffset+nRead<=pCursor->nPageSize ); pCursor->nRecordBytes = nRecordBytes; nRead += getVarint(pCell + nRead, &iRowid); assert( iCellOffset+nRead<=pCursor->nPageSize ); pCursor->iRowid = (i64)iRowid; pCursor->iRecordOffset = iCellOffset + nRead; rc = overflowMaybeCreate(pCursor->pPage, pCursor->nPageSize, pCursor->iRecordOffset, pCursor->nRecordBytes, &pCursor->nLocalRecordBytes, &pCursor->pOverflow); if( rc!=SQLITE_OK ){ return ValidateError(); } iEndOffset = pCursor->iRecordOffset + pCursor->nLocalRecordBytes; for( i=0; i<pCursor->nCells; ++i ){ const unsigned iOtherOffset = decodeUnsigned16(pCellOffsets + i*2); if( iOtherOffset>iCellOffset && iOtherOffset<iEndOffset ){ return ValidateError(); } } nRecordHeaderRead = getVarint(pCell + nRead, &nRecordHeaderBytes); assert( nRecordHeaderBytes<=nRecordBytes ); pCursor->nRecordHeaderBytes = nRecordHeaderBytes; rc = overflowGetSegment(pCursor->pPage, pCursor->iRecordOffset, pCursor->nLocalRecordBytes, pCursor->pOverflow, 0, nRecordHeaderBytes, &pCursor->pRecordHeader, &pCursor->bFreeRecordHeader); if( rc!=SQLITE_OK ){ return ValidateError(); } nRecordCols = 0; nRecordColBytes = 0; while( nRecordHeaderRead<nRecordHeaderBytes ){ u64 iSerialType; if( !checkVarint(pCursor->pRecordHeader + nRecordHeaderRead, nRecordHeaderBytes - nRecordHeaderRead) ){ return ValidateError(); } nRecordHeaderRead += getVarint(pCursor->pRecordHeader + nRecordHeaderRead, &iSerialType); if( iSerialType==10 || iSerialType==11 ){ return ValidateError(); } nRecordColBytes += SerialTypeLength(iSerialType); nRecordCols++; } pCursor->nRecordCols = nRecordCols; if( nRecordHeaderRead!=nRecordHeaderBytes ){ return ValidateError(); } if( nRecordHeaderBytes+nRecordColBytes!=nRecordBytes ){ return ValidateError(); } return SQLITE_OK; }