From 323df7907ea733e5bfada834df934cd00565e3ab Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 5 Aug 2013 19:11:29 +0000 Subject: [PATCH] Factor all KeyInfo object allocations into a single function: sqlite3KeyInfoAlloc(). Always allocate enough space so that sqlite3VdbeRecordCompare() can avoid checking boundaries and hence run faster. FossilOrigin-Name: 7301bedd94c8610568349953b18ff3575203e1b2 --- manifest | 22 ++++++++++----------- manifest.uuid | 2 +- src/build.c | 11 +++-------- src/expr.c | 21 ++++++++++---------- src/select.c | 51 ++++++++++++++++++++++++------------------------- src/sqliteInt.h | 9 +++++++-- src/vdbe.c | 2 +- src/vdbeaux.c | 27 +++++++++----------------- 8 files changed, 67 insertions(+), 78 deletions(-) diff --git a/manifest b/manifest index 14fc750b6f..803e5be65c 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Improve\sperformance\sof\ssqlite3VdbeRecordCompare()\sby\susing\san\sapproximation\nthat\smight\sgive\sfalse\snegatives\sand\sonly\srunning\sthe\smore\sexpensive\sexact\s\nsubexpression\sif\sthe\sapproximation\sfails. -D 2013-08-05T15:32:09.754 +C Factor\sall\sKeyInfo\sobject\sallocations\sinto\sa\ssingle\sfunction:\nsqlite3KeyInfoAlloc().\s\sAlways\sallocate\senough\sspace\sso\sthat\s\nsqlite3VdbeRecordCompare()\scan\savoid\schecking\sboundaries\sand\shence\nrun\sfaster. +D 2013-08-05T19:11:29.094 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -166,13 +166,13 @@ F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7 F src/btree.c 3f7bbfd72efb1cbf6a49515c376a031767ec930a F src/btree.h 6fa8a3ff2483d0bb64a9f0105a8cedeac9e00cca F src/btreeInt.h eecc84f02375b2bb7a44abbcbbe3747dde73edb2 -F src/build.c fc76e1cd014840781e175f57f6de38917986943b +F src/build.c cee4724668ebc09bb482c1be30f96e0ae2474f9b F src/callback.c d7e46f40c3cf53c43550b7da7a1d0479910b62cc F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac F src/ctime.c 4262c227bc91cecc61ae37ed3a40f08069cfa267 F src/date.c 067a81c9942c497aafd2c260e13add8a7d0c7dd4 F src/delete.c 2317c814866d9aa71fea16b3faf4fdd4d6a49b94 -F src/expr.c 2068a7c17e45f8bee6e44205b059aa30acbc71c5 +F src/expr.c 7e55edefb8bd0b35b382ce9226c58472cd63a443 F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fkey.c 914a6bbd987d857c41ac9d244efa6641f36faadb F src/func.c 5c50c1ea31fd864b0fe921fe1a8d4c55acd609ef @@ -216,12 +216,12 @@ F src/printf.c 41c49dac366a3a411190001a8ab495fa8887974e F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50 F src/resolve.c 17e670996729ac41aadf6a31f57b4e6f29b3d819 F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0 -F src/select.c 20369c82dc38eb4a77b458c8f6e353ef550580c9 +F src/select.c 97273e41f57993e817bf0e816f9b19c4c07fc15b F src/shell.c 52f975eae87c8338c4dfbf4c2842d2a0971f01fd F src/sqlite.h.in 442c109e0c3447c34b1794971ecdb673ce08a843 F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0 F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc -F src/sqliteInt.h 7c6ad474ce49ed18393c027be65c9532b7c9168f +F src/sqliteInt.h abae976c5cfc00333bd612fc1d31d64056ea1e63 F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e @@ -277,11 +277,11 @@ F src/update.c 7f3fe64d8f3b44c44a1eac293f0f85f87c355b7a F src/utf.c 8d819e2e5104a430fc2005f018db14347c95a38f F src/util.c f566b5138099a2df8533b190d0dcc74b7dfbe0c9 F src/vacuum.c d9c5759f4c5a438bb43c2086f72c5d2edabc36c8 -F src/vdbe.c d6048a720c197db2f0e7d618e918bd2e2eff0322 +F src/vdbe.c 4914ae1d00045a5310aea9e0f7c9a8edd3d9f856 F src/vdbe.h 4f554b5627f26710c4c36d919110a3fc611ca5c4 F src/vdbeInt.h e9b7c6b165a31a4715c5aa97223d20d265515231 F src/vdbeapi.c 4d13580bd058b39623e8fcfc233b7df4b8191e8b -F src/vdbeaux.c 1a149d406d812b767d70c932dfc472d586d04c45 +F src/vdbeaux.c d5cdd5bd5c063cc912df20b0bcadf78b6b351cb2 F src/vdbeblob.c 5dc79627775bd9a9b494dd956e26297946417d69 F src/vdbemem.c 833005f1cbbf447289f1973dba2a0c2228c7b8ab F src/vdbesort.c 3937e06b2a0e354500e17dc206ef4c35770a5017 @@ -1105,7 +1105,7 @@ F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/wherecosttest.c f407dc4c79786982a475261866a161cd007947ae F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 4b8b426f10f8ae13bf553f7adf5ae09383fa0bd4 -R 338de61a71c3cd74b79152f7e9194e12 +P 28979dcd16f53e0ddca8eed74b668834e2856f03 +R a1cc3bea296ae01021d8d2b465ba6a3e U drh -Z 467c61e8c494116a000cdb09272cb823 +Z fdca2fea30eff049f879427aa25c6c1a diff --git a/manifest.uuid b/manifest.uuid index caf82026b2..950c349206 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -28979dcd16f53e0ddca8eed74b668834e2856f03 \ No newline at end of file +7301bedd94c8610568349953b18ff3575203e1b2 \ No newline at end of file diff --git a/src/build.c b/src/build.c index 06ecf6570f..f5ea5be4b6 100644 --- a/src/build.c +++ b/src/build.c @@ -3805,25 +3805,20 @@ void sqlite3Reindex(Parse *pParse, Token *pName1, Token *pName2){ KeyInfo *sqlite3IndexKeyinfo(Parse *pParse, Index *pIdx){ int i; int nCol = pIdx->nColumn; - int nBytes = sizeof(KeyInfo) + (nCol-1)*sizeof(CollSeq*) + nCol; - sqlite3 *db = pParse->db; - KeyInfo *pKey = (KeyInfo *)sqlite3DbMallocZero(db, nBytes); + KeyInfo *pKey; + pKey = sqlite3KeyInfoAlloc(pParse->db, nCol); if( pKey ){ - pKey->db = pParse->db; - pKey->aSortOrder = (u8 *)&(pKey->aColl[nCol]); - assert( &pKey->aSortOrder[nCol]==&(((u8 *)pKey)[nBytes]) ); for(i=0; iazColl[i]; assert( zColl ); pKey->aColl[i] = sqlite3LocateCollSeq(pParse, zColl); pKey->aSortOrder[i] = pIdx->aSortOrder[i]; } - pKey->nField = (u16)nCol; } if( pParse->nErr ){ - sqlite3DbFree(db, pKey); + sqlite3DbFree(pParse->db, pKey); pKey = 0; } return pKey; diff --git a/src/expr.c b/src/expr.c index e7ac855f71..3857d5d841 100644 --- a/src/expr.c +++ b/src/expr.c @@ -1692,10 +1692,9 @@ int sqlite3CodeSubselect( switch( pExpr->op ){ case TK_IN: { char affinity; /* Affinity of the LHS of the IN */ - KeyInfo keyInfo; /* Keyinfo for the generated table */ - static u8 sortOrder = 0; /* Fake aSortOrder for keyInfo */ int addr; /* Address of OP_OpenEphemeral instruction */ Expr *pLeft = pExpr->pLeft; /* the LHS of the IN operator */ + KeyInfo *pKeyInfo = 0; /* Key information */ if( rMayHaveNull ){ sqlite3VdbeAddOp2(v, OP_Null, 0, rMayHaveNull); @@ -1719,9 +1718,7 @@ int sqlite3CodeSubselect( pExpr->iTable = pParse->nTab++; addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pExpr->iTable, !isRowid); if( rMayHaveNull==0 ) sqlite3VdbeChangeP5(v, BTREE_UNORDERED); - memset(&keyInfo, 0, sizeof(keyInfo)); - keyInfo.nField = 1; - keyInfo.aSortOrder = &sortOrder; + pKeyInfo = isRowid ? 0 : sqlite3KeyInfoAlloc(pParse->db, 1); if( ExprHasProperty(pExpr, EP_xIsSelect) ){ /* Case 1: expr IN (SELECT ...) @@ -1738,11 +1735,12 @@ int sqlite3CodeSubselect( assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable ); pExpr->x.pSelect->iLimit = 0; if( sqlite3Select(pParse, pExpr->x.pSelect, &dest) ){ + sqlite3DbFree(pParse->db, pKeyInfo); return 0; } pEList = pExpr->x.pSelect->pEList; - if( ALWAYS(pEList!=0 && pEList->nExpr>0) ){ - keyInfo.aColl[0] = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft, + if( pKeyInfo && ALWAYS(pEList!=0 && pEList->nExpr>0) ){ + pKeyInfo->aColl[0] = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft, pEList->a[0].pExpr); } }else if( ALWAYS(pExpr->x.pList!=0) ){ @@ -1761,8 +1759,9 @@ int sqlite3CodeSubselect( if( !affinity ){ affinity = SQLITE_AFF_NONE; } - keyInfo.aColl[0] = sqlite3ExprCollSeq(pParse, pExpr->pLeft); - keyInfo.aSortOrder = &sortOrder; + if( pKeyInfo ){ + pKeyInfo->aColl[0] = sqlite3ExprCollSeq(pParse, pExpr->pLeft); + } /* Loop through each expression in . */ r1 = sqlite3GetTempReg(pParse); @@ -1801,8 +1800,8 @@ int sqlite3CodeSubselect( sqlite3ReleaseTempReg(pParse, r1); sqlite3ReleaseTempReg(pParse, r2); } - if( !isRowid ){ - sqlite3VdbeChangeP4(v, addr, (void *)&keyInfo, P4_KEYINFO); + if( pKeyInfo ){ + sqlite3VdbeChangeP4(v, addr, (void *)pKeyInfo, P4_KEYINFO_HANDOFF); } break; } diff --git a/src/select.c b/src/select.c index 014feca8f2..bd7f54372e 100644 --- a/src/select.c +++ b/src/select.c @@ -802,6 +802,25 @@ static void selectInnerLoop( } } +/* +** Allocate a KeyInfo object sufficient for an index of N columns. +** +** Actually, always allocate one extra column for the rowid at the end +** of the index. So the KeyInfo returned will have space sufficient for +** N+1 columns. +*/ +KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *db, int N){ + KeyInfo *p = sqlite3DbMallocZero(db, + sizeof(KeyInfo) + (N+1)*(sizeof(CollSeq*)+1)); + if( p ){ + p->aSortOrder = (u8*)&p->aColl[N+1]; + p->nField = (u16)N; + p->enc = ENC(db); + p->db = db; + } + return p; +} + /* ** Given an expression list, generate a KeyInfo structure that records ** the collating sequence for each expression in that expression list. @@ -818,25 +837,19 @@ static void selectInnerLoop( ** P4_KEYINFO_HANDOFF is the usual way of dealing with this. */ static KeyInfo *keyInfoFromExprList(Parse *pParse, ExprList *pList){ - sqlite3 *db = pParse->db; int nExpr; KeyInfo *pInfo; struct ExprList_item *pItem; + sqlite3 *db = pParse->db; int i; nExpr = pList->nExpr; - pInfo = sqlite3DbMallocZero(db, sizeof(*pInfo) + nExpr*(sizeof(CollSeq*)+1) ); + pInfo = sqlite3KeyInfoAlloc(db, nExpr); if( pInfo ){ - pInfo->aSortOrder = (u8*)&pInfo->aColl[nExpr]; - pInfo->nField = (u16)nExpr; - pInfo->enc = ENC(db); - pInfo->db = db; for(i=0, pItem=pList->a; ipExpr); - if( !pColl ){ - pColl = db->pDfltColl; - } + if( !pColl ) pColl = db->pDfltColl; pInfo->aColl[i] = pColl; pInfo->aSortOrder[i] = pItem->sortOrder; } @@ -1942,23 +1955,17 @@ static int multiSelect( assert( p->pRightmost==p ); nCol = p->pEList->nExpr; - pKeyInfo = sqlite3DbMallocZero(db, - sizeof(*pKeyInfo)+nCol*(sizeof(CollSeq*) + 1)); + pKeyInfo = sqlite3KeyInfoAlloc(db, nCol); if( !pKeyInfo ){ rc = SQLITE_NOMEM; goto multi_select_end; } - - pKeyInfo->enc = ENC(db); - pKeyInfo->nField = (u16)nCol; - for(i=0, apColl=pKeyInfo->aColl; ipDfltColl; } } - pKeyInfo->aSortOrder = (u8*)apColl; for(pLoop=p; pLoop; pLoop=pLoop->pPrior){ for(i=0; i<2; i++){ @@ -2327,12 +2334,8 @@ static int multiSelectOrderBy( assert( pItem->iOrderByCol>0 && pItem->iOrderByCol<=p->pEList->nExpr ); aPermute[i] = pItem->iOrderByCol - 1; } - pKeyMerge = - sqlite3DbMallocRaw(db, sizeof(*pKeyMerge)+nOrderBy*(sizeof(CollSeq*)+1)); + pKeyMerge = sqlite3KeyInfoAlloc(db, nOrderBy); if( pKeyMerge ){ - pKeyMerge->aSortOrder = (u8*)&pKeyMerge->aColl[nOrderBy]; - pKeyMerge->nField = (u16)nOrderBy; - pKeyMerge->enc = ENC(db); for(i=0; ia[i].pExpr; @@ -2369,12 +2372,8 @@ static int multiSelectOrderBy( regPrev = pParse->nMem+1; pParse->nMem += nExpr+1; sqlite3VdbeAddOp2(v, OP_Integer, 0, regPrev); - pKeyDup = sqlite3DbMallocZero(db, - sizeof(*pKeyDup) + nExpr*(sizeof(CollSeq*)+1) ); + pKeyDup = sqlite3KeyInfoAlloc(db, nExpr); if( pKeyDup ){ - pKeyDup->aSortOrder = (u8*)&pKeyDup->aColl[nExpr]; - pKeyDup->nField = (u16)nExpr; - pKeyDup->enc = ENC(db); for(i=0; iaColl[i] = multiSelectCollSeq(pParse, p, i); pKeyDup->aSortOrder[i] = 0; diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 291957db9e..7a4983ad5d 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1464,12 +1464,16 @@ struct FKey { ** An instance of the following structure is passed as the first ** argument to sqlite3VdbeKeyCompare and is used to control the ** comparison of the two index keys. +** +** Note that aSortOrder[] and aColl[] have nField+1 slots. There +** are nField slots for the columns of an index then one extra slot +** for the rowid at the end. */ struct KeyInfo { sqlite3 *db; /* The database connection */ u8 enc; /* Text encoding - one of the SQLITE_UTF* values */ - u16 nField; /* Number of entries in aColl[] */ - u8 *aSortOrder; /* Sort order for each column. May be NULL */ + u16 nField; /* Maximum index for aColl[] and aSortOrder[] */ + u8 *aSortOrder; /* Sort order for each column. */ CollSeq *aColl[1]; /* Collating sequence for each term of the key */ }; @@ -3086,6 +3090,7 @@ void sqlite3MinimumFileFormat(Parse*, int, int); void sqlite3SchemaClear(void *); Schema *sqlite3SchemaGet(sqlite3 *, Btree *); int sqlite3SchemaToIndex(sqlite3 *db, Schema *); +KeyInfo *sqlite3KeyInfoAlloc(sqlite3*,int); KeyInfo *sqlite3IndexKeyinfo(Parse *, Index *); int sqlite3CreateFunc(sqlite3 *, const char *, int, int, void *, void (*)(sqlite3_context*,int,sqlite3_value **), diff --git a/src/vdbe.c b/src/vdbe.c index 4752c1a882..1f575c779d 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -555,7 +555,7 @@ int sqlite3VdbeExec( int iCompare = 0; /* Result of last OP_Compare operation */ unsigned nVmStep = 0; /* Number of virtual machine steps */ #ifndef SQLITE_OMIT_PROGRESS_CALLBACK - unsigned nProgressLimit; /* Invoke xProgress() when nVmStep reaches this */ + unsigned nProgressLimit = 0;/* Invoke xProgress() when nVmStep reaches this */ #endif Mem *aMem = p->aMem; /* Copy of p->aMem */ Mem *pIn1 = 0; /* 1st input operand */ diff --git a/src/vdbeaux.c b/src/vdbeaux.c index de2de6a7f8..2e2ba5d00d 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -729,20 +729,13 @@ void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int n){ pOp->p4.p = 0; pOp->p4type = P4_NOTUSED; }else if( n==P4_KEYINFO ){ - KeyInfo *pKeyInfo; - int nField, nByte; + KeyInfo *pOrig, *pNew; - nField = ((KeyInfo*)zP4)->nField; - nByte = sizeof(*pKeyInfo) + (nField-1)*sizeof(pKeyInfo->aColl[0]) + nField; - pKeyInfo = sqlite3DbMallocRaw(0, nByte); - pOp->p4.pKeyInfo = pKeyInfo; - if( pKeyInfo ){ - u8 *aSortOrder; - memcpy((char*)pKeyInfo, zP4, nByte - nField); - aSortOrder = pKeyInfo->aSortOrder; - assert( aSortOrder!=0 ); - pKeyInfo->aSortOrder = (unsigned char*)&pKeyInfo->aColl[nField]; - memcpy(pKeyInfo->aSortOrder, aSortOrder, nField); + pOrig = (KeyInfo*)zP4; + pOp->p4.pKeyInfo = pNew = sqlite3KeyInfoAlloc(db, pOrig->nField); + if( pNew ){ + memcpy(pNew->aColl, pOrig->aColl, pOrig->nField*sizeof(pNew->aColl[0])); + memcpy(pNew->aSortOrder, pOrig->aSortOrder, pOrig->nField); pOp->p4type = P4_KEYINFO; }else{ p->db->mallocFailed = 1; @@ -2993,7 +2986,6 @@ int sqlite3VdbeRecordCompare( u32 idx1; /* Offset into aKey[] of next header element */ u32 szHdr1; /* Number of bytes in header */ int i = 0; - int nField; int rc = 0; const unsigned char *aKey1 = (const unsigned char *)pKey1; KeyInfo *pKeyInfo; @@ -3016,7 +3008,7 @@ int sqlite3VdbeRecordCompare( idx1 = getVarint32(aKey1, szHdr1); d1 = szHdr1; - nField = pKeyInfo->nField; + assert( pKeyInfo->nField+1>=pPKey2->nField ); assert( pKeyInfo->aSortOrder!=0 ); while( idx1nField ){ u32 serial_type1; @@ -3042,13 +3034,12 @@ int sqlite3VdbeRecordCompare( /* Do the comparison */ - rc = sqlite3MemCompare(&mem1, &pPKey2->aMem[i], - iaColl[i] : 0); + rc = sqlite3MemCompare(&mem1, &pPKey2->aMem[i], pKeyInfo->aColl[i]); if( rc!=0 ){ assert( mem1.zMalloc==0 ); /* See comment below */ /* Invert the result if we are using DESC sort order. */ - if( iaSortOrder[i] ){ + if( pKeyInfo->aSortOrder[i] ){ rc = -rc; }