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:
+10
-12
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user