SQLite

Check-in [ff8b76b25b]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Further streamlining of the subquery materializer. New test cases for ticket [002caede898a]
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: ff8b76b25b42497a7374de56c6a8f34cbe70cd6a
User & Date: drh 2011-09-16 16:00:51.082
Context
2011-09-16
17:43
When analyzing the right-hand side of IN operators to see if the IN operator can work with an index, be sure to decend into nested subqueries. Fix for ticket [1a1308d2538d7] (check-in: 0156f10e23 user: drh tags: trunk)
16:00
Further streamlining of the subquery materializer. New test cases for ticket [002caede898a] (check-in: ff8b76b25b user: drh tags: trunk)
01:38
Merge the [002caede898] fix into trunk. (check-in: 95708ae223 user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/select.c.
3826
3827
3828
3829
3830
3831
3832
3833
3834

3835


3836
3837
3838
3839
3840
3841
3842
3843
3844
3845
3846
3847
3848
3849
3850

3851
3852
3853
3854
3855
3856
3857
3858
3859
      i = -1;
    }else{
      /* Generate a subroutine that will fill an ephemeral table with
      ** the content of this subquery.  pItem->addrFillSub will point
      ** to the address of the generated subroutine.  pItem->regReturn
      ** is a register allocated to hold the subroutine return address
      */
      int topAddr = sqlite3VdbeAddOp0(v, OP_Goto);
      int onceAddr = 0;

      assert( pItem->addrFillSub==0 );


      pItem->addrFillSub = topAddr+1;
      pItem->regReturn = ++pParse->nMem;
      if( pItem->isCorrelated==0 && pParse->pTriggerTab==0 ){
        /* If the subquery is no correlated and if we are not inside of
        ** a trigger, then we only need to compute the value of the subquery
        ** once. */
        int regOnce = ++pParse->nMem;
        onceAddr = sqlite3VdbeAddOp1(v, OP_Once, regOnce);
      }
      sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
      explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
      sqlite3Select(pParse, pSub, &dest);
      pItem->pTab->nRowEst = (unsigned)pSub->nSelectRow;
      if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr);
      sqlite3VdbeAddOp1(v, OP_Return, pItem->regReturn);

      sqlite3VdbeJumpHere(v, topAddr);
      sqlite3VdbeAddOp2(v, OP_Gosub, pItem->regReturn, topAddr+1);
    }
    if( /*pParse->nErr ||*/ db->mallocFailed ){
      goto select_end;
    }
    pParse->nHeight -= sqlite3SelectExprHeight(p);
    pTabList = p->pSrc;
    if( !IgnorableOrderby(pDest) ){







|

>

>
>

|












|
>
|
|







3826
3827
3828
3829
3830
3831
3832
3833
3834
3835
3836
3837
3838
3839
3840
3841
3842
3843
3844
3845
3846
3847
3848
3849
3850
3851
3852
3853
3854
3855
3856
3857
3858
3859
3860
3861
3862
3863
      i = -1;
    }else{
      /* Generate a subroutine that will fill an ephemeral table with
      ** the content of this subquery.  pItem->addrFillSub will point
      ** to the address of the generated subroutine.  pItem->regReturn
      ** is a register allocated to hold the subroutine return address
      */
      int topAddr;
      int onceAddr = 0;
      int retAddr;
      assert( pItem->addrFillSub==0 );
      pItem->regReturn = ++pParse->nMem;
      topAddr = sqlite3VdbeAddOp2(v, OP_Integer, 0, pItem->regReturn);
      pItem->addrFillSub = topAddr+1;
      VdbeNoopComment((v, "materialize %s", pItem->pTab->zName));
      if( pItem->isCorrelated==0 && pParse->pTriggerTab==0 ){
        /* If the subquery is no correlated and if we are not inside of
        ** a trigger, then we only need to compute the value of the subquery
        ** once. */
        int regOnce = ++pParse->nMem;
        onceAddr = sqlite3VdbeAddOp1(v, OP_Once, regOnce);
      }
      sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
      explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
      sqlite3Select(pParse, pSub, &dest);
      pItem->pTab->nRowEst = (unsigned)pSub->nSelectRow;
      if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr);
      retAddr = sqlite3VdbeAddOp1(v, OP_Return, pItem->regReturn);
      VdbeComment((v, "end %s", pItem->pTab->zName));
      sqlite3VdbeChangeP1(v, topAddr, retAddr);

    }
    if( /*pParse->nErr ||*/ db->mallocFailed ){
      goto select_end;
    }
    pParse->nHeight -= sqlite3SelectExprHeight(p);
    pTabList = p->pSrc;
    if( !IgnorableOrderby(pDest) ){
Changes to test/tkt-31338dca7e.test.
106
107
108
109
110
111
112








113











































114
115
     WHERE (a=1 AND h=4)
         OR (b=2 AND b NOT IN (
               SELECT x+1 FROM (SELECT e+f AS x, e FROM t2 ORDER BY 1 LIMIT 2)
               GROUP BY e
            ));
  }    
} {4 1 2 3 4 {}}





















































finish_test







>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>


106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
     WHERE (a=1 AND h=4)
         OR (b=2 AND b NOT IN (
               SELECT x+1 FROM (SELECT e+f AS x, e FROM t2 ORDER BY 1 LIMIT 2)
               GROUP BY e
            ));
  }    
} {4 1 2 3 4 {}}
do_test tkt-31338-3.3 {
  db eval {    
    SELECT * FROM t3 LEFT JOIN t1 ON d=g LEFT JOIN t4 ON c=h
     WHERE (+a=1 AND h=4)
         OR (b IN (
               SELECT x FROM (SELECT e+f AS x, e FROM t2 ORDER BY 1 LIMIT 2)
               GROUP BY e
            ));
  }    
} {4 1 2 3 4 {}}
do_test tkt-31338-3.4 {
  db eval {    
    SELECT * FROM t3 LEFT JOIN t1 ON d=g LEFT JOIN t4 ON c=h
     WHERE (a=1 AND h=4)
         OR (+b IN (
               SELECT x FROM (SELECT e+f AS x, e FROM t2 ORDER BY 1 LIMIT 2)
               GROUP BY e
            ));
  }    
} {4 1 2 3 4 {}}

do_test tkt-31338-3.5 {
  db eval {
    CREATE TABLE t5(a,b,c,d,e,f);
    CREATE TABLE t6(g,h);
    CREATE TRIGGER t6r AFTER INSERT ON t6 BEGIN
      INSERT INTO t5    
        SELECT * FROM t3 LEFT JOIN t1 ON d=g LEFT JOIN t4 ON c=h
         WHERE (a=1 AND h=4)
            OR (b IN (
               SELECT x FROM (SELECT e+f AS x, e FROM t2 ORDER BY 1 LIMIT 2)
               GROUP BY e
            ));
    END;
    INSERT INTO t6 VALUES(88,99);
    SELECT * FROM t5;
  }    
} {4 1 2 3 4 {}}

do_test tkt-31338-3.6 {
  db eval {    
    INSERT INTO t1 VALUES(2,4,3,4);
    INSERT INTO t1 VALUES(99,101,3,4);
    INSERT INTO t1 VALUES(98,97,3,4);
    SELECT * FROM t3 LEFT JOIN t1 ON d=g LEFT JOIN t4 ON c=h
     WHERE (a=1 AND h=4)
         OR (b IN (
               SELECT x+a FROM (SELECT e+f AS x, e FROM t2 ORDER BY 1 LIMIT 2)
               GROUP BY e
            ));
  }    
} {4 2 4 3 4 {} 4 99 101 3 4 {}}

finish_test