Or the SQLITE_UTF16_ALIGNED with the encoding field in

sqlite3_create_collation and UTF16 strings will always be aligned
on an even byte boundary when passed into the comparison function. (CVS 3103)

FossilOrigin-Name: 7a1701e8c562087d364dff28cd7cad7ca4cdb5ae
This commit is contained in:
drh
2006-02-16 18:16:36 +00:00
parent 7e310a420b
commit 7d9bd4e19e
8 changed files with 203 additions and 51 deletions
+10 -12
View File
@@ -14,7 +14,7 @@
** other files are for internal use by SQLite and should not be
** accessed by users of the library.
**
** $Id: main.c,v 1.334 2006/02/09 13:43:29 danielk1977 Exp $
** $Id: main.c,v 1.335 2006/02/16 18:16:37 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"
@@ -743,6 +743,7 @@ static int createCollation(
int(*xCompare)(void*,int,const void*,int,const void*)
){
CollSeq *pColl;
int enc2;
if( sqlite3SafetyCheck(db) ){
return SQLITE_MISUSE;
@@ -752,15 +753,13 @@ static int createCollation(
** to one of SQLITE_UTF16LE or SQLITE_UTF16BE using the
** SQLITE_UTF16NATIVE macro. SQLITE_UTF16 is not used internally.
*/
if( enc==SQLITE_UTF16 ){
enc = SQLITE_UTF16NATIVE;
enc2 = enc & ~SQLITE_UTF16_ALIGNED;
if( enc2==SQLITE_UTF16 ){
enc2 = SQLITE_UTF16NATIVE;
}
if( enc!=SQLITE_UTF8 && enc!=SQLITE_UTF16LE && enc!=SQLITE_UTF16BE ){
sqlite3Error(db, SQLITE_ERROR,
"Param 3 to sqlite3_create_collation() must be one of "
"SQLITE_UTF8, SQLITE_UTF16, SQLITE_UTF16LE or SQLITE_UTF16BE"
);
if( (enc2&~3)!=0 ){
sqlite3Error(db, SQLITE_ERROR, "unknown encoding");
return SQLITE_ERROR;
}
@@ -768,7 +767,7 @@ static int createCollation(
** sequence. If so, and there are active VMs, return busy. If there
** are no active VMs, invalidate any pre-compiled statements.
*/
pColl = sqlite3FindCollSeq(db, (u8)enc, zName, strlen(zName), 0);
pColl = sqlite3FindCollSeq(db, (u8)enc2, zName, strlen(zName), 0);
if( pColl && pColl->xCmp ){
if( db->activeVdbeCnt ){
sqlite3Error(db, SQLITE_BUSY,
@@ -778,11 +777,11 @@ static int createCollation(
sqlite3ExpirePreparedStatements(db);
}
pColl = sqlite3FindCollSeq(db, (u8)enc, zName, strlen(zName), 1);
pColl = sqlite3FindCollSeq(db, (u8)enc2, zName, strlen(zName), 1);
if( pColl ){
pColl->xCmp = xCompare;
pColl->pUser = pCtx;
pColl->enc = enc;
pColl->enc = enc2 | (enc & SQLITE_UTF16_ALIGNED);
}
sqlite3Error(db, SQLITE_OK, 0);
return SQLITE_OK;
@@ -1230,4 +1229,3 @@ error_out:
return sqlite3ApiExit(db, rc);
}
#endif
+7 -6
View File
@@ -12,7 +12,7 @@
** This header file defines the interface that the SQLite library
** presents to client programs.
**
** @(#) $Id: sqlite.h.in,v 1.162 2006/02/10 03:06:10 danielk1977 Exp $
** @(#) $Id: sqlite.h.in,v 1.163 2006/02/16 18:16:37 drh Exp $
*/
#ifndef _SQLITE3_H_
#define _SQLITE3_H_
@@ -1114,11 +1114,12 @@ void sqlite3_result_value(sqlite3_context*, sqlite3_value*);
** These are the allowed values for the eTextRep argument to
** sqlite3_create_collation and sqlite3_create_function.
*/
#define SQLITE_UTF8 1
#define SQLITE_UTF16LE 2
#define SQLITE_UTF16BE 3
#define SQLITE_UTF16 4 /* Use native byte order */
#define SQLITE_ANY 5 /* sqlite3_create_function only */
#define SQLITE_UTF8 1
#define SQLITE_UTF16LE 2
#define SQLITE_UTF16BE 3
#define SQLITE_UTF16 4 /* Use native byte order */
#define SQLITE_ANY 5 /* sqlite3_create_function only */
#define SQLITE_UTF16_ALIGNED 8 /* sqlite3_create_collation only */
/*
** These two functions are used to add new collation sequences to the
+1 -7
View File
@@ -11,7 +11,7 @@
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.483 2006/02/15 21:19:01 drh Exp $
** @(#) $Id: sqliteInt.h,v 1.484 2006/02/16 18:16:37 drh Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_
@@ -251,12 +251,6 @@ struct BusyHandler {
#include "btree.h"
#include "pager.h"
/*
** This macro casts a pointer to an integer. Useful for doing
** pointer arithmetic.
*/
#define Addr(X) ((uptr)X)
#ifdef SQLITE_MEMDEBUG
/*
** The following global variables are used for testing and debugging
+54 -2
View File
@@ -13,7 +13,7 @@
** is not included in the SQLite library. It is used for automated
** testing of the SQLite library.
**
** $Id: test1.c,v 1.206 2006/02/10 03:06:10 danielk1977 Exp $
** $Id: test1.c,v 1.207 2006/02/16 18:16:37 drh Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
@@ -1529,7 +1529,56 @@ bad_args:
Tcl_WrongNumArgs(interp, 1, objv, "DB");
return TCL_ERROR;
}
#endif /* SQLITE_OMIT_UTF16 */
/*
** tclcmd: add_alignment_test_collations DB
**
** Add two new collating sequences to the database DB
**
** utf16_aligned
** utf16_unaligned
**
** Both collating sequences use the same sort order as BINARY.
** The only difference is that the utf16_aligned collating
** sequence is declared with the SQLITE_UTF16_ALIGNED flag.
** Both collating functions increment the unaligned utf16 counter
** whenever they see a string that begins on an odd byte boundary.
*/
static int unaligned_string_counter = 0;
static int alignmentCollFunc(
void *NotUsed,
int nKey1, const void *pKey1,
int nKey2, const void *pKey2
){
int rc, n;
n = nKey1<nKey2 ? nKey1 : nKey2;
if( nKey1>0 && 1==(1&(int)pKey1) ) unaligned_string_counter++;
if( nKey2>0 && 1==(1&(int)pKey2) ) unaligned_string_counter++;
rc = memcmp(pKey1, pKey2, n);
if( rc==0 ){
rc = nKey1 - nKey2;
}
return rc;
}
static int add_alignment_test_collations(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
sqlite3 *db;
if( objc>=2 ){
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
sqlite3_create_collation(db, "utf16_unaligned",
SQLITE_UTF16,
0, alignmentCollFunc);
sqlite3_create_collation(db, "utf16_aligned",
SQLITE_UTF16 | SQLITE_UTF16_ALIGNED,
0, alignmentCollFunc);
}
return SQLITE_OK;
}
#endif /* !defined(SQLITE_OMIT_UTF16) */
/*
** Usage: add_test_function <db ptr> <utf8> <utf16le> <utf16be>
@@ -3582,6 +3631,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "sqlite3_column_text16", test_stmt_utf16, sqlite3_column_text16 },
{ "sqlite3_column_decltype16", test_stmt_utf16, sqlite3_column_decltype16},
{ "sqlite3_column_name16", test_stmt_utf16, sqlite3_column_name16 },
{ "add_alignment_test_collations", add_alignment_test_collations, 0 },
#ifdef SQLITE_ENABLE_COLUMN_METADATA
{"sqlite3_column_database_name16",
test_stmt_utf16, sqlite3_column_database_name16},
@@ -3667,6 +3717,8 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
(char*)&sqlite3_os_trace, TCL_LINK_INT);
Tcl_LinkVar(interp, "sqlite3_tsd_count",
(char*)&sqlite3_tsd_count, TCL_LINK_INT);
Tcl_LinkVar(interp, "unaligned_string_counter",
(char*)&unaligned_string_counter, TCL_LINK_INT);
#if OS_UNIX && defined(SQLITE_TEST) && defined(THREADSAFE) && THREADSAFE
Tcl_LinkVar(interp, "threadsOverrideEachOthersLocks",
(char*)&threadsOverrideEachOthersLocks, TCL_LINK_INT);
+35 -13
View File
@@ -42,6 +42,7 @@ int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){
return SQLITE_ERROR;
#else
/* MemTranslate() may return SQLITE_OK or SQLITE_NOMEM. If NOMEM is returned,
** then the encoding of the value may not have changed.
*/
@@ -596,19 +597,25 @@ int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const CollSeq *pColl){
if( pColl ){
if( pMem1->enc==pColl->enc ){
/* The strings are already in the correct encoding. Call the
** comparison function directly */
return pColl->xCmp(pColl->pUser,pMem1->n,pMem1->z,pMem2->n,pMem2->z);
}else{
u8 origEnc = pMem1->enc;
rc = pColl->xCmp(
pColl->pUser,
sqlite3ValueBytes((sqlite3_value*)pMem1, pColl->enc),
sqlite3ValueText((sqlite3_value*)pMem1, pColl->enc),
sqlite3ValueBytes((sqlite3_value*)pMem2, pColl->enc),
sqlite3ValueText((sqlite3_value*)pMem2, pColl->enc)
);
sqlite3ValueBytes((sqlite3_value*)pMem1, origEnc);
const void *v1, *v2;
int n1, n2;
/* Convert the strings into the encoding that the comparison
** function expects */
v1 = sqlite3ValueText((sqlite3_value*)pMem1, pColl->enc);
n1 = v1==0 ? 0 : pMem1->n;
assert( n1==sqlite3ValueBytes((sqlite3_value*)pMem1, pColl->enc) );
v2 = sqlite3ValueText((sqlite3_value*)pMem2, pColl->enc);
n2 = v2==0 ? 0 : pMem2->n;
assert( n2==sqlite3ValueBytes((sqlite3_value*)pMem2, pColl->enc) );
/* Do the comparison */
rc = pColl->xCmp(pColl->pUser, n1, v1, n2, v2);
/* Convert the strings back into the database encoding */
sqlite3ValueText((sqlite3_value*)pMem1, origEnc);
sqlite3ValueBytes((sqlite3_value*)pMem2, origEnc);
sqlite3ValueText((sqlite3_value*)pMem2, origEnc);
return rc;
}
@@ -752,10 +759,14 @@ void sqlite3VdbeMemSanity(Mem *pMem, u8 db_enc){
** except the data returned is in the encoding specified by the second
** parameter, which must be one of SQLITE_UTF16BE, SQLITE_UTF16LE or
** SQLITE_UTF8.
**
** (2006-02-16:) The enc value can be or-ed with SQLITE_UTF16_ALIGNED.
** If that is the case, then the result must be aligned on an even byte
** boundary.
*/
const void *sqlite3ValueText(sqlite3_value* pVal, u8 enc){
if( !pVal ) return 0;
assert( enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE || enc==SQLITE_UTF8);
assert( (enc&3)==(enc&~SQLITE_UTF16_ALIGNED) );
if( pVal->flags&MEM_Null ){
return 0;
@@ -763,12 +774,23 @@ const void *sqlite3ValueText(sqlite3_value* pVal, u8 enc){
assert( (MEM_Blob>>3) == MEM_Str );
pVal->flags |= (pVal->flags & MEM_Blob)>>3;
if( pVal->flags&MEM_Str ){
sqlite3VdbeChangeEncoding(pVal, enc);
sqlite3VdbeChangeEncoding(pVal, enc & ~SQLITE_UTF16_ALIGNED);
if( (enc & SQLITE_UTF16_ALIGNED)!=0 && 1==(1&(int)pVal->z) ){
assert( (pVal->flags & (MEM_Ephem|MEM_Static))!=0 );
if( sqlite3VdbeMemMakeWriteable(pVal)!=SQLITE_OK ){
return 0;
}
}
}else if( !(pVal->flags&MEM_Blob) ){
sqlite3VdbeMemStringify(pVal, enc);
assert( 0==(1&(int)pVal->z) );
}
assert(pVal->enc==(enc & ~SQLITE_UTF16_ALIGNED) || sqlite3MallocFailed() );
if( pVal->enc==(enc & ~SQLITE_UTF16_ALIGNED) ){
return pVal->z;
}else{
return 0;
}
assert(pVal->enc==enc || sqlite3MallocFailed() );
return (const void *)(pVal->enc==enc ? (pVal->z) : 0);
}
/*