From 192ac1dcabe3689d157f1ea42e8e5ead5d94a55e Mon Sep 17 00:00:00 2001 From: danielk1977 Date: Mon, 10 May 2004 07:17:30 +0000 Subject: [PATCH] Add versions of OP_MakeRecord and OP_Column that use manifest typing (not activated yet). (CVS 1334) FossilOrigin-Name: 8a66a502ba09e3d858d2f45df9b3b665ebb85d5b --- manifest | 20 ++-- manifest.uuid | 2 +- src/sqliteInt.h | 7 +- src/util.c | 29 +++++- src/vdbe.c | 261 +++++++++++++++++++++++++++++++++++++++++++++++- src/vdbeInt.h | 3 + src/vdbeaux.c | 27 +++++ 7 files changed, 333 insertions(+), 16 deletions(-) diff --git a/manifest b/manifest index 3e44a9cb21..5b5f47005c 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Change\ssome\scode\sthat\sassumes\sthe\sroot-page\sof\ssqlite_master\sis\s2\s(it\sis\nnow\s1)\s(CVS\s1333) -D 2004-05-10T01:17:37 +C Add\sversions\sof\sOP_MakeRecord\sand\sOP_Column\sthat\suse\smanifest\styping\s(not\nactivated\syet).\s(CVS\s1334) +D 2004-05-10T07:17:31 F Makefile.in ab7b0d5118e2da97bac66be8684a1034e3500f5a F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd @@ -49,7 +49,7 @@ F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3 F src/select.c d3868613e70ac09cf2fb4ddd211f088351d1fe51 F src/shell.c 9a242ad03c8726823f182bff81c5e12ef2882f93 F src/sqlite.h.in 532e08163a8df8b71faf7be4e69ba208938eb312 -F src/sqliteInt.h 92fb41170e75e1ce9ad8aea591fd55e7cf49b815 +F src/sqliteInt.h 987dd79044a37a37f1c386d5e3bcd702c62e27ab F src/table.c 882b0ae9524c67758157540dd6467c9a5de52335 F src/tclsqlite.c 21147148e7b57a0bb7409cff5878c60470df9acc F src/test1.c 67a72fa1f5f6d41c838fa97f324f8dbfb4051413 @@ -61,12 +61,12 @@ F src/tokenize.c 256a3cf0ff938cd79774d7f95173d74281912df9 F src/trigger.c 8b07ff87b39f24997e5f737340ebbb5ce09ca481 F src/update.c 475465fc0582160dadf5455b05235cb13c9e21f9 F src/utf.c fc799748d43fe1982d157b871e3e420a19c85d4f -F src/util.c 0c31a53b848648271d0910c2604b4d8ae516ebb1 +F src/util.c da3b43129c8912eeee1ef0599e740331ed5b8c39 F src/vacuum.c 91ba5a23eca2d9a8a11191cef577d417f9318976 -F src/vdbe.c bf7d4826cbf18c49b7ac1a5ddbc70db65ac35487 +F src/vdbe.c 3d90858d784c4353a6e5ee45a0e4d82b9ba2aa5c F src/vdbe.h 2dc4d1161b64f5684faa6a2d292e318a185ecb2e -F src/vdbeInt.h 19926d40956eea309f58bc569f9ae02f62350db2 -F src/vdbeaux.c 2789bdd1f9b510b35b0102174a5b73b8267c4f71 +F src/vdbeInt.h e4ab46c223bac43754335cdd14c9c6a95885b9a8 +F src/vdbeaux.c 4dac7718b04e6773aba8586221faadd62aa742a7 F src/where.c 6db0291280f2c642bae2c69a70750325b53717a4 F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242 F test/attach.test ba8261d38da6b6a7d4f78ec543c548c4418582ef @@ -187,7 +187,7 @@ F www/sqlite.tcl 3c83b08cf9f18aa2d69453ff441a36c40e431604 F www/tclsqlite.tcl b9271d44dcf147a93c98f8ecf28c927307abd6da F www/vdbe.tcl 9b9095d4495f37697fd1935d10e14c6015e80aa1 F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4 -P d8d1c91e55f24d17233414facaa03136b3b320d5 -R d45fafcad74fbf012530271bdce1ade4 +P 37ae528fb85799007f4ddfc56a7d9493dbb29cbf +R c990744bdc97fc1baad79ce9e836f1a6 U danielk1977 -Z c59557a5034f7f7676ea623232f2d759 +Z e5f755ccd557a6659426f0557b9e2215 diff --git a/manifest.uuid b/manifest.uuid index d3899f7ff7..b26aac6ae8 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -37ae528fb85799007f4ddfc56a7d9493dbb29cbf \ No newline at end of file +8a66a502ba09e3d858d2f45df9b3b665ebb85d5b \ No newline at end of file diff --git a/src/sqliteInt.h b/src/sqliteInt.h index a3e28d2a2e..8360f493ab 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.225 2004/05/10 01:17:37 danielk1977 Exp $ +** @(#) $Id: sqliteInt.h,v 1.226 2004/05/10 07:17:31 danielk1977 Exp $ */ #include "config.h" #include "sqlite.h" @@ -1284,6 +1284,7 @@ void *sqlite3utf8to16be(const unsigned char *pIn, int N); void *sqlite3utf8to16le(const unsigned char *pIn, int N); void sqlite3utf16to16le(void *pData, int N); void sqlite3utf16to16be(void *pData, int N); - - +int sqlite3PutVarint(unsigned char *, u64); +int sqlite3GetVarint(unsigned char *, u64 *); +int sqlite3VarintLen(u64 v); diff --git a/src/util.c b/src/util.c index 917a243849..a3df127d3f 100644 --- a/src/util.c +++ b/src/util.c @@ -14,7 +14,7 @@ ** This file contains functions for allocating memory, comparing ** strings, and stuff like that. ** -** $Id: util.c,v 1.76 2004/05/08 08:23:40 danielk1977 Exp $ +** $Id: util.c,v 1.77 2004/05/10 07:17:32 danielk1977 Exp $ */ #include "sqliteInt.h" #include @@ -1134,5 +1134,32 @@ int sqlite3SafetyCheck(sqlite *db){ return 0; } +int sqlite3PutVarint(unsigned char *p, u64 v){ + int i = 0; + do{ + p[i++] = (v & 0x7f) | 0x80; + v >>= 7; + }while( v!=0 ); + p[i-1] &= 0x7f; + return i; +} +int sqlite3GetVarint(unsigned char *p, u64 *v){ + u64 x = p[0] & 0x7f; + int n = 0; + while( (p[n++]&0x80)!=0 ){ + x |= (p[n]&0x7f)<<(n*7); + } + *v = x; + return n; +} + +int sqlite3VarintLen(u64 v){ + int i = 0; + do{ + i++; + v >>= 7; + }while( v!=0 ); + return i; +} diff --git a/src/vdbe.c b/src/vdbe.c index b47632c341..b9b558d9f1 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.271 2004/05/09 23:23:58 danielk1977 Exp $ +** $Id: vdbe.c,v 1.272 2004/05/10 07:17:32 danielk1977 Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -1809,6 +1809,265 @@ case OP_NotNull: { break; } +/* Opcode: Column3 P1 P2 * +** +** This opcode (not yet in use) is a replacement for the current +** OP_Column3 that supports the SQLite3 manifest typing feature. +** +** Interpret the data that cursor P1 points to as +** a structure built using the MakeRecord instruction. +** (See the MakeRecord opcode for additional information about +** the format of the data.) +** Push onto the stack the value of the P2-th column contained +** in the data. +** +** If the KeyAsData opcode has previously executed on this cursor, +** then the field might be extracted from the key rather than the +** data. +** +** If P1 is negative, then the record is stored on the stack rather +** than in a table. For P1==-1, the top of the stack is used. +** For P1==-2, the next on the stack is used. And so forth. The +** value pushed is always just a pointer into the record which is +** stored further down on the stack. The column value is not copied. +*/ +case OP_Column3: { + int payloadSize; + int i = pOp->p1; + int p2 = pOp->p2; + Cursor *pC; + char *zRec; + BtCursor *pCrsr; + + char *zHdr = 0; + int freeZHdr = 0; + int dataOffsetLen; + u64 dataOffset; + char *zIdx = 0; + int cnt; + u64 idxN; + u64 idxN1; + + assert( inCursor ); + pTos++; + if( i<0 ){ + assert( &pTos[i]>=p->aStack ); + assert( pTos[i].flags & MEM_Str ); + zRec = pTos[i].z; + payloadSize = pTos[i].n; + }else if( (pC = &p->aCsr[i])->pCursor!=0 ){ + sqlite3VdbeCursorMoveto(pC); + zRec = 0; + pCrsr = pC->pCursor; + if( pC->nullRow ){ + payloadSize = 0; + }else if( pC->keyAsData ){ + u64 payloadSize64; + sqlite3BtreeKeySize(pCrsr, &payloadSize64); + payloadSize = payloadSize64; + }else{ + sqlite3BtreeDataSize(pCrsr, &payloadSize); + } + }else if( pC->pseudoTable ){ + payloadSize = pC->nData; + zRec = pC->pData; + assert( payloadSize==0 || zRec!=0 ); + }else{ + payloadSize = 0; + } + + /* If payloadSize is 0, then just push a NULL onto the stack. */ + if( payloadSize==0 ){ + pTos->flags = MEM_Null; + break; + } + + /* Read the data-offset for this record */ + if( zRec ){ + dataOffsetLen = sqlite3GetVarint(zRec, &dataOffset); + }else{ + unsigned char zDataOffset[9]; + if( pC->keyAsData ){ + sqlite3BtreeKey(pCrsr, 0, 9, zDataOffset); + }else{ + sqlite3BtreeData(pCrsr, 0, 9, zDataOffset); + } + dataOffsetLen = sqlite3GetVarint(zDataOffset, &dataOffset); + } + + /* Set zHdr to point at the start of the Idx() fields of the + ** record. Set freeZHdr to 1 if we need to sqliteFree(zHdr) later. + */ + if( zRec ){ + zHdr = zRec + dataOffsetLen; + }else{ + zHdr = sqliteMalloc(dataOffset); + if( !zHdr ){ + rc = SQLITE_NOMEM; + goto abort_due_to_error; + } + freeZHdr = 1; + if( pC->keyAsData ){ + sqlite3BtreeKey(pCrsr, dataOffsetLen, dataOffset, zHdr); + }else{ + sqlite3BtreeData(pCrsr, dataOffsetLen, dataOffset, zHdr); + } + } + + /* Find the Nth byte of zHdr that does not have the 0x80 + ** bit set. The byte after this one is the start of the Idx(N) + ** varint. Then read Idx(N) and Idx(N+1) + */ + cnt = p2; + zIdx = zHdr; + while( cnt>0 ){ + assert( (zIdx-zHdr)0 ); + zHdr = sqliteMalloc(cnt); + if( !zHdr ){ + rc = SQLITE_NOMEM; + goto abort_due_to_error; + } + freeZHdr = 1; + if( pC->keyAsData ){ + sqlite3BtreeKey(pCrsr, dataOffsetLen+dataOffset+idxN, cnt, zHdr); + }else{ + sqlite3BtreeData(pCrsr, dataOffsetLen+dataOffset+idxN, cnt, zHdr); + } + } + + /* Deserialize the field value directory into the top of the + ** stack. If the deserialized length does not match the expected + ** length, this indicates corruption. + */ + if( (idxN1-idxN)!=sqlite3VdbeDeserialize(pTos, zHdr) ){ + if( freeZHdr ){ + sqliteFree(zHdr); + } + rc = SQLITE_CORRUPT; + goto abort_due_to_error; + } + + if( freeZHdr ){ + sqliteFree(zHdr); + } + break; +} + +/* Opcode MakeRecord3 P1 * * +** +** 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 +** opcode can decode the record later. Refer to source code +** comments for the details of the record format. +*/ +case OP_MakeRecord3: { + /* Assuming the record contains N fields, the record format looks + ** like this: + ** + ** -------------------------------------------------------------------------- + ** | data-offset | idx1 | ... | idx(N-1) | idx(N) | data0 | ... | data(N-1) | + ** -------------------------------------------------------------------------- + ** + ** Data(0) is taken from the lowest element of the stack and data(N-1) is + ** the top of the stack. + ** + ** The data-offset and each of the idx() entries is stored as a 1-9 + ** byte variable-length integer (see comments in btree.c). The + ** data-offset contains the offset from the end of itself to the start + ** of data(0). + ** + ** Idx(k) contains the offset from the start of data(0) to the first + ** byte of data(k). Idx(0) is implicitly 0. Hence: + ** + ** sizeof(data-offset) + data-offset + Idx(N) + ** + ** is the number of bytes in the record. The offset to start of data(X) + ** is sizeof(data-offset) + data-offset + Idx(X + ** + ** TODO: Even when the record is short enough for Mem::zShort, this opcode + ** allocates it dynamically. + */ + int nDataLen = 0; + int nHdrLen = 0; + int data_offset = 0; + int nField = pOp->p1; + unsigned char *zNewRecord; + unsigned char *zHdr; + Mem *pRec; + + Mem *pData0 = &pTos[1-nField]; + assert( pData0>=p->aStack ); + + /* Loop through the elements that will make up the record, determining + ** the aggregate length of the Data() segments and the data_offset. + */ + for(pRec=pData0; pRec!=pTos; pRec++){ + nDataLen += sqlite3VdbeSerialLen(pRec); + data_offset += sqlite3VarintLen(nDataLen); + } + + /* The size of the header is the data-offset + the size of the + ** data-offset as a varint. If the size of the header combined with + ** the size of the Data() segments is greater than MAX_BYTES_PER_ROW, + ** report an error. + */ + nHdrLen = data_offset + sqlite3VarintLen(data_offset); + if( (nHdrLen+nDataLen)>MAX_BYTES_PER_ROW ){ + rc = SQLITE_TOOBIG; + goto abort_due_to_error; + } + + /* Allocate space for the new row. */ + zNewRecord = sqliteMalloc(nHdrLen+nDataLen); + if( !zNewRecord ){ + rc = SQLITE_NOMEM; + goto abort_due_to_error; + } + + /* Write the data offset */ + zHdr = zNewRecord; + zHdr += sqlite3PutVarint(zHdr, data_offset); + + /* Loop through the values on the stack writing both the serialized value + ** and the the Idx() offset for each. + */ + nDataLen = 0; + for(pRec=pData0; pRec!=pTos; pRec++){ + nDataLen += sqlite3VdbeSerialize(pRec, &zNewRecord[nDataLen]); + zHdr += sqlite3PutVarint(zHdr, nDataLen); + } + + /* Pop nField entries from the stack and push the new entry on */ + popStack(&pTos, nField); + pTos++; + pTos->n = nDataLen+nHdrLen; + pTos->z = zNewRecord; + pTos->flags = MEM_Str | MEM_Dyn; + + break; +} + /* Opcode: MakeRecord P1 P2 * ** ** Convert the top P1 entries of the stack into a single entry diff --git a/src/vdbeInt.h b/src/vdbeInt.h index 475a2c4330..44bd4e7d3f 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -301,6 +301,9 @@ int sqlite3VdbeByteSwap(int); #if !defined(NDEBUG) || defined(VDBE_PROFILE) void sqlite3VdbePrintOp(FILE*, int, Op*); #endif +int sqlite3VdbeSerialize(const Mem *, unsigned char *); +int sqlite3VdbeSerialLen(const Mem *); +int sqlite3VdbeDeserialize(Mem *, const unsigned char *); int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *); diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 733885ae57..2900af6e61 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -1100,6 +1100,33 @@ int sqlite2BtreeKeyCompare( return rc; } +/* +** Write the serialized form of the value held by pMem into zBuf. Return +** the number of bytes written. +*/ +int sqlite3VdbeSerialize( + const Mem *pMem, /* Pointer to vdbe value to serialize */ + unsigned char *zBuf /* Buffer to write to */ +){ +} + +/* +** Return the number of bytes that would be consumed by the serialized +** form of the value held by pMem. Return negative if an error occurs. +*/ +int sqlite3VdbeSerialLen(const Mem *pMem){ +} + +/* +** Deserialize a value from zBuf and store it in *pMem. Return the number +** of bytes written, or negative if an error occurs. +*/ +int sqlite3VdbeDeserialize( + Mem *pMem, /* structure to write new value to */ + const unsigned char *zBuf /* Buffer to read from */ +){ +} + /* ** The following is the comparison function for (non-integer) ** keys in the btrees. This function returns negative, zero, or