Updates to sqlite3BtreeKeyFetch() and sqlite3BtreeDataFetch(). (CVS 1347)
FossilOrigin-Name: a675ac49882887dfcbf671e9092a29aca9eb694e
This commit is contained in:
+134
-91
@@ -9,7 +9,7 @@
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** $Id: btree.c,v 1.124 2004/05/10 23:29:49 drh Exp $
|
||||
** $Id: btree.c,v 1.125 2004/05/11 00:58:56 drh Exp $
|
||||
**
|
||||
** This file implements a external (disk-based) database using BTrees.
|
||||
** For a detailed discussion of BTrees, refer to
|
||||
@@ -1416,6 +1416,41 @@ int sqlite3BtreeKeySize(BtCursor *pCur, u64 *pSize){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Set *pSize to the number of bytes of data in the entry the
|
||||
** cursor currently points to. Always return SQLITE_OK.
|
||||
** Failure is not possible. If the cursor is not currently
|
||||
** pointing to an entry (which can happen, for example, if
|
||||
** the database is empty) then *pSize is set to 0.
|
||||
*/
|
||||
int sqlite3BtreeDataSize(BtCursor *pCur, u32 *pSize){
|
||||
MemPage *pPage;
|
||||
unsigned char *cell;
|
||||
u64 size;
|
||||
|
||||
if( !pCur->isValid ){
|
||||
return pCur->status ? pCur->status : SQLITE_INTERNAL;
|
||||
}
|
||||
pPage = pCur->pPage;
|
||||
assert( pPage!=0 );
|
||||
assert( pPage->isInit );
|
||||
pageIntegrity(pPage);
|
||||
if( pPage->zeroData ){
|
||||
*pSize = 0;
|
||||
}else{
|
||||
assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
|
||||
cell = pPage->aCell[pCur->idx];
|
||||
cell += 2; /* Skip the offset to the next cell */
|
||||
if( !pPage->leaf ){
|
||||
cell += 4; /* Skip the child pointer */
|
||||
}
|
||||
getVarint(cell, &size);
|
||||
assert( (size & 0x00000000ffffffff)==size );
|
||||
*pSize = (u32)size;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Read payload information from the entry that the pCur cursor is
|
||||
** pointing to. Begin reading the payload at "offset" and read
|
||||
@@ -1533,93 +1568,6 @@ int sqlite3BtreeKey(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
|
||||
return getPayload(pCur, offset, amt, (unsigned char*)pBuf, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return a pointer to the key of record that cursor pCur
|
||||
** is point to if the entire key is in contiguous memory.
|
||||
** If the key is split up among multiple tables, return 0.
|
||||
** If pCur is not pointing to a valid entry return 0.
|
||||
**
|
||||
** The pointer returned is ephemeral. The key may move
|
||||
** or be destroyed on the next call to any Btree routine.
|
||||
**
|
||||
** This routine is used to do quick key comparisons in the
|
||||
** common case where the entire key fits in the payload area
|
||||
** of a cell and does not overflow onto secondary pages. If
|
||||
** this routine returns 0 for a valid cursor, the caller will
|
||||
** need to allocate a buffer big enough to hold the whole key
|
||||
** then use sqlite3BtreeKey() to copy the key value into the
|
||||
** buffer. That is substantially slower. But fortunately,
|
||||
** most keys are small enough to fit in the payload area so
|
||||
** the slower method is rarely needed.
|
||||
*/
|
||||
void *sqlite3BtreeKeyFetch(BtCursor *pCur){
|
||||
unsigned char *aPayload;
|
||||
MemPage *pPage;
|
||||
Btree *pBt;
|
||||
u64 nData, nKey;
|
||||
|
||||
assert( pCur!=0 );
|
||||
if( !pCur->isValid ){
|
||||
return 0;
|
||||
}
|
||||
assert( pCur->pPage!=0 );
|
||||
assert( pCur->idx>=0 && pCur->idx<pCur->pPage->nCell );
|
||||
pBt = pCur->pBt;
|
||||
pPage = pCur->pPage;
|
||||
pageIntegrity(pPage);
|
||||
assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
|
||||
assert( pPage->intKey==0 );
|
||||
aPayload = pPage->aCell[pCur->idx];
|
||||
aPayload += 2; /* Skip the next cell index */
|
||||
if( !pPage->leaf ){
|
||||
aPayload += 4; /* Skip the child pointer */
|
||||
}
|
||||
if( !pPage->zeroData ){
|
||||
aPayload += getVarint(aPayload, &nData);
|
||||
}
|
||||
aPayload += getVarint(aPayload, &nKey);
|
||||
if( nKey>pBt->maxLocal ){
|
||||
return 0;
|
||||
}
|
||||
return aPayload;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Set *pSize to the number of bytes of data in the entry the
|
||||
** cursor currently points to. Always return SQLITE_OK.
|
||||
** Failure is not possible. If the cursor is not currently
|
||||
** pointing to an entry (which can happen, for example, if
|
||||
** the database is empty) then *pSize is set to 0.
|
||||
*/
|
||||
int sqlite3BtreeDataSize(BtCursor *pCur, u32 *pSize){
|
||||
MemPage *pPage;
|
||||
unsigned char *cell;
|
||||
u64 size;
|
||||
|
||||
if( !pCur->isValid ){
|
||||
return pCur->status ? pCur->status : SQLITE_INTERNAL;
|
||||
}
|
||||
pPage = pCur->pPage;
|
||||
assert( pPage!=0 );
|
||||
assert( pPage->isInit );
|
||||
pageIntegrity(pPage);
|
||||
if( pPage->zeroData ){
|
||||
*pSize = 0;
|
||||
}else{
|
||||
assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
|
||||
cell = pPage->aCell[pCur->idx];
|
||||
cell += 2; /* Skip the offset to the next cell */
|
||||
if( !pPage->leaf ){
|
||||
cell += 4; /* Skip the child pointer */
|
||||
}
|
||||
getVarint(cell, &size);
|
||||
assert( (size & 0x00000000ffffffff)==size );
|
||||
*pSize = (u32)size;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Read part of the data associated with cursor pCur. Exactly
|
||||
** "amt" bytes will be transfered into pBuf[]. The transfer
|
||||
@@ -1640,6 +1588,101 @@ int sqlite3BtreeData(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
|
||||
return getPayload(pCur, offset, amt, pBuf, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return a pointer to payload information from the entry that the
|
||||
** pCur cursor is pointing to. The pointer is to the beginning of
|
||||
** the key if skipKey==0 and it points to the beginning of data if
|
||||
** skipKey==1.
|
||||
**
|
||||
** At least amt bytes of information must be available on the local
|
||||
** page or else this routine returns NULL. If amt<0 then the entire
|
||||
** key/data must be available.
|
||||
**
|
||||
** This routine is an optimization. It is common for the entire key
|
||||
** and data to fit on the local page and for there to be no overflow
|
||||
** pages. When that is so, this routine can be used to access the
|
||||
** key and data without making a copy. If the key and/or data spills
|
||||
** onto overflow pages, then getPayload() must be used to reassembly
|
||||
** the key/data and copy it into a preallocated buffer.
|
||||
**
|
||||
** The pointer returned by this routine looks directly into the cached
|
||||
** page of the database. The data might change or move the next time
|
||||
** any btree routine is called.
|
||||
*/
|
||||
static const unsigned char *fetchPayload(
|
||||
BtCursor *pCur, /* Cursor pointing to entry to read from */
|
||||
int amt, /* Amount requested */
|
||||
int skipKey /* read beginning at data if this is true */
|
||||
){
|
||||
unsigned char *aPayload;
|
||||
MemPage *pPage;
|
||||
Btree *pBt;
|
||||
u64 nData, nKey;
|
||||
int maxLocal;
|
||||
|
||||
assert( pCur!=0 && pCur->pPage!=0 );
|
||||
assert( pCur->isValid );
|
||||
pBt = pCur->pBt;
|
||||
pPage = pCur->pPage;
|
||||
pageIntegrity(pPage);
|
||||
assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
|
||||
aPayload = pPage->aCell[pCur->idx];
|
||||
aPayload += 2; /* Skip the next cell index */
|
||||
if( !pPage->leaf ){
|
||||
aPayload += 4; /* Skip the child pointer */
|
||||
}
|
||||
if( pPage->zeroData ){
|
||||
nData = 0;
|
||||
}else{
|
||||
aPayload += getVarint(aPayload, &nData);
|
||||
}
|
||||
aPayload += getVarint(aPayload, &nKey);
|
||||
if( pPage->intKey ){
|
||||
nKey = 0;
|
||||
}
|
||||
maxLocal = pBt->maxLocal;
|
||||
if( skipKey ){
|
||||
aPayload += nKey;
|
||||
maxLocal -= nKey;
|
||||
if( amt<0 ) amt = nData;
|
||||
assert( amt<=nData );
|
||||
}else{
|
||||
if( amt<0 ) amt = nKey;
|
||||
assert( amt<=nKey );
|
||||
}
|
||||
if( amt>maxLocal ){
|
||||
return 0; /* If any of the data is not local, return nothing */
|
||||
}
|
||||
return aPayload;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Return a pointer to the first amt bytes of the key or data
|
||||
** for record that cursor pCur is point to if the entire request
|
||||
** exists in contiguous memory on the main tree page. If any
|
||||
** any part of the request is on an overflow page, return 0.
|
||||
** If pCur is not pointing to a valid entry return 0.
|
||||
**
|
||||
** If amt<0 then return the entire key or data.
|
||||
**
|
||||
** The pointer returned is ephemeral. The key/data may move
|
||||
** or be destroyed on the next call to any Btree routine.
|
||||
**
|
||||
** These routines is used to get quick access to key and data
|
||||
** in the common case where no overflow pages are used.
|
||||
**
|
||||
** It is a fatal error to call these routines with amt values that
|
||||
** are larger than the key/data size.
|
||||
*/
|
||||
const void *sqlite3BtreeKeyFetch(BtCursor *pCur, int amt){
|
||||
return (const void*)fetchPayload(pCur, amt, 0);
|
||||
}
|
||||
const void *sqlite3BtreeDataFetch(BtCursor *pCur, int amt){
|
||||
return (const void*)fetchPayload(pCur, amt, 1);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Move the cursor down to a new child page. The newPgno argument is the
|
||||
** page number of the child page in the byte order of the disk image.
|
||||
@@ -1907,7 +1950,7 @@ int sqlite3BtreeMoveto(BtCursor *pCur, const void *pKey, u64 nKey, int *pRes){
|
||||
upr = pPage->nCell-1;
|
||||
pageIntegrity(pPage);
|
||||
while( lwr<=upr ){
|
||||
void *pCellKey;
|
||||
const void *pCellKey;
|
||||
u64 nCellKey;
|
||||
pCur->idx = (lwr+upr)/2;
|
||||
sqlite3BtreeKeySize(pCur, &nCellKey);
|
||||
@@ -1919,10 +1962,10 @@ int sqlite3BtreeMoveto(BtCursor *pCur, const void *pKey, u64 nKey, int *pRes){
|
||||
}else{
|
||||
c = 0;
|
||||
}
|
||||
}else if( (pCellKey = sqlite3BtreeKeyFetch(pCur))!=0 ){
|
||||
}else if( (pCellKey = sqlite3BtreeKeyFetch(pCur, nCellKey))!=0 ){
|
||||
c = pCur->xCompare(pCur->pArg, nCellKey, pCellKey, nKey, pKey);
|
||||
}else{
|
||||
pCellKey = sqliteMalloc( nCellKey );
|
||||
u8 *pCellKey = sqliteMalloc( nCellKey );
|
||||
if( pCellKey==0 ) return SQLITE_NOMEM;
|
||||
rc = sqlite3BtreeKey(pCur, 0, nCellKey, pCellKey);
|
||||
c = pCur->xCompare(pCur->pArg, nCellKey, pCellKey, nKey, pKey);
|
||||
|
||||
+3
-2
@@ -13,7 +13,7 @@
|
||||
** subsystem. See comments in the source code for a detailed description
|
||||
** of what each interface routine does.
|
||||
**
|
||||
** @(#) $Id: btree.h,v 1.44 2004/05/10 23:29:50 drh Exp $
|
||||
** @(#) $Id: btree.h,v 1.45 2004/05/11 00:58:56 drh Exp $
|
||||
*/
|
||||
#ifndef _BTREE_H_
|
||||
#define _BTREE_H_
|
||||
@@ -85,7 +85,8 @@ int sqlite3BtreeFlags(BtCursor*);
|
||||
int sqlite3BtreePrevious(BtCursor*, int *pRes);
|
||||
int sqlite3BtreeKeySize(BtCursor*, u64 *pSize);
|
||||
int sqlite3BtreeKey(BtCursor*, u32 offset, u32 amt, void*);
|
||||
void *sqlite3BtreeKeyFetch(BtCursor*);
|
||||
const void *sqlite3BtreeKeyFetch(BtCursor*, int amt);
|
||||
const void *sqlite3BtreeDataFetch(BtCursor*, int amt);
|
||||
int sqlite3BtreeDataSize(BtCursor*, u32 *pSize);
|
||||
int sqlite3BtreeData(BtCursor*, u32 offset, u32 amt, void*);
|
||||
|
||||
|
||||
+79
-2
@@ -13,7 +13,7 @@
|
||||
** is not included in the SQLite library. It is used for automated
|
||||
** testing of the SQLite library.
|
||||
**
|
||||
** $Id: test3.c,v 1.34 2004/05/10 16:18:48 drh Exp $
|
||||
** $Id: test3.c,v 1.35 2004/05/11 00:58:56 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "pager.h"
|
||||
@@ -863,7 +863,8 @@ static int btree_eof(
|
||||
/*
|
||||
** Usage: btree_keysize ID
|
||||
**
|
||||
** Return the number of bytes of key.
|
||||
** Return the number of bytes of key. For an INTKEY table, this
|
||||
** returns the key itself.
|
||||
*/
|
||||
static int btree_keysize(
|
||||
void *NotUsed,
|
||||
@@ -963,6 +964,80 @@ static int btree_data(
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: btree_fetch_key ID AMT
|
||||
**
|
||||
** Use the sqlite3BtreeKeyFetch() routine to get AMT bytes of the key.
|
||||
** If sqlite3BtreeKeyFetch() fails, return an empty string.
|
||||
*/
|
||||
static int btree_fetch_key(
|
||||
void *NotUsed,
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int argc, /* Number of arguments */
|
||||
const char **argv /* Text of each argument */
|
||||
){
|
||||
BtCursor *pCur;
|
||||
int n;
|
||||
u64 nKey;
|
||||
const char *zBuf;
|
||||
char zStatic[1000];
|
||||
|
||||
if( argc!=3 ){
|
||||
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
||||
" ID AMT\"", 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR;
|
||||
if( Tcl_GetInt(interp, argv[2], &n) ) return TCL_ERROR;
|
||||
sqlite3BtreeKeySize(pCur, &nKey);
|
||||
zBuf = sqlite3BtreeKeyFetch(pCur, n);
|
||||
if( zBuf ){
|
||||
assert( nKey<sizeof(zStatic) );
|
||||
if( n>0 ) nKey = n;
|
||||
memcpy(zStatic, zBuf, (int)nKey);
|
||||
zStatic[nKey] = 0;
|
||||
Tcl_AppendResult(interp, zStatic, 0);
|
||||
}
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: btree_fetch_data ID AMT
|
||||
**
|
||||
** Use the sqlite3BtreeDataFetch() routine to get AMT bytes of the key.
|
||||
** If sqlite3BtreeDataFetch() fails, return an empty string.
|
||||
*/
|
||||
static int btree_fetch_data(
|
||||
void *NotUsed,
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int argc, /* Number of arguments */
|
||||
const char **argv /* Text of each argument */
|
||||
){
|
||||
BtCursor *pCur;
|
||||
int n;
|
||||
u32 nData;
|
||||
const char *zBuf;
|
||||
char zStatic[1000];
|
||||
|
||||
if( argc!=3 ){
|
||||
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
||||
" ID AMT
\"", 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR;
|
||||
if( Tcl_GetInt(interp, argv[2], &n) ) return TCL_ERROR;
|
||||
sqlite3BtreeDataSize(pCur, &nData);
|
||||
zBuf = sqlite3BtreeDataFetch(pCur, n);
|
||||
if( zBuf ){
|
||||
assert( nData<sizeof(zStatic) );
|
||||
if( n>0 ) nData = n;
|
||||
memcpy(zStatic, zBuf, (int)nData);
|
||||
zStatic[nData] = 0;
|
||||
Tcl_AppendResult(interp, zStatic, 0);
|
||||
}
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: btree_payload_size ID
|
||||
**
|
||||
@@ -1096,6 +1171,8 @@ int Sqlitetest3_Init(Tcl_Interp *interp){
|
||||
{ "btree_keysize", (Tcl_CmdProc*)btree_keysize },
|
||||
{ "btree_key", (Tcl_CmdProc*)btree_key },
|
||||
{ "btree_data", (Tcl_CmdProc*)btree_data },
|
||||
{ "btree_fetch_key", (Tcl_CmdProc*)btree_fetch_key },
|
||||
{ "btree_fetch_data", (Tcl_CmdProc*)btree_fetch_data },
|
||||
{ "btree_payload_size", (Tcl_CmdProc*)btree_payload_size },
|
||||
{ "btree_first", (Tcl_CmdProc*)btree_first },
|
||||
{ "btree_last", (Tcl_CmdProc*)btree_last },
|
||||
|
||||
+9
-8
@@ -1073,7 +1073,8 @@ int sqlite2BtreeKeyCompare(
|
||||
int nIgnore, /* Ignore this many bytes at the end of pCur */
|
||||
int *pResult /* Write the result here */
|
||||
){
|
||||
void *pCellKey;
|
||||
const void *pCellKey;
|
||||
void *pMallocedKey;
|
||||
u64 nCellKey;
|
||||
int rc;
|
||||
|
||||
@@ -1084,18 +1085,18 @@ int sqlite2BtreeKeyCompare(
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
pCellKey = sqlite3BtreeKeyFetch(pCur);
|
||||
pCellKey = sqlite3BtreeKeyFetch(pCur, nCellKey);
|
||||
if( pCellKey ){
|
||||
*pResult = memcmp(pCellKey, pKey, nKey>nCellKey?nCellKey:nKey);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
pCellKey = sqliteMalloc( nCellKey );
|
||||
if( pCellKey==0 ) return SQLITE_NOMEM;
|
||||
pMallocedKey = sqliteMalloc( nCellKey );
|
||||
if( pMallocedKey==0 ) return SQLITE_NOMEM;
|
||||
|
||||
rc = sqlite3BtreeKey(pCur, 0, nCellKey, pCellKey);
|
||||
*pResult = memcmp(pCellKey, pKey, nKey>nCellKey?nCellKey:nKey);
|
||||
sqliteFree(pCellKey);
|
||||
rc = sqlite3BtreeKey(pCur, 0, nCellKey, pMallocedKey);
|
||||
*pResult = memcmp(pMallocedKey, pKey, nKey>nCellKey?nCellKey:nKey);
|
||||
sqliteFree(pMallocedKey);
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -1246,7 +1247,7 @@ int sqlite3VdbeDeserialize(
|
||||
pMem->i = 0;
|
||||
|
||||
for(ii=0; ii<bytes; ii++){
|
||||
pMem->i = pMem->i<<8 + zBuf[ii+ret];
|
||||
pMem->i = (pMem->i<<8) + zBuf[ii+ret];
|
||||
}
|
||||
|
||||
/* If this is a 1, 2 or 4 byte integer, extend the sign-bit if need be. */
|
||||
|
||||
Reference in New Issue
Block a user