1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-07 02:42:48 +03:00

Add the sqlite3_collation_needed() API and fix some error handling cases

involving unknown collation sequences. (CVS 1562)

FossilOrigin-Name: edf069b9f4044ed2a80962c7722052bf1b80bf45
This commit is contained in:
danielk1977
2004-06-10 10:50:08 +00:00
parent 0de0bb3360
commit 7cedc8d4d6
13 changed files with 337 additions and 113 deletions

View File

@@ -1,5 +1,5 @@
C Misc\sfixes\sfor\stest\scases\sfailing\sdue\sto\sthe\snew\slocking\smodel.\s(CVS\s1561) C Add\sthe\ssqlite3_collation_needed()\sAPI\sand\sfix\ssome\serror\shandling\scases\ninvolving\sunknown\scollation\ssequences.\s(CVS\s1562)
D 2004-06-10T05:59:25 D 2004-06-10T10:50:08
F Makefile.in ab7b0d5118e2da97bac66be8684a1034e3500f5a F Makefile.in ab7b0d5118e2da97bac66be8684a1034e3500f5a
F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457 F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457
F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
@@ -27,17 +27,17 @@ F src/attach.c 93b8ecec4a8d7b4e9f2479e2327d90c9d01765e8
F src/auth.c 5c2f0bea4729c98c2be3b69d6b466fc51448fe79 F src/auth.c 5c2f0bea4729c98c2be3b69d6b466fc51448fe79
F src/btree.c 281af87aa117de024f5b6c2728a2339cba9ef584 F src/btree.c 281af87aa117de024f5b6c2728a2339cba9ef584
F src/btree.h 589427ac13bb544d298cd99726e2572a6fe4bdaa F src/btree.h 589427ac13bb544d298cd99726e2572a6fe4bdaa
F src/build.c 5d958f480d71f56981f262de6994a4d2ee6e5f75 F src/build.c 4b1a23d919fe01549702f7f1bfe7f8b656e77a17
F src/date.c 8e6fa3173386fb29fdef012ee08a853c1e9908b2 F src/date.c 8e6fa3173386fb29fdef012ee08a853c1e9908b2
F src/delete.c b30f08250c9ed53a25a13c7c04599c1e8753992d F src/delete.c 911221aadb35d610c84fadb32e71c52990827e58
F src/encode.c a876af473d1d636faa3dca51c7571f2e007eea37 F src/encode.c a876af473d1d636faa3dca51c7571f2e007eea37
F src/expr.c 3aea8faac17debea4f5c2659351c27d5660453a0 F src/expr.c 34e63e960ab8ca9e4fc4a1f41b0a3b77df2ae167
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 68c7f3ddd6a7f1e5596d6996da1a2861b3789a3a
F src/legacy.c ad23746f15f67e34577621b1875f639c94839e1f F src/legacy.c ad23746f15f67e34577621b1875f639c94839e1f
F src/main.c cb41777e75f6b95a2af42f439c78e761a49cdffa F src/main.c 335b4cd48af0011017e33a411aea307553114e67
F src/md5.c 4302e84ae516c616bb079c4e6d038c0addb33481 F src/md5.c 4302e84ae516c616bb079c4e6d038c0addb33481
F src/os.h 23c69c5084e71b5fe199ff1c4e35a4aded0f1380 F src/os.h 23c69c5084e71b5fe199ff1c4e35a4aded0f1380
F src/os_common.h 6393ac67a3a7b4aea19ff17529980ecf77eb2348 F src/os_common.h 6393ac67a3a7b4aea19ff17529980ecf77eb2348
@@ -50,15 +50,15 @@ F src/os_win.h 004eec47b1780fcaf07420ddc2072294b698d48c
F src/pager.c d852730901441babf6cd16fc528dd6eecc2b2eab F src/pager.c d852730901441babf6cd16fc528dd6eecc2b2eab
F src/pager.h ca8f293e1d623a7c628a1c5e0c6cf43d5bbb80bf F src/pager.h ca8f293e1d623a7c628a1c5e0c6cf43d5bbb80bf
F src/parse.y 097438674976355a10cf177bd97326c548820b86 F src/parse.y 097438674976355a10cf177bd97326c548820b86
F src/pragma.c 6ab13748a415bf8e8f2dd79e5f713fbe72dfd3f4 F src/pragma.c 0bc3adea28df802074996bec067d506d55d28f84
F src/printf.c 63b15f1ea9fe3daa066bb7430fd20d4a2d717dc8 F src/printf.c 63b15f1ea9fe3daa066bb7430fd20d4a2d717dc8
F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3 F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3
F src/select.c 1f8355e702f109f6771f82a9bfe7aac4c82cbaf2 F src/select.c 6cb407796dde0e8f27450ead68856eb9f8188789
F src/shell.c ca519519dcbbc582f6d88f7d0e7583b857fd3469 F src/shell.c ca519519dcbbc582f6d88f7d0e7583b857fd3469
F src/sqlite.h.in 00ce6b80cf4dffa9bf7a028d80d1ffba708b175a F src/sqlite.h.in 2b6afe1de6935d3dfbd6042f46a62f1b7c3b3992
F src/sqliteInt.h cd9db5ca4a2ba59cf1692fcbd1ea7318c50f0c4f F src/sqliteInt.h 6be535d420f99c57f29f13c3c2d6a3497432b366
F src/table.c af14284fa36c8d41f6829e3f2819dce07d3e2de2 F src/table.c af14284fa36c8d41f6829e3f2819dce07d3e2de2
F src/tclsqlite.c 6383ba7b620b276d49b40d48872502e0adb1b685 F src/tclsqlite.c e974c0b2479ed37334aeb268de331e0a1b21b5a8
F src/test1.c f78d6ac0675bc5db48dac9c5379c965bdadb9113 F src/test1.c f78d6ac0675bc5db48dac9c5379c965bdadb9113
F src/test2.c 05f810c90cf6262d5f352860e87d41a3f34207f9 F src/test2.c 05f810c90cf6262d5f352860e87d41a3f34207f9
F src/test3.c beafd0ccf7b9ae784744be1b1e66ffe8f64c25da F src/test3.c beafd0ccf7b9ae784744be1b1e66ffe8f64c25da
@@ -66,7 +66,7 @@ F src/test4.c a921a69821fd30209589228e64f94e9f715b6fe2
F src/test5.c 862784cd7a68e7d36f00287aac6e413ca996eaf8 F src/test5.c 862784cd7a68e7d36f00287aac6e413ca996eaf8
F src/tokenize.c 183c5d7da11affab5d70d903d33409c8c0ce6c5b F src/tokenize.c 183c5d7da11affab5d70d903d33409c8c0ce6c5b
F src/trigger.c d1a4d7a59b34c811bf6070d64d0497baa0140dcf F src/trigger.c d1a4d7a59b34c811bf6070d64d0497baa0140dcf
F src/update.c 259f06e7b22c684b2d3dda54a18185892d6e9573 F src/update.c 168b6d523087ca4545b74ec9f3102b1f3c6b1e38
F src/utf.c c2c8e445bfea724f3502609d6389fe66651f02ab F src/utf.c c2c8e445bfea724f3502609d6389fe66651f02ab
F src/util.c e8629f04d920ae968fced709dc7a3a2c62b65ac4 F src/util.c e8629f04d920ae968fced709dc7a3a2c62b65ac4
F src/vacuum.c b921eb778842592e1fb48a9d4cef7e861103878f F src/vacuum.c b921eb778842592e1fb48a9d4cef7e861103878f
@@ -218,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 adb2bd61436927d37b23bae857089d62e12397af P 71e98d0d089576433c4b06dcba1c57063bd366f5
R e8b127567100f827cb21e845b744b7ae R 3d4ef809458f49528c446bf513dcad92
U danielk1977 U danielk1977
Z 7c95f2d087a4836fb9faba67d8f7b64b Z b84856b016de718871cfb8d15d69b3b5

