diff --git a/manifest b/manifest index ad38bf3d0a..c80f965f13 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sthe\ssqlite3_collation_needed()\sAPI\sand\sfix\ssome\serror\shandling\scases\ninvolving\sunknown\scollation\ssequences.\s(CVS\s1562) -D 2004-06-10T10:50:08 +C Add\sthe\ssqlite3_collation_needed()\sAPI\sand\sfix\ssome\serror\shandling\scases\ninvolving\sunknown\scollation\ssequences.\s(CVS\s1563) +D 2004-06-10T10:51:48 F Makefile.in ab7b0d5118e2da97bac66be8684a1034e3500f5a F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd @@ -76,7 +76,7 @@ F src/vdbeInt.h d41605853332bdbd600d7ecd60e1f54bbaea174e F src/vdbeapi.c 4ac95766b0515538037a7aec172ed26142f97cf9 F src/vdbeaux.c 73764dadcdbf79aa2d948f863eae07b18589e663 F src/vdbemem.c 5b2fab8b5a830e5204413b808c4a2d8335189f21 -F src/where.c 32578882a245f8ac3303c5cea4664cd51fc73891 +F src/where.c dda77afaa593cd54e5955ec433076de18faf62f6 F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242 F test/attach.test aed659e52635662bcd5069599aaca823533edf5a F test/attach2.test 01f55202c7984f9835b9195a5bff4b5c5f0316ee @@ -96,6 +96,7 @@ F test/capi2.test 8fb64e8ab7f78b8254cd4d04bb96822167f731b2 F test/capi3.test b6fe8a66d2ffe28d4faaaec154a143131e8ff631 F test/collate1.test 7f1ad4c24ea949b7a7aee387df7839389990a998 F test/collate2.test 5b92d795048794266ac27f242a411da8ffeaae25 +F test/collate3.test 69ae73af2e32f4180397bdf2e98998d67a0d4a5d F test/collate4.test a8f2d58bd6943ed1746639c11b12896ccfe8f646 F test/conflict.test 45ce1e44ea748944aed233df8c278a9e1c4c87cc F test/crashtest1.c 09c1c7d728ccf4feb9e481671e29dda5669bbcc2 @@ -149,8 +150,8 @@ F test/sort.test dbd94673b05054e44ca3f08a80faa1e890ef06d8 F test/subselect.test f0fea8cf9f386d416d64d152e3c65f9116d0f50f F test/table.test 1defd90e8200661a822618b18748b9339a7fef2f F test/tableapi.test e0c4cce61e58343caa84dab33fa6823cb35fe1e1 -F test/tclsqlite.test ab5e5c5a00b592c48c38fec8095cde74186c3fc2 -F test/temptable.test a770ba6308d7f7332fce985086b8e06bed6430c2 +F test/tclsqlite.test 2ff5abfd1e133cddcfc61ad5850e3b93f4a7ff40 +F test/temptable.test 6809810546311140f1f4efb4a4fc679b36495f50 F test/tester.tcl fc10520db0d3ce4ef6a8b5ab91bd102fc3f4280a F test/thread1.test 52ab8d963691d5a34a7f998d364371c8c725a253 F test/threadtest1.c f7f896e62ed46feae1dc411114a48c15a0f82ee2 @@ -197,7 +198,7 @@ F www/conflict.tcl fb8a2ba83746c7fdfd9e52fa7f6aaf5c422b8246 F www/copyright-release.html 294e011760c439c44951a6bfecd4c81a1ae359e8 F www/copyright-release.pdf cfca3558fc97095e57c6117d08f1f5b80d95125a F www/copyright.tcl 82c9670c7ddb0311912ab7fe24703f33c531066c -F www/datatype3.tcl 547a852a4c5970e431e7e3c0ae4b1b3ce82c2063 +F www/datatype3.tcl f48b05cafd5e54ae5c05e643169d5217ee51a244 F www/datatypes.tcl 566004b81c36877397ddbe6e1907aae6065f6b41 F www/docs.tcl 0dcbf954907bd5dbfb7f1e0220f4e50516e07cd3 F www/download.tcl 8c84f15695c92cb01486930055fdf5192995f474 @@ -218,7 +219,7 @@ F www/support.tcl 1801397edd271cc39a2aadd54e701184b5181248 F www/tclsqlite.tcl 19191cf2a1010eaeff74c51d83fd5f5a4d899075 F www/vdbe.tcl 59288db1ac5c0616296b26dce071c36cb611dfe9 F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4 -P 71e98d0d089576433c4b06dcba1c57063bd366f5 -R 3d4ef809458f49528c446bf513dcad92 +P edf069b9f4044ed2a80962c7722052bf1b80bf45 +R 9cc8eb0d8d516e56f0a005459d5bbc05 U danielk1977 -Z b84856b016de718871cfb8d15d69b3b5 +Z 33f5dc7ea962340095db9932693801c6 diff --git a/manifest.uuid b/manifest.uuid index 9472c0a770..8b66dbf077 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -edf069b9f4044ed2a80962c7722052bf1b80bf45 \ No newline at end of file +518d82d3b1ab996d675f45c94d740c98578a04a6 \ No newline at end of file diff --git a/src/where.c b/src/where.c index 7d33af48a4..eddb24e2c3 100644 --- a/src/where.c +++ b/src/where.c @@ -12,7 +12,7 @@ ** This module contains C code that generates VDBE code used to process ** the WHERE clause of SQL statements. ** -** $Id: where.c,v 1.103 2004/06/09 09:55:20 danielk1977 Exp $ +** $Id: where.c,v 1.104 2004/06/10 10:51:48 danielk1977 Exp $ */ #include "sqliteInt.h" @@ -208,7 +208,7 @@ static void exprAnalyze(ExprMaskSet *pMaskSet, ExprInfo *pInfo){ ** set to 0 if the ORDER BY clause is all ASC. */ static Index *findSortingIndex( - sqlite *db, + Parse *pParse, Table *pTab, /* The table to be sorted */ int base, /* Cursor number for pTab */ ExprList *pOrderBy, /* The ORDER BY clause */ @@ -220,6 +220,7 @@ static Index *findSortingIndex( Index *pMatch; Index *pIdx; int sortOrder; + sqlite *db = pParse->db; assert( pOrderBy!=0 ); assert( pOrderBy->nExpr>0 ); @@ -248,7 +249,7 @@ static Index *findSortingIndex( int nExpr = pOrderBy->nExpr; if( pIdx->nColumn < nEqCol || pIdx->nColumn < nExpr ) continue; for(i=j=0; ia[j].pExpr); + CollSeq *pColl = sqlite3ExprCollSeq(pParse, pOrderBy->a[j].pExpr); if( !pColl ) pColl = db->pDfltColl; if( pPreferredIdx->aiColumn[i]!=pIdx->aiColumn[i] ) break; if( pPreferredIdx->keyInfo.aColl[i]!=pIdx->keyInfo.aColl[i] ) break; @@ -261,7 +262,7 @@ static Index *findSortingIndex( } if( ia[i+j].pExpr); + CollSeq *pColl = sqlite3ExprCollSeq(pParse, 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; @@ -540,9 +541,9 @@ WhereInfo *sqlite3WhereBegin( if( pIdx->nColumn>32 ) continue; /* Ignore indices too many columns */ for(j=0; jpLeft); + CollSeq *pColl = sqlite3ExprCollSeq(pParse, aExpr[j].p->pLeft); if( !pColl && aExpr[j].p->pRight ){ - pColl = sqlite3ExprCollSeq(aExpr[j].p->pRight); + pColl = sqlite3ExprCollSeq(pParse, aExpr[j].p->pRight); } if( !pColl ){ pColl = pParse->db->pDfltColl; @@ -676,7 +677,7 @@ WhereInfo *sqlite3WhereBegin( pSortIdx = 0; }else{ int nEqCol = (pWInfo->a[0].score+4)/8; - pSortIdx = findSortingIndex(pParse->db, pTab, pTabList->a[0].iCursor, + pSortIdx = findSortingIndex(pParse, pTab, pTabList->a[0].iCursor, *ppOrderBy, pIdx, nEqCol, &bRev); } if( pSortIdx && (pIdx==0 || pIdx==pSortIdx) ){ diff --git a/test/collate3.test b/test/collate3.test new file mode 100644 index 0000000000..673169c0c9 --- /dev/null +++ b/test/collate3.test @@ -0,0 +1,417 @@ +# +# 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 that when the user tries to use an +# unknown or undefined collation type SQLite handles this correctly. +# Also some other error cases are tested. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +# +# Tests are organised as follows: +# +# collate3.1.* - Errors related to unknown collation sequences. +# collate3.2.* - Errors related to undefined collation sequences. +# collate3.3.* - Writing to a table that has an index with an undefined c.s. +# collate3.4.* - Misc errors. +# collate3.5.* - Collation factory. +# + +# +# These tests ensure that when a user executes a statement with an +# unknown collation sequence an error is returned. +# +do_test collate3-1.0 { + execsql { + CREATE TABLE collate3t1(c1); + } +} {} +do_test collate3-1.1 { + catchsql { + SELECT * FROM collate3t1 ORDER BY 1 collate garbage; + } +} {1 {no such collation sequence: garbage}} +do_test collate3-1.2 { + catchsql { + CREATE TABLE collate3t2(c1 collate garbage); + } +} {1 {no such collation sequence: garbage}} +do_test collate3-1.3 { + catchsql { + CREATE INDEX collate3i1 ON collate3t1(c1 COLLATE garbage); + } +} {1 {no such collation sequence: garbage}} + +execsql { + DROP TABLE collate3t1; +} + +# +# Create a table with a default collation sequence, then close +# and re-open the database without re-registering the collation +# sequence. Then make sure the library stops us from using +# the collation sequence in: +# * an explicitly collated ORDER BY +# * an ORDER BY that uses the default collation sequence +# * an expression (=) +# * a CREATE TABLE statement +# * a CREATE INDEX statement that uses a default collation sequence +# * a GROUP BY that uses the default collation sequence +# * a SELECT DISTINCT that uses the default collation sequence +# * Compound SELECTs that uses the default collation sequence +# * An ORDER BY on a compound SELECT with an explicit ORDER BY. +# +do_test collate3-2.0 { + db collate string_compare {string compare} + execsql { + CREATE TABLE collate3t1(c1 COLLATE string_compare, c2); + } + db close + sqlite db test.db + expr 0 +} 0 +do_test collate3-2.1 { + catchsql { + SELECT * FROM collate3t1 ORDER BY 1 COLLATE string_compare; + } +} {1 {no such collation sequence: string_compare}} +do_test collate3-2.2 { + catchsql { + SELECT * FROM collate3t1 ORDER BY c1; + } +} {1 {no such collation sequence: string_compare}} +do_test collate3-2.3 { + catchsql { + SELECT * FROM collate3t1 WHERE c1 = 'xxx'; + } +} {1 {no such collation sequence: string_compare}} +do_test collate3-2.4 { + catchsql { + CREATE TABLE collate3t2(c1 COLLATE string_compare); + } +} {1 {no such collation sequence: string_compare}} +do_test collate3-2.5 { + catchsql { + CREATE INDEX collate3t1_i1 ON collate3t1(c1); + } +} {1 {no such collation sequence: string_compare}} +do_test collate3-2.6 { + catchsql { + SELECT * FROM collate3t1; + } +} {0 {}} + +# FIX ME +if 0 { + +do_test collate3-2.7 { + catchsql { + SELECT * FROM collate3t1 GROUP BY c1; + } +} {1 {no such collation sequence: string_compare}} +do_test collate3-2.8 { + catchsql { + SELECT DISTINCT c1 FROM collate3t1; + } +} {1 {no such collation sequence: string_compare}} +do_test collate3-2.9 { + catchsql { + SELECT c1 FROM collate3t1 UNION SELECT c1 FROM collate3t1; + } +} {1 {no such collation sequence: string_compare}} +do_test collate3-2.10 { + catchsql { + SELECT c1 FROM collate3t1 EXCEPT SELECT c1 FROM collate3t1; + } +} {1 {no such collation sequence: string_compare}} +do_test collate3-2.11 { + catchsql { + SELECT c1 FROM collate3t1 INTERSECT SELECT c1 FROM collate3t1; + } +} {1 {no such collation sequence: string_compare}} +do_test collate3-2.12 { + catchsql { + SELECT c1 FROM collate3t1 UNION ALL SELECT c1 FROM collate3t1; + } +} {0 {}} +do_test collate3-2.13 { + catchsql { + SELECT 10 UNION ALL SELECT 20 ORDER BY 1 COLLATE string_compare; + } +} {1 {no such collation sequence: string_compare}} +do_test collate3-2.14 { + catchsql { + SELECT 10 INTERSECT SELECT 20 ORDER BY 1 COLLATE string_compare; + } +} {1 {no such collation sequence: string_compare}} +do_test collate3-2.15 { + catchsql { + SELECT 10 EXCEPT SELECT 20 ORDER BY 1 COLLATE string_compare; + } +} {1 {no such collation sequence: string_compare}} +do_test collate3-2.16 { + catchsql { + SELECT 10 UNION SELECT 20 ORDER BY 1 COLLATE string_compare; + } +} {1 {no such collation sequence: string_compare}} +do_test collate3-2.17 { + catchsql { + SELECT c1 FROM collate3t1 UNION ALL SELECT c1 FROM collate3t1 ORDER BY 1; + } +} {1 {no such collation sequence: string_compare}} + +} + + +# +# Create an index that uses a collation sequence then close and +# re-open the database without re-registering the collation +# sequence. Then check that for the table with the index +# * An INSERT fails, +# * An UPDATE on the column with the index fails, +# * An UPDATE on a different column succeeds. +# * A DELETE with a WHERE clause fails +# * A DELETE without a WHERE clause succeeds +# +# Also, ensure that the restrictions tested by collate3-2.* still +# apply after the index has been created. +# +do_test collate3-3.0 { + db collate string_compare {string compare} + execsql { + CREATE INDEX collate3t1_i1 ON collate3t1(c1); + INSERT INTO collate3t1 VALUES('xxx', 'yyy'); + } + db close + sqlite db test.db + expr 0 +} 0 +db eval {select * from collate3t1} +breakpoint +do_test collate3-3.1 { + catchsql { + INSERT INTO collate3t1 VALUES('xxx', 0); + } +} {1 {no such collation sequence: string_compare}} +do_test collate3-3.2 { + catchsql { + UPDATE collate3t1 SET c1 = 'xxx'; + } +} {1 {no such collation sequence: string_compare}} +do_test collate3-3.3 { + catchsql { + UPDATE collate3t1 SET c2 = 'xxx'; + } +} {0 {}} +do_test collate3-3.4 { + catchsql { + DELETE FROM collate3t1 WHERE 1; + } +} {1 {no such collation sequence: string_compare}} +do_test collate3-3.5 { + catchsql { + SELECT * FROM collate3t1; + } +} {0 {xxx xxx}} +do_test collate3-3.6 { + catchsql { + DELETE FROM collate3t1; + } +} {0 {}} +do_test collate3-3.8 { + catchsql { + PRAGMA integrity_check + } +} {1 {no such collation sequence: string_compare}} +do_test collate3-3.9 { + catchsql { + SELECT * FROM collate3t1; + } +} {0 {}} +do_test collate3-3.10 { + catchsql { + SELECT * FROM collate3t1 ORDER BY 1 COLLATE string_compare; + } +} {1 {no such collation sequence: string_compare}} +do_test collate3-3.11 { + catchsql { + SELECT * FROM collate3t1 ORDER BY c1; + } +} {1 {no such collation sequence: string_compare}} +do_test collate3-3.12 { + catchsql { + SELECT * FROM collate3t1 WHERE c1 = 'xxx'; + } +} {1 {no such collation sequence: string_compare}} +do_test collate3-3.13 { + catchsql { + CREATE TABLE collate3t2(c1 COLLATE string_compare); + } +} {1 {no such collation sequence: string_compare}} +do_test collate3-3.14 { + catchsql { + CREATE INDEX collate3t1_i2 ON collate3t1(c1); + } +} {1 {no such collation sequence: string_compare}} +do_test collate3-3.15 { + execsql { + DROP TABLE collate3t1; + } +} {} + +# Check we can create an index that uses an explicit collation +# sequence and then close and re-open the database. +do_test collate3-4.6 { + db collate user_defined "string compare" + execsql { + CREATE TABLE collate3t1(a, b); + INSERT INTO collate3t1 VALUES('hello', NULL); + CREATE INDEX collate3i1 ON collate3t1(a COLLATE user_defined); + } +} {} +do_test collate3-4.7 { + db close + sqlite db test.db + catchsql { + SELECT * FROM collate3t1 ORDER BY a COLLATE user_defined; + } +} {1 {no such collation sequence: user_defined}} +do_test collate3-4.8 { + db collate user_defined "string compare" + catchsql { + SELECT * FROM collate3t1 ORDER BY a COLLATE user_defined; + } +} {0 {hello {}}} +do_test collate3-4.8 { + db close + lindex [catch { + sqlite db test.db + }] 0 +} {0} +do_test collate3-4.8 { + execsql { + DROP TABLE collate3t1; + } +} {} + +# Compare strings as numbers. +proc numeric_compare {lhs rhs} { + if {$rhs > $lhs} { + set res -1 + } else { + set res [expr ($lhs > $rhs)?1:0] + } + return $res +} + +# Check we can create a view that uses an explicit collation +# sequence and then close and re-open the database. +do_test collate3-4.9 { + db collate user_defined numeric_compare + execsql { + CREATE TABLE collate3t1(a, b); + INSERT INTO collate3t1 VALUES('2', NULL); + INSERT INTO collate3t1 VALUES('101', NULL); + INSERT INTO collate3t1 VALUES('12', NULL); + CREATE VIEW collate3v1 AS SELECT * FROM collate3t1 + ORDER BY 1 COLLATE user_defined; + SELECT * FROM collate3v1; + } +} {2 {} 12 {} 101 {}} +do_test collate3-4.10 { + db close + sqlite db test.db + catchsql { + SELECT * FROM collate3v1; + } +} {1 {no such collation sequence: user_defined}} +do_test collate3-4.11 { + db collate user_defined numeric_compare + catchsql { + SELECT * FROM collate3v1; + } +} {0 {2 {} 12 {} 101 {}}} +do_test collate3-4.12 { + execsql { + DROP TABLE collate3t1; + } +} {} + +# +# Test the collation factory. In the code, the "no such collation sequence" +# message is only generated in two places. So these tests just test that +# the collation factory can be called once from each of those points. +# +do_test collate3-5.0 { + catchsql { + CREATE TABLE collate3t1(a); + INSERT INTO collate3t1 VALUES(10); + SELECT a FROM collate3t1 ORDER BY 1 COLLATE unk; + } +} {1 {no such collation sequence: unk}} +do_test collate3-5.1 { + set ::cfact_cnt 0 + proc cfact {nm} { + db collate $nm {string compare} + incr ::cfact_cnt + } + db collation_needed cfact +} {} +do_test collate3-5.2 { + catchsql { + SELECT a FROM collate3t1 ORDER BY 1 COLLATE unk; + } +} {0 10} +do_test collate3-5.3 { + set ::cfact_cnt +} {1} +do_test collate3-5.4 { + catchsql { + SELECT a FROM collate3t1 ORDER BY 1 COLLATE unk; + } +} {0 10} +do_test collate3-5.5 { + set ::cfact_cnt +} {1} +do_test collate3-5.6 { + catchsql { + SELECT a FROM collate3t1 ORDER BY 1 COLLATE unk; + } +} {0 10} +do_test collate3-5.7 { + execsql { + DROP TABLE collate3t1; + CREATE TABLE collate3t1(a COLLATE unk); + } + db close + sqlite db test.db + catchsql { + SELECT a FROM collate3t1 ORDER BY 1; + } +} {1 {no such collation sequence: unk}} +do_test collate3-5.8 { + set ::cfact_cnt 0 + proc cfact {nm} { + db collate $nm {string compare} + incr ::cfact_cnt + } + db collation_needed cfact + catchsql { + SELECT a FROM collate3t1 ORDER BY 1; + } +} {0 {}} + +do_test collate3-5.9 { + execsql { + DROP TABLE collate3t1; + } +} {} + +finish_test diff --git a/test/tclsqlite.test b/test/tclsqlite.test index b1bca4a5c2..bbf2d43f01 100644 --- a/test/tclsqlite.test +++ b/test/tclsqlite.test @@ -15,7 +15,7 @@ # interface is pretty well tested. This file contains some addition # tests for fringe issues that the main test suite does not cover. # -# $Id: tclsqlite.test,v 1.22 2004/06/09 09:55:20 danielk1977 Exp $ +# $Id: tclsqlite.test,v 1.23 2004/06/10 10:51:53 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -34,7 +34,7 @@ do_test tcl-1.1 { do_test tcl-1.2 { set v [catch {db bogus} 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, trace, or collate}} +} {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, collate, or collation_needed}} do_test tcl-1.3 { execsql {CREATE TABLE t1(a int, b int)} execsql {INSERT INTO t1 VALUES(10,20)} diff --git a/test/temptable.test b/test/temptable.test index 644df0d4ec..7992766e33 100644 --- a/test/temptable.test +++ b/test/temptable.test @@ -12,7 +12,7 @@ # # This file implements tests for temporary tables and indices. # -# $Id: temptable.test,v 1.11 2004/02/14 16:31:04 drh Exp $ +# $Id: temptable.test,v 1.12 2004/06/10 10:51:53 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -237,11 +237,11 @@ do_test temptable-4.10.1 { SELECT * FROM t2; } db2 } {0 {1 2}} -#do_test temptable-4.10.2 { -# catchsql { -# SELECT name FROM sqlite_master WHERE type='table' -# } db2 -#} {1 {database schema has changed}} +do_test temptable-4.10.2 { + catchsql { + SELECT name FROM sqlite_master WHERE type='table' + } db2 +} {1 {database schema has changed}} do_test temptable-4.10.3 { catchsql { SELECT name FROM sqlite_master WHERE type='table' diff --git a/www/datatype3.tcl b/www/datatype3.tcl index f92f2651ff..601a6da6cd 100644 --- a/www/datatype3.tcl +++ b/www/datatype3.tcl @@ -1,4 +1,4 @@ -set rcsid {$Id: datatype3.tcl,v 1.4 2004/06/09 09:55:20 danielk1977 Exp $} +set rcsid {$Id: datatype3.tcl,v 1.5 2004/06/10 10:51:53 danielk1977 Exp $} source common.tcl header {Datatypes In SQLite Version 3} puts { @@ -327,8 +327,7 @@ NOCASE and REVERSE:

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 -column definition to define it.used as -illustrated in the example below to +column definition to define it.