SQLite

Check-in [2ac985a380]
Login

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

Overview
Comment:Keep the full precision of integers if possible when casting to "numeric". Ticket #2364. (CVS 4012)
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 2ac985a38034da87b0fa3837976e1f2164b22672
User & Date: drh 2007-05-16 11:55:57.000
Context
2007-05-16
13:55
Add a --nostatic option to mksqlite3c.tcl. With this option turned on, the extra "static" storage class markers are not inserted into the amalgamation. (CVS 4013) (check-in: 57e17c7cda user: drh tags: trunk)
11:55
Keep the full precision of integers if possible when casting to "numeric". Ticket #2364. (CVS 4012) (check-in: 2ac985a380 user: drh tags: trunk)
2007-05-15
18:35
Additional tests for malformed UTF-8. (CVS 4011) (check-in: 448d3ef670 user: drh tags: trunk)
Changes
Side-by-Side Diff Ignore Whitespace Patch
Changes to src/vdbe.c.
39
40
41
42
43
44
45
46

47
48
49
50
51
52
53
39
40
41
42
43
44
45

46
47
48
49
50
51
52
53







-
+







**
** Various scripts scan this source file in order to generate HTML
** documentation, headers files, or other derived files.  The formatting
** of the code in this file is, therefore, important.  See other comments
** in this file for details.  If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code.
**
** $Id: vdbe.c,v 1.618 2007/05/12 12:08:51 drh Exp $
** $Id: vdbe.c,v 1.619 2007/05/16 11:55:57 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>
#include <math.h>
#include "vdbeInt.h"

1505
1506
1507
1508
1509
1510
1511
1512

1513
1514
1515
1516
1517
1518
1519
1505
1506
1507
1508
1509
1510
1511

1512
1513
1514
1515
1516
1517
1518
1519







-
+







