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
This commit is contained in:
parent
af5b2af77d
commit
323df7907e
22
manifest
22
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
|
||||
|
@ -1 +1 @@
|
||||
28979dcd16f53e0ddca8eed74b668834e2856f03
|
||||
7301bedd94c8610568349953b18ff3575203e1b2
|
11
src/build.c
11
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; i<nCol; i++){
|
||||
char *zColl = pIdx->azColl[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;
|
||||
|
21
src/expr.c
21
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 <exprlist>. */
|
||||
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;
|
||||
}
|
||||
|
51
src/select.c
51
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; i<nExpr; i++, pItem++){
|
||||
CollSeq *pColl;
|
||||
pColl = sqlite3ExprCollSeq(pParse, pItem->pExpr);
|
||||
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; i<nCol; i++, apColl++){
|
||||
*apColl = multiSelectCollSeq(pParse, p, i);
|
||||
if( 0==*apColl ){
|
||||
*apColl = db->pDfltColl;
|
||||
}
|
||||
}
|
||||
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; i<nOrderBy; i++){
|
||||
CollSeq *pColl;
|
||||
Expr *pTerm = pOrderBy->a[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; i<nExpr; i++){
|
||||
pKeyDup->aColl[i] = multiSelectCollSeq(pParse, p, i);
|
||||
pKeyDup->aSortOrder[i] = 0;
|
||||
|
@ -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 **),
|
||||
|
@ -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 */
|
||||
|
@ -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( idx1<szHdr1 && i<pPKey2->nField ){
|
||||
u32 serial_type1;
|
||||
@ -3042,13 +3034,12 @@ int sqlite3VdbeRecordCompare(
|
||||
|
||||
/* Do the comparison
|
||||
*/
|
||||
rc = sqlite3MemCompare(&mem1, &pPKey2->aMem[i],
|
||||
i<nField ? pKeyInfo->aColl[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( i<nField && pKeyInfo->aSortOrder[i] ){
|
||||
if( pKeyInfo->aSortOrder[i] ){
|
||||
rc = -rc;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user