mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-07 02:42:48 +03:00
Modify the {quote: IdxDelete} opcode so that it takes an array of registers rather
than a record formed using {quote: MakeRecord.} This avoids a needless packing and unpacking of the record to be deleted. (CVS 4916) FossilOrigin-Name: ee381b43563e1b0637ee74389d076dff77deddf9
This commit is contained in:
36
manifest
36
manifest
@@ -1,5 +1,5 @@
|
||||
C Test\sstring\svalues\spassed\sto\sbind_text()\sand\sresult_text()\sfor\sa\snul-terminator.\s(CVS\s4915)
|
||||
D 2008-03-25T16:16:29
|
||||
C Modify\sthe\s{quote:\sIdxDelete}\sopcode\sso\sthat\sit\stakes\san\sarray\sof\sregisters\srather\r\nthan\sa\srecord\sformed\susing\s{quote:\sMakeRecord.}\s\sThis\savoids\sa\sneedless\spacking\r\nand\sunpacking\sof\sthe\srecord\sto\sbe\sdeleted.\s(CVS\s4916)
|
||||
D 2008-03-25T17:23:33
|
||||
F Makefile.arm-wince-mingw32ce-gcc ac5f7b2cef0cd850d6f755ba6ee4ab961b1fadf7
|
||||
F Makefile.in cf434ce8ca902e69126ae0f94fc9f7dc7428a5fa
|
||||
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
||||
@@ -86,14 +86,14 @@ F src/attach.c bdc75e759ca25a16f4dc7fbdbc6d37ad2561bb24
|
||||
F src/auth.c c8b2ab5c8bad4bd90ed7c294694f48269162c627
|
||||
F src/bitvec.c 49817d442e51e4123585f3cf3c2afc293a3c91e2
|
||||
F src/btmutex.c 483ced3c52205b04b97df69161fadbf87f4f1ea2
|
||||
F src/btree.c 366f5f66ebb3dfdc8513242d4aecbfb402dcc0a9
|
||||
F src/btree.h e02869e1e7753ad5b3c7cb7852e952c95c2e609a
|
||||
F src/btree.c 6e60d634d236232efbb289b800dd76e72a5ecf9d
|
||||
F src/btree.h c66cb17c6fffa84a88926dbef173bab4ae692fd4
|
||||
F src/btreeInt.h d232be68a7ab2a24376dc6332a869e717551b0bd
|
||||
F src/build.c d0715b3454b140cb405412e3029ec7c0fb434efd
|
||||
F src/build.c 4e6321d112f0ed1070c579677573e4eb76cda1fd
|
||||
F src/callback.c 77b302b0d41468dcda78c70e706e5b84577f0fa0
|
||||
F src/complete.c 4cf68fd75d60257524cbe74f87351b9848399131
|
||||
F src/date.c e41ce4513fb0e359dc678d6bddb4ace135fe365d
|
||||
F src/delete.c 526b783b71b9885b201d74720d44a386b971dc01
|
||||
F src/delete.c 3dc7d7cc46c8675219a7776b7c67b626bba530df
|
||||
F src/experimental.c 1b2d1a6cd62ecc39610e97670332ca073c50792b
|
||||
F src/expr.c 7e56d2a24af8137f4bebbfa1d7dd1dcf70107c88
|
||||
F src/fault.c c28478c7190daef16be09d261c5461638b4d686c
|
||||
@@ -131,22 +131,22 @@ F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b
|
||||
F src/pager.c 22241b59c80ca083a96816df434adb8c097afcd4
|
||||
F src/pager.h b1e2258f03878c14b06a95bfa362e8c5c9638170
|
||||
F src/parse.y b0ee84d94218046ea88c2a6561005710d127ca7d
|
||||
F src/pragma.c f64eed914518c28d1863356163dea1e6f58e28f2
|
||||
F src/pragma.c 99cec6d99d0241436494aab15b05da97b0e70683
|
||||
F src/prepare.c 185fb47f1fb3e45a345d523eb391d673f5eb367c
|
||||
F src/printf.c 05d2b44d7b5b80c8a4a09108ddad9c20e254370d
|
||||
F src/random.c 2b2db2de4ab491f5a14d3480466f8f4b5a5db74a
|
||||
F src/select.c c06849a0d0ad408fbdd8180439176e94aae43e56
|
||||
F src/select.c 831714d4f09f4b9f4be43d2399eff12dcf281c86
|
||||
F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96
|
||||
F src/shell.c 22297fffa6f00a6c6d44020fa13b1184a1bb372d
|
||||
F src/sqlite.h.in 61d8d1cefcbf0803c03c2179be138a78bfd1d335
|
||||
F src/sqlite3ext.h faacd0e6a81aabee0861c6d7883c9172e74ef5b3
|
||||
F src/sqliteInt.h 07b472437b2d7297c300f8b7cea5205984fa64d1
|
||||
F src/sqliteInt.h 50a9313829041721d34f20c8be4562c3197dcff9
|
||||
F src/sqliteLimit.h eecbc288b410ae5565e71aaa4a439aae57bb0707
|
||||
F src/table.c 2c48c575dd59b3a6c5c306bc55f51a9402cf429a
|
||||
F src/tclsqlite.c 1367762764772a233643524c3585b4711a9adcda
|
||||
F src/test1.c 342a2628310fa709074d979e695a28a3bb570834
|
||||
F src/test2.c f0808cc643528b9620e4059ca9bda8346f526121
|
||||
F src/test3.c 31027a4a190d2f3c1e479ea2d750e696160bbf04
|
||||
F src/test3.c c715b5a8a6415d7b2c67f97c394eef488b6f7e63
|
||||
F src/test4.c c2c0f5dc907f1346f5d4b65eb5799f11eb9e4071
|
||||
F src/test5.c 3a6a5717a149d7ca2e6d14f5be72cf7555d54dc4
|
||||
F src/test6.c 62281c0a9ac0265e579065942f7de4e080f8eb05
|
||||
@@ -174,11 +174,11 @@ F src/update.c 2aefd3c9277792e9fa2414dfe14202119fa49fe7
|
||||
F src/utf.c 32b00d6e19010025e58f2ecb2f921d5e126771b4
|
||||
F src/util.c dba9e04121eb17ec4643d6ca231ff859452cf0e2
|
||||
F src/vacuum.c 3524411bfb58aac0d87eadd3e5b7cd532772af30
|
||||
F src/vdbe.c bdcbf54cf944a99b004e87a523736dd326fa34be
|
||||
F src/vdbe.h 0fef6798be121ed2b5a547a5cb85e0824ec3971f
|
||||
F src/vdbeInt.h 4bbec80d55d179ab8438ac9822416d9111638919
|
||||
F src/vdbe.c 0068703495a197e7b77dbdff604b42896722a1cc
|
||||
F src/vdbe.h ecca2e1c1ac1066f4e68ad38068a20ea32ea7063
|
||||
F src/vdbeInt.h 4d767f189a1d13ff8d4881de60aacc470e54f5b8
|
||||
F src/vdbeapi.c b9e9d7a58690c1e1ae66de7232edccf4793ad817
|
||||
F src/vdbeaux.c c071014d81c1d4b2c381247c16a3e86182951e51
|
||||
F src/vdbeaux.c e45929a3b5e59e8f2d69b7d6164c9a636149e1df
|
||||
F src/vdbeblob.c cc713c142c3d4952b380c98ee035f850830ddbdb
|
||||
F src/vdbefifo.c a30c237b2a3577e1415fb6e288cbb6b8ed1e5736
|
||||
F src/vdbemem.c d48a71d66a7afd564b6537ab7e7442f7729fa5af
|
||||
@@ -617,7 +617,7 @@ F www/tclsqlite.tcl 8be95ee6dba05eabcd27a9d91331c803f2ce2130
|
||||
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
|
||||
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
|
||||
F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
|
||||
P fe1bc0f3b7cd87cd65f7d03b91095b59788a6f8d
|
||||
R 033bb4545035899c2c5396ecb143bb5f
|
||||
U danielk1977
|
||||
Z 09f5af34fae3a95557976f8d7d3936e3
|
||||
P 24c3ebc0c5c53c234516d16dce761d713fb29578
|
||||
R 66dfc33f9c0d1eba54064363b17cc27e
|
||||
U drh
|
||||
Z 040d5190ae2e9926a42f3065a9864529
|
||||
|
@@ -1 +1 @@
|
||||
24c3ebc0c5c53c234516d16dce761d713fb29578
|
||||
ee381b43563e1b0637ee74389d076dff77deddf9
|
50
src/btree.c
50
src/btree.c
@@ -9,7 +9,7 @@
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** $Id: btree.c,v 1.446 2008/03/25 14:24:57 danielk1977 Exp $
|
||||
** $Id: btree.c,v 1.447 2008/03/25 17:23:33 drh Exp $
|
||||
**
|
||||
** This file implements a external (disk-based) database using BTrees.
|
||||
** See the header comment on "btreeInt.h" for additional information.
|
||||
@@ -379,7 +379,7 @@ int sqlite3BtreeRestoreOrClearCursorPosition(BtCursor *pCur){
|
||||
}
|
||||
#endif
|
||||
pCur->eState = CURSOR_INVALID;
|
||||
rc = sqlite3BtreeMoveto(pCur, pCur->pKey, pCur->nKey, 0, &pCur->skip);
|
||||
rc = sqlite3BtreeMoveto(pCur, pCur->pKey, 0, pCur->nKey, 0, &pCur->skip);
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3_free(pCur->pKey);
|
||||
pCur->pKey = 0;
|
||||
@@ -3548,12 +3548,13 @@ int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Move the cursor so that it points to an entry near pKey/nKey.
|
||||
** Return a success code.
|
||||
/* Move the cursor so that it points to an entry near the key
|
||||
** specified by pKey/nKey/pUnKey. Return a success code.
|
||||
**
|
||||
** For INTKEY tables, only the nKey parameter is used. pKey is
|
||||
** ignored. For other tables, nKey is the number of bytes of data
|
||||
** in pKey.
|
||||
** For INTKEY tables, only the nKey parameter is used. pKey
|
||||
** and pUnKey must be NULL. For index tables, either pUnKey
|
||||
** must point to a key that has already been unpacked, or else
|
||||
** pKey/nKey describes a blob containing the key.
|
||||
**
|
||||
** If an exact match is not found, then the cursor is always
|
||||
** left pointing at a leaf page which would hold the entry if it
|
||||
@@ -3578,12 +3579,12 @@ int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
|
||||
int sqlite3BtreeMoveto(
|
||||
BtCursor *pCur, /* The cursor to be moved */
|
||||
const void *pKey, /* The key content for indices. Not used by tables */
|
||||
UnpackedRecord *pUnKey,/* Unpacked version of pKey */
|
||||
i64 nKey, /* Size of pKey. Or the key for tables */
|
||||
int biasRight, /* If true, bias the search to the high end */
|
||||
int *pRes /* Search result flag */
|
||||
){
|
||||
int rc;
|
||||
VdbeParsedRecord *pPKey;
|
||||
char aSpace[200];
|
||||
|
||||
assert( cursorHoldsMutex(pCur) );
|
||||
@@ -3600,11 +3601,22 @@ int sqlite3BtreeMoveto(
|
||||
return SQLITE_OK;
|
||||
}
|
||||
if( pCur->pPage->intKey ){
|
||||
pPKey = 0;
|
||||
}else{
|
||||
pPKey = sqlite3VdbeRecordParse(pCur->pKeyInfo, nKey, pKey,
|
||||
/* We are given an SQL table to search. The key is the integer
|
||||
** rowid contained in nKey. pKey and pUnKey should both be NULL */
|
||||
assert( pUnKey==0 );
|
||||
assert( pKey==0 );
|
||||
}else if( pUnKey==0 ){
|
||||
/* We are to search an SQL index using a key encoded as a blob.
|
||||
** The blob is found at pKey and is nKey bytes in length. Unpack
|
||||
** this key so that we can use it. */
|
||||
assert( pKey!=0 );
|
||||
pUnKey = sqlite3VdbeRecordUnpack(pCur->pKeyInfo, nKey, pKey,
|
||||
aSpace, sizeof(aSpace));
|
||||
if( pPKey==0 ) return SQLITE_NOMEM;
|
||||
if( pUnKey==0 ) return SQLITE_NOMEM;
|
||||
}else{
|
||||
/* We are to search an SQL index using a key that is already unpacked
|
||||
** and handed to us in pUnKey. */
|
||||
assert( pKey==0 );
|
||||
}
|
||||
for(;;){
|
||||
int lwr, upr;
|
||||
@@ -3613,7 +3625,7 @@ int sqlite3BtreeMoveto(
|
||||
int c = -1; /* pRes return if table is empty must be -1 */
|
||||
lwr = 0;
|
||||
upr = pPage->nCell-1;
|
||||
if( !pPage->intKey && pKey==0 ){
|
||||
if( !pPage->intKey && pUnKey==0 ){
|
||||
rc = SQLITE_CORRUPT_BKPT;
|
||||
goto moveto_finish;
|
||||
}
|
||||
@@ -3646,7 +3658,7 @@ int sqlite3BtreeMoveto(
|
||||
pCellKey = (void *)fetchPayload(pCur, &available, 0);
|
||||
nCellKey = pCur->info.nKey;
|
||||
if( available>=nCellKey ){
|
||||
c = sqlite3VdbeRecordCompareParsed(nCellKey, pCellKey, pPKey);
|
||||
c = sqlite3VdbeRecordCompare(nCellKey, pCellKey, pUnKey);
|
||||
}else{
|
||||
pCellKey = sqlite3_malloc( nCellKey );
|
||||
if( pCellKey==0 ){
|
||||
@@ -3654,7 +3666,7 @@ int sqlite3BtreeMoveto(
|
||||
goto moveto_finish;
|
||||
}
|
||||
rc = sqlite3BtreeKey(pCur, 0, nCellKey, (void *)pCellKey);
|
||||
c = sqlite3VdbeRecordCompareParsed(nCellKey, pCellKey, pPKey);
|
||||
c = sqlite3VdbeRecordCompare(nCellKey, pCellKey, pUnKey);
|
||||
sqlite3_free(pCellKey);
|
||||
if( rc ) goto moveto_finish;
|
||||
}
|
||||
@@ -3701,7 +3713,11 @@ int sqlite3BtreeMoveto(
|
||||
if( rc ) goto moveto_finish;
|
||||
}
|
||||
moveto_finish:
|
||||
sqlite3VdbeRecordUnparse(pPKey);
|
||||
if( pKey ){
|
||||
/* If we created our own unpacked key at the top of this
|
||||
** procedure, then destroy that key before returning. */
|
||||
sqlite3VdbeDeleteUnpackedRecord(pUnKey);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -5619,7 +5635,7 @@ int sqlite3BtreeInsert(
|
||||
clearCursorPosition(pCur);
|
||||
if(
|
||||
SQLITE_OK!=(rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur)) ||
|
||||
SQLITE_OK!=(rc = sqlite3BtreeMoveto(pCur, pKey, nKey, appendBias, &loc))
|
||||
SQLITE_OK!=(rc = sqlite3BtreeMoveto(pCur, pKey, 0, nKey, appendBias, &loc))
|
||||
){
|
||||
return rc;
|
||||
}
|
||||
|
13
src/btree.h
13
src/btree.h
@@ -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.96 2008/03/25 09:47:35 danielk1977 Exp $
|
||||
** @(#) $Id: btree.h,v 1.97 2008/03/25 17:23:33 drh Exp $
|
||||
*/
|
||||
#ifndef _BTREE_H_
|
||||
#define _BTREE_H_
|
||||
@@ -127,6 +127,8 @@ int sqlite3BtreeGetMeta(Btree*, int idx, u32 *pValue);
|
||||
int sqlite3BtreeUpdateMeta(Btree*, int idx, u32 value);
|
||||
void sqlite3BtreeTripAllCursors(Btree*, int);
|
||||
|
||||
struct UnpackedRecord; /* Forward declaration. Definition in vdbeaux.c. */
|
||||
|
||||
int sqlite3BtreeCursor(
|
||||
Btree*, /* BTree containing table to open */
|
||||
int iTable, /* Index of root page */
|
||||
@@ -137,7 +139,14 @@ int sqlite3BtreeCursor(
|
||||
int sqlite3BtreeCursorSize();
|
||||
|
||||
int sqlite3BtreeCloseCursor(BtCursor*);
|
||||
int sqlite3BtreeMoveto(BtCursor*,const void *pKey,i64 nKey,int bias,int *pRes);
|
||||
int sqlite3BtreeMoveto(
|
||||
BtCursor*,
|
||||
const void *pKey,
|
||||
struct UnpackedRecord *pUnKey,
|
||||
i64 nKey,
|
||||
int bias,
|
||||
int *pRes
|
||||
);
|
||||
int sqlite3BtreeDelete(BtCursor*);
|
||||
int sqlite3BtreeInsert(BtCursor*, const void *pKey, i64 nKey,
|
||||
const void *pData, int nData,
|
||||
|
@@ -22,7 +22,7 @@
|
||||
** COMMIT
|
||||
** ROLLBACK
|
||||
**
|
||||
** $Id: build.c,v 1.476 2008/03/25 09:47:35 danielk1977 Exp $
|
||||
** $Id: build.c,v 1.477 2008/03/25 17:23:33 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
@@ -2278,7 +2278,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
|
||||
sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead);
|
||||
addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iTab, 0);
|
||||
regRecord = sqlite3GetTempReg(pParse);
|
||||
regIdxKey = sqlite3GenerateIndexKey(pParse, pIndex, iTab, regRecord);
|
||||
regIdxKey = sqlite3GenerateIndexKey(pParse, pIndex, iTab, regRecord, 1);
|
||||
if( pIndex->onError!=OE_None ){
|
||||
int j1, j2;
|
||||
int regRowid;
|
||||
|
21
src/delete.c
21
src/delete.c
@@ -12,7 +12,7 @@
|
||||
** This file contains C code routines that are called by the parser
|
||||
** in order to generate code for DELETE FROM statements.
|
||||
**
|
||||
** $Id: delete.c,v 1.163 2008/03/25 09:47:35 danielk1977 Exp $
|
||||
** $Id: delete.c,v 1.164 2008/03/25 17:23:33 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@@ -488,18 +488,16 @@ void sqlite3GenerateRowIndexDelete(
|
||||
Index *pIdx;
|
||||
int r1;
|
||||
|
||||
r1 = sqlite3GetTempReg(pParse);
|
||||
for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
|
||||
if( aRegIdx!=0 && aRegIdx[i-1]==0 ) continue;
|
||||
sqlite3GenerateIndexKey(pParse, pIdx, iCur, r1);
|
||||
sqlite3VdbeAddOp2(pParse->pVdbe, OP_IdxDelete, iCur+i, r1);
|
||||
r1 = sqlite3GenerateIndexKey(pParse, pIdx, iCur, r1, 0);
|
||||
sqlite3VdbeAddOp3(pParse->pVdbe, OP_IdxDelete, iCur+i, r1,pIdx->nColumn+1);
|
||||
}
|
||||
sqlite3ReleaseTempReg(pParse, r1);
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate code that will assemble an index key and put it on the top
|
||||
** of the tack. The key with be for index pIdx which is an index on pTab.
|
||||
** Generate code that will assemble an index key and put it in register
|
||||
** regOut. The key with be for index pIdx which is an index on pTab.
|
||||
** iCur is the index of a cursor open on the pTab table and pointing to
|
||||
** the entry that needs indexing.
|
||||
**
|
||||
@@ -512,7 +510,8 @@ int sqlite3GenerateIndexKey(
|
||||
Parse *pParse, /* Parsing context */
|
||||
Index *pIdx, /* The index for which to generate a key */
|
||||
int iCur, /* Cursor number for the pIdx->pTable table */
|
||||
int regOut /* Write the new index key to this register */
|
||||
int regOut, /* Write the new index key to this register */
|
||||
int doMakeRec /* Run the OP_MakeRecord instruction if true */
|
||||
){
|
||||
Vdbe *v = pParse->pVdbe;
|
||||
int j;
|
||||
@@ -532,8 +531,10 @@ int sqlite3GenerateIndexKey(
|
||||
sqlite3ColumnDefault(v, pTab, idx);
|
||||
}
|
||||
}
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol+1, regOut);
|
||||
sqlite3IndexAffinityStr(v, pIdx);
|
||||
if( doMakeRec ){
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol+1, regOut);
|
||||
sqlite3IndexAffinityStr(v, pIdx);
|
||||
}
|
||||
sqlite3ReleaseTempRange(pParse, regBase, nCol+1);
|
||||
return regBase;
|
||||
}
|
||||
|
@@ -11,7 +11,7 @@
|
||||
*************************************************************************
|
||||
** This file contains code used to implement the PRAGMA command.
|
||||
**
|
||||
** $Id: pragma.c,v 1.172 2008/03/20 11:04:21 danielk1977 Exp $
|
||||
** $Id: pragma.c,v 1.173 2008/03/25 17:23:33 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
@@ -941,7 +941,7 @@ void sqlite3Pragma(
|
||||
{ OP_IfPos, 1, 0, 0}, /* 9 */
|
||||
{ OP_Halt, 0, 0, 0},
|
||||
};
|
||||
sqlite3GenerateIndexKey(pParse, pIdx, 1, 3);
|
||||
sqlite3GenerateIndexKey(pParse, pIdx, 1, 3, 1);
|
||||
jmp2 = sqlite3VdbeAddOp3(v, OP_Found, j+2, 0, 3);
|
||||
addr = sqlite3VdbeAddOpList(v, ArraySize(idxErr), idxErr);
|
||||
sqlite3VdbeChangeP4(v, addr+1, "rowid ", P4_STATIC);
|
||||
|
@@ -12,7 +12,7 @@
|
||||
** This file contains C code routines that are called by the parser
|
||||
** to handle SELECT statements in SQLite.
|
||||
**
|
||||
** $Id: select.c,v 1.418 2008/03/25 09:47:35 danielk1977 Exp $
|
||||
** $Id: select.c,v 1.419 2008/03/25 17:23:33 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@@ -598,12 +598,7 @@ static void selectInnerLoop(
|
||||
** the temporary table iParm.
|
||||
*/
|
||||
case SRT_Except: {
|
||||
int r1;
|
||||
r1 = sqlite3GetTempReg(pParse);
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nColumn, r1);
|
||||
sqlite3VdbeChangeP4(v, -1, aff, P4_STATIC);
|
||||
sqlite3VdbeAddOp2(v, OP_IdxDelete, iParm, r1);
|
||||
sqlite3ReleaseTempReg(pParse, r1);
|
||||
sqlite3VdbeAddOp3(v, OP_IdxDelete, iParm, regResult, nColumn);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
@@ -11,7 +11,7 @@
|
||||
*************************************************************************
|
||||
** Internal interface definitions for SQLite.
|
||||
**
|
||||
** @(#) $Id: sqliteInt.h,v 1.679 2008/03/21 16:45:47 drh Exp $
|
||||
** @(#) $Id: sqliteInt.h,v 1.680 2008/03/25 17:23:33 drh Exp $
|
||||
*/
|
||||
#ifndef _SQLITEINT_H_
|
||||
#define _SQLITEINT_H_
|
||||
@@ -1863,7 +1863,7 @@ int sqlite3ExprIsInteger(Expr*, int*);
|
||||
int sqlite3IsRowid(const char*);
|
||||
void sqlite3GenerateRowDelete(Parse*, Table*, int, int, int);
|
||||
void sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int*);
|
||||
int sqlite3GenerateIndexKey(Parse*, Index*, int, int);
|
||||
int sqlite3GenerateIndexKey(Parse*, Index*, int, int, int);
|
||||
void sqlite3GenerateConstraintChecks(Parse*,Table*,int,int,
|
||||
int*,int,int,int,int);
|
||||
void sqlite3CompleteInsertion(Parse*, Table*, int, int, int*,int,int,int,int);
|
||||
|
@@ -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.93 2008/03/25 09:47:35 danielk1977 Exp $
|
||||
** $Id: test3.c,v 1.94 2008/03/25 17:23:33 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "btreeInt.h"
|
||||
@@ -788,9 +788,9 @@ static int btree_move_to(
|
||||
sqlite3BtreeLeave(pCur->pBtree);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
rc = sqlite3BtreeMoveto(pCur, 0, iKey, 0, &res);
|
||||
rc = sqlite3BtreeMoveto(pCur, 0, 0, iKey, 0, &res);
|
||||
}else{
|
||||
rc = sqlite3BtreeMoveto(pCur, argv[2], strlen(argv[2]), 0, &res);
|
||||
rc = sqlite3BtreeMoveto(pCur, argv[2], 0, strlen(argv[2]), 0, &res);
|
||||
}
|
||||
sqlite3BtreeLeave(pCur->pBtree);
|
||||
if( rc ){
|
||||
|
33
src/vdbe.c
33
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.717 2008/03/25 09:47:35 danielk1977 Exp $
|
||||
** $Id: vdbe.c,v 1.718 2008/03/25 17:23:33 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
@@ -2794,7 +2794,7 @@ case OP_MoveGt: { /* jump, in3 */
|
||||
pC->deferredMoveto = 1;
|
||||
break;
|
||||
}
|
||||
rc = sqlite3BtreeMoveto(pC->pCursor, 0, (u64)iKey, 0, &res);
|
||||
rc = sqlite3BtreeMoveto(pC->pCursor, 0, 0, (u64)iKey, 0, &res);
|
||||
if( rc!=SQLITE_OK ){
|
||||
goto abort_due_to_error;
|
||||
}
|
||||
@@ -2803,7 +2803,7 @@ case OP_MoveGt: { /* jump, in3 */
|
||||
}else{
|
||||
assert( pIn3->flags & MEM_Blob );
|
||||
ExpandBlob(pIn3);
|
||||
rc = sqlite3BtreeMoveto(pC->pCursor, pIn3->z, pIn3->n, 0, &res);
|
||||
rc = sqlite3BtreeMoveto(pC->pCursor, pIn3->z, 0, pIn3->n, 0, &res);
|
||||
if( rc!=SQLITE_OK ){
|
||||
goto abort_due_to_error;
|
||||
}
|
||||
@@ -2888,7 +2888,7 @@ case OP_Found: { /* jump, in3 */
|
||||
if( pOp->opcode==OP_Found ){
|
||||
pC->pKeyInfo->prefixIsEqual = 1;
|
||||
}
|
||||
rc = sqlite3BtreeMoveto(pC->pCursor, pIn3->z, pIn3->n, 0, &res);
|
||||
rc = sqlite3BtreeMoveto(pC->pCursor, pIn3->z, 0, pIn3->n, 0, &res);
|
||||
pC->pKeyInfo->prefixIsEqual = 0;
|
||||
if( rc!=SQLITE_OK ){
|
||||
break;
|
||||
@@ -2965,7 +2965,7 @@ case OP_IsUnique: { /* jump, in3 */
|
||||
*/
|
||||
assert( pCx->deferredMoveto==0 );
|
||||
pCx->cacheStatus = CACHE_STALE;
|
||||
rc = sqlite3BtreeMoveto(pCrsr, zKey, len, 0, &res);
|
||||
rc = sqlite3BtreeMoveto(pCrsr, zKey, 0, len, 0, &res);
|
||||
if( rc!=SQLITE_OK ){
|
||||
goto abort_due_to_error;
|
||||
}
|
||||
@@ -3033,7 +3033,7 @@ case OP_NotExists: { /* jump, in3 */
|
||||
assert( pIn3->flags & MEM_Int );
|
||||
assert( p->apCsr[i]->isTable );
|
||||
iKey = intToKey(pIn3->u.i);
|
||||
rc = sqlite3BtreeMoveto(pCrsr, 0, iKey, 0,&res);
|
||||
rc = sqlite3BtreeMoveto(pCrsr, 0, 0, iKey, 0,&res);
|
||||
pC->lastRowid = pIn3->u.i;
|
||||
pC->rowidIsValid = res==0;
|
||||
pC->nullRow = 0;
|
||||
@@ -3203,7 +3203,7 @@ case OP_NewRowid: { /* out2-prerelease */
|
||||
}
|
||||
if( v==0 ) continue;
|
||||
x = intToKey(v);
|
||||
rx = sqlite3BtreeMoveto(pC->pCursor, 0, (u64)x, 0, &res);
|
||||
rx = sqlite3BtreeMoveto(pC->pCursor, 0, 0, (u64)x, 0, &res);
|
||||
cnt++;
|
||||
}while( cnt<100 && rx==SQLITE_OK && res==0 );
|
||||
db->priorNewRowid = v;
|
||||
@@ -3676,22 +3676,29 @@ case OP_IdxInsert: { /* in2 */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: IdxDelete P1 P2 * * *
|
||||
/* Opcode: IdxDeleteM P1 P2 P3 * *
|
||||
**
|
||||
** The content of register P2 is an index key built using the
|
||||
** MakeIdxRec opcode. This opcode removes that entry from the
|
||||
** The content of P3 registers starting at register P2 form
|
||||
** an unpacked index key. This opcode removes that entry from the
|
||||
** index opened by cursor P1.
|
||||
*/
|
||||
case OP_IdxDelete: { /* in2 */
|
||||
case OP_IdxDelete: {
|
||||
int i = pOp->p1;
|
||||
Cursor *pC;
|
||||
BtCursor *pCrsr;
|
||||
assert( pIn2->flags & MEM_Blob );
|
||||
assert( pOp->p3>0 );
|
||||
assert( pOp->p2>0 && pOp->p2+pOp->p3<=p->nMem );
|
||||
assert( i>=0 && i<p->nCursor );
|
||||
assert( p->apCsr[i]!=0 );
|
||||
if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){
|
||||
int res;
|
||||
rc = sqlite3BtreeMoveto(pCrsr, pIn2->z, pIn2->n, 0, &res);
|
||||
UnpackedRecord r;
|
||||
r.pKeyInfo = pC->pKeyInfo;
|
||||
r.nField = pOp->p3;
|
||||
r.needFree = 0;
|
||||
r.needDestroy = 0;
|
||||
r.aMem = &p->aMem[pOp->p2];
|
||||
rc = sqlite3BtreeMoveto(pCrsr, 0, &r, 0, 0, &res);
|
||||
if( rc==SQLITE_OK && res==0 ){
|
||||
rc = sqlite3BtreeDelete(pCrsr);
|
||||
}
|
||||
|
10
src/vdbe.h
10
src/vdbe.h
@@ -15,7 +15,7 @@
|
||||
** or VDBE. The VDBE implements an abstract machine that runs a
|
||||
** simple program to access and modify the underlying database.
|
||||
**
|
||||
** $Id: vdbe.h,v 1.127 2008/03/25 00:22:21 drh Exp $
|
||||
** $Id: vdbe.h,v 1.128 2008/03/25 17:23:34 drh Exp $
|
||||
*/
|
||||
#ifndef _SQLITE_VDBE_H_
|
||||
#define _SQLITE_VDBE_H_
|
||||
@@ -34,7 +34,7 @@ typedef struct Vdbe Vdbe;
|
||||
*/
|
||||
typedef struct VdbeFunc VdbeFunc;
|
||||
typedef struct Mem Mem;
|
||||
typedef struct VdbeParsedRecord VdbeParsedRecord;
|
||||
typedef struct UnpackedRecord UnpackedRecord;
|
||||
|
||||
/*
|
||||
** A single instruction of the virtual machine has an opcode
|
||||
@@ -182,9 +182,9 @@ sqlite3 *sqlite3VdbeDb(Vdbe*);
|
||||
void sqlite3VdbeSetSql(Vdbe*, const char *z, int n);
|
||||
void sqlite3VdbeSwap(Vdbe*,Vdbe*);
|
||||
|
||||
VdbeParsedRecord *sqlite3VdbeRecordParse(KeyInfo*,int,const void*,void*,int);
|
||||
void sqlite3VdbeRecordUnparse(VdbeParsedRecord*);
|
||||
int sqlite3VdbeRecordCompareParsed(int,const void*,VdbeParsedRecord*);
|
||||
UnpackedRecord *sqlite3VdbeRecordUnpack(KeyInfo*,int,const void*,void*,int);
|
||||
void sqlite3VdbeDeleteUnpackedRecord(UnpackedRecord*);
|
||||
int sqlite3VdbeRecordCompare(int,const void*,UnpackedRecord*);
|
||||
|
||||
|
||||
#ifndef NDEBUG
|
||||
|
@@ -335,6 +335,28 @@ struct Vdbe {
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
** An instance of the following structure holds information about a
|
||||
** single index record that has already been parsed out into individual
|
||||
** values.
|
||||
**
|
||||
** A record is an object that contains one or more fields of data.
|
||||
** Records are used to store the content of a table row and to store
|
||||
** the key of an index. A blob encoding of a record is created by
|
||||
** the OP_MakeRecord opcode of the VDBE and is disassemblied by the
|
||||
** OP_Column opcode.
|
||||
**
|
||||
** This structure holds a record that has already been disassembled
|
||||
** into its constitutent fields.
|
||||
*/
|
||||
struct UnpackedRecord {
|
||||
KeyInfo *pKeyInfo; /* Collation and sort-order information */
|
||||
u16 nField; /* Number of entries in apMem[] */
|
||||
u8 needFree; /* True if memory obtained from sqlite3_malloc() */
|
||||
u8 needDestroy; /* True if apMem[]s should be destroyed on close */
|
||||
Mem *aMem; /* Values */
|
||||
};
|
||||
|
||||
/*
|
||||
** The following are allowed values for Vdbe.magic
|
||||
*/
|
||||
|
154
src/vdbeaux.c
154
src/vdbeaux.c
@@ -1803,7 +1803,7 @@ int sqlite3VdbeCursorMoveto(Cursor *p){
|
||||
extern int sqlite3_search_count;
|
||||
#endif
|
||||
assert( p->isTable );
|
||||
rc = sqlite3BtreeMoveto(p->pCursor, 0, p->movetoTarget, 0, &res);
|
||||
rc = sqlite3BtreeMoveto(p->pCursor, 0, 0, p->movetoTarget, 0, &res);
|
||||
if( rc ) return rc;
|
||||
*p->pIncrKey = 0;
|
||||
p->lastRowid = keyToInt(p->movetoTarget);
|
||||
@@ -2143,120 +2143,9 @@ int sqlite3VdbeSerialGet(
|
||||
*/
|
||||
#define GetVarint(A,B) ((B = *(A))<=0x7f ? 1 : sqlite3GetVarint32(A, &B))
|
||||
|
||||
#if 0
|
||||
/*
|
||||
** This function compares the two table rows or index records specified by
|
||||
** {nKey1, pKey1} and {nKey2, pKey2}, returning a negative, zero
|
||||
** or positive integer if {nKey1, pKey1} is less than, equal to or
|
||||
** greater than {nKey2, pKey2}. Both Key1 and Key2 must be byte strings
|
||||
** composed by the OP_MakeRecord opcode of the VDBE.
|
||||
**
|
||||
** Key1 and Key2 do not have to contain the same number of fields.
|
||||
** But if the lengths differ, Key2 must be the shorter of the two.
|
||||
*/
|
||||
int sqlite3VdbeRecordCompare(
|
||||
void *userData,
|
||||
int nKey1, const void *pKey1,
|
||||
int nKey2, const void *pKey2
|
||||
){
|
||||
KeyInfo *pKeyInfo = (KeyInfo*)userData;
|
||||
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;
|
||||
|
||||
Mem mem1;
|
||||
Mem mem2;
|
||||
mem1.enc = pKeyInfo->enc;
|
||||
mem1.db = pKeyInfo->db;
|
||||
mem1.flags = 0;
|
||||
mem2.enc = pKeyInfo->enc;
|
||||
mem2.db = pKeyInfo->db;
|
||||
mem2.flags = 0;
|
||||
|
||||
idx1 = GetVarint(aKey1, szHdr1);
|
||||
d1 = szHdr1;
|
||||
idx2 = GetVarint(aKey2, szHdr2);
|
||||
d2 = szHdr2;
|
||||
nField = pKeyInfo->nField;
|
||||
while( idx1<szHdr1 && idx2<szHdr2 ){
|
||||
u32 serial_type1;
|
||||
u32 serial_type2;
|
||||
|
||||
/* Read the serial types for the next element in each key. */
|
||||
idx1 += GetVarint( aKey1+idx1, serial_type1 );
|
||||
if( d1>=nKey1 && sqlite3VdbeSerialTypeLen(serial_type1)>0 ) break;
|
||||
idx2 += GetVarint( aKey2+idx2, serial_type2 );
|
||||
if( d2>=nKey2 && sqlite3VdbeSerialTypeLen(serial_type2)>0 ) break;
|
||||
|
||||
/* Extract the values to be compared.
|
||||
*/
|
||||
d1 += sqlite3VdbeSerialGet(&aKey1[d1], serial_type1, &mem1);
|
||||
d2 += sqlite3VdbeSerialGet(&aKey2[d2], serial_type2, &mem2);
|
||||
|
||||
/* Do the comparison
|
||||
*/
|
||||
rc = sqlite3MemCompare(&mem1, &mem2, i<nField ? pKeyInfo->aColl[i] : 0);
|
||||
if( mem1.flags&MEM_Dyn ) sqlite3VdbeMemRelease(&mem1);
|
||||
if( mem2.flags&MEM_Dyn ) sqlite3VdbeMemRelease(&mem2);
|
||||
if( rc!=0 ){
|
||||
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 ){
|
||||
rc = -1;
|
||||
}else if( !pKeyInfo->prefixIsEqual ){
|
||||
if( d1<nKey1 ){
|
||||
rc = 1;
|
||||
}else if( d2<nKey2 ){
|
||||
rc = -1; /* Only occurs on a corrupt database file */
|
||||
}
|
||||
}
|
||||
}else if( pKeyInfo->aSortOrder && i<pKeyInfo->nField
|
||||
&& pKeyInfo->aSortOrder[i] ){
|
||||
rc = -rc;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** An instance of the following structure holds information about a
|
||||
** single index record that has already been parsed out into individual
|
||||
** values.
|
||||
**
|
||||
** A record is an object that contains one or more fields of data.
|
||||
** Records are used to store the content of a table row and to store
|
||||
** the key of an index. A blob encoding of a record is created by
|
||||
** the OP_MakeRecord opcode of the VDBE and is disassemblied by the
|
||||
** OP_Column opcode.
|
||||
**
|
||||
** This structure holds a record that has already been disassembled
|
||||
** into its constitutent fields.
|
||||
*/
|
||||
struct VdbeParsedRecord {
|
||||
KeyInfo *pKeyInfo; /* Collation and sort-order information */
|
||||
u16 nField; /* Number of entries in apMem[] */
|
||||
u8 needFree; /* True if memory obtained from sqlite3_malloc() */
|
||||
u8 needDestroy; /* True if apMem[]s should be destroyed on close */
|
||||
Mem *apMem[1]; /* Values */
|
||||
};
|
||||
|
||||
/*
|
||||
** Given the nKey-byte encoding of a record in pKey[], parse the
|
||||
** record into a VdbeParsedRecord structure. Return a pointer to
|
||||
** record into a UnpackedRecord structure. Return a pointer to
|
||||
** that structure.
|
||||
**
|
||||
** The calling function might provide szSpace bytes of memory
|
||||
@@ -2265,9 +2154,9 @@ struct VdbeParsedRecord {
|
||||
** not big enough, space is obtained from sqlite3_malloc().
|
||||
**
|
||||
** The returned structure should be closed by a call to
|
||||
** sqlite3VdbeRecordUnparse().
|
||||
** sqlite3VdbeDeleteUnpackedRecord().
|
||||
*/
|
||||
VdbeParsedRecord *sqlite3VdbeRecordParse(
|
||||
UnpackedRecord *sqlite3VdbeRecordUnpack(
|
||||
KeyInfo *pKeyInfo, /* Information about the record format */
|
||||
int nKey, /* Size of the binary record */
|
||||
const void *pKey, /* The binary record */
|
||||
@@ -2275,14 +2164,13 @@ VdbeParsedRecord *sqlite3VdbeRecordParse(
|
||||
int szSpace /* Size of pSpace[] in bytes */
|
||||
){
|
||||
const unsigned char *aKey = (const unsigned char *)pKey;
|
||||
VdbeParsedRecord *p;
|
||||
UnpackedRecord *p;
|
||||
int nByte;
|
||||
int i, idx, d;
|
||||
u32 szHdr;
|
||||
Mem *pMem;
|
||||
|
||||
nByte = sizeof(*p) + sizeof(Mem*)*pKeyInfo->nField
|
||||
+ sizeof(Mem)*(pKeyInfo->nField+1);
|
||||
nByte = sizeof(*p) + sizeof(Mem)*(pKeyInfo->nField+1);
|
||||
if( nByte>szSpace ){
|
||||
p = sqlite3DbMallocRaw(pKeyInfo->db, nByte);
|
||||
if( p==0 ) return 0;
|
||||
@@ -2294,7 +2182,7 @@ VdbeParsedRecord *sqlite3VdbeRecordParse(
|
||||
p->pKeyInfo = pKeyInfo;
|
||||
p->nField = pKeyInfo->nField + 1;
|
||||
p->needDestroy = 1;
|
||||
pMem = (Mem*)&p->apMem[pKeyInfo->nField+1];
|
||||
p->aMem = pMem = (Mem*)&p[1];
|
||||
idx = GetVarint(aKey, szHdr);
|
||||
d = szHdr;
|
||||
i = 0;
|
||||
@@ -2307,22 +2195,24 @@ VdbeParsedRecord *sqlite3VdbeRecordParse(
|
||||
pMem->db = pKeyInfo->db;
|
||||
pMem->flags = 0;
|
||||
d += sqlite3VdbeSerialGet(&aKey[d], serial_type, pMem);
|
||||
p->apMem[i++] = pMem++;
|
||||
pMem++;
|
||||
i++;
|
||||
}
|
||||
p->nField = i;
|
||||
return (void*)p;
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine destroys a VdbeParsedRecord object
|
||||
** This routine destroys a UnpackedRecord object
|
||||
*/
|
||||
void sqlite3VdbeRecordUnparse(VdbeParsedRecord *p){
|
||||
void sqlite3VdbeDeleteUnpackedRecord(UnpackedRecord *p){
|
||||
if( p ){
|
||||
if( p->needDestroy ){
|
||||
int i;
|
||||
for(i=0; i<p->nField; i++){
|
||||
if( p->apMem[i]->flags & MEM_Dyn ){
|
||||
sqlite3VdbeMemRelease(p->apMem[i]);
|
||||
Mem *pMem;
|
||||
for(i=0, pMem=p->aMem; i<p->nField; i++, pMem++){
|
||||
if( pMem->flags & MEM_Dyn ){
|
||||
sqlite3VdbeMemRelease(pMem);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2351,9 +2241,9 @@ void sqlite3VdbeRecordUnparse(VdbeParsedRecord *p){
|
||||
** separately and submit the parsed version. In this way, we avoid
|
||||
** parsing the same Key2 multiple times in a row.
|
||||
*/
|
||||
int sqlite3VdbeRecordCompareParsed(
|
||||
int sqlite3VdbeRecordCompare(
|
||||
int nKey1, const void *pKey1,
|
||||
VdbeParsedRecord *pPKey2
|
||||
UnpackedRecord *pPKey2
|
||||
){
|
||||
u32 d1; /* Offset into aKey[] of next data element */
|
||||
u32 idx1; /* Offset into aKey[] of next header element */
|
||||
@@ -2386,7 +2276,7 @@ int sqlite3VdbeRecordCompareParsed(
|
||||
|
||||
/* Do the comparison
|
||||
*/
|
||||
rc = sqlite3MemCompare(&mem1, pPKey2->apMem[i],
|
||||
rc = sqlite3MemCompare(&mem1, &pPKey2->aMem[i],
|
||||
i<nField ? pKeyInfo->aColl[i] : 0);
|
||||
if( mem1.flags&MEM_Dyn ) sqlite3VdbeMemRelease(&mem1);
|
||||
if( rc!=0 ){
|
||||
@@ -2483,7 +2373,7 @@ int sqlite3VdbeIdxKeyCompare(
|
||||
BtCursor *pCur = pC->pCursor;
|
||||
int lenRowid;
|
||||
Mem m;
|
||||
VdbeParsedRecord *pRec;
|
||||
UnpackedRecord *pRec;
|
||||
char zSpace[200];
|
||||
|
||||
sqlite3BtreeKeySize(pCur, &nCellKey);
|
||||
@@ -2498,13 +2388,13 @@ int sqlite3VdbeIdxKeyCompare(
|
||||
return rc;
|
||||
}
|
||||
lenRowid = sqlite3VdbeIdxRowidLen((u8*)m.z);
|
||||
pRec = sqlite3VdbeRecordParse(pC->pKeyInfo, nKey, pKey,
|
||||
pRec = sqlite3VdbeRecordUnpack(pC->pKeyInfo, nKey, pKey,
|
||||
zSpace, sizeof(zSpace));
|
||||
if( pRec==0 ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
*res = sqlite3VdbeRecordCompareParsed(m.n-lenRowid, m.z, pRec);
|
||||
sqlite3VdbeRecordUnparse(pRec);
|
||||
*res = sqlite3VdbeRecordCompare(m.n-lenRowid, m.z, pRec);
|
||||
sqlite3VdbeDeleteUnpackedRecord(pRec);
|
||||
sqlite3VdbeMemRelease(&m);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
Reference in New Issue
Block a user