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

Bug fixing in the new integer primary key code. (CVS 334)

FossilOrigin-Name: 29cab124b4f7eae9d9feb60d2f3a2c443fd9b9aa
This commit is contained in:
drh
2001-12-22 14:49:24 +00:00
parent 4a32431ce7
commit 8aff10153e
15 changed files with 551 additions and 157 deletions

View File

@@ -30,7 +30,7 @@
** But other routines are also provided to help in building up
** a program instruction by instruction.
**
** $Id: vdbe.c,v 1.101 2001/12/21 14:30:43 drh Exp $
** $Id: vdbe.c,v 1.102 2001/12/22 14:49:25 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@@ -709,6 +709,15 @@ static int isNumber(const char *zNum){
return *zNum==0;
}
/*
** Return TRUE if zNum is an integer.
*/
static int isInteger(const char *zNum){
if( *zNum=='-' || *zNum=='+' ) zNum++;
while( isdigit(*zNum) ) zNum++;
return *zNum==0;
}
/*
** Delete a keylist
*/
@@ -860,15 +869,15 @@ static char *zOpName[] = { 0,
"Goto", "If", "Halt", "ColumnCount",
"ColumnName", "Callback", "NullCallback", "Integer",
"String", "Pop", "Dup", "Pull",
"Add", "AddImm", "Subtract", "Multiply",
"Divide", "Remainder", "BitAnd", "BitOr",
"BitNot", "ShiftLeft", "ShiftRight", "AbsValue",
"Precision", "Min", "Max", "Like",
"Glob", "Eq", "Ne", "Lt",
"Le", "Gt", "Ge", "IsNull",
"NotNull", "Negative", "And", "Or",
"Not", "Concat", "Noop", "Strlen",
"Substr", "Limit",
"MustBeInt", "Add", "AddImm", "Subtract",
"Multiply", "Divide", "Remainder", "BitAnd",
"BitOr", "BitNot", "ShiftLeft", "ShiftRight",
"AbsValue", "Precision", "Min", "Max",
"Like", "Glob", "Eq", "Ne",
"Lt", "Le", "Gt", "Ge",
"IsNull", "NotNull", "Negative", "And",
"Or", "Not", "Concat", "Noop",
"Strlen", "Substr", "Limit",
};
/*
@@ -966,10 +975,21 @@ static Sorter *Merge(Sorter *pLeft, Sorter *pRight){
}
/*
** Convert an integer into a big-endian integer. In other words,
** make sure the most significant byte comes first.
** Convert an integer in between the native integer format and
** the bigEndian format used as the record number for tables.
**
** The bigEndian format (most significant byte first) is used for
** record numbers so that records will sort into the correct order
** even though memcmp() is used to compare the keys. On machines
** whose native integer format is little endian (ex: i486) the
** order of bytes is reversed. On native big-endian machines
** (ex: Alpha, Sparc, Motorola) the byte order is the same.
**
** This function is its own inverse. In other words
**
** X == byteSwap(byteSwap(X))
*/
static int bigEndian(int x){
static int byteSwap(int x){
union {
char zBuf[sizeof(int)];
int i;
@@ -981,6 +1001,15 @@ static int bigEndian(int x){
return ux.i;
}
/*
** When converting from the native format to the key format and back
** again, in addition to changing the byte order we invert the high-order
** bit of the most significant byte. This causes negative numbers to
** sort before positive numbers in the memcmp() function.
*/
#define keyToInt(X) (byteSwap(X) ^ 0x80000000)
#define intToKey(X) (byteSwap((X) ^ 0x80000000))
/*
** Code contained within the VERIFY() macro is not needed for correct
** execution. It is there only to catch errors. So when we compile
@@ -1667,6 +1696,47 @@ case OP_AddImm: {
break;
}
/* Opcode: MustBeInt * P2 *
**
** Force the top of the stack to be an integer. If the top of the
** stack is not an integer and cannot be comverted into an integer
** with out data loss, then jump immediately to P2, or if P2==0
** raise an SQLITE_MISMATCH exception.
*/
case OP_MustBeInt: {
int tos = p->tos;
VERIFY( if( tos<0 ) goto not_enough_stack; )
if( aStack[tos].flags & STK_Int ){
/* Do nothing */
}else if( aStack[tos].flags & STK_Real ){
int i = aStack[tos].r;
double r = i;
if( r!=aStack[tos].r ){
goto mismatch;
}
aStack[tos].i = i;
}else if( aStack[tos].flags & STK_Str ){
if( !isInteger(zStack[tos]) ){
goto mismatch;
}
p->aStack[tos].i = atoi(p->zStack[tos]);
}else{
goto mismatch;
}
Release(p, tos);
p->aStack[tos].flags = STK_Int;
break;
mismatch:
if( pOp->p2==0 ){
rc = SQLITE_MISMATCH;
goto abort_due_to_error;
}else{
pc = pOp->p2 - 1;
}
break;
}
/* Opcode: Eq * P2 *
**
** Pop the top two elements from the stack. If they are equal, then
@@ -2155,7 +2225,7 @@ case OP_MakeKey: {
if( addRowid ){
u32 iKey;
Integerify(p, p->tos-nField);
iKey = bigEndian(aStack[p->tos-nField].i);
iKey = intToKey(aStack[p->tos-nField].i);
memcpy(&zNewKey[j], &iKey, sizeof(u32));
}
if( pOp->p2==0 ) PopStack(p, nField+addRowid);
@@ -2540,10 +2610,10 @@ case OP_MoveTo: {
if( i>=0 && i<p->nCursor && (pC = &p->aCsr[i])->pCursor!=0 ){
int res;
if( aStack[tos].flags & STK_Int ){
int iKey = bigEndian(aStack[tos].i);
int iKey = intToKey(aStack[tos].i);
sqliteBtreeMoveto(pC->pCursor, (char*)&iKey, sizeof(int), &res);
pC->lastRecno = aStack[tos].i;
pC->recnoIsValid = 1;
pC->recnoIsValid = res==0;
}else{
if( Stringify(p, tos) ) goto no_mem;
sqliteBtreeMoveto(pC->pCursor, zStack[tos], aStack[tos].n, &res);
@@ -2606,7 +2676,7 @@ case OP_Found: {
if( VERIFY( i>=0 && i<p->nCursor && ) (pC = &p->aCsr[i])->pCursor!=0 ){
int res, rx;
if( aStack[tos].flags & STK_Int ){
int iKey = bigEndian(aStack[tos].i);
int iKey = intToKey(aStack[tos].i);
rx = sqliteBtreeMoveto(pC->pCursor, (char*)&iKey, sizeof(int), &res);
}else{
if( Stringify(p, tos) ) goto no_mem;
@@ -2665,7 +2735,7 @@ case OP_NewRecno: {
v += sqliteRandomByte() + 1;
}
if( v==0 ) continue;
x = bigEndian(v);
x = intToKey(v);
rx = sqliteBtreeMoveto(pC->pCursor, &x, sizeof(int), &res);
cnt++;
}while( cnt<1000 && rx==SQLITE_OK && res==0 );
@@ -2707,7 +2777,7 @@ case OP_Put: {
zKey = zStack[nos];
}else{
nKey = sizeof(int);
iKey = bigEndian(aStack[nos].i);
iKey = intToKey(aStack[nos].i);
zKey = (char*)&iKey;
}
if( pOp->p2 ){
@@ -2875,7 +2945,7 @@ case OP_Recno: {
v = p->aCsr[i].lastRecno;
}else{
sqliteBtreeKey(pCrsr, 0, sizeof(u32), (char*)&v);
v = bigEndian(v);
v = keyToInt(v);
}
aStack[tos].i = v;
aStack[tos].flags = STK_Int;
@@ -3060,7 +3130,7 @@ case OP_IdxRecno: {
int sz;
sqliteBtreeKeySize(pCrsr, &sz);
sqliteBtreeKey(pCrsr, sz - sizeof(u32), sizeof(u32), (char*)&v);
v = bigEndian(v);
v = keyToInt(v);
aStack[tos].i = v;
aStack[tos].flags = STK_Int;
}