SQLite4
Check-in [762134b4a8]
Not logged in

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

Overview
Comment:Replace placeholder sqlite4_num_to_int32. Change API to be analogous sqlite4_num_to_int64. Add tests.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 762134b4a82d841d48dc1136be6fdd28f219da97
User & Date: peterreid 2013-06-07 02:00:48
Context
2013-06-07
14:22
Remove the error message output parameter from sqlite4_exec(). check-in: 6833c6df33 user: dan tags: trunk
02:00
Replace placeholder sqlite4_num_to_int32. Change API to be analogous sqlite4_num_to_int64. Add tests. check-in: 762134b4a8 user: peterreid tags: trunk
00:51
Correct comments in header of num test check-in: 8cb787fa4a user: peterreid tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/math.c.

499
500
501
502
503
504
505
506







507
508

509







510

511
512
513
514
515
516
517
  }
  x.m = (u64)d;

  return x;
}

/*
** TODO: This is a placeholder implementation only.







*/
int sqlite4_num_to_int32(sqlite4_num num, int *piOut){

  *piOut = sqlite4_num_to_int64(num, 0);







  return SQLITE4_OK;

}

int sqlite4_num_to_double(sqlite4_num num, double *pr){
  double rRet;
  int i;
  rRet = num.m;
  if( num.sign ) rRet = rRet*-1;







|
>
>
>
>
>
>
>

|
>
|
>
>
>
>
>
>
>
|
>







499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
  }
  x.m = (u64)d;

  return x;
}

/*
** Convert the number passed as the first argument to a signed 32-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.
**
** Values round towards 0. If the number is outside the range that a
** signed 32-bit integer can represent, it is clamped to be inside
** that range.
*/
int sqlite4_num_to_int32(sqlite4_num num, int *pbLossy){
  sqlite4_int64 iVal; 
  iVal = sqlite4_num_to_int64(num, pbLossy);
  if( iVal<SMALLEST_INT32 ){
    if( pbLossy ) *pbLossy = 1;
    return SMALLEST_INT32;
  }else if( iVal>LARGEST_INT32 ){
    if( pbLossy ) *pbLossy = 1;
    return LARGEST_INT32;
  }else{
    return (int)iVal;
  }
}

