# Fix a problem causing collation sequence names to be dequoted multiple times # under some circumstances. # Upstream original patch: https://www.sqlite.org/src/info/eddc05e7bb31fae7 diff -up sqlite-src-3071700/src/expr.c.old sqlite-src-3071700/src/expr.c --- sqlite-src-3071700/src/expr.c.old 2015-07-23 10:26:11.220420294 +0200 +++ sqlite-src-3071700/src/expr.c 2015-07-23 10:26:47.468601833 +0200 @@ -65,9 +65,9 @@ char sqlite3ExprAffinity(Expr *pExpr){ ** If a memory allocation error occurs, that fact is recorded in pParse->db ** and the pExpr parameter is returned unchanged. */ -Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr *pExpr, Token *pCollName){ +Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr *pExpr, Token *pCollName, int dequote){ if( pCollName->n>0 ){ - Expr *pNew = sqlite3ExprAlloc(pParse->db, TK_COLLATE, pCollName, 1); + Expr *pNew = sqlite3ExprAlloc(pParse->db, TK_COLLATE, pCollName, dequote); if( pNew ){ pNew->pLeft = pExpr; pNew->flags |= EP_Collate; @@ -81,7 +81,7 @@ Expr *sqlite3ExprAddCollateString(Parse assert( zC!=0 ); s.z = zC; s.n = sqlite3Strlen30(s.z); - return sqlite3ExprAddCollateToken(pParse, pExpr, &s); + return sqlite3ExprAddCollateToken(pParse, pExpr, &s, 0); } /* diff -up sqlite-src-3071700/src/parse.y.old sqlite-src-3071700/src/parse.y --- sqlite-src-3071700/src/parse.y.old 2015-07-23 10:27:00.595682612 +0200 +++ sqlite-src-3071700/src/parse.y 2015-07-23 10:27:47.850973405 +0200 @@ -818,7 +818,7 @@ expr(A) ::= VARIABLE(X). { spanSet(&A, &X, &X); } expr(A) ::= expr(E) COLLATE ids(C). { - A.pExpr = sqlite3ExprAddCollateToken(pParse, E.pExpr, &C); + A.pExpr = sqlite3ExprAddCollateToken(pParse, E.pExpr, &C, 1); A.zStart = E.zStart; A.zEnd = &C.z[C.n]; } @@ -1143,14 +1143,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 = sqlite3ExprAddCollateToken(pParse, 0, &C); + Expr *p = sqlite3ExprAddCollateToken(pParse, 0, &C, 1); 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 = sqlite3ExprAddCollateToken(pParse, 0, &C); + Expr *p = sqlite3ExprAddCollateToken(pParse, 0, &C, 1); A = sqlite3ExprListAppend(pParse,0, p); sqlite3ExprListSetName(pParse, A, &Y, 1); sqlite3ExprListCheckLength(pParse, A, "index"); diff -up sqlite-src-3071700/src/sqliteInt.h.old sqlite-src-3071700/src/sqliteInt.h --- sqlite-src-3071700/src/sqliteInt.h.old 2015-07-23 10:34:54.516598956 +0200 +++ sqlite-src-3071700/src/sqliteInt.h 2015-07-23 10:35:12.908712134 +0200 @@ -3103,7 +3103,7 @@ 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 *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, Token*); +Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, Token*, int); Expr *sqlite3ExprAddCollateString(Parse*,Expr*,const char*); Expr *sqlite3ExprSkipCollate(Expr*); int sqlite3CheckCollSeq(Parse *, CollSeq *); diff -up sqlite-src-3071700/src/where.c.old sqlite-src-3071700/src/where.c --- sqlite-src-3071700/src/where.c.old 2015-07-23 10:35:22.365770330 +0200 +++ sqlite-src-3071700/src/where.c 2015-07-23 10:38:03.460761652 +0200 @@ -1389,7 +1389,7 @@ static void exprAnalyze( Expr *pNewExpr2; int idxNew1; int idxNew2; - Token sCollSeqName; /* Name of collating sequence */ + const char *zCollSeqName; /* Name of collating sequence */ pLeft = pExpr->x.pList->a[1].pExpr; pStr2 = sqlite3ExprDup(db, pStr1, 0); @@ -1411,11 +1411,10 @@ static void exprAnalyze( } *pC = c + 1; } - sCollSeqName.z = noCase ? "NOCASE" : "BINARY"; - sCollSeqName.n = 6; + zCollSeqName = noCase ? "NOCASE" : "BINARY"; pNewExpr1 = sqlite3ExprDup(db, pLeft, 0); pNewExpr1 = sqlite3PExpr(pParse, TK_GE, - sqlite3ExprAddCollateToken(pParse,pNewExpr1,&sCollSeqName), + sqlite3ExprAddCollateString(pParse,pNewExpr1,zCollSeqName), pStr1, 0); idxNew1 = whereClauseInsert(pWC, pNewExpr1, TERM_VIRTUAL|TERM_DYNAMIC); testcase( idxNew1==0 ); @@ -1421,7 +1421,7 @@ static void exprAnalyze( exprAnalyze(pSrc, pWC, idxNew1); pNewExpr2 = sqlite3ExprDup(db, pLeft, 0); pNewExpr2 = sqlite3PExpr(pParse, TK_LT, - sqlite3ExprAddCollateToken(pParse,pNewExpr2,&sCollSeqName), + sqlite3ExprAddCollateString(pParse,pNewExpr2,zCollSeqName), pStr2, 0); idxNew2 = whereClauseInsert(pWC, pNewExpr2, TERM_VIRTUAL|TERM_DYNAMIC); testcase( idxNew2==0 ); diff -up sqlite-src-3071700/test/collate1.test.old sqlite-src-3071700/test/collate1.test --- sqlite-src-3071700/test/collate1.test.old 2015-07-23 10:38:58.858102547 +0200 +++ sqlite-src-3071700/test/collate1.test 2015-07-23 10:40:30.474666325 +0200 @@ -10,12 +10,13 @@ # #*********************************************************************** # This file implements regression tests for SQLite library. The -# focus of this script is page cache subsystem. +# focus of this script is testing collation sequences. # # $Id: collate1.test,v 1.5 2007/02/01 23:02:46 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl +set testprefix collate1 # # Tests are roughly organised as follows: @@ -305,4 +306,54 @@ do_test collate1-4.5 { } } {} +#------------------------------------------------------------------------- +# Fix problems with handling collation sequences named '"""'. +# +do_execsql_test 6.1 { + SELECT """"""""; +} {\"\"\"} + +do_catchsql_test 6.2 { + CREATE TABLE x1(a); + SELECT a FROM x1 ORDER BY a COLLATE """"""""; +} {1 {no such collation sequence: """}} + +do_catchsql_test 6.3 { + SELECT a FROM x1 ORDER BY 1 COLLATE """"""""; +} {1 {no such collation sequence: """}} + +do_catchsql_test 6.4 { + SELECT 0 UNION SELECT 0 ORDER BY 1 COLLATE """"""""; +} {1 {no such collation sequence: """}} + +db collate {"""} [list string compare -nocase] + +do_execsql_test 6.5 { + PRAGMA foreign_keys = ON; + CREATE TABLE p1(a PRIMARY KEY COLLATE '"""'); + CREATE TABLE c1(x, y REFERENCES p1); +} {} + +do_execsql_test 6.6 { + INSERT INTO p1 VALUES('abc'); + INSERT INTO c1 VALUES(1, 'ABC'); +} + +ifcapable foreignkey { + do_catchsql_test 6.7 { + DELETE FROM p1 WHERE rowid = 1 + } {1 {foreign key constraint failed}} +} + +do_execsql_test 6.8 { + INSERT INTO p1 VALUES('abb'); + INSERT INTO p1 VALUES('wxz'); + INSERT INTO p1 VALUES('wxy'); + + INSERT INTO c1 VALUES(2, 'abb'); + INSERT INTO c1 VALUES(3, 'wxz'); + INSERT INTO c1 VALUES(4, 'WXY'); + SELECT x, y FROM c1 ORDER BY y COLLATE """"""""; +} {2 abb 1 ABC 4 WXY 3 wxz} + finish_test