SQLite

Check-in [ce6cc16e3a]
Login

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

Overview
Comment:Fix the handling of default values for ALTER TABLE ADD COLUMN columns so that is able to deal with negative numbers, including large negative numbers. Ticket [8454a207b9fd2243c4]
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | experimental
Files: files | file ages | folders
SHA1: ce6cc16e3a151a0c67855abde1411422dfcc8828
User & Date: drh 2010-09-30 14:48:06.000
Context
2010-09-30
16:51
Changes to remove sqlite3FitsIn64Bits(). (check-in: 43fef1cab6 user: shaneh tags: experimental)
14:48
Fix the handling of default values for ALTER TABLE ADD COLUMN columns so that is able to deal with negative numbers, including large negative numbers. Ticket [8454a207b9fd2243c4] (check-in: ce6cc16e3a user: drh tags: experimental)
00:50
Rework the text to numeric conversion routines so that they work with either UTF8 or UTF16 and do not require a NULL terminator. This allowed text to numeric conversion without reallocating the string. (check-in: 14eed3a0e0 user: drh tags: experimental)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/vdbe.c.
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
** is possible.
**
** A NULL value is not changed by this routine.  It remains NULL.
*/
case OP_ToNumeric: {                  /* same as TK_TO_NUMERIC, in1 */
  pIn1 = &aMem[pOp->p1];
  memAboutToChange(p, pIn1);
  if( (pIn1->flags & (MEM_Null|MEM_Int|MEM_Real))==0 ){
    sqlite3VdbeMemNumerify(pIn1);
  }
  break;
}
#endif /* SQLITE_OMIT_CAST */

/* Opcode: ToInt P1 * * * *
**
** Force the value in register P1 to be an integer.  If







<
|
<







1606
1607
1608
1609
1610
1611
1612

1613

1614
1615
1616
1617
1618
1619
1620
** is possible.
**
** A NULL value is not changed by this routine.  It remains NULL.
*/
case OP_ToNumeric: {                  /* same as TK_TO_NUMERIC, in1 */
  pIn1 = &aMem[pOp->p1];
  memAboutToChange(p, pIn1);

  sqlite3VdbeMemNumerify(pIn1);

  break;
}
#endif /* SQLITE_OMIT_CAST */

/* Opcode: ToInt P1 * * * *
**
** Force the value in register P1 to be an integer.  If
Changes to src/vdbemem.c.
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490



491
492
493
494
495
496
497
** 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 sqlite3VdbeMemNumerify(Mem *pMem){
  int rc;
  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) );
  rc = sqlite3VdbeChangeEncoding(pMem, SQLITE_UTF8);
  if( rc ) return rc;
  rc = sqlite3VdbeMemNulTerminate(pMem);
  if( rc ) return rc;
  if( sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, SQLITE_UTF8) ){
    MemSetTypeFlag(pMem, MEM_Int);
  }else{
    pMem->r = sqlite3VdbeRealValue(pMem);
    MemSetTypeFlag(pMem, MEM_Real);
    sqlite3VdbeIntegerAffinity(pMem);
  }



  return SQLITE_OK;
}

/*
** Delete any previous value and set the value stored in *pMem to NULL.
*/
void sqlite3VdbeMemSetNull(Mem *pMem){







<
|
|
|
<
<
<
<
|
|
|
|
|
|
|
>
>
>







469
470
471
472
473
474
475

476
477
478




479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
** 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 sqlite3VdbeMemNumerify(Mem *pMem){

  if( (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) );




    if( sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc) ){
      MemSetTypeFlag(pMem, MEM_Int);
    }else{
      pMem->r = sqlite3VdbeRealValue(pMem);
      MemSetTypeFlag(pMem, MEM_Real);
      sqlite3VdbeIntegerAffinity(pMem);
    }
  }
  assert( (pMem->flags & (MEM_Int|MEM_Real|MEM_Null))!=0 );
  pMem->flags &= ~(MEM_Str|MEM_Blob);
  return SQLITE_OK;
}

