Index: src/build.c ================================================================== --- src/build.c +++ src/build.c @@ -4015,18 +4015,18 @@ SrcList *p, /* The left part of the FROM clause already seen */ Token *pTable, /* Name of the table to add to the FROM clause */ Token *pDatabase, /* Name of the database containing pTable */ Token *pAlias, /* The right-hand side of the AS subexpression */ Select *pSubquery, /* A subquery used in place of a table name */ - Expr *pOn, /* The ON clause of a join */ - IdList *pUsing /* The USING clause of a join */ + const OnUsing *pOnUsing /* The ON or USING clause */ ){ struct SrcList_item *pItem; sqlite3 *db = pParse->db; - if( !p && (pOn || pUsing) ){ + assert( pOnUsing!=0 ); + if( !p && (pOnUsing->pOn || pOnUsing->pUsing) ){ sqlite3ErrorMsg(pParse, "a JOIN clause is required before %s", - (pOn ? "ON" : "USING") + (pOnUsing->pOn ? "ON" : "USING") ); goto append_from_error; } p = sqlite3SrcListAppend(db, p, pTable, pDatabase); if( p==0 ){ @@ -4043,18 +4043,18 @@ assert( pAlias!=0 ); if( pAlias->n ){ pItem->zAlias = sqlite3NameFromToken(db, pAlias); } pItem->pSelect = pSubquery; - pItem->pOn = pOn; - pItem->pUsing = pUsing; + pItem->pOn = pOnUsing->pOn; + pItem->pUsing = pOnUsing->pUsing; return p; append_from_error: assert( p==0 ); - sqlite3ExprDelete(db, pOn); - sqlite3IdListDelete(db, pUsing); + sqlite3ExprDelete(db, pOnUsing->pOn); + sqlite3IdListDelete(db, pOnUsing->pUsing); sqlite3SelectDelete(db, pSubquery); return 0; } /* Index: src/parse.y ================================================================== --- src/parse.y +++ src/parse.y @@ -506,15 +506,16 @@ %ifndef SQLITE_OMIT_COMPOUND_SELECT selectnowith(A) ::= selectnowith(A) multiselect_op(Y) oneselect(Z). { Select *pRhs = Z; Select *pLhs = A; if( pRhs && pRhs->pPrior ){ + static const OnUsing nullOnUsing = { 0, 0 }; SrcList *pFrom; Token x; x.n = 0; parserDoubleLinkSelect(pParse, pRhs); - pFrom = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&x,pRhs,0,0); + pFrom = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&x,pRhs,&nullOnUsing); pRhs = sqlite3SelectNew(pParse,0,pFrom,0,0,0,0,0,0); } if( pRhs ){ pRhs->op = (u8)Y; pRhs->pPrior = pLhs; @@ -636,30 +637,30 @@ stl_prefix(A) ::= seltablist(A) joinop(Y). { if( ALWAYS(A && A->nSrc>0) ) A->a[A->nSrc-1].fg.jointype = (u8)Y; } stl_prefix(A) ::= . {A = 0;} seltablist(A) ::= stl_prefix(A) nm(Y) dbnm(D) as(Z) indexed_opt(I) - on_opt(N) using_opt(U). { - A = sqlite3SrcListAppendFromTerm(pParse,A,&Y,&D,&Z,0,N,U); + onusing(U). { + A = sqlite3SrcListAppendFromTerm(pParse,A,&Y,&D,&Z,0,&U); sqlite3SrcListIndexedBy(pParse, A, &I); } seltablist(A) ::= stl_prefix(A) nm(Y) dbnm(D) LP exprlist(E) RP as(Z) - on_opt(N) using_opt(U). { - A = sqlite3SrcListAppendFromTerm(pParse,A,&Y,&D,&Z,0,N,U); + onusing(U). { + A = sqlite3SrcListAppendFromTerm(pParse,A,&Y,&D,&Z,0,&U); sqlite3SrcListFuncArgs(pParse, A, E); } %ifndef SQLITE_OMIT_SUBQUERY seltablist(A) ::= stl_prefix(A) LP select(S) RP - as(Z) on_opt(N) using_opt(U). { - A = sqlite3SrcListAppendFromTerm(pParse,A,0,0,&Z,S,N,U); + as(Z) onusing(U). { + A = sqlite3SrcListAppendFromTerm(pParse,A,0,0,&Z,S,&U); } seltablist(A) ::= stl_prefix(A) LP seltablist(F) RP - as(Z) on_opt(N) using_opt(U). { - if( A==0 && Z.n==0 && N==0 && U==0 ){ + as(Z) onusing(U). { + if( A==0 && Z.n==0 && U.pOn==0 && U.pUsing==0 ){ A = F; }else if( F->nSrc==1 ){ - A = sqlite3SrcListAppendFromTerm(pParse,A,0,0,&Z,0,N,U); + A = sqlite3SrcListAppendFromTerm(pParse,A,0,0,&Z,0,&U); if( A ){ struct SrcList_item *pNew = &A->a[A->nSrc-1]; struct SrcList_item *pOld = F->a; pNew->zName = pOld->zName; pNew->zDatabase = pOld->zDatabase; @@ -676,11 +677,11 @@ sqlite3SrcListDelete(pParse->db, F); }else{ Select *pSubquery; sqlite3SrcListShiftJoinType(F); pSubquery = sqlite3SelectNew(pParse,0,F,0,0,0,0,SF_NestedFrom,0); - A = sqlite3SrcListAppendFromTerm(pParse,A,0,0,&Z,pSubquery,N,U); + A = sqlite3SrcListAppendFromTerm(pParse,A,0,0,&Z,pSubquery,&U); } } %endif SQLITE_OMIT_SUBQUERY %type dbnm {Token} @@ -737,14 +738,18 @@ // INSERT INTO tab SELECT * FROM aaa JOIN bbb WHERE true ON CONFLICT ... // // The [AND] and [OR] precedence marks in the rules for on_opt cause the // ON in this context to always be interpreted as belonging to the JOIN. // -%type on_opt {Expr*} -%destructor on_opt {sqlite3ExprDelete(pParse->db, $$);} -on_opt(N) ::= ON expr(E). {N = E;} -on_opt(N) ::= . [OR] {N = 0;} +%type onusing {OnUsing} +%destructor onusing { + sqlite3ExprDelete(pParse->db, $$.pOn); + sqlite3IdListDelete(pParse->db, $$.pUsing); +} +onusing(A) ::= . [OR] {A.pOn = 0; A.pUsing = 0;} +onusing(A) ::= ON expr(E). {A.pOn = E; A.pUsing = 0;} +onusing(A) ::= USING LP idlist(L) RP. {A.pOn = 0; A.pUsing=L;} // Note that this block abuses the Token type just a little. If there is // no "INDEXED BY" clause, the returned token is empty (z==0 && n==0). If // there is an INDEXED BY clause, then the token is populated as per normal, // with z pointing to the token data and n containing the number of bytes @@ -756,16 +761,10 @@ // %type indexed_opt {Token} indexed_opt(A) ::= . {A.z=0; A.n=0;} indexed_opt(A) ::= INDEXED BY nm(X). {A = X;} indexed_opt(A) ::= NOT INDEXED. {A.z=0; A.n=1;} - -%type using_opt {IdList*} -%destructor using_opt {sqlite3IdListDelete(pParse->db, $$);} -using_opt(U) ::= USING LP idlist(L) RP. {U = L;} -using_opt(U) ::= . {U = 0;} - %type orderby_opt {ExprList*} %destructor orderby_opt {sqlite3ExprListDelete(pParse->db, $$);} // the sortlist non-terminal stores a list of expression where each Index: src/select.c ================================================================== --- src/select.c +++ src/select.c @@ -474,17 +474,14 @@ isOuter, &p->pWhere); } } } - /* Disallow both ON and USING clauses in the same join + /* Cannot both ON and USING clauses in the same join. The parser + ** does not allow this. */ - if( pRight->pOn && pRight->pUsing ){ - sqlite3ErrorMsg(pParse, "cannot have both ON and USING " - "clauses in the same join"); - return 1; - } + assert( pRight->pOn==0 || pRight->pUsing==0 ); /* Add the ON clause to the end of the WHERE clause, connected by ** an AND operator. */ if( pRight->pOn ){ @@ -4505,10 +4502,11 @@ sqlite3 *db; struct ExprList_item *a; SrcList *pNewSrc; Parse *pParse; Token dummy; + static const OnUsing nullOnUsing = { 0, 0 }; if( p->pPrior==0 ) return WRC_Continue; if( p->pOrderBy==0 ) return WRC_Continue; for(pX=p; pX && (pX->op==TK_ALL || pX->op==TK_SELECT); pX=pX->pPrior){} if( pX==0 ) return WRC_Continue; @@ -4523,11 +4521,11 @@ pParse = pWalker->pParse; db = pParse->db; pNew = sqlite3DbMallocZero(db, sizeof(*pNew) ); if( pNew==0 ) return WRC_Abort; memset(&dummy, 0, sizeof(dummy)); - pNewSrc = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&dummy,pNew,0,0); + pNewSrc = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&dummy,pNew,&nullOnUsing); if( pNewSrc==0 ) return WRC_Abort; *pNew = *p; p->pSrc = pNewSrc; p->pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db, TK_ASTERISK, 0)); p->op = TK_SELECT; Index: src/sqliteInt.h ================================================================== --- src/sqliteInt.h +++ src/sqliteInt.h @@ -1083,10 +1083,11 @@ typedef struct KeyInfo KeyInfo; typedef struct Lookaside Lookaside; typedef struct LookasideSlot LookasideSlot; typedef struct Module Module; typedef struct NameContext NameContext; +typedef struct OnUsing OnUsing; typedef struct Parse Parse; typedef struct PreUpdate PreUpdate; typedef struct PrintfArguments PrintfArguments; typedef struct RenameToken RenameToken; typedef struct RowSet RowSet; @@ -2613,10 +2614,25 @@ int idx; /* Index in some Table.aCol[] of a column named zName */ } *a; int nId; /* Number of identifiers on the list */ }; +/* +** An instance of the following structure records the ON and USING clauses +** as part of a join. +** +** ON expr USING exprlist +** +** The parser uses a single instance of this object to hold both elements +** as a performance optimization - to reduce the number of "reduce" actions +** required in the parser automaton. +*/ +struct OnUsing { + Expr *pOn; + IdList *pUsing; +}; + /* ** The following structure describes the FROM clause of a SELECT statement. ** Each table or subquery in the FROM clause is a separate element of ** the SrcList.a[] array. ** @@ -3916,11 +3932,11 @@ IdList *sqlite3IdListAppend(Parse*, IdList*, Token*); int sqlite3IdListIndex(IdList*,const char*); SrcList *sqlite3SrcListEnlarge(sqlite3*, SrcList*, int, int); SrcList *sqlite3SrcListAppend(sqlite3*, SrcList*, Token*, Token*); SrcList *sqlite3SrcListAppendFromTerm(Parse*, SrcList*, Token*, Token*, - Token*, Select*, Expr*, IdList*); + Token*, Select*, const OnUsing*); void sqlite3SrcListIndexedBy(Parse *, SrcList *, Token *); void sqlite3SrcListFuncArgs(Parse*, SrcList*, ExprList*); int sqlite3IndexedByLookup(Parse *, struct SrcList_item *); void sqlite3SrcListShiftJoinType(SrcList*); void sqlite3SrcListAssignCursors(Parse*, SrcList*);