/ Check-in [df9cc852]
Login

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

Overview
Comment:Multiplying NULL by zero gives NULL, not zero. I misread the test data and coded it wrong. This check-in fixes the problem. (CVS 601)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: df9cc852ad02dbec5558d3915a0303f7e7b79b2b
User & Date: drh 2002-06-01 21:41:10
Context
2002-06-02
16:09
Enhance the ORDER BY clause so that an integer term means to sort by the corresponding column. (CVS 602) check-in: 7acbf84b user: drh tags: trunk
2002-06-01
21:41
Multiplying NULL by zero gives NULL, not zero. I misread the test data and coded it wrong. This check-in fixes the problem. (CVS 601) check-in: df9cc852 user: drh tags: trunk
2002-05-31
15:51
Refinements to NULL processing: NULLs are indistinct for DISTINCT and UNION. Multiplying a NULL by zero yields zero. In a CASE expression, a NULL comparison is considered false, not NULL. With these changes, NULLs in SQLite now work the same as in PostgreSQL and in Oracle. (CVS 600) check-in: da61aa1d user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/vdbe.c.

26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
....
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
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
** type to the other occurs as necessary.
** 
** Most of the code in this file is taken up by the sqliteVdbeExec()
** function which does the work of interpreting a VDBE program.
** But other routines are also provided to help in building up
** a program instruction by instruction.
**
** $Id: vdbe.c,v 1.151 2002/05/31 15:51:26 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** The following global variable is incremented every time a cursor
** moves, either by the OP_MoveTo or the OP_Next opcode.  The test
................................................................................
case OP_Multiply:
case OP_Divide:
case OP_Remainder: {
  int tos = p->tos;
  int nos = tos - 1;
  VERIFY( if( nos<0 ) goto not_enough_stack; )
  if( ((aStack[tos].flags | aStack[nos].flags) & STK_Null)!=0 ){
    int resultType = STK_Null;
    if( pOp->opcode==OP_Multiply ){
      /* Special case: multiplying NULL by zero gives a zero result, not a
      ** NULL result as it would normally. */
      if( (aStack[tos].flags & (STK_Int|STK_Real))!=0
              || ((aStack[tos].flags & STK_Str)!=0 && isNumber(zStack[tos])) ){
        Integerify(p,tos);
        if( aStack[tos].i==0 ){
          resultType = STK_Int;
          aStack[nos].i = 0;
        }
      }else if( (aStack[nos].flags & (STK_Int|STK_Real))!=0
              || ((aStack[nos].flags & STK_Str)!=0 && isNumber(zStack[nos])) ){
        Integerify(p,nos);
        if( aStack[nos].i==0 ){
          resultType = STK_Int;
        }
      }
    }
    POPSTACK;
    Release(p, nos);
    aStack[nos].flags = resultType;
  }else if( (aStack[tos].flags & aStack[nos].flags & STK_Int)==STK_Int ){
    int a, b;
    a = aStack[tos].i;
    b = aStack[nos].i;
    switch( pOp->opcode ){
      case OP_Add:         b += a;       break;
      case OP_Subtract:    b -= a;       break;







|







 







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


|







26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
....
1765
1766
1767
1768
1769
1770
1771



















1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
** type to the other occurs as necessary.
** 
** Most of the code in this file is taken up by the sqliteVdbeExec()
** function which does the work of interpreting a VDBE program.
** But other routines are also provided to help in building up
** a program instruction by instruction.
**
** $Id: vdbe.c,v 1.152 2002/06/01 21:41:10 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** The following global variable is incremented every time a cursor
** moves, either by the OP_MoveTo or the OP_Next opcode.  The test
................................................................................
case OP_Multiply:
case OP_Divide:
case OP_Remainder: {
  int tos = p->tos;
  int nos = tos - 1;
  VERIFY( if( nos<0 ) goto not_enough_stack; )
  if( ((aStack[tos].flags | aStack[nos].flags) & STK_Null)!=0 ){



















    POPSTACK;
    Release(p, nos);
    aStack[nos].flags = STK_Null;
  }else if( (aStack[tos].flags & aStack[nos].flags & STK_Int)==STK_Int ){
    int a, b;
    a = aStack[tos].i;
    b = aStack[nos].i;
    switch( pOp->opcode ){
      case OP_Add:         b += a;       break;
      case OP_Subtract:    b -= a;       break;

Changes to test/null.test.

42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
    select ifnull(a+b,99) from t1;
  }
} {1 2 4 5 99 99 99}
do_test null-1.2 {
  execsql {
    select ifnull(b*c,99) from t1;
  }
} {0 0 0 1 0 99 99}
do_test null-1.2.1 {
  execsql {
    select ifnull(c*b,99) from t1;
  }
} {0 0 0 1 0 99 99}

# Check to see how the CASE expression handles NULL values.  The
# first WHEN for which the test expression is TRUE is selected.
# FALSE and UNKNOWN test expressions are skipped.
#
do_test null-2.1 {
  execsql {







|
<
<
<
<
<







42
43
44
45
46
47
48
49





50
51
52
53
54
55
56
    select ifnull(a+b,99) from t1;
  }
} {1 2 4 5 99 99 99}
do_test null-1.2 {
  execsql {
    select ifnull(b*c,99) from t1;
  }
} {0 0 0 1 99 99 99}






# Check to see how the CASE expression handles NULL values.  The
# first WHEN for which the test expression is TRUE is selected.
# FALSE and UNKNOWN test expressions are skipped.
#
do_test null-2.1 {
  execsql {