diff --git a/manifest b/manifest index 104ab04818..bcbe5aa229 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Correctly\shandle\scolumn\snames\sand\sstring\sconstants\sin\sparentheses.\nFix\sfor\sticket\s#179.\s(CVS\s770) -D 2002-10-22T23:38:04 +C Minimal\ssupport\sfor\soracle8\souter\sjoin\ssyntax.\s(CVS\s771) +D 2002-10-27T19:35:34 F Makefile.in d6c9a85c2a5e696843201d090dcf8bf2f8716f2a F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd @@ -34,27 +34,27 @@ F src/os.c ede7346dffdbab40c6de20d2f325981f3f1168fd F src/os.h 3009379b06941e7796a9812d1b6cbc59b26248c8 F src/pager.c 592e5931fdc65e952a6c3e152bc822580856532a F src/pager.h 6991c9c2dc5e4c7f2df4d4ba47d1c6458f763a32 -F src/parse.y e37e66aa0aee94d235058c7a7b7aaa71bb401324 +F src/parse.y 469c9636ff713e63c00234662209f11668671ae9 F src/printf.c 5c50fc1da75c8f5bf432b1ad17d91d6653acd167 F src/random.c 19e8e00fe0df32a742f115773f57651be327cabe -F src/select.c 4a6f3fb86a9e25f6c74ee95c5d0e26a0b8648592 +F src/select.c ce82596a2eaaf418edba45b2426f41065e49578b F src/shell.c 9e9a6eb6bca07f01e6472a603f908a0127ea50ff F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e F src/sqlite.h.in d3999a9c6374675779058d6cfe5431131618e92b -F src/sqliteInt.h 9a5fea861133f1913cfebd3bbbf6a4e9ace47fef +F src/sqliteInt.h a001c52dfb10ec38f18d6b9ed7dd8b3f42ca8c72 F src/table.c eed2098c9b577aa17f8abe89313a9c4413f57d63 F src/tclsqlite.c fa646506f02509455c1e4a878d1303bd2d4c3ead F src/test1.c a46e9f61915b32787c5d5a05a4b92e4dacc437d9 F src/test2.c 5fa694d130b3309e3f9c852f0a437750fcb5a006 F src/test3.c 540fa7fc3cb3732517b779b5f90ad9cc4303d0ab F src/threadtest.c 72bce0a284647314847bbea44616ceb056bfb77f -F src/tokenize.c 0000d3555af749cfc2d85f9686fdab82eedb77c4 +F src/tokenize.c 75e3bb37305b64e118e709752066f494c4f93c30 F src/trigger.c 5ba917fc226b96065108da28186c2efaec53e481 F src/update.c 881e4c8e7c786545da4fd2d95da19252b2e31137 F src/util.c ca7650ef2cc2d50241e48029fca109a3016144ee F src/vdbe.c b5d25c18f306cdb1da145dd555b056057920521f F src/vdbe.h b7584044223104ba7896a7f87b66daebdd6022ba -F src/where.c 8ff2acfcb9bb15a057512bd6207b259feed57a2c +F src/where.c 615a0f0bed305bcb27073c69347ea75018e8b58d F test/all.test efd958d048c70a3247997c482f0b33561f7759f0 F test/bigrow.test 8ab252dba108f12ad64e337b0f2ff31a807ac578 F test/btree.test 10e75aec120ecefc0edc4c912a0980a43db1b6c2 @@ -73,7 +73,7 @@ F test/insert.test a122afb86911e77c181d912348866a5b1a61eeab F test/insert2.test c288375a64dad3295044714f0dfed4a193cf067f F test/intpkey.test f3620158fd7963af1306b01047277f10ae91a30b F test/ioerr.test 57d9bffaca18b34f9e976f786eadc2591d6efc6a -F test/join.test 05d2cd1af855e3720e0465668d2923b228d29556 +F test/join.test 178b25dc3c5be6cbdd195b904e66bee62475d0bf F test/limit.test 9f26f874bc765df5b3f5c92d26d1b12eac6d4cf9 F test/lock.test 388a3a10962d2d571c0c1821cc35bf069ee73473 F test/main.test c66b564554b770ee7fdbf6a66c0cd90329bc2c85 @@ -149,7 +149,7 @@ F www/speed.tcl a20a792738475b68756ea7a19321600f23d1d803 F www/sqlite.tcl ae3dcfb077e53833b59d4fcc94d8a12c50a44098 F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331 F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218 -P 562da534bbb605a8ce15824135b012ef2d86bbeb -R df476aa0a67bb0f1bc7353bd04cb345e +P 3b68aa25c451b7c09ece457ac2b70a9a5d93508a +R f078ec26197d58bed051ed1d4802e2fc U drh -Z f9c703cf01e9f1a25c5301f84c45f9b9 +Z e77ead48c863ebb46d0070eee477e05f diff --git a/manifest.uuid b/manifest.uuid index 9e6c29e040..27dda7cc5f 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -3b68aa25c451b7c09ece457ac2b70a9a5d93508a \ No newline at end of file +31df3690d0fe4bd4a293cbe8ca9a26c98c3ed3ce \ No newline at end of file diff --git a/src/parse.y b/src/parse.y index e2dd57f5a4..d6f07ad65a 100644 --- a/src/parse.y +++ b/src/parse.y @@ -14,7 +14,7 @@ ** the parser. Lemon will also generate a header file containing ** numeric codes for all of the tokens. ** -** @(#) $Id: parse.y,v 1.84 2002/10/22 23:38:04 drh Exp $ +** @(#) $Id: parse.y,v 1.85 2002/10/27 19:35:34 drh Exp $ */ %token_prefix TK_ %token_type {Token} @@ -499,6 +499,7 @@ inscollist(A) ::= nm(Y). {A = sqliteIdListAppend(0,&Y);} %left STAR SLASH REM. %left CONCAT. %right UMINUS UPLUS BITNOT. +%right ORACLE_OUTER_JOIN. %type expr {Expr*} %destructor expr {sqliteExprDelete($$);} @@ -512,6 +513,8 @@ expr(A) ::= nm(X) DOT nm(Y). { Expr *temp2 = sqliteExpr(TK_ID, 0, 0, &Y); A = sqliteExpr(TK_DOT, temp1, temp2, 0); } +expr(A) ::= expr(B) ORACLE_OUTER_JOIN. + {A = B; ExprSetProperty(A,EP_Oracle8Join);} expr(A) ::= INTEGER(X). {A = sqliteExpr(TK_INTEGER, 0, 0, &X);} expr(A) ::= FLOAT(X). {A = sqliteExpr(TK_FLOAT, 0, 0, &X);} expr(A) ::= STRING(X). {A = sqliteExpr(TK_STRING, 0, 0, &X);} diff --git a/src/select.c b/src/select.c index e964f48fd7..caf0adcd37 100644 --- a/src/select.c +++ b/src/select.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. ** -** $Id: select.c,v 1.114 2002/10/22 23:38:04 drh Exp $ +** $Id: select.c,v 1.115 2002/10/27 19:35:35 drh Exp $ */ #include "sqliteInt.h" @@ -169,7 +169,7 @@ static void addWhereTerm( pE1c = sqliteExpr(TK_DOT, pE1b, pE1a, 0); pE2c = sqliteExpr(TK_DOT, pE2b, pE2a, 0); pE = sqliteExpr(TK_EQ, pE1c, pE2c, 0); - pE->isJoinExpr = 1; + ExprSetProperty(pE, EP_FromJoin); if( *ppExpr ){ *ppExpr = sqliteExpr(TK_AND, *ppExpr, pE, 0); }else{ @@ -178,15 +178,18 @@ static void addWhereTerm( } /* -** Set the Expr.isJoinExpr flag on all terms of the given expression. +** Set the EP_FromJoin property on all terms of the given expression. ** -** The Expr.isJoinExpr flag is used at on terms of an expression to tell +** The EP_FromJoin property is used at on terms of an expression to tell ** the LEFT OUTER JOIN processing logic that this term is part of the -** join restriction and not a part of the more general WHERE clause. +** join restriction specified in the ON or USING clause and not a part +** 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. */ static void setJoinExpr(Expr *p){ while( p ){ - p->isJoinExpr = 1; + ExprSetProperty(p, EP_FromJoin); setJoinExpr(p->pLeft); p = p->pRight; } @@ -277,6 +280,60 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){ return 0; } +/* +** This routine implements a minimal Oracle8 join syntax immulation. +** The precise oracle8 syntax is not implemented - it is easy enough +** to get this routine confused. But this routine does make it possible +** to write a single SQL statement that does a left outer join in both +** oracle8 and in SQLite. +** +** This routine looks for TK_COLUMN expression nodes that are marked +** with the EP_Oracle8Join property. Such nodes are generated by a +** column name (either "column" or "table.column") that is followed by +** the special "(+)" operator. If the table of the column marked with +** the (+) operator is the second are subsequent table in a join, then +** that table becomes the left table in a LEFT OUTER JOIN. The expression +** that uses that table becomes part of the ON clause for the join. +** +** It is important to enphasize that this is not exactly how oracle8 +** works. But it is close enough so that one can construct queries that +** will work correctly for both SQLite and Oracle8. +*/ +static int sqliteOracle8JoinFixup( + int base, /* VDBE cursor number for first table in pSrc */ + SrcList *pSrc, /* List of tables being joined */ + Expr *pWhere /* The WHERE clause of the SELECT statement */ +){ + int rc = 0; + if( ExprHasProperty(pWhere, EP_Oracle8Join) && pWhere->op==TK_COLUMN ){ + int idx = pWhere->iTable - base; + assert( idx>=0 && idxnSrc ); + if( idx>0 ){ + pSrc->a[idx-1].jointype &= ~JT_INNER; + pSrc->a[idx-1].jointype |= JT_OUTER|JT_LEFT; + return 1; + } + } + if( pWhere->pRight ){ + rc = sqliteOracle8JoinFixup(base, pSrc, pWhere->pRight); + } + if( pWhere->pLeft ){ + rc |= sqliteOracle8JoinFixup(base, pSrc, pWhere->pLeft); + } + if( pWhere->pList ){ + int i; + ExprList *pList = pWhere->pList; + for(i=0; inExpr && rc==0; i++){ + rc |= sqliteOracle8JoinFixup(base, pSrc, pList->a[i].pExpr); + } + } + if( rc==1 && (pWhere->op==TK_AND || pWhere->op==TK_EQ) ){ + setJoinExpr(pWhere); + rc = 0; + } + return rc; +} + /* ** Delete the given Select structure and all of its substructures. */ @@ -1801,6 +1858,7 @@ int sqliteSelect( if( sqliteExprCheck(pParse, pWhere, 0, 0) ){ goto select_end; } + sqliteOracle8JoinFixup(base, pTabList, pWhere); } if( pOrderBy ){ for(i=0; inExpr; i++){ diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 60ec0dadce..313ae5fdd1 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.147 2002/10/22 23:38:04 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.148 2002/10/27 19:35:35 drh Exp $ */ #include "sqlite.h" #include "hash.h" @@ -493,7 +493,7 @@ struct Token { struct Expr { u8 op; /* Operation performed by this node */ u8 dataType; /* Either SQLITE_SO_TEXT or SQLITE_SO_NUM */ - u8 isJoinExpr; /* Origin is the ON or USING phrase of a join */ + u16 flags; /* Various flags. See below */ Expr *pLeft, *pRight; /* Left and right subnodes */ ExprList *pList; /* A list of expressions used as function arguments ** or in " IN ( IN (