/ Check-in [06749ac7]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Allow collation sequence names to be quoted. Ticket #2744. (CVS 4537)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 06749ac7afeea4adbdeb9315f3819d5224534c66
User & Date: danielk1977 2007-11-12 09:50:26
Context
2007-11-12
15:29
Where possible, transform the DISTINCT qualifier to a GROUP BY clause. GROUP BY clauses may be optimized by indices, DISTINCT qualifiers cannot. (CVS 4538) check-in: e5633123 user: danielk1977 tags: trunk
09:50
Allow collation sequence names to be quoted. Ticket #2744. (CVS 4537) check-in: 06749ac7 user: danielk1977 tags: trunk
08:09
Modify the order of assert() macros in vdbe.c as per the suggestion in #2768. (CVS 4536) check-in: af5af5dc user: danielk1977 tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/build.c.

18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
....
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188

1189
1190
1191
1192



1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206


1207
1208
1209
1210
1211
1212
1213
....
3347
3348
3349
3350
3351
3352
3353

3354


3355
3356
3357
3358
3359
3360
3361
3362
3363

3364
3365
3366
3367
3368
3369
3370
**     CREATE INDEX
**     DROP INDEX
**     creating ID lists
**     BEGIN TRANSACTION
**     COMMIT
**     ROLLBACK
**
** $Id: build.c,v 1.447 2007/10/15 07:08:44 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** This routine is called when a new SQL statement is beginning to
** be parsed.  Initialize the pParse structure as needed.
................................................................................
  sqlite3ExprDelete(pCheckExpr);
}

/*
** Set the collation function of the most recently parsed table column
** to the CollSeq given.
*/
void sqlite3AddCollateType(Parse *pParse, const char *zType, int nType){
  Table *p;
  int i;


  if( (p = pParse->pNewTable)==0 ) return;
  i = p->nCol-1;




  if( sqlite3LocateCollSeq(pParse, zType, nType) ){
    Index *pIdx;
    p->aCol[i].zColl = sqlite3DbStrNDup(pParse->db, zType, nType);
  
    /* If the column is declared as "<name> PRIMARY KEY COLLATE <type>",
    ** then an index may have been created on this column before the
    ** collation type was added. Correct this if it is the case.
    */
    for(pIdx=p->pIndex; pIdx; pIdx=pIdx->pNext){
      assert( pIdx->nColumn==1 );
      if( pIdx->aiColumn[0]==i ){
        pIdx->azColl[0] = p->aCol[i].zColl;
      }
    }


  }
}

/*
** This function returns the collation sequence for database native text
** encoding identified by the string zName, length nName.
**
................................................................................
    return;
  }

  if( pName1==0 || pName1->z==0 ){
    reindexDatabases(pParse, 0);
    return;
  }else if( pName2==0 || pName2->z==0 ){

    assert( pName1->z );


    pColl = sqlite3FindCollSeq(db, ENC(db), (char*)pName1->z, pName1->n, 0);
    if( pColl ){
      char *zColl = sqlite3DbStrNDup(db, (const char *)pName1->z, pName1->n);
      if( zColl ){
        reindexDatabases(pParse, zColl);
        sqlite3_free(zColl);
      }
      return;
    }

  }
  iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pObjName);
  if( iDb<0 ) return;
  z = sqlite3NameFromToken(db, pObjName);
  if( z==0 ) return;
  zDb = db->aDb[iDb].zName;
  pTab = sqlite3FindTable(db, z, zDb);







|







 







|


>




>
>
>
|

|











>
>







 







>

>
>
|

<






>







18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
....
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
....
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
3363
3364
3365

3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
**     CREATE INDEX
**     DROP INDEX
**     creating ID lists
**     BEGIN TRANSACTION
**     COMMIT
**     ROLLBACK
**
** $Id: build.c,v 1.448 2007/11/12 09:50:26 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** This routine is called when a new SQL statement is beginning to
** be parsed.  Initialize the pParse structure as needed.
................................................................................
  sqlite3ExprDelete(pCheckExpr);
}

/*
** Set the collation function of the most recently parsed table column
** to the CollSeq given.
*/
void sqlite3AddCollateType(Parse *pParse, Token *pToken){
  Table *p;
  int i;
  char *zColl;              /* Dequoted name of collation sequence */

  if( (p = pParse->pNewTable)==0 ) return;
  i = p->nCol-1;

  zColl = sqlite3NameFromToken(pParse->db, pToken);
  if( !zColl ) return;

  if( sqlite3LocateCollSeq(pParse, zColl, -1) ){
    Index *pIdx;
    p->aCol[i].zColl = zColl;
  
    /* If the column is declared as "<name> PRIMARY KEY COLLATE <type>",
    ** then an index may have been created on this column before the
    ** collation type was added. Correct this if it is the case.
    */
    for(pIdx=p->pIndex; pIdx; pIdx=pIdx->pNext){
      assert( pIdx->nColumn==1 );
      if( pIdx->aiColumn[0]==i ){
        pIdx->azColl[0] = p->aCol[i].zColl;
      }
    }
  }else{
    sqlite3_free(zColl);
  }
}

