/ Check-in [2e6230ed]
Login

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

Overview
Comment:A SUM() of all NULLs returns NULL. A SUM() of nothing return 0. A SUM() of a mixture of NULLs and numbers returns the sum of the numbers. Ticket #1413. (CVS 2677)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:2e6230edfd651b40481ebad8aa01a22ac92ce80c
User & Date: drh 2005-09-08 19:45:58
Context
2005-09-08
20:37
SUM returns NULL when it has no inputs. Ticket #1413. (CVS 2678) check-in: 62818594 user: drh tags: trunk
19:45
A SUM() of all NULLs returns NULL. A SUM() of nothing return 0. A SUM() of a mixture of NULLs and numbers returns the sum of the numbers. Ticket #1413. (CVS 2677) check-in: 2e6230ed user: drh tags: trunk
19:01
Remove a C++ism that snuck in on one of the reason changes. (CVS 2676) check-in: 48f6a331 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/func.c.

12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
...
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837


838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
** This file contains the C functions that implement various SQL
** functions of SQLite.  
**
** There is only one exported symbol in this file - the function
** sqliteRegisterBuildinFunctions() found at the bottom of the file.
** All other code has file scope.
**
** $Id: func.c,v 1.108 2005/09/08 10:37:01 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
#include <math.h>
#include <stdlib.h>
#include <assert.h>
#include "vdbeInt.h"
................................................................................
** An instance of the following structure holds the context of a
** sum() or avg() aggregate computation.
*/
typedef struct SumCtx SumCtx;
struct SumCtx {
  double sum;     /* Sum of terms */
  int cnt;        /* Number of elements summed */
  int isFloat;    /* True if there has been any floating point value */
};

