-C Misc\sfixes\sfor\stest\scases\sfailing\sdue\sto\sthe\snew\slocking\smodel.\s(CVS\s1561)
-D 2004-06-10T05:59:25
+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
F Makefile.in ab7b0d5118e2da97bac66be8684a1034e3500f5a
F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457
F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
F src/auth.c 5c2f0bea4729c98c2be3b69d6b466fc51448fe79
F src/btree.c 281af87aa117de024f5b6c2728a2339cba9ef584
F src/btree.h 589427ac13bb544d298cd99726e2572a6fe4bdaa
-F src/build.c 5d958f480d71f56981f262de6994a4d2ee6e5f75
+F src/build.c 4b1a23d919fe01549702f7f1bfe7f8b656e77a17
F src/date.c 8e6fa3173386fb29fdef012ee08a853c1e9908b2
-F src/delete.c b30f08250c9ed53a25a13c7c04599c1e8753992d
+F src/delete.c 911221aadb35d610c84fadb32e71c52990827e58
F src/encode.c a876af473d1d636faa3dca51c7571f2e007eea37
-F src/expr.c 3aea8faac17debea4f5c2659351c27d5660453a0
+F src/expr.c 34e63e960ab8ca9e4fc4a1f41b0a3b77df2ae167
F src/func.c ffbdfa4cad2a16a41390c2ce923ef8b0f173d777
F src/hash.c 440c2f8cb373ee1b4e13a0988489c7cd95d55b6f
F src/hash.h 762d95f1e567664d1eafc1687de755626be962fb
-F src/insert.c 4268d9e3959cc845ea243fb4ec7507269404dad9
+F src/insert.c 68c7f3ddd6a7f1e5596d6996da1a2861b3789a3a
F src/legacy.c ad23746f15f67e34577621b1875f639c94839e1f
-F src/main.c cb41777e75f6b95a2af42f439c78e761a49cdffa
+F src/main.c 335b4cd48af0011017e33a411aea307553114e67
F src/md5.c 4302e84ae516c616bb079c4e6d038c0addb33481
F src/os.h 23c69c5084e71b5fe199ff1c4e35a4aded0f1380
F src/os_common.h 6393ac67a3a7b4aea19ff17529980ecf77eb2348
F src/pager.c d852730901441babf6cd16fc528dd6eecc2b2eab
F src/pager.h ca8f293e1d623a7c628a1c5e0c6cf43d5bbb80bf
F src/parse.y 097438674976355a10cf177bd97326c548820b86
-F src/pragma.c 6ab13748a415bf8e8f2dd79e5f713fbe72dfd3f4
+F src/pragma.c 0bc3adea28df802074996bec067d506d55d28f84
F src/printf.c 63b15f1ea9fe3daa066bb7430fd20d4a2d717dc8
F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3
-F src/select.c 1f8355e702f109f6771f82a9bfe7aac4c82cbaf2
+F src/select.c 6cb407796dde0e8f27450ead68856eb9f8188789
F src/shell.c ca519519dcbbc582f6d88f7d0e7583b857fd3469
-F src/sqlite.h.in 00ce6b80cf4dffa9bf7a028d80d1ffba708b175a
-F src/sqliteInt.h cd9db5ca4a2ba59cf1692fcbd1ea7318c50f0c4f
+F src/sqlite.h.in 2b6afe1de6935d3dfbd6042f46a62f1b7c3b3992
+F src/sqliteInt.h 6be535d420f99c57f29f13c3c2d6a3497432b366
F src/table.c af14284fa36c8d41f6829e3f2819dce07d3e2de2
-F src/tclsqlite.c 6383ba7b620b276d49b40d48872502e0adb1b685
+F src/tclsqlite.c e974c0b2479ed37334aeb268de331e0a1b21b5a8
F src/test1.c f78d6ac0675bc5db48dac9c5379c965bdadb9113
F src/test2.c 05f810c90cf6262d5f352860e87d41a3f34207f9
F src/test3.c beafd0ccf7b9ae784744be1b1e66ffe8f64c25da
F src/test5.c 862784cd7a68e7d36f00287aac6e413ca996eaf8
F src/tokenize.c 183c5d7da11affab5d70d903d33409c8c0ce6c5b
F src/trigger.c d1a4d7a59b34c811bf6070d64d0497baa0140dcf
-F src/update.c 259f06e7b22c684b2d3dda54a18185892d6e9573
+F src/update.c 168b6d523087ca4545b74ec9f3102b1f3c6b1e38
F src/utf.c c2c8e445bfea724f3502609d6389fe66651f02ab
F src/util.c e8629f04d920ae968fced709dc7a3a2c62b65ac4
F src/vacuum.c b921eb778842592e1fb48a9d4cef7e861103878f
F www/tclsqlite.tcl 19191cf2a1010eaeff74c51d83fd5f5a4d899075
F www/vdbe.tcl 59288db1ac5c0616296b26dce071c36cb611dfe9
F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4
-P adb2bd61436927d37b23bae857089d62e12397af
-R e8b127567100f827cb21e845b744b7ae
+P 71e98d0d089576433c4b06dcba1c57063bd366f5
+R 3d4ef809458f49528c446bf513dcad92
U danielk1977
-Z 7c95f2d087a4836fb9faba67d8f7b64b
+Z b84856b016de718871cfb8d15d69b3b5
-71e98d0d089576433c4b06dcba1c57063bd366f5
\ No newline at end of file
+edf069b9f4044ed2a80962c7722052bf1b80bf45
\ No newline at end of file
** ROLLBACK
** PRAGMA
**
-** $Id: build.c,v 1.214 2004/06/10 02:16:02 danielk1977 Exp $
+** $Id: build.c,v 1.215 2004/06/10 10:50:08 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
pColl[1].enc = TEXT_Utf16le;
pColl[2].zName = (char*)&pColl[3];
pColl[2].enc = TEXT_Utf16be;
- memcpy(pColl[0].zName, zName, nName+1);
+ memcpy(pColl[0].zName, zName, nName);
+ pColl[0].zName[nName] = 0;
sqlite3HashInsert(&db->aCollSeq, pColl[0].zName, nName, pColl);
}
}
return pColl;
}
+static void callCollNeeded(sqlite *db, const char *zName, int nName){
+ /* No collation sequence of this type for this encoding is registered.
+ ** Call the collation factory to see if it can supply us with one.
+ */
+ char *zExternal = 0;
+ assert( !db->xCollNeeded || !db->xCollNeeded16 );
+ if( nName<0 ) nName = strlen(zName);
+ if( db->xCollNeeded ){
+ zExternal = sqliteStrNDup(zName, nName);
+ if( !zExternal ) return;
+ db->xCollNeeded(db->pCollNeededArg, db, (int)db->enc, zExternal);
+ }
+ if( db->xCollNeeded16 ){
+ if( SQLITE_BIGENDIAN ){
+ zExternal = sqlite3utf8to16be(zName, nName);
+ }else{
+ zExternal = sqlite3utf8to16le(zName, nName);
+ }
+ if( !zExternal ) return;
+ db->xCollNeeded16(db->pCollNeededArg, db, (int)db->enc, zExternal);
+ }
+ if( zExternal ) sqliteFree(zExternal);
+}
+
+static int synthCollSeq(Parse *pParse, CollSeq *pColl){
+ /* The collation factory failed to deliver a function but there may be
+ ** other versions of this collation function (for other text encodings)
+ ** available. Use one of these instead. Avoid a UTF-8 <-> UTF-16
+ ** conversion if possible.
+ */
+ CollSeq *pColl2 = 0;
+ char *z = pColl->zName;
+ int n = strlen(z);
+ switch( pParse->db->enc ){
+ case TEXT_Utf16le:
+ pColl2 = sqlite3FindCollSeq(pParse->db, TEXT_Utf16be, z, n, 0);
+ assert( pColl2 );
+ if( pColl2->xCmp ) break;
+ pColl2 = sqlite3FindCollSeq(pParse->db, TEXT_Utf8, z, n, 0);
+ assert( pColl2 );
+ break;
+
+ case TEXT_Utf16be:
+ pColl2 = sqlite3FindCollSeq(pParse->db,TEXT_Utf16le, z, n, 0);
+ assert( pColl2 );
+ if( pColl2->xCmp ) break;
+ pColl2 = sqlite3FindCollSeq(pParse->db,TEXT_Utf8, z, n, 0);
+ assert( pColl2 );
+ break;
+
+ case TEXT_Utf8:
+ pColl2 = sqlite3FindCollSeq(pParse->db,TEXT_Utf16be, z, n, 0);
+ assert( pColl2 );
+ if( pColl2->xCmp ) break;
+ pColl2 = sqlite3FindCollSeq(pParse->db,TEXT_Utf16le, z, n, 0);
+ assert( pColl2 );
+ break;
+ }
+ if( pColl2->xCmp ){
+ memcpy(pColl, pColl2, sizeof(CollSeq));
+ }else{
+ if( pParse->nErr==0 ){
+ sqlite3SetNString(&pParse->zErrMsg, "no such collation sequence: ",
+ -1, z, n, 0);
+ }
+ pParse->nErr++;
+ return SQLITE_ERROR;
+ }
+ return SQLITE_OK;
+}
+
+/*
+** This routine is called on a collation sequence before it is used to
+** check that it is defined. An undefined collation sequence exists when
+** a database is loaded that contains references to collation sequences
+** that have not been defined by sqlite3_create_collation() etc.
+**
+** If required, this routine calls the 'collation needed' callback to
+** request a definition of the collating sequence. If this doesn't work,
+** an equivalent collating sequence that uses a text encoding different
+** from the main database is substituted, if one is available.
+*/
+int sqlite3CheckCollSeq(Parse *pParse, CollSeq *pColl){
+ if( pColl && !pColl->xCmp ){
+ callCollNeeded(pParse->db, pColl->zName, strlen(pColl->zName));
+ if( !pColl->xCmp && synthCollSeq(pParse, pColl) ){
+ return SQLITE_ERROR;
+ }
+ }
+ return SQLITE_OK;
+}
+
+int sqlite3CheckIndexCollSeq(Parse *pParse, Index *pIdx){
+ if( pIdx ){
+ int i;
+ for(i=0; i<pIdx->nColumn; i++){
+ if( sqlite3CheckCollSeq(pParse, pIdx->keyInfo.aColl[i]) ){
+ return SQLITE_ERROR;
+ }
+ }
+ }
+ return SQLITE_OK;
+}
+
/*
** This function returns the collation sequence for database native text
** encoding identified by the string zName, length nName.
*/
CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char *zName, int nName){
u8 enc = pParse->db->enc;
- CollSeq *pColl = sqlite3FindCollSeq(pParse->db, enc, zName, nName, 0);
- if( !pColl || !pColl->xCmp ){
+ u8 initbusy = pParse->db->init.busy;
+ CollSeq *pColl = sqlite3FindCollSeq(pParse->db, enc, zName, nName, initbusy);
+ if( !initbusy && (!pColl || !pColl->xCmp) ){
/* No collation sequence of this type for this encoding is registered.
** Call the collation factory to see if it can supply us with one.
*/
-
- /* FIX ME: Actually call collation factory, then call
- ** sqlite3FindCollSeq() again. */
+ callCollNeeded(pParse->db, zName, nName);
pColl = sqlite3FindCollSeq(pParse->db, enc, zName, nName, 0);
-
if( pColl && !pColl->xCmp ){
- /* The collation factory failed to deliver a function but there are
- ** other versions of this collation function (for other text
- ** encodings) available. Use one of these instead. Avoid a
- ** UTF-8 <-> UTF-16 conversion if possible.
+ /* There may be a version of the collation sequence that requires
+ ** translation between encodings. Search for it with synthCollSeq().
*/
- CollSeq *pColl2 = 0;
- switch( enc ){
- case TEXT_Utf16le:
- pColl2 = sqlite3FindCollSeq(pParse->db,TEXT_Utf16be,zName,nName,0);
- assert( pColl2 );
- if( pColl2->xCmp ) break;
- pColl2 = sqlite3FindCollSeq(pParse->db,TEXT_Utf8,zName,nName,0);
- assert( pColl2 );
- break;
-
- case TEXT_Utf16be:
- pColl2 = sqlite3FindCollSeq(pParse->db,TEXT_Utf16le,zName,nName,0);
- assert( pColl2 );
- if( pColl2->xCmp ) break;
- pColl2 = sqlite3FindCollSeq(pParse->db,TEXT_Utf8,zName,nName,0);
- assert( pColl2 );
- break;
-
- case TEXT_Utf8:
- pColl2 = sqlite3FindCollSeq(pParse->db,TEXT_Utf16be,zName,nName,0);
- assert( pColl2 );
- if( pColl2->xCmp ) break;
- pColl2 = sqlite3FindCollSeq(pParse->db,TEXT_Utf16le,zName,nName,0);
- assert( pColl2 );
- break;
- }
-
- if( pColl2->xCmp ){
- memcpy(pColl, pColl2, sizeof(CollSeq));
+ if( synthCollSeq(pParse, pColl) ){
+ return 0;
}
}
}
/* If nothing has been found, write the error message into pParse */
- if( !pColl || !pColl->xCmp ){
+ if( !initbusy && (!pColl || !pColl->xCmp) ){
if( pParse->nErr==0 ){
sqlite3SetNString(&pParse->zErrMsg, "no such collation sequence: ", -1,
zName, nName, 0);
}
pParse->nErr++;
+ pColl = 0;
}
-
return pColl;
}
pIndex->keyInfo.aColl[i] = pTab->aCol[j].pColl;
}
assert( pIndex->keyInfo.aColl[i] );
+ if( !db->init.busy &&
+ sqlite3CheckCollSeq(pParse, pIndex->keyInfo.aColl[i])
+ ){
+ goto exit_create_index;
+ }
}
pIndex->keyInfo.nField = pList->nExpr;
** specified auxiliary database and the temp database are made writable.
*/
void sqlite3BeginWriteOperation(Parse *pParse, int setStatement, int iDb){
- sqlite *db = pParse->db;
Vdbe *v = sqlite3GetVdbe(pParse);
if( v==0 ) return;
sqlite3CodeVerifySchema(pParse, iDb);
** This file contains C code routines that are called by the parser
** to handle DELETE FROM statements.
**
-** $Id: delete.c,v 1.72 2004/06/03 16:08:41 danielk1977 Exp $
+** $Id: delete.c,v 1.73 2004/06/10 10:50:15 danielk1977 Exp $
*/
#include "sqliteInt.h"
** the table and pick which records to delete.
*/
else{
+ /* Ensure all required collation sequences are available. */
+ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
+ if( sqlite3CheckIndexCollSeq(pParse, pIdx) ){
+ goto delete_from_cleanup;
+ }
+ }
+
/* Begin the database scan
*/
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 1, 0);
** This file contains routines used for analyzing expressions and
** for generating VDBE code that evaluates expressions in SQLite.
**
-** $Id: expr.c,v 1.137 2004/06/09 09:55:18 danielk1977 Exp $
+** $Id: expr.c,v 1.138 2004/06/10 10:50:17 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
** Return the default collation sequence for the expression pExpr. If
** there is no default collation type, return 0.
*/
-CollSeq *sqlite3ExprCollSeq(Expr *pExpr){
+CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){
+ CollSeq *pColl = 0;
if( pExpr ){
- if( pExpr->pColl ) return pExpr->pColl;
- if( pExpr->op==TK_AS ){
- return sqlite3ExprCollSeq(pExpr->pLeft);
+ pColl = pExpr->pColl;
+ if( pExpr->op==TK_AS && !pColl ){
+ return sqlite3ExprCollSeq(pParse, pExpr->pLeft);
}
}
- return 0;
+ if( sqlite3CheckCollSeq(pParse, pColl) ){
+ pColl = 0;
+ }
+ return pColl;
}
/*
** is used, or the default (BINARY) if neither expression has a collating
** type.
*/
-static CollSeq* binaryCompareCollSeq(Expr *pLeft, Expr *pRight){
- CollSeq *pColl = sqlite3ExprCollSeq(pLeft);
+static CollSeq* binaryCompareCollSeq(Parse *pParse, Expr *pLeft, Expr *pRight){
+ CollSeq *pColl = sqlite3ExprCollSeq(pParse, pLeft);
if( !pColl ){
- pColl = sqlite3ExprCollSeq(pRight);
+ pColl = sqlite3ExprCollSeq(pParse, pRight);
}
return pColl;
}
assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable );
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,
+ keyInfo.aColl[0] = binaryCompareCollSeq(pParse, pExpr->pLeft,
pExpr->pSelect->pEList->a[0].pExpr);
}
}else if( pExpr->pList ){
case TK_NE:
case TK_EQ: {
int p1 = binaryCompareP1(pExpr->pLeft, pExpr->pRight, 0);
- CollSeq *p3 = binaryCompareCollSeq(pExpr->pLeft, pExpr->pRight);
+ CollSeq *p3 = binaryCompareCollSeq(pParse, pExpr->pLeft, pExpr->pRight);
sqlite3ExprCode(pParse, pExpr->pLeft);
sqlite3ExprCode(pParse, pExpr->pRight);
sqlite3VdbeOp3(v, op, p1, 0, (void *)p3, P3_COLLSEQ);
sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
sqlite3ExprCode(pParse, pExpr->pList->a[0].pExpr);
p1 = binaryCompareP1(pExpr->pLeft, pExpr->pList->a[0].pExpr, 0);
- p3 = binaryCompareCollSeq(pExpr->pLeft, pExpr->pList->a[0].pExpr);
+ p3 = binaryCompareCollSeq(pParse, pExpr->pLeft, pExpr->pList->a[0].pExpr);
sqlite3VdbeOp3(v, OP_Ge, p1, 0, (void *)p3, P3_COLLSEQ);
sqlite3VdbeAddOp(v, OP_Pull, 1, 0);
sqlite3ExprCode(pParse, pExpr->pList->a[1].pExpr);
p1 = binaryCompareP1(pExpr->pLeft, pExpr->pList->a[1].pExpr, 0);
- p3 = binaryCompareCollSeq(pExpr->pLeft, pExpr->pList->a[1].pExpr);
+ p3 = binaryCompareCollSeq(pParse, pExpr->pLeft, pExpr->pList->a[1].pExpr);
sqlite3VdbeOp3(v, OP_Le, p1, 0, (void *)p3, P3_COLLSEQ);
sqlite3VdbeAddOp(v, OP_And, 0, 0);
break;
sqlite3ExprCode(pParse, pExpr->pList->a[i].pExpr);
if( pExpr->pLeft ){
int p1 = binaryCompareP1(pExpr->pLeft, pExpr->pList->a[i].pExpr, 1);
- CollSeq *p3 = binaryCompareCollSeq(pExpr->pLeft,
+ CollSeq *p3 = binaryCompareCollSeq(pParse, pExpr->pLeft,
pExpr->pList->a[i].pExpr);
sqlite3VdbeAddOp(v, OP_Dup, 1, 1);
jumpInst = sqlite3VdbeOp3(v, OP_Ne, p1, 0, (void *)p3, P3_COLLSEQ);
case TK_NE:
case TK_EQ: {
int p1 = binaryCompareP1(pExpr->pLeft, pExpr->pRight, jumpIfNull);
- CollSeq *p3 = binaryCompareCollSeq(pExpr->pLeft, pExpr->pRight);
+ CollSeq *p3 = binaryCompareCollSeq(pParse, pExpr->pLeft, pExpr->pRight);
sqlite3ExprCode(pParse, pExpr->pLeft);
sqlite3ExprCode(pParse, pExpr->pRight);
sqlite3VdbeOp3(v, op, p1, dest, (void *)p3, P3_COLLSEQ);
sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
sqlite3ExprCode(pParse, pExpr->pList->a[0].pExpr);
p1 = binaryCompareP1(pExpr->pLeft, pExpr->pList->a[0].pExpr, !jumpIfNull);
- p3 = binaryCompareCollSeq(pExpr->pLeft, pExpr->pList->a[0].pExpr);
+ p3 = binaryCompareCollSeq(pParse, 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);
p1 = binaryCompareP1(pExpr->pLeft, pExpr->pList->a[1].pExpr, jumpIfNull);
- p3 = binaryCompareCollSeq(pExpr->pLeft, pExpr->pList->a[1].pExpr);
+ p3 = binaryCompareCollSeq(pParse, pExpr->pLeft, pExpr->pList->a[1].pExpr);
sqlite3VdbeOp3(v, OP_Le, p1, dest, (void *)p3, P3_COLLSEQ);
sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
case TK_NE:
case TK_EQ: {
int p1 = binaryCompareP1(pExpr->pLeft, pExpr->pRight, jumpIfNull);
- CollSeq *p3 = binaryCompareCollSeq(pExpr->pLeft, pExpr->pRight);
+ CollSeq *p3 = binaryCompareCollSeq(pParse, pExpr->pLeft, pExpr->pRight);
sqlite3ExprCode(pParse, pExpr->pLeft);
sqlite3ExprCode(pParse, pExpr->pRight);
sqlite3VdbeOp3(v, op, p1, dest, (void *)p3, P3_COLLSEQ);
sqlite3ExprCode(pParse, pExpr->pList->a[0].pExpr);
addr = sqlite3VdbeCurrentAddr(v);
p1 = binaryCompareP1(pExpr->pLeft, pExpr->pList->a[0].pExpr, !jumpIfNull);
- p3 = binaryCompareCollSeq(pExpr->pLeft, pExpr->pList->a[0].pExpr);
+ p3 = binaryCompareCollSeq(pParse, 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_Goto, 0, dest);
sqlite3ExprCode(pParse, pExpr->pList->a[1].pExpr);
p1 = binaryCompareP1(pExpr->pLeft, pExpr->pList->a[1].pExpr, jumpIfNull);
- p3 = binaryCompareCollSeq(pExpr->pLeft, pExpr->pList->a[1].pExpr);
+ p3 = binaryCompareCollSeq(pParse, pExpr->pLeft, pExpr->pList->a[1].pExpr);
sqlite3VdbeOp3(v, OP_Gt, p1, dest, (void *)p3, P3_COLLSEQ);
break;
}
** This file contains C code routines that are called by the parser
** to handle INSERT statements in SQLite.
**
-** $Id: insert.c,v 1.109 2004/05/31 08:55:34 danielk1977 Exp $
+** $Id: insert.c,v 1.110 2004/06/10 10:50:21 danielk1977 Exp $
*/
#include "sqliteInt.h"
goto insert_cleanup;
}
+ /* Ensure all required collation sequences are available. */
+ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
+ if( sqlite3CheckIndexCollSeq(pParse, pIdx) ){
+ goto insert_cleanup;
+ }
+ }
+
/* Allocate a VDBE
*/
v = sqlite3GetVdbe(pParse);
** other files are for internal use by SQLite and should not be
** accessed by users of the library.
**
-** $Id: main.c,v 1.213 2004/06/10 02:16:02 danielk1977 Exp $
+** $Id: main.c,v 1.214 2004/06/10 10:50:22 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "os.h"
sqliteFree(zName8);
return rc;
}
+
+int sqlite3_collation_needed(
+ sqlite3 *db,
+ void *pCollNeededArg,
+ void(*xCollNeeded)(void*,sqlite3*,int eTextRep,const char*)
+){
+ db->xCollNeeded = xCollNeeded;
+ db->xCollNeeded16 = 0;
+ db->pCollNeededArg = pCollNeededArg;
+ return SQLITE_OK;
+}
+int sqlite3_collation_needed16(
+ sqlite3 *db,
+ void *pCollNeededArg,
+ void(*xCollNeeded16)(void*,sqlite3*,int eTextRep,const void*)
+){
+ db->xCollNeeded = 0;
+ db->xCollNeeded16 = xCollNeeded16;
+ db->pCollNeededArg = pCollNeededArg;
+ return SQLITE_OK;
+}
+
*************************************************************************
** This file contains code used to implement the PRAGMA command.
**
-** $Id: pragma.c,v 1.41 2004/06/10 01:30:59 drh Exp $
+** $Id: pragma.c,v 1.42 2004/06/10 10:50:25 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
sqlite3VdbeAddOp(v, OP_Integer, pTab->tnum, 0);
cnt++;
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
+ if( sqlite3CheckIndexCollSeq(pParse, pIdx) ) return;
sqlite3VdbeAddOp(v, OP_Integer, pIdx->tnum, 0);
cnt++;
}
** This file contains C code routines that are called by the parser
** to handle SELECT statements in SQLite.
**
-** $Id: select.c,v 1.185 2004/06/09 09:55:18 danielk1977 Exp $
+** $Id: select.c,v 1.186 2004/06/10 10:50:25 danielk1977 Exp $
*/
#include "sqliteInt.h"
** is stored in pOrderBy->a[i].zName. Otherwise, use the default
** collation type for the expression.
*/
- pInfo->aColl[i] = sqlite3ExprCollSeq(pOrderBy->a[i].pExpr);
+ pInfo->aColl[i] = sqlite3ExprCollSeq(pParse, pOrderBy->a[i].pExpr);
if( !pInfo->aColl[i] ){
pInfo->aColl[i] = db->pDfltColl;
}
if( zType ){
pTab->aCol[i].affinity = sqlite3AffinityType(zType, strlen(zType));
}
- pTab->aCol[i].pColl = sqlite3ExprCollSeq(p);
+ pTab->aCol[i].pColl = sqlite3ExprCollSeq(pParse, p);
if( !pTab->aCol[i].pColl ){
pTab->aCol[i].pColl = pParse->db->pDfltColl;
}
}
}
- /* 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.
*/
v = sqlite3GetVdbe(pParse);
return rc;
}
+ /* 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;
+ }
+ }
+
/* Set the limiter.
*/
computeLimitRegisters(pParse, p);
** This header file defines the interface that the SQLite library
** presents to client programs.
**
-** @(#) $Id: sqlite.h.in,v 1.96 2004/06/10 02:16:02 danielk1977 Exp $
+** @(#) $Id: sqlite.h.in,v 1.97 2004/06/10 10:50:30 danielk1977 Exp $
*/
#ifndef _SQLITE_H_
#define _SQLITE_H_
#define SQLITE_UTF16LE 2
#define SQLITE_UTF16BE 3
+/*
+** These two functions are used to add new collation sequences to the
+** sqlite3 handle specified as the first argument.
+**
+** The name of the new collation sequence is specified as a UTF-8 string
+** for sqlite3_create_collation() and a UTF-16 string for
+** sqlite3_create_collation16(). In both cases the name is passed as the
+** second function argument.
+**
+** The third argument must be one of the constants SQLITE_UTF8,
+** SQLITE_UTF16LE or SQLITE_UTF16BE, indicating that the user-supplied
+** routine expects to be passed pointers to strings encoded using UTF-8,
+** UTF-16 little-endian or UTF-16 big-endian respectively.
+**
+** A pointer to the user supplied routine must be passed as the fifth
+** argument. If it is NULL, this is the same as deleting the collation
+** sequence (so that SQLite cannot call it anymore). Each time the user
+** supplied function is invoked, it is passed a copy of the void* passed as
+** the fourth argument to sqlite3_create_collation() or
+** sqlite3_create_collation16() as its first parameter.
+**
+** The remaining arguments to the user-supplied routine are two strings,
+** each represented by a [length, data] pair and encoded in the encoding
+** that was passed as the third argument when the collation sequence was
+** registered. The user routine should return negative, zero or positive if
+** the first string is less than, equal to, or greater than the second
+** string. i.e. (STRING1 - STRING2).
+*/
int sqlite3_create_collation(
sqlite3*,
const char *zName,
- int enc,
+ int eTextRep,
void*,
int(*xCompare)(void*,int,const void*,int,const void*)
);
int sqlite3_create_collation16(
sqlite3*,
const char *zName,
- int enc,
+ int eTextRep,
void*,
int(*xCompare)(void*,int,const void*,int,const void*)
);
+/*
+** To avoid having to register all collation sequences before a database
+** can be used, a single callback function may be registered with the
+** database handle to be called whenever an undefined collation sequence is
+** required.
+**
+** If the function is registered using the sqlite3_collation_needed() API,
+** then it is passed the names of undefined collation sequences as strings
+** encoded in UTF-8. If sqlite3_collation_needed16() is used, the names
+** are passed as UTF-16 in machine native byte order. A call to either
+** function replaces any existing callback.
+**
+** When the user-function is invoked, the first argument passed is a copy
+** of the second argument to sqlite3_collation_needed() or
+** sqlite3_collation_needed16(). The second argument is the database
+** handle. The third argument is one of SQLITE_UTF8, SQLITE_UTF16BE or
+** SQLITE_UTF16LE, indicating the most desirable form of the collation
+** sequence function required. The fourth parameter is the name of the
+** required collation sequence.
+**
+** The collation sequence is returned to SQLite by a collation-needed
+** callback using the sqlite3_create_collation() or
+** sqlite3_create_collation16() APIs, described above.
+*/
+int sqlite3_collation_needed(
+ sqlite3*,
+ void*,
+ void(*)(void*,sqlite3*,int eTextRep,const char*)
+);
+int sqlite3_collation_needed16(
+ sqlite3*,
+ void*,
+ void(*)(void*,sqlite3*,int eTextRep,const void*)
+);
+
#ifdef __cplusplus
} /* End of the 'extern "C"' block */
*************************************************************************
** Internal interface definitions for SQLite.
**
-** @(#) $Id: sqliteInt.h,v 1.279 2004/06/10 02:16:02 danielk1977 Exp $
+** @(#) $Id: sqliteInt.h,v 1.280 2004/06/10 10:50:32 danielk1977 Exp $
*/
#include "config.h"
#include "sqlite3.h"
u8 enc; /* Text encoding for this database. */
u8 autoCommit; /* The auto-commit flag. */
int nMaster; /* Length of master journal name. -1=unknown */
+ void(*xCollNeeded)(void*,sqlite3*,int eTextRep,const char*);
+ void(*xCollNeeded16)(void*,sqlite3*,int eTextRep,const void*);
+ void *pCollNeededArg;
};
/*
int sqlite3ReadSchema(sqlite *db, char **);
CollSeq *sqlite3FindCollSeq(sqlite *,u8 enc, const char *,int,int);
CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char *zName, int nName);
-CollSeq *sqlite3ExprCollSeq(Expr *pExpr);
+CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr);
+int sqlite3CheckCollSeq(Parse *, CollSeq *);
+int sqlite3CheckIndexCollSeq(Parse *, Index *);
*************************************************************************
** A TCL Interface to SQLite
**
-** $Id: tclsqlite.c,v 1.82 2004/06/10 02:16:02 danielk1977 Exp $
+** $Id: tclsqlite.c,v 1.83 2004/06/10 10:50:38 danielk1977 Exp $
*/
#ifndef NO_TCL /* Omit this whole file if TCL is unavailable */
SqlFunc *pFunc; /* List of SQL functions */
SqlCollate *pCollate; /* List of SQL collation functions */
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 */
+ Tcl_Obj *pCollateNeeded; /* Collation needed script */
};
/*
return 0;
}
+static void tclCollateNeeded(
+ void *pCtx,
+ sqlite *db,
+ int enc,
+ const char *zName
+){
+ SqliteDb *pDb = (SqliteDb *)pCtx;
+ Tcl_Obj *pScript = Tcl_DuplicateObj(pDb->pCollateNeeded);
+ Tcl_IncrRefCount(pScript);
+ Tcl_ListObjAppendElement(0, pScript, Tcl_NewStringObj(zName, -1));
+ Tcl_EvalObjEx(pDb->interp, pScript, 0);
+ Tcl_DecrRefCount(pScript);
+}
+
/*
** This routine is called to evaluate an SQL collation function implemented
** using TCL script.
"errorcode", "eval", "function",
"last_insert_rowid", "last_statement_changes", "onecolumn",
"progress", "rekey", "timeout",
- "trace", "collate",
+ "trace", "collate", "collation_needed",
0
};
enum DB_enum {
DB_ERRORCODE, DB_EVAL, DB_FUNCTION,
DB_LAST_INSERT_ROWID, DB_LAST_STATEMENT_CHANGES, DB_ONECOLUMN,
DB_PROGRESS, DB_REKEY, DB_TIMEOUT,
- DB_TRACE, DB_COLLATE
+ DB_TRACE, DB_COLLATE, DB_COLLATION_NEEDED
};
if( objc<2 ){
break;
}
+ /*
+ ** $db collate_needed SCRIPT
+ **
+ ** Create a new SQL collation function called NAME. Whenever
+ ** that function is called, invoke SCRIPT to evaluate the function.
+ */
+ case DB_COLLATION_NEEDED: {
+ if( objc!=3 ){
+ Tcl_WrongNumArgs(interp, 2, objv, "SCRIPT");
+ return TCL_ERROR;
+ }
+ if( pDb->pCollateNeeded ){
+ Tcl_DecrRefCount(pDb->pCollateNeeded);
+ }
+ pDb->pCollateNeeded = Tcl_DuplicateObj(objv[2]);
+ Tcl_IncrRefCount(pDb->pCollateNeeded);
+ sqlite3_collation_needed(pDb->db, pDb, tclCollateNeeded);
+ break;
+ }
+
} /* End of the SWITCH statement */
return rc;
}
Md5_Register(p->db);
}
#endif
+ p->interp = interp;
return TCL_OK;
}
** This file contains C code routines that are called by the parser
** to handle UPDATE statements.
**
-** $Id: update.c,v 1.81 2004/05/29 11:24:50 danielk1977 Exp $
+** $Id: update.c,v 1.82 2004/06/10 10:50:45 danielk1977 Exp $
*/
#include "sqliteInt.h"
}
}
if( i<pIdx->nColumn ){
+ if( sqlite3CheckIndexCollSeq(pParse, pIdx) ) goto update_cleanup;
apIdx[nIdx++] = pIdx;
aIdxUsed[j] = 1;
}else{