View File

@@ -1 +1 @@
71e98d0d089576433c4b06dcba1c57063bd366f5 edf069b9f4044ed2a80962c7722052bf1b80bf45

View File

@@ -23,7 +23,7 @@
** ROLLBACK ** ROLLBACK
** PRAGMA ** 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 "sqliteInt.h"
#include <ctype.h> #include <ctype.h>
@@ -884,7 +884,8 @@ static CollSeq * findCollSeqEntry(
pColl[1].enc = TEXT_Utf16le; pColl[1].enc = TEXT_Utf16le;
pColl[2].zName = (char*)&pColl[3]; pColl[2].zName = (char*)&pColl[3];
pColl[2].enc = TEXT_Utf16be; 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); sqlite3HashInsert(&db->aCollSeq, pColl[0].zName, nName, pColl);
} }
} }
@@ -922,6 +923,110 @@ CollSeq *sqlite3FindCollSeq(
return 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 ** This function returns the collation sequence for database native text
** encoding identified by the string zName, length nName. ** encoding identified by the string zName, length nName.
@@ -938,64 +1043,33 @@ CollSeq *sqlite3FindCollSeq(
*/ */
CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char *zName, int nName){ CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char *zName, int nName){
u8 enc = pParse->db->enc; u8 enc = pParse->db->enc;
CollSeq *pColl = sqlite3FindCollSeq(pParse->db, enc, zName, nName, 0); u8 initbusy = pParse->db->init.busy;
if( !pColl || !pColl->xCmp ){ 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. /* No collation sequence of this type for this encoding is registered.
** Call the collation factory to see if it can supply us with one. ** Call the collation factory to see if it can supply us with one.
*/ */
callCollNeeded(pParse->db, zName, nName);
/* FIX ME: Actually call collation factory, then call
** sqlite3FindCollSeq() again. */
pColl = sqlite3FindCollSeq(pParse->db, enc, zName, nName, 0); pColl = sqlite3FindCollSeq(pParse->db, enc, zName, nName, 0);
if( pColl && !pColl->xCmp ){ if( pColl && !pColl->xCmp ){
/* The collation factory failed to deliver a function but there are /* There may be a version of the collation sequence that requires
** other versions of this collation function (for other text ** translation between encodings. Search for it with synthCollSeq().
** encodings) available. Use one of these instead. Avoid a
** UTF-8 <-> UTF-16 conversion if possible.
*/ */
CollSeq *pColl2 = 0; if( synthCollSeq(pParse, pColl) ){
switch( enc ){ return 0;
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 nothing has been found, write the error message into pParse */ /* If nothing has been found, write the error message into pParse */
if( !pColl || !pColl->xCmp ){ if( !initbusy && (!pColl || !pColl->xCmp) ){
if( pParse->nErr==0 ){ if( pParse->nErr==0 ){
sqlite3SetNString(&pParse->zErrMsg, "no such collation sequence: ", -1, sqlite3SetNString(&pParse->zErrMsg, "no such collation sequence: ", -1,
zName, nName, 0); zName, nName, 0);
} }
pParse->nErr++; pParse->nErr++;
pColl = 0;
} }
return pColl; return pColl;
} }
@@ -1943,6 +2017,11 @@ void sqlite3CreateIndex(
pIndex->keyInfo.aColl[i] = pTab->aCol[j].pColl; pIndex->keyInfo.aColl[i] = pTab->aCol[j].pColl;
} }
assert( pIndex->keyInfo.aColl[i] ); assert( pIndex->keyInfo.aColl[i] );
if( !db->init.busy &&
sqlite3CheckCollSeq(pParse, pIndex->keyInfo.aColl[i])
){
goto exit_create_index;
}
} }
pIndex->keyInfo.nField = pList->nExpr; pIndex->keyInfo.nField = pList->nExpr;
@@ -2448,7 +2527,6 @@ void sqlite3CodeVerifySchema(Parse *pParse, int iDb){
** specified auxiliary database and the temp database are made writable. ** specified auxiliary database and the temp database are made writable.
*/ */
void sqlite3BeginWriteOperation(Parse *pParse, int setStatement, int iDb){ void sqlite3BeginWriteOperation(Parse *pParse, int setStatement, int iDb){
sqlite *db = pParse->db;
Vdbe *v = sqlite3GetVdbe(pParse); Vdbe *v = sqlite3GetVdbe(pParse);
if( v==0 ) return; if( v==0 ) return;
sqlite3CodeVerifySchema(pParse, iDb); sqlite3CodeVerifySchema(pParse, iDb);

View File

@@ -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 DELETE FROM statements. ** 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" #include "sqliteInt.h"
@@ -193,6 +193,13 @@ void sqlite3DeleteFrom(
** the table and pick which records to delete. ** the table and pick which records to delete.
*/ */
else{ 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 /* Begin the database scan
*/ */
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 1, 0); pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 1, 0);

View File

@@ -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.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 "sqliteInt.h"
#include <ctype.h> #include <ctype.h>
@@ -59,14 +59,18 @@ char sqlite3ExprAffinity(Expr *pExpr){
** Return the default collation sequence for the expression pExpr. If ** Return the default collation sequence for the expression pExpr. If
** there is no default collation type, return 0. ** 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 ){
if( pExpr->pColl ) return pExpr->pColl; pColl = pExpr->pColl;
if( pExpr->op==TK_AS ){ if( pExpr->op==TK_AS && !pColl ){
return sqlite3ExprCollSeq(pExpr->pLeft); return sqlite3ExprCollSeq(pParse, pExpr->pLeft);
} }
} }
return 0; if( sqlite3CheckCollSeq(pParse, pColl) ){
pColl = 0;
}
return pColl;
} }
/* /*
@@ -157,10 +161,10 @@ static int binaryCompareP1(Expr *pExpr1, Expr *pExpr2, int jumpIfNull){
** is used, or the default (BINARY) if neither expression has a collating ** is used, or the default (BINARY) if neither expression has a collating
** type. ** type.
*/ */
static CollSeq* binaryCompareCollSeq(Expr *pLeft, Expr *pRight){ static CollSeq* binaryCompareCollSeq(Parse *pParse, Expr *pLeft, Expr *pRight){
CollSeq *pColl = sqlite3ExprCollSeq(pLeft); CollSeq *pColl = sqlite3ExprCollSeq(pParse, pLeft);
if( !pColl ){ if( !pColl ){
pColl = sqlite3ExprCollSeq(pRight); pColl = sqlite3ExprCollSeq(pParse, pRight);
} }
return pColl; return pColl;
} }
@@ -868,7 +872,7 @@ int sqlite3ExprResolveIds(
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 ){ 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); pExpr->pSelect->pEList->a[0].pExpr);
} }
}else if( pExpr->pList ){ }else if( pExpr->pList ){
@@ -1195,7 +1199,7 @@ 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); CollSeq *p3 = binaryCompareCollSeq(pParse, pExpr->pLeft, pExpr->pRight);
sqlite3ExprCode(pParse, pExpr->pLeft); sqlite3ExprCode(pParse, pExpr->pLeft);
sqlite3ExprCode(pParse, pExpr->pRight); sqlite3ExprCode(pParse, pExpr->pRight);
sqlite3VdbeOp3(v, op, p1, 0, (void *)p3, P3_COLLSEQ); sqlite3VdbeOp3(v, op, p1, 0, (void *)p3, P3_COLLSEQ);
@@ -1326,12 +1330,12 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
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);
p1 = binaryCompareP1(pExpr->pLeft, pExpr->pList->a[0].pExpr, 0); 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); 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);
p1 = binaryCompareP1(pExpr->pLeft, pExpr->pList->a[1].pExpr, 0); 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); sqlite3VdbeOp3(v, OP_Le, p1, 0, (void *)p3, P3_COLLSEQ);
sqlite3VdbeAddOp(v, OP_And, 0, 0); sqlite3VdbeAddOp(v, OP_And, 0, 0);
break; break;
@@ -1360,7 +1364,7 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
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); 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); pExpr->pList->a[i].pExpr);
sqlite3VdbeAddOp(v, OP_Dup, 1, 1); sqlite3VdbeAddOp(v, OP_Dup, 1, 1);
jumpInst = sqlite3VdbeOp3(v, OP_Ne, p1, 0, (void *)p3, P3_COLLSEQ); jumpInst = sqlite3VdbeOp3(v, OP_Ne, p1, 0, (void *)p3, P3_COLLSEQ);
@@ -1476,7 +1480,7 @@ 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); CollSeq *p3 = binaryCompareCollSeq(pParse, pExpr->pLeft, pExpr->pRight);
sqlite3ExprCode(pParse, pExpr->pLeft); sqlite3ExprCode(pParse, pExpr->pLeft);
sqlite3ExprCode(pParse, pExpr->pRight); sqlite3ExprCode(pParse, pExpr->pRight);
sqlite3VdbeOp3(v, op, p1, dest, (void *)p3, P3_COLLSEQ); sqlite3VdbeOp3(v, op, p1, dest, (void *)p3, P3_COLLSEQ);
@@ -1502,12 +1506,12 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
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);
p1 = binaryCompareP1(pExpr->pLeft, pExpr->pList->a[0].pExpr, !jumpIfNull); 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); 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);
p1 = binaryCompareP1(pExpr->pLeft, pExpr->pList->a[1].pExpr, jumpIfNull); 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); sqlite3VdbeOp3(v, OP_Le, p1, dest, (void *)p3, P3_COLLSEQ);
sqlite3VdbeAddOp(v, OP_Integer, 0, 0); sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
@@ -1570,7 +1574,7 @@ 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); CollSeq *p3 = binaryCompareCollSeq(pParse, pExpr->pLeft, pExpr->pRight);
sqlite3ExprCode(pParse, pExpr->pLeft); sqlite3ExprCode(pParse, pExpr->pLeft);
sqlite3ExprCode(pParse, pExpr->pRight); sqlite3ExprCode(pParse, pExpr->pRight);
sqlite3VdbeOp3(v, op, p1, dest, (void *)p3, P3_COLLSEQ); sqlite3VdbeOp3(v, op, p1, dest, (void *)p3, P3_COLLSEQ);
@@ -1597,13 +1601,13 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
sqlite3ExprCode(pParse, pExpr->pList->a[0].pExpr); sqlite3ExprCode(pParse, pExpr->pList->a[0].pExpr);
addr = sqlite3VdbeCurrentAddr(v); addr = sqlite3VdbeCurrentAddr(v);
p1 = binaryCompareP1(pExpr->pLeft, pExpr->pList->a[0].pExpr, !jumpIfNull); 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); 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);
p1 = binaryCompareP1(pExpr->pLeft, pExpr->pList->a[1].pExpr, jumpIfNull); 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); sqlite3VdbeOp3(v, OP_Gt, p1, dest, (void *)p3, P3_COLLSEQ);
break; break;
} }

