mirror of
https://github.com/sqlite/sqlite.git
synced 2025-11-06 15:49:35 +03:00
If a binary operator in a WHERE clause that should be performed with no affinity conversions applied to its operands (see http://www.sqlite.org/datatype3.html) is optimized by index lookup, do not apply any conversions to the key value before looking it up in the index. Fix for 93fb9f89d6.
FossilOrigin-Name: e72186f2d68d28c2e0c32894f9adb28c155b5f63
This commit is contained in:
30
manifest
30
manifest
@@ -1,8 +1,5 @@
|
||||
-----BEGIN PGP SIGNED MESSAGE-----
|
||||
Hash: SHA1
|
||||
|
||||
C Enhancements\sto\sthe\swhereB.test\sto\scheck\smore\saffinity\scorner\scases.
|
||||
D 2009-08-13T18:14:32
|
||||
C If\sa\sbinary\soperator\sin\sa\sWHERE\sclause\sthat\sshould\sbe\sperformed\swith\sno\saffinity\sconversions\sapplied\sto\sits\soperands\s(see\shttp://www.sqlite.org/datatype3.html)\sis\soptimized\sby\sindex\slookup,\sdo\snot\sapply\sany\sconversions\sto\sthe\skey\svalue\sbefore\slooking\sit\sup\sin\sthe\sindex.\sFix\sfor\s93fb9f89d6.
|
||||
D 2009-08-13T19:21:17
|
||||
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
|
||||
F Makefile.in c606c9b502dfde3b9c3b2d23ed49f3737829693b
|
||||
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
||||
@@ -116,7 +113,7 @@ F src/build.c a15de7c5d020a778b641fca0b2510126843f4b30
|
||||
F src/callback.c cb68b21b0d4ae7d11ae0e487933bce3323784dcf
|
||||
F src/complete.c 5ad5c6cd4548211867c204c41a126d73a9fbcea0
|
||||
F src/date.c ab5f7137656652a48434d64f96bdcdc823bb23b3
|
||||
F src/delete.c f1502d3c210f80eebef475a04891e8ea80099553
|
||||
F src/delete.c dcf07632d8ca3d4086df8b65ea907a47278e6382
|
||||
F src/expr.c d069ba1e060f296ea4f18fb85198fafefd00b22f
|
||||
F src/fault.c dc88c821842157460750d2d61a8a8b4197d047ff
|
||||
F src/func.c 9856373f5315f6b8690d7f07f7191aa9f279ca87
|
||||
@@ -124,7 +121,7 @@ F src/global.c 448419c44ce0701104c2121b0e06919b44514c0c
|
||||
F src/hash.c ebcaa921ffd9d86f7ea5ae16a0a29d1c871130a7
|
||||
F src/hash.h 35b216c13343d0b4f87d9f21969ac55ad72174e1
|
||||
F src/hwtime.h 4a1d45f4cae1f402ea19686acf24acf4f0cb53cb
|
||||
F src/insert.c a4bbd811a15f8b24a311753da947d61368685db1
|
||||
F src/insert.c 95625f99f377a9ef264c289407173b722c7af6e8
|
||||
F src/journal.c e00df0c0da8413ab6e1bb7d7cab5665d4a9000d0
|
||||
F src/legacy.c 303b4ffcf1ae652fcf5ef635846c563c254564f6
|
||||
F src/lempar.c 0c4d1ab0a5ef2b0381eb81a732c54f68f27a574d
|
||||
@@ -166,7 +163,7 @@ F src/select.c 67b0778c9585905c8aa75aaa469e76ef3c1d315a
|
||||
F src/shell.c db2643650b9268df89a4bedca3f1c6d9e786f1bb
|
||||
F src/sqlite.h.in eb42257503a48f6f12ff0b23a81067ba9b5ac1eb
|
||||
F src/sqlite3ext.h 1db7d63ab5de4b3e6b83dd03d1a4e64fef6d2a17
|
||||
F src/sqliteInt.h 6337542c0eb0e6521991b29f59c8bcbdfda222e7
|
||||
F src/sqliteInt.h 6a90791138ba3447572d184d0798c24f3cbbec98
|
||||
F src/sqliteLimit.h ffe93f5a0c4e7bd13e70cd7bf84cfb5c3465f45d
|
||||
F src/status.c 237b193efae0cf6ac3f0817a208de6c6c6ef6d76
|
||||
F src/table.c cc86ad3d6ad54df7c63a3e807b5783c90411a08d
|
||||
@@ -216,7 +213,7 @@ F src/vdbeblob.c a3f3e0e877fc64ea50165eec2855f5ada4477611
|
||||
F src/vdbemem.c 364cfce843926224f917ab89ee476be958c864ed
|
||||
F src/vtab.c aedd76e8670d5a5379f93804398d3ba960125547
|
||||
F src/walker.c 1edca756275f158b80f20eb6f104c8d3fcc96a04
|
||||
F src/where.c 53adef2c7b8bc888755cf41fb3449aedb36a429c
|
||||
F src/where.c 7573120c1f2fe6d4c246f138f1e30fbcda3db241
|
||||
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
||||
F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
|
||||
F test/all.test 14165b3e32715b700b5f0cbf8f6e3833dda0be45
|
||||
@@ -746,14 +743,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
|
||||
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
|
||||
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
||||
F tool/vdbe-compress.tcl 672f81d693a03f80f5ae60bfefacd8a349e76746
|
||||
P 149ec24e61437fac2b0dd6239276d3aa543c56cb
|
||||
R 1ea36fc2c7e0c32d5b2483eec1ce1a06
|
||||
U drh
|
||||
Z cdd6f1e89b3618add099c3116553394a
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
Version: GnuPG v1.4.6 (GNU/Linux)
|
||||
|
||||
iD8DBQFKhFgLoxKgR168RlERAgjMAJ0e/xokwSjX2hsY3q8mvlUGu+555wCfZL+Z
|
||||
ThH1uVO4nfptbHxSFohZy1U=
|
||||
=PHPU
|
||||
-----END PGP SIGNATURE-----
|
||||
P 1048459824746307c9e4296cbc21716bf8b5449d
|
||||
R 9cf12527faa6d7b7304f1183ac06fe71
|
||||
U dan
|
||||
Z 0b088089cd7635bacda9499fff4849b7
|
||||
|
||||
@@ -1 +1 @@
|
||||
1048459824746307c9e4296cbc21716bf8b5449d
|
||||
e72186f2d68d28c2e0c32894f9adb28c155b5f63
|
||||
@@ -622,7 +622,7 @@ int sqlite3GenerateIndexKey(
|
||||
}
|
||||
if( doMakeRec ){
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol+1, regOut);
|
||||
sqlite3IndexAffinityStr(v, pIdx);
|
||||
sqlite3VdbeChangeP4(v, -1, sqlite3IndexAffinityStr(v, pIdx), 0);
|
||||
sqlite3ExprCacheAffinityChange(pParse, regBase, nCol+1);
|
||||
}
|
||||
sqlite3ReleaseTempRange(pParse, regBase, nCol+1);
|
||||
|
||||
18
src/insert.c
18
src/insert.c
@@ -37,9 +37,9 @@ void sqlite3OpenTable(
|
||||
}
|
||||
|
||||
/*
|
||||
** Set P4 of the most recently inserted opcode to a column affinity
|
||||
** string for index pIdx. A column affinity string has one character
|
||||
** for each column in the table, according to the affinity of the column:
|
||||
** Return a pointer to the column affinity string associated with index
|
||||
** pIdx. A column affinity string has one character for each column in
|
||||
** the table, according to the affinity of the column:
|
||||
**
|
||||
** Character Column affinity
|
||||
** ------------------------------
|
||||
@@ -51,8 +51,12 @@ void sqlite3OpenTable(
|
||||
**
|
||||
** An extra 'b' is appended to the end of the string to cover the
|
||||
** rowid that appears as the last column in every index.
|
||||
**
|
||||
** Memory for the buffer containing the column index affinity string
|
||||
** is managed along with the rest of the Index structure. It will be
|
||||
** released when sqlite3DeleteIndex() is called.
|
||||
*/
|
||||
void sqlite3IndexAffinityStr(Vdbe *v, Index *pIdx){
|
||||
const char *sqlite3IndexAffinityStr(Vdbe *v, Index *pIdx){
|
||||
if( !pIdx->zColAff ){
|
||||
/* The first time a column affinity string for a particular index is
|
||||
** required, it is allocated and populated here. It is then stored as
|
||||
@@ -68,7 +72,7 @@ void sqlite3IndexAffinityStr(Vdbe *v, Index *pIdx){
|
||||
pIdx->zColAff = (char *)sqlite3Malloc(pIdx->nColumn+2);
|
||||
if( !pIdx->zColAff ){
|
||||
db->mallocFailed = 1;
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
for(n=0; n<pIdx->nColumn; n++){
|
||||
pIdx->zColAff[n] = pTab->aCol[pIdx->aiColumn[n]].affinity;
|
||||
@@ -77,7 +81,7 @@ void sqlite3IndexAffinityStr(Vdbe *v, Index *pIdx){
|
||||
pIdx->zColAff[n] = 0;
|
||||
}
|
||||
|
||||
sqlite3VdbeChangeP4(v, -1, pIdx->zColAff, 0);
|
||||
return pIdx->zColAff;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1298,7 +1302,7 @@ void sqlite3GenerateConstraintChecks(
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_SCopy, regRowid, regIdx+i);
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, regIdx, pIdx->nColumn+1, aRegIdx[iCur]);
|
||||
sqlite3IndexAffinityStr(v, pIdx);
|
||||
sqlite3VdbeChangeP4(v, -1, sqlite3IndexAffinityStr(v, pIdx), 0);
|
||||
sqlite3ExprCacheAffinityChange(pParse, regIdx, pIdx->nColumn+1);
|
||||
|
||||
/* Find out what action to take in case there is an indexing conflict */
|
||||
|
||||
@@ -2755,7 +2755,7 @@ int sqlite3VarintLen(u64 v);
|
||||
#define putVarint sqlite3PutVarint
|
||||
|
||||
|
||||
void sqlite3IndexAffinityStr(Vdbe *, Index *);
|
||||
const char *sqlite3IndexAffinityStr(Vdbe *, Index *);
|
||||
void sqlite3TableAffinityStr(Vdbe *, Table *);
|
||||
char sqlite3CompareAffinity(Expr *pExpr, char aff2);
|
||||
int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity);
|
||||
|
||||
77
src/where.c
77
src/where.c
@@ -2275,17 +2275,19 @@ static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){
|
||||
}
|
||||
|
||||
/*
|
||||
** Apply the affinities associated with the first n columns of index
|
||||
** pIdx to the values in the n registers starting at base.
|
||||
** Code an OP_Affinity opcode to apply the column affinity string zAff
|
||||
** to the n registers starting at base.
|
||||
**
|
||||
** Buffer zAff was allocated using sqlite3DbMalloc(). It is the
|
||||
** responsibility of this function to arrange for it to be eventually
|
||||
** freed using sqlite3DbFree().
|
||||
*/
|
||||
static void codeApplyAffinity(Parse *pParse, int base, int n, Index *pIdx){
|
||||
if( n>0 ){
|
||||
static void codeApplyAffinity(Parse *pParse, int base, int n, char *zAff){
|
||||
Vdbe *v = pParse->pVdbe;
|
||||
assert( v!=0 );
|
||||
sqlite3VdbeAddOp2(v, OP_Affinity, base, n);
|
||||
sqlite3IndexAffinityStr(v, pIdx);
|
||||
sqlite3VdbeChangeP4(v, -1, zAff, P4_DYNAMIC);
|
||||
sqlite3ExprCacheAffinityChange(pParse, base, n);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2376,13 +2378,29 @@ static int codeEqualityTerm(
|
||||
** key value of the loop. If one or more IN operators appear, then
|
||||
** this routine allocates an additional nEq memory cells for internal
|
||||
** use.
|
||||
**
|
||||
** Before returning, *pzAff is set to point to a buffer containing a
|
||||
** copy of the column affinity string of the index allocated using
|
||||
** sqlite3DbMalloc(). Except, entries in the copy of the string associated
|
||||
** with equality constraints that use NONE affinity are set to
|
||||
** SQLITE_AFF_NONE. This is to deal with SQL such as the following:
|
||||
**
|
||||
** CREATE TABLE t1(a TEXT PRIMARY KEY, b);
|
||||
** SELECT ... FROM t1 AS t2, t1 WHERE t1.a = t2.b;
|
||||
**
|
||||
** In the example above, the index on t1(a) has TEXT affinity. But since
|
||||
** the right hand side of the equality constraint (t2.b) has NONE affinity,
|
||||
** no conversion should be attempted before using a t2.b value as part of
|
||||
** a key to search the index. Hence the first byte in the returned affinity
|
||||
** string in this example would be set to SQLITE_AFF_NONE.
|
||||
*/
|
||||
static int codeAllEqualityTerms(
|
||||
Parse *pParse, /* Parsing context */
|
||||
WhereLevel *pLevel, /* Which nested loop of the FROM we are coding */
|
||||
WhereClause *pWC, /* The WHERE clause */
|
||||
Bitmask notReady, /* Which parts of FROM have not yet been coded */
|
||||
int nExtraReg /* Number of extra registers to allocate */
|
||||
int nExtraReg, /* Number of extra registers to allocate */
|
||||
char **pzAff /* OUT: Set to point to affinity string */
|
||||
){
|
||||
int nEq = pLevel->plan.nEq; /* The number of == or IN constraints to code */
|
||||
Vdbe *v = pParse->pVdbe; /* The vm under construction */
|
||||
@@ -2392,6 +2410,7 @@ static int codeAllEqualityTerms(
|
||||
int j; /* Loop counter */
|
||||
int regBase; /* Base register */
|
||||
int nReg; /* Number of registers to allocate */
|
||||
char *zAff; /* Affinity string to return */
|
||||
|
||||
/* This module is only called on query plans that use an index. */
|
||||
assert( pLevel->plan.wsFlags & WHERE_INDEXED );
|
||||
@@ -2403,6 +2422,11 @@ static int codeAllEqualityTerms(
|
||||
nReg = pLevel->plan.nEq + nExtraReg;
|
||||
pParse->nMem += nReg;
|
||||
|
||||
zAff = sqlite3DbStrDup(pParse->db, sqlite3IndexAffinityStr(v, pIdx));
|
||||
if( !zAff ){
|
||||
pParse->db->mallocFailed = 1;
|
||||
}
|
||||
|
||||
/* Evaluate the equality constraints
|
||||
*/
|
||||
assert( pIdx->nColumn>=nEq );
|
||||
@@ -2425,8 +2449,14 @@ static int codeAllEqualityTerms(
|
||||
testcase( pTerm->eOperator & WO_IN );
|
||||
if( (pTerm->eOperator & (WO_ISNULL|WO_IN))==0 ){
|
||||
sqlite3VdbeAddOp2(v, OP_IsNull, regBase+j, pLevel->addrBrk);
|
||||
if( zAff
|
||||
&& sqlite3CompareAffinity(pTerm->pExpr->pRight, zAff[j])==SQLITE_AFF_NONE
|
||||
){
|
||||
zAff[j] = SQLITE_AFF_NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
*pzAff = zAff;
|
||||
return regBase;
|
||||
}
|
||||
|
||||
@@ -2682,6 +2712,7 @@ static Bitmask codeOneLoopStart(
|
||||
int iIdxCur; /* The VDBE cursor for the index */
|
||||
int nExtraReg = 0; /* Number of extra registers needed */
|
||||
int op; /* Instruction opcode */
|
||||
char *zAff;
|
||||
|
||||
pIdx = pLevel->plan.u.pIdx;
|
||||
iIdxCur = pLevel->iIdxCur;
|
||||
@@ -2721,10 +2752,11 @@ static Bitmask codeOneLoopStart(
|
||||
** and store the values of those terms in an array of registers
|
||||
** starting at regBase.
|
||||
*/
|
||||
regBase = codeAllEqualityTerms(pParse, pLevel, pWC, notReady, nExtraReg);
|
||||
regBase = codeAllEqualityTerms(
|
||||
pParse, pLevel, pWC, notReady, nExtraReg, &zAff
|
||||
);
|
||||
addrNxt = pLevel->addrNxt;
|
||||
|
||||
|
||||
/* If we are doing a reverse order scan on an ascending index, or
|
||||
** a forward order scan on a descending index, interchange the
|
||||
** start and end terms (pRangeStart and pRangeEnd).
|
||||
@@ -2744,8 +2776,17 @@ static Bitmask codeOneLoopStart(
|
||||
/* Seek the index cursor to the start of the range. */
|
||||
nConstraint = nEq;
|
||||
if( pRangeStart ){
|
||||
sqlite3ExprCode(pParse, pRangeStart->pExpr->pRight, regBase+nEq);
|
||||
Expr *pRight = pRangeStart->pExpr->pRight;
|
||||
sqlite3ExprCode(pParse, pRight, regBase+nEq);
|
||||
sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, addrNxt);
|
||||
if( zAff
|
||||
&& sqlite3CompareAffinity(pRight, zAff[nConstraint])==SQLITE_AFF_NONE
|
||||
){
|
||||
/* Since the comparison is to be performed with no conversions applied
|
||||
** to the operands, set the affinity to apply to pRight to
|
||||
** SQLITE_AFF_NONE. */
|
||||
zAff[nConstraint] = SQLITE_AFF_NONE;
|
||||
}
|
||||
nConstraint++;
|
||||
}else if( isMinQuery ){
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq);
|
||||
@@ -2753,7 +2794,7 @@ static Bitmask codeOneLoopStart(
|
||||
startEq = 0;
|
||||
start_constraints = 1;
|
||||
}
|
||||
codeApplyAffinity(pParse, regBase, nConstraint, pIdx);
|
||||
codeApplyAffinity(pParse, regBase, nConstraint, zAff);
|
||||
op = aStartOp[(start_constraints<<2) + (startEq<<1) + bRev];
|
||||
assert( op!=0 );
|
||||
testcase( op==OP_Rewind );
|
||||
@@ -2770,10 +2811,20 @@ static Bitmask codeOneLoopStart(
|
||||
*/
|
||||
nConstraint = nEq;
|
||||
if( pRangeEnd ){
|
||||
Expr *pRight = pRangeEnd->pExpr->pRight;
|
||||
sqlite3ExprCacheRemove(pParse, regBase+nEq);
|
||||
sqlite3ExprCode(pParse, pRangeEnd->pExpr->pRight, regBase+nEq);
|
||||
sqlite3ExprCode(pParse, pRight, regBase+nEq);
|
||||
sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, addrNxt);
|
||||
codeApplyAffinity(pParse, regBase, nEq+1, pIdx);
|
||||
zAff = sqlite3DbStrDup(pParse->db, zAff);
|
||||
if( zAff
|
||||
&& sqlite3CompareAffinity(pRight, zAff[nConstraint])==SQLITE_AFF_NONE
|
||||
){
|
||||
/* Since the comparison is to be performed with no conversions applied
|
||||
** to the operands, set the affinity to apply to pRight to
|
||||
** SQLITE_AFF_NONE. */
|
||||
zAff[nConstraint] = SQLITE_AFF_NONE;
|
||||
}
|
||||
codeApplyAffinity(pParse, regBase, nEq+1, zAff);
|
||||
nConstraint++;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user