Index: src/math.c ================================================================== --- src/math.c +++ src/math.c @@ -504,13 +504,11 @@ /* ** TODO: This is a placeholder implementation only. */ int sqlite4_num_to_int32(sqlite4_num num, int *piOut){ - i64 i; - sqlite4_num_to_int64(num, &i); - *piOut = i; + *piOut = sqlite4_num_to_int64(num, 0); return SQLITE4_OK; } int sqlite4_num_to_double(sqlite4_num num, double *pr){ double rRet; @@ -525,23 +523,34 @@ } *pr = rRet; return SQLITE4_OK; } -int sqlite4_num_to_int64(sqlite4_num num, sqlite4_int64 *piOut){ +/* +** Convert the number passed as the first argument to a signed 64-bit +** integer and return the value. If the second argument is not NULL, +** then set the value that it points to 1 if data was lost as part +** of the conversion, or 0 otherwise. +*/ +sqlite4_int64 sqlite4_num_to_int64(sqlite4_num num, int *pbLossy){ + static const i64 L10 = (LARGEST_INT64 / 10); i64 iRet; int i; iRet = num.m; - if( num.sign ) iRet = iRet*-1; + + if( pbLossy ) *pbLossy = 0; for(i=0; iL10 ) *pbLossy = 1; iRet = iRet * 10; } for(i=num.e; i<0; i++){ + if( pbLossy && (iRet % 10) ) *pbLossy = 1; iRet = iRet / 10; } - *piOut = iRet; - return SQLITE4_OK; + + if( num.sign ) iRet = iRet*-1; + return iRet; } /* ** Convert an integer into text in the buffer supplied. The Index: src/sqlite.h.in ================================================================== --- src/sqlite.h.in +++ src/sqlite.h.in @@ -4114,11 +4114,11 @@ int sqlite4_num_compare(sqlite4_num, sqlite4_num); sqlite4_num sqlite4_num_from_text(const char*, int n, unsigned flags, int*); sqlite4_num sqlite4_num_from_int64(sqlite4_int64); sqlite4_num sqlite4_num_from_double(double); int sqlite4_num_to_int32(sqlite4_num, int*); -int sqlite4_num_to_int64(sqlite4_num, sqlite4_int64*); +sqlite4_int64 sqlite4_num_to_int64(sqlite4_num, int *); int sqlite4_num_to_double(sqlite4_num, double *); int sqlite4_num_to_text(sqlite4_num, char*, int); /* ** CAPI4REF: Flags For Text-To-Numeric Conversion Index: src/vdbe.c ================================================================== --- src/vdbe.c +++ src/vdbe.c @@ -1235,12 +1235,12 @@ pOut = &aMem[pOp->p3]; flags = pIn1->flags | pIn2->flags; if( (flags & MEM_Null)!=0 ) goto arithmetic_result_is_null; if( (pIn1->flags&MEM_Int) && (pIn2->flags&MEM_Int) ){ - sqlite4_num_to_int64(pIn1->u.num, &iA); - sqlite4_num_to_int64(pIn2->u.num, &iB); + iA = sqlite4_num_to_int64(pIn1->u.num, 0); + iB = sqlite4_num_to_int64(pIn2->u.num, 0); switch( pOp->opcode ){ case OP_Add: if( sqlite4AddInt64(&iB,iA) ) goto fp_math; break; case OP_Subtract: if( sqlite4SubInt64(&iB,iA) ) goto fp_math; break; case OP_Multiply: if( sqlite4MulInt64(&iB,iA) ) goto fp_math; break; @@ -1274,12 +1274,12 @@ case OP_Multiply: pOut->u.num = sqlite4_num_mul(num1, num2); break; case OP_Divide: pOut->u.num = sqlite4_num_div(num2, num1); break; default: { - sqlite4_num_to_int64(num1, &iA); - sqlite4_num_to_int64(num2, &iB); + iA = sqlite4_num_to_int64(num1, 0); + iB = sqlite4_num_to_int64(num2, 0); if( iA==0 ) goto arithmetic_result_is_null; pOut->u.num = sqlite4_num_from_int64(iB % iA); break; } } @@ -2575,11 +2575,11 @@ assert( pOp->p1>=0 && pOp->p1nDb ); pDb = &db->aDb[pOp->p1]; pIn3 = &aMem[pOp->p3]; sqlite4VdbeMemIntegerify(pIn3); - sqlite4_num_to_int64(pIn3->u.num, &v); + v = sqlite4_num_to_int64(pIn3->u.num, 0); rc = sqlite4KVStorePutSchema(pDb->pKV, (u32)v); pDb->pSchema->schema_cookie = (int)v; db->flags |= SQLITE4_InternChanges; if( pOp->p1==1 ){ /* Invalidate all prepared statements whenever the TEMP database @@ -3329,11 +3329,11 @@ pIn3 = sqlite4RegisterInRootFrame(p, pOp->p3); assert( memIsValid(pIn3) ); REGISTER_TRACE(pOp->p3, pIn3); sqlite4VdbeMemIntegerify(pIn3); assert( (pIn3->flags & MEM_Int)!=0 ); /* mem(P3) holds an integer */ - sqlite4_num_to_int64(pIn3->u.num, &i3); + i3 = sqlite4_num_to_int64(pIn3->u.num, 0); if( i3==MAX_ROWID ){ rc = SQLITE4_FULL; } if( vu.num, &i1); + i1 = sqlite4_num_to_int64(pIn1->u.num, 0); if( i1>=(i64)iMax ){ i1++; }else{ i1 = iMax+1; } @@ -3447,11 +3447,11 @@ if( pOp->opcode==OP_Insert ){ pKey = &aMem[pOp->p3]; assert( pKey->flags & MEM_Int ); assert( memIsValid(pKey) ); REGISTER_TRACE(pOp->p3, pKey); - sqlite4_num_to_int64(pKey->u.num, &iKey); + iKey = sqlite4_num_to_int64(pKey->u.num, 0); }else{ /* assert( pOp->opcode==OP_InsertInt ); */ iKey = pOp->p3; } @@ -4310,12 +4310,12 @@ assert( memIsValid(pIn1) ); sqlite4VdbeMemIntegerify(pIn1); pIn2 = &aMem[pOp->p2]; REGISTER_TRACE(pOp->p1, pIn1); sqlite4VdbeMemIntegerify(pIn2); - sqlite4_num_to_int64(pIn1->u.num, &i1); - sqlite4_num_to_int64(pIn2->u.num, &i2); + i1 = sqlite4_num_to_int64(pIn1->u.num, 0); + i2 = sqlite4_num_to_int64(pIn2->u.num, 0); if( i1u.num = sqlite4_num_from_int64(i2); } REGISTER_TRACE(pOp->p1, pIn1); break; @@ -4331,11 +4331,11 @@ */ case OP_IfPos: { /* jump, in1 */ i64 i1; pIn1 = &aMem[pOp->p1]; assert( pIn1->flags&MEM_Int ); - sqlite4_num_to_int64(pIn1->u.num, &i1); + i1 = sqlite4_num_to_int64(pIn1->u.num, 0); if( i1>0 ){ pc = pOp->p2 - 1; } break; } @@ -4349,11 +4349,11 @@ */ case OP_IfNeg: { /* jump, in1 */ i64 i1; pIn1 = &aMem[pOp->p1]; assert( pIn1->flags&MEM_Int ); - sqlite4_num_to_int64(pIn1->u.num, &i1); + i1 = sqlite4_num_to_int64(pIn1->u.num, 0); if( i1<0 ){ pc = pOp->p2 - 1; } break; } @@ -4368,11 +4368,11 @@ */ case OP_IfZero: { /* jump, in1 */ i64 i1; pIn1 = &aMem[pOp->p1]; assert( pIn1->flags&MEM_Int ); - sqlite4_num_to_int64(pIn1->u.num, &i1); + i1 = sqlite4_num_to_int64(pIn1->u.num, 0); i1 += pOp->p3; pIn1->u.num = sqlite4_num_from_int64(i1); if( i1==0 ){ pc = pOp->p2 - 1; } @@ -4956,11 +4956,11 @@ if( pOp->p5 ){ sqlite4Fts5EntryCksum(db, pInfo, pKey, aArg, &cksum); }else{ sqlite4Fts5RowCksum(db, pInfo, pKey, aArg, &cksum); } - sqlite4_num_to_int64(pOut->u.num, &i1); + i1 = sqlite4_num_to_int64(pOut->u.num, 0); pOut->u.num = sqlite4_num_from_int64(i1 ^ cksum); break; } Index: src/vdbeapi.c ================================================================== --- src/vdbeapi.c +++ src/vdbeapi.c @@ -1088,20 +1088,19 @@ } #endif /* SQLITE4_OMIT_UTF16 */ int sqlite4_bind_value(sqlite4_stmt *pStmt, int i, const sqlite4_value *pValue){ int rc; switch( pValue->type ){ - case SQLITE4_INTEGER: { - i64 i1; - sqlite4_num_to_int64(pValue->u.num, &i1); - rc = sqlite4_bind_int64(pStmt, i, i1); - break; - } + case SQLITE4_INTEGER: case SQLITE4_FLOAT: { - double r; - sqlite4_num_to_double(pValue->u.num, &r); - rc = sqlite4_bind_double(pStmt, i, r); + Mem *p = (Mem *)pValue; + Vdbe *v = (Vdbe *)pStmt; + vdbeUnbind(v, i); + v->aVar[i-1].u.num = p->u.num; + MemSetTypeFlag(&v->aVar[i-1], + (pValue->type==SQLITE4_FLOAT ? MEM_Real : MEM_Int) + ); break; } case SQLITE4_BLOB: { rc = sqlite4_bind_blob(pStmt, i, pValue->z, pValue->n, SQLITE4_TRANSIENT, 0); Index: src/vdbecodec.c ================================================================== --- src/vdbecodec.c +++ src/vdbecodec.c @@ -221,11 +221,11 @@ int flags = aIn[i].flags; if( flags & MEM_Null ){ aOut[nOut++] = 0; }else if( flags & MEM_Int ){ i64 i1; - sqlite4_num_to_int64(aIn[i].u.num, &i1); + i1 = sqlite4_num_to_int64(aIn[i].u.num, 0); n = significantBytes(i1); aOut[nOut++] = n+2; nPayload += n; aAux[i].n = n; }else if( flags & MEM_Real ){ @@ -264,11 +264,11 @@ int flags = aIn[i].flags; if( flags & MEM_Null ){ /* No content */ }else if( flags & MEM_Int ){ sqlite4_int64 v; - sqlite4_num_to_int64(aIn[i].u.num, &v); + v = sqlite4_num_to_int64(aIn[i].u.num, 0); n = aAux[i].n; aOut[nOut+(--n)] = v & 0xff; while( n ){ v >>= 8; aOut[nOut+(--n)] = v & 0xff; Index: src/vdbemem.c ================================================================== --- src/vdbemem.c +++ src/vdbemem.c @@ -310,27 +310,13 @@ ** an SQL-NULL value, return 0. ** ** If pMem represents a string value, its encoding might be changed. */ i64 sqlite4VdbeIntValue(Mem *pMem){ - int flags; assert( pMem->db==0 || sqlite4_mutex_held(pMem->db->mutex) ); assert( EIGHT_BYTE_ALIGNMENT(pMem) ); - flags = pMem->flags; - if( flags & (MEM_Int|MEM_Real) ){ - i64 i1; - sqlite4_num_to_int64(pMem->u.num, &i1); - return i1; - }else if( flags & (MEM_Str|MEM_Blob) ){ - i64 value = 0; - assert( pMem->z || pMem->n==0 ); - testcase( pMem->z==0 ); - sqlite4Atoi64(pMem->z, &value, pMem->n, pMem->enc); - return value; - }else{ - return 0; - } + return sqlite4_num_to_int64(sqlite4VdbeNumValue(pMem), 0); } /* ** Return the best representation of pMem that we can get into a ** double. If pMem is already a double or an integer, return its @@ -351,11 +337,11 @@ */ sqlite4_num sqlite4VdbeNumValue(Mem *pMem){ if( pMem->flags & (MEM_Real|MEM_Int) ){ return pMem->u.num; }else if( pMem->flags & (MEM_Str|MEM_Blob) ){ - int flags = SQLITE4_PREFIX_ONLY | pMem->enc; + int flags = SQLITE4_PREFIX_ONLY | SQLITE4_IGNORE_WHITESPACE | pMem->enc; return sqlite4_num_from_text(pMem->z, pMem->n, flags, 0); }else{ sqlite4_num zero = {0,0,0,0}; return zero; } @@ -365,35 +351,21 @@ ** The MEM structure is already a MEM_Real. Try to also make it a ** MEM_Int if we can. */ void sqlite4VdbeIntegerAffinity(Mem *pMem){ i64 i; - double r; + int bLossy; assert( pMem->flags & MEM_Real ); assert( (pMem->flags & MEM_RowSet)==0 ); assert( pMem->db==0 || sqlite4_mutex_held(pMem->db->mutex) ); assert( EIGHT_BYTE_ALIGNMENT(pMem) ); - sqlite4_num_to_int64(pMem->u.num, &i); - sqlite4_num_to_double(pMem->u.num, &r); - - /* Only mark the value as an integer if - ** - ** (1) the round-trip conversion real->int->real is a no-op, and - ** (2) The integer is neither the largest nor the smallest - ** possible integer (ticket #3922) - ** - ** The second and third terms in the following conditional enforces - ** the second condition under the assumption that addition overflow causes - ** values to wrap around. On x86 hardware, the third term is always - ** true and could be omitted. But we leave it in because other - ** architectures might behave differently. - */ - if( r==(double)i && i>SMALLEST_INT64 && ALWAYS(iu.num = sqlite4_num_from_int64(i); + i = sqlite4_num_to_int64(pMem->u.num, &bLossy); + if( bLossy==0 ){ MemSetTypeFlag(pMem, MEM_Int); + pMem->u.num = sqlite4_num_from_int64(i); } } /* ** Convert pMem to type integer. Invalidate any prior representations. @@ -402,23 +374,13 @@ assert( pMem->db==0 || sqlite4_mutex_held(pMem->db->mutex) ); assert( (pMem->flags & MEM_RowSet)==0 ); assert( EIGHT_BYTE_ALIGNMENT(pMem) ); if( (pMem->flags & MEM_Int)==0 ){ - sqlite4VdbeMemNumerify(pMem); - } - if( (pMem->flags & MEM_Int)==0 ){ - if( pMem->flags & MEM_Real ){ - i64 iVal; - sqlite4_num_to_int64(pMem->u.num, &iVal); - pMem->u.num = sqlite4_num_from_int64(iVal); - }else{ - pMem->u.num = sqlite4_num_from_int64(0); - } - } - - MemSetTypeFlag(pMem, MEM_Int); + pMem->u.num = sqlite4_num_from_int64(sqlite4VdbeIntValue(pMem)); + MemSetTypeFlag(pMem, MEM_Int); + } return SQLITE4_OK; } /* ** Convert pMem so that it has types MEM_Real or MEM_Int or both. @@ -730,33 +692,13 @@ /* If one value is a number and the other is not, the number is less. ** If both are numbers, compare as reals if one is a real, or as integers ** if both values are integers. */ if( combined_flags&(MEM_Int|MEM_Real) ){ - if( !(f1&(MEM_Int|MEM_Real)) ){ - return 1; - } - if( !(f2&(MEM_Int|MEM_Real)) ){ - return -1; - } - if( (f1 & f2 & MEM_Int)==0 ){ - double r1, r2; - sqlite4_num_to_double(pMem1->u.num, &r1); - sqlite4_num_to_double(pMem2->u.num, &r2); - if( r1r2 ) return 1; - return 0; - }else{ - i64 i1, i2; - sqlite4_num_to_int64(pMem1->u.num, &i1); - sqlite4_num_to_int64(pMem2->u.num, &i2); - assert( f1&MEM_Int ); - assert( f2&MEM_Int ); - if( i1i2 ) return 1; - return 0; - } + if( !(f1&(MEM_Int|MEM_Real)) ) return 1; + if( !(f2&(MEM_Int|MEM_Real)) ) return -1; + return (sqlite4_num_compare(pMem1->u.num, pMem2->u.num) - 2); } /* 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. */