View File

@@ -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 INSERT statements in SQLite. ** 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" #include "sqliteInt.h"
@@ -234,6 +234,13 @@ void sqlite3Insert(
goto insert_cleanup; 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 /* Allocate a VDBE
*/ */
v = sqlite3GetVdbe(pParse); v = sqlite3GetVdbe(pParse);

View File

@@ -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.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 "sqliteInt.h"
#include "os.h" #include "os.h"
@@ -1217,3 +1217,25 @@ int sqlite3_create_collation16(
sqliteFree(zName8); sqliteFree(zName8);
return rc; 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;
}

View File

@@ -11,7 +11,7 @@
************************************************************************* *************************************************************************
** This file contains code used to implement the PRAGMA command. ** 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 "sqliteInt.h"
#include <ctype.h> #include <ctype.h>
@@ -655,6 +655,7 @@ void sqlite3Pragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){
sqlite3VdbeAddOp(v, OP_Integer, pTab->tnum, 0); sqlite3VdbeAddOp(v, OP_Integer, pTab->tnum, 0);
cnt++; cnt++;
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
if( sqlite3CheckIndexCollSeq(pParse, pIdx) ) return;
sqlite3VdbeAddOp(v, OP_Integer, pIdx->tnum, 0); sqlite3VdbeAddOp(v, OP_Integer, pIdx->tnum, 0);
cnt++; cnt++;
} }

