From: drh Date: Fri, 22 Feb 2019 23:29:56 +0000 (+0000) Subject: Make all ephemeral tables built to hold the RHS of an IN operator be X-Git-Tag: version-3.28.0~162^2~1 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=50ef6716d2ac75314e76546d074efd694969dba2;p=thirdparty%2Fsqlite.git Make all ephemeral tables built to hold the RHS of an IN operator be index-btrees, never table-btrees, regardless of whether or not they are used as IN_INDEX_LOOP or IN_INDEX_MEMBERSHIP. That way, the same ephmerial table can be reused for both cases. FossilOrigin-Name: c2d50df8fd1a1fdae6226a3e77296ded09b53a74540caedd4868e686a93cbc10 --- diff --git a/manifest b/manifest index 1851f3ee0f..83c7b99bb1 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Check-in\s[fa792714ae62fa980]\sis\snot\sa\svalid\sfix\sfor\sticket\n[df46dfb631f75694],\sas\sthe\snew\stest\scase\sin\sthis\scheck-in\sdemonstrates.\nThe\sfix\shere\scauses\stest\scases\sfor\sthe\s[df46dfb631f75694]\sbug\sto\sfail\nagain,\sso\sthis\scheck-in\sis\son\sa\sbranch.\s\sA\snew\sfix\sis\sneeded\sfor\n[df46dfb631f75694]. -D 2019-02-22T21:33:56.743 +C Make\sall\sephemeral\stables\sbuilt\sto\shold\sthe\sRHS\sof\san\sIN\soperator\sbe\nindex-btrees,\snever\stable-btrees,\sregardless\sof\swhether\sor\snot\sthey\sare\nused\sas\sIN_INDEX_LOOP\sor\sIN_INDEX_MEMBERSHIP.\s\sThat\sway,\sthe\ssame\sephmerial\ntable\scan\sbe\sreused\sfor\sboth\scases. +D 2019-02-22T23:29:56.457 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 178d8eb6840771149cee40b322d1b3be30d330198c522c903c1b66fb5a1bfca4 @@ -467,7 +467,7 @@ F src/date.c ebe1dc7c8a347117bb02570f1a931c62dd78f4a2b1b516f4837d45b7d6426957 F src/dbpage.c 135eb3b5e74f9ef74bde5cec2571192c90c86984fa534c88bf4a055076fa19b7 F src/dbstat.c c12833de69cb655751487d2c5a59607e36be1c58ba1f4bd536609909ad47b319 F src/delete.c d08c9e01a2664afd12edcfa3a9c6578517e8ff8735f35509582693adbe0edeaf -F src/expr.c 182dc9ff30aa6a430b7f728ce84fda85ec10890e29fdf75be1e871d13222a99c +F src/expr.c f2d0ecf68213770be4fad83128ce02e67667deebaa0a44061313f7e4f2a4ae28 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fkey.c bd0138acdc008c1845ccf92f8e73787880562de649471804801c06fed814c765 F src/func.c 0341881d22903aac5ba7f352b188806d6436e1d6ae4235ff01e44d56879dfe63 @@ -476,7 +476,7 @@ F src/hash.c a12580e143f10301ed5166ea4964ae2853d3905a511d4e0c44497245c7ce1f7a F src/hash.h ab34c5c54a9e9de2e790b24349ba5aab3dbb4fd4 F src/hwtime.h 747c1bbe9df21a92e9c50f3bbec1de841dc5e5da F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71 -F src/insert.c 305f6ea82a90c3d506ad26d3b6530655bcf08dbff20403ce9f20c21758fbd5c0 +F src/insert.c 4ce12b5ba3bcbfa17ec37ce960d499fc287b6289df2c00b31201f716a3c7df45 F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/loadext.c e6f10875d52aca3b7e57ce1ec174aeafc9b6c00b43000cd30d791f9cb490b7a6 F src/main.c 27d7265625ea6eaccdfe7c53ef41adc179c9357a077702a860c1a3b0a037a16f @@ -520,7 +520,7 @@ F src/shell.c.in f2c1adbee3f6f36686b4a38d2168ebfc25298b4ad1e6d95199fc4e95b539251 F src/sqlite.h.in 7da74fd5bd7a9dbe92297060f036935520b26e240457287c5e67c7b9db51a986 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 960f1b86c3610fa23cb6a267572a97dcf286e77aa0dd3b9b23292ffaa1ea8683 -F src/sqliteInt.h 8628c582eafa5ca93523cdaa7c45b2f38a11132e419c7923850706da7fa36bc2 +F src/sqliteInt.h f253c4ec15e577a293a462e5049f8ea1d0c7a31819b3a88acdd24698df8f4d0b F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34 @@ -586,7 +586,7 @@ F src/upsert.c 0dd81b40206841814d46942a7337786932475f085716042d0cb2fc7791bf8ca4 F src/utf.c 810fbfebe12359f10bc2a011520a6e10879ab2a163bcb26c74768eab82ea62a5 F src/util.c 82a2e3f691a3b654be872e305dab1f455e565dedf5e6a90c818c1ab307c00432 F src/vacuum.c a9f389f41556c0ec310bc9169dc9476603c30a0a913ad92bfbc75c86886967ca -F src/vdbe.c c2ebe27a1e4176f5e4b48269917b7a3df096b125d3c407da90e769a9fe4e406e +F src/vdbe.c f1e7b5320df80ff58c67176e35cb48062cbda2a9c9811f11db5faa48071d3fe4 F src/vdbe.h 712bca562eaed1c25506b9faf9680bdc75fc42e2f4a1cd518d883fa79c7a4237 F src/vdbeInt.h a76d5eed62c76bcd8de7afd3147fac1bc40c5a870582664bcd7d071ef437c37f F src/vdbeapi.c cde63790c9d18ba5941d52c9f49e1a862cf6503141d5b9c112a05eb0adbf30a9 @@ -1805,10 +1805,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 579b66eaa0816561c6e47ea116b46f229188f0fc84c1173bfe0d21df2dff9a9a -R 44233d0aa266189ff2ae6bf0b0a0a078 -T *branch * tkt-df46dfb631 -T *sym-tkt-df46dfb631 * -T -sym-trunk * +P 0d456456da6e25b20d9d27ca95f1013082bca52ee74ee9bf91732a9fa843ea45 +R 63e80740e79601900e62b0317140d8ef U drh -Z ab4cb17ec0e626c52e7694e3fdcbcc49 +Z b87326ad069ad8da755635bc9cbd9517 diff --git a/manifest.uuid b/manifest.uuid index a2aa927f76..2e02e213eb 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -0d456456da6e25b20d9d27ca95f1013082bca52ee74ee9bf91732a9fa843ea45 \ No newline at end of file +c2d50df8fd1a1fdae6226a3e77296ded09b53a74540caedd4868e686a93cbc10 \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index 03ecf1567d..e39b6408c4 100644 --- a/src/expr.c +++ b/src/expr.c @@ -2552,14 +2552,11 @@ int sqlite3FindInIndex( eType = IN_INDEX_EPH; if( inFlags & IN_INDEX_LOOP ){ pParse->nQueryLoop = 0; - if( pX->pLeft->iColumn<0 && !ExprHasProperty(pX, EP_xIsSelect) ){ - eType = IN_INDEX_ROWID; - } }else if( prRhsHasNull ){ *prRhsHasNull = rMayHaveNull = ++pParse->nMem; } assert( pX->op==TK_IN ); - sqlite3CodeRhsOfIN(pParse, pX, iTab, eType==IN_INDEX_ROWID); + sqlite3CodeRhsOfIN(pParse, pX, iTab); if( rMayHaveNull ){ sqlite3SetHasNullFlag(v, iTab, rMayHaveNull); } @@ -2660,12 +2657,6 @@ void sqlite3VectorErrorMsg(Parse *pParse, Expr *pExpr){ ** however the cursor number returned might not be the same, as it might ** have been duplicated using OP_OpenDup. ** -** If parameter isRowid is non-zero, then LHS of the IN operator is guaranteed -** to be a non-null integer. In this case, the ephemeral table can be an -** table B-Tree that keyed by only integers. The more general cases uses -** an index B-Tree which can have arbitrary keys, but is slower to both -** read and write. -** ** If the LHS expression ("x" in the examples) is a column value, or ** the SELECT statement returns a column value, then the affinity of that ** column is used to build the index keys. If both 'x' and the @@ -2677,8 +2668,7 @@ void sqlite3VectorErrorMsg(Parse *pParse, Expr *pExpr){ void sqlite3CodeRhsOfIN( Parse *pParse, /* Parsing context */ Expr *pExpr, /* The IN operator */ - int iTab, /* Use this cursor number */ - int isRowid /* If true, LHS is a rowid */ + int iTab /* Use this cursor number */ ){ int addrOnce = 0; /* Address of the OP_Once instruction at top */ int addr; /* Address of OP_OpenEphemeral instruction */ @@ -2731,14 +2721,12 @@ void sqlite3CodeRhsOfIN( /* Check to see if this is a vector IN operator */ pLeft = pExpr->pLeft; nVal = sqlite3ExprVectorSize(pLeft); - assert( !isRowid || nVal==1 ); /* Construct the ephemeral table that will contain the content of ** RHS of the IN operator. */ pExpr->iTable = iTab; - addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, - pExpr->iTable, (isRowid?0:nVal)); + addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pExpr->iTable, nVal); #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS if( ExprHasProperty(pExpr, EP_xIsSelect) ){ VdbeComment((v, "Result of SELECT %u", pExpr->x.pSelect->selId)); @@ -2746,7 +2734,7 @@ void sqlite3CodeRhsOfIN( VdbeComment((v, "RHS of IN operator")); } #endif - pKeyInfo = isRowid ? 0 : sqlite3KeyInfoAlloc(pParse->db, nVal, 1); + pKeyInfo = sqlite3KeyInfoAlloc(pParse->db, nVal, 1); if( ExprHasProperty(pExpr, EP_xIsSelect) ){ /* Case 1: expr IN (SELECT ...) @@ -2760,7 +2748,6 @@ void sqlite3CodeRhsOfIN( ExplainQueryPlan((pParse, 1, "%sLIST SUBQUERY %d", addrOnce?"":"CORRELATED ", pSelect->selId )); - assert( !isRowid ); /* If the LHS and RHS of the IN operator do not match, that ** error will have been caught long before we reach this point. */ if( ALWAYS(pEList->nExpr==nVal) ){ @@ -2813,10 +2800,8 @@ void sqlite3CodeRhsOfIN( /* Loop through each expression in . */ r1 = sqlite3GetTempReg(pParse); r2 = sqlite3GetTempReg(pParse); - if( isRowid ) sqlite3VdbeAddOp4(v, OP_Blob, 0, r2, 0, "", P4_STATIC); for(i=pList->nExpr, pItem=pList->a; i>0; i--, pItem++){ Expr *pE2 = pItem->pExpr; - int iValToIns; /* If the expression is not constant then we will need to ** disable the test that was generated above that makes sure @@ -2829,20 +2814,9 @@ void sqlite3CodeRhsOfIN( } /* Evaluate the expression and insert it into the temp table */ - if( isRowid && sqlite3ExprIsInteger(pE2, &iValToIns) ){ - sqlite3VdbeAddOp3(v, OP_InsertInt, iTab, r2, iValToIns); - }else{ - r3 = sqlite3ExprCodeTarget(pParse, pE2, r1); - if( isRowid ){ - sqlite3VdbeAddOp2(v, OP_MustBeInt, r3, - sqlite3VdbeCurrentAddr(v)+2); - VdbeCoverage(v); - sqlite3VdbeAddOp3(v, OP_Insert, iTab, r2, r3); - }else{ - sqlite3VdbeAddOp4(v, OP_MakeRecord, r3, 1, r2, &affinity, 1); - sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iTab, r2, r3, 1); - } - } + r3 = sqlite3ExprCodeTarget(pParse, pE2, r1); + sqlite3VdbeAddOp4(v, OP_MakeRecord, r3, 1, r2, &affinity, 1); + sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iTab, r2, r3, 1); } sqlite3ReleaseTempReg(pParse, r1); sqlite3ReleaseTempReg(pParse, r2); diff --git a/src/insert.c b/src/insert.c index 6f044db5a7..a68db1a1d2 100644 --- a/src/insert.c +++ b/src/insert.c @@ -1921,10 +1921,13 @@ void sqlite3CompleteInsertion( pik_flags |= (update_flags & OPFLAG_SAVEPOSITION); #ifdef SQLITE_ENABLE_PREUPDATE_HOOK if( update_flags==0 ){ - sqlite3VdbeAddOp4(v, OP_InsertInt, - iIdxCur+i, aRegIdx[i], 0, (char*)pTab, P4_TABLE + int r = sqlite3GetTempReg(pParse); + sqlite3VdbeAddOp2(v, OP_Integer, 0, r); + sqlite3VdbeAddOp4(v, OP_Insert, + iIdxCur+i, aRegIdx[i], r, (char*)pTab, P4_TABLE ); sqlite3VdbeChangeP5(v, OPFLAG_ISNOOP); + sqlite3ReleaseTempReg(pParse, r); } #endif } diff --git a/src/sqliteInt.h b/src/sqliteInt.h index e568677759..f12e2b6228 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -4281,7 +4281,7 @@ void sqlite3AlterRenameColumn(Parse*, SrcList*, Token*, Token*); int sqlite3GetToken(const unsigned char *, int *); void sqlite3NestedParse(Parse*, const char*, ...); void sqlite3ExpirePreparedStatements(sqlite3*, int); -void sqlite3CodeRhsOfIN(Parse*, Expr*, int, int); +void sqlite3CodeRhsOfIN(Parse*, Expr*, int); int sqlite3CodeSubselect(Parse*, Expr*); void sqlite3SelectPrep(Parse*, Select*, NameContext*); void sqlite3SelectWrongNumTermsError(Parse *pParse, Select *p); diff --git a/src/vdbe.c b/src/vdbe.c index 5085273bc7..425a03e0e6 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -4569,14 +4569,7 @@ case OP_NewRowid: { /* out2 */ ** This instruction only works on tables. The equivalent instruction ** for indices is OP_IdxInsert. */ -/* Opcode: InsertInt P1 P2 P3 P4 P5 -** Synopsis: intkey=P3 data=r[P2] -** -** This works exactly like OP_Insert except that the key is the -** integer value P3, not the value of the integer stored in register P3. -*/ -case OP_Insert: -case OP_InsertInt: { +case OP_Insert: { Mem *pData; /* MEM cell holding data for the record to be inserted */ Mem *pKey; /* MEM cell holding key for the record */ VdbeCursor *pC; /* Cursor to table into which insert is written */ @@ -4597,16 +4590,11 @@ case OP_InsertInt: { REGISTER_TRACE(pOp->p2, pData); sqlite3VdbeIncrWriteCounter(p, pC); - if( pOp->opcode==OP_Insert ){ - pKey = &aMem[pOp->p3]; - assert( pKey->flags & MEM_Int ); - assert( memIsValid(pKey) ); - REGISTER_TRACE(pOp->p3, pKey); - x.nKey = pKey->u.i; - }else{ - assert( pOp->opcode==OP_InsertInt ); - x.nKey = pOp->p3; - } + pKey = &aMem[pOp->p3]; + assert( pKey->flags & MEM_Int ); + assert( memIsValid(pKey) ); + REGISTER_TRACE(pOp->p3, pKey); + x.nKey = pKey->u.i; if( pOp->p4type==P4_TABLE && HAS_UPDATE_HOOK(db) ){ assert( pC->iDb>=0 );