-C Set\sthe\sdefault\smaximum\spage\ssize\sto\s32768,\snot\s8192.\s(CVS\s2724)
-D 2005-09-19T19:05:21
+C ON-clause\sterms\sin\sa\sLEFT\sJOIN\sthat\srestrict\sonly\sthe\sleft\stable,\sshould\snot\nreally\srestrict\sthe\sleft\stable\sbut\sinstead\srows\sthat\sfail\sto\smeet\sthe\scondition\nto\sbe\sjoined\swith\sNULL\srows\sfrom\sthe\sright\stable.\s(CVS\s2725)
+D 2005-09-19T21:05:49
F Makefile.in 12784cdce5ffc8dfb707300c34e4f1eb3b8a14f1
F Makefile.linux-gcc 06be33b2a9ad4f005a5f42b22c4a19dab3cbb5c7
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
F src/prepare.c fc098db25d2a121affb08686cf04833fd50452d4
F src/printf.c bd421c1ad5e01013c89af63c60eab02852ccd15e
F src/random.c 90adff4e73a3b249eb4f1fc2a6ff9cf78c7233a4
-F src/select.c 459fb935f1b3f6f0011c548a7664b4d7d062a041
+F src/select.c c3fe1994da81df0e09c4604ef75180f249cabe10
F src/shell.c 3596c1e559b82663057940d19ba533ad421c7dd3
F src/sqlite.h.in 461b2535550cf77aedfd44385da11ef7d63e57a2
-F src/sqliteInt.h f59e1ceccfca73737016b8912ac5f23995dd40c6
+F src/sqliteInt.h 53daa72541b4336c5e89773cf39717ed695bd523
F src/table.c 25b3ff2b39b7d87e8d4a5da0713d68dfc06cbee9
F src/tclsqlite.c ac94682f9e601dd373912c46414a5a842db2089a
F src/test1.c 0f1a66f65a54fba029f7e93b7500d49443dc959b
F src/vdbeaux.c 57a6ced8417bdc6f06c391d9c560ecbbed644ef3
F src/vdbefifo.c 9efb94c8c3f4c979ebd0028219483f88e57584f5
F src/vdbemem.c fea0744936008831daa17cdc75056c3ca1469690
-F src/where.c 728051085e8c782370a00ab36b494a244b1e9f4e
+F src/where.c 2b7b4dd112a027021d9c53e25d221761d572a925
F tclinstaller.tcl 046e3624671962dc50f0481d7c25b38ef803eb42
F test/all.test 7f0988442ab811dfa41793b5b550f5828ce316f3
F test/alter.test 9d6837a3d946b73df692b7cef2a7644d2e2f6bc6
F test/join2.test f2171c265e57ee298a27e57e7051d22962f9f324
F test/join3.test 6f0c774ff1ba0489e6c88a3e77b9d3528fb4fda0
F test/join4.test 1a352e4e267114444c29266ce79e941af5885916
+F test/join5.test 2646825693a6e066ea89b498176d4a68df45ab68
F test/journal1.test 36f2d1bb9bf03f790f43fbdb439e44c0657fab19
F test/lastinsert.test eaa89c6ee1f13062d87139fd32c1e56753d2fd89
F test/laststmtchanges.test 19a6d0c11f7a31dc45465b495f7b845a62cbec17
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
F www/version3.tcl a99cf5f6d8bd4d5537584a2b342f0fb9fa601d8b
F www/whentouse.tcl 97e2b5cd296f7d8057e11f44427dea8a4c2db513
-P 6cc57fcf15cfa3ce73c78b1cac90f7806e5bae40
-R 263668ef8fd093a2fb233495f6df04ab
+P b32e9ec2480f9da2c2ea705ed3c88ca77b77cf2a
+R 30beedb46fba1ce2f76a3f1396f53cb5
U drh
-Z dfe987a06f47431345e9f24e1070f391
+Z a986dad9151bb581e7854782adc6d5e8
-b32e9ec2480f9da2c2ea705ed3c88ca77b77cf2a
\ No newline at end of file
+ea10f9785e3c5248dafcc297f3a2c5465b6e0dba
\ No newline at end of file
** This file contains C code routines that are called by the parser
** to handle SELECT statements in SQLite.
**
-** $Id: select.c,v 1.271 2005/09/19 17:35:53 drh Exp $
+** $Id: select.c,v 1.272 2005/09/19 21:05:49 drh Exp $
*/
#include "sqliteInt.h"
const char *zAlias1, /* Alias for first table. May be NULL */
const Table *pTab2, /* Second table */
const char *zAlias2, /* Alias for second table. May be NULL */
+ int iRightJoinTable, /* VDBE cursor for the right table */
Expr **ppExpr /* Add the equality term to this expression */
){
Expr *pE1a, *pE1b, *pE1c;
pE2c = sqlite3Expr(TK_DOT, pE2b, pE2a, 0);
pE = sqlite3Expr(TK_EQ, pE1c, pE2c, 0);
ExprSetProperty(pE, EP_FromJoin);
+ pE->iRightJoinTable = iRightJoinTable;
*ppExpr = sqlite3ExprAnd(*ppExpr, pE);
}
/*
** Set the EP_FromJoin property on all terms of the given expression.
+** And set the Expr.iRightJoinTable to iTable for every term in the
+** expression.
**
** The EP_FromJoin property is used on terms of an expression to tell
** the LEFT OUTER JOIN processing logic that this term is part of the
** of the more general WHERE clause. These terms are moved over to the
** WHERE clause during join processing but we need to remember that they
** originated in the ON or USING clause.
+**
+** The Expr.iRightJoinTable tells the WHERE clause processing that the
+** expression depends on table iRightJoinTable even if that table is not
+** explicitly mentioned in the expression. That information is needed
+** for cases like this:
+**
+** SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.b AND t1.x=5
+**
+** The where clause needs to defer the handling of the t1.x=5
+** term until after the t2 loop of the join. In that way, a
+** NULL t2 row will be inserted whenever t1.x!=5. If we do not
+** defer the handling of t1.x=5, it will be processed immediately
+** after the t1 loop and rows with t1.x!=5 will never appear in
+** the output, which is incorrect.
*/
-static void setJoinExpr(Expr *p){
+static void setJoinExpr(Expr *p, int iTable){
while( p ){
ExprSetProperty(p, EP_FromJoin);
- setJoinExpr(p->pLeft);
+ p->iRightJoinTable = iTable;
+ setJoinExpr(p->pLeft, iTable);
p = p->pRight;
}
}
char *zName = pLeftTab->aCol[j].zName;
if( columnIndex(pRightTab, zName)>=0 ){
addWhereTerm(zName, pLeftTab, pLeft->zAlias,
- pRightTab, pRight->zAlias, &p->pWhere);
+ pRightTab, pRight->zAlias,
+ pRight->iCursor, &p->pWhere);
+
}
}
}
** an AND operator.
*/
if( pLeft->pOn ){
- setJoinExpr(pLeft->pOn);
+ setJoinExpr(pLeft->pOn, pRight->iCursor);
p->pWhere = sqlite3ExprAnd(p->pWhere, pLeft->pOn);
pLeft->pOn = 0;
}
return 1;
}
addWhereTerm(zName, pLeftTab, pLeft->zAlias,
- pRightTab, pRight->zAlias, &p->pWhere);
+ pRightTab, pRight->zAlias,
+ pRight->iCursor, &p->pWhere);
}
}
}
*************************************************************************
** Internal interface definitions for SQLite.
**
-** @(#) $Id: sqliteInt.h,v 1.420 2005/09/19 17:35:53 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.421 2005/09/19 21:05:49 drh Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_
** iColumn-th field of the iTable-th table. */
AggInfo *pAggInfo; /* Used by TK_AGG_COLUMN and TK_AGG_FUNCTION */
int iAgg; /* Which entry in pAggInfo->aCol[] or ->aFunc[] */
+ int iRightJoinTable; /* If EP_FromJoin, the right table of the join */
Select *pSelect; /* When the expression is a sub-select. Also the
** right side of "<expr> IN (<select>)" */
Table *pTab; /* Table for OP_Column expressions. */
** so is applicable. Because this module is responsible for selecting
** indices, you might also think of this module as the "query optimizer".
**
-** $Id: where.c,v 1.176 2005/09/19 13:15:23 drh Exp $
+** $Id: where.c,v 1.177 2005/09/19 21:05:49 drh Exp $
*/
#include "sqliteInt.h"
}else{
pTerm->prereqRight = exprTableUsage(pMaskSet, pExpr->pRight);
}
- pTerm->prereqAll = prereqAll = exprTableUsage(pMaskSet, pExpr);
+ prereqAll = exprTableUsage(pMaskSet, pExpr);
+ if( ExprHasProperty(pExpr, EP_FromJoin) ){
+ prereqAll |= getMask(pMaskSet, pExpr->iRightJoinTable);
+ }
+ pTerm->prereqAll = prereqAll;
pTerm->leftCursor = -1;
pTerm->iParent = -1;
pTerm->operator = 0;
if( allowedOp(pExpr->op) && (pTerm->prereqRight & prereqLeft)==0 ){
Expr *pLeft = pExpr->pLeft;
Expr *pRight = pExpr->pRight;
- assert( prereqAll == (pTerm->prereqRight | prereqLeft) ); /* ticket 1433 */
if( pLeft->op==TK_COLUMN ){
pTerm->leftCursor = pLeft->iTable;
pTerm->leftColumn = pLeft->iColumn;
--- /dev/null
+# 2005 September 19
+#
+# The author disclaims copyright to this source code. In place of
+# a legal notice, here is a blessing:
+#
+# May you do good and not evil.
+# May you find forgiveness for yourself and forgive others.
+# May you share freely, never taking more than you give.
+#
+#***********************************************************************
+# This file implements regression tests for SQLite library.
+#
+# This file implements tests for left outer joins containing ON
+# clauses that restrict the scope of the left term of the join.
+#
+# $Id: join5.test,v 1.1 2005/09/19 21:05:50 drh Exp $
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+
+
+do_test join5-1.1 {
+ execsql {
+ BEGIN;
+ CREATE TABLE t1(a integer primary key, b integer, c integer);
+ CREATE TABLE t2(x integer primary key, y);
+ CREATE TABLE t3(p integer primary key, q);
+ INSERT INTO t3 VALUES(11,'t3-11');
+ INSERT INTO t3 VALUES(12,'t3-12');
+ INSERT INTO t2 VALUES(11,'t2-11');
+ INSERT INTO t2 VALUES(12,'t2-12');
+ INSERT INTO t1 VALUES(1, 5, 0);
+ INSERT INTO t1 VALUES(2, 11, 2);
+ INSERT INTO t1 VALUES(3, 12, 1);
+ COMMIT;
+ }
+} {}
+do_test join5-1.2 {
+ execsql {
+ select * from t1 left join t2 on t1.b=t2.x and t1.c=1
+ }
+} {1 5 0 {} {} 2 11 2 {} {} 3 12 1 12 t2-12}
+do_test join5-1.3 {
+ execsql {
+ select * from t1 left join t2 on t1.b=t2.x where t1.c=1
+ }
+} {3 12 1 12 t2-12}
+do_test join5-1.4 {
+ execsql {
+ select * from t1 left join t2 on t1.b=t2.x and t1.c=1
+ left join t3 on t1.b=t3.p and t1.c=2
+ }
+} {1 5 0 {} {} {} {} 2 11 2 {} {} 11 t3-11 3 12 1 12 t2-12 {} {}}
+do_test join5-1.5 {
+ execsql {
+ select * from t1 left join t2 on t1.b=t2.x and t1.c=1
+ left join t3 on t1.b=t3.p where t1.c=2
+ }
+} {2 11 2 {} {} 11 t3-11}
+
+
+finish_test