View File

@@ -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.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" #include "sqliteInt.h"
@@ -550,7 +550,7 @@ static void generateSortTail(
** is stored in pOrderBy->a[i].zName. Otherwise, use the default ** is stored in pOrderBy->a[i].zName. Otherwise, use the default
** collation type for the expression. ** 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] ){ if( !pInfo->aColl[i] ){
pInfo->aColl[i] = db->pDfltColl; pInfo->aColl[i] = db->pDfltColl;
} }
@@ -825,7 +825,7 @@ 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); pTab->aCol[i].pColl = sqlite3ExprCollSeq(pParse, p);
if( !pTab->aCol[i].pColl ){ if( !pTab->aCol[i].pColl ){
pTab->aCol[i].pColl = pParse->db->pDfltColl; pTab->aCol[i].pColl = pParse->db->pDfltColl;
} }
@@ -2233,21 +2233,6 @@ 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);
@@ -2323,6 +2308,21 @@ int sqlite3Select(
return rc; 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. /* Set the limiter.
*/ */
computeLimitRegisters(pParse, p); computeLimitRegisters(pParse, p);

View File

@@ -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.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_ #ifndef _SQLITE_H_
#define _SQLITE_H_ #define _SQLITE_H_
@@ -967,21 +967,84 @@ void sqlite3_result_value(sqlite3_context*, sqlite3_value*);
#define SQLITE_UTF16LE 2 #define SQLITE_UTF16LE 2
#define SQLITE_UTF16BE 3 #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( int sqlite3_create_collation(
sqlite3*, sqlite3*,
const char *zName, const char *zName,
int enc, int eTextRep,
void*, void*,
int(*xCompare)(void*,int,const void*,int,const void*) int(*xCompare)(void*,int,const void*,int,const void*)
); );
int sqlite3_create_collation16( int sqlite3_create_collation16(
sqlite3*, sqlite3*,
const char *zName, const char *zName,
int enc, int eTextRep,
void*, void*,
int(*xCompare)(void*,int,const void*,int,const 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 #ifdef __cplusplus
} /* End of the 'extern "C"' block */ } /* End of the 'extern "C"' block */

View File

@@ -11,7 +11,7 @@
************************************************************************* *************************************************************************
** Internal interface definitions for SQLite. ** 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 "config.h"
#include "sqlite3.h" #include "sqlite3.h"
@@ -423,6 +423,9 @@ struct sqlite {
u8 enc; /* Text encoding for this database. */ u8 enc; /* Text encoding for this database. */
u8 autoCommit; /* The auto-commit flag. */ u8 autoCommit; /* The auto-commit flag. */
int nMaster; /* Length of master journal name. -1=unknown */ 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;
}; };
/* /*
@@ -1395,4 +1398,6 @@ int sqlite3ReadUniChar(const char *zStr, int *pOffset, u8 *pEnc, int fold);
int sqlite3ReadSchema(sqlite *db, char **); int sqlite3ReadSchema(sqlite *db, char **);
CollSeq *sqlite3FindCollSeq(sqlite *,u8 enc, const char *,int,int); CollSeq *sqlite3FindCollSeq(sqlite *,u8 enc, const char *,int,int);
CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char *zName, int nName); 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 *);

View File

@@ -11,7 +11,7 @@
************************************************************************* *************************************************************************
** A TCL Interface to SQLite ** 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 */ #ifndef NO_TCL /* Omit this whole file if TCL is unavailable */
@@ -70,6 +70,7 @@ struct SqliteDb {
SqlCollate *pCollate; /* List of SQL collation 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 */
Tcl_Obj *pCollateNeeded; /* Collation needed script */
}; };
/* /*
@@ -217,6 +218,20 @@ static int DbCommitHandler(void *cd){
return 0; 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 ** This routine is called to evaluate an SQL collation function implemented
** using TCL script. ** using TCL script.
@@ -382,7 +397,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", "collate", "trace", "collate", "collation_needed",
0 0
}; };
enum DB_enum { enum DB_enum {
@@ -391,7 +406,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_COLLATE DB_TRACE, DB_COLLATE, DB_COLLATION_NEEDED
}; };
if( objc<2 ){ if( objc<2 ){
@@ -924,6 +939,26 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
break; 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 */ } /* End of the SWITCH statement */
return rc; return rc;
} }
@@ -1051,6 +1086,7 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
Md5_Register(p->db); Md5_Register(p->db);
} }
#endif #endif
p->interp = interp;
return TCL_OK; return TCL_OK;
} }

View File

@@ -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 UPDATE statements. ** 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" #include "sqliteInt.h"
@@ -179,6 +179,7 @@ void sqlite3Update(
} }
} }
if( i<pIdx->nColumn ){ if( i<pIdx->nColumn ){
if( sqlite3CheckIndexCollSeq(pParse, pIdx) ) goto update_cleanup;
apIdx[nIdx++] = pIdx; apIdx[nIdx++] = pIdx;
aIdxUsed[j] = 1; aIdxUsed[j] = 1;
}else{ }else{