]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Make a distinction between (1) WHERE clause constraints, (2) ON/USING
authordrh <>
Mon, 11 Apr 2022 12:38:06 +0000 (12:38 +0000)
committerdrh <>
Mon, 11 Apr 2022 12:38:06 +0000 (12:38 +0000)
constraints on outer joins, and (3) ON/USING clause constraints on inner
joins.  Formerly, there was no distinctionb between 1 and 3, but RIGHT JOIN
needs to know the difference.  Make RIGHT JOIN aware of this difference and
add test cases.

FossilOrigin-Name: 0f6f61c3664cc87209c2a6f9b6df3a750d1510723fcde209c33db8feaf48bcf3

manifest
manifest.uuid
src/select.c
src/sqliteInt.h
src/where.c
src/whereexpr.c
test/join7.test

index 1ac8ab2ca06ec33cc75977d545e2150885bb7e81..235ea5152de5441ec935bc18e7d950fe0638199f 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Fix\ssome\scomments\sthat\srefer\sto\sLEFT\sJOIN\sthat\sshould\srefer\sto\sOUTER\sJOIN.\nNo\schanges\sto\scode.
-D 2022-04-11T11:59:25.896
+C Make\sa\sdistinction\sbetween\s(1)\sWHERE\sclause\sconstraints,\s(2)\sON/USING\nconstraints\son\souter\sjoins,\sand\s(3)\sON/USING\sclause\sconstraints\son\sinner\njoins.\s\sFormerly,\sthere\swas\sno\sdistinctionb\sbetween\s1\sand\s3,\sbut\sRIGHT\sJOIN\nneeds\sto\sknow\sthe\sdifference.\s\sMake\sRIGHT\sJOIN\saware\sof\sthis\sdifference\sand\nadd\stest\scases.
+D 2022-04-11T12:38:06.753
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -552,12 +552,12 @@ F src/printf.c 05d8dfd2018bc4fc3ddb8b37eb97ccef7abf985643fa1caebdcf2916ca90fa32
 F src/random.c 097dc8b31b8fba5a9aca1697aeb9fd82078ec91be734c16bffda620ced7ab83c
 F src/resolve.c 7110fc3b5a4dec5d11559141c1906c4a125349fb602f541b05db3a3d448d4b95
 F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92
-F src/select.c 178edb7fc4e6f5dabbd9c3755eb601151af78eaf69af73cc6bfe8195121c3d41
+F src/select.c 41d1b171d123a98bff4a2ddbe5ef7c47324274ca967030615506c4e246e96c12
 F src/shell.c.in eb7f10d5e2c47bd014d92ec5db1def21fcc1ed56ffaaa4ee715b6c37c370b47f
 F src/sqlite.h.in 2a35f62185eb5e7ecc64a2f68442b538ce9be74f80f28a00abc24837edcf1c17
 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
 F src/sqlite3ext.h f49e28c25bd941e79794db5415fdf7b202deb3bc072ed6f1ed273d578703684e
-F src/sqliteInt.h 8a804f402410b06958bf6376daa91f11e2667ebd60e149eb5a371654a71ce448
+F src/sqliteInt.h fa220cb1b04ae45fa34de634efec4c04ce668ddcb6316c8f3260a8cf1a31310b
 F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657
 F src/status.c 4a3da6d77eeb3531cb0dbdf7047772a2a1b99f98c69e90ce009c75fe6328b2c0
 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
@@ -639,10 +639,10 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
 F src/wal.c b9df133a705093da8977da5eb202eaadb844839f1c7297c08d33471f5491843d
 F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a
 F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b
-F src/where.c e05c2c85a894d0175983241789344e48ed134f79bb84adda23a6bff53c39cf42
+F src/where.c 8d8e54e2e29ac503ac5824cac0d368a9a45b0a2a3f129b0f2d50a1e3a891c62f
 F src/whereInt.h ecf0d9fe3e35f2546e660c6389e56aedb6fd2434e31a0449b261ff55ebc6df2d
 F src/wherecode.c 808e94b66f1bf052cbb77665ba08625ba93fbb0c343fe0ecafdfdd264bf0c6c9
-F src/whereexpr.c d79dd55b6ad4d072c16838e9709d7b144c321e463ebd216de224821c06bc1fd3
+F src/whereexpr.c 174d4ad5be165c610c907abb779ef4a97974d22b84e1ce7898d2d9f6947249e5
 F src/window.c 42a71595263dbd8ef8248218e4fc7d4b5ddccece52146ad48e079342d93f6f8f
 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
 F test/affinity2.test ce1aafc86e110685b324e9a763eab4f2a73f737842ec3b687bd965867de90627
