SQLite

Check-in [4fbb9ffe]
Login

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

Overview
Comment:Fix a problem with automatic indexes introduced by check-in [664b461bb5063d980] and reported by forum post 0d3200f4f3bcd3a3.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | branch-3.38
Files: files | file ages | folders
SHA3-256: 4fbb9ffe72f112d5f3b02760759b90ef935ddff4089013caac3a9e222a98a304
User & Date: drh 2022-04-25 21:21:08
Context
2022-04-25
21:22
Increase the version number to 3.38.3. (check-in: b113afa2 user: drh tags: branch-3.38)
21:21
Fix a problem with automatic indexes introduced by check-in [664b461bb5063d980] and reported by forum post 0d3200f4f3bcd3a3. (check-in: 4fbb9ffe user: drh tags: branch-3.38)
20:56
Fix a problem with automatic indexes introduced by check-in [664b461bb5063d980] and reported by forum post 0d3200f4f3bcd3a3. (check-in: 134cfb18 user: drh tags: trunk)
2022-04-04
15:26
Fix two minor problems in the JSON functions associated with JSON Paths for object labels that require quoting. (check-in: 4a1553b5 user: drh tags: branch-3.38)
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/expr.c.

2279
2280
2281
2282
2283
2284
2285
































2286
2287
2288
2289
2290
2291
2292
** for any single row of the table with cursor iCur.  In other words, the
** expression must not refer to any non-deterministic function nor any
** table other than iCur.
*/
int sqlite3ExprIsTableConstant(Expr *p, int iCur){
  return exprIsConst(p, 3, iCur);
}


































