From: danielk1977 Date: Fri, 18 Apr 2008 10:25:24 +0000 (+0000) Subject: Combine cases 3 and 4 in where.c, since case 4 is now a special case of case 3. ... X-Git-Tag: version-3.6.10~1148 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b790c6c596feaa8e47043ed0cf7a30f10aac0dd5;p=thirdparty%2Fsqlite.git Combine cases 3 and 4 in where.c, since case 4 is now a special case of case 3. (CVS 5029) FossilOrigin-Name: 9a976819246eb558ba43429f8889972c4a4bce9d --- diff --git a/manifest b/manifest index 5a456e3c1a..5f4675a8a5 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Allow\sOP_MoveGt\sand\ssimilar\sto\suse\san\sarray\sof\sregisters\sinstead\sof\sa\sserialized\srecord.\sModify\sone\stype\sof\sindex\srange\sscan\sto\suse\sthis.\s(CVS\s5028) -D 2008-04-18T09:01:16 +C Combine\scases\s3\sand\s4\sin\swhere.c,\ssince\scase\s4\sis\snow\sa\sspecial\scase\sof\scase\s3.\s(CVS\s5029) +D 2008-04-18T10:25:24 F Makefile.arm-wince-mingw32ce-gcc ac5f7b2cef0cd850d6f755ba6ee4ab961b1fadf7 F Makefile.in 25b3282a4ac39388632c2fb0e044ff494d490952 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -174,7 +174,7 @@ F src/update.c 57282dae1ffffaf4aedc3201ed77f8ef09be4f45 F src/utf.c 8c94fa10efc78c2568d08d436acc59df4df7191b F src/util.c 943caa4071488b20ed90588f0704c6825f91836b F src/vacuum.c 3524411bfb58aac0d87eadd3e5b7cd532772af30 -F src/vdbe.c 6b3a2273255d7527f17a2f4c123bcaa02969ddc0 +F src/vdbe.c 892a871879c80a905eaa0d1f7bd24e0221bad56d F src/vdbe.h bfd84bda447f39cb599302c7ec85067dae20453c F src/vdbeInt.h 05316345da487b0cf540482576f9ae3337d133cd F src/vdbeapi.c 0e1b5a808bb0e556f2a975eb7d11fd3153e922bf @@ -183,7 +183,7 @@ F src/vdbeblob.c cc713c142c3d4952b380c98ee035f850830ddbdb F src/vdbefifo.c a30c237b2a3577e1415fb6e288cbb6b8ed1e5736 F src/vdbemem.c 237e61216381998ff71c6431e5e7bd03386f6225 F src/vtab.c f5e78bf73df3b0c1b53861109c1b2e0800b108cc -F src/where.c e6850aa2fbe655c15914e9b102a20abf2834ab89 +F src/where.c 011f866cf0f05c832eea5a30e079eb108253ac64 F tclinstaller.tcl 4356d9d94d2b5ed5e68f9f0c80c4df3048dd7617 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/all.test d56a3ca8acdf761204aff0a2e7aa5eb8e11b31e6 @@ -631,7 +631,7 @@ F www/tclsqlite.tcl 8be95ee6dba05eabcd27a9d91331c803f2ce2130 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5 -P 4a72a7bb9c5793cdaf4ee038482053e042d8db54 -R 63ab958aeb1a64fb1b489284d8bf24a2 +P c448f15aa5ed3dec511426775e893efea324faa1 +R 2fd8586df4700418bc96607c52d60fc1 U danielk1977 -Z ffb6897ecd3dcda79af541b97309bd4b +Z 63b2d6660f8e65e3dba8e17623deefd8 diff --git a/manifest.uuid b/manifest.uuid index 83af5c671c..eb2840abdf 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c448f15aa5ed3dec511426775e893efea324faa1 \ No newline at end of file +9a976819246eb558ba43429f8889972c4a4bce9d \ No newline at end of file diff --git a/src/vdbe.c b/src/vdbe.c index 16cd578b7a..62a8c1a432 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -43,7 +43,7 @@ ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. ** -** $Id: vdbe.c,v 1.731 2008/04/18 09:01:16 danielk1977 Exp $ +** $Id: vdbe.c,v 1.732 2008/04/18 10:25:24 danielk1977 Exp $ */ #include "sqliteInt.h" #include @@ -2148,6 +2148,7 @@ case OP_Affinity: { Mem *pRec; for(pRec=pData0; pRec<=pLast; pRec++){ + ExpandBlob(pRec); applyAffinity(pRec, zAffinity[pRec-pData0], encoding); } break; @@ -2790,13 +2791,16 @@ case OP_Close: { break; } -/* Opcode: MoveGe P1 P2 P3 * * +/* Opcode: MoveGe P1 P2 P3 P4 * ** -** Use the value in register P3 as a key. Reposition -** cursor P1 so that it points to the smallest entry that is greater -** than or equal to the key in register P3. -** If there are no records greater than or equal to the key and P2 -** is not zero, then jump to P2. +** If cursor P1 refers to an SQL table (B-Tree that uses integer keys), +** use the integer value in register P3 as a key. If cursor P1 refers +** to an SQL index, then P3 is the first in an array of P4 registers +** that are used as an unpacked index key. +** +** Reposition cursor P1 so that it points to the smallest entry that +** is greater than or equal to the key value. If there are no records +** greater than or equal to the key and P2 is not zero, then jump to P2. ** ** A special feature of this opcode (and different from the ** related OP_MoveGt, OP_MoveLt, and OP_MoveLe) is that if P2 is @@ -2807,37 +2811,42 @@ case OP_Close: { ** ** See also: Found, NotFound, Distinct, MoveLt, MoveGt, MoveLe */ -/* Opcode: MoveGt P1 P2 P3 * * +/* Opcode: MoveGt P1 P2 P3 P4 * +** +** If cursor P1 refers to an SQL table (B-Tree that uses integer keys), +** use the integer value in register P3 as a key. If cursor P1 refers +** to an SQL index, then P3 is the first in an array of P4 registers +** that are used as an unpacked index key. ** -** Use the value in register P3 as a key. Reposition -** cursor P1 so that it points to the smallest entry that is greater -** than the key in register P3. -** If there are no records greater than the key -** then jump to P2. +** Reposition cursor P1 so that it points to the smallest entry that +** is greater than the key value. If there are no records greater than +** the key and P2 is not zero, then jump to P2. ** ** See also: Found, NotFound, Distinct, MoveLt, MoveGe, MoveLe */ -/* Opcode: MoveLt P1 P2 P3 * * +/* Opcode: MoveLt P1 P2 P3 P4 * +** +** If cursor P1 refers to an SQL table (B-Tree that uses integer keys), +** use the integer value in register P3 as a key. If cursor P1 refers +** to an SQL index, then P3 is the first in an array of P4 registers +** that are used as an unpacked index key. ** -** Use the value in register P3 as a key. Reposition -** cursor P1 so that it points to the largest entry that is less -** than the key in register P3. -** If there are no records less than the key -** then jump to P2. +** Reposition cursor P1 so that it points to the largest entry that +** is less than the key value. If there are no records less than +** the key and P2 is not zero, then jump to P2. ** ** See also: Found, NotFound, Distinct, MoveGt, MoveGe, MoveLe */ /* Opcode: MoveLe P1 P2 P3 P4 * ** -** P4 is always an integer value. If it is zero, then use the value in -** register P3 as a key. Reposition cursor P1 so that it points to the -** largest entry that is less than or equal to the key. If there are no -** records less than or eqal to the key then jump to P2. +** If cursor P1 refers to an SQL table (B-Tree that uses integer keys), +** use the integer value in register P3 as a key. If cursor P1 refers +** to an SQL index, then P3 is the first in an array of P4 registers +** that are used as an unpacked index key. ** -** If the integer value in operand P4 is non-zero, then P3 is the first -** of a contiguous array of P4 memory cells that form an unpacked index -** key. In this case the unpacked key is used instead of the value of -** register P3 in the procedure described above. +** Reposition cursor P1 so that it points to the largest entry that +** is less than or equal to the key value. If there are no records +** less than or equal to the key and P2 is not zero, then jump to P2. ** ** See also: Found, NotFound, Distinct, MoveGt, MoveGe, MoveLt */ @@ -2872,20 +2881,16 @@ case OP_MoveGt: { /* jump, in3 */ pC->lastRowid = iKey; pC->rowidIsValid = res==0; }else{ - int nField = ((pOp->p4type==P4_INT32)?pOp->p4.i:0); - assert( pIn3->flags&MEM_Blob || nField>0 ); - if( nField==0 ){ - ExpandBlob(pIn3); - rc = sqlite3BtreeMoveto(pC->pCursor, pIn3->z, 0, pIn3->n, 0, &res); - }else{ - UnpackedRecord r; - r.pKeyInfo = pC->pKeyInfo; - r.nField = nField; - r.needFree = 0; - r.needDestroy = 0; - r.aMem = &p->aMem[pOp->p3]; - rc = sqlite3BtreeMoveto(pC->pCursor, 0, &r, 0, 0, &res); - } + UnpackedRecord r; + int nField = pOp->p4.i; + assert( pOp->p4type==P4_INT32 ); + assert( nField>0 ); + r.pKeyInfo = pC->pKeyInfo; + r.nField = nField; + r.needFree = 0; + r.needDestroy = 0; + r.aMem = &p->aMem[pOp->p3]; + rc = sqlite3BtreeMoveto(pC->pCursor, 0, &r, 0, 0, &res); if( rc!=SQLITE_OK ){ goto abort_due_to_error; } diff --git a/src/where.c b/src/where.c index 0ccc601663..5bce2262ee 100644 --- a/src/where.c +++ b/src/where.c @@ -16,7 +16,7 @@ ** so is applicable. Because this module is responsible for selecting ** indices, you might also think of this module as the "query optimizer". ** -** $Id: where.c,v 1.300 2008/04/18 09:01:16 danielk1977 Exp $ +** $Id: where.c,v 1.301 2008/04/18 10:25:24 danielk1977 Exp $ */ #include "sqliteInt.h" @@ -1727,27 +1727,17 @@ static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){ } /* -** Generate code that builds a probe for an index. -** -** There should be nColumn values on the stack. The index -** to be probed is pIdx. Pop the values from the stack and -** replace them all with a single record that is the index -** problem. +** Apply the affinities associated with the first n columns of index +** pIdx to the values in the n registers starting at base. */ -static void buildIndexProbe( - Parse *pParse, /* Parsing and code generation context */ - int nColumn, /* The number of columns to check for NULL */ - Index *pIdx, /* Index that we will be searching */ - int regSrc, /* Take values from this register */ - int regDest /* Write the result into this register */ -){ - Vdbe *v = pParse->pVdbe; - assert( regSrc>0 ); - assert( regDest>0 ); - assert( v!=0 ); - sqlite3VdbeAddOp3(v, OP_MakeRecord, regSrc, nColumn, regDest); - sqlite3IndexAffinityStr(v, pIdx); - sqlite3ExprCacheAffinityChange(pParse, regSrc, nColumn); +static void codeApplyAffinity(Parse *pParse, int base, int n, Index *pIdx){ + if( n>0 ){ + Vdbe *v = pParse->pVdbe; + assert( v!=0 ); + sqlite3VdbeAddOp2(v, OP_Affinity, base, n); + sqlite3IndexAffinityStr(v, pIdx); + sqlite3ExprCacheAffinityChange(pParse, base, n); + } } @@ -2463,30 +2453,45 @@ WhereInfo *sqlite3WhereBegin( sqlite3VdbeChangeP5(v, SQLITE_AFF_NUMERIC | SQLITE_JUMPIFNULL); sqlite3ReleaseTempReg(pParse, r1); } - }else if( pLevel->flags & WHERE_COLUMN_RANGE ){ - /* Case 3: The WHERE clause term that refers to the right-most - ** column of the index is an inequality. For example, if - ** the index is on (x,y,z) and the WHERE clause is of the - ** form "x=5 AND y<10" then this case is used. Only the - ** right-most column can be an inequality - the rest must - ** use the "==" and "IN" operators. + }else if( pLevel->flags & (WHERE_COLUMN_RANGE|WHERE_COLUMN_EQ) ){ + /* Case 3: A scan using an index. + ** + ** The WHERE clause may contain one or more equality + ** terms ("==" or "IN" operators) that refer to the N + ** left-most columns of the index. It may also contain + ** inequality constraints (>, <, >= or <=) on the indexed + ** column that immediately follows the N equalities. Only + ** the right-most column can be an inequality - the rest must + ** use the "==" and "IN" operators. For example, if the + ** index is on (x,y,z), then the following clauses are all + ** optimized: + ** + ** x=5 + ** x=5 AND y=10 + ** x=5 AND y<10 + ** x=5 AND y>5 AND y<10 + ** x=5 AND y=5 AND z<=10 + ** + ** This cannot be optimized: + ** + ** x=5 AND z<10 ** ** This case is also used when there are no WHERE clause ** constraints but an index is selected anyway, in order ** to force the output order to conform to an ORDER BY. - */ + */ int aStartOp[] = { 0, 0, - OP_Rewind, /* 2: (!start_constraints && startEq && !bRev) */ - OP_Last, /* 3: (!start_constraints && startEq && bRev) */ + OP_Rewind, /* 2: (!start_constraints && startEq && !bRev) */ + OP_Last, /* 3: (!start_constraints && startEq && bRev) */ OP_MoveGt, /* 4: (start_constraints && !startEq && !bRev) */ - OP_MoveLt, /* 5: (start_constraints && !startEq && bRev) */ + OP_MoveLt, /* 5: (start_constraints && !startEq && bRev) */ OP_MoveGe, /* 6: (start_constraints && startEq && !bRev) */ - OP_MoveLe /* 7: (start_constraints && startEq && bRev) */ + OP_MoveLe /* 7: (start_constraints && startEq && bRev) */ }; int aEndOp[] = { - OP_Noop, /* 0: () */ + OP_Noop, /* 0: (!end_constraints) */ OP_IdxGE, /* 1: (end_constraints && !bRev) */ OP_IdxLT /* 2: (end_constraints && bRev) */ }; @@ -2526,7 +2531,7 @@ WhereInfo *sqlite3WhereBegin( isMinQuery = 1; } - /* Find the inequality constraint terms for the start and end + /* Find any inequality constraint terms for the start and end ** of the range. */ if( pLevel->flags & WHERE_TOP_LIMIT ){ @@ -2565,8 +2570,7 @@ WhereInfo *sqlite3WhereBegin( startEq = 0; start_constraints = 1; } - sqlite3VdbeAddOp2(v, OP_Affinity, regBase, (int)ptr); - sqlite3IndexAffinityStr(v, pIdx); + codeApplyAffinity(pParse, regBase, (int)ptr, pIdx); op = aStartOp[(start_constraints<<2) + (startEq<<1) + bRev]; sqlite3VdbeAddOp4(v, op, iIdxCur, nxt, regBase, ptr, P4_INT32); @@ -2577,10 +2581,9 @@ WhereInfo *sqlite3WhereBegin( if( pRangeEnd ){ sqlite3ExprCode(pParse, pRangeEnd->pExpr->pRight, regBase+nEq); sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, nxt); + codeApplyAffinity(pParse, regBase, nEq+1, pIdx); ptr++; } - sqlite3VdbeAddOp2(v, OP_Affinity, regBase, (int)ptr); - sqlite3IndexAffinityStr(v, pIdx); /* Top of the loop body */ pLevel->p2 = sqlite3VdbeCurrentAddr(v); @@ -2615,77 +2618,6 @@ WhereInfo *sqlite3WhereBegin( pLevel->p1 = iIdxCur; disableTerm(pLevel, pRangeStart); disableTerm(pLevel, pRangeEnd); - }else if( pLevel->flags & WHERE_COLUMN_EQ ){ - /* Case 4: There is an index and all terms of the WHERE clause that - ** refer to the index using the "==" or "IN" operators. - */ - int start; - int nEq = pLevel->nEq; - int isMinQuery = 0; /* If this is an optimized SELECT min(x) ... */ - int regBase; /* Base register of array holding constraints */ - int r1; - - /* Generate code to evaluate all constraint terms using == or IN - ** and leave the values of those terms on the stack. - */ - regBase = codeAllEqualityTerms(pParse, pLevel, &wc, notReady, 1); - nxt = pLevel->nxt; - - if( (wflags&WHERE_ORDERBY_MIN)!=0 - && (pLevel->flags&WHERE_ORDERBY) - && (pIdx->nColumn>nEq) - && (pOrderBy->a[0].pExpr->iColumn==pIdx->aiColumn[nEq]) - ){ - isMinQuery = 1; - buildIndexProbe(pParse, nEq, pIdx, regBase, pLevel->iMem); - sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq); - r1 = ++pParse->nMem; - buildIndexProbe(pParse, nEq+1, pIdx, regBase, r1); - }else{ - /* Generate a single key that will be used to both start and - ** terminate the search - */ - r1 = pLevel->iMem; - buildIndexProbe(pParse, nEq, pIdx, regBase, r1); - } - - /* Generate code (1) to move to the first matching element of the table. - ** Then generate code (2) that jumps to "nxt" after the cursor is past - ** the last matching element of the table. The code (1) is executed - ** once to initialize the search, the code (2) is executed before each - ** iteration of the scan to see if the scan has finished. */ - if( bRev ){ - /* Scan in reverse order */ - int op; - if( isMinQuery ){ - op = OP_MoveLt; - }else{ - op = OP_MoveLe; - } - sqlite3VdbeAddOp3(v, op, iIdxCur, nxt, r1); - start = sqlite3VdbeAddOp3(v, OP_IdxLT, iIdxCur, nxt, pLevel->iMem); - pLevel->op = OP_Prev; - }else{ - /* Scan in the forward order */ - int op; - if( isMinQuery ){ - op = OP_MoveGt; - }else{ - op = OP_MoveGe; - } - sqlite3VdbeAddOp3(v, op, iIdxCur, nxt, r1); - start = sqlite3VdbeAddOp3(v, OP_IdxGE, iIdxCur, nxt, pLevel->iMem); - sqlite3VdbeChangeP5(v, 1); - pLevel->op = OP_Next; - } - if( !omitTable ){ - r1 = sqlite3GetTempReg(pParse); - sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, r1); - sqlite3VdbeAddOp3(v, OP_MoveGe, iCur, 0, r1); /* Deferred seek */ - sqlite3ReleaseTempReg(pParse, r1); - } - pLevel->p1 = iIdxCur; - pLevel->p2 = start; }else{ /* Case 5: There is no usable index. We must do a complete ** scan of the entire table.