@@ -1146,7 +1146,7 @@ F test/join3.test 6f0c774ff1ba0489e6c88a3e77b9d3528fb4fda0
 F test/join4.test 1a352e4e267114444c29266ce79e941af5885916
 F test/join5.test 0d63c7e43b3160b9d4b93f196ef83b6efc7751b9edd0d18c53a46fbec7a49cfc
 F test/join6.test f809c025fa253f9e150c0e9afd4cef8813257bceeb6f46e04041228c9403cc2c
-F test/join7.test 059f7ab42737fbd835dfc791354f1b182585566b540b013f3ed46bfa1e80ba42
+F test/join7.test 87f08f814012b4593a7b6021ebfbcc0d2c837045cad012a3a38e810182fe268a
 F test/journal1.test c7b768041b7f494471531e17abc2f4f5ebf9e5096984f43ed17c4eb80ba34497
 F test/journal2.test 9dac6b4ba0ca79c3b21446bbae993a462c2397c4
 F test/journal3.test 7c3cf23ffc77db06601c1fcfc9743de8441cb77db9d1aa931863d94f5ffa140e
@@ -1946,8 +1946,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 29927926eb32acd963e2c496ad67d55177615ec4150fd218afaf2f9a730cabec
-R 6a36a3a28fad2aa38e4b5d7c8bda927a
+P 5be5ede5cca1cd5ef863fe0feb2b4a990f4a42865281a6c2e4eb816f48847dc6
+R 9c8f191b416653ff62ae70d11a61358b
 U drh
-Z 390b95acc02a593d1c52fcc716321c1e
+Z e1bd204470110fd5d9bea7467b9ac13a
 # Remove this line to create a well-formed Fossil manifest.