int sqlite4_num_to_double(sqlite4_num num, double *pr){
  double rRet;
  int i;
  rRet = num.m;
  if( num.sign ) rRet = rRet*-1;

Changes to src/sqliteInt.h.

465
466
467
468
469
470
471






472
473
474
475
476
477
478
** These macros are designed to work correctly on both 32-bit and 64-bit
** compilers.
*/
#define LARGEST_INT64  (0xffffffff|(((i64)0x7fffffff)<<32))
#define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64)
#define LARGEST_UINT64  (0xffffffff|(((u64)0xffffffff)<<32))







/* 
** Round up a number to the next larger multiple of 8.  This is used
** to force 8-byte alignment on 64-bit architectures.
*/
#define ROUND8(x)     (((x)+7)&~7)

/*







>
>
>
>
>
>







465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
** These macros are designed to work correctly on both 32-bit and 64-bit
** compilers.
*/
#define LARGEST_INT64  (0xffffffff|(((i64)0x7fffffff)<<32))
#define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64)
#define LARGEST_UINT64  (0xffffffff|(((u64)0xffffffff)<<32))

/*
** Constants for the largest and smallest possible 32-bit signed integers.
*/
#define LARGEST_INT32  0x7fffffff
#define SMALLEST_INT32 (-LARGEST_INT32 - 1) 

/* 
** Round up a number to the next larger multiple of 8.  This is used
** to force 8-byte alignment on 64-bit architectures.
*/
#define ROUND8(x)     (((x)+7)&~7)

/*

Changes to src/vdbe.c.

743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
....
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
....
4904
4905
4906
4907
4908
4909
4910
4911
4912
4913
4914
4915
4916
4917
4918
/* Opcode:  Return P1 * * * *
**
** Jump to the next instruction after the address in register P1.
*/
case OP_Return: {           /* in1 */
  pIn1 = &aMem[pOp->p1];
  assert( pIn1->flags & MEM_Int );
  sqlite4_num_to_int32(pIn1->u.num, &pc);
  break;
}

/* Opcode:  Yield P1 * * * *
**
** Swap the program counter with the value in register P1.
*/
case OP_Yield: {            /* in1 */
  int pcDest;
  pIn1 = &aMem[pOp->p1];
  assert( (pIn1->flags & MEM_Dyn)==0 );
  pIn1->flags = MEM_Int;
  sqlite4_num_to_int32(pIn1->u.num, &pcDest);
  pIn1->u.num = sqlite4_num_from_int64(pc);
  REGISTER_TRACE(pOp->p1, pIn1);
  pc = pcDest;
  break;
}

/* Opcode:  HaltIfNull  P1 P2 P3 P4 *
................................................................................
  if( pOp->p5 ){
    assert( p2>0 );
    assert( p2<=p->nMem );
    pIn2 = &aMem[p2];
    assert( memIsValid(pIn2) );
    assert( (pIn2->flags & MEM_Int)!=0 );
    sqlite4VdbeMemIntegerify(pIn2);
    sqlite4_num_to_int32(pIn2->u.num, &p2);
    /* The p2 value always comes from a prior OP_NewIdxid opcode and
    ** that opcode will always set the p2 value to 2 or more or else fail.
    ** If there were a failure, the prepared statement would have halted
    ** before reaching this instruction. */
    if( NEVER(p2<2) ) {
      rc = SQLITE4_CORRUPT_BKPT;
      goto abort_due_to_error;
................................................................................

  assert( pOp->p4type==P4_FTS5INFO );
  pInfo = pOp->p4.pFtsInfo;
  aArg = &aMem[pOp->p3];
  pKey = &aMem[pOp->p1];

  if( pOp->p2 ){
    sqlite4_num_to_int32(aMem[pOp->p2].u.num, &iRoot);
  }else{
    iRoot = 0;
  }

  rc = sqlite4Fts5Update(db, pInfo, iRoot, pKey, aArg, pOp->p5, &p->zErrMsg);
  break;
}







|












|







 







|







 







|







743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
....
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
....
4904
4905
4906
4907
4908
4909
4910
4911
4912
4913
4914
4915
4916
4917
4918
/* Opcode:  Return P1 * * * *
**
** Jump to the next instruction after the address in register P1.
*/
case OP_Return: {           /* in1 */
  pIn1 = &aMem[pOp->p1];
  assert( pIn1->flags & MEM_Int );
  pc = sqlite4_num_to_int32(pIn1->u.num, 0);
  break;
}

/* Opcode:  Yield P1 * * * *
**
** Swap the program counter with the value in register P1.
*/
case OP_Yield: {            /* in1 */
  int pcDest;
  pIn1 = &aMem[pOp->p1];
  assert( (pIn1->flags & MEM_Dyn)==0 );
  pIn1->flags = MEM_Int;
  pcDest = sqlite4_num_to_int32(pIn1->u.num, 0);
  pIn1->u.num = sqlite4_num_from_int64(pc);
  REGISTER_TRACE(pOp->p1, pIn1);
  pc = pcDest;
  break;
}

/* Opcode:  HaltIfNull  P1 P2 P3 P4 *
................................................................................
  if( pOp->p5 ){
    assert( p2>0 );
    assert( p2<=p->nMem );
    pIn2 = &aMem[p2];
    assert( memIsValid(pIn2) );
    assert( (pIn2->flags & MEM_Int)!=0 );
    sqlite4VdbeMemIntegerify(pIn2);
    p2 = sqlite4_num_to_int32(pIn2->u.num, 0);
    /* The p2 value always comes from a prior OP_NewIdxid opcode and
    ** that opcode will always set the p2 value to 2 or more or else fail.
    ** If there were a failure, the prepared statement would have halted
    ** before reaching this instruction. */
    if( NEVER(p2<2) ) {
      rc = SQLITE4_CORRUPT_BKPT;
      goto abort_due_to_error;
................................................................................

  assert( pOp->p4type==P4_FTS5INFO );
  pInfo = pOp->p4.pFtsInfo;
  aArg = &aMem[pOp->p3];
  pKey = &aMem[pOp->p1];

  if( pOp->p2 ){
    iRoot = sqlite4_num_to_int32(aMem[pOp->p2].u.num, 0);
  }else{
    iRoot = 0;
  }

  rc = sqlite4Fts5Update(db, pInfo, iRoot, pKey, aArg, pOp->p5, &p->zErrMsg);
  break;
}

Changes to test/num.test.

177
178
179
180
181
182
183















184
185
186
187
188
  15    -93.9                                        ~-93
  16    -12.1                                        ~-12
  17    {sign:0 approx:1 e:0 m:4053}                 ~4053
} {
  do_test num-10.1.$tn { sqlite4_num_to_int64 $in } [list {*}$out]
}

















