Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Fix for ticket #813. (CVS 1818) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
88e4bfa154e33c627ff2abb15cc55a10 |
User & Date: | drh 2004-07-19 19:14:01.000 |
Context
2004-07-19
| ||
19:28 | Remove debugging code that was accidently left in join4.test. (CVS 1819) (check-in: e36e59f02e user: drh tags: trunk) | |
19:14 | Fix for ticket #813. (CVS 1818) (check-in: 88e4bfa154 user: drh tags: trunk) | |
17:25 | Store schema cookies on the TEMP database. Ticket #807. (CVS 1817) (check-in: c6c13dc460 user: drh tags: trunk) | |
Changes
Changes to src/where.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This module contains C code that generates VDBE code used to process ** the WHERE clause of SQL statements. ** | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This module contains C code that generates VDBE code used to process ** the WHERE clause of SQL statements. ** ** $Id: where.c,v 1.110 2004/07/19 19:14:01 drh Exp $ */ #include "sqliteInt.h" /* ** The query generator uses an array of instances of this structure to ** help it analyze the subexpressions of the WHERE clause. Each WHERE ** clause subexpression is separated from the others by an AND operator. |
︙ | ︙ | |||
275 276 277 278 279 280 281 282 283 284 285 286 287 288 | } } if( pMatch && pbRev ){ *pbRev = sortOrder==SQLITE_SO_DESC; } return pMatch; } /* ** Generate the beginning of the loop used for WHERE clause processing. ** The return value is a pointer to an (opaque) structure that contains ** information needed to terminate the loop. Later, the calling routine ** should invoke sqlite3WhereEnd() with the return value of this function ** in order to complete the WHERE clause processing. | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 | } } if( pMatch && pbRev ){ *pbRev = sortOrder==SQLITE_SO_DESC; } return pMatch; } /* ** Disable a term in the WHERE clause. Except, do not disable the term ** if it controls a LEFT OUTER JOIN and it did not originate in the ON ** or USING clause of that join. ** ** Consider the term t2.z='ok' in the following queries: ** ** (1) SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.x WHERE t2.z='ok' ** (2) SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.x AND t2.z='ok' ** (3) SELECT * FROM t1, t2 WHERE t1.a=t2.x AND t2.z='ok' ** ** The t2.z='ok' is disabled in the in (2) because it did not originate ** in the ON clause. The term is disabled in (3) because it is not part ** of a LEFT OUTER JOIN. In (1), the term is not disabled. ** ** Disabling a term causes that term to not be tested in the inner loop ** of the join. Disabling is an optimization. We would get the correct ** results if nothing were ever disabled, but joins might run a little ** slower. The trick is to disable as much as we can without disabling ** too much. If we disabled in (1), we'd get the wrong answer. ** See ticket #813. */ static void disableTerm(WhereLevel *pLevel, Expr **ppExpr){ Expr *pExpr = *ppExpr; if( pLevel->iLeftJoin==0 || ExprHasProperty(pExpr, EP_FromJoin) ){ *ppExpr = 0; } } /* ** Generate the beginning of the loop used for WHERE clause processing. ** The return value is a pointer to an (opaque) structure that contains ** information needed to terminate the loop. Later, the calling routine ** should invoke sqlite3WhereEnd() with the return value of this function ** in order to complete the WHERE clause processing. |
︙ | ︙ | |||
756 757 758 759 760 761 762 | pLevel->inP2 = sqlite3VdbeAddOp(v, OP_IdxColumn, pX->iTable, 0); pLevel->inOp = OP_Next; pLevel->inP1 = pX->iTable; } }else{ sqlite3ExprCode(pParse, aExpr[k].p->pLeft); } | | | 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 | pLevel->inP2 = sqlite3VdbeAddOp(v, OP_IdxColumn, pX->iTable, 0); pLevel->inOp = OP_Next; pLevel->inP1 = pX->iTable; } }else{ sqlite3ExprCode(pParse, aExpr[k].p->pLeft); } disableTerm(pLevel, &aExpr[k].p); cont = pLevel->cont = sqlite3VdbeMakeLabel(v); sqlite3VdbeAddOp(v, OP_MustBeInt, 1, brk); haveKey = 0; sqlite3VdbeAddOp(v, OP_NotExists, iCur, brk); pLevel->op = OP_Noop; }else if( pIdx!=0 && pLevel->score>0 && pLevel->score%4==0 ){ /* Case 2: There is an index and all terms of the WHERE clause that |
︙ | ︙ | |||
785 786 787 788 789 790 791 | && (aExpr[k].prereqRight & loopMask)==aExpr[k].prereqRight && pX->pLeft->iColumn==pIdx->aiColumn[j] ){ char idxaff = pIdx->pTable->aCol[pX->pLeft->iColumn].affinity; if( sqlite3IndexAffinityOk(aExpr[k].p, idxaff) ){ if( pX->op==TK_EQ ){ sqlite3ExprCode(pParse, pX->pRight); | | | | | 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 | && (aExpr[k].prereqRight & loopMask)==aExpr[k].prereqRight && pX->pLeft->iColumn==pIdx->aiColumn[j] ){ char idxaff = pIdx->pTable->aCol[pX->pLeft->iColumn].affinity; if( sqlite3IndexAffinityOk(aExpr[k].p, idxaff) ){ if( pX->op==TK_EQ ){ sqlite3ExprCode(pParse, pX->pRight); disableTerm(pLevel, &aExpr[k].p); break; } if( pX->op==TK_IN && nColumn==1 ){ sqlite3VdbeAddOp(v, OP_Rewind, pX->iTable, brk); sqlite3VdbeAddOp(v, OP_KeyAsData, pX->iTable, 1); pLevel->inP2 = sqlite3VdbeAddOp(v, OP_IdxColumn, pX->iTable, 0); pLevel->inOp = OP_Next; pLevel->inP1 = pX->iTable; disableTerm(pLevel, &aExpr[k].p); break; } } } if( aExpr[k].idxRight==iCur && aExpr[k].p->op==TK_EQ && (aExpr[k].prereqLeft & loopMask)==aExpr[k].prereqLeft && aExpr[k].p->pRight->iColumn==pIdx->aiColumn[j] ){ char idxaff = pIdx->pTable->aCol[pX->pRight->iColumn].affinity; if( sqlite3IndexAffinityOk(aExpr[k].p, idxaff) ){ sqlite3ExprCode(pParse, aExpr[k].p->pLeft); disableTerm(pLevel, &aExpr[k].p); break; } } } } pLevel->iMem = pParse->nMem++; cont = pLevel->cont = sqlite3VdbeMakeLabel(v); |
︙ | ︙ | |||
879 880 881 882 883 884 885 | sqlite3ExprCode(pParse, aExpr[k].p->pRight); }else{ sqlite3ExprCode(pParse, aExpr[k].p->pLeft); } sqlite3VdbeAddOp(v, OP_ForceInt, aExpr[k].p->op==TK_LT || aExpr[k].p->op==TK_GT, brk); sqlite3VdbeAddOp(v, OP_MoveGe, iCur, brk); | | | 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 | sqlite3ExprCode(pParse, aExpr[k].p->pRight); }else{ sqlite3ExprCode(pParse, aExpr[k].p->pLeft); } sqlite3VdbeAddOp(v, OP_ForceInt, aExpr[k].p->op==TK_LT || aExpr[k].p->op==TK_GT, brk); sqlite3VdbeAddOp(v, OP_MoveGe, iCur, brk); disableTerm(pLevel, &aExpr[k].p); }else{ sqlite3VdbeAddOp(v, OP_Rewind, iCur, brk); } if( iDirectLt[i]>=0 ){ k = iDirectLt[i]; assert( k<nExpr ); assert( aExpr[k].p!=0 ); |
︙ | ︙ | |||
901 902 903 904 905 906 907 | pLevel->iMem = pParse->nMem++; sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 1); if( aExpr[k].p->op==TK_LT || aExpr[k].p->op==TK_GT ){ testOp = OP_Ge; }else{ testOp = OP_Gt; } | | | 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 | pLevel->iMem = pParse->nMem++; sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 1); if( aExpr[k].p->op==TK_LT || aExpr[k].p->op==TK_GT ){ testOp = OP_Ge; }else{ testOp = OP_Gt; } disableTerm(pLevel, &aExpr[k].p); } start = sqlite3VdbeCurrentAddr(v); pLevel->op = OP_Next; pLevel->p1 = iCur; pLevel->p2 = start; if( testOp!=OP_Noop ){ sqlite3VdbeAddOp(v, OP_Recno, iCur, 0); |
︙ | ︙ | |||
956 957 958 959 960 961 962 | if( aExpr[k].p==0 ) continue; if( aExpr[k].idxLeft==iCur && aExpr[k].p->op==TK_EQ && (aExpr[k].prereqRight & loopMask)==aExpr[k].prereqRight && aExpr[k].p->pLeft->iColumn==pIdx->aiColumn[j] ){ sqlite3ExprCode(pParse, aExpr[k].p->pRight); | | | | 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 | if( aExpr[k].p==0 ) continue; if( aExpr[k].idxLeft==iCur && aExpr[k].p->op==TK_EQ && (aExpr[k].prereqRight & loopMask)==aExpr[k].prereqRight && aExpr[k].p->pLeft->iColumn==pIdx->aiColumn[j] ){ sqlite3ExprCode(pParse, aExpr[k].p->pRight); disableTerm(pLevel, &aExpr[k].p); break; } if( aExpr[k].idxRight==iCur && aExpr[k].p->op==TK_EQ && (aExpr[k].prereqLeft & loopMask)==aExpr[k].prereqLeft && aExpr[k].p->pRight->iColumn==pIdx->aiColumn[j] ){ sqlite3ExprCode(pParse, aExpr[k].p->pLeft); disableTerm(pLevel, &aExpr[k].p); break; } } } /* Duplicate the equality term values because they will all be ** used twice: once to make the termination key and once to make the |
︙ | ︙ | |||
1002 1003 1004 1005 1006 1007 1008 | if( aExpr[k].idxLeft==iCur && (pExpr->op==TK_LT || pExpr->op==TK_LE) && (aExpr[k].prereqRight & loopMask)==aExpr[k].prereqRight && pExpr->pLeft->iColumn==pIdx->aiColumn[j] ){ sqlite3ExprCode(pParse, pExpr->pRight); leFlag = pExpr->op==TK_LE; | | | | 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 | if( aExpr[k].idxLeft==iCur && (pExpr->op==TK_LT || pExpr->op==TK_LE) && (aExpr[k].prereqRight & loopMask)==aExpr[k].prereqRight && pExpr->pLeft->iColumn==pIdx->aiColumn[j] ){ sqlite3ExprCode(pParse, pExpr->pRight); leFlag = pExpr->op==TK_LE; disableTerm(pLevel, &aExpr[k].p); break; } if( aExpr[k].idxRight==iCur && (pExpr->op==TK_GT || pExpr->op==TK_GE) && (aExpr[k].prereqLeft & loopMask)==aExpr[k].prereqLeft && pExpr->pRight->iColumn==pIdx->aiColumn[j] ){ sqlite3ExprCode(pParse, pExpr->pLeft); leFlag = pExpr->op==TK_GE; disableTerm(pLevel, &aExpr[k].p); break; } } testOp = OP_IdxGE; }else{ testOp = nEqColumn>0 ? OP_IdxGE : OP_Noop; leFlag = 1; |
︙ | ︙ | |||
1059 1060 1061 1062 1063 1064 1065 | if( aExpr[k].idxLeft==iCur && (pExpr->op==TK_GT || pExpr->op==TK_GE) && (aExpr[k].prereqRight & loopMask)==aExpr[k].prereqRight && pExpr->pLeft->iColumn==pIdx->aiColumn[j] ){ sqlite3ExprCode(pParse, pExpr->pRight); geFlag = pExpr->op==TK_GE; | | | | 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 | if( aExpr[k].idxLeft==iCur && (pExpr->op==TK_GT || pExpr->op==TK_GE) && (aExpr[k].prereqRight & loopMask)==aExpr[k].prereqRight && pExpr->pLeft->iColumn==pIdx->aiColumn[j] ){ sqlite3ExprCode(pParse, pExpr->pRight); geFlag = pExpr->op==TK_GE; disableTerm(pLevel, &aExpr[k].p); break; } if( aExpr[k].idxRight==iCur && (pExpr->op==TK_LT || pExpr->op==TK_LE) && (aExpr[k].prereqLeft & loopMask)==aExpr[k].prereqLeft && pExpr->pRight->iColumn==pIdx->aiColumn[j] ){ sqlite3ExprCode(pParse, pExpr->pLeft); geFlag = pExpr->op==TK_LE; disableTerm(pLevel, &aExpr[k].p); break; } } }else{ geFlag = 1; } if( nEqColumn>0 || (score&2)!=0 ){ |
︙ | ︙ |
Added test/join4.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | # 2002 May 24 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. # # This file implements tests for left outer joins containing WHERE # clauses that restrict the scope of the left term of the join. # # $Id: join4.test,v 1.1 2004/07/19 19:14:01 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl do_test join4-1.1 { execsql { create temp table t1(a integer, b varchar(10)); insert into t1 values(1,'one'); insert into t1 values(2,'two'); insert into t1 values(3,'three'); insert into t1 values(4,'four'); create temp table t2(x integer, y varchar(10), z varchar(10)); insert into t2 values(2,'niban','ok'); insert into t2 values(4,'yonban','err'); } execsql { select * from t1 left outer join t2 on t1.a=t2.x where t2.z='ok' } } {2 two 2 niban ok} do_test join4-1.2 { execsql { select * from t1 left outer join t2 on t1.a=t2.x and t2.z='ok' } } {1 one {} {} {} 2 two 2 niban ok 3 three {} {} {} 4 four {} {} {}} do_test join4-1.3 { execsql { create index i2 on t2(z); } btree_breakpoint execsql { select * from t1 left outer join t2 on t1.a=t2.x where t2.z='ok' } } {2 two 2 niban ok} do_test join4-1.4 { execsql { select * from t1 left outer join t2 on t1.a=t2.x and t2.z='ok' } } {1 one {} {} {} 2 two 2 niban ok 3 three {} {} {} 4 four {} {} {}} do_test join4-1.5 { execsql { select * from t1 left outer join t2 on t1.a=t2.x where t2.z>='ok' } } {2 two 2 niban ok} do_test join4-1.4 { execsql { select * from t1 left outer join t2 on t1.a=t2.x and t2.z>='ok' } } {1 one {} {} {} 2 two 2 niban ok 3 three {} {} {} 4 four {} {} {}} do_test join4-1.6 { execsql { select * from t1 left outer join t2 on t1.a=t2.x where t2.z IN ('ok') } } {2 two 2 niban ok} do_test join4-1.7 { execsql { select * from t1 left outer join t2 on t1.a=t2.x and t2.z IN ('ok') } } {1 one {} {} {} 2 two 2 niban ok 3 three {} {} {} 4 four {} {} {}} finish_test |