aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/expr.c35
-rw-r--r--src/fkey.c7
-rw-r--r--src/parse.y14
-rw-r--r--src/resolve.c49
-rw-r--r--src/sqliteInt.h4
-rw-r--r--src/where.c4
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 );