/ Check-in [4744257d]
Login
SQLite training in Houston TX on 2019-11-05 (details)
Part of the 2019 Tcl Conference

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Do explicit range tests before attempting to convert a 64-bit float into a 64-bit integer. Some systems (windows) seem to throw exceptions if the conversion is out of range. Ticket #2880. (CVS 4706)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 4744257d3cd2dd96485fde6d9f60542714383421
User & Date: drh 2008-01-11 15:27:03
Context
2008-01-12
12:48
Continuing work toward converting the VM into a register machine. (CVS 4707) check-in: a6dddebc user: drh tags: trunk
2008-01-11
15:27
Do explicit range tests before attempting to convert a 64-bit float into a 64-bit integer. Some systems (windows) seem to throw exceptions if the conversion is out of range. Ticket #2880. (CVS 4706) check-in: 4744257d user: drh tags: trunk
00:06
Attempt to work around a bug in the Borland BCC 5.5.1 compiler. Ticket #2880. (CVS 4705) check-in: 6de0ee49 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/vdbemem.c.

283
284
285
286
287
288
289
































290
291
292
293
294
295
296
...
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
...
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
...
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
    }else{
      sqlite3_free(p->z);
    }
    p->z = 0;
    p->xDel = 0;
  }
}

































/*
** Return some kind of integer value which is the best we can do
** at representing the value that *pMem describes as an integer.
** If pMem is an integer, then the value is exact.  If pMem is
** a floating-point then the value returned is the integer part.
** If pMem is a string or blob, then we make an attempt to convert
................................................................................
i64 sqlite3VdbeIntValue(Mem *pMem){
  int flags;
  assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
  flags = pMem->flags;
  if( flags & MEM_Int ){
    return pMem->u.i;
  }else if( flags & MEM_Real ){
    return (i64)pMem->r;
  }else if( flags & (MEM_Str|MEM_Blob) ){
    i64 value;
    pMem->flags |= MEM_Str;
    if( sqlite3VdbeChangeEncoding(pMem, SQLITE_UTF8)
       || sqlite3VdbeMemNulTerminate(pMem) ){
      return 0;
    }
................................................................................
** The MEM structure is already a MEM_Real.  Try to also make it a
** MEM_Int if we can.
*/
void sqlite3VdbeIntegerAffinity(Mem *pMem){
  assert( pMem->flags & MEM_Real );
  assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );

  /* It is reported (in ticket #2880) that the BCC 5.5.1 compiler
  ** will corrupt a floating point number on the right-hand side
  ** of an assignment if the lvalue for the assignment is an integer.
  **
  ** We will attempt to work around this bug in the Borland compiler
  ** by moving the value into a temporary variable first so that if
  ** the assignment into the integer really does corrupt the right-hand
  ** side value, it will corrupt a temporary variable that we do not
  ** care about.
  */
#ifdef __BORLANDC__
  {
    double r = pMem->r;
    pMem->u.i = r;
  }
#else
  pMem->u.i = pMem->r;
#endif

  if( ((double)pMem->u.i)==pMem->r ){
    pMem->flags |= MEM_Int;
  }
}

/*
** Convert pMem to type integer.  Invalidate any prior representations.
*/
................................................................................
int sqlite3VdbeMemNumerify(Mem *pMem){
  double r1, r2;
  i64 i;
  assert( (pMem->flags & (MEM_Int|MEM_Real|MEM_Null))==0 );
  assert( (pMem->flags & (MEM_Blob|MEM_Str))!=0 );
  assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
  r1 = sqlite3VdbeRealValue(pMem);
  i = (i64)r1;
  r2 = (double)i;
  if( r1==r2 ){
    sqlite3VdbeMemIntegerify(pMem);
  }else{
    pMem->r = r1;
    pMem->flags = MEM_Real;
    sqlite3VdbeMemRelease(pMem);







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







|







 







<
<
<
<
<
<
<
<
<
<
<
<
<
|
<
<
<
<
<
|







 







|







283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
...
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
...
384
385
386
387
388
389
390













391





392
393
394
395
396
397
398
399
...
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
    }else{
      sqlite3_free(p->z);
    }
    p->z = 0;
    p->xDel = 0;
  }
}

/*
** Convert a 64-bit IEEE double into a 64-bit signed integer.
** If the double is too large, return 0x8000000000000000.
**
** Most systems appear to do this simply by assigning
** variables and without the extra range tests.  But
** there are reports that windows throws an expection
** if the floating point value is out of range. (See ticket #2880.)
** Because we do not completely understand the problem, we will
** take the conservative approach and always do range tests
** before attempting the conversion.
*/
static i64 doubleToInt64(double r){
  /*
  ** Many compilers we encounter do not define constants for the
  ** minimum and maximum 64-bit integers, or they define them
  ** inconsistently.  And many do not understand the "LL" notation.
  ** So we define our own static constants here using nothing
  ** larger than a 32-bit integer constant.
  */
  static const i64 maxInt = (((i64)0x7fffffff)<<32)|0xffffffff;
  static const i64 minInt = ((i64)0x80000000)<<32;

  if( r<(double)minInt ){
    return minInt;
  }else if( r>(double)maxInt ){
    return minInt;
  }else{
    return (i64)r;
  }
}

/*
** Return some kind of integer value which is the best we can do
** at representing the value that *pMem describes as an integer.
** If pMem is an integer, then the value is exact.  If pMem is
** a floating-point then the value returned is the integer part.
** If pMem is a string or blob, then we make an attempt to convert
................................................................................
i64 sqlite3VdbeIntValue(Mem *pMem){
  int flags;
  assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
  flags = pMem->flags;
  if( flags & MEM_Int ){
    return pMem->u.i;
  }else if( flags & MEM_Real ){
    return doubleToInt64(pMem->r);
  }else if( flags & (MEM_Str|MEM_Blob) ){
    i64 value;
    pMem->flags |= MEM_Str;
    if( sqlite3VdbeChangeEncoding(pMem, SQLITE_UTF8)
       || sqlite3VdbeMemNulTerminate(pMem) ){
      return 0;
    }
................................................................................
** The MEM structure is already a MEM_Real.  Try to also make it a
** MEM_Int if we can.
*/
void sqlite3VdbeIntegerAffinity(Mem *pMem){
  assert( pMem->flags & MEM_Real );
  assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );














  pMem->u.i = doubleToInt64(pMem->r);





  if( pMem->r==(double)pMem->u.i ){
    pMem->flags |= MEM_Int;
  }
}

/*
** Convert pMem to type integer.  Invalidate any prior representations.
*/
................................................................................
int sqlite3VdbeMemNumerify(Mem *pMem){
  double r1, r2;
  i64 i;
  assert( (pMem->flags & (MEM_Int|MEM_Real|MEM_Null))==0 );
  assert( (pMem->flags & (MEM_Blob|MEM_Str))!=0 );
  assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
  r1 = sqlite3VdbeRealValue(pMem);
  i = doubleToInt64(r1);
  r2 = (double)i;
  if( r1==r2 ){
    sqlite3VdbeMemIntegerify(pMem);
  }else{
    pMem->r = r1;
    pMem->flags = MEM_Real;
    sqlite3VdbeMemRelease(pMem);