/*
** Routines used to compute the sum or average.
*/
static void sumStep(sqlite3_context *context, int argc, sqlite3_value **argv){
  SumCtx *p;
  int type;
  if( argc<1 ) return;
  p = sqlite3_aggregate_context(context, sizeof(*p));
  type = sqlite3_value_type(argv[0]);
  if( p && type!=SQLITE_NULL ){
    p->sum += sqlite3_value_double(argv[0]);
    p->cnt++;
    if( type==SQLITE_FLOAT ) p->isFloat = 1;


  }
}
static void sumFinalize(sqlite3_context *context){
  SumCtx *p;
  p = sqlite3_aggregate_context(context, 0);
  if( p==0 ){
    sqlite3_result_int(context, 0);
  }else if( p->isFloat ){
    sqlite3_result_double(context, p->sum);
  }else{
    sqlite3_result_int64(context, (i64)p->sum);
  }
}
static void avgFinalize(sqlite3_context *context){
  SumCtx *p;
  p = sqlite3_aggregate_context(context, 0);
  if( p && p->cnt>0 ){







|







 







|








|





|
>
>







|

|







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
...
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
** This file contains the C functions that implement various SQL
** functions of SQLite.  
**
** There is only one exported symbol in this file - the function
** sqliteRegisterBuildinFunctions() found at the bottom of the file.
** All other code has file scope.
**
** $Id: func.c,v 1.109 2005/09/08 19:45:58 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
#include <math.h>
#include <stdlib.h>
#include <assert.h>
#include "vdbeInt.h"
................................................................................
** An instance of the following structure holds the context of a
** sum() or avg() aggregate computation.
*/
typedef struct SumCtx SumCtx;
struct SumCtx {
  double sum;     /* Sum of terms */
  int cnt;        /* Number of elements summed */
  u8 seenFloat;   /* True if there has been any floating point value */
};

/*
** Routines used to compute the sum or average.
*/
static void sumStep(sqlite3_context *context, int argc, sqlite3_value **argv){
  SumCtx *p;
  int type;
  assert( argc==1 );
  p = sqlite3_aggregate_context(context, sizeof(*p));
  type = sqlite3_value_type(argv[0]);
  if( p && type!=SQLITE_NULL ){
    p->sum += sqlite3_value_double(argv[0]);
    p->cnt++;
    if( type==SQLITE_FLOAT ){
      p->seenFloat = 1;
    }
  }
}
static void sumFinalize(sqlite3_context *context){
  SumCtx *p;
  p = sqlite3_aggregate_context(context, 0);
  if( p==0 ){
    sqlite3_result_int(context, 0);
  }else if( p->seenFloat ){
    sqlite3_result_double(context, p->sum);
  }else if( p->cnt>0 ){
    sqlite3_result_int64(context, (i64)p->sum);
  }
}
static void avgFinalize(sqlite3_context *context){
  SumCtx *p;
  p = sqlite3_aggregate_context(context, 0);
  if( p && p->cnt>0 ){

Changes to test/func.test.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
509
510
511
512
513
514
515

516

























517
#    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 built-in functions.
#
# $Id: func.test,v 1.38 2005/09/08 10:37:01 drh Exp $

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

# Create a table to work with.
#
do_test func-0.0 {
................................................................................
do_test func-18.2 {
  execsql {
    INSERT INTO t5 VALUES(0.0);
    SELECT sum(x) FROM t5;
  }
} {9902.0}




























finish_test







|







 







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

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
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
534
535
536
537
538
539
540
541
542
543
#    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 built-in functions.
#
# $Id: func.test,v 1.39 2005/09/08 19:45:58 drh Exp $

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

# Create a table to work with.
#
do_test func-0.0 {
................................................................................
do_test func-18.2 {
  execsql {
    INSERT INTO t5 VALUES(0.0);
    SELECT sum(x) FROM t5;
  }
} {9902.0}

# The sum of nothing is 0.  But the sum of all NULLs is NULL.
#
do_test func-18.3 {
  execsql {
    DELETE FROM t5;
    SELECT sum(x) FROM t5;
  }
} {0}
do_test func-18.4 {
  execsql {
    INSERT INTO t5 VALUES(NULL);
    SELECT sum(x) FROM t5
  }
} {{}}
do_test func-18.5 {
  execsql {
    INSERT INTO t5 VALUES(NULL);
    SELECT sum(x) FROM t5
  }
} {{}}
do_test func-18.6 {
  execsql {
    INSERT INTO t5 VALUES(123);
    SELECT sum(x) FROM t5
  }
} {123}

finish_test

Changes to test/minmax.test.

9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
...
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this file is testing SELECT statements that contain
# aggregate min() and max() functions and which are handled as
# as a special case.
#
# $Id: minmax.test,v 1.17 2005/09/08 10:37:01 drh Exp $

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

do_test minmax-1.0 {
  execsql {
    BEGIN;
................................................................................
    execsql {
      SELECT coalesce(min(x+0),-1), coalesce(max(x+0),-1) FROM
        (SELECT * FROM t1 UNION SELECT NULL as 'x', NULL as 'y')
    }
  } {1 20}
  do_test minmax-4.2 {
    execsql {
      SELECT y, sum(x) FROM
        (SELECT null, y+1 FROM t1 UNION SELECT * FROM t1)
      GROUP BY y ORDER BY y;
    }
  } {1 1 2 5 3 22 4 92 5 90 6 0}
  do_test minmax-4.3 {
    execsql {
      SELECT y, count(x), count(*) FROM







|







 







|







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
...
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this file is testing SELECT statements that contain
# aggregate min() and max() functions and which are handled as
# as a special case.
#
# $Id: minmax.test,v 1.18 2005/09/08 19:45:58 drh Exp $

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

do_test minmax-1.0 {
  execsql {
    BEGIN;
................................................................................
    execsql {
      SELECT coalesce(min(x+0),-1), coalesce(max(x+0),-1) FROM
        (SELECT * FROM t1 UNION SELECT NULL as 'x', NULL as 'y')
    }
  } {1 20}
  do_test minmax-4.2 {
    execsql {
      SELECT y, coalesce(sum(x),0) FROM
        (SELECT null, y+1 FROM t1 UNION SELECT * FROM t1)
      GROUP BY y ORDER BY y;
    }
  } {1 1 2 5 3 22 4 92 5 90 6 0}
  do_test minmax-4.3 {
    execsql {
      SELECT y, count(x), count(*) FROM