index 11566ff6d24fc84d5bab58e2a8b7c61e0f31327b..41dbfa450df8748367b8648b297be6c761c59b0d 100644 (file)
@@ -1 +1 @@
-5be5ede5cca1cd5ef863fe0feb2b4a990f4a42865281a6c2e4eb816f48847dc6
\ No newline at end of file
+0f6f61c3664cc87209c2a6f9b6df3a750d1510723fcde209c33db8feaf48bcf3
\ No newline at end of file
index 3e4f783a3384b5837195155ffcd9640c68a25872..79ff500f41cf411fbf7a1f38414e123605f9b87c 100644 (file)
@@ -373,7 +373,7 @@ static void addWhereTerm(
   int iColLeft,                   /* Index of column in first table */
   int iRight,                     /* Index of second table in pSrc */
   int iColRight,                  /* Index of column in second table */
-  int isOuterJoin,                /* True if this is an OUTER join */
+  u32 joinType,                   /* EP_FromJoin or EP_InnerJoin */
   Expr **ppWhere                  /* IN/OUT: The WHERE clause to add to */
 ){
   sqlite3 *db = pParse->db;
@@ -393,8 +393,8 @@ static void addWhereTerm(
   assert( pE2!=0 || pEq==0 );  /* Due to db->mallocFailed test
                                ** in sqlite3DbMallocRawNN() called from
                                ** sqlite3PExpr(). */
-  if( pEq && isOuterJoin ){
-    ExprSetProperty(pEq, EP_FromJoin);
+  if( pEq ){
+    ExprSetProperty(pEq, joinType);
     assert( !ExprHasProperty(pEq, EP_TokenOnly|EP_Reduced) );
     ExprSetVVAProperty(pEq, EP_NoReduce);
     pEq->w.iJoin = pE2->iTable;
@@ -428,9 +428,10 @@ static void addWhereTerm(
 ** after the t1 loop and rows with t1.x!=5 will never appear in
 ** the output, which is incorrect.
 */
-void sqlite3SetJoinExpr(Expr *p, int iTable){
+void sqlite3SetJoinExpr(Expr *p, int iTable, u32 joinFlag){
+  assert( joinFlag==EP_FromJoin || joinFlag==EP_InnerJoin );
   while( p ){
-    ExprSetProperty(p, EP_FromJoin);
+    ExprSetProperty(p, joinFlag);
     assert( !ExprHasProperty(p, EP_TokenOnly|EP_Reduced) );
     ExprSetVVAProperty(p, EP_NoReduce);
     p->w.iJoin = iTable;
@@ -439,11 +440,11 @@ void sqlite3SetJoinExpr(Expr *p, int iTable){
       if( p->x.pList ){
         int i;
         for(i=0; i<p->x.pList->nExpr; i++){
-          sqlite3SetJoinExpr(p->x.pList->a[i].pExpr, iTable);
+          sqlite3SetJoinExpr(p->x.pList->a[i].pExpr, iTable, joinFlag);
         }
       }
     }
-    sqlite3SetJoinExpr(p->pLeft, iTable);
+    sqlite3SetJoinExpr(p->pLeft, iTable, joinFlag);
     p = p->pRight;
   } 
 }
@@ -459,6 +460,7 @@ static void unsetJoinExpr(Expr *p, int iTable){
     if( ExprHasProperty(p, EP_FromJoin)
      && (iTable<0 || p->w.iJoin==iTable) ){
       ExprClearProperty(p, EP_FromJoin);
+      ExprSetProperty(p, EP_InnerJoin);
     }
     if( p->op==TK_COLUMN && p->iTable==iTable ){
       ExprClearProperty(p, EP_CanBeNull);
@@ -502,10 +504,10 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){
   pRight = &pLeft[1];
   for(i=0; i<pSrc->nSrc-1; i++, pRight++, pLeft++){
     Table *pRightTab = pRight->pTab;
-    int isOuter;
+    u32 joinType;
 
     if( NEVER(pLeft->pTab==0 || pRightTab==0) ) continue;
-    isOuter = (pRight->fg.jointype & JT_OUTER)!=0;
+    joinType = (pRight->fg.jointype & JT_OUTER)!=0 ? EP_FromJoin : EP_InnerJoin;
 
     /* When the NATURAL keyword is present, add WHERE clause terms for
     ** every column that the two tables have in common.
@@ -525,7 +527,7 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){
         zName = pRightTab->aCol[j].zCnName;
         if( tableAndColumnIndex(pSrc, i+1, zName, &iLeft, &iLeftCol, 1) ){
           addWhereTerm(pParse, pSrc, iLeft, iLeftCol, i+1, j,
-                isOuter, &p->pWhere);
+                joinType, &p->pWhere);
         }
       }
     }
@@ -556,7 +558,7 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){
           return 1;
         }
         addWhereTerm(pParse, pSrc, iLeft, iLeftCol, i+1, iRightCol,
-                     isOuter, &p->pWhere);
+                     joinType, &p->pWhere);
       }
     }
 
@@ -564,7 +566,7 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){
     ** an AND operator.
     */
     else if( pRight->u3.pOn ){
-      if( isOuter ) sqlite3SetJoinExpr(pRight->u3.pOn, pRight->iCursor);
+      sqlite3SetJoinExpr(pRight->u3.pOn, pRight->iCursor, joinType);
       p->pWhere = sqlite3ExprAnd(pParse, p->pWhere, pRight->u3.pOn);
       pRight->u3.pOn = 0;
     }
@@ -3724,8 +3726,9 @@ static Expr *substExpr(
         if( pSubst->isLeftJoin ){
           ExprSetProperty(pNew, EP_CanBeNull);
         }
-        if( ExprHasProperty(pExpr,EP_FromJoin) ){
-          sqlite3SetJoinExpr(pNew, pExpr->w.iJoin);
+        if( ExprHasProperty(pExpr,EP_FromJoin|EP_InnerJoin) ){
+          sqlite3SetJoinExpr(pNew, pExpr->w.iJoin,
+                             pExpr->flags & (EP_FromJoin|EP_InnerJoin));
         }
         sqlite3ExprDelete(db, pExpr);
         pExpr = pNew;
@@ -4452,7 +4455,7 @@ static int flattenSubquery(
     pWhere = pSub->pWhere;
     pSub->pWhere = 0;
     if( isLeftJoin>0 ){
-      sqlite3SetJoinExpr(pWhere, iNewParent);
+      sqlite3SetJoinExpr(pWhere, iNewParent, EP_FromJoin);
     }
     if( pWhere ){
       if( pParent->pWhere ){
index 7f8a8e015176c5d329546bc0068934c89d14adbd..b9eb970c7a8779bfa10507da554c3f540b0cc459 100644 (file)
@@ -2887,7 +2887,7 @@ struct Expr {
 #define EP_ConstFunc  0x080000 /* A SQLITE_FUNC_CONSTANT or _SLOCHNG function */
 #define EP_CanBeNull  0x100000 /* Can be null despite NOT NULL constraint */
 #define EP_Subquery   0x200000 /* Tree contains a TK_SELECT operator */
-                 /*   0x400000 // Available */
+#define EP_InnerJoin  0x400000 /* Originates in ON/USING of an inner join */
 #define EP_Leaf       0x800000 /* Expr.pLeft, .pRight, .u.pSelect all NULL */
 #define EP_WinFunc   0x1000000 /* TK_FUNCTION with Expr.y.pWin set */
 #define EP_Subrtn    0x2000000 /* Uses Expr.y.sub. TK_IN, _SELECT, or _EXISTS */
@@ -4829,7 +4829,7 @@ void sqlite3MaterializeView(Parse*, Table*, Expr*, ExprList*,Expr*,int);
 
 int sqlite3JoinType(Parse*, Token*, Token*, Token*);
 int sqlite3ColumnIndex(Table *pTab, const char *zCol);
-void sqlite3SetJoinExpr(Expr*,int);
+void sqlite3SetJoinExpr(Expr*,int,u32);
 void sqlite3CreateForeignKey(Parse*, ExprList*, Token*, ExprList*, int);
 void sqlite3DeferForeignKey(Parse*, int);
 #ifndef SQLITE_OMIT_AUTHORIZATION
index 3fbe69e59331f13ecf70dc756a8150f9682c9c9c..1cd8f4ded8806849a7a88cb8feec576145b25c89 100644 (file)
@@ -6172,14 +6172,18 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
       WhereInfo *pSubWInfo;
       SrcList sFrom;
       Bitmask mAll = 0;
-      for(k=0; k<=i; k++){
+      for(k=0; k<i; k++){
+        int iIdxCur;
         mAll |= pWInfo->a[k].pWLoop->maskSelf;
+        iIdxCur = pWInfo->a[k].iIdxCur;
+        if( iIdxCur ) sqlite3VdbeAddOp1(v, OP_NullRow, iIdxCur);
       }
+      mAll |= pLoop->maskSelf;
       for(k=0; k<pWC->nTerm; k++){
         WhereTerm *pTerm = &pWC->a[k];
         if( pTerm->wtFlags & TERM_VIRTUAL ) break;
         if( pTerm->prereqAll & ~mAll ) continue;
-        if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) continue;
+        if( ExprHasProperty(pTerm->pExpr, EP_FromJoin|EP_InnerJoin) ) continue;
         pSubWhere = sqlite3ExprAnd(pParse, pSubWhere,
                                    sqlite3ExprDup(db, pTerm->pExpr, 0));
       }
index b622eed1b35eea8434cbd01b93beecc38efa4a0e..90c344806e47fd2905cde75a51e9686261104031 100644 (file)
@@ -1809,6 +1809,7 @@ void sqlite3WhereTabFuncArgs(
   if( pArgs==0 ) return;
   for(j=k=0; j<pArgs->nExpr; j++){
     Expr *pRhs;
+    u32 joinType;
     while( k<pTab->nCol && (pTab->aCol[k].colFlags & COLFLAG_HIDDEN)==0 ){k++;}
     if( k>=pTab->nCol ){
       sqlite3ErrorMsg(pParse, "too many arguments on %s() - max %d",
@@ -1826,8 +1827,11 @@ void sqlite3WhereTabFuncArgs(
         sqlite3ExprDup(pParse->db, pArgs->a[j].pExpr, 0), 0);
     pTerm = sqlite3PExpr(pParse, TK_EQ, pColRef, pRhs);
     if( pItem->fg.jointype & (JT_LEFT|JT_LTORJ) ){
-      sqlite3SetJoinExpr(pTerm, pItem->iCursor);
+      joinType = EP_FromJoin;
+    }else{
+      joinType = EP_InnerJoin;
     }
+    sqlite3SetJoinExpr(pTerm, pItem->iCursor, joinType);
     whereClauseInsert(pWC, pTerm, TERM_DYNAMIC);
   }
 }
index c1cd9ff6cbebe8873c9c6deeb19f236c9f752470..3b7d1f684e08f79d274f662c61e7466e20bb93db 100644 (file)
@@ -175,5 +175,16 @@ foreach {id schema} {
     1    3    NULL NULL
     1    4    NULL NULL
   }
+  do_execsql_test join7-$id.12 {
+    SELECT a, b, c, d
+      FROM t2 FULL OUTER JOIN t1 ON b=c AND d<=0 ORDER BY +b, +d;
+  } {
+    NULL NULL 3    33
+    NULL NULL 4    44
+    NULL NULL 5    55
+    1    2    NULL NULL
+    1    3    NULL NULL
+    1    4    NULL NULL
+  }
 }  
 finish_test