diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/expr.c | 35 | ||||
-rw-r--r-- | src/fkey.c | 7 | ||||
-rw-r--r-- | src/parse.y | 14 | ||||
-rw-r--r-- | src/resolve.c | 49 | ||||
-rw-r--r-- | src/sqliteInt.h | 4 | ||||
-rw-r--r-- | src/where.c | 4 |
6 files changed, 70 insertions, 43 deletions
diff --git a/src/expr.c b/src/expr.c index 34be87114..b47752aec 100644 --- a/src/expr.c +++ b/src/expr.c @@ -59,14 +59,37 @@ char sqlite3ExprAffinity(Expr *pExpr){ ** Set the collating sequence for expression pExpr to be the collating ** sequence named by pToken. Return a pointer to a new Expr node that ** implements the COLLATE operator. +** +** If a memory allocation error occurs, that fact is recorded in pParse->db +** and the pExpr parameter is returned unchanged. */ -Expr *sqlite3ExprSetCollByToken(Parse *pParse, Expr *pExpr, Token *pCollName){ - Expr *pNew = sqlite3ExprAlloc(pParse->db, TK_COLLATE, pCollName, 1); - if( pNew ){ - pNew->pLeft = pExpr; - pNew->flags |= EP_Collate; +Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr *pExpr, Token *pCollName){ + if( pCollName->n>0 ){ + Expr *pNew = sqlite3ExprAlloc(pParse->db, TK_COLLATE, pCollName, 1); + if( pNew ){ + pNew->pLeft = pExpr; + pNew->flags |= EP_Collate; + pExpr = pNew; + } } - return pNew; + return pExpr; +} +Expr *sqlite3ExprAddCollateString(Parse *pParse, Expr *pExpr, const char *zC){ + if( zC ){ + Token s; + s.z = zC; + s.n = sqlite3Strlen30(s.z); + pExpr = sqlite3ExprAddCollateToken(pParse, pExpr, &s); + } + return pExpr; +} + +/* +** Skip over any TK_COLLATE operator in an expression. +*/ +Expr *sqlite3ExprSkipCollate(Expr *pExpr){ + if( pExpr && pExpr->op==TK_COLLATE ) pExpr = pExpr->pLeft; + return pExpr; } /* diff --git a/src/fkey.c b/src/fkey.c index f9401ae6c..bf56b35d8 100644 --- a/src/fkey.c +++ b/src/fkey.c @@ -511,17 +511,12 @@ static void fkScanChildren( ** expression to the parent key column defaults. */ if( pIdx ){ Column *pCol; - Expr *pNew; - Token s; iCol = pIdx->aiColumn[i]; pCol = &pTab->aCol[iCol]; if( pTab->iPKey==iCol ) iCol = -1; pLeft->iTable = regData+iCol+1; pLeft->affinity = pCol->affinity; - s.z = pCol->zColl; - s.n = sqlite3Strlen30(s.z); - pNew = sqlite3ExprSetCollByToken(pParse, pLeft, &s); - if( pNew ) pLeft = pNew; + pLeft = sqlite3ExprAddCollateString(pParse, pLeft, pCol->zColl); }else{ pLeft->iTable = regData; pLeft->affinity = SQLITE_AFF_INTEGER; diff --git a/src/parse.y b/src/parse.y index 94433d539..0bfe823d4 100644 --- a/src/parse.y +++ b/src/parse.y @@ -815,7 +815,7 @@ expr(A) ::= VARIABLE(X). { spanSet(&A, &X, &X); } expr(A) ::= expr(E) COLLATE ids(C). { - A.pExpr = sqlite3ExprSetCollByToken(pParse, E.pExpr, &C); + A.pExpr = sqlite3ExprAddCollateToken(pParse, E.pExpr, &C); A.zStart = E.zStart; A.zEnd = &C.z[C.n]; } @@ -1140,22 +1140,14 @@ uniqueflag(A) ::= . {A = OE_None;} idxlist_opt(A) ::= . {A = 0;} idxlist_opt(A) ::= LP idxlist(X) RP. {A = X;} idxlist(A) ::= idxlist(X) COMMA nm(Y) collate(C) sortorder(Z). { - Expr *p = 0; - if( C.n>0 ){ - p = sqlite3Expr(pParse->db, TK_COLUMN, 0); - sqlite3ExprSetCollByToken(pParse, p, &C); - } + Expr *p = sqlite3ExprAddCollateToken(pParse, 0, &C); A = sqlite3ExprListAppend(pParse,X, p); sqlite3ExprListSetName(pParse,A,&Y,1); sqlite3ExprListCheckLength(pParse, A, "index"); if( A ) A->a[A->nExpr-1].sortOrder = (u8)Z; } idxlist(A) ::= nm(Y) collate(C) sortorder(Z). { - Expr *p = 0; - if( C.n>0 ){ - p = sqlite3PExpr(pParse, TK_COLUMN, 0, 0, 0); - sqlite3ExprSetCollByToken(pParse, p, &C); - } + Expr *p = sqlite3ExprAddCollateToken(pParse, 0, &C); A = sqlite3ExprListAppend(pParse,0, p); sqlite3ExprListSetName(pParse, A, &Y, 1); sqlite3ExprListCheckLength(pParse, A, "index"); diff --git a/src/resolve.c b/src/resolve.c index 8ae170ab4..6e5e2e7a9 100644 --- a/src/resolve.c +++ b/src/resolve.c @@ -68,6 +68,15 @@ static void incrAggFunctionDepth(Expr *pExpr, int N){ ** from the result in the result-set. We might fix this someday. Or ** then again, we might not... ** +** If the reference is followed by a COLLATE operator, then make sure +** the COLLATE operator is preserved. For example: +** +** SELECT a+b, c+d FROM t1 ORDER BY 1 COLLATE nocase; +** +** Should be transformed into: +** +** SELECT a+b, c+d FROM t1 ORDER BY (a+b) COLLATE nocase; +** ** The nSubquery parameter specifies how many levels of subquery the ** alias is removed from the original expression. The usually value is ** zero but it might be more if the alias is contained within a subquery @@ -91,8 +100,9 @@ static void resolveAlias( assert( pOrig!=0 ); assert( pOrig->flags & EP_Resolved ); db = pParse->db; + pDup = sqlite3ExprDup(db, pOrig, 0); + if( pDup==0 ) return; if( pOrig->op!=TK_COLUMN && zType[0]!='G' ){ - pDup = sqlite3ExprDup(db, pOrig, 0); incrAggFunctionDepth(pDup, nSubquery); pDup = sqlite3PExpr(pParse, TK_AS, pDup, 0, 0); if( pDup==0 ) return; @@ -100,21 +110,21 @@ static void resolveAlias( pEList->a[iCol].iAlias = (u16)(++pParse->nAlias); } pDup->iTable = pEList->a[iCol].iAlias; - }else if( ExprHasProperty(pOrig, EP_IntValue) || pOrig->u.zToken==0 ){ - pDup = sqlite3ExprDup(db, pOrig, 0); - if( pDup==0 ) return; - }else{ - char *zToken = pOrig->u.zToken; - assert( zToken!=0 ); - pOrig->u.zToken = 0; - pDup = sqlite3ExprDup(db, pOrig, 0); - pOrig->u.zToken = zToken; - if( pDup==0 ) return; - assert( (pDup->flags & (EP_Reduced|EP_TokenOnly))==0 ); - pDup->flags2 |= EP2_MallocedToken; - pDup->u.zToken = sqlite3DbStrDup(db, zToken); } - pDup->flags |= EP_Collate & pExpr->flags; +#if 1 /* FIXME */ + if( pExpr->flags & EP_Collate ){ + CollSeq *pColl = sqlite3ExprCollSeq(pParse, pExpr); + if( pColl ){ + pDup = sqlite3ExprAddCollateString(pParse, pDup, pColl->zName); + } + pDup->flags |= EP_Collate; + } +#else + /* Should be this: */ + if( pExpr->op==TK_COLLATE ){ + pDup = sqlite3ExprAddCollateString(pParse, pDup, pExpr->u.zToken); + } +#endif /* Before calling sqlite3ExprDelete(), set the EP_Static flag. This ** prevents ExprDelete() from deleting the Expr structure itself, @@ -123,6 +133,11 @@ static void resolveAlias( ExprSetProperty(pExpr, EP_Static); sqlite3ExprDelete(db, pExpr); memcpy(pExpr, pDup, sizeof(*pExpr)); + if( !ExprHasProperty(pExpr, EP_IntValue) && pExpr->u.zToken!=0 ){ + assert( (pExpr->flags & (EP_Reduced|EP_TokenOnly))==0 ); + pExpr->u.zToken = sqlite3DbStrDup(db, pExpr->u.zToken); + pExpr->flags2 |= EP2_MallocedToken; + } sqlite3DbFree(db, pDup); } @@ -936,11 +951,11 @@ static int resolveOrderGroupBy( pItem->iOrderByCol = (u16)iCol; continue; } - if( sqlite3ExprIsInteger(pE, &iCol) ){ + if( sqlite3ExprIsInteger(sqlite3ExprSkipCollate(pE), &iCol) ){ /* The ORDER BY term is an integer constant. Again, set the column ** number so that sqlite3ResolveOrderGroupBy() will convert the ** order-by term to a copy of the result-set expression */ - if( iCol<1 ){ + if( (iCol & ~0xffff)!=0 ){ resolveOutOfRangeError(pParse, zType, i+1, nResult); return 1; } diff --git a/src/sqliteInt.h b/src/sqliteInt.h index fc975bd3c..b15e0b208 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -3021,7 +3021,9 @@ int sqlite3ReadSchema(Parse *pParse); CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char*,int); CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char*zName); CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr); -Expr *sqlite3ExprSetCollByToken(Parse *pParse, Expr*, Token*); +Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, Token*); +Expr *sqlite3ExprAddCollateString(Parse*,Expr*,const char*); +Expr *sqlite3ExprSkipCollate(Expr*); int sqlite3CheckCollSeq(Parse *, CollSeq *); int sqlite3CheckObjectName(Parse *, const char *); void sqlite3VdbeSetChanges(sqlite3 *, int); diff --git a/src/where.c b/src/where.c index 459081e3e..c5bb729d8 100644 --- a/src/where.c +++ b/src/where.c @@ -1349,14 +1349,14 @@ static void exprAnalyze( sCollSeqName.n = 6; pNewExpr1 = sqlite3ExprDup(db, pLeft, 0); pNewExpr1 = sqlite3PExpr(pParse, TK_GE, - sqlite3ExprSetCollByToken(pParse,pNewExpr1,&sCollSeqName), + sqlite3ExprAddCollateToken(pParse,pNewExpr1,&sCollSeqName), pStr1, 0); idxNew1 = whereClauseInsert(pWC, pNewExpr1, TERM_VIRTUAL|TERM_DYNAMIC); testcase( idxNew1==0 ); exprAnalyze(pSrc, pWC, idxNew1); pNewExpr2 = sqlite3ExprDup(db, pLeft, 0); pNewExpr2 = sqlite3PExpr(pParse, TK_LT, - sqlite3ExprSetCollByToken(pParse,pNewExpr2,&sCollSeqName), + sqlite3ExprAddCollateToken(pParse,pNewExpr2,&sCollSeqName), pStr2, 0); idxNew2 = whereClauseInsert(pWC, pNewExpr2, TERM_VIRTUAL|TERM_DYNAMIC); testcase( idxNew2==0 ); |