SQLite4
Check-in [f875ba1944]
Not logged in

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

Overview
Comment:Further progress on using decimal arithmetic.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | sqlite4-num
Files: files | file ages | folders
SHA1: f875ba19445081b7001599e43facb07390847f22
User & Date: dan 2013-05-25 20:13:47
Context
2013-05-28
20:33
Further progress on decimal arithmetic. check-in: b55b217f6a user: dan tags: sqlite4-num
2013-05-25
20:13
Further progress on using decimal arithmetic. check-in: f875ba1944 user: dan tags: sqlite4-num
16:41
Fix some bugs in the code that uses sqlite4_num. check-in: 598f3f02f4 user: dan tags: sqlite4-num
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/expr.c.

1899
1900
1901
1902
1903
1904
1905










1906
1907
1908
1909
1910
1911
1912

1913
1914
1915
1916
1917
1918
1919
....
1925
1926
1927
1928
1929
1930
1931

1932
1933
1934
1935








1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948

1949
1950
1951
1952
1953
1954
1955
**
** The z[] string will probably not be zero-terminated.  But the 
** z[n] character is guaranteed to be something that does not look
** like the continuation of the number.
*/
static void codeReal(Vdbe *v, const char *z, int negateFlag, int iMem){
  if( ALWAYS(z!=0) ){










    double value;
    char *zV;
    sqlite4AtoF(z, &value, sqlite4Strlen30(z), SQLITE4_UTF8);
    assert( !sqlite4IsNaN(value) ); /* The new AtoF never returns NaN */
    if( negateFlag ) value = -value;
    zV = dup8bytes(v, (char*)&value);
    sqlite4VdbeAddOp4(v, OP_Real, 0, iMem, 0, zV, P4_REAL);

  }
}
#endif


