SQLite

Check-in [61a1c6db]
Login

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

Overview
Comment:Fix for the problem identified in forum post 0cd8e058bf: When evaluating an multi-index OR, do not push down auxiliary WHERE clause terms that involve subqueries into the OR-subqueries. Otherwise, the covering-index optimizer might convert table-references into index-references for the particular OR index that is active for the branch in which the subquery subroutine is coded, and those index-references will not work if the subquery subroutine is invoked from a different OR branch that uses a different index.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 61a1c6dbd089979cbeb8b0c0c5ee1ab1abcb466be1d21a3a851be73c27e67a6c
User & Date: drh 2022-03-03 15:59:22
Context
2022-03-05
19:39
Cherry-pick all bug fix changes since the 3.38.0 release. (check-in: 45a5d5ac user: drh tags: branch-3.38)
2022-03-03
16:48
Make sure the xParseCell and xCellSize methods of the MemPage object are initialized consistently even if the page is detected as being corrupt. dbsqlfuzz fd21f341f3b4f582401d2feb2a1c0c4cc2c26caa. (check-in: 725a0643 user: drh tags: trunk)
15:59
Fix for the problem identified in forum post 0cd8e058bf: When evaluating an multi-index OR, do not push down auxiliary WHERE clause terms that involve subqueries into the OR-subqueries. Otherwise, the covering-index optimizer might convert table-references into index-references for the particular OR index that is active for the branch in which the subquery subroutine is coded, and those index-references will not work if the subquery subroutine is invoked from a different OR branch that uses a different index. (check-in: 61a1c6db user: drh tags: trunk)
15:00
Add the new OP_BeginSubrtn opcode (which is really an alias for OP_Integer) and make other changes so that the span of a subroutine that implements a subquery is more readily apparent in bytecode listings. (check-in: b8226748 user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/wherecode.c.
2341
2342
2343
2344
2345
2346
2347








2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
    ** See ticket http://www.sqlite.org/src/info/f2369304e4
    **
    ** 2022-02-04:  Do not push down slices of a row-value comparison.
    ** In other words, "w" or "y" may not be a slice of a vector.  Otherwise,
    ** the initialization of the right-hand operand of the vector comparison
    ** might not occur, or might occur only in an OR branch that is not
    ** taken.  dbsqlfuzz 80a9fade844b4fb43564efc972bcb2c68270f5d1.








    */
    if( pWC->nTerm>1 ){
      int iTerm;
      for(iTerm=0; iTerm<pWC->nTerm; iTerm++){
        Expr *pExpr = pWC->a[iTerm].pExpr;
        if( &pWC->a[iTerm] == pTerm ) continue;
        testcase( pWC->a[iTerm].wtFlags & TERM_VIRTUAL );
        testcase( pWC->a[iTerm].wtFlags & TERM_CODED );
        testcase( pWC->a[iTerm].wtFlags & TERM_SLICE );
        if( (pWC->a[iTerm].wtFlags & (TERM_VIRTUAL|TERM_CODED|TERM_SLICE))!=0 ){
          continue;
        }
        if( (pWC->a[iTerm].eOperator & WO_ALL)==0 ) continue;
        testcase( pWC->a[iTerm].wtFlags & TERM_ORINFO );
        pExpr = sqlite3ExprDup(db, pExpr, 0);
        pAndExpr = sqlite3ExprAnd(pParse, pAndExpr, pExpr);
      }
      if( pAndExpr ){
        /* The extra 0x10000 bit on the opcode is masked off and does not
        ** become part of the new Expr.op.  However, it does make the
        ** op==TK_AND comparison inside of sqlite3PExpr() false, and this







>
>
>
>
>
>
>
>












|
|







2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
    ** See ticket http://www.sqlite.org/src/info/f2369304e4
    **
    ** 2022-02-04:  Do not push down slices of a row-value comparison.
    ** In other words, "w" or "y" may not be a slice of a vector.  Otherwise,
    ** the initialization of the right-hand operand of the vector comparison
    ** might not occur, or might occur only in an OR branch that is not
    ** taken.  dbsqlfuzz 80a9fade844b4fb43564efc972bcb2c68270f5d1.
    **
    ** 2022-03-03:  Do not push down expressions that involve subqueries.
    ** The subquery might get coded as a subroutine.  Any table-references
    ** in the subquery might be resolved to index-references for the index on
    ** the OR branch in which the subroutine is coded.  But if the subroutine
    ** is invoked from a different OR branch that uses a different index, such
    ** index-references will not work.  tag-20220303a
    ** https://sqlite.org/forum/forumpost/36937b197273d403
    */
    if( pWC->nTerm>1 ){
      int iTerm;
      for(iTerm=0; iTerm<pWC->nTerm; iTerm++){
        Expr *pExpr = pWC->a[iTerm].pExpr;
        if( &pWC->a[iTerm] == pTerm ) continue;
        testcase( pWC->a[iTerm].wtFlags & TERM_VIRTUAL );
        testcase( pWC->a[iTerm].wtFlags & TERM_CODED );
        testcase( pWC->a[iTerm].wtFlags & TERM_SLICE );
        if( (pWC->a[iTerm].wtFlags & (TERM_VIRTUAL|TERM_CODED|TERM_SLICE))!=0 ){
          continue;
        }
        if( (pWC->a[iTerm].eOperator & WO_SINGLE)==0 ) continue;
        if( ExprHasProperty(pExpr, EP_Subquery) ) continue;  /* tag-20220303a */
        pExpr = sqlite3ExprDup(db, pExpr, 0);
        pAndExpr = sqlite3ExprAnd(pParse, pAndExpr, pExpr);
      }
      if( pAndExpr ){
        /* The extra 0x10000 bit on the opcode is masked off and does not
        ** become part of the new Expr.op.  However, it does make the
        ** op==TK_AND comparison inside of sqlite3PExpr() false, and this
Changes to test/where7.test.
23356
23357
23358
23359
23360
23361
23362
























23363
23364
  |  |--INDEX 1
  |  |  `--SEARCH t301 USING COVERING INDEX t301_c4 (c4=?)
  |  `--INDEX 2
  |     `--SEARCH t301 USING INTEGER PRIMARY KEY (rowid=?)
  |--SEARCH t302 USING INDEX t302_c8_c3 (c8=? AND c3>?)
  `--USE TEMP B-TREE FOR ORDER BY
}

























finish_test







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>


23356
23357
23358
23359
23360
23361
23362
23363
23364
23365
23366
23367
23368
23369
23370
23371
23372
23373
23374
23375
23376
23377
23378
23379
23380
23381
23382
23383
23384
23385
23386
23387
23388
  |  |--INDEX 1
  |  |  `--SEARCH t301 USING COVERING INDEX t301_c4 (c4=?)
  |  `--INDEX 2
  |     `--SEARCH t301 USING INTEGER PRIMARY KEY (rowid=?)
  |--SEARCH t302 USING INDEX t302_c8_c3 (c8=? AND c3>?)
  `--USE TEMP B-TREE FOR ORDER BY
}

# 2022-03-03 https://sqlite.org/forum/forumpost/36937b197273d403
#
# In the multi-index OR, if there is an auxiliary WHERE clause term
# that includes a subquery and that subquery is pushed down into the
# OR-clause subqueries, WHERE subquery might get coded as a subroutine.
# In that case, the covering-index optimizer will attempt to change
# table-references into index-references.  But it will do so for the
# index of the OR branch in which the subquery is coded.  If the
# subquery subroutine is called from a different OR branch, the
# index might be different and the index-reference will no longer
# work.  tag-20220303a
#
reset_db
do_execsql_test 4.1 {
  CREATE TABLE t0(w);
  INSERT INTO t0(w) VALUES(1);
  CREATE TABLE t1(x INT, y INT PRIMARY KEY, z); 
  INSERT INTO t1 VALUES(0,111,222);
  CREATE INDEX t1zxy ON t1(z,x,y);
  SELECT y FROM t1
   WHERE (z=222 OR y=111)
     AND (false OR EXISTS(SELECT 1 FROM t0 WHERE t1.y));
} {111}

finish_test