diff --git a/manifest b/manifest index 27ab9e542f..135e363efd 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sproblems\swith\stypes\sand\sthe\srecognition\sof\sBLOB\sas\shaving\sno\saffinity.\s(CVS\s1418) -D 2004-05-20T12:41:20 +C sqlite3MemCompare\snow\stakes\sa\sCollSeq*\sargument.\s(CVS\s1419) +D 2004-05-20T13:54:54 F Makefile.in ab7b0d5118e2da97bac66be8684a1034e3500f5a F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd @@ -32,7 +32,7 @@ F src/copy.c 4d2038602fd0549d80c59bda27d96f13ea9b5e29 F src/date.c 0eb0a89960bb45c7f7e768748605a7a97b0c8064 F src/delete.c 2e1dda38345416a1ea1c0a6468589a7472334dac F src/encode.c a876af473d1d636faa3dca51c7571f2e007eea37 -F src/expr.c 34fceec0ae7d9108d6cf98b0685d3d2afa962728 +F src/expr.c 22ee818d11c6dec2a4d1e8117b42c59928995e49 F src/func.c cfbb7096efb58e2857e3b312a8958a12774b625a F src/hash.c 440c2f8cb373ee1b4e13a0988489c7cd95d55b6f F src/hash.h 762d95f1e567664d1eafc1687de755626be962fb @@ -64,10 +64,10 @@ F src/update.c 1f6687f8d1085f896a24c0fa13d802223ed55539 F src/utf.c c27c4f1120f7aaef00cd6942b3d9e3f4ca4fe0e4 F src/util.c 5cbeb452da09cfc7248de9948c15b14d840723f7 F src/vacuum.c c134702e023db8778e6be59ac0ea7b02315b5476 -F src/vdbe.c fe412966e48948b680a5bc25796e6e9727174b4b -F src/vdbe.h 314e9c07db73a42a6ba91ab7539e27652fc88870 -F src/vdbeInt.h 97b95c622ea467d39879ae97d07732ebb4891b76 -F src/vdbeaux.c c48157e910b16010812f67daf981141d3b913e64 +F src/vdbe.c 4aedca4e37bd4762c1ad7f90e0ababf4ad52aa29 +F src/vdbe.h e75fe13aff16cc6e840371f473762615239264e4 +F src/vdbeInt.h 69a7dd040f0656e211d4e20b3cafdcee8461107e +F src/vdbeaux.c b770802151f30589bd063f434174d230aa043406 F src/where.c 626b2cbc4290d8be6c04ad7c8395f46d4e21d0d8 F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242 F test/attach.test cb9b884344e6cfa5e165965d5b1adea679a24c83 @@ -195,7 +195,7 @@ F www/sqlite.tcl 3c83b08cf9f18aa2d69453ff441a36c40e431604 F www/tclsqlite.tcl b9271d44dcf147a93c98f8ecf28c927307abd6da F www/vdbe.tcl 9b9095d4495f37697fd1935d10e14c6015e80aa1 F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4 -P 948307f07d6f8cc1cc186167ff7aaa5dfd5d8a2e -R 59f05a5952887901890856f7cd04108e +P 8411718f0ac17e9c2376fdf8b5fa0cc5fc88be9b +R 0120dca1e321b23f5d0817fb2f4d18f3 U drh -Z 90bb81f98be65daf25dbb23b209b7296 +Z 85c2c075127be3f9e1f00b69921810df diff --git a/manifest.uuid b/manifest.uuid index ba13805a37..e70de3aee0 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -8411718f0ac17e9c2376fdf8b5fa0cc5fc88be9b \ No newline at end of file +5c1e47a25244eacc69b688f5f4e62cec9f09665a \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index 65821bd535..1987169e0b 100644 --- a/src/expr.c +++ b/src/expr.c @@ -12,7 +12,7 @@ ** This file contains routines used for analyzing expressions and ** for generating VDBE code that evaluates expressions in SQLite. ** -** $Id: expr.c,v 1.123 2004/05/19 20:41:03 drh Exp $ +** $Id: expr.c,v 1.124 2004/05/20 13:54:54 drh Exp $ */ #include "sqliteInt.h" #include @@ -55,6 +55,11 @@ char sqlite3ExprAffinity(Expr *pExpr){ return pExpr->affinity; } +/* +** pExpr is the left operand of a comparison operator. aff2 is the +** type affinity of the right operand. This routine returns the +** type affinity that should be used for the comparison operator. +*/ char sqlite3CompareAffinity(Expr *pExpr, char aff2){ char aff1 = sqlite3ExprAffinity(pExpr); if( aff1 && aff2 ){ @@ -79,6 +84,10 @@ char sqlite3CompareAffinity(Expr *pExpr, char aff2){ } } +/* +** pExpr is a comparison operator. Return the type affinity that should +** be applied to both operands prior to doing the comparison. +*/ static char comparisonAffinity(Expr *pExpr){ char aff; assert( pExpr->op==TK_EQ || pExpr->op==TK_IN || pExpr->op==TK_LT || diff --git a/src/vdbe.c b/src/vdbe.c index 03096403d8..ee12fc4cce 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -43,7 +43,7 @@ ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. ** -** $Id: vdbe.c,v 1.307 2004/05/20 02:42:17 drh Exp $ +** $Id: vdbe.c,v 1.308 2004/05/20 13:54:54 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -1484,7 +1484,7 @@ mismatch: break; } -/* Opcode: Eq P1 P2 * +/* Opcode: Eq P1 P2 P3 ** ** Pop the top two elements from the stack. If they are equal, then ** jump to instruction P2. Otherwise, continue to the next instruction. @@ -1508,131 +1508,38 @@ mismatch: ** stack if the jump would have been taken, or a 0 if not. Push a ** NULL if either operand was NULL. ** +** If P3 is not NULL it is a pointer to a collating sequence (a CollSeq +** structure) that defines how to compare text. */ -/* Opcode: Ne P1 P2 * +/* Opcode: Ne P1 P2 P3 ** -** Pop the top two elements from the stack. If they are not equal, then -** jump to instruction P2. Otherwise, continue to the next instruction. -** -** The least significant byte of P1 may be either 0x00 or 0x01. If either -** operand is NULL (and thus if the result is unknown) then take the jump -** only if the least significant byte of P1 is 0x01. -** -** The second least significant byte of P1 must be an affinity character - -** 'n', 't', 'i' or 'o' - or 0x00. An attempt is made to coerce both values -** according to the affinity before the comparison is made. If the byte is -** 0x00, then numeric affinity is used. -** -** Once any conversions have taken place, and neither value is NULL, -** the values are compared. If both values are blobs, or both are text, -** then memcmp() is used to determine the results of the comparison. If -** both values are numeric, then a numeric comparison is used. If the -** two values are of different types, then they are inequal. -** -** If P2 is zero, do not jump. Instead, push an integer 1 onto the -** stack if the jump would have been taken, or a 0 if not. Push a -** NULL if either operand was NULL. +** This works just like the Eq opcode except that the jump is taken if +** the operands from the stack are not equal. See the Eq opcode for +** additional information. */ -/* Opcode: Lt P1 P2 * +/* Opcode: Lt P1 P2 P3 ** -** Pop the top two elements from the stack. If second element (the -** next on stack) is less than the first (the top of stack), then -** jump to instruction P2. Otherwise, continue to the next instruction. -** In other words, jump if NOSTOS. -** -** The least significant byte of P1 may be either 0x00 or 0x01. If either -** operand is NULL (and thus if the result is unknown) then take the jump -** only if the least significant byte of P1 is 0x01. -** -** The second least significant byte of P1 must be an affinity character - -** 'n', 't', 'i' or 'o' - or 0x00. An attempt is made to coerce both values -** according to the affinity before the comparison is made. If the byte is -** 0x00, then numeric affinity is used. -** -** Once any conversions have taken place, and neither value is NULL, -** the values are compared. If both values are blobs, or both are text, -** then memcmp() is used to determine the results of the comparison. If -** both values are numeric, then a numeric comparison is used. If the -** two values are of different types, then they are inequal. -** -** If P2 is zero, do not jump. Instead, push an integer 1 onto the -** stack if the jump would have been taken, or a 0 if not. Push a -** NULL if either operand was NULL. +** This works just like the Eq opcode except that the jump is taken if +** the 2nd element down on the task is greater than the top of the stack. +** See the Eq opcode for additional information. */ -/* Opcode: Ge P1 P2 * +/* Opcode: Ge P1 P2 P3 ** -** Pop the top two elements from the stack. If second element (the next -** on stack) is greater than or equal to the first (the top of stack), -** then jump to instruction P2. In other words, jump if NOS>=TOS. -** -** The least significant byte of P1 may be either 0x00 or 0x01. If either -** operand is NULL (and thus if the result is unknown) then take the jump -** only if the least significant byte of P1 is 0x01. -** -** The second least significant byte of P1 must be an affinity character - -** 'n', 't', 'i' or 'o' - or 0x00. An attempt is made to coerce both values -** according to the affinity before the comparison is made. If the byte is -** 0x00, then numeric affinity is used. -** -** Once any conversions have taken place, and neither value is NULL, -** the values are compared. If both values are blobs, or both are text, -** then memcmp() is used to determine the results of the comparison. If -** both values are numeric, then a numeric comparison is used. If the -** two values are of different types, then they are inequal. -** -** If P2 is zero, do not jump. Instead, push an integer 1 onto the -** stack if the jump would have been taken, or a 0 if not. Push a -** NULL if either operand was NULL. +** This works just like the Eq opcode except that the jump is taken if +** the 2nd element down on the task is greater than or equal to the +** top of the stack. See the Eq opcode for additional information. */ case OP_Eq: case OP_Ne: @@ -1668,7 +1575,8 @@ case OP_Ge: { applyAffinity(pNos, affinity); applyAffinity(pTos, affinity); - res = sqlite3MemCompare(pNos, pTos); + assert( pOp->p3type==P3_COLLSEQ || pOp->p3==0 ); + res = sqlite3MemCompare(pNos, pTos, (CollSeq*)pOp->p3); switch( pOp->opcode ){ case OP_Eq: res = res==0; break; case OP_Ne: res = res!=0; break; diff --git a/src/vdbe.h b/src/vdbe.h index 62db796cad..b997ce98fb 100644 --- a/src/vdbe.h +++ b/src/vdbe.h @@ -15,7 +15,7 @@ ** or VDBE. The VDBE implements an abstract machine that runs a ** simple program to access and modify the underlying database. ** -** $Id: vdbe.h,v 1.77 2004/05/18 23:21:36 drh Exp $ +** $Id: vdbe.h,v 1.78 2004/05/20 13:54:54 drh Exp $ */ #ifndef _SQLITE_VDBE_H_ #define _SQLITE_VDBE_H_ @@ -65,6 +65,7 @@ typedef struct VdbeOpList VdbeOpList; #define P3_DYNAMIC (-1) /* Pointer to a string obtained from sqliteMalloc() */ #define P3_STATIC (-2) /* Pointer to a static string */ #define P3_POINTER (-3) /* P3 is a pointer to some structure or object */ +#define P3_COLLSEQ (-4) /* P3 is a pointer to a CollSeq structure */ /* ** The following macro converts a relative address in the p2 field diff --git a/src/vdbeInt.h b/src/vdbeInt.h index 4f5d0f7147..3751126aac 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -332,6 +332,6 @@ int sqlite3VdbeSerialGet(const unsigned char *, u64, Mem *); int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *); int sqlite3VdbeIdxKeyCompare(Cursor*, int , const unsigned char*, int*); int sqlite3VdbeIdxRowid(BtCursor *, i64 *); -int sqlite3MemCompare(Mem *, Mem *); +int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*); int sqlite3VdbeKeyCompare(void*,int,const void*,int, const void*); int sqlite3VdbeRowCompare(void*,int,const void*,int, const void*); diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 19ed035122..45c104bb3c 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -1426,15 +1426,28 @@ int sqlite3VdbeSerialGet(const unsigned char *buf, u64 serial_type, Mem *pMem){ ** ** Two NULL values are considered equal by this function. */ -int sqlite3MemCompare(Mem *pMem1, Mem *pMem2){ +int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const CollSeq *pColl){ int rc; - int combined_flags = pMem1->flags|pMem2->flags; + int f1, f2; + int combined_flags; + + /* Interchange pMem1 and pMem2 if the collating sequence specifies + ** DESC order. + */ + if( pColl && pColl->reverseOrder ){ + const Mem *pTemp = pMem1; + pMem1 = pMem2; + pMem2 = pTemp; + } + f1 = pMem1->flags; + f2 = pMem2->flags; + combined_flags = f1|f2; /* If one value is NULL, it is less than the other. If both values ** are NULL, return 0. */ if( combined_flags&MEM_Null ){ - return (pMem2->flags&MEM_Null) - (pMem1->flags&MEM_Null); + return (f2&MEM_Null) - (f1&MEM_Null); } /* If one value is a number and the other is not, the number is less. @@ -1442,44 +1455,61 @@ int sqlite3MemCompare(Mem *pMem1, Mem *pMem2){ ** if both values are integers. */ if( combined_flags&(MEM_Int|MEM_Real) ){ - i64 diff; - if( !(pMem1->flags&(MEM_Int|MEM_Real)) ){ + if( !(f1&(MEM_Int|MEM_Real)) ){ return 1; } - if( !(pMem2->flags&(MEM_Int|MEM_Real)) ){ + if( !(f2&(MEM_Int|MEM_Real)) ){ return -1; } - if( combined_flags&MEM_Real ){ - if( pMem1->flags&MEM_Int ){ - pMem1->r = pMem1->i; + if( (f1 & f2 & MEM_Int)==0 ){ + double r1, r2; + if( (f1&MEM_Real)==0 ){ + r1 = pMem1->i; + }else{ + r1 = pMem1->r; } - if( pMem2->flags&MEM_Int ){ - pMem2->r = pMem2->i; + if( (f2&MEM_Real)==0 ){ + r2 = pMem2->i; + }else{ + r2 = pMem2->r; } - if( pMem1->r < pMem2->r ) return -1; - if( pMem1->r > pMem2->r ) return 1; + if( r1r2 ) return 1; + return 0; + }else{ + assert( f1&MEM_Int ); + assert( f2&MEM_Int ); + if( pMem1->i < pMem2->i ) return -1; + if( pMem1->i > pMem2->i ) return 1; return 0; } - diff = pMem1->i - pMem2->i; - return diff<0 ? -1 : diff==0 ? 0 : +1; } - rc = (pMem2->flags&MEM_Null) - (pMem1->flags&MEM_Null); - if( rc ){ - return rc; + /* If one value is a string and the other is a blob, the string is less. + ** If both are strings, compare using the collating functions. + */ + if( combined_flags&MEM_Str ){ + if( (f1 & MEM_Str)==0 ){ + return 1; + } + if( (f2 & MEM_Str)==0 ){ + return -1; + } + if( pColl && pColl->xCmp ){ + return pColl->xCmp(pColl->pUser, pMem1->n, pMem1->z, pMem2->n, pMem2->z); + }else{ + /* If no collating sequence is defined, fall through into the + ** blob case below and use memcmp() for the comparison. */ + } } - - /* Both values must be strings or blobs. If only one is a string, then - ** that value is less. Otherwise, compare with memcmp(). If memcmp() - ** returns 0 and one value is longer than the other, then that value - ** is greater. + + /* Both values must be blobs. Compare using memcmp(). */ rc = memcmp(pMem1->z, pMem2->z, (pMem1->n>pMem2->n)?pMem2->n:pMem1->n); - if( rc ){ - return rc; + if( rc==0 ){ + rc = pMem1->n - pMem2->n; } - - return (pMem1->n - pMem2->n); + return rc; } /* @@ -1539,7 +1569,7 @@ int sqlite3VdbeKeyCompare( offset1 += sqlite3VdbeSerialGet(&aKey1[offset1], serial_type1, &mem1); offset2 += sqlite3VdbeSerialGet(&aKey2[offset2], serial_type2, &mem2); - rc = sqlite3MemCompare(&mem1, &mem2); + rc = sqlite3MemCompare(&mem1, &mem2, 0); if( mem1.flags&MEM_Dyn ){ sqliteFree(mem1.z); } @@ -1624,7 +1654,7 @@ int sqlite3VdbeRowCompare( offset1 += sqlite3VdbeSerialGet(&aKey1[offset1], serial_type1, &mem1); offset2 += sqlite3VdbeSerialGet(&aKey2[offset2], serial_type2, &mem2); - rc = sqlite3MemCompare(&mem1, &mem2); + rc = sqlite3MemCompare(&mem1, &mem2, 0); if( mem1.flags&MEM_Dyn ){ sqliteFree(mem1.z); }