SQLite

Check-in [1783655e]
Login

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

Overview
Comment:Avoid assuming that an expression in an ON() clause that evaluates to zero implies that the query will return zero rows when the query contains a RIGHT JOIN. Forum Post 95849acbe1.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 1783655ea422185e75593b89e4ef452a6f5496aefd389f88ce7fe4b7d41d6a98
User & Date: dan 2023-04-25 14:37:12
References
2023-05-10
00:33
New restriction on the push-down optimization to prevent an ON or USING clause on the left side of a RIGHT JOIN from being pushed down into a subquery that is on the right side of that RIGHT JOIN. Forum post a7d4be7fb6. This is similar to an earlier problem fixed at [1783655ea422185e]. Also add comments to describe previously undocumented push-down optimization restrictions. (check-in: da3fba18 user: drh tags: trunk)
2023-04-25
14:54
Remove unused variable ltoj accidentally added by [1783655e]. (check-in: faa1575c user: dan tags: trunk)
Context
2023-04-25
15:12
If an ON clause to the left of a RIGHT JOIN is false, that does not imply that the query returns no rows. (Leaf check-in: 4011b9d3 user: drh tags: branch-3.41)
14:54
Remove unused variable ltoj accidentally added by [1783655e]. (check-in: faa1575c user: dan tags: trunk)
14:37
Avoid assuming that an expression in an ON() clause that evaluates to zero implies that the query will return zero rows when the query contains a RIGHT JOIN. Forum Post 95849acbe1. (check-in: 1783655e user: dan tags: trunk)
04:28
Handle newline-trimmed input TEXT correctly in base64, base85 UDFs, an issue exposed in forum post 8d6ed893c0. (check-in: 8f637aae user: larrybr tags: trunk)
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/where.c.

5978
5979
5980
5981
5982
5983
5984


5985
5986

5987
5988





5989
5990

5991
5992
5993
5994






5995
5996
5997


5998




5999