/*
** This function returns the collation sequence for database native text
** encoding identified by the string zName, length nName.
**
................................................................................
    return;
  }

  if( pName1==0 || pName1->z==0 ){
    reindexDatabases(pParse, 0);
    return;
  }else if( pName2==0 || pName2->z==0 ){
    char *zColl;
    assert( pName1->z );
    zColl = sqlite3NameFromToken(pParse->db, pName1);
    if( !zColl ) return;
    pColl = sqlite3FindCollSeq(db, ENC(db), zColl, -1, 0);
    if( pColl ){

      if( zColl ){
        reindexDatabases(pParse, zColl);
        sqlite3_free(zColl);
      }
      return;
    }
    sqlite3_free(zColl);
  }
  iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pObjName);
  if( iDb<0 ) return;
  z = sqlite3NameFromToken(db, pObjName);
  if( z==0 ) return;
  zDb = db->aDb[iDb].zName;
  pTab = sqlite3FindTable(db, z, zDb);

Changes to src/expr.c.

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
..
50
51
52
53
54
55
56

57

58
59
60
61
62
63


64
65
66
67
68
69
70
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains routines used for analyzing expressions and
** for generating VDBE code that evaluates expressions in SQLite.
**
** $Id: expr.c,v 1.315 2007/10/23 18:55:49 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** Return the 'affinity' of the expression pExpr if any.
**
................................................................................
** Set the collating sequence for expression pExpr to be the collating
** sequence named by pToken.   Return a pointer to the revised expression.
** The collating sequence is marked as "explicit" using the EP_ExpCollate
** flag.  An explicit collating sequence will override implicit
** collating sequences.
*/
Expr *sqlite3ExprSetColl(Parse *pParse, Expr *pExpr, Token *pName){

  CollSeq *pColl;

  if( pExpr==0 ) return 0;
  pColl = sqlite3LocateCollSeq(pParse, (char*)pName->z, pName->n);
  if( pColl ){
    pExpr->pColl = pColl;
    pExpr->flags |= EP_ExpCollate;
  }


  return pExpr;
}

/*
** Return the default collation sequence for the expression pExpr. If
** there is no default collation type, return 0.
*/







|







 







>

>
|
|
|
|
|
|
>
>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
..
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains routines used for analyzing expressions and
** for generating VDBE code that evaluates expressions in SQLite.
**
** $Id: expr.c,v 1.316 2007/11/12 09:50:26 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** Return the 'affinity' of the expression pExpr if any.
**
................................................................................
** Set the collating sequence for expression pExpr to be the collating
** sequence named by pToken.   Return a pointer to the revised expression.
** The collating sequence is marked as "explicit" using the EP_ExpCollate
** flag.  An explicit collating sequence will override implicit
** collating sequences.
*/
Expr *sqlite3ExprSetColl(Parse *pParse, Expr *pExpr, Token *pName){
  char *zColl = 0;            /* Dequoted name of collation sequence */
  CollSeq *pColl;
  zColl = sqlite3NameFromToken(pParse->db, pName);
  if( pExpr && zColl ){
    pColl = sqlite3LocateCollSeq(pParse, zColl, -1);
    if( pColl ){
      pExpr->pColl = pColl;
      pExpr->flags |= EP_ExpCollate;
    }
  }
  sqlite3_free(zColl);
  return pExpr;
}

