Index: src/build.c ================================================================== --- src/build.c +++ src/build.c @@ -20,11 +20,11 @@ ** creating ID lists ** BEGIN TRANSACTION ** COMMIT ** ROLLBACK ** -** $Id: build.c,v 1.555 2009/07/01 14:56:40 danielk1977 Exp $ +** $Id: build.c,v 1.556 2009/07/01 16:12:08 danielk1977 Exp $ */ #include "sqliteInt.h" /* ** This routine is called when a new SQL statement is beginning to @@ -3206,31 +3206,36 @@ Expr *pOn, /* The ON clause of a join */ IdList *pUsing /* The USING clause of a join */ ){ struct SrcList_item *pItem; sqlite3 *db = pParse->db; + if( !p && (pOn || pUsing) ){ + sqlite3ErrorMsg(pParse, "a JOIN clause is required before %s", + (pOn ? "ON" : "USING") + ); + goto append_from_error; + } p = sqlite3SrcListAppend(db, p, pTable, pDatabase); if( p==0 || NEVER(p->nSrc==0) ){ - sqlite3ExprDelete(db, pOn); - sqlite3IdListDelete(db, pUsing); - sqlite3SelectDelete(db, pSubquery); - return p; + goto append_from_error; } pItem = &p->a[p->nSrc-1]; assert( pAlias!=0 ); if( pAlias->n ){ pItem->zAlias = sqlite3NameFromToken(db, pAlias); } pItem->pSelect = pSubquery; - if( p->nSrc>1 ){ - pItem->pOn = pOn; - pItem->pUsing = pUsing; - }else{ - sqlite3ExprDelete(db, pOn); - sqlite3IdListDelete(db, pUsing); - } + pItem->pOn = pOn; + pItem->pUsing = pUsing; return p; + + append_from_error: + assert( p==0 ); + sqlite3ExprDelete(db, pOn); + sqlite3IdListDelete(db, pUsing); + sqlite3SelectDelete(db, pSubquery); + return 0; } /* ** Add an INDEXED BY or NOT INDEXED clause to the most recently added ** element of the source-list passed as the second argument. Index: test/join.test ================================================================== --- test/join.test +++ test/join.test @@ -10,11 +10,11 @@ #*********************************************************************** # This file implements regression tests for SQLite library. # # This file implements tests for joins, including outer joins. # -# $Id: join.test,v 1.26 2008/12/05 00:00:07 drh Exp $ +# $Id: join.test,v 1.27 2009/07/01 16:12:08 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl do_test join-1.1 { @@ -307,14 +307,12 @@ catchsql { SELECT * FROM t1 JOIN t2 USING(d); } } {1 {cannot join using column d - column not present in both tables}} do_test join-3.5 { - catchsql { - SELECT * FROM t1 USING(a); - } -} {0 {1 2 3 2 3 4 3 4 5}} + catchsql { SELECT * FROM t1 USING(a) } +} {1 {a JOIN clause is required before USING}} do_test join-3.6 { catchsql { SELECT * FROM t1 JOIN t2 ON t3.a=t2.b; } } {1 {no such column: t3.a}} Index: test/tkt3935.test ================================================================== --- test/tkt3935.test +++ test/tkt3935.test @@ -10,11 +10,11 @@ #*********************************************************************** # This file implements regression tests for SQLite library. # # This file implements tests to verify that ticket #3935 has been fixed. # -# $Id: tkt3935.test,v 1.1 2009/07/01 14:56:41 danielk1977 Exp $ +# $Id: tkt3935.test,v 1.2 2009/07/01 16:12:08 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl do_test tkt3935.1 { @@ -31,24 +31,27 @@ execsql { SELECT j1.b FROM (t1 INNER JOIN t2 ON a=c) AS j1 } } {} do_test tkt3935.4 { - execsql { SELECT a FROM (t1) AS t ON b USING(a) } -} {} + catchsql { SELECT a FROM (t1) AS t ON b USING(a) } +} {1 {a JOIN clause is required before ON}} do_test tkt3935.5 { - execsql { SELECT a FROM (t1) AS t ON b } -} {} + catchsql { SELECT a FROM (t1) AS t ON b } +} {1 {a JOIN clause is required before ON}} do_test tkt3935.6 { - execsql { SELECT a FROM (SELECT * FROM t1) AS t ON b USING(a) } -} {} + catchsql { SELECT a FROM (SELECT * FROM t1) AS t ON b USING(a) } +} {1 {a JOIN clause is required before ON}} do_test tkt3935.7 { - execsql { SELECT a FROM (SELECT * FROM t1) AS t ON b } -} {} + catchsql { SELECT a FROM (SELECT * FROM t1) AS t ON b } +} {1 {a JOIN clause is required before ON}} do_test tkt3935.8 { - execsql { SELECT a FROM t1 AS t ON b } -} {} + catchsql { SELECT a FROM t1 AS t ON b } +} {1 {a JOIN clause is required before ON}} do_test tkt3935.9 { - execsql { SELECT a FROM t1 AS t ON b USING(a) } -} {} + catchsql { SELECT a FROM t1 AS t ON b USING(a) } +} {1 {a JOIN clause is required before ON}} +do_test tkt3935.10 { + catchsql { SELECT a FROM t1 AS t USING(a) } +} {1 {a JOIN clause is required before USING}} finish_test Index: test/vtab6.test ================================================================== --- test/vtab6.test +++ test/vtab6.test @@ -12,11 +12,11 @@ # # This file implements tests for joins, including outer joins involving # virtual tables. The test cases in this file are copied from the file # join.test, and some of the comments still reflect that. # -# $Id: vtab6.test,v 1.4 2008/07/12 14:52:21 drh Exp $ +# $Id: vtab6.test,v 1.5 2009/07/01 16:12:08 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !vtab { @@ -263,14 +263,12 @@ catchsql { SELECT * FROM t1 JOIN t2 USING(a); } } {1 {cannot join using column a - column not present in both tables}} do_test vtab6-3.5 { - catchsql { - SELECT * FROM t1 USING(a); - } -} {0 {1 2 3 2 3 4 3 4 5}} + catchsql { SELECT * FROM t1 USING(a) } +} {1 {a JOIN clause is required before USING}} do_test vtab6-3.6 { catchsql { SELECT * FROM t1 JOIN t2 ON t3.a=t2.b; } } {1 {no such column: t3.a}}