6000
6001
6002
6003
6004
6005
6006
6007
  /* Analyze all of the subexpressions. */
  sqlite3WhereExprAnalyze(pTabList, &pWInfo->sWC);
  if( pSelect && pSelect->pLimit ){
    sqlite3WhereAddLimit(&pWInfo->sWC, pSelect);
  }
  if( pParse->nErr ) goto whereBeginError;



  /* Special case: WHERE terms that do not refer to any tables in the join
  ** (constant expressions). Evaluate each such term, and jump over all the

  ** generated code if the result is not true.  
  **





  ** Do not do this if the expression contains non-deterministic functions
  ** that are not within a sub-select. This is not strictly required, but

  ** preserves SQLite's legacy behaviour in the following two cases:
  **
  **   FROM ... WHERE random()>0;           -- eval random() once per row
  **   FROM ... WHERE (SELECT random())>0;  -- eval random() once overall






  */
  for(ii=0; ii<sWLB.pWC->nBase; ii++){
    WhereTerm *pT = &sWLB.pWC->a[ii];


    if( pT->wtFlags & TERM_VIRTUAL ) continue;




    if( pT->prereqAll==0 && (nTabList==0 || exprIsDeterministic(pT->pExpr)) ){



      sqlite3ExprIfFalse(pParse, pT->pExpr, pWInfo->iBreak, SQLITE_JUMPIFNULL);
      pT->wtFlags |= TERM_CODED;
    }
  }

  if( wctrlFlags & WHERE_WANT_DISTINCT ){
    if( OptimizationDisabled(db, SQLITE_DistinctOpt) ){
      /* Disable the DISTINCT optimization if SQLITE_DistinctOpt is set via







>
>
|
|
>
|

>
>
>
>
>
|
|
>
|

|
|
>
>
>
>
>
>


|
>
>

>
>
>
>
|
>
>
>
|







5978
5979
5980
5981
5982
5983
5984
5985
5986
5987
5988
5989
5990
5991
5992
5993
5994
5995
5996
5997
5998
5999
6000
6001
6002
6003
6004
6005
6006
6007
6008
6009
6010
6011
6012
6013
6014
6015
6016
6017
6018
6019
6020
6021
6022
6023
6024
6025
6026
6027
6028
6029
6030
6031
  /* Analyze all of the subexpressions. */
  sqlite3WhereExprAnalyze(pTabList, &pWInfo->sWC);
  if( pSelect && pSelect->pLimit ){
    sqlite3WhereAddLimit(&pWInfo->sWC, pSelect);
  }
  if( pParse->nErr ) goto whereBeginError;

  /* The False-WHERE-Term-Bypass optimization:
  **
  ** If there are WHERE terms that are false, then no rows will be output,
  ** so skip over all of the code generated here.
  **
  ** Conditions:
  **
  **   (1)  The WHERE term must not refer to any tables in the join.
  **   (2)  The term must not come from an ON clause on the
  **        right-hand side of a LEFT or FULL JOIN.
  **   (3)  The term must not come from an ON clause, or there must be
  **        no RIGHT or FULL OUTER joins in pTabList.
  **   (4)  If the expression contains non-deterministic functions
  **        that are not within a sub-select. This is not required
  **        for correctness but rather to preserves SQLite's legacy
  **        behaviour in the following two cases:
  **
  **          WHERE random()>0;           -- eval random() once per row
  **          WHERE (SELECT random())>0;  -- eval random() just once overall
  **
  ** Note that the Where term need not be a constant in order for this
  ** optimization to apply, though it does need to be constant relative to
  ** the current subquery (condition 1).  The term might include variables
  ** from outer queries so that the value of the term changes from one
  ** invocation of the current subquery to the next.
  */
  for(ii=0; ii<sWLB.pWC->nBase; ii++){
    WhereTerm *pT = &sWLB.pWC->a[ii];  /* A term of the WHERE clause */
    Expr *pX;                          /* The expression of pT */
    int ltoj;                          /* Left table of the join */
    if( pT->wtFlags & TERM_VIRTUAL ) continue;
    pX = pT->pExpr;
    assert( pX!=0 );
    assert( pT->prereqAll!=0 || !ExprHasProperty(pX, EP_OuterON) );
    if( pT->prereqAll==0                           /* Conditions (1) and (2) */
     && (nTabList==0 || exprIsDeterministic(pX))   /* Condition (4) */
     && !(ExprHasProperty(pX, EP_InnerON)          /* Condition (3) */
          && (pTabList->a[0].fg.jointype & JT_LTORJ)!=0 )
    ){
      sqlite3ExprIfFalse(pParse, pX, pWInfo->iBreak, SQLITE_JUMPIFNULL);
      pT->wtFlags |= TERM_CODED;
    }
  }

  if( wctrlFlags & WHERE_WANT_DISTINCT ){
    if( OptimizationDisabled(db, SQLITE_DistinctOpt) ){
      /* Disable the DISTINCT optimization if SQLITE_DistinctOpt is set via

Changes to test/joinH.test.

85
86
87
88
89
90
91






























92
93
  CREATE INDEX i1 ON t1( (d IS NULL), d );
}

do_execsql_test 4.4 {
  SELECT (d IS NULL) FROM t1 RIGHT JOIN t2 ON (j=33);
} {1}
































finish_test







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


85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
  CREATE INDEX i1 ON t1( (d IS NULL), d );
}

do_execsql_test 4.4 {
  SELECT (d IS NULL) FROM t1 RIGHT JOIN t2 ON (j=33);
} {1}

#-------------------------------------------------------------------------
#
reset_db
do_execsql_test 5.0 {
  CREATE TABLE t0(w);
  CREATE TABLE t1(x);
  CREATE TABLE t2(y);
  CREATE TABLE t3(z);
  INSERT INTO t3 VALUES('t3val');
}

do_execsql_test 5.1 {
  SELECT * FROM t1 INNER JOIN t2 ON (0) RIGHT OUTER JOIN t3;
} {{} {} t3val}

do_execsql_test 5.2 {
  SELECT * FROM t1 INNER JOIN t2 ON (0) FULL OUTER JOIN t3;
} {{} {} t3val}

do_execsql_test 5.3 {
  SELECT * FROM t3 LEFT JOIN t2 ON (0);
} {t3val {}}

do_execsql_test 5.4 {
  SELECT * FROM t0 RIGHT JOIN t1 INNER JOIN t2 ON (0) RIGHT JOIN t3
} {{} {} {} t3val}

do_execsql_test 5.5 {
  SELECT * FROM t0 RIGHT JOIN t1 INNER JOIN t2 ON (0)
} {}

finish_test