mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-30 19:03:16 +03:00
Change the record format to include an extra varint at the beginning to record the number of bytes in the header. (CVS 1478)
FossilOrigin-Name: 0c4d138807f367d75b3fb5b2dadf206df725659f
This commit is contained in:
18
manifest
18
manifest
@ -1,5 +1,5 @@
|
|||||||
C Remove\sthe\sCOPY\scommand.\s(CVS\s1477)
|
C Change\sthe\srecord\sformat\sto\sinclude\san\sextra\svarint\sat\sthe\sbeginning\sto\srecord\sthe\snumber\sof\sbytes\sin\sthe\sheader.\s(CVS\s1478)
|
||||||
D 2004-05-27T17:22:55
|
D 2004-05-27T19:59:32
|
||||||
F Makefile.in ab7b0d5118e2da97bac66be8684a1034e3500f5a
|
F Makefile.in ab7b0d5118e2da97bac66be8684a1034e3500f5a
|
||||||
F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
|
F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
|
||||||
F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
|
F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
|
||||||
@ -69,11 +69,11 @@ F src/update.c 96461bcf4e946697e83c09c77c7e61b545a2f66e
|
|||||||
F src/utf.c 59b5c8f06a4384a9f64933d6c57a2de02ce3673b
|
F src/utf.c 59b5c8f06a4384a9f64933d6c57a2de02ce3673b
|
||||||
F src/util.c d299404febd509556e720fbecadd880756b0f899
|
F src/util.c d299404febd509556e720fbecadd880756b0f899
|
||||||
F src/vacuum.c 8734f89742f246abd91dbd3e087fc153bddbfbad
|
F src/vacuum.c 8734f89742f246abd91dbd3e087fc153bddbfbad
|
||||||
F src/vdbe.c 2f2c9859ad19836b31825d2d70c4a8e6a9eba0d1
|
F src/vdbe.c c068f9ab3d82906de297c1f20e50d601981328fb
|
||||||
F src/vdbe.h e73f890e0f2a6c42b183d7d6937947930fe4fdeb
|
F src/vdbe.h e73f890e0f2a6c42b183d7d6937947930fe4fdeb
|
||||||
F src/vdbeInt.h fab8bb7f7a7f4e0714d9b3217c3db97366e16b99
|
F src/vdbeInt.h 0c30699ea21371980bc278e4e3d17d80ced722df
|
||||||
F src/vdbeapi.c b0bb1f98c899ba00c8a5cbca612c2a28a1bb79de
|
F src/vdbeapi.c b0bb1f98c899ba00c8a5cbca612c2a28a1bb79de
|
||||||
F src/vdbeaux.c 5b886ac74a68e7e956259eba53e3d002a8ddc6a7
|
F src/vdbeaux.c c1beed304947bcfe49bd7c2abe45a58c2db0c67b
|
||||||
F src/vdbemem.c b487e8a903012de1c0b7f603e8efeede2b51b21d
|
F src/vdbemem.c b487e8a903012de1c0b7f603e8efeede2b51b21d
|
||||||
F src/where.c efe5d25fe18cd7381722457898cd863e84097a0c
|
F src/where.c efe5d25fe18cd7381722457898cd863e84097a0c
|
||||||
F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242
|
F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242
|
||||||
@ -154,7 +154,7 @@ F test/trigger1.test 4538c1c7d6bbca5dfe619ea6e1682b07ece95b21
|
|||||||
F test/trigger2.test 0767ab30cb5a2c8402c8524f3d566b410b6f5263
|
F test/trigger2.test 0767ab30cb5a2c8402c8524f3d566b410b6f5263
|
||||||
F test/trigger3.test a95ccace88291449f5eae7139ec438a42f90654d
|
F test/trigger3.test a95ccace88291449f5eae7139ec438a42f90654d
|
||||||
F test/trigger4.test 542afce45774e8f8e1130b96b8675f414d6e4bd8
|
F test/trigger4.test 542afce45774e8f8e1130b96b8675f414d6e4bd8
|
||||||
F test/types.test 8fa51489d4765b8baa2d3c92de32aba06315a655
|
F test/types.test 6c49e574970866558365a025b44c9fd8a162ef0d
|
||||||
F test/types2.test 5d725fcb68dbd032c6d4950d568d75fa33872687
|
F test/types2.test 5d725fcb68dbd032c6d4950d568d75fa33872687
|
||||||
F test/unique.test 0e38d4cc7affeef2527720d1dafd1f6870f02f2b
|
F test/unique.test 0e38d4cc7affeef2527720d1dafd1f6870f02f2b
|
||||||
F test/update.test b29bd9061a1150426dab6959806fcc73a41b1217
|
F test/update.test b29bd9061a1150426dab6959806fcc73a41b1217
|
||||||
@ -203,7 +203,7 @@ F www/sqlite.tcl 3c83b08cf9f18aa2d69453ff441a36c40e431604
|
|||||||
F www/tclsqlite.tcl b9271d44dcf147a93c98f8ecf28c927307abd6da
|
F www/tclsqlite.tcl b9271d44dcf147a93c98f8ecf28c927307abd6da
|
||||||
F www/vdbe.tcl 9b9095d4495f37697fd1935d10e14c6015e80aa1
|
F www/vdbe.tcl 9b9095d4495f37697fd1935d10e14c6015e80aa1
|
||||||
F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4
|
F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4
|
||||||
P c85e5f1528d098ea330ed0cf7e3c01cf9be93c10
|
P 287f86731c71401dbac098e08357367b4f8e5a43
|
||||||
R 0f424c162c35b47a72bb56f63064dff2
|
R ae5f0056bb6540c5d0436f9717bf751b
|
||||||
U drh
|
U drh
|
||||||
Z 4f618cbd73c341429c69a19968301445
|
Z 6b3a034bd2c2b8589e4d067a67b642dc
|
||||||
|
@ -1 +1 @@
|
|||||||
287f86731c71401dbac098e08357367b4f8e5a43
|
0c4d138807f367d75b3fb5b2dadf206df725659f
|
251
src/vdbe.c
251
src/vdbe.c
@ -43,7 +43,7 @@
|
|||||||
** in this file for details. If in doubt, do not deviate from existing
|
** in this file for details. If in doubt, do not deviate from existing
|
||||||
** commenting and indentation practices when changing or adding code.
|
** commenting and indentation practices when changing or adding code.
|
||||||
**
|
**
|
||||||
** $Id: vdbe.c,v 1.340 2004/05/27 17:22:56 drh Exp $
|
** $Id: vdbe.c,v 1.341 2004/05/27 19:59:32 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include "os.h"
|
#include "os.h"
|
||||||
@ -241,32 +241,6 @@ static Sorter *Merge(Sorter *pLeft, Sorter *pRight, KeyInfo *pKeyInfo){
|
|||||||
return sHead.pNext;
|
return sHead.pNext;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
** The following routine works like a replacement for the standard
|
|
||||||
** library routine fgets(). The difference is in how end-of-line (EOL)
|
|
||||||
** is handled. Standard fgets() uses LF for EOL under unix, CRLF
|
|
||||||
** under windows, and CR under mac. This routine accepts any of these
|
|
||||||
** character sequences as an EOL mark. The EOL mark is replaced by
|
|
||||||
** a single LF character in zBuf.
|
|
||||||
*/
|
|
||||||
static char *vdbe_fgets(char *zBuf, int nBuf, FILE *in){
|
|
||||||
int i, c;
|
|
||||||
for(i=0; i<nBuf-1 && (c=getc(in))!=EOF; i++){
|
|
||||||
zBuf[i] = c;
|
|
||||||
if( c=='\r' || c=='\n' ){
|
|
||||||
if( c=='\r' ){
|
|
||||||
zBuf[i] = '\n';
|
|
||||||
c = getc(in);
|
|
||||||
if( c!=EOF && c!='\n' ) ungetc(c, in);
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
zBuf[i] = 0;
|
|
||||||
return i>0 ? zBuf : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Make sure there is space in the Vdbe structure to hold at least
|
** Make sure there is space in the Vdbe structure to hold at least
|
||||||
** mxCursor cursors. If there is not currently enough space, then
|
** mxCursor cursors. If there is not currently enough space, then
|
||||||
@ -1846,75 +1820,46 @@ case OP_SetNumColumns: {
|
|||||||
*/
|
*/
|
||||||
case OP_Column: {
|
case OP_Column: {
|
||||||
int payloadSize; /* Number of bytes in the record */
|
int payloadSize; /* Number of bytes in the record */
|
||||||
int i = pOp->p1;
|
int p1 = pOp->p1; /* P1 value of the opcode */
|
||||||
int p2 = pOp->p2; /* column number to retrieve */
|
int p2 = pOp->p2; /* column number to retrieve */
|
||||||
Cursor *pC = 0;
|
Cursor *pC = 0; /* The VDBE cursor */
|
||||||
char *zRec; /* Pointer to record-data from stack or pseudo-table. */
|
char *zRec; /* Pointer to record-data from stack or pseudo-table. */
|
||||||
BtCursor *pCrsr;
|
BtCursor *pCrsr; /* The BTree cursor */
|
||||||
|
u32 *aType; /* aType[i] holds the numeric type of the i-th column */
|
||||||
|
u32 *aOffset; /* aOffset[i] is offset to start of data for i-th column */
|
||||||
u64 nField; /* number of fields in the record */
|
u64 nField; /* number of fields in the record */
|
||||||
|
u32 szHdr; /* Number of bytes in the record header */
|
||||||
int len; /* The length of the serialized data for the column */
|
int len; /* The length of the serialized data for the column */
|
||||||
int offset = 0;
|
int offset = 0; /* Offset into the data */
|
||||||
int nn;
|
int idx; /* Index into the header */
|
||||||
|
int i; /* Loop counter */
|
||||||
|
char *zData; /* Part of the record being decoded */
|
||||||
|
Mem sMem; /* For storing the record being decoded */
|
||||||
|
|
||||||
char *zData;
|
|
||||||
Mem sMem;
|
|
||||||
sMem.flags = 0;
|
sMem.flags = 0;
|
||||||
|
assert( p1<p->nCursor );
|
||||||
assert( i<p->nCursor );
|
|
||||||
pTos++;
|
pTos++;
|
||||||
|
|
||||||
/* If the record is coming from the stack, not from a cursor, then there
|
|
||||||
** is nowhere to cache the record header infomation. This simplifies
|
|
||||||
** things greatly, so deal with this case seperately.
|
|
||||||
*/
|
|
||||||
if( i<0 ){
|
|
||||||
char *zRec; /* Pointer to record data from the stack. */
|
|
||||||
int off = 0; /* Offset in zRec to start of the columns data. */
|
|
||||||
int off2 = 0; /* Offset in zRec to the next serial type to read */
|
|
||||||
u64 colType; /* The serial type of the value being read. */
|
|
||||||
|
|
||||||
assert( &pTos[i-1]>=p->aStack );
|
|
||||||
|
|
||||||
/* FIX ME: I don't understand this either. How is it related to
|
|
||||||
** OP_SortNext? (I thought it would be the commented out assert())
|
|
||||||
*/
|
|
||||||
/* assert( pTos[i].flags & MEM_Blob ); */
|
|
||||||
assert( pTos[i].flags & (MEM_Blob|MEM_Str) );
|
|
||||||
assert( pTos[i-1].flags & MEM_Int );
|
|
||||||
|
|
||||||
if( pTos[i].n==0 ){
|
|
||||||
pTos->flags = MEM_Null;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
zRec = pTos[i].z;
|
|
||||||
nField = pTos[i-1].i;
|
|
||||||
|
|
||||||
for( nn=0; nn<nField; nn++ ){
|
|
||||||
u64 v;
|
|
||||||
off2 += sqlite3GetVarint(&zRec[off2], &v);
|
|
||||||
if( nn==p2 ){
|
|
||||||
colType = v;
|
|
||||||
}else if( nn<p2 ){
|
|
||||||
off += sqlite3VdbeSerialTypeLen(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
off += off2;
|
|
||||||
|
|
||||||
sqlite3VdbeSerialGet(&zRec[off], colType, pTos, p->db->enc);
|
|
||||||
if( rc!=SQLITE_OK ){
|
|
||||||
goto abort_due_to_error;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* This block sets the variable payloadSize, and if the data is coming
|
/* This block sets the variable payloadSize, and if the data is coming
|
||||||
** from the stack or from a pseudo-table zRec. If the data is coming
|
** from the stack or from a pseudo-table zRec. If the data is coming
|
||||||
** from a real cursor, then zRec is left as NULL.
|
** from a real cursor, then zRec is left as NULL.
|
||||||
|
**
|
||||||
|
** We also compute the number of columns in the record. For cursors,
|
||||||
|
** the number of columns is stored in the Cursor.nField element. For
|
||||||
|
** records on the stack, the next entry down on the stack is an integer
|
||||||
|
** which is the number of records.
|
||||||
*/
|
*/
|
||||||
if( (pC = p->apCsr[i])->pCursor!=0 ){
|
if( p1<0 ){
|
||||||
|
Mem *pRec = &pTos[p1];
|
||||||
|
Mem *pCnt = &pRec[-1];
|
||||||
|
assert( pRec>=p->aStack );
|
||||||
|
assert( pRec->flags & MEM_Blob );
|
||||||
|
payloadSize = pRec->n;
|
||||||
|
zRec = pRec->z;
|
||||||
|
assert( pCnt>=p->aStack );
|
||||||
|
assert( pCnt->flags & MEM_Int );
|
||||||
|
nField = pCnt->i;
|
||||||
|
}else if( (pC = p->apCsr[p1])->pCursor!=0 ){
|
||||||
sqlite3VdbeCursorMoveto(pC);
|
sqlite3VdbeCursorMoveto(pC);
|
||||||
zRec = 0;
|
zRec = 0;
|
||||||
pCrsr = pC->pCursor;
|
pCrsr = pC->pCursor;
|
||||||
@ -1929,11 +1874,13 @@ case OP_Column: {
|
|||||||
}else{
|
}else{
|
||||||
sqlite3BtreeDataSize(pCrsr, &payloadSize);
|
sqlite3BtreeDataSize(pCrsr, &payloadSize);
|
||||||
}
|
}
|
||||||
|
nField = pC->nField;
|
||||||
}else if( pC->pseudoTable ){
|
}else if( pC->pseudoTable ){
|
||||||
payloadSize = pC->nData;
|
payloadSize = pC->nData;
|
||||||
zRec = pC->pData;
|
zRec = pC->pData;
|
||||||
pC->cacheValid = 0;
|
pC->cacheValid = 0;
|
||||||
assert( payloadSize==0 || zRec!=0 );
|
assert( payloadSize==0 || zRec!=0 );
|
||||||
|
nField = pC->nField;
|
||||||
}else{
|
}else{
|
||||||
payloadSize = 0;
|
payloadSize = 0;
|
||||||
}
|
}
|
||||||
@ -1944,93 +1891,104 @@ case OP_Column: {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If the row data is coming from a cursor, then OP_SetNumColumns must of
|
assert( p2<nField );
|
||||||
** been executed on that cursor. Also, p2 (the column to read) must be
|
|
||||||
** less than nField.
|
|
||||||
*/
|
|
||||||
assert( !pC || pC->nField>0 );
|
|
||||||
assert( p2<pC->nField );
|
|
||||||
nField = pC->nField;
|
|
||||||
|
|
||||||
/* Read and parse the table header. Store the results of the parse
|
/* Read and parse the table header. Store the results of the parse
|
||||||
** into the record header cache fields of the cursor.
|
** into the record header cache fields of the cursor.
|
||||||
*/
|
*/
|
||||||
if( !pC || !pC->cacheValid ){
|
if( pC && pC->cacheValid ){
|
||||||
pC->payloadSize = payloadSize;
|
aType = pC->aType;
|
||||||
if( !pC->aType ){
|
aOffset = pC->aOffset;
|
||||||
pC->aType = sqliteMallocRaw( nField*sizeof(pC->aType[0]) );
|
}else{
|
||||||
if( pC->aType==0 ){
|
aType = sqliteMallocRaw( 2*nField*sizeof(aType) );
|
||||||
goto no_mem;
|
aOffset = &aType[nField];
|
||||||
}
|
if( aType==0 ){
|
||||||
|
goto no_mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Figure out how many bytes are in the header */
|
||||||
if( zRec ){
|
if( zRec ){
|
||||||
zData = zRec;
|
zData = zRec;
|
||||||
}else{
|
}else{
|
||||||
/* Estimate the maximum space required by the nField varints by
|
int sz = payloadSize<5 ? payloadSize : 5;
|
||||||
** assuming the maximum space for each is the length required to store:
|
if( pC->keyAsData ){
|
||||||
**
|
zData = (char*)sqlite3BtreeKeyFetch(pCrsr, sz);
|
||||||
** (<record length> * 2) + 13
|
}else{
|
||||||
**
|
zData = (char*)sqlite3BtreeDataFetch(pCrsr, sz);
|
||||||
** This is the serial-type for a text object as long as the record
|
|
||||||
** itself. In almost all cases the length required to store this is
|
|
||||||
** three bytes or less.
|
|
||||||
*/
|
|
||||||
int max_space = sqlite3VarintLen((((u64)payloadSize)<<1)+13)*nField;
|
|
||||||
if( max_space>payloadSize ){
|
|
||||||
max_space = payloadSize;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
idx = sqlite3GetVarint32(zData, &szHdr);
|
||||||
|
|
||||||
rc = getBtreeMem(pCrsr, 0, max_space, pC->keyAsData, &sMem);
|
/* Get the complete header text */
|
||||||
|
if( !zRec ){
|
||||||
|
rc = getBtreeMem(pCrsr, 0, szHdr, pC->keyAsData, &sMem);
|
||||||
if( rc!=SQLITE_OK ){
|
if( rc!=SQLITE_OK ){
|
||||||
goto abort_due_to_error;
|
goto abort_due_to_error;
|
||||||
}
|
}
|
||||||
zData = sMem.z;
|
zData = sMem.z;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read all the serial types for the record. At the end of this block
|
/* Scan the header and use it to fill in the aType[] and aOffset[]
|
||||||
** variable offset is set to the offset to the start of Data0 in the record.
|
** arrays. aType[i] will contain the type integer for the i-th
|
||||||
|
** column and aOffset[i] will contain the offset from the beginning
|
||||||
|
** of the record to the start of the data for the i-th column
|
||||||
*/
|
*/
|
||||||
for(nn=0; nn<nField; nn++){
|
offset = szHdr;
|
||||||
offset += sqlite3GetVarint(&zData[offset], &pC->aType[nn]);
|
i = 0;
|
||||||
|
while( idx<szHdr && i<nField && offset<=payloadSize ){
|
||||||
|
aOffset[i] = offset;
|
||||||
|
idx += sqlite3GetVarint32(&zData[idx], &aType[i]);
|
||||||
|
offset += sqlite3VdbeSerialTypeLen(aType[i]);
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
pC->nHeader = offset;
|
|
||||||
pC->cacheValid = 1;
|
|
||||||
|
|
||||||
Release(&sMem);
|
Release(&sMem);
|
||||||
sMem.flags = 0;
|
sMem.flags = MEM_Null;
|
||||||
|
|
||||||
|
/* The header should end at the start of data and the data should
|
||||||
|
** end at last byte of the record. If this is not the case then
|
||||||
|
** we are dealing with a malformed record.
|
||||||
|
*/
|
||||||
|
if( idx!=szHdr || offset!=payloadSize ){
|
||||||
|
sqliteFree(aType);
|
||||||
|
if( pC ) pC->aType = 0;
|
||||||
|
rc = SQLITE_CORRUPT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remember all aType and aColumn information if we have a cursor
|
||||||
|
** to remember it in. */
|
||||||
|
if( pC ){
|
||||||
|
pC->payloadSize = payloadSize;
|
||||||
|
pC->aType = aType;
|
||||||
|
pC->aOffset = aOffset;
|
||||||
|
pC->cacheValid = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Compute the offset from the beginning of the record to the beginning
|
/* Get the column information.
|
||||||
** of the data. And get the length of the data.
|
|
||||||
*/
|
*/
|
||||||
offset = pC->nHeader;
|
|
||||||
for(nn=0; nn<p2; nn++){
|
|
||||||
offset += sqlite3VdbeSerialTypeLen(pC->aType[nn]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if( zRec ){
|
if( zRec ){
|
||||||
zData = &zRec[offset];
|
zData = &zRec[aOffset[p2]];
|
||||||
}else{
|
}else{
|
||||||
len = sqlite3VdbeSerialTypeLen(pC->aType[p2]);
|
len = sqlite3VdbeSerialTypeLen(aType[p2]);
|
||||||
getBtreeMem(pCrsr, offset, len, pC->keyAsData, &sMem);
|
getBtreeMem(pCrsr, aOffset[p2], len, pC->keyAsData, &sMem);
|
||||||
zData = sMem.z;
|
zData = sMem.z;
|
||||||
}
|
}
|
||||||
sqlite3VdbeSerialGet(zData, pC->aType[p2], pTos, p->db->enc);
|
sqlite3VdbeSerialGet(zData, aType[p2], pTos, p->db->enc);
|
||||||
if( rc!=SQLITE_OK ){
|
if( rc!=SQLITE_OK ){
|
||||||
goto abort_due_to_error;
|
goto abort_due_to_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
Release(&sMem);
|
Release(&sMem);
|
||||||
|
|
||||||
|
/* Release the aType[] memory if we are not dealing with cursor */
|
||||||
|
if( !pC ){
|
||||||
|
sqliteFree(aType);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Opcode MakeRecord P1 * P3
|
/* Opcode MakeRecord P1 * P3
|
||||||
**
|
**
|
||||||
** This opcode (not yet in use) is a replacement for the current
|
|
||||||
** OP_MakeRecord that supports the SQLite3 manifest typing feature.
|
|
||||||
** It drops the (P2==1) option that was never use.
|
|
||||||
**
|
|
||||||
** Convert the top P1 entries of the stack into a single entry
|
** Convert the top P1 entries of the stack into a single entry
|
||||||
** suitable for use as a data record in a database table. The
|
** suitable for use as a data record in a database table. The
|
||||||
** details of the format are irrelavant as long as the OP_Column
|
** details of the format are irrelavant as long as the OP_Column
|
||||||
@ -2056,7 +2014,7 @@ case OP_MakeRecord: {
|
|||||||
** like this:
|
** like this:
|
||||||
**
|
**
|
||||||
** --------------------------------------------------------------------------
|
** --------------------------------------------------------------------------
|
||||||
** | num-fields | type 0 | type 1 | ... | type N-1 | data0 | ... | data N-1 |
|
** | header-siz | type 0 | type 1 | ... | type N-1 | data0 | ... | data N-1 |
|
||||||
** --------------------------------------------------------------------------
|
** --------------------------------------------------------------------------
|
||||||
**
|
**
|
||||||
** Data(0) is taken from the lowest element of the stack and data(N-1) is
|
** Data(0) is taken from the lowest element of the stack and data(N-1) is
|
||||||
@ -2074,7 +2032,9 @@ case OP_MakeRecord: {
|
|||||||
unsigned char *zCsr;
|
unsigned char *zCsr;
|
||||||
char *zAffinity;
|
char *zAffinity;
|
||||||
Mem *pRec;
|
Mem *pRec;
|
||||||
int nBytes = 0; /* Space required for this record */
|
int nData = 0; /* Number of bytes of data space */
|
||||||
|
int nHdr = 0; /* Number of bytes of header space */
|
||||||
|
int nByte = 0; /* Space required for this record */
|
||||||
|
|
||||||
Mem *pData0 = &pTos[1-nField];
|
Mem *pData0 = &pTos[1-nField];
|
||||||
assert( pData0>=p->aStack );
|
assert( pData0>=p->aStack );
|
||||||
@ -2089,23 +2049,26 @@ case OP_MakeRecord: {
|
|||||||
applyAffinity(pRec, zAffinity[pRec-pData0], db->enc);
|
applyAffinity(pRec, zAffinity[pRec-pData0], db->enc);
|
||||||
}
|
}
|
||||||
serial_type = sqlite3VdbeSerialType(pRec);
|
serial_type = sqlite3VdbeSerialType(pRec);
|
||||||
nBytes += sqlite3VdbeSerialTypeLen(serial_type);
|
nData += sqlite3VdbeSerialTypeLen(serial_type);
|
||||||
nBytes += sqlite3VarintLen(serial_type);
|
nHdr += sqlite3VarintLen(serial_type);
|
||||||
}
|
}
|
||||||
|
nHdr += sqlite3VarintLen(nHdr);
|
||||||
|
nByte = nHdr+nData;
|
||||||
|
|
||||||
if( nBytes>MAX_BYTES_PER_ROW ){
|
if( nByte>MAX_BYTES_PER_ROW ){
|
||||||
rc = SQLITE_TOOBIG;
|
rc = SQLITE_TOOBIG;
|
||||||
goto abort_due_to_error;
|
goto abort_due_to_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allocate space for the new record. */
|
/* Allocate space for the new record. */
|
||||||
zNewRecord = sqliteMallocRaw(nBytes);
|
zNewRecord = sqliteMallocRaw(nByte);
|
||||||
if( !zNewRecord ){
|
if( !zNewRecord ){
|
||||||
goto no_mem;
|
goto no_mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write the record */
|
/* Write the record */
|
||||||
zCsr = zNewRecord;
|
zCsr = zNewRecord;
|
||||||
|
zCsr += sqlite3PutVarint(zCsr, nHdr);
|
||||||
for(pRec=pData0; pRec<=pTos; pRec++){
|
for(pRec=pData0; pRec<=pTos; pRec++){
|
||||||
u64 serial_type = sqlite3VdbeSerialType(pRec);
|
u64 serial_type = sqlite3VdbeSerialType(pRec);
|
||||||
zCsr += sqlite3PutVarint(zCsr, serial_type); /* serial type */
|
zCsr += sqlite3PutVarint(zCsr, serial_type); /* serial type */
|
||||||
@ -2114,11 +2077,11 @@ case OP_MakeRecord: {
|
|||||||
zCsr += sqlite3VdbeSerialPut(zCsr, pRec); /* serial data */
|
zCsr += sqlite3VdbeSerialPut(zCsr, pRec); /* serial data */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If zCsr has not been advanced exactly nBytes bytes, then one
|
/* If zCsr has not been advanced exactly nByte bytes, then one
|
||||||
** of the sqlite3PutVarint() or sqlite3VdbeSerialPut() calls above
|
** of the sqlite3PutVarint() or sqlite3VdbeSerialPut() calls above
|
||||||
** failed. This indicates a corrupted memory cell or code bug.
|
** failed. This indicates a corrupted memory cell or code bug.
|
||||||
*/
|
*/
|
||||||
if( zCsr!=(zNewRecord+nBytes) ){
|
if( zCsr!=(zNewRecord+nByte) ){
|
||||||
rc = SQLITE_INTERNAL;
|
rc = SQLITE_INTERNAL;
|
||||||
goto abort_due_to_error;
|
goto abort_due_to_error;
|
||||||
}
|
}
|
||||||
@ -2126,7 +2089,7 @@ case OP_MakeRecord: {
|
|||||||
/* Pop nField entries from the stack and push the new entry on */
|
/* Pop nField entries from the stack and push the new entry on */
|
||||||
popStack(&pTos, nField);
|
popStack(&pTos, nField);
|
||||||
pTos++;
|
pTos++;
|
||||||
pTos->n = nBytes;
|
pTos->n = nByte;
|
||||||
pTos->z = zNewRecord;
|
pTos->z = zNewRecord;
|
||||||
pTos->flags = MEM_Blob | MEM_Dyn;
|
pTos->flags = MEM_Blob | MEM_Dyn;
|
||||||
|
|
||||||
|
@ -80,14 +80,14 @@ struct Cursor {
|
|||||||
i64 iKey; /* Key for the NEW or OLD pseudo-table row */
|
i64 iKey; /* Key for the NEW or OLD pseudo-table row */
|
||||||
u8 *pIncrKey; /* Pointer to pKeyInfo->incrKey */
|
u8 *pIncrKey; /* Pointer to pKeyInfo->incrKey */
|
||||||
KeyInfo *pKeyInfo; /* Info about index keys needed by index cursors */
|
KeyInfo *pKeyInfo; /* Info about index keys needed by index cursors */
|
||||||
|
int nField; /* Number of fields in the header */
|
||||||
|
|
||||||
/* Cached information about the header for the data record that the
|
/* Cached information about the header for the data record that the
|
||||||
** cursor is currently pointing to */
|
** cursor is currently pointing to */
|
||||||
Bool cacheValid; /* True if the cache is valid */
|
Bool cacheValid; /* True if the cache is valid */
|
||||||
int nField; /* Number of fields in the header */
|
|
||||||
int nHeader; /* Number of bytes in the entire header */
|
|
||||||
int payloadSize; /* Total number of bytes in the record */
|
int payloadSize; /* Total number of bytes in the record */
|
||||||
u64 *aType; /* Type values for all entries in the record */
|
u32 *aType; /* Type values for all entries in the record */
|
||||||
|
u32 *aOffset; /* Cached offsets to the start of each columns data */
|
||||||
};
|
};
|
||||||
typedef struct Cursor Cursor;
|
typedef struct Cursor Cursor;
|
||||||
|
|
||||||
@ -367,4 +367,3 @@ int sqlite3VdbeMemRealify(Mem*);
|
|||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
void sqlite3VdbeMemSanity(Mem*, u8);
|
void sqlite3VdbeMemSanity(Mem*, u8);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1431,44 +1431,37 @@ int sqlite3VdbeRowCompare(
|
|||||||
int nKey2, const void *pKey2
|
int nKey2, const void *pKey2
|
||||||
){
|
){
|
||||||
KeyInfo *pKeyInfo = (KeyInfo*)userData;
|
KeyInfo *pKeyInfo = (KeyInfo*)userData;
|
||||||
int offset1 = 0;
|
u32 d1, d2; /* Offset into aKey[] of next data element */
|
||||||
int offset2 = 0;
|
u32 idx1, idx2; /* Offset into aKey[] of next header element */
|
||||||
int toffset1 = 0;
|
u32 szHdr1, szHdr2; /* Number of bytes in header */
|
||||||
int toffset2 = 0;
|
int i = 0;
|
||||||
int i;
|
int nField;
|
||||||
u8 enc = pKeyInfo->enc;
|
int rc = 0;
|
||||||
const unsigned char *aKey1 = (const unsigned char *)pKey1;
|
const unsigned char *aKey1 = (const unsigned char *)pKey1;
|
||||||
const unsigned char *aKey2 = (const unsigned char *)pKey2;
|
const unsigned char *aKey2 = (const unsigned char *)pKey2;
|
||||||
|
|
||||||
assert( pKeyInfo );
|
idx1 = sqlite3GetVarint32(pKey1, &szHdr1);
|
||||||
assert( pKeyInfo->nField>0 );
|
d1 = szHdr1;
|
||||||
|
idx2 = sqlite3GetVarint32(pKey2, &szHdr2);
|
||||||
for( i=0; i<pKeyInfo->nField; i++ ){
|
d2 = szHdr2;
|
||||||
u64 dummy;
|
nField = pKeyInfo->nField;
|
||||||
offset1 += sqlite3GetVarint(&aKey1[offset1], &dummy);
|
while( idx1<szHdr1 && idx2<szHdr2 && d1<nKey1 && d2<nKey2 && i<nField ){
|
||||||
offset2 += sqlite3GetVarint(&aKey1[offset1], &dummy);
|
|
||||||
}
|
|
||||||
|
|
||||||
for( i=0; i<pKeyInfo->nField; i++ ){
|
|
||||||
Mem mem1;
|
Mem mem1;
|
||||||
Mem mem2;
|
Mem mem2;
|
||||||
u64 serial_type1;
|
u32 serial_type1;
|
||||||
u64 serial_type2;
|
u32 serial_type2;
|
||||||
int rc;
|
|
||||||
|
|
||||||
/* Read the serial types for the next element in each key. */
|
/* Read the serial types for the next element in each key. */
|
||||||
toffset1 += sqlite3GetVarint(&aKey1[toffset1], &serial_type1);
|
idx1 += sqlite3GetVarint32(&aKey1[idx1], &serial_type1);
|
||||||
toffset2 += sqlite3GetVarint(&aKey2[toffset2], &serial_type2);
|
idx2 += sqlite3GetVarint32(&aKey2[idx2], &serial_type2);
|
||||||
|
|
||||||
assert( serial_type1 && serial_type2 );
|
|
||||||
|
|
||||||
/* Assert that there is enough space left in each key for the blob of
|
/* Assert that there is enough space left in each key for the blob of
|
||||||
** data to go with the serial type just read. This assert may fail if
|
** data to go with the serial type just read. This assert may fail if
|
||||||
** the file is corrupted. Then read the value from each key into mem1
|
** the file is corrupted. Then read the value from each key into mem1
|
||||||
** and mem2 respectively.
|
** and mem2 respectively.
|
||||||
*/
|
*/
|
||||||
offset1 += sqlite3VdbeSerialGet(&aKey1[offset1], serial_type1, &mem1, enc);
|
d1 += sqlite3VdbeSerialGet(&aKey1[d1], serial_type1, &mem1, 0);
|
||||||
offset2 += sqlite3VdbeSerialGet(&aKey2[offset2], serial_type2, &mem2, enc);
|
d2 += sqlite3VdbeSerialGet(&aKey2[d2], serial_type2, &mem2, 0);
|
||||||
|
|
||||||
rc = sqlite3MemCompare(&mem1, &mem2, pKeyInfo->aColl[i]);
|
rc = sqlite3MemCompare(&mem1, &mem2, pKeyInfo->aColl[i]);
|
||||||
if( mem1.flags&MEM_Dyn ){
|
if( mem1.flags&MEM_Dyn ){
|
||||||
@ -1478,11 +1471,31 @@ int sqlite3VdbeRowCompare(
|
|||||||
sqliteFree(mem2.z);
|
sqliteFree(mem2.z);
|
||||||
}
|
}
|
||||||
if( rc!=0 ){
|
if( rc!=0 ){
|
||||||
return rc;
|
break;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* One of the keys ran out of fields, but all the fields up to that point
|
||||||
|
** were equal. If the incrKey flag is true, then the second key is
|
||||||
|
** treated as larger.
|
||||||
|
*/
|
||||||
|
if( rc==0 ){
|
||||||
|
if( pKeyInfo->incrKey ){
|
||||||
|
assert( d2==nKey2 );
|
||||||
|
rc = -1;
|
||||||
|
}else if( d1<nKey1 ){
|
||||||
|
rc = 1;
|
||||||
|
}else if( d2<nKey2 ){
|
||||||
|
rc = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
if( pKeyInfo->aSortOrder && i<pKeyInfo->nField && pKeyInfo->aSortOrder[i] ){
|
||||||
|
rc = -rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
# it tests that the different storage classes (integer, real, text etc.)
|
# it tests that the different storage classes (integer, real, text etc.)
|
||||||
# all work correctly.
|
# all work correctly.
|
||||||
#
|
#
|
||||||
# $Id: types.test,v 1.6 2004/05/24 12:55:55 danielk1977 Exp $
|
# $Id: types.test,v 1.7 2004/05/27 19:59:33 drh Exp $
|
||||||
|
|
||||||
set testdir [file dirname $argv0]
|
set testdir [file dirname $argv0]
|
||||||
source $testdir/tester.tcl
|
source $testdir/tester.tcl
|
||||||
@ -199,7 +199,7 @@ do_test types-2.1.8 {
|
|||||||
do_test types-2.1.9 {
|
do_test types-2.1.9 {
|
||||||
set root [db eval {select rootpage from sqlite_master where name = 't1'}]
|
set root [db eval {select rootpage from sqlite_master where name = 't1'}]
|
||||||
record_sizes $root
|
record_sizes $root
|
||||||
} {2 2 2 3 3 5 5 9 9}
|
} {3 3 3 4 4 6 6 10 10}
|
||||||
|
|
||||||
# Insert some reals. These should be 10 byte records.
|
# Insert some reals. These should be 10 byte records.
|
||||||
do_test types-2.2.1 {
|
do_test types-2.2.1 {
|
||||||
@ -220,7 +220,7 @@ do_test types-2.2.2 {
|
|||||||
do_test types-2.2.3 {
|
do_test types-2.2.3 {
|
||||||
set root [db eval {select rootpage from sqlite_master where name = 't2'}]
|
set root [db eval {select rootpage from sqlite_master where name = 't2'}]
|
||||||
record_sizes $root
|
record_sizes $root
|
||||||
} {9 9 9}
|
} {10 10 10}
|
||||||
|
|
||||||
# Insert a NULL. This should be a two byte record.
|
# Insert a NULL. This should be a two byte record.
|
||||||
do_test types-2.3.1 {
|
do_test types-2.3.1 {
|
||||||
@ -239,7 +239,7 @@ do_test types-2.3.2 {
|
|||||||
do_test types-2.3.3 {
|
do_test types-2.3.3 {
|
||||||
set root [db eval {select rootpage from sqlite_master where name = 't3'}]
|
set root [db eval {select rootpage from sqlite_master where name = 't3'}]
|
||||||
record_sizes $root
|
record_sizes $root
|
||||||
} {1}
|
} {2}
|
||||||
|
|
||||||
# Insert a couple of strings.
|
# Insert a couple of strings.
|
||||||
do_test types-2.4.1 {
|
do_test types-2.4.1 {
|
||||||
@ -264,7 +264,7 @@ do_test types-2.4.2 {
|
|||||||
do_test types-2.4.3 {
|
do_test types-2.4.3 {
|
||||||
set root [db eval {select rootpage from sqlite_master where name = 't4'}]
|
set root [db eval {select rootpage from sqlite_master where name = 't4'}]
|
||||||
record_sizes $root
|
record_sizes $root
|
||||||
} {11 502 500003}
|
} {12 503 500004}
|
||||||
|
|
||||||
do_test types-2.5.1 {
|
do_test types-2.5.1 {
|
||||||
execsql {
|
execsql {
|
||||||
|
Reference in New Issue
Block a user