Enhance the OP_IdxInsert opcode so that it can used unpacked key values if
they are available. Update the code generator to take advantage of this new capability. The speedtest1.c test is about 2.6% faster as a result. FossilOrigin-Name: 925840cfdb969a76640a1247cc4a7b2c0de5cb74
This commit is contained in:
commit
4b727f17d6
35
manifest
35
manifest
@ -1,5 +1,5 @@
|
||||
C Fix\sa\sproblem\swith\sswitching\sfrom\swal\sto\srollback\smode\swhen\nSQLITE_DBCONFIG_NO_CKPT_ON_CLOSE\sis\sconfigured.
|
||||
D 2016-11-11T17:08:51.459
|
||||
C Enhance\sthe\sOP_IdxInsert\sopcode\sso\sthat\sit\scan\sused\sunpacked\skey\svalues\sif\nthey\sare\savailable.\s\sUpdate\sthe\scode\sgenerator\sto\stake\sadvantage\sof\sthis\nnew\scapability.\s\sThe\sspeedtest1.c\stest\sis\sabout\s2.6%\sfaster\sas\sa\sresult.
|
||||
D 2016-11-11T19:01:11.983
|
||||
F Makefile.in 6fd48ffcf7c2deea7499062d1f3747f986c19678
|
||||
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
|
||||
F Makefile.msc e0217f2d35a0448abbe4b066132ae20136e8b408
|
||||
@ -330,17 +330,17 @@ F src/auth.c 930b376a9c56998557367e6f7f8aaeac82a2a792
|
||||
F src/backup.c faf17e60b43233c214aae6a8179d24503a61e83b
|
||||
F src/bitvec.c 3ee4c8b2c94ed3a7377256e18199e6ff5cf33f63
|
||||
F src/btmutex.c bc87dd3b062cc26edfe79918de2200ccb8d41e73
|
||||
F src/btree.c 6ae1c17347fb2888b2b28a260b947b7717a9fca9
|
||||
F src/btree.h d05b2fcc290991a8a3d9ea1816ddd55a4359dcde
|
||||
F src/btree.c cfe038d1844420caddfa0238d52b7b2102dda98b
|
||||
F src/btree.h 630303068c82a359f6ddf202b205ae927721b090
|
||||
F src/btreeInt.h c18b7d2a3494695133e4e60ee36061d37f45d9a5
|
||||
F src/build.c fcd220ccf7cae1b50b700b37eca950cd72c64ff0
|
||||
F src/build.c 178f16698cbcb43402c343a9413fe22c99ffee21
|
||||
F src/callback.c 2e76147783386374bf01b227f752c81ec872d730
|
||||
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
|
||||
F src/ctime.c a2a52d6e353f459d8ab0f07321f60fafa47d5421
|
||||
F src/date.c 95c9a8d00767e7221a8e9a31f4e913fc8029bf6b
|
||||
F src/dbstat.c 19ee7a4e89979d4df8e44cfac7a8f905ec89b77d
|
||||
F src/delete.c cb3f6300df24c26c609778b2731f82644b5532ec
|
||||
F src/expr.c ce7110980fac6dfdfbe1e393443bdb79bad29339
|
||||
F src/delete.c 6cac3a6c3f3c5ad4cacc402aee1610fc94ebc3dc
|
||||
F src/expr.c ddd46bafbbd77b83c8daa733ebbe906093b558dc
|
||||
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
|
||||
F src/fkey.c b9ca262f6ad4d030a3cab737ebf9b0b3c8b4ac80
|
||||
F src/func.c 7057bc2c105b82faa668d8e2ec85fad4540e5c51
|
||||
@ -349,7 +349,7 @@ F src/hash.c 63d0ee752a3b92d4695b2b1f5259c4621b2cfebd
|
||||
F src/hash.h ab34c5c54a9e9de2e790b24349ba5aab3dbb4fd4
|
||||
F src/hwtime.h 747c1bbe9df21a92e9c50f3bbec1de841dc5e5da
|
||||
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
|
||||
F src/insert.c 8c1346304a9a386b036652475296103bae27e0a1
|
||||
F src/insert.c 0db6364a6a64e521281d6f443b1669a5a16bdbd6
|
||||
F src/legacy.c 75d3023be8f0d2b99d60f905090341a03358c58e
|
||||
F src/loadext.c 5d6642d141c07d366e43d359e94ec9de47add41d
|
||||
F src/main.c 694ac90557abdaa62151a6090670e107b0f2c2ab
|
||||
@ -387,7 +387,7 @@ F src/printf.c a5f0ca08ddede803c241266abb46356ec748ded1
|
||||
F src/random.c ba2679f80ec82c4190062d756f22d0c358180696
|
||||
F src/resolve.c bb070cf5f23611c44ab7e4788803684e385fc3fb
|
||||
F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
|
||||
F src/select.c ea3af83e2d0f245fef81ea4cf04cb730ce67f722
|
||||
F src/select.c 0a7c523d755bcd39ae54f6a44bb66a7f0e1d89b3
|
||||
F src/shell.c f04e4af75c5517735397d060ed0b4a874104bb41
|
||||
F src/sqlite.h.in 803f7050f69b2eea573fac219f3c92582c096027
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
@ -450,13 +450,13 @@ F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
|
||||
F src/tokenize.c 78c8085bc7af1922aa687f0f4bbd716821330de5
|
||||
F src/treeview.c 4e44ade3bfe59d82005039f72e09333ce2b4162c
|
||||
F src/trigger.c 3419bb9862983d84d70735fb4c94b21b934cd0c5
|
||||
F src/update.c 8179e699dbd45b92934fd02d3d8e3732e8da8802
|
||||
F src/update.c bb9854778bdbbbca55d7533e55058733bd3fefe3
|
||||
F src/utf.c 699001c79f28e48e9bcdf8a463da029ea660540c
|
||||
F src/util.c 3e2da6101888d073e79ecc6af5e0a2f70fa1e498
|
||||
F src/vacuum.c 33c174b28886b2faf26e503b5a49a1c01a9b1c16
|
||||
F src/vdbe.c 20307c93ad55af6ab8f50b17147a4704d4f17dab
|
||||
F src/vdbe.c f1a8e5bf7747f2e731812804cb65d4d07d86862e
|
||||
F src/vdbe.h c044be7050ac6bf596eecc6ab159f5dbc020a3b7
|
||||
F src/vdbeInt.h d8a56a491b752dbb5f671963b8c861ec72ea875e
|
||||
F src/vdbeInt.h 29b25318a0286c4b2599c0fbef6acf524398489a
|
||||
F src/vdbeapi.c 97129bec6b1553da50d8e73f523c278bda66d9f6
|
||||
F src/vdbeaux.c 52d9b840859f260ce8418be9333dd77c902e1c74
|
||||
F src/vdbeblob.c 3e82a797b60c3b9fed7b8de8c539ca7607874937
|
||||
@ -470,7 +470,7 @@ F src/wal.h bf03a23da3100ab25e5c0363450233cfee09cfc2
|
||||
F src/walker.c 91a6df7435827e41cff6bb7df50ea00934ee78b0
|
||||
F src/where.c 952f76e7a03727480b274b66ca6641b1657cd591
|
||||
F src/whereInt.h 2bcc3d176e6091cb8f50a30b65c006e88a73614d
|
||||
F src/wherecode.c 717a65294df46f30e9b9933d2a63a4bcbca5a9a8
|
||||
F src/wherecode.c 507738d957dcc3cfa93020bcc1e4b02d11ecab9e
|
||||
F src/whereexpr.c a83d70154f3bbce5051a7e9710021f647c0fe4f2
|
||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||
F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd
|
||||
@ -1532,7 +1532,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P 119d6ef8478ea6ab07dfd0e974d2f5a8dcfce87e
|
||||
R 713cac12bbad56d229ae83741d89e9ae
|
||||
U dan
|
||||
Z eb4e3f5ce4749269e2c70de28f3602c7
|
||||
P 46e0016207b8e7df2ae6c7491fd0f3c2926eed21 1a587d72f981cb7064cfd8916a52a83ad9ba6074
|
||||
R d4149095f37aacb5dfcbf6f677226eee
|
||||
T +closed 1a587d72f981cb7064cfd8916a52a83ad9ba6074
|
||||
U drh
|
||||
Z 89ee46a4d9ea247735e0710261d136a5
|
||||
|
@ -1 +1 @@
|
||||
46e0016207b8e7df2ae6c7491fd0f3c2926eed21
|
||||
925840cfdb969a76640a1247cc4a7b2c0de5cb74
|
53
src/btree.c
53
src/btree.c
@ -5165,16 +5165,16 @@ int sqlite3BtreeMovetoUnpacked(
|
||||
if( lwr>upr ){ c = +1; break; }
|
||||
}else{
|
||||
assert( nCellKey==intKey );
|
||||
pCur->curFlags |= BTCF_ValidNKey;
|
||||
pCur->info.nKey = nCellKey;
|
||||
pCur->aiIdx[pCur->iPage] = (u16)idx;
|
||||
if( !pPage->leaf ){
|
||||
lwr = idx;
|
||||
goto moveto_next_layer;
|
||||
}else{
|
||||
pCur->curFlags |= BTCF_ValidNKey;
|
||||
pCur->info.nKey = nCellKey;
|
||||
pCur->info.nSize = 0;
|
||||
*pRes = 0;
|
||||
rc = SQLITE_OK;
|
||||
goto moveto_finish;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
}
|
||||
assert( lwr+upr>=0 );
|
||||
@ -5285,7 +5285,7 @@ moveto_next_layer:
|
||||
}
|
||||
moveto_finish:
|
||||
pCur->info.nSize = 0;
|
||||
pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
|
||||
assert( (pCur->curFlags & BTCF_ValidOvfl)==0 );
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -5483,7 +5483,7 @@ static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur, int *pRes){
|
||||
moveToParent(pCur);
|
||||
}
|
||||
assert( pCur->info.nSize==0 );
|
||||
assert( (pCur->curFlags & (BTCF_ValidNKey|BTCF_ValidOvfl))==0 );
|
||||
assert( (pCur->curFlags & (BTCF_ValidOvfl))==0 );
|
||||
|
||||
pCur->aiIdx[pCur->iPage]--;
|
||||
pPage = pCur->apPage[pCur->iPage];
|
||||
@ -7940,17 +7940,19 @@ static int balance(BtCursor *pCur){
|
||||
** pX.pData,nData,nZero fields must be zero.
|
||||
**
|
||||
** If the seekResult parameter is non-zero, then a successful call to
|
||||
** MovetoUnpacked() to seek cursor pCur to (pKey, nKey) has already
|
||||
** been performed. seekResult is the search result returned (a negative
|
||||
** number if pCur points at an entry that is smaller than (pKey, nKey), or
|
||||
** a positive value if pCur points at an entry that is larger than
|
||||
** (pKey, nKey)).
|
||||
** MovetoUnpacked() to seek cursor pCur to (pKey,nKey) has already
|
||||
** been performed. In other words, if seekResult!=0 then the cursor
|
||||
** is currently pointing to a cell that will be adjacent to the cell
|
||||
** to be inserted. If seekResult<0 then pCur points to a cell that is
|
||||
** smaller then (pKey,nKey). If seekResult>0 then pCur points to a cell
|
||||
** that is larger than (pKey,nKey).
|
||||
**
|
||||
** If the seekResult parameter is non-zero, then the caller guarantees that
|
||||
** cursor pCur is pointing at the existing copy of a row that is to be
|
||||
** overwritten. If the seekResult parameter is 0, then cursor pCur may
|
||||
** point to any entry or to no entry at all and so this function has to seek
|
||||
** the cursor before the new key can be inserted.
|
||||
** If seekResult==0, that means pCur is pointing at some unknown location.
|
||||
** In that case, this routine must seek the cursor to the correct insertion
|
||||
** point for (pKey,nKey) before doing the insertion. For index btrees,
|
||||
** if pX->nMem is non-zero, then pX->aMem contains pointers to the unpacked
|
||||
** key values and pX->aMem can be used instead of pX->pKey to avoid having
|
||||
** to decode the key.
|
||||
*/
|
||||
int sqlite3BtreeInsert(
|
||||
BtCursor *pCur, /* Insert data into the table of this cursor */
|
||||
@ -8011,15 +8013,26 @@ int sqlite3BtreeInsert(
|
||||
/* If the cursor is currently on the last row and we are appending a
|
||||
** new row onto the end, set the "loc" to avoid an unnecessary
|
||||
** btreeMoveto() call */
|
||||
if( (pCur->curFlags&BTCF_ValidNKey)!=0 && pX->nKey>0
|
||||
&& pCur->info.nKey==pX->nKey-1 ){
|
||||
loc = -1;
|
||||
if( (pCur->curFlags&BTCF_ValidNKey)!=0 && pX->nKey==pCur->info.nKey ){
|
||||
loc = 0;
|
||||
}else if( (pCur->curFlags&BTCF_ValidNKey)!=0 && pX->nKey>0
|
||||
&& pCur->info.nKey==pX->nKey-1 ){
|
||||
loc = -1;
|
||||
}else if( loc==0 ){
|
||||
rc = sqlite3BtreeMovetoUnpacked(pCur, 0, pX->nKey, appendBias, &loc);
|
||||
if( rc ) return rc;
|
||||
}
|
||||
}else if( loc==0 ){
|
||||
rc = btreeMoveto(pCur, pX->pKey, pX->nKey, appendBias, &loc);
|
||||
if( pX->nMem ){
|
||||
UnpackedRecord r;
|
||||
memset(&r, 0, sizeof(r));
|
||||
r.pKeyInfo = pCur->pKeyInfo;
|
||||
r.aMem = pX->aMem;
|
||||
r.nField = pX->nMem;
|
||||
rc = sqlite3BtreeMovetoUnpacked(pCur, &r, 0, appendBias, &loc);
|
||||
}else{
|
||||
rc = btreeMoveto(pCur, pX->pKey, pX->nKey, appendBias, &loc);
|
||||
}
|
||||
if( rc ) return rc;
|
||||
}
|
||||
assert( pCur->eState==CURSOR_VALID || (pCur->eState==CURSOR_INVALID && loc) );
|
||||
|
@ -275,6 +275,8 @@ struct BtreePayload {
|
||||
const void *pKey; /* Key content for indexes. NULL for tables */
|
||||
sqlite3_int64 nKey; /* Size of pKey for indexes. PRIMARY KEY for tabs */
|
||||
const void *pData; /* Data for tables. NULL for indexes */
|
||||
struct Mem *aMem; /* First of nMem value in the unpacked pKey */
|
||||
u16 nMem; /* Number of aMem[] value. Might be zero */
|
||||
int nData; /* Size of pData. 0 if none. */
|
||||
int nZero; /* Extra zero data appended after pData,nData */
|
||||
};
|
||||
|
@ -2818,7 +2818,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
|
||||
}
|
||||
sqlite3VdbeAddOp3(v, OP_SorterData, iSorter, regRecord, iIdx);
|
||||
sqlite3VdbeAddOp3(v, OP_Last, iIdx, 0, -1);
|
||||
sqlite3VdbeAddOp3(v, OP_IdxInsert, iIdx, regRecord, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_IdxInsert, iIdx, regRecord);
|
||||
sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
|
||||
sqlite3ReleaseTempReg(pParse, regRecord);
|
||||
sqlite3VdbeAddOp2(v, OP_SorterNext, iSorter, addr2); VdbeCoverage(v);
|
||||
|
@ -449,7 +449,7 @@ void sqlite3DeleteFrom(
|
||||
nKey = 0; /* Zero tells OP_Found to use a composite key */
|
||||
sqlite3VdbeAddOp4(v, OP_MakeRecord, iPk, nPk, iKey,
|
||||
sqlite3IndexAffinityStr(pParse->db, pPk), nPk);
|
||||
sqlite3VdbeAddOp2(v, OP_IdxInsert, iEphCur, iKey);
|
||||
sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iEphCur, iKey, iPk, nPk);
|
||||
}else{
|
||||
/* Add the rowid of the row to be deleted to the RowSet */
|
||||
nKey = 1; /* OP_Seek always uses a single rowid */
|
||||
|
@ -2538,7 +2538,7 @@ int sqlite3CodeSubselect(
|
||||
}else{
|
||||
sqlite3VdbeAddOp4(v, OP_MakeRecord, r3, 1, r2, &affinity, 1);
|
||||
sqlite3ExprCacheAffinityChange(pParse, r3, 1);
|
||||
sqlite3VdbeAddOp2(v, OP_IdxInsert, pExpr->iTable, r2);
|
||||
sqlite3VdbeAddOp4Int(v, OP_IdxInsert, pExpr->iTable, r2, r3, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
28
src/insert.c
28
src/insert.c
@ -786,14 +786,17 @@ void sqlite3Insert(
|
||||
/* If this is not a view, open the table and and all indices */
|
||||
if( !isView ){
|
||||
int nIdx;
|
||||
Index *pIdx;
|
||||
nIdx = sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, 0, -1, 0,
|
||||
&iDataCur, &iIdxCur);
|
||||
aRegIdx = sqlite3DbMallocRawNN(db, sizeof(int)*(nIdx+1));
|
||||
if( aRegIdx==0 ){
|
||||
goto insert_cleanup;
|
||||
}
|
||||
for(i=0; i<nIdx; i++){
|
||||
for(i=0, pIdx=pTab->pIndex; i<nIdx; pIdx=pIdx->pNext, i++){
|
||||
assert( pIdx );
|
||||
aRegIdx[i] = ++pParse->nMem;
|
||||
pParse->nMem += pIdx->nColumn;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1257,7 +1260,6 @@ void sqlite3GenerateConstraintChecks(
|
||||
int ipkBottom = 0; /* Bottom of the rowid change constraint check */
|
||||
u8 isUpdate; /* True if this is an UPDATE operation */
|
||||
u8 bAffinityDone = 0; /* True if the OP_Affinity operation has been run */
|
||||
int regRowid = -1; /* Register holding ROWID value */
|
||||
|
||||
isUpdate = regOldData!=0;
|
||||
db = pParse->db;
|
||||
@ -1377,7 +1379,7 @@ void sqlite3GenerateConstraintChecks(
|
||||
}
|
||||
|
||||
if( isUpdate ){
|
||||
/* pkChng!=0 does not mean that the rowid has change, only that
|
||||
/* pkChng!=0 does not mean that the rowid has changed, only that
|
||||
** it might have changed. Skip the conflict logic below if the rowid
|
||||
** is unchanged. */
|
||||
sqlite3VdbeAddOp3(v, OP_Eq, regNewData, addrRowidOk, regOldData);
|
||||
@ -1512,7 +1514,7 @@ void sqlite3GenerateConstraintChecks(
|
||||
/* Create a record for this index entry as it should appear after
|
||||
** the insert or update. Store that record in the aRegIdx[ix] register
|
||||
*/
|
||||
regIdx = sqlite3GetTempRange(pParse, pIdx->nColumn);
|
||||
regIdx = aRegIdx[ix]+1;
|
||||
for(i=0; i<pIdx->nColumn; i++){
|
||||
int iField = pIdx->aiColumn[i];
|
||||
int x;
|
||||
@ -1523,9 +1525,7 @@ void sqlite3GenerateConstraintChecks(
|
||||
VdbeComment((v, "%s column %d", pIdx->zName, i));
|
||||
}else{
|
||||
if( iField==XN_ROWID || iField==pTab->iPKey ){
|
||||
if( regRowid==regIdx+i ) continue; /* ROWID already in regIdx+i */
|
||||
x = regNewData;
|
||||
regRowid = pIdx->pPartIdxWhere ? -1 : regIdx+i;
|
||||
}else{
|
||||
x = iField + regNewData + 1;
|
||||
}
|
||||
@ -1549,7 +1549,6 @@ void sqlite3GenerateConstraintChecks(
|
||||
/* Find out what action to take in case there is a uniqueness conflict */
|
||||
onError = pIdx->onError;
|
||||
if( onError==OE_None ){
|
||||
sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nColumn);
|
||||
sqlite3VdbeResolveLabel(v, addrUniqueOk);
|
||||
continue; /* pIdx is not a UNIQUE index */
|
||||
}
|
||||
@ -1558,6 +1557,12 @@ void sqlite3GenerateConstraintChecks(
|
||||
}else if( onError==OE_Default ){
|
||||
onError = OE_Abort;
|
||||
}
|
||||
|
||||
if( ix==0 && pPk==pIdx && onError==OE_Replace && pPk->pNext==0 ){
|
||||
sqlite3VdbeResolveLabel(v, addrUniqueOk);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
/* Check to see if the new index entry will be unique */
|
||||
sqlite3VdbeAddOp4Int(v, OP_NoConflict, iThisCur, addrUniqueOk,
|
||||
@ -1648,7 +1653,6 @@ void sqlite3GenerateConstraintChecks(
|
||||
}
|
||||
}
|
||||
sqlite3VdbeResolveLabel(v, addrUniqueOk);
|
||||
sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nColumn);
|
||||
if( regR!=regIdx ) sqlite3ReleaseTempRange(pParse, regR, nPkField);
|
||||
}
|
||||
if( ipkTop ){
|
||||
@ -1698,7 +1702,9 @@ void sqlite3CompleteInsertion(
|
||||
sqlite3VdbeAddOp2(v, OP_IsNull, aRegIdx[i], sqlite3VdbeCurrentAddr(v)+2);
|
||||
VdbeCoverage(v);
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_IdxInsert, iIdxCur+i, aRegIdx[i]);
|
||||
sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iIdxCur+i, aRegIdx[i],
|
||||
aRegIdx[i]+1,
|
||||
pIdx->uniqNotNull ? pIdx->nKeyCol: pIdx->nColumn);
|
||||
pik_flags = 0;
|
||||
if( useSeekResult ) pik_flags = OPFLAG_USESEEKRESULT;
|
||||
if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){
|
||||
@ -2180,8 +2186,8 @@ static int xferOptimization(
|
||||
if( !HasRowid(pSrc) && pDestIdx->idxType==2 ){
|
||||
idxInsFlags |= OPFLAG_NCHANGE;
|
||||
}
|
||||
sqlite3VdbeAddOp3(v, OP_IdxInsert, iDest, regData, 1);
|
||||
sqlite3VdbeChangeP5(v, idxInsFlags);
|
||||
sqlite3VdbeAddOp2(v, OP_IdxInsert, iDest, regData);
|
||||
sqlite3VdbeChangeP5(v, idxInsFlags|OPFLAG_APPEND);
|
||||
sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1+1); VdbeCoverage(v);
|
||||
sqlite3VdbeJumpHere(v, addr1);
|
||||
sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0);
|
||||
|
18
src/select.c
18
src/select.c
@ -587,7 +587,8 @@ static void pushOntoSorter(
|
||||
}else{
|
||||
op = OP_IdxInsert;
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, op, pSort->iECursor, regRecord);
|
||||
sqlite3VdbeAddOp4Int(v, op, pSort->iECursor, regRecord,
|
||||
regBase+nOBSat, nBase-nOBSat);
|
||||
if( iLimit ){
|
||||
int addr;
|
||||
int r1 = 0;
|
||||
@ -655,7 +656,7 @@ static void codeDistinct(
|
||||
r1 = sqlite3GetTempReg(pParse);
|
||||
sqlite3VdbeAddOp4Int(v, OP_Found, iTab, addrRepeat, iMem, N); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, iMem, N, r1);
|
||||
sqlite3VdbeAddOp2(v, OP_IdxInsert, iTab, r1);
|
||||
sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iTab, r1, iMem, N);
|
||||
sqlite3ReleaseTempReg(pParse, r1);
|
||||
}
|
||||
|
||||
@ -808,7 +809,7 @@ static void selectInnerLoop(
|
||||
int r1;
|
||||
r1 = sqlite3GetTempReg(pParse);
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r1);
|
||||
sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, r1);
|
||||
sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, regResult, nResultCol);
|
||||
sqlite3ReleaseTempReg(pParse, r1);
|
||||
break;
|
||||
}
|
||||
@ -845,7 +846,7 @@ static void selectInnerLoop(
|
||||
int addr = sqlite3VdbeCurrentAddr(v) + 4;
|
||||
sqlite3VdbeAddOp4Int(v, OP_Found, iParm+1, addr, r1, 0);
|
||||
VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm+1, r1);
|
||||
sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm+1, r1,regResult,nResultCol);
|
||||
assert( pSort==0 );
|
||||
}
|
||||
#endif
|
||||
@ -881,7 +882,7 @@ static void selectInnerLoop(
|
||||
sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult, nResultCol,
|
||||
r1, pDest->zAffSdst, nResultCol);
|
||||
sqlite3ExprCacheAffinityChange(pParse, regResult, nResultCol);
|
||||
sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, r1);
|
||||
sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, regResult, nResultCol);
|
||||
sqlite3ReleaseTempReg(pParse, r1);
|
||||
}
|
||||
break;
|
||||
@ -967,7 +968,7 @@ static void selectInnerLoop(
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_Sequence, iParm, r2+nKey);
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, r2, nKey+2, r1);
|
||||
sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, r1);
|
||||
sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, r2, nKey+2);
|
||||
if( addrTest ) sqlite3VdbeJumpHere(v, addrTest);
|
||||
sqlite3ReleaseTempReg(pParse, r1);
|
||||
sqlite3ReleaseTempRange(pParse, r2, nKey+2);
|
||||
@ -1264,7 +1265,7 @@ static void generateSortTail(
|
||||
sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, nColumn, regRowid,
|
||||
pDest->zAffSdst, nColumn);
|
||||
sqlite3ExprCacheAffinityChange(pParse, regRow, nColumn);
|
||||
sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, regRowid);
|
||||
sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, regRowid, regRow, nColumn);
|
||||
break;
|
||||
}
|
||||
case SRT_Mem: {
|
||||
@ -2640,7 +2641,8 @@ static int generateOutputSubroutine(
|
||||
sqlite3VdbeAddOp4(v, OP_MakeRecord, pIn->iSdst, pIn->nSdst,
|
||||
r1, pDest->zAffSdst, pIn->nSdst);
|
||||
sqlite3ExprCacheAffinityChange(pParse, pIn->iSdst, pIn->nSdst);
|
||||
sqlite3VdbeAddOp2(v, OP_IdxInsert, pDest->iSDParm, r1);
|
||||
sqlite3VdbeAddOp4Int(v, OP_IdxInsert, pDest->iSDParm, r1,
|
||||
pIn->iSdst, pIn->nSdst);
|
||||
sqlite3ReleaseTempReg(pParse, r1);
|
||||
break;
|
||||
}
|
||||
|
@ -282,12 +282,14 @@ void sqlite3Update(
|
||||
int reg;
|
||||
if( chngKey || hasFK || pIdx->pPartIdxWhere || pIdx==pPk ){
|
||||
reg = ++pParse->nMem;
|
||||
pParse->nMem += pIdx->nColumn;
|
||||
}else{
|
||||
reg = 0;
|
||||
for(i=0; i<pIdx->nKeyCol; i++){
|
||||
i16 iIdxCol = pIdx->aiColumn[i];
|
||||
if( iIdxCol<0 || aXRef[iIdxCol]>=0 ){
|
||||
reg = ++pParse->nMem;
|
||||
pParse->nMem += pIdx->nColumn;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -398,7 +400,7 @@ void sqlite3Update(
|
||||
}else{
|
||||
sqlite3VdbeAddOp4(v, OP_MakeRecord, iPk, nPk, regKey,
|
||||
sqlite3IndexAffinityStr(db, pPk), nPk);
|
||||
sqlite3VdbeAddOp2(v, OP_IdxInsert, iEph, regKey);
|
||||
sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iEph, regKey, iPk, nPk);
|
||||
}
|
||||
sqlite3WhereEnd(pWInfo);
|
||||
}
|
||||
|
37
src/vdbe.c
37
src/vdbe.c
@ -4322,15 +4322,10 @@ case OP_NewRowid: { /* out2 */
|
||||
** then rowid is stored for subsequent return by the
|
||||
** sqlite3_last_insert_rowid() function (otherwise it is unmodified).
|
||||
**
|
||||
** If the OPFLAG_USESEEKRESULT flag of P5 is set and if the result of
|
||||
** the last seek operation (OP_NotExists or OP_SeekRowid) was a success,
|
||||
** then this
|
||||
** operation will not attempt to find the appropriate row before doing
|
||||
** the insert but will instead overwrite the row that the cursor is
|
||||
** currently pointing to. Presumably, the prior OP_NotExists or
|
||||
** OP_SeekRowid opcode
|
||||
** has already positioned the cursor correctly. This is an optimization
|
||||
** that boosts performance by avoiding redundant seeks.
|
||||
** If the OPFLAG_USESEEKRESULT flag of P5 is set, the implementation might
|
||||
** run faster by avoiding an unnecessary seek on cursor P1. However,
|
||||
** the OPFLAG_USESEEKRESULT flag must only be set if there have been no prior
|
||||
** seeks on the cursor or if the most recent seek used a key equal to P3.
|
||||
**
|
||||
** If the OPFLAG_ISUPDATE flag is set, then this opcode is part of an
|
||||
** UPDATE operation. Otherwise (if the flag is clear) then this opcode
|
||||
@ -5017,23 +5012,30 @@ next_tail:
|
||||
goto check_for_interrupt;
|
||||
}
|
||||
|
||||
/* Opcode: IdxInsert P1 P2 P3 * P5
|
||||
/* Opcode: IdxInsert P1 P2 P3 P4 P5
|
||||
** Synopsis: key=r[P2]
|
||||
**
|
||||
** Register P2 holds an SQL index key made using the
|
||||
** MakeRecord instructions. This opcode writes that key
|
||||
** into the index P1. Data for the entry is nil.
|
||||
**
|
||||
** P3 is a flag that provides a hint to the b-tree layer that this
|
||||
** insert is likely to be an append.
|
||||
** If P4 is not zero, then it is the number of values in the unpacked
|
||||
** key of reg(P2). In that case, P3 is the index of the first register
|
||||
** for the unpacked key. The availability of the unpacked key can sometimes
|
||||
** be an optimization.
|
||||
**
|
||||
** If P5 has the OPFLAG_APPEND bit set, that is a hint to the b-tree layer
|
||||
** that this insert is likely to be an append.
|
||||
**
|
||||
** If P5 has the OPFLAG_NCHANGE bit set, then the change counter is
|
||||
** incremented by this instruction. If the OPFLAG_NCHANGE bit is clear,
|
||||
** then the change counter is unchanged.
|
||||
**
|
||||
** If P5 has the OPFLAG_USESEEKRESULT bit set, then the cursor must have
|
||||
** just done a seek to the spot where the new entry is to be inserted.
|
||||
** This flag avoids doing an extra seek.
|
||||
** If the OPFLAG_USESEEKRESULT flag of P5 is set, the implementation might
|
||||
** run faster by avoiding an unnecessary seek on cursor P1. However,
|
||||
** the OPFLAG_USESEEKRESULT flag must only be set if there have been no prior
|
||||
** seeks on the cursor or if the most recent seek used a key equivalent
|
||||
** to P2.
|
||||
**
|
||||
** This instruction only works for indices. The equivalent instruction
|
||||
** for tables is OP_Insert.
|
||||
@ -5066,7 +5068,10 @@ case OP_IdxInsert: { /* in2 */
|
||||
}else{
|
||||
x.nKey = pIn2->n;
|
||||
x.pKey = pIn2->z;
|
||||
rc = sqlite3BtreeInsert(pC->uc.pCursor, &x, pOp->p3,
|
||||
x.aMem = aMem + pOp->p3;
|
||||
x.nMem = (u16)pOp->p4.i;
|
||||
rc = sqlite3BtreeInsert(pC->uc.pCursor, &x,
|
||||
(pOp->p5 & OPFLAG_APPEND)!=0,
|
||||
((pOp->p5 & OPFLAG_USESEEKRESULT) ? pC->seekResult : 0)
|
||||
);
|
||||
assert( pC->deferredMoveto==0 );
|
||||
|
@ -96,7 +96,10 @@ struct VdbeCursor {
|
||||
} uc;
|
||||
Btree *pBt; /* Separate file holding temporary table */
|
||||
KeyInfo *pKeyInfo; /* Info about index keys needed by index cursors */
|
||||
int seekResult; /* Result of previous sqlite3BtreeMoveto() */
|
||||
int seekResult; /* Result of previous sqlite3BtreeMoveto() or 0
|
||||
** if there have been no prior seeks on the cursor. */
|
||||
/* NB: seekResult does not distinguish between "no seeks have ever occurred
|
||||
** on this cursor" and "the most recent seek was an exact match". */
|
||||
i64 seqCount; /* Sequence counter */
|
||||
i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */
|
||||
VdbeCursor *pAltCursor; /* Associated index cursor from which to read */
|
||||
|
@ -1844,7 +1844,8 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
}
|
||||
if( iSet>=0 ){
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, r, nPk, regRowid);
|
||||
sqlite3VdbeAddOp3(v, OP_IdxInsert, regRowset, regRowid, 0);
|
||||
sqlite3VdbeAddOp4Int(v, OP_IdxInsert, regRowset, regRowid,
|
||||
r, nPk);
|
||||
if( iSet ) sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user