** equivalent of atoi() or atof() and store 0 if no such conversion 
** is possible.
**
** A NULL value is not changed by this routine.  It remains NULL.
*/
case OP_ToNumeric: {                  /* same as TK_TO_NUMERIC, no-push */
  assert( pTos>=p->aStack );
  if( (pTos->flags & MEM_Null)==0 ){
  if( (pTos->flags & (MEM_Null|MEM_Int|MEM_Real))==0 ){
    sqlite3VdbeMemNumerify(pTos);
  }
  break;
}
#endif /* SQLITE_OMIT_CAST */

/* Opcode: ToInt * * *
1759
1760
1761
1762
1763
1764
1765



1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769

1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780





1781
1782
1783
1784
1785
1786
1787







+
+
+

-











-
-
-
-
-







** Treat the top of the stack as a numeric quantity.  Replace it
** with its absolute value. If the top of the stack is NULL
** its value is unchanged.
*/
case OP_Negative:              /* same as TK_UMINUS, no-push */
case OP_AbsValue: {
  assert( pTos>=p->aStack );
  if( (pTos->flags & (MEM_Real|MEM_Int|MEM_Null))==0 ){
    sqlite3VdbeMemNumerify(pTos);
  }
  if( pTos->flags & MEM_Real ){
    neg_abs_real_case:
    Release(pTos);
    if( pOp->opcode==OP_Negative || pTos->r<0.0 ){
      pTos->r = -pTos->r;
    }
    pTos->flags = MEM_Real;
  }else if( pTos->flags & MEM_Int ){
    Release(pTos);
    if( pOp->opcode==OP_Negative || pTos->u.i<0 ){
      pTos->u.i = -pTos->u.i;
    }
    pTos->flags = MEM_Int;
  }else if( pTos->flags & MEM_Null ){
    /* Do nothing */
  }else{
    sqlite3VdbeMemNumerify(pTos);
    goto neg_abs_real_case;
  }
  break;
}

/* Opcode: Not * * *
**
** Interpret the top of the stack as a boolean value.  Replace it
Changes to src/vdbemem.c.
358
359
360
361
362
363
364












365

366

367
368
369
370
371
372
373
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







+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+







}

/*
** Convert pMem so that it has types MEM_Real or MEM_Int or both.
** 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 );
  r1 = sqlite3VdbeRealValue(pMem);
  i = (i64)r1;
  r2 = (double)i;
  if( r1==r2 ){
    sqlite3VdbeMemIntegerify(pMem);
  }else{
    pMem->r = r1;
    pMem->flags = MEM_Real;
  sqlite3VdbeMemRealify(pMem);
    sqlite3VdbeMemRelease(pMem);
  sqlite3VdbeIntegerAffinity(pMem);
  }
  return SQLITE_OK;
}

/*
** Delete any previous value and set the value stored in *pMem to NULL.
*/
void sqlite3VdbeMemSetNull(Mem *pMem){
Changes to test/cast.test.
1
2
3
4
5
6
7
8
9
10
11
12
13
14

15
16
17
18
19
20
21
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
21













-
+







# 2005 June 25
#
# 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 implements regression tests for SQLite library.  The
# focus of this file is testing the CAST operator.
#
# $Id: cast.test,v 1.5 2006/03/03 19:12:30 drh Exp $
# $Id: cast.test,v 1.6 2007/05/16 11:55:57 drh Exp $

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

# Only run these tests if the build includes the CAST operator
ifcapable !cast {
  finish_test
187
188
189
190
191
192
193
194



195




































































196
187
188
189
190
191
192
193
194
195
196
197

198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
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








+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

#
do_test cast-2.1 {
  execsql {SELECT CAST('   123' AS integer)}
} 123
do_test cast-2.2 {
  execsql {SELECT CAST('   -123.456' AS real)}
} -123.456

# ticket #2364.  Use full percision integers if possible when casting
# to numeric.  Do not fallback to real (and the corresponding 48-bit
# mantissa) unless absolutely necessary.

#
do_test cast-3.1 {
  execsql {SELECT CAST(9223372036854774800 AS integer)}
} 9223372036854774800
do_test cast-3.2 {
  execsql {SELECT CAST(9223372036854774800 AS numeric)}
} 9223372036854774800
do_test cast-3.3 {
  execsql {SELECT CAST(9223372036854774800 AS real)}
} 9.22337203685477e+18
do_test cast-3.4 {
  execsql {SELECT CAST(CAST(9223372036854774800 AS real) AS integer)}
} 9223372036854774784
do_test cast-3.5 {
  execsql {SELECT CAST(-9223372036854774800 AS integer)}
} -9223372036854774800
do_test cast-3.6 {
  execsql {SELECT CAST(-9223372036854774800 AS numeric)}
} -9223372036854774800
do_test cast-3.7 {
  execsql {SELECT CAST(-9223372036854774800 AS real)}
} -9.22337203685477e+18
do_test cast-3.8 {
  execsql {SELECT CAST(CAST(-9223372036854774800 AS real) AS integer)}
} -9223372036854774784
do_test cast-3.11 {
  execsql {SELECT CAST('9223372036854774800' AS integer)}
} 9223372036854774800
do_test cast-3.12 {
  execsql {SELECT CAST('9223372036854774800' AS numeric)}
} 9223372036854774800
do_test cast-3.13 {
  execsql {SELECT CAST('9223372036854774800' AS real)}
} 9.22337203685477e+18
do_test cast-3.14 {
  execsql {SELECT CAST(CAST('9223372036854774800' AS real) AS integer)}
} 9223372036854774784
do_test cast-3.15 {
  execsql {SELECT CAST('-9223372036854774800' AS integer)}
} -9223372036854774800
do_test cast-3.16 {
  execsql {SELECT CAST('-9223372036854774800' AS numeric)}
} -9223372036854774800
do_test cast-3.17 {
  execsql {SELECT CAST('-9223372036854774800' AS real)}
} -9.22337203685477e+18
do_test cast-3.18 {
  execsql {SELECT CAST(CAST('-9223372036854774800' AS real) AS integer)}
} -9223372036854774784
if {[db eval {PRAGMA encoding}]=="UTF-8"} {
  do_test cast-3.21 {
    execsql {SELECT CAST(x'39323233333732303336383534373734383030' AS integer)}
  } 9223372036854774800
  do_test cast-3.22 {
    execsql {SELECT CAST(x'39323233333732303336383534373734383030' AS numeric)}
  } 9223372036854774800
  do_test cast-3.23 {
    execsql {SELECT CAST(x'39323233333732303336383534373734383030' AS real)}
  } 9.22337203685477e+18
  do_test cast-3.24 {
    execsql {SELECT CAST(CAST(x'39323233333732303336383534373734383030' AS real) AS integer)}
  } 9223372036854774784
}
do_test case-3.31 {
  execsql {SELECT CAST(NULL AS numeric)}
} {{}}


finish_test