mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-30 19:03:16 +03:00
Some progress on user-defined collation sequences. (CVS 1544)
FossilOrigin-Name: c634e71f1909819fb55c728bc410e5cc390428e3
This commit is contained in:
53
manifest
53
manifest
@ -1,5 +1,5 @@
|
|||||||
C Start\sall\stransactions\sand\sverify\sall\sschema\scookies\snear\sthe\sbeginning\sof\nof\seach\svdbe\sprogram.\s(CVS\s1543)
|
C Some\sprogress\son\suser-defined\scollation\ssequences.\s(CVS\s1544)
|
||||||
D 2004-06-09T00:48:12
|
D 2004-06-09T09:55:17
|
||||||
F Makefile.in ab7b0d5118e2da97bac66be8684a1034e3500f5a
|
F Makefile.in ab7b0d5118e2da97bac66be8684a1034e3500f5a
|
||||||
F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
|
F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
|
||||||
F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
|
F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
|
||||||
@ -27,17 +27,17 @@ F src/attach.c e76e4590ec5dd389e5646b171881b5243a6ef391
|
|||||||
F src/auth.c 5c2f0bea4729c98c2be3b69d6b466fc51448fe79
|
F src/auth.c 5c2f0bea4729c98c2be3b69d6b466fc51448fe79
|
||||||
F src/btree.c edb38affc2e83f4299e49104cfe14e6570d8bd32
|
F src/btree.c edb38affc2e83f4299e49104cfe14e6570d8bd32
|
||||||
F src/btree.h 589427ac13bb544d298cd99726e2572a6fe4bdaa
|
F src/btree.h 589427ac13bb544d298cd99726e2572a6fe4bdaa
|
||||||
F src/build.c f720a2538af6b39a0edc9f62fad3a8c809d455b5
|
F src/build.c 763cb50521ee88873522ae2e836b121f312d2bb2
|
||||||
F src/date.c 8e6fa3173386fb29fdef012ee08a853c1e9908b2
|
F src/date.c 8e6fa3173386fb29fdef012ee08a853c1e9908b2
|
||||||
F src/delete.c b30f08250c9ed53a25a13c7c04599c1e8753992d
|
F src/delete.c b30f08250c9ed53a25a13c7c04599c1e8753992d
|
||||||
F src/encode.c a876af473d1d636faa3dca51c7571f2e007eea37
|
F src/encode.c a876af473d1d636faa3dca51c7571f2e007eea37
|
||||||
F src/expr.c 2b18dd4ed178e39989f22d75bf0e68ba6ed3923c
|
F src/expr.c 3aea8faac17debea4f5c2659351c27d5660453a0
|
||||||
F src/func.c ffbdfa4cad2a16a41390c2ce923ef8b0f173d777
|
F src/func.c ffbdfa4cad2a16a41390c2ce923ef8b0f173d777
|
||||||
F src/hash.c 440c2f8cb373ee1b4e13a0988489c7cd95d55b6f
|
F src/hash.c 440c2f8cb373ee1b4e13a0988489c7cd95d55b6f
|
||||||
F src/hash.h 762d95f1e567664d1eafc1687de755626be962fb
|
F src/hash.h 762d95f1e567664d1eafc1687de755626be962fb
|
||||||
F src/insert.c 4268d9e3959cc845ea243fb4ec7507269404dad9
|
F src/insert.c 4268d9e3959cc845ea243fb4ec7507269404dad9
|
||||||
F src/legacy.c ad23746f15f67e34577621b1875f639c94839e1f
|
F src/legacy.c ad23746f15f67e34577621b1875f639c94839e1f
|
||||||
F src/main.c f94886765e71082d020c9d7b4d4f8645029ee7f6
|
F src/main.c ac8a6e871be5917775d2728b9abbb1659d59f8fd
|
||||||
F src/md5.c 4302e84ae516c616bb079c4e6d038c0addb33481
|
F src/md5.c 4302e84ae516c616bb079c4e6d038c0addb33481
|
||||||
F src/os.h a3a9c2df29acbff54aef742e85c302d23634019f
|
F src/os.h a3a9c2df29acbff54aef742e85c302d23634019f
|
||||||
F src/os_common.h 12074232439f904b3805beeff1245bd1b5532994
|
F src/os_common.h 12074232439f904b3805beeff1245bd1b5532994
|
||||||
@ -49,34 +49,34 @@ F src/os_win.c a13b85a0d4889e3d0b254ed2a61354acddc59fc4
|
|||||||
F src/os_win.h 004eec47b1780fcaf07420ddc2072294b698d48c
|
F src/os_win.h 004eec47b1780fcaf07420ddc2072294b698d48c
|
||||||
F src/pager.c 3fddd1e5b3e449b19e4f762ab1f1d10786d56d28
|
F src/pager.c 3fddd1e5b3e449b19e4f762ab1f1d10786d56d28
|
||||||
F src/pager.h 0c7b5ac45c69e690c45d160d03bdc8fbd2d4657b
|
F src/pager.h 0c7b5ac45c69e690c45d160d03bdc8fbd2d4657b
|
||||||
F src/parse.y 19972fbaa3440f511da36eae1d1fe536fe2c7805
|
F src/parse.y 097438674976355a10cf177bd97326c548820b86
|
||||||
F src/pragma.c 9328a31c22615758077e8ded1126affe8f5e7fbe
|
F src/pragma.c 9328a31c22615758077e8ded1126affe8f5e7fbe
|
||||||
F src/printf.c 63b15f1ea9fe3daa066bb7430fd20d4a2d717dc8
|
F src/printf.c 63b15f1ea9fe3daa066bb7430fd20d4a2d717dc8
|
||||||
F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3
|
F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3
|
||||||
F src/select.c 0ac0adeb2ae15255ac4399d9ee1b0d25a266a676
|
F src/select.c 1f8355e702f109f6771f82a9bfe7aac4c82cbaf2
|
||||||
F src/shell.c ca519519dcbbc582f6d88f7d0e7583b857fd3469
|
F src/shell.c ca519519dcbbc582f6d88f7d0e7583b857fd3469
|
||||||
F src/sqlite.h.in 577974e9a1b85815ccddfb5b858695b62000f595
|
F src/sqlite.h.in 6ad05abc7fd72da74691e1eb45f0eff4117eba4e
|
||||||
F src/sqliteInt.h 472033b41fe76cf0a9c39dda410cedbadeb61b03
|
F src/sqliteInt.h 55525f9a2d7b238ea4a89c04ae86fe9339452d6d
|
||||||
F src/table.c af14284fa36c8d41f6829e3f2819dce07d3e2de2
|
F src/table.c af14284fa36c8d41f6829e3f2819dce07d3e2de2
|
||||||
F src/tclsqlite.c c4d549ad9f5941288247759ead89d9632254fdc3
|
F src/tclsqlite.c f5c5116720baefb7de5d6acf18baedf1e42756cc
|
||||||
F src/test1.c 416a37411f2ca7947e6509c5b6ddc6dd86a1204e
|
F src/test1.c 73770f2cd2bf97027e2edf62ee345e90c78dfcef
|
||||||
F src/test2.c ae18537d8a85e5028c955837797f9da461b908b8
|
F src/test2.c ae18537d8a85e5028c955837797f9da461b908b8
|
||||||
F src/test3.c beafd0ccf7b9ae784744be1b1e66ffe8f64c25da
|
F src/test3.c beafd0ccf7b9ae784744be1b1e66ffe8f64c25da
|
||||||
F src/test4.c a921a69821fd30209589228e64f94e9f715b6fe2
|
F src/test4.c a921a69821fd30209589228e64f94e9f715b6fe2
|
||||||
F src/test5.c 44178ce85c3afd2004ab4eeb5cfd7487116ce366
|
F src/test5.c 862784cd7a68e7d36f00287aac6e413ca996eaf8
|
||||||
F src/tokenize.c 183c5d7da11affab5d70d903d33409c8c0ce6c5b
|
F src/tokenize.c 183c5d7da11affab5d70d903d33409c8c0ce6c5b
|
||||||
F src/trigger.c 2c28bf37f21e1ca2fc39cd88db8dbe3ad6ac5419
|
F src/trigger.c 2c28bf37f21e1ca2fc39cd88db8dbe3ad6ac5419
|
||||||
F src/update.c 259f06e7b22c684b2d3dda54a18185892d6e9573
|
F src/update.c 259f06e7b22c684b2d3dda54a18185892d6e9573
|
||||||
F src/utf.c c2c8e445bfea724f3502609d6389fe66651f02ab
|
F src/utf.c c2c8e445bfea724f3502609d6389fe66651f02ab
|
||||||
F src/util.c 8b3680271111bcdf5b395916b08b9a6684e0e73d
|
F src/util.c ad379519d8267ea1f626874ad4e629e982e8ca58
|
||||||
F src/vacuum.c b921eb778842592e1fb48a9d4cef7e861103878f
|
F src/vacuum.c b921eb778842592e1fb48a9d4cef7e861103878f
|
||||||
F src/vdbe.c 3ffa1effb57f861131f1abc6d4f14db81fad2ade
|
F src/vdbe.c fec13be8b6f03158bfb3069c7bd6182eb3ef4fca
|
||||||
F src/vdbe.h 46f74444a213129bc4b5ce40124dd8ed613b0cde
|
F src/vdbe.h 46f74444a213129bc4b5ce40124dd8ed613b0cde
|
||||||
F src/vdbeInt.h ab592f23ed5a1913f9a506bd7b76c5e39377942a
|
F src/vdbeInt.h ab592f23ed5a1913f9a506bd7b76c5e39377942a
|
||||||
F src/vdbeapi.c 4ac95766b0515538037a7aec172ed26142f97cf9
|
F src/vdbeapi.c 4ac95766b0515538037a7aec172ed26142f97cf9
|
||||||
F src/vdbeaux.c ab8c99fd5c94ff366f0db3801eb7a1d3f4026e23
|
F src/vdbeaux.c 8547c18b160f3e02fb14e90f0162c195af702c00
|
||||||
F src/vdbemem.c 5d029d83bc60eaf9c45837fcbc0b03348ec95d7a
|
F src/vdbemem.c 04502b81039f9a2b1c9a096e894eecf6d4877508
|
||||||
F src/where.c ded00b92dcee77ebe358ff48f5ef05ee8e8ff163
|
F src/where.c 32578882a245f8ac3303c5cea4664cd51fc73891
|
||||||
F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242
|
F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242
|
||||||
F test/attach.test aed659e52635662bcd5069599aaca823533edf5a
|
F test/attach.test aed659e52635662bcd5069599aaca823533edf5a
|
||||||
F test/attach2.test 2185dce04ef9ceb7b2d3df7d17fb2c3817028dea
|
F test/attach2.test 2185dce04ef9ceb7b2d3df7d17fb2c3817028dea
|
||||||
@ -94,6 +94,9 @@ F test/btree6.test a5ede6bfbbb2ec8b27e62813612c0f28e8f3e027
|
|||||||
F test/btree7.test 429b96cfef5b51a7d512cfb4b5b3e453384af293
|
F test/btree7.test 429b96cfef5b51a7d512cfb4b5b3e453384af293
|
||||||
F test/capi2.test 8fb64e8ab7f78b8254cd4d04bb96822167f731b2
|
F test/capi2.test 8fb64e8ab7f78b8254cd4d04bb96822167f731b2
|
||||||
F test/capi3.test b6fe8a66d2ffe28d4faaaec154a143131e8ff631
|
F test/capi3.test b6fe8a66d2ffe28d4faaaec154a143131e8ff631
|
||||||
|
F test/collate1.test 7f1ad4c24ea949b7a7aee387df7839389990a998
|
||||||
|
F test/collate2.test 5b92d795048794266ac27f242a411da8ffeaae25
|
||||||
|
F test/collate4.test a8f2d58bd6943ed1746639c11b12896ccfe8f646
|
||||||
F test/conflict.test 45ce1e44ea748944aed233df8c278a9e1c4c87cc
|
F test/conflict.test 45ce1e44ea748944aed233df8c278a9e1c4c87cc
|
||||||
F test/crashtest1.c 09c1c7d728ccf4feb9e481671e29dda5669bbcc2
|
F test/crashtest1.c 09c1c7d728ccf4feb9e481671e29dda5669bbcc2
|
||||||
F test/date.test aed5030482ebc02bd8d386c6c86a29f694ab068d
|
F test/date.test aed5030482ebc02bd8d386c6c86a29f694ab068d
|
||||||
@ -122,7 +125,7 @@ F test/malloc.test 4e19b96d9cd7d61f4826e6fce03849ad5ad526dd
|
|||||||
F test/memdb.test 6ece25c7c0e6500199d3662607a3edca081abb2a
|
F test/memdb.test 6ece25c7c0e6500199d3662607a3edca081abb2a
|
||||||
F test/memleak.test 4d5d374c8ea1fc5ac634aed58cac1047848ce65e
|
F test/memleak.test 4d5d374c8ea1fc5ac634aed58cac1047848ce65e
|
||||||
F test/minmax.test 9dcf52f713b1b9e61d0a88a51eb8bb2e3c52d0ab
|
F test/minmax.test 9dcf52f713b1b9e61d0a88a51eb8bb2e3c52d0ab
|
||||||
F test/misc1.test 508ef7287490900570054dfd853641ec4ef66cd6
|
F test/misc1.test 06e92b613615d38919bf6fea85536bc685a3da4b
|
||||||
F test/misc2.test 10c2ce26407d37411b96273e552d5095393732be
|
F test/misc2.test 10c2ce26407d37411b96273e552d5095393732be
|
||||||
F test/misc3.test eb488314990bfc0959221a1acc465013238bf168
|
F test/misc3.test eb488314990bfc0959221a1acc465013238bf168
|
||||||
F test/misuse.test 1095f26d1aed406c65e1d2eba651c4bb7c38cbff
|
F test/misuse.test 1095f26d1aed406c65e1d2eba651c4bb7c38cbff
|
||||||
@ -142,11 +145,11 @@ F test/select3.test f8ff60d98c7b4898f5e7326f0c5929ba56f5d047
|
|||||||
F test/select4.test 86e72fc3b07de4fe11439aa419e37db3c49467e2
|
F test/select4.test 86e72fc3b07de4fe11439aa419e37db3c49467e2
|
||||||
F test/select5.test 3f3f0f31e674fa61f8a3bdb6af1517dfae674081
|
F test/select5.test 3f3f0f31e674fa61f8a3bdb6af1517dfae674081
|
||||||
F test/select6.test a9e31906e700e7c7592c4d0acfc022808f718baf
|
F test/select6.test a9e31906e700e7c7592c4d0acfc022808f718baf
|
||||||
F test/sort.test 863f07884fb68a70b738998e9a548132a0d0b7d9
|
F test/sort.test dbd94673b05054e44ca3f08a80faa1e890ef06d8
|
||||||
F test/subselect.test f0fea8cf9f386d416d64d152e3c65f9116d0f50f
|
F test/subselect.test f0fea8cf9f386d416d64d152e3c65f9116d0f50f
|
||||||
F test/table.test 1defd90e8200661a822618b18748b9339a7fef2f
|
F test/table.test 1defd90e8200661a822618b18748b9339a7fef2f
|
||||||
F test/tableapi.test e0c4cce61e58343caa84dab33fa6823cb35fe1e1
|
F test/tableapi.test e0c4cce61e58343caa84dab33fa6823cb35fe1e1
|
||||||
F test/tclsqlite.test 853e4372004d209e2ff0d4b0b35c91d4f64cd7d8
|
F test/tclsqlite.test ab5e5c5a00b592c48c38fec8095cde74186c3fc2
|
||||||
F test/temptable.test a770ba6308d7f7332fce985086b8e06bed6430c2
|
F test/temptable.test a770ba6308d7f7332fce985086b8e06bed6430c2
|
||||||
F test/tester.tcl fc10520db0d3ce4ef6a8b5ab91bd102fc3f4280a
|
F test/tester.tcl fc10520db0d3ce4ef6a8b5ab91bd102fc3f4280a
|
||||||
F test/thread1.test 2fd5c10e82434f6b03be77b61fde5a050668abf2
|
F test/thread1.test 2fd5c10e82434f6b03be77b61fde5a050668abf2
|
||||||
@ -194,7 +197,7 @@ F www/conflict.tcl fb8a2ba83746c7fdfd9e52fa7f6aaf5c422b8246
|
|||||||
F www/copyright-release.html 294e011760c439c44951a6bfecd4c81a1ae359e8
|
F www/copyright-release.html 294e011760c439c44951a6bfecd4c81a1ae359e8
|
||||||
F www/copyright-release.pdf cfca3558fc97095e57c6117d08f1f5b80d95125a
|
F www/copyright-release.pdf cfca3558fc97095e57c6117d08f1f5b80d95125a
|
||||||
F www/copyright.tcl 82c9670c7ddb0311912ab7fe24703f33c531066c
|
F www/copyright.tcl 82c9670c7ddb0311912ab7fe24703f33c531066c
|
||||||
F www/datatype3.tcl 22f59662aa4b7a246ef56ee1bf40c514fc06e21c
|
F www/datatype3.tcl 547a852a4c5970e431e7e3c0ae4b1b3ce82c2063
|
||||||
F www/datatypes.tcl 566004b81c36877397ddbe6e1907aae6065f6b41
|
F www/datatypes.tcl 566004b81c36877397ddbe6e1907aae6065f6b41
|
||||||
F www/docs.tcl 0dcbf954907bd5dbfb7f1e0220f4e50516e07cd3
|
F www/docs.tcl 0dcbf954907bd5dbfb7f1e0220f4e50516e07cd3
|
||||||
F www/download.tcl 8c84f15695c92cb01486930055fdf5192995f474
|
F www/download.tcl 8c84f15695c92cb01486930055fdf5192995f474
|
||||||
@ -215,7 +218,7 @@ F www/support.tcl 1801397edd271cc39a2aadd54e701184b5181248
|
|||||||
F www/tclsqlite.tcl 19191cf2a1010eaeff74c51d83fd5f5a4d899075
|
F www/tclsqlite.tcl 19191cf2a1010eaeff74c51d83fd5f5a4d899075
|
||||||
F www/vdbe.tcl 59288db1ac5c0616296b26dce071c36cb611dfe9
|
F www/vdbe.tcl 59288db1ac5c0616296b26dce071c36cb611dfe9
|
||||||
F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4
|
F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4
|
||||||
P 4dfdea7373f3471d17498da3d6c3aaf926a72d4b
|
P 1086196460e261718e78512d77e25dde021a117d
|
||||||
R 6bf109928e5c77863915e3d9ce0daa3e
|
R 20d537aca227a4420895d927bae8916e
|
||||||
U drh
|
U danielk1977
|
||||||
Z 588abfea4494baa41bec5420972c8c24
|
Z 480a8bf4fe8242d162be76603ac93c57
|
||||||
|
@ -1 +1 @@
|
|||||||
1086196460e261718e78512d77e25dde021a117d
|
c634e71f1909819fb55c728bc410e5cc390428e3
|
155
src/build.c
155
src/build.c
@ -23,7 +23,7 @@
|
|||||||
** ROLLBACK
|
** ROLLBACK
|
||||||
** PRAGMA
|
** PRAGMA
|
||||||
**
|
**
|
||||||
** $Id: build.c,v 1.210 2004/06/09 00:48:12 drh Exp $
|
** $Id: build.c,v 1.211 2004/06/09 09:55:17 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
@ -784,7 +784,7 @@ void sqlite3AddDefaultValue(Parse *pParse, Token *pVal, int minusFlag){
|
|||||||
** If the key is not an INTEGER PRIMARY KEY, then create a unique
|
** If the key is not an INTEGER PRIMARY KEY, then create a unique
|
||||||
** index for the key. No index is created for INTEGER PRIMARY KEYs.
|
** index for the key. No index is created for INTEGER PRIMARY KEYs.
|
||||||
*/
|
*/
|
||||||
void sqlite3AddPrimaryKey(Parse *pParse, IdList *pList, int onError){
|
void sqlite3AddPrimaryKey(Parse *pParse, ExprList *pList, int onError){
|
||||||
Table *pTab = pParse->pNewTable;
|
Table *pTab = pParse->pNewTable;
|
||||||
char *zType = 0;
|
char *zType = 0;
|
||||||
int iCol = -1, i;
|
int iCol = -1, i;
|
||||||
@ -799,7 +799,7 @@ void sqlite3AddPrimaryKey(Parse *pParse, IdList *pList, int onError){
|
|||||||
iCol = pTab->nCol - 1;
|
iCol = pTab->nCol - 1;
|
||||||
pTab->aCol[iCol].isPrimKey = 1;
|
pTab->aCol[iCol].isPrimKey = 1;
|
||||||
}else{
|
}else{
|
||||||
for(i=0; i<pList->nId; i++){
|
for(i=0; i<pList->nExpr; i++){
|
||||||
for(iCol=0; iCol<pTab->nCol; iCol++){
|
for(iCol=0; iCol<pTab->nCol; iCol++){
|
||||||
if( sqlite3StrICmp(pList->a[i].zName, pTab->aCol[iCol].zName)==0 ){
|
if( sqlite3StrICmp(pList->a[i].zName, pTab->aCol[iCol].zName)==0 ){
|
||||||
break;
|
break;
|
||||||
@ -807,7 +807,7 @@ void sqlite3AddPrimaryKey(Parse *pParse, IdList *pList, int onError){
|
|||||||
}
|
}
|
||||||
if( iCol<pTab->nCol ) pTab->aCol[iCol].isPrimKey = 1;
|
if( iCol<pTab->nCol ) pTab->aCol[iCol].isPrimKey = 1;
|
||||||
}
|
}
|
||||||
if( pList->nId>1 ) iCol = -1;
|
if( pList->nExpr>1 ) iCol = -1;
|
||||||
}
|
}
|
||||||
if( iCol>=0 && iCol<pTab->nCol ){
|
if( iCol>=0 && iCol<pTab->nCol ){
|
||||||
zType = pTab->aCol[iCol].zType;
|
zType = pTab->aCol[iCol].zType;
|
||||||
@ -821,79 +821,84 @@ void sqlite3AddPrimaryKey(Parse *pParse, IdList *pList, int onError){
|
|||||||
}
|
}
|
||||||
|
|
||||||
primary_key_exit:
|
primary_key_exit:
|
||||||
sqlite3IdListDelete(pList);
|
sqlite3ExprListDelete(pList);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
** Return a pointer to CollSeq given the name of a collating sequence.
|
|
||||||
** If the collating sequence did not previously exist, create it but
|
|
||||||
** assign it an NULL comparison function.
|
|
||||||
*/
|
|
||||||
CollSeq *sqlite3CollateType(Parse *pParse, const char *zType, int nType){
|
|
||||||
CollSeq *pColl;
|
|
||||||
sqlite *db = pParse->db;
|
|
||||||
|
|
||||||
pColl = sqlite3HashFind(&db->aCollSeq, zType, nType);
|
|
||||||
if( pColl==0 ){
|
|
||||||
sqlite3ChangeCollatingFunction(db, zType, nType, 0, 0);
|
|
||||||
pColl = sqlite3HashFind(&db->aCollSeq, zType, nType);
|
|
||||||
}
|
|
||||||
return pColl;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Set the collation function of the most recently parsed table column
|
** Set the collation function of the most recently parsed table column
|
||||||
** to the CollSeq given.
|
** to the CollSeq given.
|
||||||
*/
|
*/
|
||||||
void sqlite3AddCollateType(Parse *pParse, const char *zType, int nType){
|
void sqlite3AddCollateType(Parse *pParse, const char *zType, int nType){
|
||||||
Table *p;
|
Table *p;
|
||||||
|
Index *pIdx;
|
||||||
CollSeq *pColl;
|
CollSeq *pColl;
|
||||||
sqlite *db = pParse->db;
|
int i;
|
||||||
|
|
||||||
if( (p = pParse->pNewTable)==0 ) return;
|
if( (p = pParse->pNewTable)==0 ) return;
|
||||||
pColl = sqlite3HashFind(&db->aCollSeq, zType, nType);
|
i = p->nCol-1;
|
||||||
if( pColl==0 ){
|
|
||||||
pColl = sqlite3ChangeCollatingFunction(db, zType, nType, 0, 0);
|
pColl = sqlite3LocateCollSeq(pParse, zType, nType);
|
||||||
}
|
p->aCol[i].pColl = pColl;
|
||||||
if( pColl ){
|
|
||||||
p->aCol[p->nCol-1].pColl = pColl;
|
/* 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->keyInfo.aColl[0] = pColl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Create or modify a collating sequence entry in the sqlite.aCollSeq
|
** Locate and return an entry from the db.aCollSeq hash table. If the entry
|
||||||
** table.
|
** specified by zName and nName is not found and parameter 'create' is
|
||||||
|
** true, then create a new entry.
|
||||||
**
|
**
|
||||||
** Once an entry is added to the sqlite.aCollSeq table, it can never
|
** FIX ME: For now, return NULL if create is not true and the entry is not
|
||||||
** be removed, though is comparison function or user data can be changed.
|
** found. But this needs to change to call the collation factory.
|
||||||
**
|
**
|
||||||
** Return a pointer to the collating function that was created or modified.
|
** FIX ME: If we have a UTF-8 version of the collation function, and a
|
||||||
|
** UTF-16 version would be better, should the collation factory be called?
|
||||||
|
** If so should a flag be set to say that we already requested such a
|
||||||
|
** function and couldn't get one?
|
||||||
*/
|
*/
|
||||||
CollSeq *sqlite3ChangeCollatingFunction(
|
CollSeq *sqlite3FindCollSeq(
|
||||||
sqlite *db, /* Database into which to insert the collation */
|
sqlite *db,
|
||||||
const char *zName, /* Name of the collation */
|
const char *zName,
|
||||||
int nName, /* Number of characters in zName */
|
int nName,
|
||||||
void *pUser, /* First argument to xCmp */
|
int create
|
||||||
int (*xCmp)(void*,int,const void*,int,const void*) /* Comparison function */
|
|
||||||
){
|
){
|
||||||
CollSeq *pColl;
|
CollSeq *pColl;
|
||||||
|
if( nName<0 ) nName = strlen(zName);
|
||||||
pColl = sqlite3HashFind(&db->aCollSeq, zName, nName);
|
pColl = sqlite3HashFind(&db->aCollSeq, zName, nName);
|
||||||
if( pColl==0 ){
|
if( 0==pColl && create ){
|
||||||
pColl = sqliteMallocRaw( sizeof(*pColl) + nName + 1 );
|
pColl = sqliteMalloc( sizeof(*pColl) + nName + 1 );
|
||||||
if( pColl==0 ){
|
if( pColl ){
|
||||||
return 0;
|
pColl->zName = (char*)&pColl[1];
|
||||||
|
memcpy(pColl->zName, zName, nName+1);
|
||||||
|
sqlite3HashInsert(&db->aCollSeq, pColl->zName, nName, pColl);
|
||||||
}
|
}
|
||||||
pColl->zName = (char*)&pColl[1];
|
|
||||||
memcpy(pColl->zName, zName, nName+1);
|
|
||||||
sqlite3HashInsert(&db->aCollSeq, pColl->zName, nName, pColl);
|
|
||||||
}
|
}
|
||||||
pColl->pUser = pUser;
|
|
||||||
pColl->xCmp = xCmp;
|
|
||||||
return pColl;
|
return pColl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char *zName, int nName){
|
||||||
|
CollSeq *pColl = sqlite3FindCollSeq(pParse->db, zName, nName, 0);
|
||||||
|
if( !pColl ){
|
||||||
|
if( pParse->nErr==0 ){
|
||||||
|
sqlite3SetNString(&pParse->zErrMsg,
|
||||||
|
"no such collation sequence: ", -1,
|
||||||
|
zName, nName, 0);
|
||||||
|
}
|
||||||
|
pParse->nErr++;
|
||||||
|
}
|
||||||
|
return pColl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Scan the column type name zType (length nType) and return the
|
** Scan the column type name zType (length nType) and return the
|
||||||
** associated affinity type.
|
** associated affinity type.
|
||||||
@ -1540,9 +1545,9 @@ exit_drop_table:
|
|||||||
*/
|
*/
|
||||||
void sqlite3CreateForeignKey(
|
void sqlite3CreateForeignKey(
|
||||||
Parse *pParse, /* Parsing context */
|
Parse *pParse, /* Parsing context */
|
||||||
IdList *pFromCol, /* Columns in this table that point to other table */
|
ExprList *pFromCol, /* Columns in this table that point to other table */
|
||||||
Token *pTo, /* Name of the other table */
|
Token *pTo, /* Name of the other table */
|
||||||
IdList *pToCol, /* Columns in the other table */
|
ExprList *pToCol, /* Columns in the other table */
|
||||||
int flags /* Conflict resolution algorithms. */
|
int flags /* Conflict resolution algorithms. */
|
||||||
){
|
){
|
||||||
Table *p = pParse->pNewTable;
|
Table *p = pParse->pNewTable;
|
||||||
@ -1557,24 +1562,24 @@ void sqlite3CreateForeignKey(
|
|||||||
if( pFromCol==0 ){
|
if( pFromCol==0 ){
|
||||||
int iCol = p->nCol-1;
|
int iCol = p->nCol-1;
|
||||||
if( iCol<0 ) goto fk_end;
|
if( iCol<0 ) goto fk_end;
|
||||||
if( pToCol && pToCol->nId!=1 ){
|
if( pToCol && pToCol->nExpr!=1 ){
|
||||||
sqlite3ErrorMsg(pParse, "foreign key on %s"
|
sqlite3ErrorMsg(pParse, "foreign key on %s"
|
||||||
" should reference only one column of table %T",
|
" should reference only one column of table %T",
|
||||||
p->aCol[iCol].zName, pTo);
|
p->aCol[iCol].zName, pTo);
|
||||||
goto fk_end;
|
goto fk_end;
|
||||||
}
|
}
|
||||||
nCol = 1;
|
nCol = 1;
|
||||||
}else if( pToCol && pToCol->nId!=pFromCol->nId ){
|
}else if( pToCol && pToCol->nExpr!=pFromCol->nExpr ){
|
||||||
sqlite3ErrorMsg(pParse,
|
sqlite3ErrorMsg(pParse,
|
||||||
"number of columns in foreign key does not match the number of "
|
"number of columns in foreign key does not match the number of "
|
||||||
"columns in the referenced table");
|
"columns in the referenced table");
|
||||||
goto fk_end;
|
goto fk_end;
|
||||||
}else{
|
}else{
|
||||||
nCol = pFromCol->nId;
|
nCol = pFromCol->nExpr;
|
||||||
}
|
}
|
||||||
nByte = sizeof(*pFKey) + nCol*sizeof(pFKey->aCol[0]) + pTo->n + 1;
|
nByte = sizeof(*pFKey) + nCol*sizeof(pFKey->aCol[0]) + pTo->n + 1;
|
||||||
if( pToCol ){
|
if( pToCol ){
|
||||||
for(i=0; i<pToCol->nId; i++){
|
for(i=0; i<pToCol->nExpr; i++){
|
||||||
nByte += strlen(pToCol->a[i].zName) + 1;
|
nByte += strlen(pToCol->a[i].zName) + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1631,8 +1636,8 @@ void sqlite3CreateForeignKey(
|
|||||||
|
|
||||||
fk_end:
|
fk_end:
|
||||||
sqliteFree(pFKey);
|
sqliteFree(pFKey);
|
||||||
sqlite3IdListDelete(pFromCol);
|
sqlite3ExprListDelete(pFromCol);
|
||||||
sqlite3IdListDelete(pToCol);
|
sqlite3ExprListDelete(pToCol);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1665,8 +1670,8 @@ void sqlite3CreateIndex(
|
|||||||
Parse *pParse, /* All information about this parse */
|
Parse *pParse, /* All information about this parse */
|
||||||
Token *pName1, /* First part of index name. May be NULL */
|
Token *pName1, /* First part of index name. May be NULL */
|
||||||
Token *pName2, /* Second part of index name. May be NULL */
|
Token *pName2, /* Second part of index name. May be NULL */
|
||||||
SrcList *pTblName, /* Name of the table to index. Use pParse->pNewTable if 0 */
|
SrcList *pTblName, /* Table to index. Use pParse->pNewTable if 0 */
|
||||||
IdList *pList, /* A list of columns to be indexed */
|
ExprList *pList, /* A list of columns to be indexed */
|
||||||
int onError, /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
|
int onError, /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
|
||||||
Token *pStart, /* The CREATE token that begins a CREATE TABLE statement */
|
Token *pStart, /* The CREATE token that begins a CREATE TABLE statement */
|
||||||
Token *pEnd /* The ")" that closes the CREATE INDEX statement */
|
Token *pEnd /* The ")" that closes the CREATE INDEX statement */
|
||||||
@ -1794,7 +1799,7 @@ void sqlite3CreateIndex(
|
|||||||
if( pList==0 ){
|
if( pList==0 ){
|
||||||
nullId.z = pTab->aCol[pTab->nCol-1].zName;
|
nullId.z = pTab->aCol[pTab->nCol-1].zName;
|
||||||
nullId.n = strlen(nullId.z);
|
nullId.n = strlen(nullId.z);
|
||||||
pList = sqlite3IdListAppend(0, &nullId);
|
pList = sqlite3ExprListAppend(0, 0, &nullId);
|
||||||
if( pList==0 ) goto exit_create_index;
|
if( pList==0 ) goto exit_create_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1802,13 +1807,13 @@ void sqlite3CreateIndex(
|
|||||||
** Allocate the index structure.
|
** Allocate the index structure.
|
||||||
*/
|
*/
|
||||||
pIndex = sqliteMalloc( sizeof(Index) + strlen(zName) + 1 +
|
pIndex = sqliteMalloc( sizeof(Index) + strlen(zName) + 1 +
|
||||||
(sizeof(int) + sizeof(CollSeq*))*pList->nId );
|
(sizeof(int) + sizeof(CollSeq*))*pList->nExpr );
|
||||||
if( pIndex==0 ) goto exit_create_index;
|
if( pIndex==0 ) goto exit_create_index;
|
||||||
pIndex->aiColumn = (int*)&pIndex->keyInfo.aColl[pList->nId];
|
pIndex->aiColumn = (int*)&pIndex->keyInfo.aColl[pList->nExpr];
|
||||||
pIndex->zName = (char*)&pIndex->aiColumn[pList->nId];
|
pIndex->zName = (char*)&pIndex->aiColumn[pList->nExpr];
|
||||||
strcpy(pIndex->zName, zName);
|
strcpy(pIndex->zName, zName);
|
||||||
pIndex->pTable = pTab;
|
pIndex->pTable = pTab;
|
||||||
pIndex->nColumn = pList->nId;
|
pIndex->nColumn = pList->nExpr;
|
||||||
pIndex->onError = onError;
|
pIndex->onError = onError;
|
||||||
pIndex->autoIndex = pName==0;
|
pIndex->autoIndex = pName==0;
|
||||||
pIndex->iDb = iDb;
|
pIndex->iDb = iDb;
|
||||||
@ -1817,7 +1822,7 @@ void sqlite3CreateIndex(
|
|||||||
** load the column indices into the Index structure. Report an error
|
** load the column indices into the Index structure. Report an error
|
||||||
** if any column is not found.
|
** if any column is not found.
|
||||||
*/
|
*/
|
||||||
for(i=0; i<pList->nId; i++){
|
for(i=0; i<pList->nExpr; i++){
|
||||||
for(j=0; j<pTab->nCol; j++){
|
for(j=0; j<pTab->nCol; j++){
|
||||||
if( sqlite3StrICmp(pList->a[i].zName, pTab->aCol[j].zName)==0 ) break;
|
if( sqlite3StrICmp(pList->a[i].zName, pTab->aCol[j].zName)==0 ) break;
|
||||||
}
|
}
|
||||||
@ -1828,9 +1833,15 @@ void sqlite3CreateIndex(
|
|||||||
goto exit_create_index;
|
goto exit_create_index;
|
||||||
}
|
}
|
||||||
pIndex->aiColumn[i] = j;
|
pIndex->aiColumn[i] = j;
|
||||||
pIndex->keyInfo.aColl[i] = pTab->aCol[j].pColl;
|
if( pList->a[i].pExpr ){
|
||||||
|
assert( pList->a[i].pExpr->pColl );
|
||||||
|
pIndex->keyInfo.aColl[i] = pList->a[i].pExpr->pColl;
|
||||||
|
}else{
|
||||||
|
pIndex->keyInfo.aColl[i] = pTab->aCol[j].pColl;
|
||||||
|
}
|
||||||
|
assert( pIndex->keyInfo.aColl[i] );
|
||||||
}
|
}
|
||||||
pIndex->keyInfo.nField = pList->nId;
|
pIndex->keyInfo.nField = pList->nExpr;
|
||||||
|
|
||||||
/* Link the new Index structure to its table and to the other
|
/* Link the new Index structure to its table and to the other
|
||||||
** in-memory database structures.
|
** in-memory database structures.
|
||||||
@ -1915,7 +1926,11 @@ void sqlite3CreateIndex(
|
|||||||
}
|
}
|
||||||
sqlite3VdbeAddOp(v, OP_String8, 0, 0);
|
sqlite3VdbeAddOp(v, OP_String8, 0, 0);
|
||||||
if( pStart && pEnd ){
|
if( pStart && pEnd ){
|
||||||
sqlite3VdbeChangeP3(v, -1, "CREATE INDEX ", P3_STATIC);
|
if( onError==OE_None ){
|
||||||
|
sqlite3VdbeChangeP3(v, -1, "CREATE INDEX ", P3_STATIC);
|
||||||
|
}else{
|
||||||
|
sqlite3VdbeChangeP3(v, -1, "CREATE UNIQUE INDEX ", P3_STATIC);
|
||||||
|
}
|
||||||
sqlite3VdbeAddOp(v, OP_String8, 0, 0);
|
sqlite3VdbeAddOp(v, OP_String8, 0, 0);
|
||||||
n = Addr(pEnd->z) - Addr(pName->z) + 1;
|
n = Addr(pEnd->z) - Addr(pName->z) + 1;
|
||||||
sqlite3VdbeChangeP3(v, -1, pName->z, n);
|
sqlite3VdbeChangeP3(v, -1, pName->z, n);
|
||||||
@ -1950,7 +1965,7 @@ void sqlite3CreateIndex(
|
|||||||
|
|
||||||
/* Clean up before exiting */
|
/* Clean up before exiting */
|
||||||
exit_create_index:
|
exit_create_index:
|
||||||
sqlite3IdListDelete(pList);
|
sqlite3ExprListDelete(pList);
|
||||||
/* sqlite3SrcListDelete(pTable); */
|
/* sqlite3SrcListDelete(pTable); */
|
||||||
sqliteFree(zName);
|
sqliteFree(zName);
|
||||||
return;
|
return;
|
||||||
|
126
src/expr.c
126
src/expr.c
@ -12,7 +12,7 @@
|
|||||||
** This file contains routines used for analyzing expressions and
|
** This file contains routines used for analyzing expressions and
|
||||||
** for generating VDBE code that evaluates expressions in SQLite.
|
** for generating VDBE code that evaluates expressions in SQLite.
|
||||||
**
|
**
|
||||||
** $Id: expr.c,v 1.136 2004/06/06 12:41:50 danielk1977 Exp $
|
** $Id: expr.c,v 1.137 2004/06/09 09:55:18 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
@ -55,6 +55,20 @@ char sqlite3ExprAffinity(Expr *pExpr){
|
|||||||
return pExpr->affinity;
|
return pExpr->affinity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Return the default collation sequence for the expression pExpr. If
|
||||||
|
** there is no default collation type, return 0.
|
||||||
|
*/
|
||||||
|
CollSeq *sqlite3ExprCollSeq(Expr *pExpr){
|
||||||
|
if( pExpr ){
|
||||||
|
if( pExpr->pColl ) return pExpr->pColl;
|
||||||
|
if( pExpr->op==TK_AS ){
|
||||||
|
return sqlite3ExprCollSeq(pExpr->pLeft);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** pExpr is the left operand of a comparison operator. aff2 is the
|
** pExpr is the left operand of a comparison operator. aff2 is the
|
||||||
** type affinity of the right operand. This routine returns the
|
** type affinity of the right operand. This routine returns the
|
||||||
@ -134,6 +148,23 @@ static int binaryCompareP1(Expr *pExpr1, Expr *pExpr2, int jumpIfNull){
|
|||||||
return (((int)sqlite3CompareAffinity(pExpr1, aff))<<8)+(jumpIfNull?1:0);
|
return (((int)sqlite3CompareAffinity(pExpr1, aff))<<8)+(jumpIfNull?1:0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Return a pointer to the collation sequence that should be used by
|
||||||
|
** a binary comparison operator comparing pLeft and pRight.
|
||||||
|
**
|
||||||
|
** If the left hand expression has a collating sequence type, then it is
|
||||||
|
** used. Otherwise the collation sequence for the right hand expression
|
||||||
|
** is used, or the default (BINARY) if neither expression has a collating
|
||||||
|
** type.
|
||||||
|
*/
|
||||||
|
static CollSeq* binaryCompareCollSeq(Expr *pLeft, Expr *pRight){
|
||||||
|
CollSeq *pColl = sqlite3ExprCollSeq(pLeft);
|
||||||
|
if( !pColl ){
|
||||||
|
pColl = sqlite3ExprCollSeq(pRight);
|
||||||
|
}
|
||||||
|
return pColl;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Construct a new expression node and return a pointer to it. Memory
|
** Construct a new expression node and return a pointer to it. Memory
|
||||||
** for this node is obtained from sqliteMalloc(). The calling function
|
** for this node is obtained from sqliteMalloc(). The calling function
|
||||||
@ -588,6 +619,7 @@ static int lookupName(
|
|||||||
/* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */
|
/* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */
|
||||||
pExpr->iColumn = j==pTab->iPKey ? -1 : j;
|
pExpr->iColumn = j==pTab->iPKey ? -1 : j;
|
||||||
pExpr->affinity = pTab->aCol[j].affinity;
|
pExpr->affinity = pTab->aCol[j].affinity;
|
||||||
|
pExpr->pColl = pTab->aCol[j].pColl;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -620,6 +652,7 @@ static int lookupName(
|
|||||||
cnt++;
|
cnt++;
|
||||||
pExpr->iColumn = j==pTab->iPKey ? -1 : j;
|
pExpr->iColumn = j==pTab->iPKey ? -1 : j;
|
||||||
pExpr->affinity = pTab->aCol[j].affinity;
|
pExpr->affinity = pTab->aCol[j].affinity;
|
||||||
|
pExpr->pColl = pTab->aCol[j].pColl;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -798,6 +831,7 @@ int sqlite3ExprResolveIds(
|
|||||||
char affinity;
|
char affinity;
|
||||||
Vdbe *v = sqlite3GetVdbe(pParse);
|
Vdbe *v = sqlite3GetVdbe(pParse);
|
||||||
KeyInfo keyInfo;
|
KeyInfo keyInfo;
|
||||||
|
int addr; /* Address of OP_OpenTemp instruction */
|
||||||
|
|
||||||
if( v==0 ) return 1;
|
if( v==0 ) return 1;
|
||||||
if( sqlite3ExprResolveIds(pParse, pSrcList, pEList, pExpr->pLeft) ){
|
if( sqlite3ExprResolveIds(pParse, pSrcList, pEList, pExpr->pLeft) ){
|
||||||
@ -819,11 +853,9 @@ int sqlite3ExprResolveIds(
|
|||||||
** is used.
|
** is used.
|
||||||
*/
|
*/
|
||||||
pExpr->iTable = pParse->nTab++;
|
pExpr->iTable = pParse->nTab++;
|
||||||
|
addr = sqlite3VdbeAddOp(v, OP_OpenTemp, pExpr->iTable, 0);
|
||||||
memset(&keyInfo, 0, sizeof(keyInfo));
|
memset(&keyInfo, 0, sizeof(keyInfo));
|
||||||
keyInfo.nField = 1;
|
keyInfo.nField = 1;
|
||||||
keyInfo.aColl[0] = pParse->db->pDfltColl;
|
|
||||||
sqlite3VdbeOp3(v, OP_OpenTemp, pExpr->iTable, 0, \
|
|
||||||
(char*)&keyInfo, P3_KEYINFO);
|
|
||||||
sqlite3VdbeAddOp(v, OP_SetNumColumns, pExpr->iTable, 1);
|
sqlite3VdbeAddOp(v, OP_SetNumColumns, pExpr->iTable, 1);
|
||||||
|
|
||||||
if( pExpr->pSelect ){
|
if( pExpr->pSelect ){
|
||||||
@ -835,6 +867,10 @@ int sqlite3ExprResolveIds(
|
|||||||
int iParm = pExpr->iTable + (((int)affinity)<<16);
|
int iParm = pExpr->iTable + (((int)affinity)<<16);
|
||||||
assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable );
|
assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable );
|
||||||
sqlite3Select(pParse, pExpr->pSelect, SRT_Set, iParm, 0, 0, 0, 0);
|
sqlite3Select(pParse, pExpr->pSelect, SRT_Set, iParm, 0, 0, 0, 0);
|
||||||
|
if( pExpr->pSelect->pEList && pExpr->pSelect->pEList->nExpr>0 ){
|
||||||
|
keyInfo.aColl[0] = binaryCompareCollSeq(pExpr->pLeft,
|
||||||
|
pExpr->pSelect->pEList->a[0].pExpr);
|
||||||
|
}
|
||||||
}else if( pExpr->pList ){
|
}else if( pExpr->pList ){
|
||||||
/* Case 2: expr IN (exprlist)
|
/* Case 2: expr IN (exprlist)
|
||||||
**
|
**
|
||||||
@ -849,6 +885,7 @@ int sqlite3ExprResolveIds(
|
|||||||
affinity = SQLITE_AFF_NUMERIC;
|
affinity = SQLITE_AFF_NUMERIC;
|
||||||
}
|
}
|
||||||
affStr = sqlite3AffinityString(affinity);
|
affStr = sqlite3AffinityString(affinity);
|
||||||
|
keyInfo.aColl[0] = pExpr->pLeft->pColl;
|
||||||
|
|
||||||
/* Loop through each expression in <exprlist>. */
|
/* Loop through each expression in <exprlist>. */
|
||||||
for(i=0; i<pExpr->pList->nExpr; i++){
|
for(i=0; i<pExpr->pList->nExpr; i++){
|
||||||
@ -871,6 +908,8 @@ int sqlite3ExprResolveIds(
|
|||||||
sqlite3VdbeAddOp(v, OP_PutStrKey, pExpr->iTable, 0);
|
sqlite3VdbeAddOp(v, OP_PutStrKey, pExpr->iTable, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
sqlite3VdbeChangeP3(v, addr, (void *)&keyInfo, P3_KEYINFO);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1002,8 +1041,9 @@ int sqlite3ExprCheck(Parse *pParse, Expr *pExpr, int allowAgg, int *pIsAgg){
|
|||||||
nErr = sqlite3ExprCheck(pParse, pExpr->pList->a[i].pExpr,
|
nErr = sqlite3ExprCheck(pParse, pExpr->pList->a[i].pExpr,
|
||||||
allowAgg && !is_agg, pIsAgg);
|
allowAgg && !is_agg, pIsAgg);
|
||||||
}
|
}
|
||||||
/** TODO: Compute pExpr->affinity based on the expected return
|
/* FIX ME: Compute pExpr->affinity based on the expected return
|
||||||
** type of the function */
|
** type of the function
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
if( pExpr->pLeft ){
|
if( pExpr->pLeft ){
|
||||||
@ -1155,9 +1195,10 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
|
|||||||
case TK_NE:
|
case TK_NE:
|
||||||
case TK_EQ: {
|
case TK_EQ: {
|
||||||
int p1 = binaryCompareP1(pExpr->pLeft, pExpr->pRight, 0);
|
int p1 = binaryCompareP1(pExpr->pLeft, pExpr->pRight, 0);
|
||||||
|
CollSeq *p3 = binaryCompareCollSeq(pExpr->pLeft, pExpr->pRight);
|
||||||
sqlite3ExprCode(pParse, pExpr->pLeft);
|
sqlite3ExprCode(pParse, pExpr->pLeft);
|
||||||
sqlite3ExprCode(pParse, pExpr->pRight);
|
sqlite3ExprCode(pParse, pExpr->pRight);
|
||||||
sqlite3VdbeAddOp(v, op, p1, 0);
|
sqlite3VdbeOp3(v, op, p1, 0, (void *)p3, P3_COLLSEQ);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TK_AND:
|
case TK_AND:
|
||||||
@ -1279,13 +1320,19 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TK_BETWEEN: {
|
case TK_BETWEEN: {
|
||||||
|
int p1;
|
||||||
|
CollSeq *p3;
|
||||||
sqlite3ExprCode(pParse, pExpr->pLeft);
|
sqlite3ExprCode(pParse, pExpr->pLeft);
|
||||||
sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
|
sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
|
||||||
sqlite3ExprCode(pParse, pExpr->pList->a[0].pExpr);
|
sqlite3ExprCode(pParse, pExpr->pList->a[0].pExpr);
|
||||||
sqlite3VdbeAddOp(v, OP_Ge, 0, 0);
|
p1 = binaryCompareP1(pExpr->pLeft, pExpr->pList->a[0].pExpr, 0);
|
||||||
|
p3 = binaryCompareCollSeq(pExpr->pLeft, pExpr->pList->a[0].pExpr);
|
||||||
|
sqlite3VdbeOp3(v, OP_Ge, p1, 0, (void *)p3, P3_COLLSEQ);
|
||||||
sqlite3VdbeAddOp(v, OP_Pull, 1, 0);
|
sqlite3VdbeAddOp(v, OP_Pull, 1, 0);
|
||||||
sqlite3ExprCode(pParse, pExpr->pList->a[1].pExpr);
|
sqlite3ExprCode(pParse, pExpr->pList->a[1].pExpr);
|
||||||
sqlite3VdbeAddOp(v, OP_Le, 0, 0);
|
p1 = binaryCompareP1(pExpr->pLeft, pExpr->pList->a[1].pExpr, 0);
|
||||||
|
p3 = binaryCompareCollSeq(pExpr->pLeft, pExpr->pList->a[1].pExpr);
|
||||||
|
sqlite3VdbeOp3(v, OP_Le, p1, 0, (void *)p3, P3_COLLSEQ);
|
||||||
sqlite3VdbeAddOp(v, OP_And, 0, 0);
|
sqlite3VdbeAddOp(v, OP_And, 0, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1312,8 +1359,11 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
|
|||||||
for(i=0; i<nExpr; i=i+2){
|
for(i=0; i<nExpr; i=i+2){
|
||||||
sqlite3ExprCode(pParse, pExpr->pList->a[i].pExpr);
|
sqlite3ExprCode(pParse, pExpr->pList->a[i].pExpr);
|
||||||
if( pExpr->pLeft ){
|
if( pExpr->pLeft ){
|
||||||
|
int p1 = binaryCompareP1(pExpr->pLeft, pExpr->pList->a[i].pExpr, 1);
|
||||||
|
CollSeq *p3 = binaryCompareCollSeq(pExpr->pLeft,
|
||||||
|
pExpr->pList->a[i].pExpr);
|
||||||
sqlite3VdbeAddOp(v, OP_Dup, 1, 1);
|
sqlite3VdbeAddOp(v, OP_Dup, 1, 1);
|
||||||
jumpInst = sqlite3VdbeAddOp(v, OP_Ne, 1, 0);
|
jumpInst = sqlite3VdbeOp3(v, OP_Ne, p1, 0, (void *)p3, P3_COLLSEQ);
|
||||||
sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
|
sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
|
||||||
}else{
|
}else{
|
||||||
jumpInst = sqlite3VdbeAddOp(v, OP_IfNot, 1, 0);
|
jumpInst = sqlite3VdbeAddOp(v, OP_IfNot, 1, 0);
|
||||||
@ -1426,9 +1476,10 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
|||||||
case TK_NE:
|
case TK_NE:
|
||||||
case TK_EQ: {
|
case TK_EQ: {
|
||||||
int p1 = binaryCompareP1(pExpr->pLeft, pExpr->pRight, jumpIfNull);
|
int p1 = binaryCompareP1(pExpr->pLeft, pExpr->pRight, jumpIfNull);
|
||||||
|
CollSeq *p3 = binaryCompareCollSeq(pExpr->pLeft, pExpr->pRight);
|
||||||
sqlite3ExprCode(pParse, pExpr->pLeft);
|
sqlite3ExprCode(pParse, pExpr->pLeft);
|
||||||
sqlite3ExprCode(pParse, pExpr->pRight);
|
sqlite3ExprCode(pParse, pExpr->pRight);
|
||||||
sqlite3VdbeAddOp(v, op, p1, dest);
|
sqlite3VdbeOp3(v, op, p1, dest, (void *)p3, P3_COLLSEQ);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TK_ISNULL:
|
case TK_ISNULL:
|
||||||
@ -1438,13 +1489,27 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TK_BETWEEN: {
|
case TK_BETWEEN: {
|
||||||
|
/* The expression "x BETWEEN y AND z" is implemented as:
|
||||||
|
**
|
||||||
|
** 1 IF (x < y) GOTO 3
|
||||||
|
** 2 IF (x <= z) GOTO <dest>
|
||||||
|
** 3 ...
|
||||||
|
*/
|
||||||
int addr;
|
int addr;
|
||||||
|
int p1;
|
||||||
|
CollSeq *p3;
|
||||||
sqlite3ExprCode(pParse, pExpr->pLeft);
|
sqlite3ExprCode(pParse, pExpr->pLeft);
|
||||||
sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
|
sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
|
||||||
sqlite3ExprCode(pParse, pExpr->pList->a[0].pExpr);
|
sqlite3ExprCode(pParse, pExpr->pList->a[0].pExpr);
|
||||||
addr = sqlite3VdbeAddOp(v, OP_Lt, !jumpIfNull, 0);
|
p1 = binaryCompareP1(pExpr->pLeft, pExpr->pList->a[0].pExpr, !jumpIfNull);
|
||||||
|
p3 = binaryCompareCollSeq(pExpr->pLeft, pExpr->pList->a[0].pExpr);
|
||||||
|
addr = sqlite3VdbeOp3(v, OP_Lt, p1, 0, (void *)p3, P3_COLLSEQ);
|
||||||
|
|
||||||
sqlite3ExprCode(pParse, pExpr->pList->a[1].pExpr);
|
sqlite3ExprCode(pParse, pExpr->pList->a[1].pExpr);
|
||||||
sqlite3VdbeAddOp(v, OP_Le, jumpIfNull, dest);
|
p1 = binaryCompareP1(pExpr->pLeft, pExpr->pList->a[1].pExpr, jumpIfNull);
|
||||||
|
p3 = binaryCompareCollSeq(pExpr->pLeft, pExpr->pList->a[1].pExpr);
|
||||||
|
sqlite3VdbeOp3(v, OP_Le, p1, dest, (void *)p3, P3_COLLSEQ);
|
||||||
|
|
||||||
sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
|
sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
|
||||||
sqlite3VdbeChangeP2(v, addr, sqlite3VdbeCurrentAddr(v));
|
sqlite3VdbeChangeP2(v, addr, sqlite3VdbeCurrentAddr(v));
|
||||||
sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
|
sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
|
||||||
@ -1505,9 +1570,10 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
|||||||
case TK_NE:
|
case TK_NE:
|
||||||
case TK_EQ: {
|
case TK_EQ: {
|
||||||
int p1 = binaryCompareP1(pExpr->pLeft, pExpr->pRight, jumpIfNull);
|
int p1 = binaryCompareP1(pExpr->pLeft, pExpr->pRight, jumpIfNull);
|
||||||
|
CollSeq *p3 = binaryCompareCollSeq(pExpr->pLeft, pExpr->pRight);
|
||||||
sqlite3ExprCode(pParse, pExpr->pLeft);
|
sqlite3ExprCode(pParse, pExpr->pLeft);
|
||||||
sqlite3ExprCode(pParse, pExpr->pRight);
|
sqlite3ExprCode(pParse, pExpr->pRight);
|
||||||
sqlite3VdbeAddOp(v, op, p1, dest);
|
sqlite3VdbeOp3(v, op, p1, dest, (void *)p3, P3_COLLSEQ);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TK_ISNULL:
|
case TK_ISNULL:
|
||||||
@ -1516,33 +1582,29 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
|||||||
sqlite3VdbeAddOp(v, op, 1, dest);
|
sqlite3VdbeAddOp(v, op, 1, dest);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#if 0
|
|
||||||
case TK_IN: {
|
|
||||||
int addr;
|
|
||||||
sqlite3ExprCode(pParse, pExpr->pLeft);
|
|
||||||
addr = sqlite3VdbeCurrentAddr(v);
|
|
||||||
sqlite3VdbeAddOp(v, OP_NotNull, -1, addr+3);
|
|
||||||
sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
|
|
||||||
sqlite3VdbeAddOp(v, OP_Goto, 0, jumpIfNull ? dest : addr+4);
|
|
||||||
if( pExpr->pSelect ){
|
|
||||||
sqlite3VdbeAddOp(v, OP_NotFound, pExpr->iTable, dest);
|
|
||||||
}else{
|
|
||||||
sqlite3VdbeAddOp(v, OP_SetNotFound, pExpr->iTable, dest);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
case TK_BETWEEN: {
|
case TK_BETWEEN: {
|
||||||
|
/* The expression is "x BETWEEN y AND z". It is implemented as:
|
||||||
|
**
|
||||||
|
** 1 IF (x >= y) GOTO 3
|
||||||
|
** 2 GOTO <dest>
|
||||||
|
** 3 IF (x > z) GOTO <dest>
|
||||||
|
*/
|
||||||
int addr;
|
int addr;
|
||||||
|
int p1;
|
||||||
|
CollSeq *p3;
|
||||||
sqlite3ExprCode(pParse, pExpr->pLeft);
|
sqlite3ExprCode(pParse, pExpr->pLeft);
|
||||||
sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
|
sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
|
||||||
sqlite3ExprCode(pParse, pExpr->pList->a[0].pExpr);
|
sqlite3ExprCode(pParse, pExpr->pList->a[0].pExpr);
|
||||||
addr = sqlite3VdbeCurrentAddr(v);
|
addr = sqlite3VdbeCurrentAddr(v);
|
||||||
sqlite3VdbeAddOp(v, OP_Ge, !jumpIfNull, addr+3);
|
p1 = binaryCompareP1(pExpr->pLeft, pExpr->pList->a[0].pExpr, !jumpIfNull);
|
||||||
|
p3 = binaryCompareCollSeq(pExpr->pLeft, pExpr->pList->a[0].pExpr);
|
||||||
|
sqlite3VdbeOp3(v, OP_Ge, p1, addr+3, (void *)p3, P3_COLLSEQ);
|
||||||
sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
|
sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
|
||||||
sqlite3VdbeAddOp(v, OP_Goto, 0, dest);
|
sqlite3VdbeAddOp(v, OP_Goto, 0, dest);
|
||||||
sqlite3ExprCode(pParse, pExpr->pList->a[1].pExpr);
|
sqlite3ExprCode(pParse, pExpr->pList->a[1].pExpr);
|
||||||
sqlite3VdbeAddOp(v, OP_Gt, jumpIfNull, dest);
|
p1 = binaryCompareP1(pExpr->pLeft, pExpr->pList->a[1].pExpr, jumpIfNull);
|
||||||
|
p3 = binaryCompareCollSeq(pExpr->pLeft, pExpr->pList->a[1].pExpr);
|
||||||
|
sqlite3VdbeOp3(v, OP_Gt, p1, dest, (void *)p3, P3_COLLSEQ);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
|
76
src/main.c
76
src/main.c
@ -14,7 +14,7 @@
|
|||||||
** other files are for internal use by SQLite and should not be
|
** other files are for internal use by SQLite and should not be
|
||||||
** accessed by users of the library.
|
** accessed by users of the library.
|
||||||
**
|
**
|
||||||
** $Id: main.c,v 1.207 2004/06/08 00:02:34 danielk1977 Exp $
|
** $Id: main.c,v 1.208 2004/06/09 09:55:18 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include "os.h"
|
#include "os.h"
|
||||||
@ -424,6 +424,23 @@ static int binaryCollatingFunc(
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Another built-in collating sequence: NOCASE. At the moment there is
|
||||||
|
** only a UTF-8 implementation.
|
||||||
|
*/
|
||||||
|
static int nocaseCollatingFunc(
|
||||||
|
void *NotUsed,
|
||||||
|
int nKey1, const void *pKey1,
|
||||||
|
int nKey2, const void *pKey2
|
||||||
|
){
|
||||||
|
int r = sqlite3StrNICmp(
|
||||||
|
(const char *)pKey1, (const char *)pKey2, (nKey1>nKey2)?nKey1:nKey2);
|
||||||
|
if( 0==r ){
|
||||||
|
r = nKey1-nKey2;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Return the ROWID of the most recent insert
|
** Return the ROWID of the most recent insert
|
||||||
*/
|
*/
|
||||||
@ -1001,9 +1018,24 @@ static int openDatabase(
|
|||||||
sqlite3HashInit(&db->aDb[i].trigHash, SQLITE_HASH_STRING, 0);
|
sqlite3HashInit(&db->aDb[i].trigHash, SQLITE_HASH_STRING, 0);
|
||||||
sqlite3HashInit(&db->aDb[i].aFKey, SQLITE_HASH_STRING, 1);
|
sqlite3HashInit(&db->aDb[i].aFKey, SQLITE_HASH_STRING, 1);
|
||||||
}
|
}
|
||||||
db->pDfltColl =
|
|
||||||
sqlite3ChangeCollatingFunction(db, "BINARY", 6, 0, binaryCollatingFunc);
|
|
||||||
|
|
||||||
|
/* Add the default collation sequence BINARY. BINARY works for both UTF-8
|
||||||
|
** and UTF-16, so add a version for each to avoid any unnecessary
|
||||||
|
** conversions. The only error that can occur here is a malloc() failure.
|
||||||
|
*/
|
||||||
|
sqlite3_create_collation(db, "BINARY", 0, 0, binaryCollatingFunc);
|
||||||
|
sqlite3_create_collation(db, "BINARY", 1, 0, binaryCollatingFunc);
|
||||||
|
db->pDfltColl = sqlite3FindCollSeq(db, "BINARY", 6, 0);
|
||||||
|
if( !db->pDfltColl ){
|
||||||
|
rc = db->errCode;
|
||||||
|
assert( rc!=SQLITE_OK );
|
||||||
|
db->magic = SQLITE_MAGIC_CLOSED;
|
||||||
|
goto opendb_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Also add a UTF-8 case-insensitive collation sequence. */
|
||||||
|
sqlite3_create_collation(db, "NOCASE", 0, 0, nocaseCollatingFunc);
|
||||||
|
|
||||||
/* Open the backend database driver */
|
/* Open the backend database driver */
|
||||||
if( zFilename[0]==':' && strcmp(zFilename,":memory:")==0 ){
|
if( zFilename[0]==':' && strcmp(zFilename,":memory:")==0 ){
|
||||||
db->temp_store = 2;
|
db->temp_store = 2;
|
||||||
@ -1098,3 +1130,41 @@ int sqlite3_reset(sqlite3_stmt *pStmt){
|
|||||||
sqlite3VdbeMakeReady((Vdbe*)pStmt, -1, 0);
|
sqlite3VdbeMakeReady((Vdbe*)pStmt, -1, 0);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int sqlite3_create_collation(
|
||||||
|
sqlite3* db,
|
||||||
|
const char *zName,
|
||||||
|
int pref16,
|
||||||
|
void* pCtx,
|
||||||
|
int(*xCompare)(void*,int,const void*,int,const void*)
|
||||||
|
){
|
||||||
|
CollSeq *pColl;
|
||||||
|
int rc = SQLITE_OK;
|
||||||
|
pColl = sqlite3FindCollSeq(db, zName, strlen(zName), 1);
|
||||||
|
if( 0==pColl ){
|
||||||
|
rc = SQLITE_NOMEM;
|
||||||
|
}else if( pref16 ){
|
||||||
|
pColl->xCmp16 = xCompare;
|
||||||
|
pColl->pUser16 = pCtx;
|
||||||
|
}else{
|
||||||
|
pColl->xCmp = xCompare;
|
||||||
|
pColl->pUser = pCtx;
|
||||||
|
}
|
||||||
|
sqlite3Error(db, rc, 0);
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sqlite3_create_collation16(
|
||||||
|
sqlite3* db,
|
||||||
|
const char *zName,
|
||||||
|
int pref16,
|
||||||
|
void* pCtx,
|
||||||
|
int(*xCompare)(void*,int,const void*,int,const void*)
|
||||||
|
){
|
||||||
|
int rc;
|
||||||
|
char *zName8 = sqlite3utf16to8(zName, -1, SQLITE_BIGENDIAN);
|
||||||
|
rc = sqlite3_create_collation(db, zName8, pref16, pCtx, xCompare);
|
||||||
|
sqliteFree(zName8);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
33
src/parse.y
33
src/parse.y
@ -14,7 +14,7 @@
|
|||||||
** the parser. Lemon will also generate a header file containing
|
** the parser. Lemon will also generate a header file containing
|
||||||
** numeric codes for all of the tokens.
|
** numeric codes for all of the tokens.
|
||||||
**
|
**
|
||||||
** @(#) $Id: parse.y,v 1.126 2004/06/09 00:48:13 drh Exp $
|
** @(#) $Id: parse.y,v 1.127 2004/06/09 09:55:18 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
%token_prefix TK_
|
%token_prefix TK_
|
||||||
%token_type {Token}
|
%token_type {Token}
|
||||||
@ -423,7 +423,7 @@ on_opt(N) ::= . {N = 0;}
|
|||||||
|
|
||||||
%type using_opt {IdList*}
|
%type using_opt {IdList*}
|
||||||
%destructor using_opt {sqlite3IdListDelete($$);}
|
%destructor using_opt {sqlite3IdListDelete($$);}
|
||||||
using_opt(U) ::= USING LP idxlist(L) RP. {U = L;}
|
using_opt(U) ::= USING LP inscollist(L) RP. {U = L;}
|
||||||
using_opt(U) ::= . {U = 0;}
|
using_opt(U) ::= . {U = 0;}
|
||||||
|
|
||||||
|
|
||||||
@ -741,17 +741,32 @@ cmd ::= CREATE(S) uniqueflag(U) INDEX nm(X) dbnm(D)
|
|||||||
uniqueflag(A) ::= UNIQUE. { A = OE_Abort; }
|
uniqueflag(A) ::= UNIQUE. { A = OE_Abort; }
|
||||||
uniqueflag(A) ::= . { A = OE_None; }
|
uniqueflag(A) ::= . { A = OE_None; }
|
||||||
|
|
||||||
%type idxlist {IdList*}
|
%type idxlist {ExprList*}
|
||||||
%destructor idxlist {sqlite3IdListDelete($$);}
|
%destructor idxlist {sqlite3ExprListDelete($$);}
|
||||||
%type idxlist_opt {IdList*}
|
%type idxlist_opt {ExprList*}
|
||||||
%destructor idxlist_opt {sqlite3IdListDelete($$);}
|
%destructor idxlist_opt {sqlite3ExprListDelete($$);}
|
||||||
%type idxitem {Token}
|
%type idxitem {Token}
|
||||||
|
|
||||||
idxlist_opt(A) ::= . {A = 0;}
|
idxlist_opt(A) ::= . {A = 0;}
|
||||||
idxlist_opt(A) ::= LP idxlist(X) RP. {A = X;}
|
idxlist_opt(A) ::= LP idxlist(X) RP. {A = X;}
|
||||||
idxlist(A) ::= idxlist(X) COMMA idxitem(Y). {A = sqlite3IdListAppend(X,&Y);}
|
idxlist(A) ::= idxlist(X) COMMA idxitem(Y) collate(C) sortorder. {
|
||||||
idxlist(A) ::= idxitem(Y). {A = sqlite3IdListAppend(0,&Y);}
|
Expr *p = 0;
|
||||||
idxitem(A) ::= nm(X) sortorder. {A = X;}
|
if( C.n>0 ){
|
||||||
|
p = sqlite3Expr(TK_COLUMN, 0, 0, 0);
|
||||||
|
if( p ) p->pColl = sqlite3LocateCollSeq(pParse, C.z, C.n);
|
||||||
|
}
|
||||||
|
A = sqlite3ExprListAppend(X, p, &Y);
|
||||||
|
}
|
||||||
|
idxlist(A) ::= idxitem(Y) collate(C) sortorder. {
|
||||||
|
Expr *p = 0;
|
||||||
|
if( C.n>0 ){
|
||||||
|
p = sqlite3Expr(TK_COLUMN, 0, 0, 0);
|
||||||
|
if( p ) p->pColl = sqlite3LocateCollSeq(pParse, C.z, C.n);
|
||||||
|
}
|
||||||
|
A = sqlite3ExprListAppend(0, p, &Y);
|
||||||
|
}
|
||||||
|
idxitem(A) ::= nm(X). {A = X;}
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////// The DROP INDEX command /////////////////////////
|
///////////////////////////// The DROP INDEX command /////////////////////////
|
||||||
//
|
//
|
||||||
|
30
src/select.c
30
src/select.c
@ -12,7 +12,7 @@
|
|||||||
** This file contains C code routines that are called by the parser
|
** This file contains C code routines that are called by the parser
|
||||||
** to handle SELECT statements in SQLite.
|
** to handle SELECT statements in SQLite.
|
||||||
**
|
**
|
||||||
** $Id: select.c,v 1.184 2004/06/07 10:00:31 danielk1977 Exp $
|
** $Id: select.c,v 1.185 2004/06/09 09:55:18 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@ -546,7 +546,14 @@ static void generateSortTail(
|
|||||||
pInfo->aSortOrder = (char*)&pInfo->aColl[nCol];
|
pInfo->aSortOrder = (char*)&pInfo->aColl[nCol];
|
||||||
pInfo->nField = nCol;
|
pInfo->nField = nCol;
|
||||||
for(i=0; i<nCol; i++){
|
for(i=0; i<nCol; i++){
|
||||||
pInfo->aColl[i] = db->pDfltColl;
|
/* If a collation sequence was specified explicity, then it
|
||||||
|
** is stored in pOrderBy->a[i].zName. Otherwise, use the default
|
||||||
|
** collation type for the expression.
|
||||||
|
*/
|
||||||
|
pInfo->aColl[i] = sqlite3ExprCollSeq(pOrderBy->a[i].pExpr);
|
||||||
|
if( !pInfo->aColl[i] ){
|
||||||
|
pInfo->aColl[i] = db->pDfltColl;
|
||||||
|
}
|
||||||
pInfo->aSortOrder[i] = pOrderBy->a[i].sortOrder;
|
pInfo->aSortOrder[i] = pOrderBy->a[i].sortOrder;
|
||||||
}
|
}
|
||||||
sqlite3VdbeOp3(v, OP_Sort, 0, 0, (char*)pInfo, P3_KEYINFO_HANDOFF);
|
sqlite3VdbeOp3(v, OP_Sort, 0, 0, (char*)pInfo, P3_KEYINFO_HANDOFF);
|
||||||
@ -818,6 +825,10 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, char *zTabName, Select *pSelect){
|
|||||||
if( zType ){
|
if( zType ){
|
||||||
pTab->aCol[i].affinity = sqlite3AffinityType(zType, strlen(zType));
|
pTab->aCol[i].affinity = sqlite3AffinityType(zType, strlen(zType));
|
||||||
}
|
}
|
||||||
|
pTab->aCol[i].pColl = sqlite3ExprCollSeq(p);
|
||||||
|
if( !pTab->aCol[i].pColl ){
|
||||||
|
pTab->aCol[i].pColl = pParse->db->pDfltColl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pTab->iPKey = -1;
|
pTab->iPKey = -1;
|
||||||
return pTab;
|
return pTab;
|
||||||
@ -2222,6 +2233,21 @@ int sqlite3Select(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If there is an ORDER BY clause, resolve any collation sequences
|
||||||
|
** names that have been explicitly specified.
|
||||||
|
*/
|
||||||
|
if( pOrderBy ){
|
||||||
|
for(i=0; i<pOrderBy->nExpr; i++){
|
||||||
|
if( pOrderBy->a[i].zName ){
|
||||||
|
pOrderBy->a[i].pExpr->pColl =
|
||||||
|
sqlite3LocateCollSeq(pParse, pOrderBy->a[i].zName, -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( pParse->nErr ){
|
||||||
|
goto select_end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Begin generating code.
|
/* Begin generating code.
|
||||||
*/
|
*/
|
||||||
v = sqlite3GetVdbe(pParse);
|
v = sqlite3GetVdbe(pParse);
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
** This header file defines the interface that the SQLite library
|
** This header file defines the interface that the SQLite library
|
||||||
** presents to client programs.
|
** presents to client programs.
|
||||||
**
|
**
|
||||||
** @(#) $Id: sqlite.h.in,v 1.94 2004/06/08 00:02:35 danielk1977 Exp $
|
** @(#) $Id: sqlite.h.in,v 1.95 2004/06/09 09:55:18 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#ifndef _SQLITE_H_
|
#ifndef _SQLITE_H_
|
||||||
#define _SQLITE_H_
|
#define _SQLITE_H_
|
||||||
@ -963,6 +963,22 @@ void sqlite3_result_text(sqlite3_context*, const char*, int n, int eCopy);
|
|||||||
void sqlite3_result_text16(sqlite3_context*, const void*, int n, int eCopy);
|
void sqlite3_result_text16(sqlite3_context*, const void*, int n, int eCopy);
|
||||||
void sqlite3_result_value(sqlite3_context*, sqlite3_value*);
|
void sqlite3_result_value(sqlite3_context*, sqlite3_value*);
|
||||||
|
|
||||||
|
int sqlite3_create_collation(
|
||||||
|
sqlite3*,
|
||||||
|
const char *zName,
|
||||||
|
int pref16,
|
||||||
|
void*,
|
||||||
|
int(*xCompare)(void*,int,const void*,int,const void*)
|
||||||
|
);
|
||||||
|
int sqlite3_create_collation16(
|
||||||
|
sqlite3*,
|
||||||
|
const char *zName,
|
||||||
|
int pref16,
|
||||||
|
void*,
|
||||||
|
int(*xCompare)(void*,int,const void*,int,const void*)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} /* End of the 'extern "C"' block */
|
} /* End of the 'extern "C"' block */
|
||||||
#endif
|
#endif
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
*************************************************************************
|
*************************************************************************
|
||||||
** Internal interface definitions for SQLite.
|
** Internal interface definitions for SQLite.
|
||||||
**
|
**
|
||||||
** @(#) $Id: sqliteInt.h,v 1.272 2004/06/09 00:48:13 drh Exp $
|
** @(#) $Id: sqliteInt.h,v 1.273 2004/06/09 09:55:19 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "sqlite3.h"
|
#include "sqlite3.h"
|
||||||
@ -488,19 +488,31 @@ struct Column {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
** A "Collating Sequence" is defined by an instance of the following
|
** A "Collating Sequence" is defined by an instance of the following
|
||||||
** structure. Every collating sequence has a name and a comparison
|
** structure. Conceptually, a collating sequence consists of a name and
|
||||||
** function that defines the order of text for that sequence. The
|
** a comparison routine that defines the order of that sequence.
|
||||||
** CollSeq.pUser parameter is an extra parameter that passed in as
|
|
||||||
** the first argument to the comparison function.
|
|
||||||
**
|
**
|
||||||
** If CollSeq.xCmp is NULL, it means that the collating sequence is
|
** There may two seperate implementations of the collation function, one
|
||||||
** undefined. Indices built on an undefined collating sequence may
|
** that processes text in UTF-8 encoding (CollSeq.xCmp) and another that
|
||||||
** not be read or written.
|
** processes text encoded in UTF-16 (CollSeq.xCmp16), using the machine
|
||||||
|
** native byte order. When a collation sequence is invoked, SQLite selects
|
||||||
|
** the version that will require the least expensive encoding
|
||||||
|
** transalations, if any.
|
||||||
|
**
|
||||||
|
** The CollSeq.pUser member variable is an extra parameter that passed in
|
||||||
|
** as the first argument to the UTF-8 comparison function, xCmp.
|
||||||
|
** CollSeq.pUser16 is the equivalent for the UTF-16 comparison function,
|
||||||
|
** xCmp16.
|
||||||
|
**
|
||||||
|
** If both CollSeq.xCmp and CollSeq.xCmp16 are NULL, it means that the
|
||||||
|
** collating sequence is undefined. Indices built on an undefined
|
||||||
|
** collating sequence may not be read or written.
|
||||||
*/
|
*/
|
||||||
struct CollSeq {
|
struct CollSeq {
|
||||||
char *zName; /* Name of the collating sequence */
|
char *zName; /* Name of the collating sequence, UTF-8 encoded */
|
||||||
void *pUser; /* First argument to xCmp() */
|
void *pUser; /* First argument to xCmp() */
|
||||||
int (*xCmp)(void*,int,const void*,int,const void*); /* Comparison function */
|
void *pUser16; /* First argument to xCmp16() */
|
||||||
|
int (*xCmp)(void*,int, const void*, int, const void*);
|
||||||
|
int (*xCmp16)(void*,int, const void*, int, const void*);
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -756,6 +768,7 @@ struct Token {
|
|||||||
struct Expr {
|
struct Expr {
|
||||||
u8 op; /* Operation performed by this node */
|
u8 op; /* Operation performed by this node */
|
||||||
char affinity; /* The affinity of the column or 0 if not a column */
|
char affinity; /* The affinity of the column or 0 if not a column */
|
||||||
|
CollSeq *pColl; /* The collation type of the column or 0 */
|
||||||
u8 iDb; /* Database referenced by this expression */
|
u8 iDb; /* Database referenced by this expression */
|
||||||
u8 flags; /* Various flags. See below */
|
u8 flags; /* Various flags. See below */
|
||||||
Expr *pLeft, *pRight; /* Left and right subnodes */
|
Expr *pLeft, *pRight; /* Left and right subnodes */
|
||||||
@ -1224,12 +1237,10 @@ void sqlite3OpenMasterTable(Vdbe *v, int);
|
|||||||
void sqlite3StartTable(Parse*,Token*,Token*,Token*,int,int);
|
void sqlite3StartTable(Parse*,Token*,Token*,Token*,int,int);
|
||||||
void sqlite3AddColumn(Parse*,Token*);
|
void sqlite3AddColumn(Parse*,Token*);
|
||||||
void sqlite3AddNotNull(Parse*, int);
|
void sqlite3AddNotNull(Parse*, int);
|
||||||
void sqlite3AddPrimaryKey(Parse*, IdList*, int);
|
void sqlite3AddPrimaryKey(Parse*, ExprList*, int);
|
||||||
void sqlite3AddColumnType(Parse*,Token*,Token*);
|
void sqlite3AddColumnType(Parse*,Token*,Token*);
|
||||||
void sqlite3AddDefaultValue(Parse*,Token*,int);
|
void sqlite3AddDefaultValue(Parse*,Token*,int);
|
||||||
void sqlite3AddCollateType(Parse*, const char*, int);
|
void sqlite3AddCollateType(Parse*, const char*, int);
|
||||||
CollSeq *sqlite3ChangeCollatingFunction(sqlite*,const char*,int,
|
|
||||||
void*, int(*)(void*,int,const void*,int,const void*));
|
|
||||||
void sqlite3EndTable(Parse*,Token*,Select*);
|
void sqlite3EndTable(Parse*,Token*,Select*);
|
||||||
void sqlite3CreateView(Parse*,Token*,Token*,Token*,Select*,int);
|
void sqlite3CreateView(Parse*,Token*,Token*,Token*,Select*,int);
|
||||||
int sqlite3ViewGetColumnNames(Parse*,Table*);
|
int sqlite3ViewGetColumnNames(Parse*,Table*);
|
||||||
@ -1243,7 +1254,7 @@ void sqlite3SrcListAddAlias(SrcList*, Token*);
|
|||||||
void sqlite3SrcListAssignCursors(Parse*, SrcList*);
|
void sqlite3SrcListAssignCursors(Parse*, SrcList*);
|
||||||
void sqlite3IdListDelete(IdList*);
|
void sqlite3IdListDelete(IdList*);
|
||||||
void sqlite3SrcListDelete(SrcList*);
|
void sqlite3SrcListDelete(SrcList*);
|
||||||
void sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,IdList*,int,Token*,
|
void sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*,
|
||||||
Token*);
|
Token*);
|
||||||
void sqlite3DropIndex(Parse*, SrcList*);
|
void sqlite3DropIndex(Parse*, SrcList*);
|
||||||
void sqlite3AddKeyType(Vdbe*, ExprList*);
|
void sqlite3AddKeyType(Vdbe*, ExprList*);
|
||||||
@ -1324,7 +1335,7 @@ TriggerStep *sqlite3TriggerUpdateStep(Token*, ExprList*, Expr*, int);
|
|||||||
TriggerStep *sqlite3TriggerDeleteStep(Token*, Expr*);
|
TriggerStep *sqlite3TriggerDeleteStep(Token*, Expr*);
|
||||||
void sqlite3DeleteTrigger(Trigger*);
|
void sqlite3DeleteTrigger(Trigger*);
|
||||||
int sqlite3JoinType(Parse*, Token*, Token*, Token*);
|
int sqlite3JoinType(Parse*, Token*, Token*, Token*);
|
||||||
void sqlite3CreateForeignKey(Parse*, IdList*, Token*, IdList*, int);
|
void sqlite3CreateForeignKey(Parse*, ExprList*, Token*, ExprList*, int);
|
||||||
void sqlite3DeferForeignKey(Parse*, int);
|
void sqlite3DeferForeignKey(Parse*, int);
|
||||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||||
void sqlite3AuthRead(Parse*,Expr*,SrcList*);
|
void sqlite3AuthRead(Parse*,Expr*,SrcList*);
|
||||||
@ -1379,3 +1390,6 @@ int sqlite3TwoPartName(Parse *, Token *, Token *, Token **);
|
|||||||
const char *sqlite3ErrStr(int);
|
const char *sqlite3ErrStr(int);
|
||||||
int sqlite3ReadUniChar(const char *zStr, int *pOffset, u8 *pEnc, int fold);
|
int sqlite3ReadUniChar(const char *zStr, int *pOffset, u8 *pEnc, int fold);
|
||||||
int sqlite3ReadSchema(sqlite *db);
|
int sqlite3ReadSchema(sqlite *db);
|
||||||
|
CollSeq *sqlite3FindCollSeq(sqlite *,const char *,int,int);
|
||||||
|
CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char *zName, int nName);
|
||||||
|
CollSeq *sqlite3ExprCollSeq(Expr *pExpr);
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
*************************************************************************
|
*************************************************************************
|
||||||
** A TCL Interface to SQLite
|
** A TCL Interface to SQLite
|
||||||
**
|
**
|
||||||
** $Id: tclsqlite.c,v 1.80 2004/06/08 00:02:35 danielk1977 Exp $
|
** $Id: tclsqlite.c,v 1.81 2004/06/09 09:55:19 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#ifndef NO_TCL /* Omit this whole file if TCL is unavailable */
|
#ifndef NO_TCL /* Omit this whole file if TCL is unavailable */
|
||||||
|
|
||||||
@ -42,6 +42,17 @@ struct SqlFunc {
|
|||||||
SqlFunc *pNext; /* Next function on the list of them all */
|
SqlFunc *pNext; /* Next function on the list of them all */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
** New collation sequences function can be created as TCL scripts. Each such
|
||||||
|
** function is described by an instance of the following structure.
|
||||||
|
*/
|
||||||
|
typedef struct SqlCollate SqlCollate;
|
||||||
|
struct SqlCollate {
|
||||||
|
Tcl_Interp *interp; /* The TCL interpret to execute the function */
|
||||||
|
char *zScript; /* The script to be run */
|
||||||
|
SqlCollate *pNext; /* Next function on the list of them all */
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** There is one instance of this structure for each SQLite database
|
** There is one instance of this structure for each SQLite database
|
||||||
** that has been opened by the SQLite TCL interface.
|
** that has been opened by the SQLite TCL interface.
|
||||||
@ -56,6 +67,7 @@ struct SqliteDb {
|
|||||||
char *zProgress; /* The progress callback routine */
|
char *zProgress; /* The progress callback routine */
|
||||||
char *zAuth; /* The authorization callback routine */
|
char *zAuth; /* The authorization callback routine */
|
||||||
SqlFunc *pFunc; /* List of SQL functions */
|
SqlFunc *pFunc; /* List of SQL functions */
|
||||||
|
SqlCollate *pCollate; /* List of SQL collation functions */
|
||||||
int rc; /* Return code of most recent sqlite3_exec() */
|
int rc; /* Return code of most recent sqlite3_exec() */
|
||||||
int nChange; /* Database changes for the most recent eval */
|
int nChange; /* Database changes for the most recent eval */
|
||||||
};
|
};
|
||||||
@ -115,6 +127,11 @@ static void DbDeleteCmd(void *db){
|
|||||||
pDb->pFunc = pFunc->pNext;
|
pDb->pFunc = pFunc->pNext;
|
||||||
Tcl_Free((char*)pFunc);
|
Tcl_Free((char*)pFunc);
|
||||||
}
|
}
|
||||||
|
while( pDb->pCollate ){
|
||||||
|
SqlCollate *pCollate = pDb->pCollate;
|
||||||
|
pDb->pCollate = pCollate->pNext;
|
||||||
|
Tcl_Free((char*)pCollate);
|
||||||
|
}
|
||||||
if( pDb->zBusy ){
|
if( pDb->zBusy ){
|
||||||
Tcl_Free(pDb->zBusy);
|
Tcl_Free(pDb->zBusy);
|
||||||
}
|
}
|
||||||
@ -200,6 +217,29 @@ static int DbCommitHandler(void *cd){
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** This routine is called to evaluate an SQL collation function implemented
|
||||||
|
** using TCL script.
|
||||||
|
*/
|
||||||
|
static int tclSqlCollate(
|
||||||
|
void *pCtx,
|
||||||
|
int nA,
|
||||||
|
const void *zA,
|
||||||
|
int nB,
|
||||||
|
const void *zB
|
||||||
|
){
|
||||||
|
SqlCollate *p = (SqlCollate *)pCtx;
|
||||||
|
Tcl_Obj *pCmd;
|
||||||
|
|
||||||
|
pCmd = Tcl_NewStringObj(p->zScript, -1);
|
||||||
|
Tcl_IncrRefCount(pCmd);
|
||||||
|
Tcl_ListObjAppendElement(p->interp, pCmd, Tcl_NewStringObj(zA, nA));
|
||||||
|
Tcl_ListObjAppendElement(p->interp, pCmd, Tcl_NewStringObj(zB, nB));
|
||||||
|
Tcl_EvalObjEx(p->interp, pCmd, 0);
|
||||||
|
Tcl_DecrRefCount(pCmd);
|
||||||
|
return (atoi(Tcl_GetStringResult(p->interp)));
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** This routine is called to evaluate an SQL function implemented
|
** This routine is called to evaluate an SQL function implemented
|
||||||
** using TCL script.
|
** using TCL script.
|
||||||
@ -342,7 +382,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||||||
"errorcode", "eval", "function",
|
"errorcode", "eval", "function",
|
||||||
"last_insert_rowid", "last_statement_changes", "onecolumn",
|
"last_insert_rowid", "last_statement_changes", "onecolumn",
|
||||||
"progress", "rekey", "timeout",
|
"progress", "rekey", "timeout",
|
||||||
"trace",
|
"trace", "collate",
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
enum DB_enum {
|
enum DB_enum {
|
||||||
@ -351,7 +391,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||||||
DB_ERRORCODE, DB_EVAL, DB_FUNCTION,
|
DB_ERRORCODE, DB_EVAL, DB_FUNCTION,
|
||||||
DB_LAST_INSERT_ROWID, DB_LAST_STATEMENT_CHANGES, DB_ONECOLUMN,
|
DB_LAST_INSERT_ROWID, DB_LAST_STATEMENT_CHANGES, DB_ONECOLUMN,
|
||||||
DB_PROGRESS, DB_REKEY, DB_TIMEOUT,
|
DB_PROGRESS, DB_REKEY, DB_TIMEOUT,
|
||||||
DB_TRACE
|
DB_TRACE, DB_COLLATE
|
||||||
};
|
};
|
||||||
|
|
||||||
if( objc<2 ){
|
if( objc<2 ){
|
||||||
@ -854,6 +894,35 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** $db collate NAME SCRIPT
|
||||||
|
**
|
||||||
|
** Create a new SQL collation function called NAME. Whenever
|
||||||
|
** that function is called, invoke SCRIPT to evaluate the function.
|
||||||
|
*/
|
||||||
|
case DB_COLLATE: {
|
||||||
|
SqlCollate *pCollate;
|
||||||
|
char *zName;
|
||||||
|
char *zScript;
|
||||||
|
int nScript;
|
||||||
|
if( objc!=4 ){
|
||||||
|
Tcl_WrongNumArgs(interp, 2, objv, "NAME SCRIPT");
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
zName = Tcl_GetStringFromObj(objv[2], 0);
|
||||||
|
zScript = Tcl_GetStringFromObj(objv[3], &nScript);
|
||||||
|
pCollate = (SqlCollate*)Tcl_Alloc( sizeof(*pCollate) + nScript + 1 );
|
||||||
|
if( pCollate==0 ) return TCL_ERROR;
|
||||||
|
pCollate->interp = interp;
|
||||||
|
pCollate->pNext = pDb->pCollate;
|
||||||
|
pCollate->zScript = (char*)&pCollate[1];
|
||||||
|
strcpy(pCollate->zScript, zScript);
|
||||||
|
if( sqlite3_create_collation(pDb->db, zName, 0, pCollate, tclSqlCollate) ){
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
} /* End of the SWITCH statement */
|
} /* End of the SWITCH statement */
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
44
src/test1.c
44
src/test1.c
@ -13,7 +13,7 @@
|
|||||||
** is not included in the SQLite library. It is used for automated
|
** is not included in the SQLite library. It is used for automated
|
||||||
** testing of the SQLite library.
|
** testing of the SQLite library.
|
||||||
**
|
**
|
||||||
** $Id: test1.c,v 1.71 2004/06/08 00:02:35 danielk1977 Exp $
|
** $Id: test1.c,v 1.72 2004/06/09 09:55:19 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include "tcl.h"
|
#include "tcl.h"
|
||||||
@ -1550,47 +1550,6 @@ static int test_data_count(
|
|||||||
return TCL_OK;
|
return TCL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
** This is a collating function named "REVERSE" which sorts text
|
|
||||||
** in reverse order.
|
|
||||||
*/
|
|
||||||
static int reverseCollatingFunc(
|
|
||||||
void *NotUsed,
|
|
||||||
int nKey1, const void *pKey1,
|
|
||||||
int nKey2, const void *pKey2
|
|
||||||
){
|
|
||||||
int rc, n;
|
|
||||||
n = nKey1<nKey2 ? nKey1 : nKey2;
|
|
||||||
rc = memcmp(pKey1, pKey2, n);
|
|
||||||
if( rc==0 ){
|
|
||||||
rc = nKey1 - nKey2;
|
|
||||||
}
|
|
||||||
return -rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Usage: add_reverse_collating_func DB
|
|
||||||
**
|
|
||||||
** This routine adds a collation named "REVERSE" to database given.
|
|
||||||
** REVERSE is used for testing only.
|
|
||||||
*/
|
|
||||||
static int reverse_collfunc(
|
|
||||||
void * clientData,
|
|
||||||
Tcl_Interp *interp,
|
|
||||||
int objc,
|
|
||||||
Tcl_Obj *CONST objv[]
|
|
||||||
){
|
|
||||||
sqlite3 *db;
|
|
||||||
|
|
||||||
if( objc!=2 ){
|
|
||||||
Tcl_WrongNumArgs(interp, 1, objv, "DB");
|
|
||||||
return TCL_ERROR;
|
|
||||||
}
|
|
||||||
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
|
|
||||||
sqlite3ChangeCollatingFunction(db, "REVERSE", 7, 0, reverseCollatingFunc);
|
|
||||||
return TCL_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Usage: sqlite3_column_text STMT column
|
** Usage: sqlite3_column_text STMT column
|
||||||
**
|
**
|
||||||
@ -1880,7 +1839,6 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
|||||||
{ "sqlite3_errmsg16", test_errmsg16 ,0 },
|
{ "sqlite3_errmsg16", test_errmsg16 ,0 },
|
||||||
{ "sqlite3_open", test_open ,0 },
|
{ "sqlite3_open", test_open ,0 },
|
||||||
{ "sqlite3_open16", test_open16 ,0 },
|
{ "sqlite3_open16", test_open16 ,0 },
|
||||||
{ "add_reverse_collating_func", reverse_collfunc ,0 },
|
|
||||||
|
|
||||||
{ "sqlite3_prepare", test_prepare ,0 },
|
{ "sqlite3_prepare", test_prepare ,0 },
|
||||||
{ "sqlite3_prepare16", test_prepare16 ,0 },
|
{ "sqlite3_prepare16", test_prepare16 ,0 },
|
||||||
|
54
src/test5.c
54
src/test5.c
@ -15,9 +15,10 @@
|
|||||||
** is used for testing the SQLite routines for converting between
|
** is used for testing the SQLite routines for converting between
|
||||||
** the various supported unicode encodings.
|
** the various supported unicode encodings.
|
||||||
**
|
**
|
||||||
** $Id: test5.c,v 1.8 2004/06/04 06:22:02 danielk1977 Exp $
|
** $Id: test5.c,v 1.9 2004/06/09 09:55:19 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
#include "vdbeInt.h"
|
||||||
#include "os.h" /* to get SQLITE_BIGENDIAN */
|
#include "os.h" /* to get SQLITE_BIGENDIAN */
|
||||||
#include "tcl.h"
|
#include "tcl.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -234,6 +235,52 @@ static int binarize(
|
|||||||
return TCL_OK;
|
return TCL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Usage: test_value_overhead <repeat-count> <do-calls>.
|
||||||
|
**
|
||||||
|
** This routine is used to test the overhead of calls to
|
||||||
|
** sqlite3_value_text(), on a value that contains a UTF-8 string. The idea
|
||||||
|
** is to figure out whether or not it is a problem to use sqlite3_value
|
||||||
|
** structures with collation sequence functions.
|
||||||
|
**
|
||||||
|
** If <do-calls> is 0, then the calls to sqlite3_value_text() are not
|
||||||
|
** actually made.
|
||||||
|
*/
|
||||||
|
static int test_value_overhead(
|
||||||
|
void * clientData,
|
||||||
|
Tcl_Interp *interp,
|
||||||
|
int objc,
|
||||||
|
Tcl_Obj *CONST objv[]
|
||||||
|
){
|
||||||
|
int do_calls;
|
||||||
|
int repeat_count;
|
||||||
|
int i;
|
||||||
|
Mem val;
|
||||||
|
const char *zVal;
|
||||||
|
|
||||||
|
if( objc!=3 ){
|
||||||
|
Tcl_AppendResult(interp, "wrong # args: should be \"",
|
||||||
|
Tcl_GetStringFromObj(objv[0], 0), " <repeat-count> <do-calls>", 0);
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( Tcl_GetIntFromObj(interp, objv[1], &repeat_count) ) return TCL_ERROR;
|
||||||
|
if( Tcl_GetIntFromObj(interp, objv[2], &do_calls) ) return TCL_ERROR;
|
||||||
|
|
||||||
|
val.flags = MEM_Str|MEM_Term|MEM_Static;
|
||||||
|
val.z = "hello world";
|
||||||
|
val.type = SQLITE_TEXT;
|
||||||
|
val.enc = TEXT_Utf8;
|
||||||
|
|
||||||
|
for(i=0; i<repeat_count; i++){
|
||||||
|
if( do_calls ){
|
||||||
|
zVal = sqlite3_value_text(&val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return TCL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Register commands with the TCL interpreter.
|
** Register commands with the TCL interpreter.
|
||||||
@ -249,11 +296,12 @@ int Sqlitetest5_Init(Tcl_Interp *interp){
|
|||||||
{ "sqlite_utf16to16le", (Tcl_ObjCmdProc*)sqlite_utf16to16le },
|
{ "sqlite_utf16to16le", (Tcl_ObjCmdProc*)sqlite_utf16to16le },
|
||||||
{ "sqlite_utf16to16be", (Tcl_ObjCmdProc*)sqlite_utf16to16be },
|
{ "sqlite_utf16to16be", (Tcl_ObjCmdProc*)sqlite_utf16to16be },
|
||||||
{ "binarize", (Tcl_ObjCmdProc*)binarize },
|
{ "binarize", (Tcl_ObjCmdProc*)binarize },
|
||||||
|
{ "test_value_overhead", (Tcl_ObjCmdProc*)test_value_overhead },
|
||||||
};
|
};
|
||||||
int i;
|
int i;
|
||||||
for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
|
for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
|
||||||
Tcl_CreateObjCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
|
Tcl_CreateObjCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
|
||||||
}
|
}
|
||||||
|
return SQLITE_OK;
|
||||||
return TCL_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
** This file contains functions for allocating memory, comparing
|
** This file contains functions for allocating memory, comparing
|
||||||
** strings, and stuff like that.
|
** strings, and stuff like that.
|
||||||
**
|
**
|
||||||
** $Id: util.c,v 1.98 2004/06/06 12:41:50 danielk1977 Exp $
|
** $Id: util.c,v 1.99 2004/06/09 09:55:19 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
@ -553,7 +553,7 @@ int sqlite3StrNICmp(const char *zLeft, const char *zRight, int N){
|
|||||||
a = (unsigned char *)zLeft;
|
a = (unsigned char *)zLeft;
|
||||||
b = (unsigned char *)zRight;
|
b = (unsigned char *)zRight;
|
||||||
while( N-- > 0 && *a!=0 && UpperToLower[*a]==UpperToLower[*b]){ a++; b++; }
|
while( N-- > 0 && *a!=0 && UpperToLower[*a]==UpperToLower[*b]){ a++; b++; }
|
||||||
return N<0 ? 0 : *a - *b;
|
return N<0 ? 0 : UpperToLower[*a] - UpperToLower[*b];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
10
src/vdbe.c
10
src/vdbe.c
@ -43,7 +43,7 @@
|
|||||||
** in this file for details. If in doubt, do not deviate from existing
|
** in this file for details. If in doubt, do not deviate from existing
|
||||||
** commenting and indentation practices when changing or adding code.
|
** commenting and indentation practices when changing or adding code.
|
||||||
**
|
**
|
||||||
** $Id: vdbe.c,v 1.360 2004/06/09 00:48:14 drh Exp $
|
** $Id: vdbe.c,v 1.361 2004/06/09 09:55:19 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include "os.h"
|
#include "os.h"
|
||||||
@ -1510,25 +1510,25 @@ mismatch:
|
|||||||
/* Opcode: Lt P1 P2 P3
|
/* Opcode: Lt P1 P2 P3
|
||||||
**
|
**
|
||||||
** This works just like the Eq opcode except that the jump is taken if
|
** This works just like the Eq opcode except that the jump is taken if
|
||||||
** the 2nd element down on the task is less than the top of the stack.
|
** the 2nd element down on the stack is less than the top of the stack.
|
||||||
** See the Eq opcode for additional information.
|
** See the Eq opcode for additional information.
|
||||||
*/
|
*/
|
||||||
/* Opcode: Le P1 P2 P3
|
/* Opcode: Le P1 P2 P3
|
||||||
**
|
**
|
||||||
** This works just like the Eq opcode except that the jump is taken if
|
** This works just like the Eq opcode except that the jump is taken if
|
||||||
** the 2nd element down on the task is less than or equal to the
|
** the 2nd element down on the stack is less than or equal to the
|
||||||
** top of the stack. See the Eq opcode for additional information.
|
** top of the stack. See the Eq opcode for additional information.
|
||||||
*/
|
*/
|
||||||
/* Opcode: Gt P1 P2 P3
|
/* Opcode: Gt P1 P2 P3
|
||||||
**
|
**
|
||||||
** This works just like the Eq opcode except that the jump is taken if
|
** This works just like the Eq opcode except that the jump is taken if
|
||||||
** the 2nd element down on the task is greater than the top of the stack.
|
** the 2nd element down on the stack is greater than the top of the stack.
|
||||||
** See the Eq opcode for additional information.
|
** See the Eq opcode for additional information.
|
||||||
*/
|
*/
|
||||||
/* Opcode: Ge P1 P2 P3
|
/* Opcode: Ge P1 P2 P3
|
||||||
**
|
**
|
||||||
** This works just like the Eq opcode except that the jump is taken if
|
** This works just like the Eq opcode except that the jump is taken if
|
||||||
** the 2nd element down on the task is greater than or equal to the
|
** the 2nd element down on the stack is greater than or equal to the
|
||||||
** top of the stack. See the Eq opcode for additional information.
|
** top of the stack. See the Eq opcode for additional information.
|
||||||
*/
|
*/
|
||||||
case OP_Eq:
|
case OP_Eq:
|
||||||
|
@ -1256,7 +1256,7 @@ void sqlite3VdbeDelete(Vdbe *p){
|
|||||||
int j;
|
int j;
|
||||||
VdbeFunc *pVdbeFunc = (VdbeFunc *)pOp->p3;
|
VdbeFunc *pVdbeFunc = (VdbeFunc *)pOp->p3;
|
||||||
for(j=0; j<pVdbeFunc->nAux; j++){
|
for(j=0; j<pVdbeFunc->nAux; j++){
|
||||||
struct AuxData *pAuxData = &pVdbeFunc->apAux[j].pAux;
|
struct AuxData *pAuxData = &pVdbeFunc->apAux[j];
|
||||||
if( pAuxData->pAux && pAuxData->xDelete ){
|
if( pAuxData->pAux && pAuxData->xDelete ){
|
||||||
pAuxData->xDelete(pAuxData->pAux);
|
pAuxData->xDelete(pAuxData->pAux);
|
||||||
}
|
}
|
||||||
@ -1520,6 +1520,11 @@ int sqlite3VdbeRecordCompare(
|
|||||||
int rc = 0;
|
int rc = 0;
|
||||||
const unsigned char *aKey1 = (const unsigned char *)pKey1;
|
const unsigned char *aKey1 = (const unsigned char *)pKey1;
|
||||||
const unsigned char *aKey2 = (const unsigned char *)pKey2;
|
const unsigned char *aKey2 = (const unsigned char *)pKey2;
|
||||||
|
|
||||||
|
Mem mem1;
|
||||||
|
Mem mem2;
|
||||||
|
mem1.enc = pKeyInfo->enc;
|
||||||
|
mem2.enc = pKeyInfo->enc;
|
||||||
|
|
||||||
idx1 = sqlite3GetVarint32(pKey1, &szHdr1);
|
idx1 = sqlite3GetVarint32(pKey1, &szHdr1);
|
||||||
d1 = szHdr1;
|
d1 = szHdr1;
|
||||||
@ -1527,8 +1532,6 @@ int sqlite3VdbeRecordCompare(
|
|||||||
d2 = szHdr2;
|
d2 = szHdr2;
|
||||||
nField = pKeyInfo->nField;
|
nField = pKeyInfo->nField;
|
||||||
while( idx1<szHdr1 && idx2<szHdr2 ){
|
while( idx1<szHdr1 && idx2<szHdr2 ){
|
||||||
Mem mem1;
|
|
||||||
Mem mem2;
|
|
||||||
u32 serial_type1;
|
u32 serial_type1;
|
||||||
u32 serial_type2;
|
u32 serial_type2;
|
||||||
|
|
||||||
|
@ -427,12 +427,41 @@ int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const CollSeq *pColl){
|
|||||||
if( (f2 & MEM_Str)==0 ){
|
if( (f2 & MEM_Str)==0 ){
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if( pColl && pColl->xCmp ){
|
|
||||||
return pColl->xCmp(pColl->pUser, pMem1->n, pMem1->z, pMem2->n, pMem2->z);
|
assert( pMem1->enc==pMem2->enc );
|
||||||
}else{
|
assert( pMem1->enc==TEXT_Utf8 ||
|
||||||
/* If no collating sequence is defined, fall through into the
|
pMem1->enc==TEXT_Utf16le || pMem1->enc==TEXT_Utf16be );
|
||||||
** blob case below and use memcmp() for the comparison. */
|
|
||||||
|
/* FIX ME: This may fail if the collation sequence is deleted after
|
||||||
|
** this vdbe program is compiled. We cannot just use BINARY in this
|
||||||
|
** case as this may lead to a segfault caused by traversing an index
|
||||||
|
** table incorrectly. We need to return an error to the user in this
|
||||||
|
** case.
|
||||||
|
*/
|
||||||
|
assert( !pColl || (pColl->xCmp || pColl->xCmp16) );
|
||||||
|
|
||||||
|
if( pColl ){
|
||||||
|
if( (pMem1->enc==TEXT_Utf8 && pColl->xCmp) || !pColl->xCmp16 ){
|
||||||
|
return pColl->xCmp(
|
||||||
|
pColl->pUser,
|
||||||
|
sqlite3_value_bytes((sqlite3_value *)pMem1),
|
||||||
|
sqlite3_value_text((sqlite3_value *)pMem1),
|
||||||
|
sqlite3_value_bytes((sqlite3_value *)pMem2),
|
||||||
|
sqlite3_value_text((sqlite3_value *)pMem2)
|
||||||
|
);
|
||||||
|
}else{
|
||||||
|
return pColl->xCmp16(
|
||||||
|
pColl->pUser,
|
||||||
|
sqlite3_value_bytes16((sqlite3_value *)pMem1),
|
||||||
|
sqlite3_value_text16((sqlite3_value *)pMem1),
|
||||||
|
sqlite3_value_bytes16((sqlite3_value *)pMem2),
|
||||||
|
sqlite3_value_text16((sqlite3_value *)pMem2)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
/* If a NULL pointer was passed as the collate function, fall through
|
||||||
|
** to the blob case and use memcmp().
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Both values must be blobs. Compare using memcmp().
|
/* Both values must be blobs. Compare using memcmp().
|
||||||
|
47
src/where.c
47
src/where.c
@ -12,7 +12,7 @@
|
|||||||
** This module contains C code that generates VDBE code used to process
|
** This module contains C code that generates VDBE code used to process
|
||||||
** the WHERE clause of SQL statements.
|
** the WHERE clause of SQL statements.
|
||||||
**
|
**
|
||||||
** $Id: where.c,v 1.102 2004/06/09 00:48:15 drh Exp $
|
** $Id: where.c,v 1.103 2004/06/09 09:55:20 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
|
||||||
@ -208,6 +208,7 @@ static void exprAnalyze(ExprMaskSet *pMaskSet, ExprInfo *pInfo){
|
|||||||
** set to 0 if the ORDER BY clause is all ASC.
|
** set to 0 if the ORDER BY clause is all ASC.
|
||||||
*/
|
*/
|
||||||
static Index *findSortingIndex(
|
static Index *findSortingIndex(
|
||||||
|
sqlite *db,
|
||||||
Table *pTab, /* The table to be sorted */
|
Table *pTab, /* The table to be sorted */
|
||||||
int base, /* Cursor number for pTab */
|
int base, /* Cursor number for pTab */
|
||||||
ExprList *pOrderBy, /* The ORDER BY clause */
|
ExprList *pOrderBy, /* The ORDER BY clause */
|
||||||
@ -230,10 +231,6 @@ static Index *findSortingIndex(
|
|||||||
** DESC or ASC. Indices cannot be used on a mixture. */
|
** DESC or ASC. Indices cannot be used on a mixture. */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if( pOrderBy->a[i].zName!=0 ){
|
|
||||||
/* Do not sort by index if there is a COLLATE clause */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
p = pOrderBy->a[i].pExpr;
|
p = pOrderBy->a[i].pExpr;
|
||||||
if( p->op!=TK_COLUMN || p->iTable!=base ){
|
if( p->op!=TK_COLUMN || p->iTable!=base ){
|
||||||
/* Can not use an index sort on anything that is not a column in the
|
/* Can not use an index sort on anything that is not a column in the
|
||||||
@ -241,7 +238,7 @@ static Index *findSortingIndex(
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we get this far, it means the ORDER BY clause consists only of
|
/* If we get this far, it means the ORDER BY clause consists only of
|
||||||
** ascending columns in the left-most table of the FROM clause. Now
|
** ascending columns in the left-most table of the FROM clause. Now
|
||||||
** check for a matching index.
|
** check for a matching index.
|
||||||
@ -251,12 +248,23 @@ static Index *findSortingIndex(
|
|||||||
int nExpr = pOrderBy->nExpr;
|
int nExpr = pOrderBy->nExpr;
|
||||||
if( pIdx->nColumn < nEqCol || pIdx->nColumn < nExpr ) continue;
|
if( pIdx->nColumn < nEqCol || pIdx->nColumn < nExpr ) continue;
|
||||||
for(i=j=0; i<nEqCol; i++){
|
for(i=j=0; i<nEqCol; i++){
|
||||||
|
CollSeq *pColl = sqlite3ExprCollSeq(pOrderBy->a[j].pExpr);
|
||||||
|
if( !pColl ) pColl = db->pDfltColl;
|
||||||
if( pPreferredIdx->aiColumn[i]!=pIdx->aiColumn[i] ) break;
|
if( pPreferredIdx->aiColumn[i]!=pIdx->aiColumn[i] ) break;
|
||||||
if( j<nExpr && pOrderBy->a[j].pExpr->iColumn==pIdx->aiColumn[i] ){ j++; }
|
if( pPreferredIdx->keyInfo.aColl[i]!=pIdx->keyInfo.aColl[i] ) break;
|
||||||
|
if( j<nExpr &&
|
||||||
|
pOrderBy->a[j].pExpr->iColumn==pIdx->aiColumn[i] &&
|
||||||
|
pColl==pIdx->keyInfo.aColl[i]
|
||||||
|
){
|
||||||
|
j++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if( i<nEqCol ) continue;
|
if( i<nEqCol ) continue;
|
||||||
for(i=0; i+j<nExpr; i++){
|
for(i=0; i+j<nExpr; i++){
|
||||||
if( pOrderBy->a[i+j].pExpr->iColumn!=pIdx->aiColumn[i+nEqCol] ) break;
|
CollSeq *pColl = sqlite3ExprCollSeq(pOrderBy->a[i+j].pExpr);
|
||||||
|
if( !pColl ) pColl = db->pDfltColl;
|
||||||
|
if( pOrderBy->a[i+j].pExpr->iColumn!=pIdx->aiColumn[i+nEqCol] ||
|
||||||
|
pColl!=pIdx->keyInfo.aColl[i+nEqCol] ) break;
|
||||||
}
|
}
|
||||||
if( i+j>=nExpr ){
|
if( i+j>=nExpr ){
|
||||||
pMatch = pIdx;
|
pMatch = pIdx;
|
||||||
@ -532,14 +540,24 @@ WhereInfo *sqlite3WhereBegin(
|
|||||||
|
|
||||||
if( pIdx->nColumn>32 ) continue; /* Ignore indices too many columns */
|
if( pIdx->nColumn>32 ) continue; /* Ignore indices too many columns */
|
||||||
for(j=0; j<nExpr; j++){
|
for(j=0; j<nExpr; j++){
|
||||||
|
CollSeq *pColl = sqlite3ExprCollSeq(aExpr[j].p->pLeft);
|
||||||
|
if( !pColl && aExpr[j].p->pRight ){
|
||||||
|
pColl = sqlite3ExprCollSeq(aExpr[j].p->pRight);
|
||||||
|
}
|
||||||
|
if( !pColl ){
|
||||||
|
pColl = pParse->db->pDfltColl;
|
||||||
|
}
|
||||||
if( aExpr[j].idxLeft==iCur
|
if( aExpr[j].idxLeft==iCur
|
||||||
&& (aExpr[j].prereqRight & loopMask)==aExpr[j].prereqRight ){
|
&& (aExpr[j].prereqRight & loopMask)==aExpr[j].prereqRight ){
|
||||||
int iColumn = aExpr[j].p->pLeft->iColumn;
|
int iColumn = aExpr[j].p->pLeft->iColumn;
|
||||||
int k;
|
int k;
|
||||||
char idxaff = pIdx->pTable->aCol[iColumn].affinity;
|
char idxaff = pIdx->pTable->aCol[iColumn].affinity;
|
||||||
for(k=0; k<pIdx->nColumn; k++){
|
for(k=0; k<pIdx->nColumn; k++){
|
||||||
if( pIdx->aiColumn[k]==iColumn
|
/* If the collating sequences or affinities don't match,
|
||||||
&& sqlite3IndexAffinityOk(aExpr[j].p, idxaff) ){
|
** ignore this index. */
|
||||||
|
if( pColl!=pIdx->keyInfo.aColl[k] ) continue;
|
||||||
|
if( !sqlite3IndexAffinityOk(aExpr[j].p, idxaff) ) continue;
|
||||||
|
if( pIdx->aiColumn[k]==iColumn ){
|
||||||
switch( aExpr[j].p->op ){
|
switch( aExpr[j].p->op ){
|
||||||
case TK_IN: {
|
case TK_IN: {
|
||||||
if( k==0 ) inMask |= 1;
|
if( k==0 ) inMask |= 1;
|
||||||
@ -575,8 +593,11 @@ WhereInfo *sqlite3WhereBegin(
|
|||||||
int k;
|
int k;
|
||||||
char idxaff = pIdx->pTable->aCol[iColumn].affinity;
|
char idxaff = pIdx->pTable->aCol[iColumn].affinity;
|
||||||
for(k=0; k<pIdx->nColumn; k++){
|
for(k=0; k<pIdx->nColumn; k++){
|
||||||
if( pIdx->aiColumn[k]==iColumn
|
/* If the collating sequences or affinities don't match,
|
||||||
&& sqlite3IndexAffinityOk(aExpr[j].p, idxaff) ){
|
** ignore this index. */
|
||||||
|
if( pColl!=pIdx->keyInfo.aColl[k] ) continue;
|
||||||
|
if( !sqlite3IndexAffinityOk(aExpr[j].p, idxaff) ) continue;
|
||||||
|
if( pIdx->aiColumn[k]==iColumn ){
|
||||||
switch( aExpr[j].p->op ){
|
switch( aExpr[j].p->op ){
|
||||||
case TK_EQ: {
|
case TK_EQ: {
|
||||||
eqMask |= 1<<k;
|
eqMask |= 1<<k;
|
||||||
@ -655,7 +676,7 @@ WhereInfo *sqlite3WhereBegin(
|
|||||||
pSortIdx = 0;
|
pSortIdx = 0;
|
||||||
}else{
|
}else{
|
||||||
int nEqCol = (pWInfo->a[0].score+4)/8;
|
int nEqCol = (pWInfo->a[0].score+4)/8;
|
||||||
pSortIdx = findSortingIndex(pTab, pTabList->a[0].iCursor,
|
pSortIdx = findSortingIndex(pParse->db, pTab, pTabList->a[0].iCursor,
|
||||||
*ppOrderBy, pIdx, nEqCol, &bRev);
|
*ppOrderBy, pIdx, nEqCol, &bRev);
|
||||||
}
|
}
|
||||||
if( pSortIdx && (pIdx==0 || pIdx==pSortIdx) ){
|
if( pSortIdx && (pIdx==0 || pIdx==pSortIdx) ){
|
||||||
|
226
test/collate1.test
Normal file
226
test/collate1.test
Normal file
@ -0,0 +1,226 @@
|
|||||||
|
#
|
||||||
|
# The author or author's hereby grant to the public domain a non-exclusive,
|
||||||
|
# fully paid-up, perpetual, license in the software and all related
|
||||||
|
# intellectual property to make, have made, use, have used, reproduce,
|
||||||
|
# prepare derivative works, distribute, perform and display the work.
|
||||||
|
#
|
||||||
|
#*************************************************************************
|
||||||
|
# This file implements regression tests for SQLite library. The
|
||||||
|
# focus of this file is testing the ORDER BY clause with
|
||||||
|
# user-defined collation sequences.
|
||||||
|
#
|
||||||
|
# $Id: collate1.test,v 1.1 2004/06/09 09:55:20 danielk1977 Exp $
|
||||||
|
|
||||||
|
set testdir [file dirname $argv0]
|
||||||
|
source $testdir/tester.tcl
|
||||||
|
|
||||||
|
#
|
||||||
|
# Tests are roughly organised as follows:
|
||||||
|
#
|
||||||
|
# collate1-1.* - Single-field ORDER BY with an explicit COLLATE clause.
|
||||||
|
# collate1-2.* - Multi-field ORDER BY with an explicit COLLATE clause.
|
||||||
|
# collate1-3.* - ORDER BY using a default collation type. Also that an
|
||||||
|
# explict collate type overrides a default collate type.
|
||||||
|
# collate1-4.* - ORDER BY using a data type.
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# Collation type 'HEX'. If an argument can be interpreted as a hexadecimal
|
||||||
|
# number, then it is converted to one before the comparison is performed.
|
||||||
|
# Numbers are less than other strings. If neither argument is a number,
|
||||||
|
# [string compare] is used.
|
||||||
|
#
|
||||||
|
db collate HEX hex_collate
|
||||||
|
proc hex_collate {lhs rhs} {
|
||||||
|
set lhs_ishex [regexp {^(0x|)[1234567890abcdefABCDEF]+$} $lhs]
|
||||||
|
set rhs_ishex [regexp {^(0x|)[1234567890abcdefABCDEF]+$} $rhs]
|
||||||
|
if {$lhs_ishex && $rhs_ishex} {
|
||||||
|
set lhsx [scan $lhs %x]
|
||||||
|
set rhsx [scan $rhs %x]
|
||||||
|
if {$lhs < $rhs} {return -1}
|
||||||
|
if {$lhs == $rhs} {return 0}
|
||||||
|
if {$lhs > $rhs} {return 1}
|
||||||
|
}
|
||||||
|
if {$lhs_ishex} {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if {$rhs_ishex} {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return [string compare $lhs $rhs]
|
||||||
|
}
|
||||||
|
db function hex {format 0x%X}
|
||||||
|
|
||||||
|
# Mimic the SQLite 2 collation type NUMERIC.
|
||||||
|
db collate numeric numeric_collate
|
||||||
|
proc numeric_collate {lhs rhs} {
|
||||||
|
if {$lhs == $rhs} {return 0}
|
||||||
|
return [expr ($lhs>$rhs)?1:-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
do_test collate1-1.0 {
|
||||||
|
execsql {
|
||||||
|
CREATE TABLE collate1t1(c1, c2);
|
||||||
|
INSERT INTO collate1t1 VALUES(45, hex(45));
|
||||||
|
INSERT INTO collate1t1 VALUES(NULL, NULL);
|
||||||
|
INSERT INTO collate1t1 VALUES(281, hex(281));
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
do_test collate1-1.1 {
|
||||||
|
execsql {
|
||||||
|
SELECT c2 FROM collate1t1 ORDER BY 1;
|
||||||
|
}
|
||||||
|
} {{} 0x119 0x2D}
|
||||||
|
do_test collate1-1.2 {
|
||||||
|
execsql {
|
||||||
|
SELECT c2 FROM collate1t1 ORDER BY 1 COLLATE hex;
|
||||||
|
}
|
||||||
|
} {{} 0x2D 0x119}
|
||||||
|
do_test collate1-1.3 {
|
||||||
|
execsql {
|
||||||
|
SELECT c2 FROM collate1t1 ORDER BY 1 COLLATE hex DESC;
|
||||||
|
}
|
||||||
|
} {0x119 0x2D {}}
|
||||||
|
do_test collate1-1.4 {
|
||||||
|
execsql {
|
||||||
|
SELECT c2 FROM collate1t1 ORDER BY 1 COLLATE hex ASC;
|
||||||
|
}
|
||||||
|
} {{} 0x2D 0x119}
|
||||||
|
do_test collate1-1.5 {
|
||||||
|
execsql {
|
||||||
|
DROP TABLE collate1t1;
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
|
||||||
|
do_test collate1-2.0 {
|
||||||
|
execsql {
|
||||||
|
CREATE TABLE collate1t1(c1, c2);
|
||||||
|
INSERT INTO collate1t1 VALUES('5', '0x11');
|
||||||
|
INSERT INTO collate1t1 VALUES('5', '0xA');
|
||||||
|
INSERT INTO collate1t1 VALUES(NULL, NULL);
|
||||||
|
INSERT INTO collate1t1 VALUES('7', '0xA');
|
||||||
|
INSERT INTO collate1t1 VALUES('11', '0x11');
|
||||||
|
INSERT INTO collate1t1 VALUES('11', '0x101');
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
do_test collate1-2.2 {
|
||||||
|
execsql {
|
||||||
|
SELECT c1, c2 FROM collate1t1 ORDER BY 1 COLLATE numeric, 2 COLLATE hex;
|
||||||
|
}
|
||||||
|
} {{} {} 5 0xA 5 0x11 7 0xA 11 0x11 11 0x101}
|
||||||
|
do_test collate1-2.3 {
|
||||||
|
execsql {
|
||||||
|
SELECT c1, c2 FROM collate1t1 ORDER BY 1 COLLATE binary, 2 COLLATE hex;
|
||||||
|
}
|
||||||
|
} {{} {} 11 0x11 11 0x101 5 0xA 5 0x11 7 0xA}
|
||||||
|
do_test collate1-2.4 {
|
||||||
|
execsql {
|
||||||
|
SELECT c1, c2 FROM collate1t1 ORDER BY 1 COLLATE binary DESC, 2 COLLATE hex;
|
||||||
|
}
|
||||||
|
} {7 0xA 5 0xA 5 0x11 11 0x11 11 0x101 {} {}}
|
||||||
|
do_test collate1-2.5 {
|
||||||
|
execsql {
|
||||||
|
SELECT c1, c2 FROM collate1t1
|
||||||
|
ORDER BY 1 COLLATE binary DESC, 2 COLLATE hex DESC;
|
||||||
|
}
|
||||||
|
} {7 0xA 5 0x11 5 0xA 11 0x101 11 0x11 {} {}}
|
||||||
|
do_test collate1-2.6 {
|
||||||
|
execsql {
|
||||||
|
SELECT c1, c2 FROM collate1t1
|
||||||
|
ORDER BY 1 COLLATE binary ASC, 2 COLLATE hex ASC;
|
||||||
|
}
|
||||||
|
} {{} {} 11 0x11 11 0x101 5 0xA 5 0x11 7 0xA}
|
||||||
|
do_test collate1-2.7 {
|
||||||
|
execsql {
|
||||||
|
DROP TABLE collate1t1;
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
|
||||||
|
#
|
||||||
|
# These tests ensure that the default collation type for a column is used
|
||||||
|
# by an ORDER BY clause correctly. The focus is all the different ways
|
||||||
|
# the column can be referenced. i.e. a, collate2t1.a, main.collate2t1.a etc.
|
||||||
|
#
|
||||||
|
do_test collate1-3.0 {
|
||||||
|
execsql {
|
||||||
|
CREATE TABLE collate1t1(a COLLATE hex, b);
|
||||||
|
INSERT INTO collate1t1 VALUES( '0x5', 5 );
|
||||||
|
INSERT INTO collate1t1 VALUES( '1', 1 );
|
||||||
|
INSERT INTO collate1t1 VALUES( '0x45', 69 );
|
||||||
|
INSERT INTO collate1t1 VALUES( NULL, NULL );
|
||||||
|
SELECT * FROM collate1t1 ORDER BY a;
|
||||||
|
}
|
||||||
|
} {{} {} 1 1 0x5 5 0x45 69}
|
||||||
|
|
||||||
|
do_test collate1-3.1 {
|
||||||
|
execsql {
|
||||||
|
SELECT * FROM collate1t1 ORDER BY 1;
|
||||||
|
}
|
||||||
|
} {{} {} 1 1 0x5 5 0x45 69}
|
||||||
|
do_test collate1-3.2 {
|
||||||
|
execsql {
|
||||||
|
SELECT * FROM collate1t1 ORDER BY collate1t1.a;
|
||||||
|
}
|
||||||
|
} {{} {} 1 1 0x5 5 0x45 69}
|
||||||
|
do_test collate1-3.3 {
|
||||||
|
execsql {
|
||||||
|
SELECT * FROM collate1t1 ORDER BY main.collate1t1.a;
|
||||||
|
}
|
||||||
|
} {{} {} 1 1 0x5 5 0x45 69}
|
||||||
|
do_test collate1-3.4 {
|
||||||
|
execsql {
|
||||||
|
SELECT a as c1, b as c2 FROM collate1t1 ORDER BY c1;
|
||||||
|
}
|
||||||
|
} {{} {} 1 1 0x5 5 0x45 69}
|
||||||
|
do_test collate1-3.5 {
|
||||||
|
execsql {
|
||||||
|
SELECT a as c1, b as c2 FROM collate1t1 ORDER BY c1 COLLATE binary;
|
||||||
|
}
|
||||||
|
} {{} {} 0x45 69 0x5 5 1 1}
|
||||||
|
do_test collate1-3.6 {
|
||||||
|
execsql {
|
||||||
|
DROP TABLE collate1t1;
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
|
||||||
|
# Update for SQLite version 3. The collate1-4.* test cases were written
|
||||||
|
# before manifest types were introduced. The following test cases still
|
||||||
|
# work, due to the 'affinity' mechanism, but they don't prove anything
|
||||||
|
# about collation sequences.
|
||||||
|
#
|
||||||
|
do_test collate1-4.0 {
|
||||||
|
execsql {
|
||||||
|
CREATE TABLE collate1t1(c1 numeric, c2 text);
|
||||||
|
INSERT INTO collate1t1 VALUES(1, 1);
|
||||||
|
INSERT INTO collate1t1 VALUES(12, 12);
|
||||||
|
INSERT INTO collate1t1 VALUES(NULL, NULL);
|
||||||
|
INSERT INTO collate1t1 VALUES(101, 101);
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
do_test collate1-4.1 {
|
||||||
|
execsql {
|
||||||
|
SELECT c1 FROM collate1t1 ORDER BY 1;
|
||||||
|
}
|
||||||
|
} {{} 1 12 101}
|
||||||
|
do_test collate1-4.2 {
|
||||||
|
execsql {
|
||||||
|
SELECT c2 FROM collate1t1 ORDER BY 1;
|
||||||
|
}
|
||||||
|
} {{} 1 101 12}
|
||||||
|
do_test collate1-4.3 {
|
||||||
|
execsql {
|
||||||
|
SELECT c2+0 FROM collate1t1 ORDER BY 1;
|
||||||
|
}
|
||||||
|
} {{} 1 12 101}
|
||||||
|
do_test collate1-4.4 {
|
||||||
|
execsql {
|
||||||
|
SELECT c1||'' FROM collate1t1 ORDER BY 1;
|
||||||
|
}
|
||||||
|
} {{} 1 101 12}
|
||||||
|
do_test collate1-4.5 {
|
||||||
|
execsql {
|
||||||
|
DROP TABLE collate1t1;
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
|
||||||
|
finish_test
|
604
test/collate2.test
Normal file
604
test/collate2.test
Normal file
@ -0,0 +1,604 @@
|
|||||||
|
#
|
||||||
|
# The author or author's hereby grant to the public domain a non-exclusive,
|
||||||
|
# fully paid-up, perpetual, license in the software and all related
|
||||||
|
# intellectual property to make, have made, use, have used, reproduce,
|
||||||
|
# prepare derivative works, distribute, perform and display the work.
|
||||||
|
#
|
||||||
|
#*************************************************************************
|
||||||
|
# This file implements regression tests for SQLite library. The
|
||||||
|
# focus of this file is testing comparison operators in expressions
|
||||||
|
# that use user-defined collation sequences.
|
||||||
|
#
|
||||||
|
|
||||||
|
set testdir [file dirname $argv0]
|
||||||
|
source $testdir/tester.tcl
|
||||||
|
|
||||||
|
#
|
||||||
|
# Tests are organised as follows:
|
||||||
|
#
|
||||||
|
# collate2-1.* WHERE <expr> expressions (sqliteExprIfTrue).
|
||||||
|
# collate2-2.* WHERE NOT <expr> expressions (sqliteExprIfFalse).
|
||||||
|
# collate2-3.* SELECT <expr> expressions (sqliteExprCode).
|
||||||
|
# collate2-4.* Precedence of collation/data types in binary comparisons
|
||||||
|
# collate2-5.* JOIN syntax.
|
||||||
|
#
|
||||||
|
|
||||||
|
# Create a collation type BACKWARDS for use in testing. This collation type
|
||||||
|
# is similar to the built-in TEXT collation type except the order of
|
||||||
|
# characters in each string is reversed before the comparison is performed.
|
||||||
|
db collate BACKWARDS backwards_collate
|
||||||
|
proc backwards_collate {a b} {
|
||||||
|
set ra {};
|
||||||
|
set rb {}
|
||||||
|
foreach c [split $a {}] { set ra $c$ra }
|
||||||
|
foreach c [split $b {}] { set rb $c$rb }
|
||||||
|
return [string compare $ra $rb]
|
||||||
|
}
|
||||||
|
|
||||||
|
# The following values are used in these tests:
|
||||||
|
# NULL aa ab ba bb aA aB bA bB Aa Ab Ba Bb AA AB BA BB
|
||||||
|
#
|
||||||
|
# The collation orders for each of the tested collation types are:
|
||||||
|
#
|
||||||
|
# BINARY: NULL AA AB Aa Ab BA BB Ba Bb aA aB aa ab bA bB ba bb
|
||||||
|
# NOCASE: NULL aa aA Aa AA ab aB Ab AB ba bA Ba BA bb bB Bb BB
|
||||||
|
# BACKWARDS: NULL AA BA aA bA AB BB aB bB Aa Ba aa ba Ab Bb ab bb
|
||||||
|
#
|
||||||
|
# These tests verify that the default collation type for a column is used
|
||||||
|
# for comparison operators (<, >, <=, >=, =) involving that column and
|
||||||
|
# an expression that is not a column with a default collation type.
|
||||||
|
#
|
||||||
|
# The collation sequences BINARY and NOCASE are built-in, the BACKWARDS
|
||||||
|
# collation sequence is implemented by the TCL proc backwards_collate
|
||||||
|
# above.
|
||||||
|
#
|
||||||
|
do_test collate2-1.0 {
|
||||||
|
execsql {
|
||||||
|
CREATE TABLE collate2t1(
|
||||||
|
a COLLATE BINARY,
|
||||||
|
b COLLATE NOCASE,
|
||||||
|
c COLLATE BACKWARDS
|
||||||
|
);
|
||||||
|
INSERT INTO collate2t1 VALUES( NULL, NULL, NULL );
|
||||||
|
|
||||||
|
INSERT INTO collate2t1 VALUES( 'aa', 'aa', 'aa' );
|
||||||
|
INSERT INTO collate2t1 VALUES( 'ab', 'ab', 'ab' );
|
||||||
|
INSERT INTO collate2t1 VALUES( 'ba', 'ba', 'ba' );
|
||||||
|
INSERT INTO collate2t1 VALUES( 'bb', 'bb', 'bb' );
|
||||||
|
|
||||||
|
INSERT INTO collate2t1 VALUES( 'aA', 'aA', 'aA' );
|
||||||
|
INSERT INTO collate2t1 VALUES( 'aB', 'aB', 'aB' );
|
||||||
|
INSERT INTO collate2t1 VALUES( 'bA', 'bA', 'bA' );
|
||||||
|
INSERT INTO collate2t1 VALUES( 'bB', 'bB', 'bB' );
|
||||||
|
|
||||||
|
INSERT INTO collate2t1 VALUES( 'Aa', 'Aa', 'Aa' );
|
||||||
|
INSERT INTO collate2t1 VALUES( 'Ab', 'Ab', 'Ab' );
|
||||||
|
INSERT INTO collate2t1 VALUES( 'Ba', 'Ba', 'Ba' );
|
||||||
|
INSERT INTO collate2t1 VALUES( 'Bb', 'Bb', 'Bb' );
|
||||||
|
|
||||||
|
INSERT INTO collate2t1 VALUES( 'AA', 'AA', 'AA' );
|
||||||
|
INSERT INTO collate2t1 VALUES( 'AB', 'AB', 'AB' );
|
||||||
|
INSERT INTO collate2t1 VALUES( 'BA', 'BA', 'BA' );
|
||||||
|
INSERT INTO collate2t1 VALUES( 'BB', 'BB', 'BB' );
|
||||||
|
}
|
||||||
|
if {[info exists collate_test_use_index]} {
|
||||||
|
execsql {
|
||||||
|
CREATE INDEX collate2t1_i1 ON collate2t1(a);
|
||||||
|
CREATE INDEX collate2t1_i2 ON collate2t1(b);
|
||||||
|
CREATE INDEX collate2t1_i3 ON collate2t1(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
do_test collate2-1.1 {
|
||||||
|
execsql {
|
||||||
|
SELECT a FROM collate2t1 WHERE a > 'aa' ORDER BY 1;
|
||||||
|
}
|
||||||
|
} {ab bA bB ba bb}
|
||||||
|
do_test collate2-1.2 {
|
||||||
|
execsql {
|
||||||
|
SELECT b FROM collate2t1 WHERE b > 'aa' ORDER BY 1, oid;
|
||||||
|
}
|
||||||
|
} {ab aB Ab AB ba bA Ba BA bb bB Bb BB}
|
||||||
|
do_test collate2-1.3 {
|
||||||
|
execsql {
|
||||||
|
SELECT c FROM collate2t1 WHERE c > 'aa' ORDER BY 1;
|
||||||
|
}
|
||||||
|
} {ba Ab Bb ab bb}
|
||||||
|
do_test collate2-1.4 {
|
||||||
|
execsql {
|
||||||
|
SELECT a FROM collate2t1 WHERE a < 'aa' ORDER BY 1;
|
||||||
|
}
|
||||||
|
} {AA AB Aa Ab BA BB Ba Bb aA aB}
|
||||||
|
do_test collate2-1.5 {
|
||||||
|
execsql {
|
||||||
|
SELECT b FROM collate2t1 WHERE b < 'aa' ORDER BY 1, oid;
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
do_test collate2-1.6 {
|
||||||
|
execsql {
|
||||||
|
SELECT c FROM collate2t1 WHERE c < 'aa' ORDER BY 1;
|
||||||
|
}
|
||||||
|
} {AA BA aA bA AB BB aB bB Aa Ba}
|
||||||
|
do_test collate2-1.7 {
|
||||||
|
execsql {
|
||||||
|
SELECT a FROM collate2t1 WHERE a = 'aa';
|
||||||
|
}
|
||||||
|
} {aa}
|
||||||
|
do_test collate2-1.8 {
|
||||||
|
execsql {
|
||||||
|
SELECT b FROM collate2t1 WHERE b = 'aa' ORDER BY oid;
|
||||||
|
}
|
||||||
|
} {aa aA Aa AA}
|
||||||
|
do_test collate2-1.9 {
|
||||||
|
execsql {
|
||||||
|
SELECT c FROM collate2t1 WHERE c = 'aa';
|
||||||
|
}
|
||||||
|
} {aa}
|
||||||
|
do_test collate2-1.10 {
|
||||||
|
execsql {
|
||||||
|
SELECT a FROM collate2t1 WHERE a >= 'aa' ORDER BY 1;
|
||||||
|
}
|
||||||
|
} {aa ab bA bB ba bb}
|
||||||
|
do_test collate2-1.11 {
|
||||||
|
execsql {
|
||||||
|
SELECT b FROM collate2t1 WHERE b >= 'aa' ORDER BY 1, oid;
|
||||||
|
}
|
||||||
|
} {aa aA Aa AA ab aB Ab AB ba bA Ba BA bb bB Bb BB}
|
||||||
|
do_test collate2-1.12 {
|
||||||
|
execsql {
|
||||||
|
SELECT c FROM collate2t1 WHERE c >= 'aa' ORDER BY 1;
|
||||||
|
}
|
||||||
|
} {aa ba Ab Bb ab bb}
|
||||||
|
do_test collate2-1.13 {
|
||||||
|
execsql {
|
||||||
|
SELECT a FROM collate2t1 WHERE a <= 'aa' ORDER BY 1;
|
||||||
|
}
|
||||||
|
} {AA AB Aa Ab BA BB Ba Bb aA aB aa}
|
||||||
|
do_test collate2-1.14 {
|
||||||
|
execsql {
|
||||||
|
SELECT b FROM collate2t1 WHERE b <= 'aa' ORDER BY 1, oid;
|
||||||
|
}
|
||||||
|
} {aa aA Aa AA}
|
||||||
|
do_test collate2-1.15 {
|
||||||
|
execsql {
|
||||||
|
SELECT c FROM collate2t1 WHERE c <= 'aa' ORDER BY 1;
|
||||||
|
}
|
||||||
|
} {AA BA aA bA AB BB aB bB Aa Ba aa}
|
||||||
|
do_test collate2-1.16 {
|
||||||
|
execsql {
|
||||||
|
SELECT a FROM collate2t1 WHERE a BETWEEN 'Aa' AND 'Bb' ORDER BY 1;
|
||||||
|
}
|
||||||
|
} {Aa Ab BA BB Ba Bb}
|
||||||
|
do_test collate2-1.17 {
|
||||||
|
execsql {
|
||||||
|
SELECT b FROM collate2t1 WHERE b BETWEEN 'Aa' AND 'Bb' ORDER BY 1, oid;
|
||||||
|
}
|
||||||
|
} {aa aA Aa AA ab aB Ab AB ba bA Ba BA bb bB Bb BB}
|
||||||
|
do_test collate2-1.18 {
|
||||||
|
execsql {
|
||||||
|
SELECT c FROM collate2t1 WHERE c BETWEEN 'Aa' AND 'Bb' ORDER BY 1;
|
||||||
|
}
|
||||||
|
} {Aa Ba aa ba Ab Bb}
|
||||||
|
do_test collate2-1.19 {
|
||||||
|
execsql {
|
||||||
|
SELECT a FROM collate2t1 WHERE
|
||||||
|
CASE a WHEN 'aa' THEN 1 ELSE 0 END
|
||||||
|
ORDER BY 1, oid;
|
||||||
|
}
|
||||||
|
} {aa}
|
||||||
|
do_test collate2-1.20 {
|
||||||
|
execsql {
|
||||||
|
SELECT b FROM collate2t1 WHERE
|
||||||
|
CASE b WHEN 'aa' THEN 1 ELSE 0 END
|
||||||
|
ORDER BY 1, oid;
|
||||||
|
}
|
||||||
|
} {aa aA Aa AA}
|
||||||
|
do_test collate2-1.21 {
|
||||||
|
execsql {
|
||||||
|
SELECT c FROM collate2t1 WHERE
|
||||||
|
CASE c WHEN 'aa' THEN 1 ELSE 0 END
|
||||||
|
ORDER BY 1, oid;
|
||||||
|
}
|
||||||
|
} {aa}
|
||||||
|
do_test collate2-1.22 {
|
||||||
|
execsql {
|
||||||
|
SELECT a FROM collate2t1 WHERE a IN ('aa', 'bb') ORDER BY 1, oid;
|
||||||
|
}
|
||||||
|
} {aa bb}
|
||||||
|
do_test collate2-1.23 {
|
||||||
|
execsql {
|
||||||
|
SELECT b FROM collate2t1 WHERE b IN ('aa', 'bb') ORDER BY 1, oid;
|
||||||
|
}
|
||||||
|
} {aa aA Aa AA bb bB Bb BB}
|
||||||
|
do_test collate2-1.24 {
|
||||||
|
execsql {
|
||||||
|
SELECT c FROM collate2t1 WHERE c IN ('aa', 'bb') ORDER BY 1, oid;
|
||||||
|
}
|
||||||
|
} {aa bb}
|
||||||
|
do_test collate2-1.25 {
|
||||||
|
execsql {
|
||||||
|
SELECT a FROM collate2t1
|
||||||
|
WHERE a IN (SELECT a FROM collate2t1 WHERE a IN ('aa', 'bb'));
|
||||||
|
}
|
||||||
|
} {aa bb}
|
||||||
|
do_test collate2-1.26 {
|
||||||
|
execsql {
|
||||||
|
SELECT b FROM collate2t1
|
||||||
|
WHERE b IN (SELECT a FROM collate2t1 WHERE a IN ('aa', 'bb'));
|
||||||
|
}
|
||||||
|
} {aa bb aA bB Aa Bb AA BB}
|
||||||
|
do_test collate2-1.27 {
|
||||||
|
execsql {
|
||||||
|
SELECT c FROM collate2t1
|
||||||
|
WHERE c IN (SELECT a FROM collate2t1 WHERE a IN ('aa', 'bb'));
|
||||||
|
}
|
||||||
|
} {aa bb}
|
||||||
|
|
||||||
|
do_test collate2-2.1 {
|
||||||
|
execsql {
|
||||||
|
SELECT a FROM collate2t1 WHERE NOT a > 'aa' ORDER BY 1;
|
||||||
|
}
|
||||||
|
} {AA AB Aa Ab BA BB Ba Bb aA aB aa}
|
||||||
|
do_test collate2-2.2 {
|
||||||
|
execsql {
|
||||||
|
SELECT b FROM collate2t1 WHERE NOT b > 'aa' ORDER BY 1, oid;
|
||||||
|
}
|
||||||
|
} {aa aA Aa AA}
|
||||||
|
do_test collate2-2.3 {
|
||||||
|
execsql {
|
||||||
|
SELECT c FROM collate2t1 WHERE NOT c > 'aa' ORDER BY 1;
|
||||||
|
}
|
||||||
|
} {AA BA aA bA AB BB aB bB Aa Ba aa}
|
||||||
|
do_test collate2-2.4 {
|
||||||
|
execsql {
|
||||||
|
SELECT a FROM collate2t1 WHERE NOT a < 'aa' ORDER BY 1;
|
||||||
|
}
|
||||||
|
} {aa ab bA bB ba bb}
|
||||||
|
do_test collate2-2.5 {
|
||||||
|
execsql {
|
||||||
|
SELECT b FROM collate2t1 WHERE NOT b < 'aa' ORDER BY 1, oid;
|
||||||
|
}
|
||||||
|
} {aa aA Aa AA ab aB Ab AB ba bA Ba BA bb bB Bb BB}
|
||||||
|
do_test collate2-2.6 {
|
||||||
|
execsql {
|
||||||
|
SELECT c FROM collate2t1 WHERE NOT c < 'aa' ORDER BY 1;
|
||||||
|
}
|
||||||
|
} {aa ba Ab Bb ab bb}
|
||||||
|
do_test collate2-2.7 {
|
||||||
|
execsql {
|
||||||
|
SELECT a FROM collate2t1 WHERE NOT a = 'aa';
|
||||||
|
}
|
||||||
|
} {ab ba bb aA aB bA bB Aa Ab Ba Bb AA AB BA BB}
|
||||||
|
do_test collate2-2.8 {
|
||||||
|
execsql {
|
||||||
|
SELECT b FROM collate2t1 WHERE NOT b = 'aa';
|
||||||
|
}
|
||||||
|
} {ab ba bb aB bA bB Ab Ba Bb AB BA BB}
|
||||||
|
do_test collate2-2.9 {
|
||||||
|
execsql {
|
||||||
|
SELECT c FROM collate2t1 WHERE NOT c = 'aa';
|
||||||
|
}
|
||||||
|
} {ab ba bb aA aB bA bB Aa Ab Ba Bb AA AB BA BB}
|
||||||
|
do_test collate2-2.10 {
|
||||||
|
execsql {
|
||||||
|
SELECT a FROM collate2t1 WHERE NOT a >= 'aa' ORDER BY 1;
|
||||||
|
}
|
||||||
|
} {AA AB Aa Ab BA BB Ba Bb aA aB}
|
||||||
|
do_test collate2-2.11 {
|
||||||
|
execsql {
|
||||||
|
SELECT b FROM collate2t1 WHERE NOT b >= 'aa' ORDER BY 1, oid;
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
do_test collate2-2.12 {
|
||||||
|
execsql {
|
||||||
|
SELECT c FROM collate2t1 WHERE NOT c >= 'aa' ORDER BY 1;
|
||||||
|
}
|
||||||
|
} {AA BA aA bA AB BB aB bB Aa Ba}
|
||||||
|
do_test collate2-2.13 {
|
||||||
|
execsql {
|
||||||
|
SELECT a FROM collate2t1 WHERE NOT a <= 'aa' ORDER BY 1;
|
||||||
|
}
|
||||||
|
} {ab bA bB ba bb}
|
||||||
|
do_test collate2-2.14 {
|
||||||
|
execsql {
|
||||||
|
SELECT b FROM collate2t1 WHERE NOT b <= 'aa' ORDER BY 1, oid;
|
||||||
|
}
|
||||||
|
} {ab aB Ab AB ba bA Ba BA bb bB Bb BB}
|
||||||
|
do_test collate2-2.15 {
|
||||||
|
execsql {
|
||||||
|
SELECT c FROM collate2t1 WHERE NOT c <= 'aa' ORDER BY 1;
|
||||||
|
}
|
||||||
|
} {ba Ab Bb ab bb}
|
||||||
|
do_test collate2-2.16 {
|
||||||
|
execsql {
|
||||||
|
SELECT a FROM collate2t1 WHERE a NOT BETWEEN 'Aa' AND 'Bb' ORDER BY 1;
|
||||||
|
}
|
||||||
|
} {AA AB aA aB aa ab bA bB ba bb}
|
||||||
|
do_test collate2-2.17 {
|
||||||
|
execsql {
|
||||||
|
SELECT b FROM collate2t1 WHERE b NOT BETWEEN 'Aa' AND 'Bb' ORDER BY 1, oid;
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
do_test collate2-2.18 {
|
||||||
|
execsql {
|
||||||
|
SELECT c FROM collate2t1 WHERE c NOT BETWEEN 'Aa' AND 'Bb' ORDER BY 1;
|
||||||
|
}
|
||||||
|
} {AA BA aA bA AB BB aB bB ab bb}
|
||||||
|
do_test collate2-2.19 {
|
||||||
|
execsql {
|
||||||
|
SELECT a FROM collate2t1 WHERE NOT CASE a WHEN 'aa' THEN 1 ELSE 0 END;
|
||||||
|
}
|
||||||
|
} {{} ab ba bb aA aB bA bB Aa Ab Ba Bb AA AB BA BB}
|
||||||
|
do_test collate2-2.20 {
|
||||||
|
execsql {
|
||||||
|
SELECT b FROM collate2t1 WHERE NOT CASE b WHEN 'aa' THEN 1 ELSE 0 END;
|
||||||
|
}
|
||||||
|
} {{} ab ba bb aB bA bB Ab Ba Bb AB BA BB}
|
||||||
|
do_test collate2-2.21 {
|
||||||
|
execsql {
|
||||||
|
SELECT c FROM collate2t1 WHERE NOT CASE c WHEN 'aa' THEN 1 ELSE 0 END;
|
||||||
|
}
|
||||||
|
} {{} ab ba bb aA aB bA bB Aa Ab Ba Bb AA AB BA BB}
|
||||||
|
do_test collate2-2.22 {
|
||||||
|
execsql {
|
||||||
|
SELECT a FROM collate2t1 WHERE NOT a IN ('aa', 'bb');
|
||||||
|
}
|
||||||
|
} {ab ba aA aB bA bB Aa Ab Ba Bb AA AB BA BB}
|
||||||
|
do_test collate2-2.23 {
|
||||||
|
execsql {
|
||||||
|
SELECT b FROM collate2t1 WHERE NOT b IN ('aa', 'bb');
|
||||||
|
}
|
||||||
|
} {ab ba aB bA Ab Ba AB BA}
|
||||||
|
do_test collate2-2.24 {
|
||||||
|
execsql {
|
||||||
|
SELECT c FROM collate2t1 WHERE NOT c IN ('aa', 'bb');
|
||||||
|
}
|
||||||
|
} {ab ba aA aB bA bB Aa Ab Ba Bb AA AB BA BB}
|
||||||
|
do_test collate2-2.25 {
|
||||||
|
execsql {
|
||||||
|
SELECT a FROM collate2t1
|
||||||
|
WHERE NOT a IN (SELECT a FROM collate2t1 WHERE a IN ('aa', 'bb'));
|
||||||
|
}
|
||||||
|
} {ab ba aA aB bA bB Aa Ab Ba Bb AA AB BA BB}
|
||||||
|
do_test collate2-2.26 {
|
||||||
|
execsql {
|
||||||
|
SELECT b FROM collate2t1
|
||||||
|
WHERE NOT b IN (SELECT a FROM collate2t1 WHERE a IN ('aa', 'bb'));
|
||||||
|
}
|
||||||
|
} {ab ba aB bA Ab Ba AB BA}
|
||||||
|
do_test collate2-2.27 {
|
||||||
|
execsql {
|
||||||
|
SELECT c FROM collate2t1
|
||||||
|
WHERE NOT c IN (SELECT a FROM collate2t1 WHERE a IN ('aa', 'bb'));
|
||||||
|
}
|
||||||
|
} {ab ba aA aB bA bB Aa Ab Ba Bb AA AB BA BB}
|
||||||
|
|
||||||
|
do_test collate2-3.1 {
|
||||||
|
execsql {
|
||||||
|
SELECT a > 'aa' FROM collate2t1;
|
||||||
|
}
|
||||||
|
} {{} 0 1 1 1 0 0 1 1 0 0 0 0 0 0 0 0}
|
||||||
|
do_test collate2-3.2 {
|
||||||
|
execsql {
|
||||||
|
SELECT b > 'aa' FROM collate2t1;
|
||||||
|
}
|
||||||
|
} {{} 0 1 1 1 0 1 1 1 0 1 1 1 0 1 1 1}
|
||||||
|
do_test collate2-3.3 {
|
||||||
|
execsql {
|
||||||
|
SELECT c > 'aa' FROM collate2t1;
|
||||||
|
}
|
||||||
|
} {{} 0 1 1 1 0 0 0 0 0 1 0 1 0 0 0 0}
|
||||||
|
do_test collate2-3.4 {
|
||||||
|
execsql {
|
||||||
|
SELECT a < 'aa' FROM collate2t1;
|
||||||
|
}
|
||||||
|
} {{} 0 0 0 0 1 1 0 0 1 1 1 1 1 1 1 1}
|
||||||
|
do_test collate2-3.5 {
|
||||||
|
execsql {
|
||||||
|
SELECT b < 'aa' FROM collate2t1;
|
||||||
|
}
|
||||||
|
} {{} 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0}
|
||||||
|
do_test collate2-3.6 {
|
||||||
|
execsql {
|
||||||
|
SELECT c < 'aa' FROM collate2t1;
|
||||||
|
}
|
||||||
|
} {{} 0 0 0 0 1 1 1 1 1 0 1 0 1 1 1 1}
|
||||||
|
do_test collate2-3.7 {
|
||||||
|
execsql {
|
||||||
|
SELECT a = 'aa' FROM collate2t1;
|
||||||
|
}
|
||||||
|
} {{} 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0}
|
||||||
|
do_test collate2-3.8 {
|
||||||
|
execsql {
|
||||||
|
SELECT b = 'aa' FROM collate2t1;
|
||||||
|
}
|
||||||
|
} {{} 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0}
|
||||||
|
do_test collate2-3.9 {
|
||||||
|
execsql {
|
||||||
|
SELECT c = 'aa' FROM collate2t1;
|
||||||
|
}
|
||||||
|
} {{} 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0}
|
||||||
|
do_test collate2-3.10 {
|
||||||
|
execsql {
|
||||||
|
SELECT a <= 'aa' FROM collate2t1;
|
||||||
|
}
|
||||||
|
} {{} 1 0 0 0 1 1 0 0 1 1 1 1 1 1 1 1}
|
||||||
|
do_test collate2-3.11 {
|
||||||
|
execsql {
|
||||||
|
SELECT b <= 'aa' FROM collate2t1;
|
||||||
|
}
|
||||||
|
} {{} 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0}
|
||||||
|
do_test collate2-3.12 {
|
||||||
|
execsql {
|
||||||
|
SELECT c <= 'aa' FROM collate2t1;
|
||||||
|
}
|
||||||
|
} {{} 1 0 0 0 1 1 1 1 1 0 1 0 1 1 1 1}
|
||||||
|
do_test collate2-3.13 {
|
||||||
|
execsql {
|
||||||
|
SELECT a >= 'aa' FROM collate2t1;
|
||||||
|
}
|
||||||
|
} {{} 1 1 1 1 0 0 1 1 0 0 0 0 0 0 0 0}
|
||||||
|
do_test collate2-3.14 {
|
||||||
|
execsql {
|
||||||
|
SELECT b >= 'aa' FROM collate2t1;
|
||||||
|
}
|
||||||
|
} {{} 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1}
|
||||||
|
do_test collate2-3.15 {
|
||||||
|
execsql {
|
||||||
|
SELECT c >= 'aa' FROM collate2t1;
|
||||||
|
}
|
||||||
|
} {{} 1 1 1 1 0 0 0 0 0 1 0 1 0 0 0 0}
|
||||||
|
do_test collate2-3.16 {
|
||||||
|
execsql {
|
||||||
|
SELECT a BETWEEN 'Aa' AND 'Bb' FROM collate2t1;
|
||||||
|
}
|
||||||
|
} {{} 0 0 0 0 0 0 0 0 1 1 1 1 0 0 1 1}
|
||||||
|
do_test collate2-3.17 {
|
||||||
|
execsql {
|
||||||
|
SELECT b BETWEEN 'Aa' AND 'Bb' FROM collate2t1;
|
||||||
|
}
|
||||||
|
} {{} 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1}
|
||||||
|
do_test collate2-3.18 {
|
||||||
|
execsql {
|
||||||
|
SELECT c BETWEEN 'Aa' AND 'Bb' FROM collate2t1;
|
||||||
|
}
|
||||||
|
} {{} 1 0 1 0 0 0 0 0 1 1 1 1 0 0 0 0}
|
||||||
|
do_test collate2-3.19 {
|
||||||
|
execsql {
|
||||||
|
SELECT CASE a WHEN 'aa' THEN 1 ELSE 0 END FROM collate2t1;
|
||||||
|
}
|
||||||
|
} {0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0}
|
||||||
|
do_test collate2-3.20 {
|
||||||
|
execsql {
|
||||||
|
SELECT CASE b WHEN 'aa' THEN 1 ELSE 0 END FROM collate2t1;
|
||||||
|
}
|
||||||
|
} {0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0}
|
||||||
|
do_test collate2-3.21 {
|
||||||
|
execsql {
|
||||||
|
SELECT CASE c WHEN 'aa' THEN 1 ELSE 0 END FROM collate2t1;
|
||||||
|
}
|
||||||
|
} {0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0}
|
||||||
|
do_test collate2-3.22 {
|
||||||
|
execsql {
|
||||||
|
SELECT a IN ('aa', 'bb') FROM collate2t1;
|
||||||
|
}
|
||||||
|
} {{} 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0}
|
||||||
|
do_test collate2-3.23 {
|
||||||
|
execsql {
|
||||||
|
SELECT b IN ('aa', 'bb') FROM collate2t1;
|
||||||
|
}
|
||||||
|
} {{} 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1}
|
||||||
|
do_test collate2-3.24 {
|
||||||
|
execsql {
|
||||||
|
SELECT c IN ('aa', 'bb') FROM collate2t1;
|
||||||
|
}
|
||||||
|
} {{} 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0}
|
||||||
|
do_test collate2-3.25 {
|
||||||
|
execsql {
|
||||||
|
SELECT a IN (SELECT a FROM collate2t1 WHERE a IN ('aa', 'bb'))
|
||||||
|
FROM collate2t1;
|
||||||
|
}
|
||||||
|
} {{} 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0}
|
||||||
|
do_test collate2-3.26 {
|
||||||
|
execsql {
|
||||||
|
SELECT b IN (SELECT a FROM collate2t1 WHERE a IN ('aa', 'bb'))
|
||||||
|
FROM collate2t1;
|
||||||
|
}
|
||||||
|
} {{} 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1}
|
||||||
|
do_test collate2-3.27 {
|
||||||
|
execsql {
|
||||||
|
SELECT c IN (SELECT a FROM collate2t1 WHERE a IN ('aa', 'bb'))
|
||||||
|
FROM collate2t1;
|
||||||
|
}
|
||||||
|
} {{} 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0}
|
||||||
|
|
||||||
|
do_test collate2-4.0 {
|
||||||
|
execsql {
|
||||||
|
CREATE TABLE collate2t2(b COLLATE binary);
|
||||||
|
CREATE TABLE collate2t3(b text);
|
||||||
|
INSERT INTO collate2t2 VALUES('aa');
|
||||||
|
INSERT INTO collate2t3 VALUES('aa');
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
|
||||||
|
# Test that when both sides of a binary comparison operator have
|
||||||
|
# default collation types, the collate type for the leftmost term
|
||||||
|
# is used.
|
||||||
|
do_test collate2-4.1 {
|
||||||
|
execsql {
|
||||||
|
SELECT collate2t1.a FROM collate2t1, collate2t2
|
||||||
|
WHERE collate2t1.b = collate2t2.b;
|
||||||
|
}
|
||||||
|
} {aa aA Aa AA}
|
||||||
|
do_test collate2-4.2 {
|
||||||
|
execsql {
|
||||||
|
SELECT collate2t1.a FROM collate2t1, collate2t2
|
||||||
|
WHERE collate2t2.b = collate2t1.b;
|
||||||
|
}
|
||||||
|
} {aa}
|
||||||
|
|
||||||
|
# Test that when one side has a default collation type and the other
|
||||||
|
# does not, the collation type is used.
|
||||||
|
do_test collate2-4.3 {
|
||||||
|
execsql {
|
||||||
|
SELECT collate2t1.a FROM collate2t1, collate2t3
|
||||||
|
WHERE collate2t1.b = collate2t3.b||'';
|
||||||
|
}
|
||||||
|
} {aa aA Aa AA}
|
||||||
|
do_test collate2-4.4 {
|
||||||
|
execsql {
|
||||||
|
SELECT collate2t1.a FROM collate2t1, collate2t3
|
||||||
|
WHERE collate2t3.b||'' = collate2t1.b;
|
||||||
|
}
|
||||||
|
} {aa aA Aa AA}
|
||||||
|
|
||||||
|
do_test collate2-4.5 {
|
||||||
|
execsql {
|
||||||
|
DROP TABLE collate2t3;
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Test that the default collation types are used when the JOIN syntax
|
||||||
|
# is used in place of a WHERE clause.
|
||||||
|
#
|
||||||
|
# SQLite transforms the JOIN syntax into a WHERE clause internally, so
|
||||||
|
# the focus of these tests is to ensure that the table on the left-hand-side
|
||||||
|
# of the join determines the collation type used.
|
||||||
|
#
|
||||||
|
do_test collate2-5.0 {
|
||||||
|
execsql {
|
||||||
|
SELECT collate2t1.b FROM collate2t1 JOIN collate2t2 USING (b);
|
||||||
|
}
|
||||||
|
} {aa aA Aa AA}
|
||||||
|
do_test collate2-5.1 {
|
||||||
|
execsql {
|
||||||
|
SELECT collate2t1.b FROM collate2t2 JOIN collate2t1 USING (b);
|
||||||
|
}
|
||||||
|
} {aa}
|
||||||
|
do_test collate2-5.2 {
|
||||||
|
execsql {
|
||||||
|
SELECT collate2t1.b FROM collate2t1 NATURAL JOIN collate2t2;
|
||||||
|
}
|
||||||
|
} {aa aA Aa AA}
|
||||||
|
do_test collate2-5.3 {
|
||||||
|
execsql {
|
||||||
|
SELECT collate2t1.b FROM collate2t2 NATURAL JOIN collate2t1;
|
||||||
|
}
|
||||||
|
} {aa}
|
||||||
|
do_test collate2-5.4 {
|
||||||
|
execsql {
|
||||||
|
SELECT collate2t2.b FROM collate2t1 LEFT OUTER JOIN collate2t2 USING (b) order by collate2t1.oid;
|
||||||
|
}
|
||||||
|
} {{} aa {} {} {} aa {} {} {} aa {} {} {} aa {} {} {}}
|
||||||
|
do_test collate2-5.5 {
|
||||||
|
execsql {
|
||||||
|
SELECT collate2t1.b, collate2t2.b FROM collate2t2 LEFT OUTER JOIN collate2t1 USING (b);
|
||||||
|
}
|
||||||
|
} {aa aa}
|
||||||
|
|
||||||
|
finish_test
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
860
test/collate4.test
Normal file
860
test/collate4.test
Normal file
@ -0,0 +1,860 @@
|
|||||||
|
#
|
||||||
|
# The author or author's hereby grant to the public domain a non-exclusive,
|
||||||
|
# fully paid-up, perpetual, license in the software and all related
|
||||||
|
# intellectual property to make, have made, use, have used, reproduce,
|
||||||
|
# prepare derivative works, distribute, perform and display the work.
|
||||||
|
#
|
||||||
|
#*************************************************************************
|
||||||
|
# This file implements regression tests for SQLite library. The
|
||||||
|
# focus of this file is testing indices that use user-defined collation
|
||||||
|
# sequences.
|
||||||
|
#
|
||||||
|
|
||||||
|
set testdir [file dirname $argv0]
|
||||||
|
source $testdir/tester.tcl
|
||||||
|
|
||||||
|
db collate TEXT text_collate
|
||||||
|
proc text_collate {a b} {
|
||||||
|
return [string compare $a $b]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Do an SQL statement. Append the search count to the end of the result.
|
||||||
|
#
|
||||||
|
proc count sql {
|
||||||
|
set ::sqlite_search_count 0
|
||||||
|
return [concat [execsql $sql] $::sqlite_search_count]
|
||||||
|
}
|
||||||
|
|
||||||
|
# This procedure executes the SQL. Then it checks the generated program
|
||||||
|
# for the SQL and appends a "nosort" to the result if the program contains the
|
||||||
|
# SortCallback opcode. If the program does not contain the SortCallback
|
||||||
|
# opcode it appends "sort"
|
||||||
|
#
|
||||||
|
proc cksort {sql} {
|
||||||
|
set data [execsql $sql]
|
||||||
|
set prog [execsql "EXPLAIN $sql"]
|
||||||
|
if {[regexp Sort $prog]} {set x sort} {set x nosort}
|
||||||
|
lappend data $x
|
||||||
|
return $data
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Test cases are organized roughly as follows:
|
||||||
|
#
|
||||||
|
# collate4-1.* ORDER BY.
|
||||||
|
# collate4-2.* WHERE clauses.
|
||||||
|
# collate4-3.* constraints (primary key, unique).
|
||||||
|
# collate4-4.* simple min() or max() queries.
|
||||||
|
# collate4-5.* REINDEX command
|
||||||
|
# collate4-6.* INTEGER PRIMARY KEY indices.
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# These tests - collate4-1.* - check that indices are correctly
|
||||||
|
# selected or not selected to implement ORDER BY clauses when
|
||||||
|
# user defined collation sequences are involved.
|
||||||
|
#
|
||||||
|
# Because these tests also exercise all the different ways indices
|
||||||
|
# can be created, they also serve to verify that indices are correctly
|
||||||
|
# initialised with user-defined collation sequences when they are
|
||||||
|
# created.
|
||||||
|
#
|
||||||
|
# Tests named collate4-1.1.* use indices with a single column. Tests
|
||||||
|
# collate4-1.2.* use indices with two columns.
|
||||||
|
#
|
||||||
|
do_test collate4-1.1.0 {
|
||||||
|
execsql {
|
||||||
|
CREATE TABLE collate4t1(a COLLATE NOCASE, b COLLATE TEXT);
|
||||||
|
INSERT INTO collate4t1 VALUES( 'a', 'a' );
|
||||||
|
INSERT INTO collate4t1 VALUES( 'b', 'b' );
|
||||||
|
INSERT INTO collate4t1 VALUES( NULL, NULL );
|
||||||
|
INSERT INTO collate4t1 VALUES( 'B', 'B' );
|
||||||
|
INSERT INTO collate4t1 VALUES( 'A', 'A' );
|
||||||
|
CREATE INDEX collate4i1 ON collate4t1(a);
|
||||||
|
CREATE INDEX collate4i2 ON collate4t1(b);
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
do_test collate4-1.1.1 {
|
||||||
|
cksort {SELECT a FROM collate4t1 ORDER BY a}
|
||||||
|
} {{} a A b B nosort}
|
||||||
|
do_test collate4-1.1.2 {
|
||||||
|
cksort {SELECT a FROM collate4t1 ORDER BY a COLLATE NOCASE}
|
||||||
|
} {{} a A b B nosort}
|
||||||
|
do_test collate4-1.1.3 {
|
||||||
|
cksort {SELECT a FROM collate4t1 ORDER BY a COLLATE TEXT}
|
||||||
|
} {{} A B a b sort}
|
||||||
|
do_test collate4-1.1.4 {
|
||||||
|
cksort {SELECT b FROM collate4t1 ORDER BY b}
|
||||||
|
} {{} A B a b nosort}
|
||||||
|
do_test collate4-1.1.5 {
|
||||||
|
cksort {SELECT b FROM collate4t1 ORDER BY b COLLATE TEXT}
|
||||||
|
} {{} A B a b nosort}
|
||||||
|
do_test collate4-1.1.6 {
|
||||||
|
cksort {SELECT b FROM collate4t1 ORDER BY b COLLATE NOCASE}
|
||||||
|
} {{} A a B b sort}
|
||||||
|
|
||||||
|
do_test collate4-1.1.7 {
|
||||||
|
execsql {
|
||||||
|
CREATE TABLE collate4t2(
|
||||||
|
a PRIMARY KEY COLLATE NOCASE,
|
||||||
|
b UNIQUE COLLATE TEXT
|
||||||
|
);
|
||||||
|
INSERT INTO collate4t2 VALUES( 'a', 'a' );
|
||||||
|
INSERT INTO collate4t2 VALUES( NULL, NULL );
|
||||||
|
INSERT INTO collate4t2 VALUES( 'B', 'B' );
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
do_test collate4-1.1.8 {
|
||||||
|
cksort {SELECT a FROM collate4t2 ORDER BY a}
|
||||||
|
} {{} a B nosort}
|
||||||
|
do_test collate4-1.1.9 {
|
||||||
|
cksort {SELECT a FROM collate4t2 ORDER BY a COLLATE NOCASE}
|
||||||
|
} {{} a B nosort}
|
||||||
|
do_test collate4-1.1.10 {
|
||||||
|
cksort {SELECT a FROM collate4t2 ORDER BY a COLLATE TEXT}
|
||||||
|
} {{} B a sort}
|
||||||
|
do_test collate4-1.1.11 {
|
||||||
|
cksort {SELECT b FROM collate4t2 ORDER BY b}
|
||||||
|
} {{} B a nosort}
|
||||||
|
do_test collate4-1.1.12 {
|
||||||
|
cksort {SELECT b FROM collate4t2 ORDER BY b COLLATE TEXT}
|
||||||
|
} {{} B a nosort}
|
||||||
|
do_test collate4-1.1.13 {
|
||||||
|
cksort {SELECT b FROM collate4t2 ORDER BY b COLLATE NOCASE}
|
||||||
|
} {{} a B sort}
|
||||||
|
|
||||||
|
do_test collate4-1.1.14 {
|
||||||
|
execsql {
|
||||||
|
CREATE TABLE collate4t3(
|
||||||
|
b COLLATE TEXT,
|
||||||
|
a COLLATE NOCASE,
|
||||||
|
UNIQUE(a), PRIMARY KEY(b)
|
||||||
|
);
|
||||||
|
INSERT INTO collate4t3 VALUES( 'a', 'a' );
|
||||||
|
INSERT INTO collate4t3 VALUES( NULL, NULL );
|
||||||
|
INSERT INTO collate4t3 VALUES( 'B', 'B' );
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
do_test collate4-1.1.15 {
|
||||||
|
cksort {SELECT a FROM collate4t3 ORDER BY a}
|
||||||
|
} {{} a B nosort}
|
||||||
|
do_test collate4-1.1.16 {
|
||||||
|
cksort {SELECT a FROM collate4t3 ORDER BY a COLLATE NOCASE}
|
||||||
|
} {{} a B nosort}
|
||||||
|
do_test collate4-1.1.17 {
|
||||||
|
cksort {SELECT a FROM collate4t3 ORDER BY a COLLATE TEXT}
|
||||||
|
} {{} B a sort}
|
||||||
|
do_test collate4-1.1.18 {
|
||||||
|
cksort {SELECT b FROM collate4t3 ORDER BY b}
|
||||||
|
} {{} B a nosort}
|
||||||
|
do_test collate4-1.1.19 {
|
||||||
|
cksort {SELECT b FROM collate4t3 ORDER BY b COLLATE TEXT}
|
||||||
|
} {{} B a nosort}
|
||||||
|
do_test collate4-1.1.20 {
|
||||||
|
cksort {SELECT b FROM collate4t3 ORDER BY b COLLATE NOCASE}
|
||||||
|
} {{} a B sort}
|
||||||
|
|
||||||
|
do_test collate4-1.1.21 {
|
||||||
|
execsql {
|
||||||
|
CREATE TABLE collate4t4(a COLLATE NOCASE, b COLLATE TEXT);
|
||||||
|
INSERT INTO collate4t4 VALUES( 'a', 'a' );
|
||||||
|
INSERT INTO collate4t4 VALUES( 'b', 'b' );
|
||||||
|
INSERT INTO collate4t4 VALUES( NULL, NULL );
|
||||||
|
INSERT INTO collate4t4 VALUES( 'B', 'B' );
|
||||||
|
INSERT INTO collate4t4 VALUES( 'A', 'A' );
|
||||||
|
CREATE INDEX collate4i3 ON collate4t4(a COLLATE TEXT);
|
||||||
|
CREATE INDEX collate4i4 ON collate4t4(b COLLATE NOCASE);
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
do_test collate4-1.1.22 {
|
||||||
|
cksort {SELECT a FROM collate4t4 ORDER BY a}
|
||||||
|
} {{} A a B b sort}
|
||||||
|
do_test collate4-1.1.23 {
|
||||||
|
cksort {SELECT a FROM collate4t4 ORDER BY a COLLATE NOCASE}
|
||||||
|
} {{} A a B b sort}
|
||||||
|
do_test collate4-1.1.24 {
|
||||||
|
cksort {SELECT a FROM collate4t4 ORDER BY a COLLATE TEXT}
|
||||||
|
} {{} A B a b nosort}
|
||||||
|
do_test collate4-1.1.25 {
|
||||||
|
cksort {SELECT b FROM collate4t4 ORDER BY b}
|
||||||
|
} {{} A B a b sort}
|
||||||
|
do_test collate4-1.1.26 {
|
||||||
|
cksort {SELECT b FROM collate4t4 ORDER BY b COLLATE TEXT}
|
||||||
|
} {{} A B a b sort}
|
||||||
|
do_test collate4-1.1.27 {
|
||||||
|
cksort {SELECT b FROM collate4t4 ORDER BY b COLLATE NOCASE}
|
||||||
|
} {{} a A b B nosort}
|
||||||
|
|
||||||
|
do_test collate4-1.1.30 {
|
||||||
|
execsql {
|
||||||
|
DROP TABLE collate4t1;
|
||||||
|
DROP TABLE collate4t2;
|
||||||
|
DROP TABLE collate4t3;
|
||||||
|
DROP TABLE collate4t4;
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
|
||||||
|
do_test collate4-1.2.0 {
|
||||||
|
execsql {
|
||||||
|
CREATE TABLE collate4t1(a COLLATE NOCASE, b COLLATE TEXT);
|
||||||
|
INSERT INTO collate4t1 VALUES( 'a', 'a' );
|
||||||
|
INSERT INTO collate4t1 VALUES( 'b', 'b' );
|
||||||
|
INSERT INTO collate4t1 VALUES( NULL, NULL );
|
||||||
|
INSERT INTO collate4t1 VALUES( 'B', 'B' );
|
||||||
|
INSERT INTO collate4t1 VALUES( 'A', 'A' );
|
||||||
|
CREATE INDEX collate4i1 ON collate4t1(a, b);
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
do_test collate4-1.2.1 {
|
||||||
|
cksort {SELECT a FROM collate4t1 ORDER BY a}
|
||||||
|
} {{} A a B b nosort}
|
||||||
|
do_test collate4-1.2.2 {
|
||||||
|
cksort {SELECT a FROM collate4t1 ORDER BY a COLLATE nocase}
|
||||||
|
} {{} A a B b nosort}
|
||||||
|
do_test collate4-1.2.3 {
|
||||||
|
cksort {SELECT a FROM collate4t1 ORDER BY a COLLATE text}
|
||||||
|
} {{} A B a b sort}
|
||||||
|
do_test collate4-1.2.4 {
|
||||||
|
cksort {SELECT a FROM collate4t1 ORDER BY a, b}
|
||||||
|
} {{} A a B b nosort}
|
||||||
|
do_test collate4-1.2.5 {
|
||||||
|
cksort {SELECT a FROM collate4t1 ORDER BY a, b COLLATE nocase}
|
||||||
|
} {{} A a B b sort}
|
||||||
|
do_test collate4-1.2.6 {
|
||||||
|
cksort {SELECT a FROM collate4t1 ORDER BY a, b COLLATE text}
|
||||||
|
} {{} A a B b nosort}
|
||||||
|
|
||||||
|
do_test collate4-1.2.7 {
|
||||||
|
execsql {
|
||||||
|
CREATE TABLE collate4t2(
|
||||||
|
a COLLATE NOCASE,
|
||||||
|
b COLLATE TEXT,
|
||||||
|
PRIMARY KEY(a, b)
|
||||||
|
);
|
||||||
|
INSERT INTO collate4t2 VALUES( 'a', 'a' );
|
||||||
|
INSERT INTO collate4t2 VALUES( NULL, NULL );
|
||||||
|
INSERT INTO collate4t2 VALUES( 'B', 'B' );
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
do_test collate4-1.2.8 {
|
||||||
|
cksort {SELECT a FROM collate4t2 ORDER BY a}
|
||||||
|
} {{} a B nosort}
|
||||||
|
do_test collate4-1.2.9 {
|
||||||
|
cksort {SELECT a FROM collate4t2 ORDER BY a COLLATE nocase}
|
||||||
|
} {{} a B nosort}
|
||||||
|
do_test collate4-1.2.10 {
|
||||||
|
cksort {SELECT a FROM collate4t2 ORDER BY a COLLATE text}
|
||||||
|
} {{} B a sort}
|
||||||
|
do_test collate4-1.2.11 {
|
||||||
|
cksort {SELECT a FROM collate4t2 ORDER BY a, b}
|
||||||
|
} {{} a B nosort}
|
||||||
|
do_test collate4-1.2.12 {
|
||||||
|
cksort {SELECT a FROM collate4t2 ORDER BY a, b COLLATE nocase}
|
||||||
|
} {{} a B sort}
|
||||||
|
do_test collate4-1.2.13 {
|
||||||
|
cksort {SELECT a FROM collate4t2 ORDER BY a, b COLLATE text}
|
||||||
|
} {{} a B nosort}
|
||||||
|
|
||||||
|
do_test collate4-1.2.14 {
|
||||||
|
execsql {
|
||||||
|
CREATE TABLE collate4t3(a COLLATE NOCASE, b COLLATE TEXT);
|
||||||
|
INSERT INTO collate4t3 VALUES( 'a', 'a' );
|
||||||
|
INSERT INTO collate4t3 VALUES( 'b', 'b' );
|
||||||
|
INSERT INTO collate4t3 VALUES( NULL, NULL );
|
||||||
|
INSERT INTO collate4t3 VALUES( 'B', 'B' );
|
||||||
|
INSERT INTO collate4t3 VALUES( 'A', 'A' );
|
||||||
|
CREATE INDEX collate4i2 ON collate4t3(a COLLATE TEXT, b COLLATE NOCASE);
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
do_test collate4-1.2.15 {
|
||||||
|
cksort {SELECT a FROM collate4t3 ORDER BY a}
|
||||||
|
} {{} A a B b sort}
|
||||||
|
do_test collate4-1.2.16 {
|
||||||
|
cksort {SELECT a FROM collate4t3 ORDER BY a COLLATE nocase}
|
||||||
|
} {{} A a B b sort}
|
||||||
|
do_test collate4-1.2.17 {
|
||||||
|
cksort {SELECT a FROM collate4t3 ORDER BY a COLLATE text}
|
||||||
|
} {{} A B a b nosort}
|
||||||
|
do_test collate4-1.2.18 {
|
||||||
|
cksort {SELECT a FROM collate4t3 ORDER BY a COLLATE text, b}
|
||||||
|
} {{} A B a b sort}
|
||||||
|
do_test collate4-1.2.19 {
|
||||||
|
cksort {SELECT a FROM collate4t3 ORDER BY a COLLATE text, b COLLATE nocase}
|
||||||
|
} {{} A B a b nosort}
|
||||||
|
do_test collate4-1.2.20 {
|
||||||
|
cksort {SELECT a FROM collate4t3 ORDER BY a COLLATE text, b COLLATE text}
|
||||||
|
} {{} A B a b sort}
|
||||||
|
do_test collate4-1.2.21 {
|
||||||
|
cksort {SELECT a FROM collate4t3 ORDER BY a COLLATE text DESC}
|
||||||
|
} {b a B A {} nosort}
|
||||||
|
do_test collate4-1.2.22 {
|
||||||
|
cksort {SELECT a FROM collate4t3 ORDER BY a COLLATE text DESC, b}
|
||||||
|
} {b a B A {} sort}
|
||||||
|
do_test collate4-1.2.23 {
|
||||||
|
cksort {SELECT a FROM collate4t3
|
||||||
|
ORDER BY a COLLATE text DESC, b COLLATE nocase}
|
||||||
|
} {b a B A {} sort}
|
||||||
|
do_test collate4-1.2.24 {
|
||||||
|
cksort {SELECT a FROM collate4t3
|
||||||
|
ORDER BY a COLLATE text DESC, b COLLATE nocase DESC}
|
||||||
|
} {b a B A {} nosort}
|
||||||
|
|
||||||
|
do_test collate4-1.2.25 {
|
||||||
|
execsql {
|
||||||
|
DROP TABLE collate4t1;
|
||||||
|
DROP TABLE collate4t2;
|
||||||
|
DROP TABLE collate4t3;
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
|
||||||
|
#
|
||||||
|
# These tests - collate4-2.* - check that indices are correctly
|
||||||
|
# selected or not selected to implement WHERE clauses when user
|
||||||
|
# defined collation sequences are involved.
|
||||||
|
#
|
||||||
|
# Indices may optimise WHERE clauses using <, >, <=, >=, = or IN
|
||||||
|
# operators.
|
||||||
|
#
|
||||||
|
do_test collate4-2.1.0 {
|
||||||
|
execsql {
|
||||||
|
CREATE TABLE collate4t1(a COLLATE NOCASE);
|
||||||
|
CREATE TABLE collate4t2(b COLLATE TEXT);
|
||||||
|
|
||||||
|
INSERT INTO collate4t1 VALUES('a');
|
||||||
|
INSERT INTO collate4t1 VALUES('A');
|
||||||
|
INSERT INTO collate4t1 VALUES('b');
|
||||||
|
INSERT INTO collate4t1 VALUES('B');
|
||||||
|
INSERT INTO collate4t1 VALUES('c');
|
||||||
|
INSERT INTO collate4t1 VALUES('C');
|
||||||
|
INSERT INTO collate4t1 VALUES('d');
|
||||||
|
INSERT INTO collate4t1 VALUES('D');
|
||||||
|
INSERT INTO collate4t1 VALUES('e');
|
||||||
|
INSERT INTO collate4t1 VALUES('D');
|
||||||
|
|
||||||
|
INSERT INTO collate4t2 VALUES('A');
|
||||||
|
INSERT INTO collate4t2 VALUES('Z');
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
do_test collate4-2.1.1 {
|
||||||
|
count {
|
||||||
|
SELECT * FROM collate4t2, collate4t1 WHERE a = b;
|
||||||
|
}
|
||||||
|
} {A a A A 19}
|
||||||
|
do_test collate4-2.1.2 {
|
||||||
|
execsql {
|
||||||
|
CREATE INDEX collate4i1 ON collate4t1(a);
|
||||||
|
}
|
||||||
|
count {
|
||||||
|
SELECT * FROM collate4t2, collate4t1 WHERE a = b;
|
||||||
|
}
|
||||||
|
} {A a A A 7}
|
||||||
|
do_test collate4-2.1.3 {
|
||||||
|
count {
|
||||||
|
SELECT * FROM collate4t2, collate4t1 WHERE b = a;
|
||||||
|
}
|
||||||
|
} {A A 19}
|
||||||
|
do_test collate4-2.1.4 {
|
||||||
|
execsql {
|
||||||
|
DROP INDEX collate4i1;
|
||||||
|
CREATE INDEX collate4i1 ON collate4t1(a COLLATE TEXT);
|
||||||
|
}
|
||||||
|
count {
|
||||||
|
SELECT * FROM collate4t2, collate4t1 WHERE a = b;
|
||||||
|
}
|
||||||
|
} {A a A A 19}
|
||||||
|
do_test collate4-2.1.5 {
|
||||||
|
count {
|
||||||
|
SELECT * FROM collate4t2, collate4t1 WHERE b = a;
|
||||||
|
}
|
||||||
|
} {A A 5}
|
||||||
|
do_test collate4-2.1.6 {
|
||||||
|
count {
|
||||||
|
SELECT a FROM collate4t1 WHERE a IN (SELECT * FROM collate4t2);
|
||||||
|
}
|
||||||
|
} {a A 10}
|
||||||
|
do_test collate4-2.1.7 {
|
||||||
|
execsql {
|
||||||
|
DROP INDEX collate4i1;
|
||||||
|
CREATE INDEX collate4i1 ON collate4t1(a);
|
||||||
|
}
|
||||||
|
count {
|
||||||
|
SELECT a FROM collate4t1 WHERE a IN (SELECT * FROM collate4t2);
|
||||||
|
}
|
||||||
|
} {a A 8}
|
||||||
|
do_test collate4-2.1.8 {
|
||||||
|
count {
|
||||||
|
SELECT a FROM collate4t1 WHERE a IN ('z', 'a');
|
||||||
|
}
|
||||||
|
} {a A 7}
|
||||||
|
do_test collate4-2.1.9 {
|
||||||
|
execsql {
|
||||||
|
DROP INDEX collate4i1;
|
||||||
|
CREATE INDEX collate4i1 ON collate4t1(a COLLATE TEXT);
|
||||||
|
}
|
||||||
|
count {
|
||||||
|
SELECT a FROM collate4t1 WHERE a IN ('z', 'a');
|
||||||
|
}
|
||||||
|
} {a A 9}
|
||||||
|
do_test collate4-2.1.10 {
|
||||||
|
execsql {
|
||||||
|
DROP TABLE collate4t1;
|
||||||
|
DROP TABLE collate4t2;
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
|
||||||
|
do_test collate4-2.2.0 {
|
||||||
|
execsql {
|
||||||
|
CREATE TABLE collate4t1(a COLLATE nocase, b COLLATE text, c);
|
||||||
|
CREATE TABLE collate4t2(a COLLATE nocase, b COLLATE text, c COLLATE TEXT);
|
||||||
|
|
||||||
|
INSERT INTO collate4t1 VALUES('0', '0', '0');
|
||||||
|
INSERT INTO collate4t1 VALUES('0', '0', '1');
|
||||||
|
INSERT INTO collate4t1 VALUES('0', '1', '0');
|
||||||
|
INSERT INTO collate4t1 VALUES('0', '1', '1');
|
||||||
|
INSERT INTO collate4t1 VALUES('1', '0', '0');
|
||||||
|
INSERT INTO collate4t1 VALUES('1', '0', '1');
|
||||||
|
INSERT INTO collate4t1 VALUES('1', '1', '0');
|
||||||
|
INSERT INTO collate4t1 VALUES('1', '1', '1');
|
||||||
|
insert into collate4t2 SELECT * FROM collate4t1;
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
do_test collate4-2.2.1 {
|
||||||
|
count {
|
||||||
|
SELECT * FROM collate4t2 NATURAL JOIN collate4t1;
|
||||||
|
}
|
||||||
|
} {0 0 0 0 0 1 0 1 0 0 1 1 1 0 0 1 0 1 1 1 0 1 1 1 63}
|
||||||
|
do_test collate4-2.2.1 {
|
||||||
|
execsql {
|
||||||
|
CREATE INDEX collate4i1 ON collate4t1(a, b, c);
|
||||||
|
}
|
||||||
|
count {
|
||||||
|
SELECT * FROM collate4t2 NATURAL JOIN collate4t1;
|
||||||
|
}
|
||||||
|
} {0 0 0 0 0 1 0 1 0 0 1 1 1 0 0 1 0 1 1 1 0 1 1 1 45}
|
||||||
|
do_test collate4-2.2.2 {
|
||||||
|
execsql {
|
||||||
|
DROP INDEX collate4i1;
|
||||||
|
CREATE INDEX collate4i1 ON collate4t1(a, b, c COLLATE text);
|
||||||
|
}
|
||||||
|
count {
|
||||||
|
SELECT * FROM collate4t2 NATURAL JOIN collate4t1;
|
||||||
|
}
|
||||||
|
} {0 0 0 0 0 1 0 1 0 0 1 1 1 0 0 1 0 1 1 1 0 1 1 1 22}
|
||||||
|
|
||||||
|
do_test collate4-2.2.10 {
|
||||||
|
execsql {
|
||||||
|
DROP TABLE collate4t1;
|
||||||
|
DROP TABLE collate4t2;
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
|
||||||
|
#
|
||||||
|
# These tests - collate4-3.* verify that indices that implement
|
||||||
|
# UNIQUE and PRIMARY KEY constraints operate correctly with user
|
||||||
|
# defined collation sequences.
|
||||||
|
#
|
||||||
|
do_test collate4-3.0 {
|
||||||
|
execsql {
|
||||||
|
CREATE TABLE collate4t1(a PRIMARY KEY COLLATE NOCASE);
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
do_test collate4-3.1 {
|
||||||
|
catchsql {
|
||||||
|
INSERT INTO collate4t1 VALUES('abc');
|
||||||
|
INSERT INTO collate4t1 VALUES('ABC');
|
||||||
|
}
|
||||||
|
} {1 {column a is not unique}}
|
||||||
|
do_test collate4-3.2 {
|
||||||
|
execsql {
|
||||||
|
SELECT * FROM collate4t1;
|
||||||
|
}
|
||||||
|
} {abc}
|
||||||
|
do_test collate4-3.3 {
|
||||||
|
catchsql {
|
||||||
|
INSERT INTO collate4t1 SELECT upper(a) FROM collate4t1;
|
||||||
|
}
|
||||||
|
} {1 {column a is not unique}}
|
||||||
|
do_test collate4-3.4 {
|
||||||
|
catchsql {
|
||||||
|
INSERT INTO collate4t1 VALUES(1);
|
||||||
|
UPDATE collate4t1 SET a = 'abc';
|
||||||
|
}
|
||||||
|
} {1 {column a is not unique}}
|
||||||
|
do_test collate4-3.5 {
|
||||||
|
execsql {
|
||||||
|
DROP TABLE collate4t1;
|
||||||
|
CREATE TABLE collate4t1(a COLLATE NOCASE UNIQUE);
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
do_test collate4-3.6 {
|
||||||
|
catchsql {
|
||||||
|
INSERT INTO collate4t1 VALUES('abc');
|
||||||
|
INSERT INTO collate4t1 VALUES('ABC');
|
||||||
|
}
|
||||||
|
} {1 {column a is not unique}}
|
||||||
|
do_test collate4-3.7 {
|
||||||
|
execsql {
|
||||||
|
SELECT * FROM collate4t1;
|
||||||
|
}
|
||||||
|
} {abc}
|
||||||
|
do_test collate4-3.8 {
|
||||||
|
catchsql {
|
||||||
|
INSERT INTO collate4t1 SELECT upper(a) FROM collate4t1;
|
||||||
|
}
|
||||||
|
} {1 {column a is not unique}}
|
||||||
|
do_test collate4-3.9 {
|
||||||
|
catchsql {
|
||||||
|
INSERT INTO collate4t1 VALUES(1);
|
||||||
|
UPDATE collate4t1 SET a = 'abc';
|
||||||
|
}
|
||||||
|
} {1 {column a is not unique}}
|
||||||
|
do_test collate4-3.10 {
|
||||||
|
execsql {
|
||||||
|
DROP TABLE collate4t1;
|
||||||
|
CREATE TABLE collate4t1(a);
|
||||||
|
CREATE UNIQUE INDEX collate4i1 ON collate4t1(a COLLATE NOCASE);
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
do_test collate4-3.11 {
|
||||||
|
catchsql {
|
||||||
|
INSERT INTO collate4t1 VALUES('abc');
|
||||||
|
INSERT INTO collate4t1 VALUES('ABC');
|
||||||
|
}
|
||||||
|
} {1 {column a is not unique}}
|
||||||
|
do_test collate4-3.12 {
|
||||||
|
execsql {
|
||||||
|
SELECT * FROM collate4t1;
|
||||||
|
}
|
||||||
|
} {abc}
|
||||||
|
do_test collate4-3.13 {
|
||||||
|
catchsql {
|
||||||
|
INSERT INTO collate4t1 SELECT upper(a) FROM collate4t1;
|
||||||
|
}
|
||||||
|
} {1 {column a is not unique}}
|
||||||
|
do_test collate4-3.14 {
|
||||||
|
catchsql {
|
||||||
|
INSERT INTO collate4t1 VALUES(1);
|
||||||
|
UPDATE collate4t1 SET a = 'abc';
|
||||||
|
}
|
||||||
|
} {1 {column a is not unique}}
|
||||||
|
|
||||||
|
do_test collate4-3.15 {
|
||||||
|
execsql {
|
||||||
|
DROP TABLE collate4t1;
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
|
||||||
|
#
|
||||||
|
# These tests - collate4-4.* check that min() and max() only ever
|
||||||
|
# use indices constructed with built-in collation type numeric.
|
||||||
|
#
|
||||||
|
# CHANGED: min() and max() now use the collation type. If there
|
||||||
|
# is an indice that can be used, it is used.
|
||||||
|
#
|
||||||
|
|
||||||
|
# FIX ME: min() and max() are currently broken.
|
||||||
|
if 0 {
|
||||||
|
|
||||||
|
do_test collate4-4.0 {
|
||||||
|
execsql {
|
||||||
|
CREATE TABLE collate4t1(a COLLATE TEXT);
|
||||||
|
INSERT INTO collate4t1 VALUES(2);
|
||||||
|
INSERT INTO collate4t1 VALUES(10);
|
||||||
|
INSERT INTO collate4t1 VALUES(20);
|
||||||
|
INSERT INTO collate4t1 VALUES(104);
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
do_test collate4-4.1 {
|
||||||
|
count {
|
||||||
|
SELECT max(a) FROM collate4t1
|
||||||
|
}
|
||||||
|
} {20 3}
|
||||||
|
do_test collate4-4.2 {
|
||||||
|
count {
|
||||||
|
SELECT min(a) FROM collate4t1
|
||||||
|
}
|
||||||
|
} {10 3}
|
||||||
|
do_test collate4-4.3 {
|
||||||
|
# Test that the index with collation type TEXT is used.
|
||||||
|
execsql {
|
||||||
|
CREATE INDEX collate4i1 ON collate4t1(a);
|
||||||
|
}
|
||||||
|
count {
|
||||||
|
SELECT min(a) FROM collate4t1;
|
||||||
|
}
|
||||||
|
} {10 1}
|
||||||
|
do_test collate4-4.4 {
|
||||||
|
count {
|
||||||
|
SELECT max(a) FROM collate4t1;
|
||||||
|
}
|
||||||
|
} {20 1}
|
||||||
|
do_test collate4-4.5 {
|
||||||
|
# Test that the index with collation type NUMERIC is not used.
|
||||||
|
execsql {
|
||||||
|
DROP INDEX collate4i1;
|
||||||
|
CREATE INDEX collate4i1 ON collate4t1(a COLLATE NUMERIC);
|
||||||
|
}
|
||||||
|
count {
|
||||||
|
SELECT min(a) FROM collate4t1;
|
||||||
|
}
|
||||||
|
} {10 3}
|
||||||
|
do_test collate4-4.6 {
|
||||||
|
count {
|
||||||
|
SELECT max(a) FROM collate4t1;
|
||||||
|
}
|
||||||
|
} {20 3}
|
||||||
|
do_test collate4-4.7 {
|
||||||
|
execsql {
|
||||||
|
DROP TABLE collate4t1;
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
|
||||||
|
# Also test the scalar min() and max() functions.
|
||||||
|
#
|
||||||
|
do_test collate4-4.8 {
|
||||||
|
execsql {
|
||||||
|
CREATE TABLE collate4t1(a NUMERIC, b TEXT,
|
||||||
|
c COLLATE TEXT, d COLLATE NUMERIC);
|
||||||
|
INSERT INTO collate4t1 VALUES(11, 101, 1001, 10001);
|
||||||
|
INSERT INTO collate4t1 VALUES(20002, 2002, 202, 22);
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
do_test collate4-4.9 {
|
||||||
|
execsql {
|
||||||
|
SELECT max(a, b, c) FROM collate4t1;
|
||||||
|
}
|
||||||
|
} {11 202}
|
||||||
|
do_test collate4-4.10 {
|
||||||
|
execsql {
|
||||||
|
SELECT max(c, b, a) FROM collate4t1;
|
||||||
|
}
|
||||||
|
} {11 202}
|
||||||
|
do_test collate4-4.11 {
|
||||||
|
execsql {
|
||||||
|
SELECT max(a, b) FROM collate4t1;
|
||||||
|
}
|
||||||
|
} {101 20002}
|
||||||
|
do_test collate4-4.12 {
|
||||||
|
execsql {
|
||||||
|
SELECT max(b, a) FROM collate4t1;
|
||||||
|
}
|
||||||
|
} {101 20002}
|
||||||
|
do_test collate4-4.13 {
|
||||||
|
execsql {
|
||||||
|
SELECT max(b, a) FROM collate4t1;
|
||||||
|
}
|
||||||
|
} {101 20002}
|
||||||
|
do_test collate4-4.14 {
|
||||||
|
execsql {
|
||||||
|
SELECT max(b, '11') FROM collate4t1;
|
||||||
|
}
|
||||||
|
} {11 2002}
|
||||||
|
do_test collate4-4.15 {
|
||||||
|
execsql {
|
||||||
|
SELECT max('11', b) FROM collate4t1;
|
||||||
|
}
|
||||||
|
} {11 2002}
|
||||||
|
do_test collate4-4.16 {
|
||||||
|
execsql {
|
||||||
|
SELECT max(11, b) FROM collate4t1;
|
||||||
|
}
|
||||||
|
} {101 2002}
|
||||||
|
do_test collate4-4.17 {
|
||||||
|
execsql {
|
||||||
|
SELECT max(b, 11) FROM collate4t1;
|
||||||
|
}
|
||||||
|
} {101 2002}
|
||||||
|
do_test collate4-4.18 {
|
||||||
|
execsql {
|
||||||
|
SELECT max(c, d) FROM collate4t1;
|
||||||
|
}
|
||||||
|
} {1001 22}
|
||||||
|
do_test collate4-4.19 {
|
||||||
|
execsql {
|
||||||
|
SELECT max(d, c) FROM collate4t1;
|
||||||
|
}
|
||||||
|
} {10001 202}
|
||||||
|
do_test collate4-4.20 {
|
||||||
|
execsql {
|
||||||
|
DROP TABLE collate4t1;
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# These tests - collate4-5.* - test the REINDEX command.
|
||||||
|
#
|
||||||
|
# FIX ME: Find out if version 3 needs REINDEX.
|
||||||
|
if 0 {
|
||||||
|
|
||||||
|
proc install_normal_collate {} {
|
||||||
|
db collate collate1 "string compare"
|
||||||
|
}
|
||||||
|
proc inverse_collate {l r} {
|
||||||
|
expr -1 * [string compare $l $r]
|
||||||
|
}
|
||||||
|
proc install_inverse_collate {} {
|
||||||
|
db collate collate1 inverse_collate
|
||||||
|
}
|
||||||
|
install_normal_collate
|
||||||
|
|
||||||
|
do_test collate4-5.0 {
|
||||||
|
execsql {
|
||||||
|
CREATE TABLE collate4t1(a COLLATE collate1);
|
||||||
|
INSERT INTO collate4t1 VALUES('A');
|
||||||
|
INSERT INTO collate4t1 VALUES(NULL);
|
||||||
|
INSERT INTO collate4t1 VALUES('B');
|
||||||
|
CREATE INDEX collate4i1 ON collate4t1(a);
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
do_test collate4-5.1 {
|
||||||
|
cksort {
|
||||||
|
SELECT * FROM collate4t1 ORDER BY 1;
|
||||||
|
}
|
||||||
|
} {{} A B nosort}
|
||||||
|
do_test collate4-5.2 {
|
||||||
|
install_inverse_collate
|
||||||
|
cksort {
|
||||||
|
SELECT * FROM collate4t1 ORDER BY 1;
|
||||||
|
}
|
||||||
|
} {{} A B nosort} ;# This is incorrect - because we need to REINDEX
|
||||||
|
do_test collate4-5.3 {
|
||||||
|
install_inverse_collate
|
||||||
|
cksort {
|
||||||
|
REINDEX collate4t1;
|
||||||
|
SELECT * FROM collate4t1 ORDER BY 1;
|
||||||
|
}
|
||||||
|
} {{} B A nosort}
|
||||||
|
do_test collate4-5.4 {
|
||||||
|
install_normal_collate
|
||||||
|
cksort {
|
||||||
|
REINDEX;
|
||||||
|
SELECT * FROM collate4t1 ORDER BY 1;
|
||||||
|
}
|
||||||
|
} {{} A B nosort}
|
||||||
|
do_test collate4-5.5 {
|
||||||
|
install_inverse_collate
|
||||||
|
cksort {
|
||||||
|
REINDEX main.collate4t1;
|
||||||
|
SELECT * FROM collate4t1 ORDER BY 1;
|
||||||
|
}
|
||||||
|
} {{} B A nosort}
|
||||||
|
do_test collate4-5.6 {
|
||||||
|
catchsql {
|
||||||
|
REINDEX garbage;
|
||||||
|
}
|
||||||
|
} {1 {no such table: garbage}}
|
||||||
|
do_test collate4-5.7 {
|
||||||
|
execsql {
|
||||||
|
DROP TABLE collate4t1;
|
||||||
|
CREATE TEMP TABLE collate4t1(a COLLATE collate1, b COLLATE collate1);
|
||||||
|
CREATE INDEX collatei1 ON collate4t1(a);
|
||||||
|
CREATE INDEX collatei2 ON collate4t1(b);
|
||||||
|
INSERT INTO collate4t1 VALUES(1, 1);
|
||||||
|
INSERT INTO collate4t1 VALUES(NULL, NULL);
|
||||||
|
INSERT INTO collate4t1 VALUES(2, 2);
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
do_test collate4-5.8 {
|
||||||
|
cksort {
|
||||||
|
SELECT * FROM collate4t1 ORDER BY 1
|
||||||
|
}
|
||||||
|
} {{} {} 2 2 1 1 nosort}
|
||||||
|
do_test collate4-5.9 {
|
||||||
|
install_normal_collate
|
||||||
|
cksort {
|
||||||
|
REINDEX;
|
||||||
|
SELECT * FROM collate4t1 order by 2;
|
||||||
|
}
|
||||||
|
} {{} {} 1 1 2 2 nosort}
|
||||||
|
do_test collate4-5.10 {
|
||||||
|
install_inverse_collate
|
||||||
|
cksort {
|
||||||
|
REINDEX collate4t1;
|
||||||
|
SELECT * FROM collate4t1 order by 1;
|
||||||
|
}
|
||||||
|
} {{} {} 2 2 1 1 nosort}
|
||||||
|
do_test collate4-5.11 {
|
||||||
|
install_normal_collate
|
||||||
|
cksort {
|
||||||
|
REINDEX temp.collate4t1;
|
||||||
|
SELECT * FROM collate4t1 order by 2;
|
||||||
|
}
|
||||||
|
} {{} {} 1 1 2 2 nosort}
|
||||||
|
|
||||||
|
# This checks that if a REINDEX operation produces a conflict an error
|
||||||
|
# is raised and the checkpoint rolled back.
|
||||||
|
do_test collate4-5.12 {
|
||||||
|
execsql {
|
||||||
|
BEGIN;
|
||||||
|
CREATE UNIQUE INDEX collate4i3 ON collate4t1(a);
|
||||||
|
INSERT INTO collate4t1 VALUES(3, 3);
|
||||||
|
}
|
||||||
|
db collate collate1 "expr 0 ;"
|
||||||
|
catchsql {
|
||||||
|
REINDEX;
|
||||||
|
}
|
||||||
|
} {1 {indexed columns are not unique}}
|
||||||
|
do_test collate4-5.13 {
|
||||||
|
execsql {
|
||||||
|
COMMIT;
|
||||||
|
SELECT * FROM collate4t1;
|
||||||
|
}
|
||||||
|
} {1 1 {} {} 2 2 3 3}
|
||||||
|
|
||||||
|
# Do an EXPLAIN REINDEX, just in case it leaks memory or something.
|
||||||
|
do_test collate4-5.14 {
|
||||||
|
execsql {
|
||||||
|
EXPLAIN REINDEX;
|
||||||
|
}
|
||||||
|
expr 0
|
||||||
|
} {0}
|
||||||
|
do_test collate4-5.15 {
|
||||||
|
execsql {
|
||||||
|
EXPLAIN REINDEX collate4t1;
|
||||||
|
}
|
||||||
|
expr 0
|
||||||
|
} {0}
|
||||||
|
|
||||||
|
do_test collate4-5.16 {
|
||||||
|
execsql {
|
||||||
|
DROP TABLE collate4t1;
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# These tests - collate4.6.* - ensure that implict INTEGER PRIMARY KEY
|
||||||
|
# indices do not confuse collation sequences.
|
||||||
|
#
|
||||||
|
# These indices are never used for sorting in SQLite. And you can't
|
||||||
|
# create another index on an INTEGER PRIMARY KEY column, so we don't have
|
||||||
|
# to test that.
|
||||||
|
#
|
||||||
|
do_test collate4-6.0 {
|
||||||
|
execsql {
|
||||||
|
CREATE TABLE collate4t1(a INTEGER PRIMARY KEY);
|
||||||
|
INSERT INTO collate4t1 VALUES(101);
|
||||||
|
INSERT INTO collate4t1 VALUES(10);
|
||||||
|
INSERT INTO collate4t1 VALUES(15);
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
do_test collate4-6.1 {
|
||||||
|
cksort {
|
||||||
|
SELECT * FROM collate4t1 ORDER BY 1;
|
||||||
|
}
|
||||||
|
} {10 15 101 sort}
|
||||||
|
do_test collate4-6.2 {
|
||||||
|
cksort {
|
||||||
|
SELECT * FROM collate4t1 ORDER BY oid;
|
||||||
|
}
|
||||||
|
} {10 15 101 sort}
|
||||||
|
do_test collate4-6.3 {
|
||||||
|
cksort {
|
||||||
|
SELECT * FROM collate4t1 ORDER BY oid||'' COLLATE TEXT;
|
||||||
|
}
|
||||||
|
} {10 101 15 sort}
|
||||||
|
|
||||||
|
finish_test
|
@ -1,4 +1,4 @@
|
|||||||
# 2001 September 15
|
# 2001 September 15.
|
||||||
#
|
#
|
||||||
# The author disclaims copyright to this source code. In place of
|
# The author disclaims copyright to this source code. In place of
|
||||||
# a legal notice, here is a blessing:
|
# a legal notice, here is a blessing:
|
||||||
@ -13,11 +13,24 @@
|
|||||||
# This file implements tests for miscellanous features that were
|
# This file implements tests for miscellanous features that were
|
||||||
# left out of other test files.
|
# left out of other test files.
|
||||||
#
|
#
|
||||||
# $Id: misc1.test,v 1.25 2004/05/31 08:26:49 danielk1977 Exp $
|
# $Id: misc1.test,v 1.26 2004/06/09 09:55:20 danielk1977 Exp $
|
||||||
|
|
||||||
set testdir [file dirname $argv0]
|
set testdir [file dirname $argv0]
|
||||||
source $testdir/tester.tcl
|
source $testdir/tester.tcl
|
||||||
|
|
||||||
|
# Mimic the SQLite 2 collation type NUMERIC.
|
||||||
|
db collate numeric numeric_collate
|
||||||
|
proc numeric_collate {lhs rhs} {
|
||||||
|
if {$lhs == $rhs} {return 0}
|
||||||
|
return [expr ($lhs>$rhs)?1:-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Mimic the SQLite 2 collation type TEXT.
|
||||||
|
db collate text text_collate
|
||||||
|
proc numeric_collate {lhs rhs} {
|
||||||
|
return [string compare $lhs $rhs]
|
||||||
|
}
|
||||||
|
|
||||||
# Test the creation and use of tables that have a large number
|
# Test the creation and use of tables that have a large number
|
||||||
# of columns.
|
# of columns.
|
||||||
#
|
#
|
||||||
@ -381,11 +394,14 @@ do_test misc1-12.9 {
|
|||||||
# identifiers can be used as a collating sequence. Collation is by text
|
# identifiers can be used as a collating sequence. Collation is by text
|
||||||
# if the identifier contains "text", "blob", or "clob" and is numeric
|
# if the identifier contains "text", "blob", or "clob" and is numeric
|
||||||
# otherwise.
|
# otherwise.
|
||||||
do_test misc1-12.10 {
|
#
|
||||||
catchsql {
|
# Update: In v3, it is an error again.
|
||||||
SELECT * FROM t6 ORDER BY a COLLATE unknown;
|
#
|
||||||
}
|
#do_test misc1-12.10 {
|
||||||
} {0 {0 0.0 y 0}}
|
# catchsql {
|
||||||
|
# SELECT * FROM t6 ORDER BY a COLLATE unknown;
|
||||||
|
# }
|
||||||
|
#} {0 {0 0.0 y 0}}
|
||||||
do_test misc1-12.11 {
|
do_test misc1-12.11 {
|
||||||
execsql {
|
execsql {
|
||||||
CREATE TABLE t8(x TEXT COLLATE numeric, y INTEGER COLLATE text, z);
|
CREATE TABLE t8(x TEXT COLLATE numeric, y INTEGER COLLATE text, z);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# 2001 September 15
|
# 2001 September 15.
|
||||||
#
|
#
|
||||||
# The author disclaims copyright to this source code. In place of
|
# The author disclaims copyright to this source code. In place of
|
||||||
# a legal notice, here is a blessing:
|
# a legal notice, here is a blessing:
|
||||||
@ -11,7 +11,7 @@
|
|||||||
# This file implements regression tests for SQLite library. The
|
# This file implements regression tests for SQLite library. The
|
||||||
# focus of this file is testing the CREATE TABLE statement.
|
# focus of this file is testing the CREATE TABLE statement.
|
||||||
#
|
#
|
||||||
# $Id: sort.test,v 1.12 2004/05/27 17:22:56 drh Exp $
|
# $Id: sort.test,v 1.13 2004/06/09 09:55:20 danielk1977 Exp $
|
||||||
|
|
||||||
set testdir [file dirname $argv0]
|
set testdir [file dirname $argv0]
|
||||||
source $testdir/tester.tcl
|
source $testdir/tester.tcl
|
||||||
@ -323,26 +323,26 @@ do_test sort-7.8 {
|
|||||||
# SELECT b FROM t4 UNION SELECT b FROM v4 ORDER BY 1 COLLATE integer;
|
# SELECT b FROM t4 UNION SELECT b FROM v4 ORDER BY 1 COLLATE integer;
|
||||||
# }
|
# }
|
||||||
#} {1 2 11 12}
|
#} {1 2 11 12}
|
||||||
do_test sort-7.11 {
|
#do_test sort-7.11 {
|
||||||
execsql {
|
# execsql {
|
||||||
SELECT b FROM t4 UNION SELECT b FROM v4 ORDER BY 1 COLLATE text;
|
# SELECT b FROM t4 UNION SELECT b FROM v4 ORDER BY 1 COLLATE text;
|
||||||
}
|
# }
|
||||||
} {1 11 12 2}
|
#} {1 11 12 2}
|
||||||
do_test sort-7.12 {
|
#do_test sort-7.12 {
|
||||||
execsql {
|
# execsql {
|
||||||
SELECT b FROM t4 UNION SELECT b FROM v4 ORDER BY 1 COLLATE blob;
|
# SELECT b FROM t4 UNION SELECT b FROM v4 ORDER BY 1 COLLATE blob;
|
||||||
}
|
# }
|
||||||
} {1 11 12 2}
|
#} {1 11 12 2}
|
||||||
do_test sort-7.13 {
|
#do_test sort-7.13 {
|
||||||
execsql {
|
# execsql {
|
||||||
SELECT b FROM t4 UNION SELECT b FROM v4 ORDER BY 1 COLLATE clob;
|
# SELECT b FROM t4 UNION SELECT b FROM v4 ORDER BY 1 COLLATE clob;
|
||||||
}
|
# }
|
||||||
} {1 11 12 2}
|
#} {1 11 12 2}
|
||||||
do_test sort-7.14 {
|
#do_test sort-7.14 {
|
||||||
execsql {
|
# execsql {
|
||||||
SELECT b FROM t4 UNION SELECT b FROM v4 ORDER BY 1 COLLATE varchar;
|
# SELECT b FROM t4 UNION SELECT b FROM v4 ORDER BY 1 COLLATE varchar;
|
||||||
}
|
# }
|
||||||
} {1 11 12 2}
|
#} {1 11 12 2}
|
||||||
|
|
||||||
# Ticket #297
|
# Ticket #297
|
||||||
#
|
#
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
# interface is pretty well tested. This file contains some addition
|
# interface is pretty well tested. This file contains some addition
|
||||||
# tests for fringe issues that the main test suite does not cover.
|
# tests for fringe issues that the main test suite does not cover.
|
||||||
#
|
#
|
||||||
# $Id: tclsqlite.test,v 1.21 2004/06/02 00:41:10 drh Exp $
|
# $Id: tclsqlite.test,v 1.22 2004/06/09 09:55:20 danielk1977 Exp $
|
||||||
|
|
||||||
set testdir [file dirname $argv0]
|
set testdir [file dirname $argv0]
|
||||||
source $testdir/tester.tcl
|
source $testdir/tester.tcl
|
||||||
@ -34,7 +34,7 @@ do_test tcl-1.1 {
|
|||||||
do_test tcl-1.2 {
|
do_test tcl-1.2 {
|
||||||
set v [catch {db bogus} msg]
|
set v [catch {db bogus} msg]
|
||||||
lappend v $msg
|
lappend v $msg
|
||||||
} {1 {bad option "bogus": must be authorizer, busy, changes, close, commit_hook, complete, errorcode, eval, function, last_insert_rowid, last_statement_changes, onecolumn, progress, rekey, timeout, or trace}}
|
} {1 {bad option "bogus": must be authorizer, busy, changes, close, commit_hook, complete, errorcode, eval, function, last_insert_rowid, last_statement_changes, onecolumn, progress, rekey, timeout, trace, or collate}}
|
||||||
do_test tcl-1.3 {
|
do_test tcl-1.3 {
|
||||||
execsql {CREATE TABLE t1(a int, b int)}
|
execsql {CREATE TABLE t1(a int, b int)}
|
||||||
execsql {INSERT INTO t1 VALUES(10,20)}
|
execsql {INSERT INTO t1 VALUES(10,20)}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
set rcsid {$Id: datatype3.tcl,v 1.3 2004/06/01 10:01:25 drh Exp $}
|
set rcsid {$Id: datatype3.tcl,v 1.4 2004/06/09 09:55:20 danielk1977 Exp $}
|
||||||
source common.tcl
|
source common.tcl
|
||||||
header {Datatypes In SQLite Version 3}
|
header {Datatypes In SQLite Version 3}
|
||||||
puts {
|
puts {
|
||||||
@ -44,7 +44,8 @@ database engine may convert values between numeric storage classes
|
|||||||
quotes, INTEGER if the literal is specified as an unquoted number
|
quotes, INTEGER if the literal is specified as an unquoted number
|
||||||
with no decimal point or exponent, REAL if the literal is an
|
with no decimal point or exponent, REAL if the literal is an
|
||||||
unquoted number with a decimal point or exponent and NULL if the
|
unquoted number with a decimal point or exponent and NULL if the
|
||||||
value is a NULL.</P>
|
value is a NULL. Literals with storage class BLOB are specified
|
||||||
|
using the X'ABCD' notation.</P>
|
||||||
<LI><P>Values supplied using the sqlite3_bind_* APIs are assigned
|
<LI><P>Values supplied using the sqlite3_bind_* APIs are assigned
|
||||||
the storage class that most closely matches the native type bound
|
the storage class that most closely matches the native type bound
|
||||||
(i.e. sqlite3_bind_blob() binds a value with storage class BLOB).</P>
|
(i.e. sqlite3_bind_blob() binds a value with storage class BLOB).</P>
|
||||||
@ -199,6 +200,22 @@ SQL scalar expression or literal other than a column value.</P>
|
|||||||
place.</P>
|
place.</P>
|
||||||
</UL>
|
</UL>
|
||||||
|
|
||||||
|
<P>
|
||||||
|
In SQLite, the expression "a BETWEEN b AND c" is equivalent to "a >= b
|
||||||
|
AND a <= c", even if this means that different affinities are applied to
|
||||||
|
'a' in each of the comparisons required to evaluate the expression.
|
||||||
|
</P>
|
||||||
|
|
||||||
|
<P>Expressions of the type "a IN (SELECT b ....)" are handled by the three
|
||||||
|
rules enumerated above for binary comparisons (e.g. in a
|
||||||
|
similar manner to "a = b"). For example if 'b' is a column value
|
||||||
|
and 'a' is an expression, then the affinity of 'b' is applied to 'a'
|
||||||
|
before any comparisons take place.</P>
|
||||||
|
|
||||||
|
<P>SQLite treats the expression "a IN (x, y, z)" as equivalent to "a = z OR
|
||||||
|
a = y OR a = z".
|
||||||
|
</P>
|
||||||
|
|
||||||
<h4>3.1 Comparison Example</h4>
|
<h4>3.1 Comparison Example</h4>
|
||||||
|
|
||||||
<blockquote>
|
<blockquote>
|
||||||
@ -227,25 +244,6 @@ SELECT c < 60, c < 600 FROM t1;
|
|||||||
0|0
|
0|0
|
||||||
</PRE>
|
</PRE>
|
||||||
</blockquote>
|
</blockquote>
|
||||||
|
|
||||||
<P>
|
|
||||||
In SQLite, the expression "a BETWEEN b AND c" is currently
|
|
||||||
equivalent to "a >= b AND a <= c". SQLite will continue to
|
|
||||||
treat the two as exactly equivalent, even if this means that
|
|
||||||
different affinities are applied to 'a' in each of the comparisons
|
|
||||||
required to evaluate the expression.</P>
|
|
||||||
<P>Expressions of the type "a IN (SELECT b ....)" are handled by
|
|
||||||
the three rules enumerated above for binary comparisons (e.g. in a
|
|
||||||
similar manner to "a = b"). For example if 'b' is a column value
|
|
||||||
and 'a' is an expression, then the affinity of 'b' is applied to 'a'
|
|
||||||
before any comparisons take place.</P>
|
|
||||||
|
|
||||||
<P>SQLite currently treats the expression "a IN (x, y, z)" as
|
|
||||||
equivalent to "a = z OR a = y OR a = z". SQLite will continue to
|
|
||||||
treat the two as exactly equivalent, even if this means that
|
|
||||||
different affinities are applied to 'a' in each of the comparisons
|
|
||||||
required to evaluate the expression.</P>
|
|
||||||
|
|
||||||
<h3>4. Operators</h3>
|
<h3>4. Operators</h3>
|
||||||
|
|
||||||
<P>All mathematical operators (which is to say, all operators other
|
<P>All mathematical operators (which is to say, all operators other
|
||||||
@ -302,11 +300,121 @@ modes, as follows:</P>
|
|||||||
|
|
||||||
<h3>7. User-defined Collation Sequences</h3>
|
<h3>7. User-defined Collation Sequences</h3>
|
||||||
|
|
||||||
<P>By default, when SQLite compares two
|
<p>
|
||||||
text values, the result of the comparison is determined using
|
By default, when SQLite compares two text values, the result of the
|
||||||
memcmp(), regardless of the encoding of the string. SQLite v3
|
comparison is determined using memcmp(), regardless of the encoding of the
|
||||||
provides the ability for users to supply arbitrary comparison
|
string. SQLite v3 provides the ability for users to supply arbitrary
|
||||||
functions, known as user-defined collation sequences, to be used
|
comparison functions, known as user-defined collation sequences, to be used
|
||||||
instead of memcmp().</P>
|
instead of memcmp().
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Aside from the default collation sequence BINARY, implemented using
|
||||||
|
memcmp(), SQLite features two extra built-in collation sequences,
|
||||||
|
NOCASE and REVERSE:
|
||||||
|
</p>
|
||||||
|
<UL>
|
||||||
|
<LI><b>BINARY</b> - Compares string data using memcmp(), regardless
|
||||||
|
of text encoding.</LI>
|
||||||
|
<LI><b>REVERSE</b> - Collate in the reverse order to BINARY. </LI>
|
||||||
|
<LI><b>NOCASE</b> - The same as binary, except the 26 upper case
|
||||||
|
characters used by the English language are
|
||||||
|
folded to their lower case equivalents before
|
||||||
|
the comparison is performed. </UL>
|
||||||
|
|
||||||
|
|
||||||
|
<h4>7.1 Assigning Collation Sequences from SQL</h4>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Each column of each table has a default collation type. If a collation type
|
||||||
|
other than BINARY is required, a COLLATE clause is specified as part of the
|
||||||
|
<a href="lang.html#createtable">column definition</a> to define it.used as
|
||||||
|
illustrated in the example below to
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Whenever two text values are compared by SQLite, a collation sequence is
|
||||||
|
used to determine the results of the comparison according to the following
|
||||||
|
rules. Sections 3 and 5 of this document describe the circumstances under
|
||||||
|
which such a comparison takes place.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
For binary comparison operators (=, <, >, <= and >=) if either operand is a
|
||||||
|
column, then the default collation type of the column determines the
|
||||||
|
collation sequence to use for the comparison. If both operands are columns,
|
||||||
|
then the collation type for the left operand determines the collation
|
||||||
|
sequence used. If neither operand is a column, then the BINARY collation
|
||||||
|
sequence is used.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The expression "x BETWEEN y and z" is equivalent to "x >= y AND x <=
|
||||||
|
z". The expression "x IN (SELECT y ...)" is handled in the same way as the
|
||||||
|
expression "x = y" for the purposes of determining the collation sequence
|
||||||
|
to use. The collation sequence used for expressions of the form "x IN (y, z
|
||||||
|
...)" is the default collation type of x if x is a column, or BINARY
|
||||||
|
otherwise.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
An <a href="lang.html#select">ORDER BY</a> clause that is part of a SELECT
|
||||||
|
statement may be assigned a collation sequence to be used for the sort
|
||||||
|
operation explicitly. In this case the explicit collation sequence is
|
||||||
|
always used. Otherwise, if the expression sorted by an ORDER BY clause is
|
||||||
|
a column, then the default collation type of the column is used to
|
||||||
|
determine sort order. If the expression is not a column, then the BINARY
|
||||||
|
collation sequence is used.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h4>7.2 Collation Sequences Example</h4>
|
||||||
|
<p>
|
||||||
|
The examples below identify the collation sequences that would be used to
|
||||||
|
determine the results of text comparisons that may be performed by various
|
||||||
|
SQL statements. Note that a text comparison may not be required, and no
|
||||||
|
collation sequence used, in the case of numeric, blob or NULL values.
|
||||||
|
</p>
|
||||||
|
<blockquote>
|
||||||
|
<PRE>
|
||||||
|
CREATE TABLE t1(
|
||||||
|
a, -- default collation type BINARY
|
||||||
|
b COLLATE BINARY, -- default collation type BINARY
|
||||||
|
c COLLATE REVERSE, -- default collation type REVERSE
|
||||||
|
d COLLATE NOCASE -- default collation type NOCASE
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Text comparison is performed using the BINARY collation sequence.
|
||||||
|
SELECT (a = b) FROM t1;
|
||||||
|
|
||||||
|
-- Text comparison is performed using the NOCASE collation sequence.
|
||||||
|
SELECT (a = d) FROM t1;
|
||||||
|
|
||||||
|
-- Text comparison is performed using the BINARY collation sequence.
|
||||||
|
SELECT (d = a) FROM t1;
|
||||||
|
|
||||||
|
-- Text comparison is performed using the REVERSE collation sequence.
|
||||||
|
SELECT ('abc' = c) FROM t1;
|
||||||
|
|
||||||
|
-- Text comparison is performed using the REVERSE collation sequence.
|
||||||
|
SELECT (c = 'abc') FROM t1;
|
||||||
|
|
||||||
|
-- Grouping is performed using the NOCASE collation sequence (i.e. values
|
||||||
|
-- 'abc' and 'ABC' are placed in the same group).
|
||||||
|
SELECT count(*) GROUP BY d FROM t1;
|
||||||
|
|
||||||
|
-- Grouping is performed using the BINARY collation sequence.
|
||||||
|
SELECT count(*) GROUP BY (d || '') FROM t1;
|
||||||
|
|
||||||
|
-- Sorting is performed using the REVERSE collation sequence.
|
||||||
|
SELECT * FROM t1 ORDER BY c;
|
||||||
|
|
||||||
|
-- Sorting is performed using the BINARY collation sequence.
|
||||||
|
SELECT * FROM t1 ORDER BY (c || '');
|
||||||
|
|
||||||
|
-- Sorting is performed using the NOCASE collation sequence.
|
||||||
|
SELECT * FROM t1 ORDER BY c COLLATE NOCASE;
|
||||||
|
|
||||||
|
</PRE>
|
||||||
|
</blockquote>
|
||||||
|
|
||||||
}
|
}
|
||||||
footer $rcsid
|
footer $rcsid
|
||||||
|
Reference in New Issue
Block a user