/*
** sqlite3WalkExpr() callback used by sqlite3ExprIsConstantOrGroupBy().
*/
static int exprNodeIsConstantOrGroupBy(Walker *pWalker, Expr *pExpr){
  ExprList *pGroupBy = pWalker->u.pGroupBy;







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







2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
** for any single row of the table with cursor iCur.  In other words, the
** expression must not refer to any non-deterministic function nor any
** table other than iCur.
*/
int sqlite3ExprIsTableConstant(Expr *p, int iCur){
  return exprIsConst(p, 3, iCur);
}

/*
** Check pExpr to see if it is an invariant constraint on data source pSrc.
** This is an optimization.  False negatives will perhaps cause slower
** queries, but false positives will yield incorrect answers.  So when in
** double, return 0.
**
** To be an invariant constraint, the following must be true:
**
**   (1)  pExpr cannot refer to any table other than pSrc->iCursor.
**
**   (2)  pExpr cannot use subqueries or non-deterministic functions.
**
**   (*)  ** Not applicable to this branch **
**
**   (4)  If pSrc is the right operand of a LEFT JOIN, then...
**         (4a)  pExpr must come from an ON clause..
**         (4b)  and specifically the ON clause associated with the LEFT JOIN.
**
**   (5)  If pSrc is not the right operand of a LEFT JOIN or the left
**        operand of a RIGHT JOIN, then pExpr must be from the WHERE
**        clause, not an ON clause.
*/
int sqlite3ExprIsTableConstraint(Expr *pExpr, const SrcItem *pSrc){
  if( pSrc->fg.jointype & JT_LEFT ){
    if( !ExprHasProperty(pExpr, EP_FromJoin) ) return 0;    /* rule (4a) */
    if( pExpr->w.iRightJoinTable!=pSrc->iCursor ) return 0; /* rule (4b) */
  }else{
    if( ExprHasProperty(pExpr, EP_FromJoin) ) return 0;     /* rule (5) */
  }
  return sqlite3ExprIsTableConstant(pExpr, pSrc->iCursor);  /* rules (1), (2) */
}


/*
** sqlite3WalkExpr() callback used by sqlite3ExprIsConstantOrGroupBy().
*/
static int exprNodeIsConstantOrGroupBy(Walker *pWalker, Expr *pExpr){
  ExprList *pGroupBy = pWalker->u.pGroupBy;

Changes to src/select.c.

4818
4819
4820
4821
4822
4823
4824
4825
4826
4827
4828
4829
4830
4831
4832
4833
** Return 0 if no changes are made and non-zero if one or more WHERE clause
** terms are duplicated into the subquery.
*/
static int pushDownWhereTerms(
  Parse *pParse,        /* Parse context (for malloc() and error reporting) */
  Select *pSubq,        /* The subquery whose WHERE clause is to be augmented */
  Expr *pWhere,         /* The WHERE clause of the outer query */
  int iCursor,          /* Cursor number of the subquery */
  int isLeftJoin        /* True if pSubq is the right term of a LEFT JOIN */
){
  Expr *pNew;
  int nChng = 0;
  if( pWhere==0 ) return 0;
  if( pSubq->selFlags & (SF_Recursive|SF_MultiPart) ) return 0;

#ifndef SQLITE_OMIT_WINDOWFUNC







|
<







4818
4819
4820
4821
4822
4823
4824
4825

4826
4827
4828
4829
4830
4831
4832
** Return 0 if no changes are made and non-zero if one or more WHERE clause
** terms are duplicated into the subquery.
*/
static int pushDownWhereTerms(
  Parse *pParse,        /* Parse context (for malloc() and error reporting) */
  Select *pSubq,        /* The subquery whose WHERE clause is to be augmented */
  Expr *pWhere,         /* The WHERE clause of the outer query */
  SrcItem *pSrc         /* The subquery term of the outer FROM clause */

){
  Expr *pNew;
  int nChng = 0;
  if( pWhere==0 ) return 0;
  if( pSubq->selFlags & (SF_Recursive|SF_MultiPart) ) return 0;

#ifndef SQLITE_OMIT_WINDOWFUNC
4854
4855
4856
4857
4858
4859
4860
4861
4862
4863
4864


4865
4866
4867
4868
4869
4870
4871
4872
4873
4874
4875


4876
4877
4878
4879
4880
4881
4882
4883
4884
4885
4886
4887
4888
4889
4890
4891
4892
  }
#endif

  if( pSubq->pLimit!=0 ){
    return 0; /* restriction (3) */
  }
  while( pWhere->op==TK_AND ){
    nChng += pushDownWhereTerms(pParse, pSubq, pWhere->pRight,
                                iCursor, isLeftJoin);
    pWhere = pWhere->pLeft;
  }


  if( isLeftJoin
   && (ExprHasProperty(pWhere,EP_FromJoin)==0
         || pWhere->w.iRightJoinTable!=iCursor)
  ){
    return 0; /* restriction (4) */
  }
  if( ExprHasProperty(pWhere,EP_FromJoin)
   && pWhere->w.iRightJoinTable!=iCursor 
  ){
    return 0; /* restriction (5) */
  }


  if( sqlite3ExprIsTableConstant(pWhere, iCursor) ){
    nChng++;
    pSubq->selFlags |= SF_PushDown;
    while( pSubq ){
      SubstContext x;
      pNew = sqlite3ExprDup(pParse->db, pWhere, 0);
      unsetJoinExpr(pNew, -1);
      x.pParse = pParse;
      x.iTable = iCursor;
      x.iNewTable = iCursor;
      x.isLeftJoin = 0;
      x.pEList = pSubq->pEList;
      pNew = substExpr(&x, pNew);
#ifndef SQLITE_OMIT_WINDOWFUNC
      if( pSubq->pWin && 0==pushDownWindowCheck(pParse, pSubq, pNew) ){
        /* Restriction 6c has prevented push-down in this case */
        sqlite3ExprDelete(pParse->db, pNew);







|
<


>
>











>
>
|







|
|







4853
4854
4855
4856
4857
4858
4859
4860

4861
4862
4863
4864
4865
4866
4867
4868
4869
4870
4871
4872
4873
4874
4875
4876
4877
4878
4879
4880
4881
4882
4883
4884
4885
4886
4887
4888
4889
4890
4891
4892
4893
4894
  }
#endif

  if( pSubq->pLimit!=0 ){
    return 0; /* restriction (3) */
  }
  while( pWhere->op==TK_AND ){
    nChng += pushDownWhereTerms(pParse, pSubq, pWhere->pRight, pSrc);

    pWhere = pWhere->pLeft;
  }

#if 0  /* Legacy code. Checks now done by sqlite3ExprIsTableConstraint() */
  if( isLeftJoin
   && (ExprHasProperty(pWhere,EP_FromJoin)==0
         || pWhere->w.iRightJoinTable!=iCursor)
  ){
    return 0; /* restriction (4) */
  }
  if( ExprHasProperty(pWhere,EP_FromJoin)
   && pWhere->w.iRightJoinTable!=iCursor 
  ){
    return 0; /* restriction (5) */
  }
#endif

  if( sqlite3ExprIsTableConstraint(pWhere, pSrc) ){
    nChng++;
    pSubq->selFlags |= SF_PushDown;
    while( pSubq ){
      SubstContext x;
      pNew = sqlite3ExprDup(pParse->db, pWhere, 0);
      unsetJoinExpr(pNew, -1);
      x.pParse = pParse;
      x.iTable = pSrc->iCursor;
      x.iNewTable = pSrc->iCursor;
      x.isLeftJoin = 0;
      x.pEList = pSubq->pEList;
      pNew = substExpr(&x, pNew);
#ifndef SQLITE_OMIT_WINDOWFUNC
      if( pSubq->pWin && 0==pushDownWindowCheck(pParse, pSubq, pNew) ){
        /* Restriction 6c has prevented push-down in this case */
        sqlite3ExprDelete(pParse->db, pNew);
6660
6661
6662
6663
6664
6665
6666
6667
6668
6669
6670
6671
6672
6673
6674
6675

    /* Make copies of constant WHERE-clause terms in the outer query down
    ** inside the subquery.  This can help the subquery to run more efficiently.
    */
    if( OptimizationEnabled(db, SQLITE_PushDown)
     && (pItem->fg.isCte==0 
         || (pItem->u2.pCteUse->eM10d!=M10d_Yes && pItem->u2.pCteUse->nUse<2))
     && pushDownWhereTerms(pParse, pSub, p->pWhere, pItem->iCursor,
                           (pItem->fg.jointype & JT_OUTER)!=0)
    ){
#if SELECTTRACE_ENABLED
      if( sqlite3SelectTrace & 0x100 ){
        SELECTTRACE(0x100,pParse,p,
            ("After WHERE-clause push-down into subquery %d:\n", pSub->selId));
        sqlite3TreeViewSelect(0, p, 0);
      }







|
<







6662
6663
6664
6665
6666
6667
6668
6669

6670
6671
6672
6673
6674
6675
6676

    /* Make copies of constant WHERE-clause terms in the outer query down
    ** inside the subquery.  This can help the subquery to run more efficiently.
    */
    if( OptimizationEnabled(db, SQLITE_PushDown)
     && (pItem->fg.isCte==0 
         || (pItem->u2.pCteUse->eM10d!=M10d_Yes && pItem->u2.pCteUse->nUse<2))
     && pushDownWhereTerms(pParse, pSub, p->pWhere, pItem)

    ){
#if SELECTTRACE_ENABLED
      if( sqlite3SelectTrace & 0x100 ){
        SELECTTRACE(0x100,pParse,p,
            ("After WHERE-clause push-down into subquery %d:\n", pSub->selId));
        sqlite3TreeViewSelect(0, p, 0);
      }

Changes to src/sqliteInt.h.

4658
4659
4660
4661
4662
4663
4664

4665
4666
4667
4668
4669
4670
4671
int sqlite3ExprIdToTrueFalse(Expr*);
int sqlite3ExprTruthValue(const Expr*);
int sqlite3ExprIsConstant(Expr*);
int sqlite3ExprIsConstantNotJoin(Expr*);
int sqlite3ExprIsConstantOrFunction(Expr*, u8);
int sqlite3ExprIsConstantOrGroupBy(Parse*, Expr*, ExprList*);
int sqlite3ExprIsTableConstant(Expr*,int);

#ifdef SQLITE_ENABLE_CURSOR_HINTS
int sqlite3ExprContainsSubquery(Expr*);
#endif
int sqlite3ExprIsInteger(const Expr*, int*);
int sqlite3ExprCanBeNull(const Expr*);
int sqlite3ExprNeedsNoAffinityChange(const Expr*, char);
int sqlite3IsRowid(const char*);







>







4658
4659
4660
4661
4662
4663
4664
4665
4666
4667
4668
4669
4670
4671
4672
int sqlite3ExprIdToTrueFalse(Expr*);
int sqlite3ExprTruthValue(const Expr*);
int sqlite3ExprIsConstant(Expr*);
int sqlite3ExprIsConstantNotJoin(Expr*);
int sqlite3ExprIsConstantOrFunction(Expr*, u8);
int sqlite3ExprIsConstantOrGroupBy(Parse*, Expr*, ExprList*);
int sqlite3ExprIsTableConstant(Expr*,int);
int sqlite3ExprIsTableConstraint(Expr*,const SrcItem*);
#ifdef SQLITE_ENABLE_CURSOR_HINTS
int sqlite3ExprContainsSubquery(Expr*);
#endif
int sqlite3ExprIsInteger(const Expr*, int*);
int sqlite3ExprCanBeNull(const Expr*);
int sqlite3ExprNeedsNoAffinityChange(const Expr*, char);
int sqlite3IsRowid(const char*);

Changes to src/where.c.

804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
  idxCols = 0;
  for(pTerm=pWC->a; pTerm<pWCEnd; pTerm++){
    Expr *pExpr = pTerm->pExpr;
    /* Make the automatic index a partial index if there are terms in the
    ** WHERE clause (or the ON clause of a LEFT join) that constrain which
    ** rows of the target table (pSrc) that can be used. */
    if( (pTerm->wtFlags & TERM_VIRTUAL)==0
     && ((pSrc->fg.jointype&JT_LEFT)==0 || ExprHasProperty(pExpr,EP_FromJoin))
     && sqlite3ExprIsTableConstant(pExpr, pSrc->iCursor)
    ){
      pPartial = sqlite3ExprAnd(pParse, pPartial,
                                sqlite3ExprDup(pParse->db, pExpr, 0));
    }
    if( termCanDriveIndex(pTerm, pSrc, notReady) ){
      int iCol;
      Bitmask cMask;







<
|







804
805
806
807
808
809
810

811
812
813
814
815
816
817
818
  idxCols = 0;
  for(pTerm=pWC->a; pTerm<pWCEnd; pTerm++){
    Expr *pExpr = pTerm->pExpr;
    /* Make the automatic index a partial index if there are terms in the
    ** WHERE clause (or the ON clause of a LEFT join) that constrain which
    ** rows of the target table (pSrc) that can be used. */
    if( (pTerm->wtFlags & TERM_VIRTUAL)==0

     && sqlite3ExprIsTableConstraint(pExpr, pSrc)
    ){
      pPartial = sqlite3ExprAnd(pParse, pPartial,
                                sqlite3ExprDup(pParse->db, pExpr, 0));
    }
    if( termCanDriveIndex(pTerm, pSrc, notReady) ){
      int iCol;
      Bitmask cMask;
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
    sqlite3VdbeAddOp2(v, OP_Blob, (int)sz, pLevel->regFilter);

    addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, iCur); VdbeCoverage(v);
    pWCEnd = &pWInfo->sWC.a[pWInfo->sWC.nTerm];
    for(pTerm=pWInfo->sWC.a; pTerm<pWCEnd; pTerm++){
      Expr *pExpr = pTerm->pExpr;
      if( (pTerm->wtFlags & TERM_VIRTUAL)==0
       && sqlite3ExprIsTableConstant(pExpr, iCur)
      ){
        sqlite3ExprIfFalse(pParse, pTerm->pExpr, addrCont, SQLITE_JUMPIFNULL);
      }
    }
    if( pLoop->wsFlags & WHERE_IPK ){
      int r1 = sqlite3GetTempReg(pParse);
      sqlite3VdbeAddOp2(v, OP_Rowid, iCur, r1);







|







1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
    sqlite3VdbeAddOp2(v, OP_Blob, (int)sz, pLevel->regFilter);

    addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, iCur); VdbeCoverage(v);
    pWCEnd = &pWInfo->sWC.a[pWInfo->sWC.nTerm];
    for(pTerm=pWInfo->sWC.a; pTerm<pWCEnd; pTerm++){
      Expr *pExpr = pTerm->pExpr;
      if( (pTerm->wtFlags & TERM_VIRTUAL)==0
       && sqlite3ExprIsTableConstraint(pExpr, pItem)
      ){
        sqlite3ExprIfFalse(pParse, pTerm->pExpr, addrCont, SQLITE_JUMPIFNULL);
      }
    }
    if( pLoop->wsFlags & WHERE_IPK ){
      int r1 = sqlite3GetTempReg(pParse);
      sqlite3VdbeAddOp2(v, OP_Rowid, iCur, r1);

Changes to test/autoindex1.test.

538
539
540
541
542
543
544
545

546















547
548
  INSERT INTO t11 VALUES(NULL);
  INSERT INTO t12 VALUES('notnull');
}
do_execsql_test autoindex1-1020 {
  SELECT count(*) FROM t11 LEFT JOIN t12 WHERE t12.y IS t11.w;
} 0




















finish_test







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


538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
  INSERT INTO t11 VALUES(NULL);
  INSERT INTO t12 VALUES('notnull');
}
do_execsql_test autoindex1-1020 {
  SELECT count(*) FROM t11 LEFT JOIN t12 WHERE t12.y IS t11.w;
} 0

# 2022-04-25
# https://sqlite.org/forum/forumpost/0d3200f4f3bcd3a3
#
reset_db
do_execsql_test autoindex-1100 {
  CREATE TABLE t1(a INT, b INT);
  CREATE TABLE t2(c INT, d INT);
  CREATE TABLE t3(e TEXT, f TEXT);
  INSERT INTO t1 VALUES(1, 1);
  INSERT INTO t2 VALUES(1, 2);
  INSERT INTO t3 VALUES('abc', 'def');
} {}
do_execsql_test autoindex-1110 {
  SELECT * FROM t1, t2 LEFT JOIN t3 ON (t2.d=1) WHERE t2.c = +t1.a;
} {1 1 1 2 {} {}}
do_execsql_test autoindex-1120 {
  SELECT * FROM t1 LEFT JOIN t2 ON (t2.c=+t1.a) LEFT JOIN t3 ON (t2.d IS NULL);
} {1 1 1 2 {} {}}

finish_test