diff --git a/manifest b/manifest index 86bad0e3f1..cfdaa13898 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Remove\sthe\sCOPY\scommand.\s(CVS\s1477) -D 2004-05-27T17:22:55 +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-27T19:59:32 F Makefile.in ab7b0d5118e2da97bac66be8684a1034e3500f5a F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd @@ -69,11 +69,11 @@ F src/update.c 96461bcf4e946697e83c09c77c7e61b545a2f66e F src/utf.c 59b5c8f06a4384a9f64933d6c57a2de02ce3673b F src/util.c d299404febd509556e720fbecadd880756b0f899 F src/vacuum.c 8734f89742f246abd91dbd3e087fc153bddbfbad -F src/vdbe.c 2f2c9859ad19836b31825d2d70c4a8e6a9eba0d1 +F src/vdbe.c c068f9ab3d82906de297c1f20e50d601981328fb F src/vdbe.h e73f890e0f2a6c42b183d7d6937947930fe4fdeb -F src/vdbeInt.h fab8bb7f7a7f4e0714d9b3217c3db97366e16b99 +F src/vdbeInt.h 0c30699ea21371980bc278e4e3d17d80ced722df F src/vdbeapi.c b0bb1f98c899ba00c8a5cbca612c2a28a1bb79de -F src/vdbeaux.c 5b886ac74a68e7e956259eba53e3d002a8ddc6a7 +F src/vdbeaux.c c1beed304947bcfe49bd7c2abe45a58c2db0c67b F src/vdbemem.c b487e8a903012de1c0b7f603e8efeede2b51b21d F src/where.c efe5d25fe18cd7381722457898cd863e84097a0c F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242 @@ -154,7 +154,7 @@ F test/trigger1.test 4538c1c7d6bbca5dfe619ea6e1682b07ece95b21 F test/trigger2.test 0767ab30cb5a2c8402c8524f3d566b410b6f5263 F test/trigger3.test a95ccace88291449f5eae7139ec438a42f90654d F test/trigger4.test 542afce45774e8f8e1130b96b8675f414d6e4bd8 -F test/types.test 8fa51489d4765b8baa2d3c92de32aba06315a655 +F test/types.test 6c49e574970866558365a025b44c9fd8a162ef0d F test/types2.test 5d725fcb68dbd032c6d4950d568d75fa33872687 F test/unique.test 0e38d4cc7affeef2527720d1dafd1f6870f02f2b F test/update.test b29bd9061a1150426dab6959806fcc73a41b1217 @@ -203,7 +203,7 @@ F www/sqlite.tcl 3c83b08cf9f18aa2d69453ff441a36c40e431604 F www/tclsqlite.tcl b9271d44dcf147a93c98f8ecf28c927307abd6da F www/vdbe.tcl 9b9095d4495f37697fd1935d10e14c6015e80aa1 F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4 -P c85e5f1528d098ea330ed0cf7e3c01cf9be93c10 -R 0f424c162c35b47a72bb56f63064dff2 +P 287f86731c71401dbac098e08357367b4f8e5a43 +R ae5f0056bb6540c5d0436f9717bf751b U drh -Z 4f618cbd73c341429c69a19968301445 +Z 6b3a034bd2c2b8589e4d067a67b642dc diff --git a/manifest.uuid b/manifest.uuid index 1e9ff0d83b..50be98f33e 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -287f86731c71401dbac098e08357367b4f8e5a43 \ No newline at end of file +0c4d138807f367d75b3fb5b2dadf206df725659f \ No newline at end of file diff --git a/src/vdbe.c b/src/vdbe.c index c7ee88962b..3930fd6919 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -43,7 +43,7 @@ ** in this file for details. If in doubt, do not deviate from existing ** 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 "os.h" @@ -241,32 +241,6 @@ static Sorter *Merge(Sorter *pLeft, Sorter *pRight, KeyInfo *pKeyInfo){ 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; i0 ? zBuf : 0; -} - /* ** Make sure there is space in the Vdbe structure to hold at least ** mxCursor cursors. If there is not currently enough space, then @@ -1846,75 +1820,46 @@ case OP_SetNumColumns: { */ case OP_Column: { 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 */ - Cursor *pC = 0; + Cursor *pC = 0; /* The VDBE cursor */ 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 */ + u32 szHdr; /* Number of bytes in the record header */ int len; /* The length of the serialized data for the column */ - int offset = 0; - int nn; + int offset = 0; /* Offset into the data */ + 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; - - assert( inCursor ); + assert( p1nCursor ); 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; nndb->enc); - if( rc!=SQLITE_OK ){ - goto abort_due_to_error; - } - break; - } - - /* 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 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); zRec = 0; pCrsr = pC->pCursor; @@ -1929,11 +1874,13 @@ case OP_Column: { }else{ sqlite3BtreeDataSize(pCrsr, &payloadSize); } + nField = pC->nField; }else if( pC->pseudoTable ){ payloadSize = pC->nData; zRec = pC->pData; pC->cacheValid = 0; assert( payloadSize==0 || zRec!=0 ); + nField = pC->nField; }else{ payloadSize = 0; } @@ -1944,93 +1891,104 @@ case OP_Column: { break; } - /* If the row data is coming from a cursor, then OP_SetNumColumns must of - ** been executed on that cursor. Also, p2 (the column to read) must be - ** less than nField. - */ - assert( !pC || pC->nField>0 ); - assert( p2nField ); - nField = pC->nField; + assert( p2cacheValid ){ - pC->payloadSize = payloadSize; - if( !pC->aType ){ - pC->aType = sqliteMallocRaw( nField*sizeof(pC->aType[0]) ); - if( pC->aType==0 ){ - goto no_mem; - } + if( pC && pC->cacheValid ){ + aType = pC->aType; + aOffset = pC->aOffset; + }else{ + aType = sqliteMallocRaw( 2*nField*sizeof(aType) ); + aOffset = &aType[nField]; + if( aType==0 ){ + goto no_mem; } + /* Figure out how many bytes are in the header */ if( zRec ){ zData = zRec; }else{ - /* Estimate the maximum space required by the nField varints by - ** assuming the maximum space for each is the length required to store: - ** - ** ( * 2) + 13 - ** - ** 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; + int sz = payloadSize<5 ? payloadSize : 5; + if( pC->keyAsData ){ + zData = (char*)sqlite3BtreeKeyFetch(pCrsr, sz); + }else{ + zData = (char*)sqlite3BtreeDataFetch(pCrsr, sz); } + } + 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 ){ goto abort_due_to_error; } zData = sMem.z; } - /* Read all the serial types for the record. At the end of this block - ** variable offset is set to the offset to the start of Data0 in the record. + /* Scan the header and use it to fill in the aType[] and aOffset[] + ** 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; nnaType[nn]); + offset = szHdr; + i = 0; + while( idxnHeader = offset; - pC->cacheValid = 1; - 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 - ** of the data. And get the length of the data. + /* Get the column information. */ - offset = pC->nHeader; - for(nn=0; nnaType[nn]); - } - if( zRec ){ - zData = &zRec[offset]; + zData = &zRec[aOffset[p2]]; }else{ - len = sqlite3VdbeSerialTypeLen(pC->aType[p2]); - getBtreeMem(pCrsr, offset, len, pC->keyAsData, &sMem); + len = sqlite3VdbeSerialTypeLen(aType[p2]); + getBtreeMem(pCrsr, aOffset[p2], len, pC->keyAsData, &sMem); zData = sMem.z; } - sqlite3VdbeSerialGet(zData, pC->aType[p2], pTos, p->db->enc); + sqlite3VdbeSerialGet(zData, aType[p2], pTos, p->db->enc); if( rc!=SQLITE_OK ){ goto abort_due_to_error; } - Release(&sMem); + + /* Release the aType[] memory if we are not dealing with cursor */ + if( !pC ){ + sqliteFree(aType); + } break; } /* 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 ** suitable for use as a data record in a database table. The ** details of the format are irrelavant as long as the OP_Column @@ -2056,7 +2014,7 @@ case OP_MakeRecord: { ** 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 @@ -2074,7 +2032,9 @@ case OP_MakeRecord: { unsigned char *zCsr; char *zAffinity; 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]; assert( pData0>=p->aStack ); @@ -2089,23 +2049,26 @@ case OP_MakeRecord: { applyAffinity(pRec, zAffinity[pRec-pData0], db->enc); } serial_type = sqlite3VdbeSerialType(pRec); - nBytes += sqlite3VdbeSerialTypeLen(serial_type); - nBytes += sqlite3VarintLen(serial_type); + nData += sqlite3VdbeSerialTypeLen(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; goto abort_due_to_error; } /* Allocate space for the new record. */ - zNewRecord = sqliteMallocRaw(nBytes); + zNewRecord = sqliteMallocRaw(nByte); if( !zNewRecord ){ goto no_mem; } /* Write the record */ zCsr = zNewRecord; + zCsr += sqlite3PutVarint(zCsr, nHdr); for(pRec=pData0; pRec<=pTos; pRec++){ u64 serial_type = sqlite3VdbeSerialType(pRec); zCsr += sqlite3PutVarint(zCsr, serial_type); /* serial type */ @@ -2114,11 +2077,11 @@ case OP_MakeRecord: { 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 ** failed. This indicates a corrupted memory cell or code bug. */ - if( zCsr!=(zNewRecord+nBytes) ){ + if( zCsr!=(zNewRecord+nByte) ){ rc = SQLITE_INTERNAL; goto abort_due_to_error; } @@ -2126,7 +2089,7 @@ case OP_MakeRecord: { /* Pop nField entries from the stack and push the new entry on */ popStack(&pTos, nField); pTos++; - pTos->n = nBytes; + pTos->n = nByte; pTos->z = zNewRecord; pTos->flags = MEM_Blob | MEM_Dyn; diff --git a/src/vdbeInt.h b/src/vdbeInt.h index c0c99b12aa..9e8abcbcb9 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -80,14 +80,14 @@ struct Cursor { i64 iKey; /* Key for the NEW or OLD pseudo-table row */ u8 *pIncrKey; /* Pointer to pKeyInfo->incrKey */ 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 ** cursor is currently pointing to */ 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 */ - 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; @@ -367,4 +367,3 @@ int sqlite3VdbeMemRealify(Mem*); #ifndef NDEBUG void sqlite3VdbeMemSanity(Mem*, u8); #endif - diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 5028dc9381..e6c3606bfb 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -1431,44 +1431,37 @@ int sqlite3VdbeRowCompare( int nKey2, const void *pKey2 ){ KeyInfo *pKeyInfo = (KeyInfo*)userData; - int offset1 = 0; - int offset2 = 0; - int toffset1 = 0; - int toffset2 = 0; - int i; - u8 enc = pKeyInfo->enc; + u32 d1, d2; /* Offset into aKey[] of next data element */ + u32 idx1, idx2; /* Offset into aKey[] of next header element */ + u32 szHdr1, szHdr2; /* Number of bytes in header */ + int i = 0; + int nField; + int rc = 0; const unsigned char *aKey1 = (const unsigned char *)pKey1; const unsigned char *aKey2 = (const unsigned char *)pKey2; - - assert( pKeyInfo ); - assert( pKeyInfo->nField>0 ); - - for( i=0; inField; i++ ){ - u64 dummy; - offset1 += sqlite3GetVarint(&aKey1[offset1], &dummy); - offset2 += sqlite3GetVarint(&aKey1[offset1], &dummy); - } - - for( i=0; inField; i++ ){ + + idx1 = sqlite3GetVarint32(pKey1, &szHdr1); + d1 = szHdr1; + idx2 = sqlite3GetVarint32(pKey2, &szHdr2); + d2 = szHdr2; + nField = pKeyInfo->nField; + while( idx1aColl[i]); if( mem1.flags&MEM_Dyn ){ @@ -1478,11 +1471,31 @@ int sqlite3VdbeRowCompare( sqliteFree(mem2.z); } 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( d1aSortOrder && inField && pKeyInfo->aSortOrder[i] ){ + rc = -rc; + } + + return rc; } diff --git a/test/types.test b/test/types.test index 7d9cbb67d4..9ca1947482 100644 --- a/test/types.test +++ b/test/types.test @@ -12,7 +12,7 @@ # it tests that the different storage classes (integer, real, text etc.) # 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] source $testdir/tester.tcl @@ -199,7 +199,7 @@ do_test types-2.1.8 { do_test types-2.1.9 { set root [db eval {select rootpage from sqlite_master where name = 't1'}] 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. do_test types-2.2.1 { @@ -220,7 +220,7 @@ do_test types-2.2.2 { do_test types-2.2.3 { set root [db eval {select rootpage from sqlite_master where name = 't2'}] record_sizes $root -} {9 9 9} +} {10 10 10} # Insert a NULL. This should be a two byte record. do_test types-2.3.1 { @@ -239,7 +239,7 @@ do_test types-2.3.2 { do_test types-2.3.3 { set root [db eval {select rootpage from sqlite_master where name = 't3'}] record_sizes $root -} {1} +} {2} # Insert a couple of strings. do_test types-2.4.1 { @@ -264,7 +264,7 @@ do_test types-2.4.2 { do_test types-2.4.3 { set root [db eval {select rootpage from sqlite_master where name = 't4'}] record_sizes $root -} {11 502 500003} +} {12 503 500004} do_test types-2.5.1 { execsql {