/*
** Delete any previous value and set the value stored in *pMem to NULL.
*/
void sqlite3VdbeMemSetNull(Mem *pMem){
1026
1027
1028
1029
1030
1031
1032


1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048











1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065

1066
1067
1068
1069

1070

1071
1072
1073

1074
1075
1076
1077
1078
1079
1080
  u8 enc,                   /* Encoding to use */
  u8 affinity,              /* Affinity to use */
  sqlite3_value **ppVal     /* Write the new value here */
){
  int op;
  char *zVal = 0;
  sqlite3_value *pVal = 0;



  if( !pExpr ){
    *ppVal = 0;
    return SQLITE_OK;
  }
  op = pExpr->op;

  /* op can only be TK_REGISTER if we have compiled with SQLITE_ENABLE_STAT2.
  ** The ifdef here is to enable us to achieve 100% branch test coverage even
  ** when SQLITE_ENABLE_STAT2 is omitted.
  */
#ifdef SQLITE_ENABLE_STAT2
  if( op==TK_REGISTER ) op = pExpr->op2;
#else
  if( NEVER(op==TK_REGISTER) ) op = pExpr->op2;
#endif












  if( op==TK_STRING || op==TK_FLOAT || op==TK_INTEGER ){
    pVal = sqlite3ValueNew(db);
    if( pVal==0 ) goto no_mem;
    if( ExprHasProperty(pExpr, EP_IntValue) ){
      sqlite3VdbeMemSetInt64(pVal, (i64)pExpr->u.iValue);
    }else{
      zVal = sqlite3DbStrDup(db, pExpr->u.zToken);
      if( zVal==0 ) goto no_mem;
      sqlite3ValueSetStr(pVal, -1, zVal, SQLITE_UTF8, SQLITE_DYNAMIC);
      if( op==TK_FLOAT ) pVal->type = SQLITE_FLOAT;
    }
    if( (op==TK_INTEGER || op==TK_FLOAT ) && affinity==SQLITE_AFF_NONE ){
      sqlite3ValueApplyAffinity(pVal, SQLITE_AFF_NUMERIC, SQLITE_UTF8);
    }else{
      sqlite3ValueApplyAffinity(pVal, affinity, SQLITE_UTF8);
    }

    if( enc!=SQLITE_UTF8 ){
      sqlite3VdbeChangeEncoding(pVal, enc);
    }
  }else if( op==TK_UMINUS ) {

    if( SQLITE_OK==sqlite3ValueFromExpr(db,pExpr->pLeft,enc,affinity,&pVal) ){

      pVal->u.i = -1 * pVal->u.i;
      /* (double)-1 In case of SQLITE_OMIT_FLOATING_POINT... */
      pVal->r = (double)-1 * pVal->r;

    }
  }
#ifndef SQLITE_OMIT_BLOB_LITERAL
  else if( op==TK_BLOB ){
    int nVal;
    assert( pExpr->u.zToken[0]=='x' || pExpr->u.zToken[0]=='X' );
    assert( pExpr->u.zToken[1]=='\'' );







>
>
















>
>
>
>
>
>
>
>
>
>
>





|

|









>




>

>



>







1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
  u8 enc,                   /* Encoding to use */
  u8 affinity,              /* Affinity to use */
  sqlite3_value **ppVal     /* Write the new value here */
){
  int op;
  char *zVal = 0;
  sqlite3_value *pVal = 0;
  int negInt = 1;
  const char *zNeg = "";

  if( !pExpr ){
    *ppVal = 0;
    return SQLITE_OK;
  }
  op = pExpr->op;

  /* op can only be TK_REGISTER if we have compiled with SQLITE_ENABLE_STAT2.
  ** The ifdef here is to enable us to achieve 100% branch test coverage even
  ** when SQLITE_ENABLE_STAT2 is omitted.
  */
#ifdef SQLITE_ENABLE_STAT2
  if( op==TK_REGISTER ) op = pExpr->op2;
#else
  if( NEVER(op==TK_REGISTER) ) op = pExpr->op2;
#endif

  /* Handle negative integers in a single step.  This is needed in the
  ** case when the value is -9223372036854775808.
  */
  if( op==TK_UMINUS
   && (pExpr->pLeft->op==TK_INTEGER || pExpr->pLeft->op==TK_FLOAT) ){
    pExpr = pExpr->pLeft;
    op = pExpr->op;
    negInt = -1;
    zNeg = "-";
  }

  if( op==TK_STRING || op==TK_FLOAT || op==TK_INTEGER ){
    pVal = sqlite3ValueNew(db);
    if( pVal==0 ) goto no_mem;
    if( ExprHasProperty(pExpr, EP_IntValue) ){
      sqlite3VdbeMemSetInt64(pVal, (i64)pExpr->u.iValue*negInt);
    }else{
      zVal = sqlite3MPrintf(db, "%s%s", zNeg, pExpr->u.zToken);
      if( zVal==0 ) goto no_mem;
      sqlite3ValueSetStr(pVal, -1, zVal, SQLITE_UTF8, SQLITE_DYNAMIC);
      if( op==TK_FLOAT ) pVal->type = SQLITE_FLOAT;
    }
    if( (op==TK_INTEGER || op==TK_FLOAT ) && affinity==SQLITE_AFF_NONE ){
      sqlite3ValueApplyAffinity(pVal, SQLITE_AFF_NUMERIC, SQLITE_UTF8);
    }else{
      sqlite3ValueApplyAffinity(pVal, affinity, SQLITE_UTF8);
    }
    if( pVal->flags & (MEM_Int|MEM_Real) ) pVal->flags &= ~MEM_Str;
    if( enc!=SQLITE_UTF8 ){
      sqlite3VdbeChangeEncoding(pVal, enc);
    }
  }else if( op==TK_UMINUS ) {
    /* This branch happens for multiple negative signs.  Ex: -(-5) */
    if( SQLITE_OK==sqlite3ValueFromExpr(db,pExpr->pLeft,enc,affinity,&pVal) ){
      sqlite3VdbeMemNumerify(pVal);
      pVal->u.i = -1 * pVal->u.i;
      /* (double)-1 In case of SQLITE_OMIT_FLOATING_POINT... */
      pVal->r = (double)-1 * pVal->r;
      sqlite3ValueApplyAffinity(pVal, affinity, enc);
    }
  }
#ifndef SQLITE_OMIT_BLOB_LITERAL
  else if( op==TK_BLOB ){
    int nVal;
    assert( pExpr->u.zToken[0]=='x' || pExpr->u.zToken[0]=='X' );
    assert( pExpr->u.zToken[1]=='\'' );
Added test/tkt-8454a207b9.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
# 2010 September 30
#
# 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. Specifically,
# it tests that ticket [8454a207b9fd2243c4c6b7a73f67ea0315717c1a].  Verify
# that a negative default value on an added text column actually comes
# out negative.
#

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

do_test tkt-8454a207b9.1 {
  db eval {
    CREATE TABLE t1(a);
    INSERT INTO t1 VALUES(1);
    ALTER TABLE t1 ADD COLUMN b TEXT DEFAULT -123.0;
    SELECT b, typeof(b) FROM t1;
  }
} {-123.0 text}
do_test tkt-8454a207b9.2 {
  db eval {
    ALTER TABLE t1 ADD COLUMN c TEXT DEFAULT -123.5;
    SELECT c, typeof(c) FROM t1;
  }
} {-123.5 text}
do_test tkt-8454a207b9.3 {
  db eval {
    ALTER TABLE t1 ADD COLUMN d TEXT DEFAULT -'hello';
    SELECT d, typeof(d) FROM t1;
  }
} {0 text}
do_test tkt-8454a207b9.4 {
  db eval {
    ALTER TABLE t1 ADD COLUMN e DEFAULT -123.0;
    SELECT e, typeof(e) FROM t1;
  }
} {-123 integer}
do_test tkt-8454a207b9.5 {
  db eval {
    ALTER TABLE t1 ADD COLUMN f DEFAULT -123.5;
    SELECT f, typeof(f) FROM t1;
  }
} {-123.5 real}
do_test tkt-8454a207b9.6 {
  db eval {
    ALTER TABLE t1 ADD COLUMN g DEFAULT -9223372036854775808;
    SELECT g, typeof(g) FROM t1;
  }
} {-9223372036854775808 integer}
do_test tkt-8454a207b9.7 {
  db eval {
    ALTER TABLE t1 ADD COLUMN h DEFAULT 9223372036854775807;
    SELECT h, typeof(h) FROM t1;
  }
} {9223372036854775807 integer}


finish_test