/*
** Generate an instruction that will put the integer describe by
................................................................................
  Vdbe *v = pParse->pVdbe;
  if( pExpr->flags & EP_IntValue ){
    int i = pExpr->u.iValue;
    assert( i>=0 );
    if( negFlag ) i = -i;
    sqlite4VdbeAddOp2(v, OP_Integer, i, iMem);
  }else{

    int c;
    i64 value;
    const char *z = pExpr->u.zToken;
    assert( z!=0 );








    c = sqlite4Atoi64(z, &value, sqlite4Strlen30(z), SQLITE4_UTF8);
    if( c==0 || (c==2 && negFlag) ){
      char *zV;
      if( negFlag ){ value = c==2 ? SMALLEST_INT64 : -value; }
      zV = dup8bytes(v, (char*)&value);
      sqlite4VdbeAddOp4(v, OP_Int64, 0, iMem, 0, zV, P4_INT64);
    }else{
#ifdef SQLITE4_OMIT_FLOATING_POINT
      sqlite4ErrorMsg(pParse, "oversized integer: %s%s", negFlag ? "-" : "", z);
#else
      codeReal(v, z, negFlag, iMem);
#endif
    }

  }
}

/*
** Clear a cache entry.
*/
static void cacheEntryClear(Parse *pParse, ParseYColCache *p){







>
>
>
>
>
>
>
>
>
>







>







 







>




>
>
>
>
>
>
>
>













>







1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
....
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
**
** The z[] string will probably not be zero-terminated.  But the 
** z[n] character is guaranteed to be something that does not look
** like the continuation of the number.
*/
static void codeReal(Vdbe *v, const char *z, int negateFlag, int iMem){
  if( ALWAYS(z!=0) ){
    int s = sizeof(sqlite4_num);
    sqlite4_num *p = (sqlite4_num *)sqlite4DbMallocZero(sqlite4VdbeDb(v), s);
    if( p ){
      *p = sqlite4_num_from_text(z, -1, 0);
      assert( p->sign==0 );
      assert( negateFlag==0 || negateFlag==1 );
      p->sign = negateFlag;
      sqlite4VdbeAddOp4(v, OP_Num, 0, iMem, 0, (const char *)p, P4_NUM);
    }
#if 0
    double value;
    char *zV;
    sqlite4AtoF(z, &value, sqlite4Strlen30(z), SQLITE4_UTF8);
    assert( !sqlite4IsNaN(value) ); /* The new AtoF never returns NaN */
    if( negateFlag ) value = -value;
    zV = dup8bytes(v, (char*)&value);
    sqlite4VdbeAddOp4(v, OP_Real, 0, iMem, 0, zV, P4_REAL);
#endif
  }
}
#endif


/*
** Generate an instruction that will put the integer describe by
................................................................................
  Vdbe *v = pParse->pVdbe;
  if( pExpr->flags & EP_IntValue ){
    int i = pExpr->u.iValue;
    assert( i>=0 );
    if( negFlag ) i = -i;
    sqlite4VdbeAddOp2(v, OP_Integer, i, iMem);
  }else{
    sqlite4_num *p;
    int c;
    i64 value;
    const char *z = pExpr->u.zToken;
    assert( z!=0 );

    p = (sqlite4_num *)sqlite4DbMallocRaw(pParse->db, sizeof(sqlite4_num));
    if( p ){
      *p = sqlite4_num_from_text(z, -1, 0);
      sqlite4VdbeAddOp4(v, OP_Num, p->e==0, iMem, 0, (const char *)p, P4_NUM);
    }

#if 0
    c = sqlite4Atoi64(z, &value, sqlite4Strlen30(z), SQLITE4_UTF8);
    if( c==0 || (c==2 && negFlag) ){
      char *zV;
      if( negFlag ){ value = c==2 ? SMALLEST_INT64 : -value; }
      zV = dup8bytes(v, (char*)&value);
      sqlite4VdbeAddOp4(v, OP_Int64, 0, iMem, 0, zV, P4_INT64);
    }else{
#ifdef SQLITE4_OMIT_FLOATING_POINT
      sqlite4ErrorMsg(pParse, "oversized integer: %s%s", negFlag ? "-" : "", z);
#else
      codeReal(v, z, negFlag, iMem);
#endif
    }
#endif
  }
}

/*
** Clear a cache entry.
*/
static void cacheEntryClear(Parse *pParse, ParseYColCache *p){

Changes to src/math.c.

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
329
330
331







332
333
334
335
336
337
338
339
340



341
342
343
344
345
346
347
348
349

350
351
352
353
354
355
356
...
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395

396
397







398
399
400
401
402
403
404
405
...
485
486
487
488
489
490
491














492
493
494
495
496
497
498
**
** Conversion stops at the first \000 character.  At most nIn bytes
** of zIn are examined.  Or if nIn is negative, up to a billion bytes
** are scanned, which we assume is more than will be found in any valid
** numeric string.
*/
sqlite4_num sqlite4_num_from_text(const char *zIn, int nIn, unsigned flags){
  int incr = 1;



  sqlite4_num r;
  char c;
  int nDigit = 0;
  int seenRadix = 0;
  int i;
  static int one = 1;
  
  memset(&r, 0, sizeof(r));
  if( nIn<0 ) nIn = 1000000000;
  c = flags & 0xf;
  if( c==0 || c==SQLITE4_UTF8 ){
    incr = 1;
  }else if( c==SQLITE4_UTF16 ){
    incr = 2;
    c = *(char*)&one;
    zIn += c;
    nIn -= c;
  }
  
  if( nIn<=0 ) goto not_a_valid_number;







  if( zIn[0]=='-' ){
    r.sign = 1;
    i = incr;
  }else if( zIn[0]=='+' ){
    i = incr;
  }else{
    i = 0;
  }
  if( nIn<=0 ) goto not_a_valid_number;



  if( nIn>=incr*3
   && ((c=zIn[i])=='i' || c=='I')
   && ((c=zIn[i+incr])=='n' || c=='N')
   && ((c=zIn[i+incr*2])=='f' || c=='F')
  ){
    r.e = SQLITE4_MX_EXP+1;
    r.m = nIn<=i+incr*3 || zIn[i+incr*3]==0;
    return r;
  }

  while( i<nIn && (c = zIn[i])!=0 ){
    i += incr;
    if( c>='0' && c<='9' ){
      if( c=='0' && nDigit==0 ){
        if( seenRadix && r.e > -(SQLITE4_MX_EXP+1000) ) r.e--;
        continue;
      }
................................................................................
      int nEDigit = 0;
      if( zIn[i]=='-' ){
        expsign = 1;
        i += incr;
      }else if( zIn[i]=='+' ){
        i += incr;
      }
      if( i>=nIn ) goto not_a_valid_number;
      while( i<nIn && (c = zIn[i])!=0 ){
        i += incr;
        if( c<'0' || c>'9' ) goto not_a_valid_number;
        if( c=='0' && nEDigit==0 ) continue;
        nEDigit++;
        if( nEDigit>3 ) goto not_a_valid_number;
        exp = exp*10 + c - '0';
      }
      if( expsign ) exp = -exp;
      r.e += exp;
      break;
    }else{
      goto not_a_valid_number;
    }
  }
  return r;
  
not_a_valid_number:

  r.e = SQLITE4_MX_EXP+1;
  r.m = 0;







  return r;  
}

/*
** Convert an sqlite4_int64 to a number and return that number.
*/
sqlite4_num sqlite4_num_from_int64(sqlite4_int64 n){
  sqlite4_num r;
................................................................................
  for(i=num.e; i<0; i++){
    iRet = iRet / 10;
  }
  *piOut = iRet;
  return SQLITE4_OK;
}















/*
** Convert an integer into text in the buffer supplied. The
** text is zero-terminated and right-justified in the buffer.
** A pointer to the first character of text is returned.
**
** The buffer needs to be at least 21 bytes in length.
*/







|
>
>
>
|


<

<













|
>
>
>
>
>
>
>
|

|
|
|
<
<

<
>
>
>
|








>







 







|


|


|






|


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







 







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







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
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344


345

346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
...
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
...
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
**
** Conversion stops at the first \000 character.  At most nIn bytes
** of zIn are examined.  Or if nIn is negative, up to a billion bytes
** are scanned, which we assume is more than will be found in any valid
** numeric string.
*/
sqlite4_num sqlite4_num_from_text(const char *zIn, int nIn, unsigned flags){
  static int one = 1;             /* Used to test machine endianness */
  int seenRadix = 0;              /* True after decimal point has been parsed */
  int incr = 1;                   /* 1 for utf-8, 2 for utf-16 */
  int bInvalid = 1;               /* True for a bad parse */
  sqlite4_num r;                  /* Value to return */
  char c;
  int nDigit = 0;

  int i;

  
  memset(&r, 0, sizeof(r));
  if( nIn<0 ) nIn = 1000000000;
  c = flags & 0xf;
  if( c==0 || c==SQLITE4_UTF8 ){
    incr = 1;
  }else if( c==SQLITE4_UTF16 ){
    incr = 2;
    c = *(char*)&one;
    zIn += c;
    nIn -= c;
  }
  
  /* If the PREFIX_ONLY flag is set, ignore any leading whitespace. */
  i = 0;
  if( flags & SQLITE4_PREFIX_ONLY ){
    while( sqlite4Isspace(zIn[i]) && i<nIn ) i+=incr;
  }
  if( nIn<=i ) goto finished;

  /* Check for a leading '+' or '-' symbol. */
  if( zIn[i]=='-' ){
    r.sign = 1;
    i += incr;
  }else if( zIn[i]=='+' ){
    i += incr;


  }

  if( nIn<=i ) goto finished;

  /* Check for the string "inf". This is a special case. */
  if( (nIn-i)>=incr*3
   && ((c=zIn[i])=='i' || c=='I')
   && ((c=zIn[i+incr])=='n' || c=='N')
   && ((c=zIn[i+incr*2])=='f' || c=='F')
  ){
    r.e = SQLITE4_MX_EXP+1;
    r.m = nIn<=i+incr*3 || zIn[i+incr*3]==0;
    return r;
  }

  while( i<nIn && (c = zIn[i])!=0 ){
    i += incr;
    if( c>='0' && c<='9' ){
      if( c=='0' && nDigit==0 ){
        if( seenRadix && r.e > -(SQLITE4_MX_EXP+1000) ) r.e--;
        continue;
      }
................................................................................
      int nEDigit = 0;
      if( zIn[i]=='-' ){
        expsign = 1;
        i += incr;
      }else if( zIn[i]=='+' ){
        i += incr;
      }
      if( i>=nIn ) goto finished;
      while( i<nIn && (c = zIn[i])!=0 ){
        i += incr;
        if( c<'0' || c>'9' ) goto finished;
        if( c=='0' && nEDigit==0 ) continue;
        nEDigit++;
        if( nEDigit>3 ) goto finished;
        exp = exp*10 + c - '0';
      }
      if( expsign ) exp = -exp;
      r.e += exp;
      break;
    }else{
      goto finished;
    }
  }
  bInvalid = 0;

finished:
  if( bInvalid && (flags & SQLITE4_PREFIX_ONLY)==0 ){
    r.e = SQLITE4_MX_EXP+1;
    r.m = 0;
  }

  else if( seenRadix==0 && r.e==1 && r.m<=(LARGEST_INT64/10) ){
    r.m = r.m*10;
    r.e = 0;
  }

  return r;
}

/*
** Convert an sqlite4_int64 to a number and return that number.
*/
sqlite4_num sqlite4_num_from_int64(sqlite4_int64 n){
  sqlite4_num r;
................................................................................
  for(i=num.e; i<0; i++){
    iRet = iRet / 10;
  }
  *piOut = iRet;
  return SQLITE4_OK;
}


/*
** Return true if the sqlite4_num value passed as the first argument 
** may be stored in an i64 without loss of precision.
**
** TODO: This only works with values just returned from
** sqlite4_num_from_text().
*/
int sqlite4_num_is_int64(sqlite4_num num){
  if( num.approx==1 ) return 0;
  if( num.e<0 ){
  }
}

/*
** Convert an integer into text in the buffer supplied. The
** text is zero-terminated and right-justified in the buffer.
** A pointer to the first character of text is returned.
**
** The buffer needs to be at least 21 bytes in length.
*/

Changes to src/vdbe.c.

864
865
866
867
868
869
870












871
872
873
874
875
876
877
....
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
case OP_Real: {            /* same as TK_FLOAT, out2-prerelease */
  pOut->flags = MEM_Real;
  assert( !sqlite4IsNaN(*pOp->p4.pReal) );
  pOut->u.num = sqlite4_num_from_double(*pOp->p4.pReal);
  break;
}
#endif













/* Opcode: String8 * P2 * P4 *
**
** P4 points to a nul terminated UTF-8 string. This opcode is transformed 
** into an OP_String before it is executed for the first time.
*/
case OP_String8: {         /* same as TK_STRING, out2-prerelease */
................................................................................
** equivalent of atoi() and store 0.0 if no such conversion is possible.
**
** A NULL value is not changed by this routine.  It remains NULL.
*/
case OP_ToReal: {                  /* same as TK_TO_REAL, in1 */
  pIn1 = &aMem[pOp->p1];
  memAboutToChange(p, pIn1);
  if( (pIn1->flags & MEM_Null)==0 ){
    sqlite4VdbeMemRealify(pIn1);
  }
  break;
}
#endif /* !defined(SQLITE4_OMIT_CAST) && !defined(SQLITE4_OMIT_FLOATING_POINT) */

/* Opcode: Lt P1 P2 P3 P4 P5
**
** Compare the values in register P1 and P3.  If reg(P3)<reg(P1) then







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







 







|
|
|







864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
....
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
case OP_Real: {            /* same as TK_FLOAT, out2-prerelease */
  pOut->flags = MEM_Real;
  assert( !sqlite4IsNaN(*pOp->p4.pReal) );
  pOut->u.num = sqlite4_num_from_double(*pOp->p4.pReal);
  break;
}
#endif

/* Opcode: Num P1 P2 * P4 *
**
** P4 is a pointer to an sqlite4_num value. Write that value into 
** register P2. Set the register flags to MEM_Int if P1 is non-zero,
** or MEM_Real otherwise.
*/
case OP_Num: {            /* out2-prerelease */
  pOut->flags = (pOp->p1 ? MEM_Int : MEM_Real);
  pOut->u.num = *(pOp->p4.pNum);
  break;
}

/* Opcode: String8 * P2 * P4 *
**
** P4 points to a nul terminated UTF-8 string. This opcode is transformed 
** into an OP_String before it is executed for the first time.
*/
case OP_String8: {         /* same as TK_STRING, out2-prerelease */
................................................................................
** equivalent of atoi() and store 0.0 if no such conversion is possible.
**
** A NULL value is not changed by this routine.  It remains NULL.
*/
case OP_ToReal: {                  /* same as TK_TO_REAL, in1 */
  pIn1 = &aMem[pOp->p1];
  memAboutToChange(p, pIn1);
  sqlite4VdbeMemNumerify(pIn1);
  pIn1->flags |= MEM_Real;
  pIn1->flags &= ~MEM_Int;
  break;
}
#endif /* !defined(SQLITE4_OMIT_CAST) && !defined(SQLITE4_OMIT_FLOATING_POINT) */

/* Opcode: Lt P1 P2 P3 P4 P5
**
** Compare the values in register P1 and P3.  If reg(P3)<reg(P1) then

Changes to src/vdbe.h.

60
61
62
63
64
65
66

67
68
69
70
71
72
73
...
118
119
120
121
122
123
124

125
126
127
128
129
130
131
    Mem *pMem;             /* Used when p4type is P4_MEM */
    VTable *pVtab;         /* Used when p4type is P4_VTAB */
    KeyInfo *pKeyInfo;     /* Used when p4type is P4_KEYINFO */
    int *ai;               /* Used when p4type is P4_INTARRAY */
    SubProgram *pProgram;  /* Used when p4type is P4_SUBPROGRAM */
    Fts5Info *pFtsInfo;    /* Used when p4type is P4_FTS5INDEXINFO */
    int (*xAdvance)(VdbeCursor*);

  } p4;
#ifdef SQLITE4_DEBUG
  char *zComment;          /* Comment to improve readability */
#endif
#ifdef VDBE_PROFILE
  int cnt;                 /* Number of times this instruction was executed */
  u64 cycles;              /* Total time spent executing this instruction */
................................................................................
#define P4_REAL     (-12) /* P4 is a 64-bit floating point value */
#define P4_INT64    (-13) /* P4 is a 64-bit signed integer */
#define P4_INT32    (-14) /* P4 is a 32-bit signed integer */
#define P4_INTARRAY (-15) /* P4 is a vector of 32-bit integers */
#define P4_SUBPROGRAM  (-18) /* P4 is a pointer to a SubProgram structure */
#define P4_ADVANCE  (-19) /* P4 is a pointer to BtreeNext() or BtreePrev() */
#define P4_FTS5INFO (-20) /* P4 points to an Fts5Info structure */


/* When adding a P4 argument using P4_KEYINFO, a copy of the KeyInfo structure
** is made.  That copy is freed when the Vdbe is finalized.  But if the
** argument is P4_KEYINFO_HANDOFF, the passed in pointer is used.  It still
** gets freed when the Vdbe is finalized so it still should be obtained
** from a single sqliteMalloc().  But no copy is made and the calling
** function should *not* try to free the KeyInfo.







>







 







>







60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
...
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
    Mem *pMem;             /* Used when p4type is P4_MEM */
    VTable *pVtab;         /* Used when p4type is P4_VTAB */
    KeyInfo *pKeyInfo;     /* Used when p4type is P4_KEYINFO */
    int *ai;               /* Used when p4type is P4_INTARRAY */
    SubProgram *pProgram;  /* Used when p4type is P4_SUBPROGRAM */
    Fts5Info *pFtsInfo;    /* Used when p4type is P4_FTS5INDEXINFO */
    int (*xAdvance)(VdbeCursor*);
    sqlite4_num *pNum;     /* Used when p4type is P4_NUM */
  } p4;
#ifdef SQLITE4_DEBUG
  char *zComment;          /* Comment to improve readability */
#endif
#ifdef VDBE_PROFILE
  int cnt;                 /* Number of times this instruction was executed */
  u64 cycles;              /* Total time spent executing this instruction */
................................................................................
#define P4_REAL     (-12) /* P4 is a 64-bit floating point value */
#define P4_INT64    (-13) /* P4 is a 64-bit signed integer */
#define P4_INT32    (-14) /* P4 is a 32-bit signed integer */
#define P4_INTARRAY (-15) /* P4 is a vector of 32-bit integers */
#define P4_SUBPROGRAM  (-18) /* P4 is a pointer to a SubProgram structure */
#define P4_ADVANCE  (-19) /* P4 is a pointer to BtreeNext() or BtreePrev() */
#define P4_FTS5INFO (-20) /* P4 points to an Fts5Info structure */
#define P4_NUM      (-21) /* P4 points to an Fts5Info structure */

/* When adding a P4 argument using P4_KEYINFO, a copy of the KeyInfo structure
** is made.  That copy is freed when the Vdbe is finalized.  But if the
** argument is P4_KEYINFO_HANDOFF, the passed in pointer is used.  It still
** gets freed when the Vdbe is finalized so it still should be obtained
** from a single sqliteMalloc().  But no copy is made and the calling
** function should *not* try to free the KeyInfo.

Changes to src/vdbeaux.c.

578
579
580
581
582
583
584

585
586
587
588
589
590
591
** Delete a P4 value if necessary.
*/
static void freeP4(sqlite4 *db, int p4type, void *p4){
  if( p4 ){
    assert( db );
    switch( p4type ){
      case P4_REAL:

      case P4_INT64:
      case P4_DYNAMIC:
      case P4_KEYINFO:
      case P4_INTARRAY:
      case P4_KEYINFO_HANDOFF: {
        sqlite4DbFree(db, p4);
        break;







>







578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
** Delete a P4 value if necessary.
*/
static void freeP4(sqlite4 *db, int p4type, void *p4){
  if( p4 ){
    assert( db );
    switch( p4type ){
      case P4_REAL:
      case P4_NUM:
      case P4_INT64:
      case P4_DYNAMIC:
      case P4_KEYINFO:
      case P4_INTARRAY:
      case P4_KEYINFO_HANDOFF: {
        sqlite4DbFree(db, p4);
        break;

Changes to src/vdbemem.c.

392
393
394
395
396
397
398






399

400

401
402
403
404
405
406
407
...
420
421
422
423
424
425
426
427

428
429







430
431
432
433
434
435
436
437

438
439
440
441
442
443
444
** Convert pMem to type integer.  Invalidate any prior representations.
*/
int sqlite4VdbeMemIntegerify(Mem *pMem){
  assert( pMem->db==0 || sqlite4_mutex_held(pMem->db->mutex) );
  assert( (pMem->flags & MEM_RowSet)==0 );
  assert( EIGHT_BYTE_ALIGNMENT(pMem) );







  pMem->u.num = sqlite4_num_from_int64(sqlite4VdbeIntValue(pMem));

  MemSetTypeFlag(pMem, MEM_Int);

  return SQLITE4_OK;
}

/*
** Convert pMem so that it is of type MEM_Real.
** Invalidate any prior representations.
*/
................................................................................
**
** Every effort is made to force the conversion, even if the input
** is a string that does not look completely like a number.  Convert
** as much of the string as we can and ignore the rest.
*/
int sqlite4VdbeMemNumerify(Mem *pMem){
  if( (pMem->flags & (MEM_Int|MEM_Real|MEM_Null))==0 ){
    i64 i1;

    assert( (pMem->flags & (MEM_Blob|MEM_Str))!=0 );
    assert( pMem->db==0 || sqlite4_mutex_held(pMem->db->mutex) );







    if( 0==sqlite4Atoi64(pMem->z, &i1, pMem->n, pMem->enc) ){
      pMem->u.num = sqlite4_num_from_int64(i1);
      MemSetTypeFlag(pMem, MEM_Int);
    }else{
      pMem->u.num = sqlite4_num_from_double(sqlite4VdbeRealValue(pMem));
      MemSetTypeFlag(pMem, MEM_Real);
      sqlite4VdbeIntegerAffinity(pMem);
    }

  }
  assert( (pMem->flags & (MEM_Int|MEM_Real|MEM_Null))!=0 );
  pMem->flags &= ~(MEM_Str|MEM_Blob);
  return SQLITE4_OK;
}

/*







>
>
>
>
>
>
|
>

>







 







|
>


>
>
>
>
>
>
>








>







392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
...
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
** Convert pMem to type integer.  Invalidate any prior representations.
*/
int sqlite4VdbeMemIntegerify(Mem *pMem){
  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 ){
    i64 iVal;
    sqlite4_num_to_int64(pMem->u.num, &iVal);
    pMem->u.num = sqlite4_num_from_int64(iVal);
  }
  MemSetTypeFlag(pMem, MEM_Int);

  return SQLITE4_OK;
}

/*
** Convert pMem so that it is of type MEM_Real.
** Invalidate any prior representations.
*/
................................................................................
**
** Every effort is made to force the conversion, even if the input
** is a string that does not look completely like a number.  Convert
** as much of the string as we can and ignore the rest.
*/
int sqlite4VdbeMemNumerify(Mem *pMem){
  if( (pMem->flags & (MEM_Int|MEM_Real|MEM_Null))==0 ){
    int flags = (pMem->enc | SQLITE4_PREFIX_ONLY);

    assert( (pMem->flags & (MEM_Blob|MEM_Str))!=0 );
    assert( pMem->db==0 || sqlite4_mutex_held(pMem->db->mutex) );
    pMem->u.num = sqlite4_num_from_text(pMem->z, pMem->n, flags);
    if( pMem->u.num.e==0 ){
      MemSetTypeFlag(pMem, MEM_Int);
    }else{
      MemSetTypeFlag(pMem, MEM_Real);
    }
#if 0
    if( 0==sqlite4Atoi64(pMem->z, &i1, pMem->n, pMem->enc) ){
      pMem->u.num = sqlite4_num_from_int64(i1);
      MemSetTypeFlag(pMem, MEM_Int);
    }else{
      pMem->u.num = sqlite4_num_from_double(sqlite4VdbeRealValue(pMem));
      MemSetTypeFlag(pMem, MEM_Real);
      sqlite4VdbeIntegerAffinity(pMem);
    }
#endif
  }
  assert( (pMem->flags & (MEM_Int|MEM_Real|MEM_Null))!=0 );
  pMem->flags &= ~(MEM_Str|MEM_Blob);
  return SQLITE4_OK;
}

/*

Added test/auth4.test.







































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# 2013 May 8
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
#
# This file contains tests for the sqlite4_authorizer_push() and
# sqlite4_authorizer_pop() API functions.
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix auth4

ifcapable !auth { finish_test ; return }

#--------------------------------------------------------------------
# Test cases auth4-1.* test that when there are multiple authorizers
# on the stack, they are invoked in order from most to least recently 
# added until all have been invoked or one of them returns other than
# SQLITE4_OK.
#
do_execsql_test 1.0 {
  CREATE TABLE t1(x, y);
  INSERT INTO t1 VALUES(1, 'one');
  INSERT INTO t1 VALUES(2, 'two');
}

proc auth_callback {id code z1 z2 z3 z4} {
  if {$code == "SQLITE4_READ" && $z1=="t1" && $z2=="y"} {
    incr ::NAUTH
    return [lindex $::AUTH $id]
  }
  return SQLITE4_OK
}

sqlite4_authorizer_push db {auth_callback 2}
sqlite4_authorizer_push db {auth_callback 1}
sqlite4_authorizer_push db {auth_callback 0}

foreach {tn codes ncall res} {
  1  {SQLITE4_OK SQLITE4_OK SQLITE4_OK}   3 {0 {1 one 2 two}}

  2  {SQLITE4_OK SQLITE4_OK SQLITE4_DENY} 3 {1 {access to t1.y is prohibited}}
  3  {SQLITE4_DENY SQLITE4_OK SQLITE4_OK} 1 {1 {access to t1.y is prohibited}}
  4  {SQLITE4_OK SQLITE4_DENY SQLITE4_OK} 2 {1 {access to t1.y is prohibited}}

  5  {SQLITE4_OK SQLITE4_OK SQLITE4_IGNORE} 3 {0 {1 {} 2 {}}}
  6  {SQLITE4_IGNORE SQLITE4_OK SQLITE4_OK} 1 {0 {1 {} 2 {}}}
  7  {SQLITE4_OK SQLITE4_IGNORE SQLITE4_OK} 2 {0 {1 {} 2 {}}}

  8  {SQLITE4_OK SQLITE4_OK SQLITE4_ALLOW} 3 {0 {1 one 2 two}}
  9  {SQLITE4_ALLOW SQLITE4_OK SQLITE4_OK} 1 {0 {1 one 2 two}}
  10 {SQLITE4_OK SQLITE4_ALLOW SQLITE4_OK} 2 {0 {1 one 2 two}}

} {
  db cache flush

  set ::AUTH $codes
  set ::NAUTH 0

  do_catchsql_test 1.$tn.1 { SELECT * FROM t1; } $res
  do_test 1.$tn.2 { set ::NAUTH } $ncall
}

sqlite4_authorizer_pop db
sqlite4_authorizer_pop db
sqlite4_authorizer_pop db

#--------------------------------------------------------------------
# Test cases auth4-2.* test that the push and pop operations seem to
# work correctly.
#
set ::STACK [list]
proc auth_callback {id code z1 z2 z3 z4} {
  if {$code == "SQLITE4_READ" && $z1=="t1" && $z2=="y"} {
    lappend ::AUTH $id
  }
  return SQLITE4_OK
}
proc test_stack {} {
  set ::AUTH [list]
  db eval { SELECT * FROM t1 }
  set ::AUTH
}
proc push {id} {
  set ::STACK [concat $id $::STACK]
  sqlite4_authorizer_push db [list auth_callback $id]
}
proc pop {} {
  set ::STACK [lrange $::STACK 1 end]
  sqlite4_authorizer_pop db
}

do_execsql_test 2.0 {
  DROP TABLE IF EXISTS t1;
  CREATE TABLE t1(x, y);
  INSERT INTO t1 VALUES(1, 'one');
}

for {set i 1} {$i <= 100} {incr i} {
  if { int(rand()*2.0) } {
    pop
  } else {
    push [expr int(rand() * 500.0)]
  }
  do_test 2.$i { test_stack } $::STACK
}

#--------------------------------------------------------------------
# Test that sqlite4_authorizer_pop() returns an error if the stack is
# empty when it is called.
#
db close
sqlite4 db test.db

do_test 3.1 {
  sqlite4_authorizer_pop db
} {SQLITE4_ERROR}
do_test 3.2 {
  sqlite4_authorizer_push db xyz
  sqlite4_authorizer_pop db
} {SQLITE4_OK}

finish_test