Index: src/expr.c ================================================================== --- src/expr.c +++ src/expr.c @@ -10,11 +10,11 @@ ** ************************************************************************* ** This file contains routines used for analyzing expressions and ** for generating VDBE code that evaluates expressions in SQLite. ** -** $Id: expr.c,v 1.102 2003/12/10 03:13:44 drh Exp $ +** $Id: expr.c,v 1.103 2004/01/06 01:13:46 drh Exp $ */ #include "sqliteInt.h" #include /* @@ -326,26 +326,30 @@ } return 0; } /* -** If the given expression codes a constant integer, return 1 and put -** the value of the integer in *pValue. If the expression is not an -** integer, return 0 and leave *pValue unchanged. +** If the given expression codes a constant integer that is small enough +** to fit in a 32-bit integer, return 1 and put the value of the integer +** in *pValue. If the expression is not an integer or if it is too big +** to fit in a signed 32-bit integer, return 0 and leave *pValue unchanged. */ int sqliteExprIsInteger(Expr *p, int *pValue){ switch( p->op ){ case TK_INTEGER: { - *pValue = atoi(p->token.z); - return 1; + if( sqliteFitsIn32Bits(p->token.z) ){ + *pValue = atoi(p->token.z); + return 1; + } + break; } case TK_STRING: { const char *z = p->token.z; int n = p->token.n; if( n>0 && z[0]=='-' ){ z++; n--; } while( n>0 && *z && isdigit(*z) ){ z++; n--; } - if( n==0 ){ + if( n==0 && sqliteFitsIn32Bits(p->token.z) ){ *pValue = atoi(p->token.z); return 1; } break; } @@ -967,10 +971,13 @@ break; } return SQLITE_SO_NUM; } +/* +** Run + /* ** Generate code into the current Vdbe to evaluate the given ** expression and leave the result on the top of stack. */ void sqliteExprCode(Parse *pParse, Expr *pExpr){ @@ -1012,20 +1019,14 @@ sqliteVdbeAddOp(v, OP_Recno, pExpr->iTable, 0); } break; } case TK_INTEGER: { - int iVal = atoi(pExpr->token.z); - char zBuf[30]; - sprintf(zBuf,"%d",iVal); - if( strlen(zBuf)!=pExpr->token.n - || strncmp(pExpr->token.z,zBuf,pExpr->token.n)!=0 ){ - /* If the integer value cannot be represented exactly in 32 bits, - ** then code it as a string instead. */ + if( !sqliteFitsIn32Bits(pExpr->token.z) ){ sqliteVdbeAddOp(v, OP_String, 0, 0); }else{ - sqliteVdbeAddOp(v, OP_Integer, iVal, 0); + sqliteVdbeAddOp(v, OP_Integer, atoi(pExpr->token.z), 0); } sqliteVdbeChangeP3(v, -1, pExpr->token.z, pExpr->token.n); break; } case TK_FLOAT: { @@ -1088,11 +1089,15 @@ break; } case TK_UPLUS: { Expr *pLeft = pExpr->pLeft; if( pLeft && pLeft->op==TK_INTEGER ){ - sqliteVdbeAddOp(v, OP_Integer, atoi(pLeft->token.z), 0); + if( sqliteFitsIn32Bits(pLeft->token.z) ){ + sqliteVdbeAddOp(v, OP_Integer, atoi(pLeft->token.z), 0); + }else{ + sqliteVdbeAddOp(v, OP_String, 0, 0); + } sqliteVdbeChangeP3(v, -1, pLeft->token.z, pLeft->token.n); }else if( pLeft && pLeft->op==TK_FLOAT ){ sqliteVdbeAddOp(v, OP_String, 0, 0); sqliteVdbeChangeP3(v, -1, pLeft->token.z, pLeft->token.n); }else{ @@ -1104,11 +1109,11 @@ assert( pExpr->pLeft ); if( pExpr->pLeft->op==TK_FLOAT || pExpr->pLeft->op==TK_INTEGER ){ Token *p = &pExpr->pLeft->token; char *z = sqliteMalloc( p->n + 2 ); sprintf(z, "-%.*s", p->n, p->z); - if( pExpr->pLeft->op==TK_INTEGER ){ + if( pExpr->pLeft->op==TK_INTEGER && sqliteFitsIn32Bits(z) ){ sqliteVdbeAddOp(v, OP_Integer, atoi(z), 0); }else{ sqliteVdbeAddOp(v, OP_String, 0, 0); } sqliteVdbeChangeP3(v, -1, z, p->n+1); Index: src/sqliteInt.h ================================================================== --- src/sqliteInt.h +++ src/sqliteInt.h @@ -9,11 +9,11 @@ ** May you share freely, never taking more than you give. ** ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.205 2003/12/23 02:17:35 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.206 2004/01/06 01:13:47 drh Exp $ */ #include "config.h" #include "sqlite.h" #include "hash.h" #include "vdbe.h" @@ -1203,5 +1203,6 @@ int sqliteFixExpr(DbFixer*, Expr*); int sqliteFixExprList(DbFixer*, ExprList*); int sqliteFixTriggerStep(DbFixer*, TriggerStep*); double sqliteAtoF(const char *z); int sqlite_snprintf(int,char*,const char*,...); +int sqliteFitsIn32Bits(const char *); Index: src/util.c ================================================================== --- src/util.c +++ src/util.c @@ -12,11 +12,11 @@ ** Utility functions used throughout sqlite. ** ** This file contains functions for allocating memory, comparing ** strings, and stuff like that. ** -** $Id: util.c,v 1.69 2003/12/23 02:17:35 drh Exp $ +** $Id: util.c,v 1.70 2004/01/06 01:13:47 drh Exp $ */ #include "sqliteInt.h" #include #include @@ -710,10 +710,28 @@ v1 *= scale; } } return sign<0 ? -v1 : v1; } + +/* +** The string zNum represents an integer. There might be some other +** information following the integer too, but that part is ignored. +** If the integer that the prefix of zNum represents will fit in a +** 32-bit signed integer, return TRUE. Otherwise return FALSE. +** +** This routine returns FALSE for the string -2147483648 even that +** that number will, in theory fit in a 32-bit integer. But positive +** 2147483648 will not fit in 32 bits. So it seems safer to return +** false. +*/ +int sqliteFitsIn32Bits(const char *zNum){ + int i, c; + if( *zNum=='-' || *zNum=='+' ) zNum++; + for(i=0; (c=zNum[i])>='0' && c<='9'; i++){} + return i<10 || (i==10 && memcmp(zNum,"2147483647",10)<=0); +} /* This comparison routine is what we use for comparison operations ** between numeric values in an SQL expression. "Numeric" is a little ** bit misleading here. What we mean is that the strings have a ** type of "numeric" from the point of view of SQL. The strings Index: test/misc3.test ================================================================== --- test/misc3.test +++ test/misc3.test @@ -11,11 +11,11 @@ # This file implements regression tests for SQLite library. # # This file implements tests for miscellanous features that were # left out of other test files. # -# $Id: misc3.test,v 1.2 2003/12/23 02:17:35 drh Exp $ +# $Id: misc3.test,v 1.3 2004/01/06 01:13:47 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Ticket #529. Make sure an ABORT does not damage the in-memory cache @@ -96,7 +96,31 @@ } 1e+100 do_test misc3-2.9 { execsql {SELECT 2.0e-27 * '+0.000005e+132'} } 1e+100 +# Ticket #522. Make sure integer overflow is handled properly in +# indices. +# +do_test misc3-3.1 { + execsql {PRAGMA integrity_check} +} ok +do_test misc3-3.2 { + execsql { + CREATE TABLE t2(a INT UNIQUE); + PRAGMA integrity_check; + } +} ok +do_test misc3-3.3 { + execsql { + INSERT INTO t2 VALUES(2147483648); + PRAGMA integrity_check; + } +} ok +do_test misc3-3.4 { + execsql { + INSERT INTO t2 VALUES(-2147483649); + PRAGMA integrity_check; + } +} ok finish_test