/*
** Return the default collation sequence for the expression pExpr. If
** there is no default collation type, return 0.
*/

Changes to src/parse.y.

10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
...
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
...
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
...
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
**
*************************************************************************
** This file contains SQLite's grammar for SQL.  Process this file
** using the lemon parser generator to generate C code that runs
** the parser.  Lemon will also generate a header file containing
** numeric codes for all of the tokens.
**
** @(#) $Id: parse.y,v 1.234 2007/08/21 10:44:16 drh Exp $
*/

// All token codes are small integers with #defines that begin with "TK_"
%token_prefix TK_

// The type of the data attached to each token is Token.  This is also the
// default type for non-terminals.
................................................................................
ccons ::= PRIMARY KEY sortorder(Z) onconf(R) autoinc(I).
                                     {sqlite3AddPrimaryKey(pParse,0,R,I,Z);}
ccons ::= UNIQUE onconf(R).    {sqlite3CreateIndex(pParse,0,0,0,0,R,0,0,0,0);}
ccons ::= CHECK LP expr(X) RP.       {sqlite3AddCheckConstraint(pParse,X);}
ccons ::= REFERENCES nm(T) idxlist_opt(TA) refargs(R).
                                {sqlite3CreateForeignKey(pParse,0,&T,TA,R);}
ccons ::= defer_subclause(D).   {sqlite3DeferForeignKey(pParse,D);}
ccons ::= COLLATE id(C).  {sqlite3AddCollateType(pParse, (char*)C.z, C.n);}

// The optional AUTOINCREMENT keyword
%type autoinc {int}
autoinc(X) ::= .          {X = 0;}
autoinc(X) ::= AUTOINCR.  {X = 1;}

// The next group of rules parses the arguments to a REFERENCES clause
................................................................................
term(A) ::= STRING(X).       {A = sqlite3PExpr(pParse, @X, 0, 0, &X);}
expr(A) ::= REGISTER(X).     {A = sqlite3RegisterExpr(pParse, &X);}
expr(A) ::= VARIABLE(X).     {
  Token *pToken = &X;
  Expr *pExpr = A = sqlite3PExpr(pParse, TK_VARIABLE, 0, 0, pToken);
  sqlite3ExprAssignVarNumber(pParse, pExpr);
}
expr(A) ::= expr(E) COLLATE id(C). {
  A = sqlite3ExprSetColl(pParse, E, &C);
}
%ifndef SQLITE_OMIT_CAST
expr(A) ::= CAST(X) LP expr(E) AS typetoken(T) RP(Y). {
  A = sqlite3PExpr(pParse, TK_CAST, E, 0, &T);
  sqlite3ExprSpan(A,&X,&Y);
}
................................................................................

idxlist_opt(A) ::= .                         {A = 0;}
idxlist_opt(A) ::= LP idxlist(X) RP.         {A = X;}
idxlist(A) ::= idxlist(X) COMMA idxitem(Y) collate(C) sortorder(Z).  {
  Expr *p = 0;
  if( C.n>0 ){
    p = sqlite3PExpr(pParse, TK_COLUMN, 0, 0, 0);
    if( p ) p->pColl = sqlite3LocateCollSeq(pParse, (char*)C.z, C.n);
  }
  A = sqlite3ExprListAppend(pParse,X, p, &Y);
  sqlite3ExprListCheckLength(pParse, A, SQLITE_MAX_COLUMN, "index");
  if( A ) A->a[A->nExpr-1].sortOrder = Z;
}
idxlist(A) ::= idxitem(Y) collate(C) sortorder(Z). {
  Expr *p = 0;
  if( C.n>0 ){
    p = sqlite3PExpr(pParse, TK_COLUMN, 0, 0, 0);
    if( p ) p->pColl = sqlite3LocateCollSeq(pParse, (char*)C.z, C.n);
  }
  A = sqlite3ExprListAppend(pParse,0, p, &Y);
  sqlite3ExprListCheckLength(pParse, A, SQLITE_MAX_COLUMN, "index");
  if( A ) A->a[A->nExpr-1].sortOrder = Z;
}
idxitem(A) ::= nm(X).              {A = X;}

%type collate {Token}
collate(C) ::= .                {C.z = 0; C.n = 0;}
collate(C) ::= COLLATE id(X).   {C = X;}


///////////////////////////// The DROP INDEX command /////////////////////////
//
cmd ::= DROP INDEX ifexists(E) fullname(X).   {sqlite3DropIndex(pParse, X, E);}

///////////////////////////// The VACUUM command /////////////////////////////







|







 







|







 







|







 







|









|









|







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
...
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
...
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
...
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
**
*************************************************************************
** This file contains SQLite's grammar for SQL.  Process this file
** using the lemon parser generator to generate C code that runs
** the parser.  Lemon will also generate a header file containing
** numeric codes for all of the tokens.
**
** @(#) $Id: parse.y,v 1.235 2007/11/12 09:50:26 danielk1977 Exp $
*/

// All token codes are small integers with #defines that begin with "TK_"
%token_prefix TK_

// The type of the data attached to each token is Token.  This is also the
// default type for non-terminals.
................................................................................
ccons ::= PRIMARY KEY sortorder(Z) onconf(R) autoinc(I).
                                     {sqlite3AddPrimaryKey(pParse,0,R,I,Z);}
ccons ::= UNIQUE onconf(R).    {sqlite3CreateIndex(pParse,0,0,0,0,R,0,0,0,0);}
ccons ::= CHECK LP expr(X) RP.       {sqlite3AddCheckConstraint(pParse,X);}
ccons ::= REFERENCES nm(T) idxlist_opt(TA) refargs(R).
                                {sqlite3CreateForeignKey(pParse,0,&T,TA,R);}
ccons ::= defer_subclause(D).   {sqlite3DeferForeignKey(pParse,D);}
ccons ::= COLLATE ids(C).  {sqlite3AddCollateType(pParse, &C);}

// The optional AUTOINCREMENT keyword
%type autoinc {int}
autoinc(X) ::= .          {X = 0;}
autoinc(X) ::= AUTOINCR.  {X = 1;}

// The next group of rules parses the arguments to a REFERENCES clause
................................................................................
term(A) ::= STRING(X).       {A = sqlite3PExpr(pParse, @X, 0, 0, &X);}
expr(A) ::= REGISTER(X).     {A = sqlite3RegisterExpr(pParse, &X);}
expr(A) ::= VARIABLE(X).     {
  Token *pToken = &X;
  Expr *pExpr = A = sqlite3PExpr(pParse, TK_VARIABLE, 0, 0, pToken);
  sqlite3ExprAssignVarNumber(pParse, pExpr);
}
expr(A) ::= expr(E) COLLATE ids(C). {
  A = sqlite3ExprSetColl(pParse, E, &C);
}
%ifndef SQLITE_OMIT_CAST
expr(A) ::= CAST(X) LP expr(E) AS typetoken(T) RP(Y). {
  A = sqlite3PExpr(pParse, TK_CAST, E, 0, &T);
  sqlite3ExprSpan(A,&X,&Y);
}
................................................................................

idxlist_opt(A) ::= .                         {A = 0;}
idxlist_opt(A) ::= LP idxlist(X) RP.         {A = X;}
idxlist(A) ::= idxlist(X) COMMA idxitem(Y) collate(C) sortorder(Z).  {
  Expr *p = 0;
  if( C.n>0 ){
    p = sqlite3PExpr(pParse, TK_COLUMN, 0, 0, 0);
    sqlite3ExprSetColl(pParse, p, &C);
  }
  A = sqlite3ExprListAppend(pParse,X, p, &Y);
  sqlite3ExprListCheckLength(pParse, A, SQLITE_MAX_COLUMN, "index");
  if( A ) A->a[A->nExpr-1].sortOrder = Z;
}
idxlist(A) ::= idxitem(Y) collate(C) sortorder(Z). {
  Expr *p = 0;
  if( C.n>0 ){
    p = sqlite3PExpr(pParse, TK_COLUMN, 0, 0, 0);
    sqlite3ExprSetColl(pParse, p, &C);
  }
  A = sqlite3ExprListAppend(pParse,0, p, &Y);
  sqlite3ExprListCheckLength(pParse, A, SQLITE_MAX_COLUMN, "index");
  if( A ) A->a[A->nExpr-1].sortOrder = Z;
}
idxitem(A) ::= nm(X).              {A = X;}

%type collate {Token}
collate(C) ::= .                {C.z = 0; C.n = 0;}
collate(C) ::= COLLATE ids(X).   {C = X;}


///////////////////////////// The DROP INDEX command /////////////////////////
//
cmd ::= DROP INDEX ifexists(E) fullname(X).   {sqlite3DropIndex(pParse, X, E);}

///////////////////////////// The VACUUM command /////////////////////////////

Changes to src/sqliteInt.h.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
....
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.617 2007/10/23 15:59:18 drh Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_

/*
** These #defines should enable >2GB file support on Posix if the
** underlying operating system supports it.  If the OS lacks
................................................................................
void sqlite3StartTable(Parse*,Token*,Token*,int,int,int,int);
void sqlite3AddColumn(Parse*,Token*);
void sqlite3AddNotNull(Parse*, int);
void sqlite3AddPrimaryKey(Parse*, ExprList*, int, int, int);
void sqlite3AddCheckConstraint(Parse*, Expr*);
void sqlite3AddColumnType(Parse*,Token*);
void sqlite3AddDefaultValue(Parse*,Expr*);
void sqlite3AddCollateType(Parse*, const char*, int);
void sqlite3EndTable(Parse*,Token*,Token*,Select*);

void sqlite3CreateView(Parse*,Token*,Token*,Token*,Select*,int,int);

#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE)
  int sqlite3ViewGetColumnNames(Parse*,Table*);
#else







|







 







|







7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
....
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.618 2007/11/12 09:50:26 danielk1977 Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_

/*
** These #defines should enable >2GB file support on Posix if the
** underlying operating system supports it.  If the OS lacks
................................................................................
void sqlite3StartTable(Parse*,Token*,Token*,int,int,int,int);
void sqlite3AddColumn(Parse*,Token*);
void sqlite3AddNotNull(Parse*, int);
void sqlite3AddPrimaryKey(Parse*, ExprList*, int, int, int);
void sqlite3AddCheckConstraint(Parse*, Expr*);
void sqlite3AddColumnType(Parse*,Token*);
void sqlite3AddDefaultValue(Parse*,Expr*);
void sqlite3AddCollateType(Parse*, Token*);
void sqlite3EndTable(Parse*,Token*,Token*,Select*);

void sqlite3CreateView(Parse*,Token*,Token*,Token*,Select*,int,int);

#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE)
  int sqlite3ViewGetColumnNames(Parse*,Table*);
#else

Added test/collate9.test.









































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
#
# 2007 November 12
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this script is making sure that the names of collation
# sequences may be quoted using double quotes in SQL statements.
#
# $Id: collate9.test,v 1.1 2007/11/12 09:50:26 danielk1977 Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

proc reverse_sort {lhs rhs} {
  return [string compare $rhs $lhs]
}
db collate "reverse sort" reverse_sort

# This procedure executes the SQL.  Then it checks to see if the OP_Sort
# opcode was executed.  If an OP_Sort did occur, then "sort" is appended
# to the result.  If no OP_Sort happened, then "nosort" is appended.
#
# This procedure is used to check to make sure sorting is or is not
# occurring as expected.
#
proc cksort {sql} {
  set ::sqlite_sort_count 0
  set data [execsql $sql]
  if {$::sqlite_sort_count} {set x sort} {set x nosort}
  lappend data $x
  return $data
}

# Test plan:
#
#     collate9-1.* - Test collation sequences attached to table columns
#     collate9-2.* - Test collation sequences attached to expressions
#     collate9-3.* - Test collation sequences attached to an index
#     collate9-4.* - Test collation sequences as an argument to REINDEX
#

do_test collate9-1.1 {
  execsql {
    CREATE TABLE xy(x COLLATE "reverse sort", y COLLATE binary);
    INSERT INTO xy VALUES('one', 'one');
    INSERT INTO xy VALUES('two', 'two');
    INSERT INTO xy VALUES('three', 'three');
  }
} {}
do_test collate9-1.2 {
  execsql { 
    SELECT x FROM xy ORDER BY x
  }
} {two three one}
do_test collate9-1.3 {
  execsql { 
    SELECT y FROM xy ORDER BY y
  }
} {one three two}
do_test collate9-1.4 {
  cksort { 
    SELECT x FROM xy ORDER BY x
  }
} {two three one sort}
do_test collate9-1.5 {
  execsql { 
    CREATE INDEX xy_i ON xy(x)
  }
} {}
do_test collate9-1.6 {
  cksort { 
    SELECT x FROM xy ORDER BY x
  }
} {two three one nosort}

do_test collate9-2.1 {
  execsql { 
    SELECT x, x < 'seven' FROM xy ORDER BY x
  }
} {two 1 three 1 one 0}
do_test collate9-2.2 {
  execsql { 
    SELECT y, y < 'seven' FROM xy ORDER BY x
  }
} {two 0 three 0 one 1}
do_test collate9-2.3 {
  execsql { 
    SELECT y, y COLLATE "reverse sort" < 'seven' FROM xy ORDER BY x
  }
} {two 1 three 1 one 0}
do_test collate9-2.4 {
  execsql {
    SELECT y FROM xy ORDER BY y
  }
} {one three two}
do_test collate9-2.5 {
  execsql {
    SELECT y FROM xy ORDER BY y COLLATE "reverse sort"
  }
} {two three one}

do_test collate9-3.1 {
  execsql {
    CREATE INDEX xy_i2 ON xy(y COLLATE "reverse sort");
  }
} {}
do_test collate9-3.2 {
  cksort { 
    SELECT y FROM xy ORDER BY y 
  }
} {one three two sort}
do_test collate9-3.3 {
  cksort { 
    SELECT y FROM xy ORDER BY y COLLATE "reverse sort"
  }
} {two three one nosort}

ifcapable reindex {
  do_test collate9-4.1 {
    execsql {
      REINDEX "reverse sort"
    }
  } {}

  # Modify the "reverse sort" collation so that it now sorts in the same
  # order as binary.
  proc reverse_sort {lhs rhs} {
    return [string compare $lhs $rhs]
  }

  # The integrity check should now fail because the indexes created using
  # "reverse sort" are no longer in sync with the collation sequence
  # implementation.
  do_test collate9-4.2 {
    expr {"ok" eq [execsql { PRAGMA integrity_check }]}
  } {0}

  do_test collate9-4.3 {
    execsql {
      REINDEX "reverse sort"
    }
  } {}

  # Integrity check should now pass.
  do_test collate9-4.4 {
    expr {"ok" eq [execsql { PRAGMA integrity_check }]}
  } {1}

  do_test collate9-4.5 {
    cksort {
      SELECT x FROM xy ORDER BY x COLLATE "reverse sort"
    }
  } {one three two nosort}
}

finish_test