#-------------------------------------------------------------------------
finish_test









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





177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
  15    -93.9                                        ~-93
  16    -12.1                                        ~-12
  17    {sign:0 approx:1 e:0 m:4053}                 ~4053
} {
  do_test num-10.1.$tn { sqlite4_num_to_int64 $in } [list {*}$out]
}

foreach {tn in out} {
  0     7093                                         7093
  1     -98                                          -98
  2     33.9                                         ~33
  3     -438.4                                       ~-438
  4     1e300                                        ~2147483647
  5     -5000000000000                               ~-2147483648 
  6     2147483647                                   2147483647 
  7     -2147483648                                  -2147483648 
  8     {sign:0 approx:1 e:4 m:2}                    ~20000
  9     .00034                                       ~0
  10    -.99                                         ~0
} {
  do_test num-11.1.$tn { sqlite4_num_to_int32 $in } [list {*}$out]
}

#-------------------------------------------------------------------------
finish_test


Changes to test/test_num.c.

236
237
238
239
240
241
242






















243
244
245
246
247
248
249
...
277
278
279
280
281
282
283

284
285
286
287
288
289
290
  ret = sqlite4_num_from_double(val);

  Tcl_ResetResult(interp);
  append_num_result(interp, ret);
  return TCL_OK;
}
























static int test_num_to_int64(
  void *NotUsed,
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
  int argc,              /* Number of arguments */
  char **argv            /* Text of each argument */
){
................................................................................
     { "sqlite4_num_to_text",           (Tcl_CmdProc*)test_num_to_text      },
     { "sqlite4_num_add",               (Tcl_CmdProc*)test_num_add          },
     { "sqlite4_num_sub",               (Tcl_CmdProc*)test_num_sub          },
     { "sqlite4_num_mul",               (Tcl_CmdProc*)test_num_mul          },
     { "sqlite4_num_div",               (Tcl_CmdProc*)test_num_div          },
     { "sqlite4_num_isinf",             (Tcl_CmdProc*)test_num_isinf        },
     { "sqlite4_num_isnan",             (Tcl_CmdProc*)test_num_isnan        },

     { "sqlite4_num_to_int64",          (Tcl_CmdProc*)test_num_to_int64     },
  };

  static struct {
     char *zName;
     Tcl_ObjCmdProc *xProc;
     void *clientData;







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







 







>







236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
...
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
  ret = sqlite4_num_from_double(val);

  Tcl_ResetResult(interp);
  append_num_result(interp, ret);
  return TCL_OK;
}


static int test_num_to_int32(
  void *NotUsed,
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
  int argc,              /* Number of arguments */
  char **argv            /* Text of each argument */
){
  sqlite4_num A;
  int lossy;
  int iVal;
  char buf[50];
  if( argc!=2 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
      " NUM\"", 0);
    return TCL_ERROR;
  }
  A = test_parse_num(argv[1]);
  iVal = sqlite4_num_to_int32(A, &lossy);
  sprintf( buf, "%s%d", lossy?"~":"", iVal );
  Tcl_AppendResult(interp, buf, 0);
  return TCL_OK;
}

static int test_num_to_int64(
  void *NotUsed,
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
  int argc,              /* Number of arguments */
  char **argv            /* Text of each argument */
){
................................................................................
     { "sqlite4_num_to_text",           (Tcl_CmdProc*)test_num_to_text      },
     { "sqlite4_num_add",               (Tcl_CmdProc*)test_num_add          },
     { "sqlite4_num_sub",               (Tcl_CmdProc*)test_num_sub          },
     { "sqlite4_num_mul",               (Tcl_CmdProc*)test_num_mul          },
     { "sqlite4_num_div",               (Tcl_CmdProc*)test_num_div          },
     { "sqlite4_num_isinf",             (Tcl_CmdProc*)test_num_isinf        },
     { "sqlite4_num_isnan",             (Tcl_CmdProc*)test_num_isnan        },
     { "sqlite4_num_to_int32",          (Tcl_CmdProc*)test_num_to_int32     },
     { "sqlite4_num_to_int64",          (Tcl_CmdProc*)test_num_to_int64     },
  };

  static struct {
     char *zName;
     Tcl_ObjCmdProc *xProc;
     void *clientData;