mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-08 14:02:16 +03:00
Performance improvements:
Avoid unnecessary seeks when doing a single-row UPDATE on a WITHOUT ROWID table. FossilOrigin-Name: 6f187a0fb1b09ebc4732c4afbf3c813f82e069f1
This commit is contained in:
19
manifest
19
manifest
@@ -1,5 +1,5 @@
|
|||||||
C Merge\schange\sto\sdrop\sthe\smutex\son\sthe\smultiplexor\sbefore\sentering\sthe\sxRead\nVFS\scall,\sin\sorder\sto\senhance\sparallelizability.
|
C Performance\simprovements:\nAvoid\sunnecessary\sseeks\swhen\sdoing\sa\ssingle-row\sUPDATE\son\sa\sWITHOUT\sROWID\ntable.
|
||||||
D 2013-11-08T12:14:50.705
|
D 2013-11-08T15:19:46.383
|
||||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||||
F Makefile.in d12e4455cf7a36e42d3949876c1c3b88ff70867a
|
F Makefile.in d12e4455cf7a36e42d3949876c1c3b88ff70867a
|
||||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||||
@@ -223,7 +223,7 @@ F src/shell.c 03d8d9b4052430343ff30d646334621f980f1202
|
|||||||
F src/sqlite.h.in a8cad179541b8d171fed425a737084702ef462ef
|
F src/sqlite.h.in a8cad179541b8d171fed425a737084702ef462ef
|
||||||
F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e
|
F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e
|
||||||
F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc
|
F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc
|
||||||
F src/sqliteInt.h 360c8a484065f6b52ecdd5ef6766429e7aa552dd
|
F src/sqliteInt.h b4311956d26be8036f5feb2f1c904c313979ea17
|
||||||
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
|
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
|
||||||
F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158
|
F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158
|
||||||
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
|
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
|
||||||
@@ -275,11 +275,11 @@ F src/test_vfstrace.c 34b544e80ba7fb77be15395a609c669df2e660a2
|
|||||||
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||||
F src/tokenize.c ec4c1a62b890bf1dbcdb966399e140b904c700a4
|
F src/tokenize.c ec4c1a62b890bf1dbcdb966399e140b904c700a4
|
||||||
F src/trigger.c 53d6b5d50b3b23d4fcd0a36504feb5cff9aed716
|
F src/trigger.c 53d6b5d50b3b23d4fcd0a36504feb5cff9aed716
|
||||||
F src/update.c 79f10ddcb078778193b27a9e050d14741b93148a
|
F src/update.c 95a640c56d71ea9d58be66eab863d502701d092b
|
||||||
F src/utf.c 6fc6c88d50448c469c5c196acf21617a24f90269
|
F src/utf.c 6fc6c88d50448c469c5c196acf21617a24f90269
|
||||||
F src/util.c 2fa6c821d28bbdbeec1b2a7b091a281c9ef8f918
|
F src/util.c 2fa6c821d28bbdbeec1b2a7b091a281c9ef8f918
|
||||||
F src/vacuum.c 3728d74919d4fb1356f9e9a13e27773db60b7179
|
F src/vacuum.c 3728d74919d4fb1356f9e9a13e27773db60b7179
|
||||||
F src/vdbe.c ff0170cd3c5fea68386818cbd19a23bbfc711364
|
F src/vdbe.c f635690f3f2253ac8db7d505a100383a9a555362
|
||||||
F src/vdbe.h 8d5a7351024d80374fc0acdbbe3cfe65c51ba8b6
|
F src/vdbe.h 8d5a7351024d80374fc0acdbbe3cfe65c51ba8b6
|
||||||
F src/vdbeInt.h f2fa3ceccceeb757773921fb08af7c6e9f3caa1c
|
F src/vdbeInt.h f2fa3ceccceeb757773921fb08af7c6e9f3caa1c
|
||||||
F src/vdbeapi.c 93a22a9ba2abe292d5c2cf304d7eb2e894dde0ed
|
F src/vdbeapi.c 93a22a9ba2abe292d5c2cf304d7eb2e894dde0ed
|
||||||
@@ -292,7 +292,7 @@ F src/vtab.c 5a423b042eb1402ef77697d03d6a67378d97bc8d
|
|||||||
F src/wal.c 7dc3966ef98b74422267e7e6e46e07ff6c6eb1b4
|
F src/wal.c 7dc3966ef98b74422267e7e6e46e07ff6c6eb1b4
|
||||||
F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
|
F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
|
||||||
F src/walker.c e9e593d5bb798c3e67fc3893dfe7055c9e7d8d74
|
F src/walker.c e9e593d5bb798c3e67fc3893dfe7055c9e7d8d74
|
||||||
F src/where.c 30462cf04157b872b4443724739ef617b1535686
|
F src/where.c 1b5780b645dfba94ea63f2fb845a8bbfeada4162
|
||||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||||
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
||||||
F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6
|
F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6
|
||||||
@@ -1135,8 +1135,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381
|
|||||||
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
||||||
F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01
|
F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01
|
||||||
F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff
|
F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff
|
||||||
P 74e3ee2ee6ea89af2c12dd0bce248467fd0f1310 a00d2ed49c9f53263cd76ad41dad9e35e646ebb5
|
P 3c566e41e4c9c66960cc5a3ddee8556835237999
|
||||||
R 3835fd3c0df78c22220952d9100c6a09
|
R cbe50e39428754e7aa6f05505b294390
|
||||||
T +closed a00d2ed49c9f53263cd76ad41dad9e35e646ebb5
|
|
||||||
U drh
|
U drh
|
||||||
Z 74a2387ae02d248fbf85568c38a09fbd
|
Z 2b1321d582e3f35ab93369db1373861d
|
||||||
|
@@ -1 +1 @@
|
|||||||
3c566e41e4c9c66960cc5a3ddee8556835237999
|
6f187a0fb1b09ebc4732c4afbf3c813f82e069f1
|
@@ -2876,7 +2876,7 @@ int sqlite3WhereIsDistinct(WhereInfo*);
|
|||||||
int sqlite3WhereIsOrdered(WhereInfo*);
|
int sqlite3WhereIsOrdered(WhereInfo*);
|
||||||
int sqlite3WhereContinueLabel(WhereInfo*);
|
int sqlite3WhereContinueLabel(WhereInfo*);
|
||||||
int sqlite3WhereBreakLabel(WhereInfo*);
|
int sqlite3WhereBreakLabel(WhereInfo*);
|
||||||
int sqlite3WhereOkOnePass(WhereInfo*);
|
int sqlite3WhereOkOnePass(WhereInfo*, int*);
|
||||||
int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, u8);
|
int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, u8);
|
||||||
void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int);
|
void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int);
|
||||||
void sqlite3ExprCodeMove(Parse*, int, int, int);
|
void sqlite3ExprCodeMove(Parse*, int, int, int);
|
||||||
|
30
src/update.c
30
src/update.c
@@ -129,6 +129,7 @@ void sqlite3Update(
|
|||||||
int newmask; /* Mask of NEW.* columns accessed by BEFORE triggers */
|
int newmask; /* Mask of NEW.* columns accessed by BEFORE triggers */
|
||||||
int iEph = 0; /* Ephemeral table holding all primary key values */
|
int iEph = 0; /* Ephemeral table holding all primary key values */
|
||||||
int nKey = 0; /* Number of elements in regKey for WITHOUT ROWID */
|
int nKey = 0; /* Number of elements in regKey for WITHOUT ROWID */
|
||||||
|
int aiCurOnePass[2]; /* The write cursors opened by WHERE_ONEPASS */
|
||||||
|
|
||||||
/* Register Allocations */
|
/* Register Allocations */
|
||||||
int regRowCount = 0; /* A count of rows changed */
|
int regRowCount = 0; /* A count of rows changed */
|
||||||
@@ -336,10 +337,10 @@ void sqlite3Update(
|
|||||||
if( HasRowid(pTab) ){
|
if( HasRowid(pTab) ){
|
||||||
sqlite3VdbeAddOp3(v, OP_Null, 0, regRowSet, regOldRowid);
|
sqlite3VdbeAddOp3(v, OP_Null, 0, regRowSet, regOldRowid);
|
||||||
pWInfo = sqlite3WhereBegin(
|
pWInfo = sqlite3WhereBegin(
|
||||||
pParse, pTabList, pWhere, 0, 0, WHERE_ONEPASS_DESIRED, 0
|
pParse, pTabList, pWhere, 0, 0, WHERE_ONEPASS_DESIRED, iIdxCur
|
||||||
);
|
);
|
||||||
if( pWInfo==0 ) goto update_cleanup;
|
if( pWInfo==0 ) goto update_cleanup;
|
||||||
okOnePass = sqlite3WhereOkOnePass(pWInfo);
|
okOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass);
|
||||||
|
|
||||||
/* Remember the rowid of every item to be updated.
|
/* Remember the rowid of every item to be updated.
|
||||||
*/
|
*/
|
||||||
@@ -366,9 +367,9 @@ void sqlite3Update(
|
|||||||
addrOpen = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, iEph, nPk);
|
addrOpen = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, iEph, nPk);
|
||||||
sqlite3VdbeSetP4KeyInfo(pParse, pPk);
|
sqlite3VdbeSetP4KeyInfo(pParse, pPk);
|
||||||
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0,
|
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0,
|
||||||
WHERE_ONEPASS_DESIRED, 0);
|
WHERE_ONEPASS_DESIRED, iIdxCur);
|
||||||
if( pWInfo==0 ) goto update_cleanup;
|
if( pWInfo==0 ) goto update_cleanup;
|
||||||
okOnePass = sqlite3WhereOkOnePass(pWInfo);
|
okOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass);
|
||||||
for(i=0; i<nPk; i++){
|
for(i=0; i<nPk; i++){
|
||||||
sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, pPk->aiColumn[i],
|
sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, pPk->aiColumn[i],
|
||||||
iPk+i);
|
iPk+i);
|
||||||
@@ -392,6 +393,7 @@ void sqlite3Update(
|
|||||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, regRowCount);
|
sqlite3VdbeAddOp2(v, OP_Integer, 0, regRowCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
labelBreak = sqlite3VdbeMakeLabel(v);
|
||||||
if( !isView ){
|
if( !isView ){
|
||||||
/*
|
/*
|
||||||
** Open every index that needs updating. Note that if any
|
** Open every index that needs updating. Note that if any
|
||||||
@@ -415,24 +417,28 @@ void sqlite3Update(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
|
for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
|
||||||
|
int iThisCur = iIdxCur+i;
|
||||||
assert( aRegIdx );
|
assert( aRegIdx );
|
||||||
if( openAll || aRegIdx[i]>0 ){
|
if( (openAll || aRegIdx[i]>0)
|
||||||
sqlite3VdbeAddOp3(v, OP_OpenWrite, iIdxCur+i, pIdx->tnum, iDb);
|
&& iThisCur!=aiCurOnePass[0]
|
||||||
|
&& iThisCur!=aiCurOnePass[1]
|
||||||
|
){
|
||||||
|
sqlite3VdbeAddOp3(v, OP_OpenWrite, iThisCur, pIdx->tnum, iDb);
|
||||||
sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
|
sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
|
||||||
assert( pParse->nTab>iIdxCur+i );
|
assert( pParse->nTab>iThisCur );
|
||||||
VdbeComment((v, "%s", pIdx->zName));
|
VdbeComment((v, "%s", pIdx->zName));
|
||||||
|
if( okOnePass && pPk && iThisCur==iDataCur ){
|
||||||
|
sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelBreak,
|
||||||
|
regKey, nKey);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Top of the update loop */
|
/* Top of the update loop */
|
||||||
labelBreak = sqlite3VdbeMakeLabel(v);
|
|
||||||
if( okOnePass ){
|
if( okOnePass ){
|
||||||
labelContinue = labelBreak;
|
labelContinue = labelBreak;
|
||||||
sqlite3VdbeAddOp2(v, OP_IsNull, pPk ? regKey : regOldRowid, labelBreak);
|
sqlite3VdbeAddOp2(v, OP_IsNull, pPk ? regKey : regOldRowid, labelBreak);
|
||||||
if( pPk ){
|
|
||||||
sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelBreak, regKey, nKey);
|
|
||||||
}
|
|
||||||
}else if( pPk ){
|
}else if( pPk ){
|
||||||
labelContinue = sqlite3VdbeMakeLabel(v);
|
labelContinue = sqlite3VdbeMakeLabel(v);
|
||||||
sqlite3VdbeAddOp2(v, OP_Rewind, iEph, labelBreak);
|
sqlite3VdbeAddOp2(v, OP_Rewind, iEph, labelBreak);
|
||||||
@@ -624,7 +630,7 @@ void sqlite3Update(
|
|||||||
for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
|
for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
|
||||||
assert( aRegIdx );
|
assert( aRegIdx );
|
||||||
if( openAll || aRegIdx[i]>0 ){
|
if( openAll || aRegIdx[i]>0 ){
|
||||||
sqlite3VdbeAddOp2(v, OP_Close, iIdxCur, 0);
|
sqlite3VdbeAddOp2(v, OP_Close, iIdxCur+i, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if( iDataCur<iIdxCur ) sqlite3VdbeAddOp2(v, OP_Close, iDataCur, 0);
|
if( iDataCur<iIdxCur ) sqlite3VdbeAddOp2(v, OP_Close, iDataCur, 0);
|
||||||
|
@@ -2182,6 +2182,7 @@ case OP_IfNot: { /* jump, in1 */
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Opcode: IsNull P1 P2 * * *
|
/* Opcode: IsNull P1 P2 * * *
|
||||||
|
** Synopsis: if r[P1]==NULL goto P2
|
||||||
**
|
**
|
||||||
** Jump to P2 if the value in register P1 is NULL.
|
** Jump to P2 if the value in register P1 is NULL.
|
||||||
*/
|
*/
|
||||||
@@ -2194,6 +2195,7 @@ case OP_IsNull: { /* same as TK_ISNULL, jump, in1 */
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Opcode: NotNull P1 P2 * * *
|
/* Opcode: NotNull P1 P2 * * *
|
||||||
|
** Synopsis: if r[P1]!=NULL goto P2
|
||||||
**
|
**
|
||||||
** Jump to P2 if the value in register P1 is not NULL.
|
** Jump to P2 if the value in register P1 is not NULL.
|
||||||
*/
|
*/
|
||||||
|
69
src/where.c
69
src/where.c
@@ -409,6 +409,7 @@ struct WhereInfo {
|
|||||||
int iContinue; /* Jump here to continue with next record */
|
int iContinue; /* Jump here to continue with next record */
|
||||||
int iBreak; /* Jump here to break out of the loop */
|
int iBreak; /* Jump here to break out of the loop */
|
||||||
int savedNQueryLoop; /* pParse->nQueryLoop outside the WHERE loop */
|
int savedNQueryLoop; /* pParse->nQueryLoop outside the WHERE loop */
|
||||||
|
int aiCurOnePass[2]; /* OP_OpenWrite cursors for the ONEPASS opt */
|
||||||
WhereMaskSet sMaskSet; /* Map cursor numbers to bitmasks */
|
WhereMaskSet sMaskSet; /* Map cursor numbers to bitmasks */
|
||||||
WhereClause sWC; /* Decomposition of the WHERE clause */
|
WhereClause sWC; /* Decomposition of the WHERE clause */
|
||||||
WhereLevel a[1]; /* Information about each nest loop in WHERE */
|
WhereLevel a[1]; /* Information about each nest loop in WHERE */
|
||||||
@@ -501,8 +502,19 @@ int sqlite3WhereBreakLabel(WhereInfo *pWInfo){
|
|||||||
** Return TRUE if an UPDATE or DELETE statement can operate directly on
|
** Return TRUE if an UPDATE or DELETE statement can operate directly on
|
||||||
** the rowids returned by a WHERE clause. Return FALSE if doing an
|
** the rowids returned by a WHERE clause. Return FALSE if doing an
|
||||||
** UPDATE or DELETE might change subsequent WHERE clause results.
|
** UPDATE or DELETE might change subsequent WHERE clause results.
|
||||||
|
**
|
||||||
|
** If the ONEPASS optimization is used (if this routine returns true)
|
||||||
|
** then also write the indices of open cursors used by ONEPASS
|
||||||
|
** into aiCur[0] and aiCur[1]. iaCur[0] gets the cursor of the data
|
||||||
|
** table and iaCur[1] gets the cursor used by an auxiliary index.
|
||||||
|
** Either value may be -1, indicating that cursor is not used.
|
||||||
|
** Any cursors returned will have been opened for writing.
|
||||||
|
**
|
||||||
|
** aiCur[0] and aiCur[1] both get -1 if the where-clause logic is
|
||||||
|
** unable to use the ONEPASS optimization.
|
||||||
*/
|
*/
|
||||||
int sqlite3WhereOkOnePass(WhereInfo *pWInfo){
|
int sqlite3WhereOkOnePass(WhereInfo *pWInfo, int *aiCur){
|
||||||
|
memcpy(aiCur, pWInfo->aiCurOnePass, sizeof(int)*2);
|
||||||
return pWInfo->okOnePass;
|
return pWInfo->okOnePass;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3152,7 +3164,7 @@ static Bitmask codeOneLoopStart(
|
|||||||
bRev = (pWInfo->revMask>>iLevel)&1;
|
bRev = (pWInfo->revMask>>iLevel)&1;
|
||||||
omitTable = (pLoop->wsFlags & WHERE_IDX_ONLY)!=0
|
omitTable = (pLoop->wsFlags & WHERE_IDX_ONLY)!=0
|
||||||
&& (pWInfo->wctrlFlags & WHERE_FORCE_TABLE)==0;
|
&& (pWInfo->wctrlFlags & WHERE_FORCE_TABLE)==0;
|
||||||
VdbeNoopComment((v, "Begin Join Loop %d", iLevel));
|
VdbeNoopComment((v, "Begin WHERE-Loop %d: %s", iLevel,pTabItem->pTab->zName));
|
||||||
|
|
||||||
/* Create labels for the "break" and "continue" instructions
|
/* Create labels for the "break" and "continue" instructions
|
||||||
** for the current loop. Jump to addrBrk to break out of a loop.
|
** for the current loop. Jump to addrBrk to break out of a loop.
|
||||||
@@ -5694,6 +5706,14 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
|
|||||||
** if the WHERE_GROUPBY flag is set in wctrlFlags) of a SELECT statement
|
** if the WHERE_GROUPBY flag is set in wctrlFlags) of a SELECT statement
|
||||||
** if there is one. If there is no ORDER BY clause or if this routine
|
** if there is one. If there is no ORDER BY clause or if this routine
|
||||||
** is called from an UPDATE or DELETE statement, then pOrderBy is NULL.
|
** is called from an UPDATE or DELETE statement, then pOrderBy is NULL.
|
||||||
|
**
|
||||||
|
** The iIdxCur parameter is the cursor number of an index. If
|
||||||
|
** WHERE_ONETABLE_ONLY is set, iIdxCur is the cursor number of an index
|
||||||
|
** to use for OR clause processing. The WHERE clause should use this
|
||||||
|
** specific cursor. If WHERE_ONEPASS_DESIRED is set, then iIdxCur is
|
||||||
|
** the first cursor in an array of cursors for all indices. iIdxCur should
|
||||||
|
** be used to compute the appropriate cursor depending on which index is
|
||||||
|
** used.
|
||||||
*/
|
*/
|
||||||
WhereInfo *sqlite3WhereBegin(
|
WhereInfo *sqlite3WhereBegin(
|
||||||
Parse *pParse, /* The parser context */
|
Parse *pParse, /* The parser context */
|
||||||
@@ -5759,6 +5779,7 @@ WhereInfo *sqlite3WhereBegin(
|
|||||||
pWInfo = 0;
|
pWInfo = 0;
|
||||||
goto whereBeginError;
|
goto whereBeginError;
|
||||||
}
|
}
|
||||||
|
pWInfo->aiCurOnePass[0] = pWInfo->aiCurOnePass[1] = -1;
|
||||||
pWInfo->nLevel = nTabList;
|
pWInfo->nLevel = nTabList;
|
||||||
pWInfo->pParse = pParse;
|
pWInfo->pParse = pParse;
|
||||||
pWInfo->pTabList = pTabList;
|
pWInfo->pTabList = pTabList;
|
||||||
@@ -6022,8 +6043,13 @@ WhereInfo *sqlite3WhereBegin(
|
|||||||
#endif
|
#endif
|
||||||
if( (pLoop->wsFlags & WHERE_IDX_ONLY)==0
|
if( (pLoop->wsFlags & WHERE_IDX_ONLY)==0
|
||||||
&& (wctrlFlags & WHERE_OMIT_OPEN_CLOSE)==0 ){
|
&& (wctrlFlags & WHERE_OMIT_OPEN_CLOSE)==0 ){
|
||||||
int op = pWInfo->okOnePass ? OP_OpenWrite : OP_OpenRead;
|
int op = OP_OpenRead;
|
||||||
|
if( pWInfo->okOnePass ){
|
||||||
|
op = OP_OpenWrite;
|
||||||
|
pWInfo->aiCurOnePass[0] = pTabItem->iCursor;
|
||||||
|
};
|
||||||
sqlite3OpenTable(pParse, pTabItem->iCursor, iDb, pTab, op);
|
sqlite3OpenTable(pParse, pTabItem->iCursor, iDb, pTab, op);
|
||||||
|
assert( pTabItem->iCursor==pLevel->iTabCur );
|
||||||
testcase( !pWInfo->okOnePass && pTab->nCol==BMS-1 );
|
testcase( !pWInfo->okOnePass && pTab->nCol==BMS-1 );
|
||||||
testcase( !pWInfo->okOnePass && pTab->nCol==BMS );
|
testcase( !pWInfo->okOnePass && pTab->nCol==BMS );
|
||||||
if( !pWInfo->okOnePass && pTab->nCol<BMS && HasRowid(pTab) ){
|
if( !pWInfo->okOnePass && pTab->nCol<BMS && HasRowid(pTab) ){
|
||||||
@@ -6039,11 +6065,27 @@ WhereInfo *sqlite3WhereBegin(
|
|||||||
}
|
}
|
||||||
if( pLoop->wsFlags & WHERE_INDEXED ){
|
if( pLoop->wsFlags & WHERE_INDEXED ){
|
||||||
Index *pIx = pLoop->u.btree.pIndex;
|
Index *pIx = pLoop->u.btree.pIndex;
|
||||||
/* FIXME: As an optimization use pTabItem->iCursor if WHERE_IDX_ONLY */
|
int iIndexCur;
|
||||||
int iIndexCur = pLevel->iIdxCur = iIdxCur ? iIdxCur : pParse->nTab++;
|
int op = OP_OpenRead;
|
||||||
|
if( pWInfo->okOnePass && iIdxCur ){
|
||||||
|
Index *pJ = pTabItem->pTab->pIndex;
|
||||||
|
iIndexCur = iIdxCur;
|
||||||
|
assert( wctrlFlags & WHERE_ONEPASS_DESIRED );
|
||||||
|
while( ALWAYS(pJ) && pJ!=pIx ){
|
||||||
|
iIndexCur++;
|
||||||
|
pJ = pJ->pNext;
|
||||||
|
}
|
||||||
|
op = OP_OpenWrite;
|
||||||
|
pWInfo->aiCurOnePass[1] = iIndexCur;
|
||||||
|
}else if( iIdxCur && (wctrlFlags & WHERE_ONETABLE_ONLY)!=0 ){
|
||||||
|
iIndexCur = iIdxCur;
|
||||||
|
}else{
|
||||||
|
iIndexCur = pParse->nTab++;
|
||||||
|
}
|
||||||
|
pLevel->iIdxCur = iIndexCur;
|
||||||
assert( pIx->pSchema==pTab->pSchema );
|
assert( pIx->pSchema==pTab->pSchema );
|
||||||
assert( iIndexCur>=0 );
|
assert( iIndexCur>=0 );
|
||||||
sqlite3VdbeAddOp3(v, OP_OpenRead, iIndexCur, pIx->tnum, iDb);
|
sqlite3VdbeAddOp3(v, op, iIndexCur, pIx->tnum, iDb);
|
||||||
sqlite3VdbeSetP4KeyInfo(pParse, pIx);
|
sqlite3VdbeSetP4KeyInfo(pParse, pIx);
|
||||||
VdbeComment((v, "%s", pIx->zName));
|
VdbeComment((v, "%s", pIx->zName));
|
||||||
}
|
}
|
||||||
@@ -6139,6 +6181,8 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
|||||||
}
|
}
|
||||||
sqlite3VdbeJumpHere(v, addr);
|
sqlite3VdbeJumpHere(v, addr);
|
||||||
}
|
}
|
||||||
|
VdbeNoopComment((v, "End WHERE-Loop %d: %s", i,
|
||||||
|
pWInfo->pTabList->a[pLevel->iFrom].pTab->zName));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The "break" point is here, just past the end of the outer loop.
|
/* The "break" point is here, just past the end of the outer loop.
|
||||||
@@ -6146,8 +6190,6 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
|||||||
*/
|
*/
|
||||||
sqlite3VdbeResolveLabel(v, pWInfo->iBreak);
|
sqlite3VdbeResolveLabel(v, pWInfo->iBreak);
|
||||||
|
|
||||||
/* Close all of the cursors that were opened by sqlite3WhereBegin.
|
|
||||||
*/
|
|
||||||
assert( pWInfo->nLevel<=pTabList->nSrc );
|
assert( pWInfo->nLevel<=pTabList->nSrc );
|
||||||
for(i=0, pLevel=pWInfo->a; i<pWInfo->nLevel; i++, pLevel++){
|
for(i=0, pLevel=pWInfo->a; i<pWInfo->nLevel; i++, pLevel++){
|
||||||
Index *pIdx = 0;
|
Index *pIdx = 0;
|
||||||
@@ -6155,6 +6197,12 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
|||||||
Table *pTab = pTabItem->pTab;
|
Table *pTab = pTabItem->pTab;
|
||||||
assert( pTab!=0 );
|
assert( pTab!=0 );
|
||||||
pLoop = pLevel->pWLoop;
|
pLoop = pLevel->pWLoop;
|
||||||
|
|
||||||
|
/* Close all of the cursors that were opened by sqlite3WhereBegin.
|
||||||
|
** Except, do not close cursors that will be reused by the OR optimization
|
||||||
|
** (WHERE_OMIT_OPEN_CLOSE). And do not close the OP_OpenWrite cursors
|
||||||
|
** created for the ONEPASS optimization.
|
||||||
|
*/
|
||||||
if( (pTab->tabFlags & TF_Ephemeral)==0
|
if( (pTab->tabFlags & TF_Ephemeral)==0
|
||||||
&& pTab->pSelect==0
|
&& pTab->pSelect==0
|
||||||
&& (pWInfo->wctrlFlags & WHERE_OMIT_OPEN_CLOSE)==0
|
&& (pWInfo->wctrlFlags & WHERE_OMIT_OPEN_CLOSE)==0
|
||||||
@@ -6163,7 +6211,10 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
|||||||
if( !pWInfo->okOnePass && (ws & WHERE_IDX_ONLY)==0 ){
|
if( !pWInfo->okOnePass && (ws & WHERE_IDX_ONLY)==0 ){
|
||||||
sqlite3VdbeAddOp1(v, OP_Close, pTabItem->iCursor);
|
sqlite3VdbeAddOp1(v, OP_Close, pTabItem->iCursor);
|
||||||
}
|
}
|
||||||
if( (ws & WHERE_INDEXED)!=0 && (ws & (WHERE_IPK|WHERE_AUTO_INDEX))==0 ){
|
if( (ws & WHERE_INDEXED)!=0
|
||||||
|
&& (ws & (WHERE_IPK|WHERE_AUTO_INDEX))==0
|
||||||
|
&& pLevel->iIdxCur!=pWInfo->aiCurOnePass[1]
|
||||||
|
){
|
||||||
sqlite3VdbeAddOp1(v, OP_Close, pLevel->iIdxCur);
|
sqlite3VdbeAddOp1(v, OP_Close, pLevel->iIdxCur);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user