]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Built-in aggregate functions (MIN, SUM, AVG, etc) should ignore NULL entires. (CVS...
authordrh <drh@noemail.net>
Wed, 29 May 2002 23:22:23 +0000 (23:22 +0000)
committerdrh <drh@noemail.net>
Wed, 29 May 2002 23:22:23 +0000 (23:22 +0000)
FossilOrigin-Name: 19ae12bef210ae5fe171f10833faa38d640c129f

manifest
manifest.uuid
src/func.c
test/func.test
test/minmax.test
test/select1.test

index b2ce488ca95a34c0cc3f565a0c55c1e89f9a5201..9a8c52ed43860b8456d5e937028242081b7e02dd 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Remove\sextra\s\\\scharacters\sfrom\stemporary\sfilenames\sunder\swindows.\n(Ticket\s#52)\s(CVS\s596)
-D 2002-05-29T12:44:53
+C Built-in\saggregate\sfunctions\s(MIN,\sSUM,\sAVG,\setc)\sshould\signore\sNULL\sentires.\s(CVS\s597)
+D 2002-05-29T23:22:23
 F Makefile.in 6291a33b87d2a395aafd7646ee1ed562c6f2c28c
 F Makefile.template 4e11752e0b5c7a043ca50af4296ec562857ba495
 F README a4c0ba11354ef6ba0776b400d057c59da47a4cc0
@@ -24,7 +24,7 @@ F src/build.c 36e42718a7a94f554ea39508993378482f5335c7
 F src/delete.c a2b098cbbf518e6b641847e26de85827793bc523
 F src/encode.c 346b12b46148506c32038524b95c4631ab46d760
 F src/expr.c 1a7a2f5f2b7dd37659783cdb6efaac74a092ba71
-F src/func.c 16e994eea8cceb0cd451938e63d337f7d9d089bf
+F src/func.c 2cd4922913234ad384ccb75dd41bc35259a8338c
 F src/hash.c 6a6236b89c8c060c65dabd300a1c8ce7c10edb72
 F src/hash.h dca065dda89d4575f3176e75e9a3dc0f4b4fb8b9
 F src/insert.c 24b4e146319bada6f82a1d5eae6b38b3065d132f
@@ -64,7 +64,7 @@ F test/conflict.test 5149646703d3930c9111068b5cda7e2e938476e3
 F test/copy.test b3cefcb520c64d7e7dfedbab06b4d4c31fa5b99a
 F test/delete.test c904a62129fe102b314a96111a8417f10249e4d8
 F test/expr.test 518ee35ec8d2c8883544d75a031219c75391fb21
-F test/func.test 1505ac9ebc11ca5c0300192d1519a542d5cbcfe1
+F test/func.test 628ab513b0d9c54251a63e026a26b7b4347e54ab
 F test/in.test c09312672e3f0709fa02c8e2e9cd8fb4bd6269aa
 F test/index.test c8a471243bbf878974b99baf5badd59407237cf3
 F test/insert.test 58d44c19b3557f67f4aeb5110ed9ef02038c3684
@@ -76,7 +76,7 @@ F test/limit.test 6f98bcefc92209103bb3764c81975a6ec21d6702
 F test/lock.test 3fcfd46a73119f6a18094673328a32c7b3047a8f
 F test/main.test c66b564554b770ee7fdbf6a66c0cd90329bc2c85
 F test/malloc.test 7ba32a9ebd3aeed52ae4aaa6d42ca37e444536fd
-F test/minmax.test c50bcc760433acd7ca8e22bc4c525b9ae82762e2
+F test/minmax.test a234053455ffd42d785ba6edc5425374e064ff0d
 F test/misc1.test df281e9b26cd1db5808939c7cf2703072d555be0
 F test/misuse.test a3aa2b18a97e4c409a1fcaff5151a4dd804a0162
 F test/notnull.test b1f3e42fc475b0b5827b27b2e9b562081995ff30
@@ -86,7 +86,7 @@ F test/printf.test 3cb415073754cb8ff076f26173143c3cd293a9da
 F test/quick.test 6f023c7a73fc413e6d65b7a1879c79764038dc05
 F test/quote.test 08f23385c685d3dc7914ec760d492cacea7f6e3d
 F test/rowid.test 4c55943300cddf73dd0f88d40a268cab14c83274
-F test/select1.test 1842aa108d0d780b71fd1250d3518188498d737b
+F test/select1.test a19a8026b5c2c5bdf5384d761f3d446954b7ebf9
 F test/select2.test aceea74fd895b9d007512f72499db589735bd8e4
 F test/select3.test 9469c332250a75a0ef1771fb5da62dc04ec77f18
 F test/select4.test 2ea8c7b7feceb853da167a39e4cce996a5c3ad88
@@ -135,7 +135,7 @@ F www/speed.tcl da8afcc1d3ccc5696cfb388a68982bc3d9f7f00f
 F www/sqlite.tcl 8b5884354cb615049aed83039f8dfe1552a44279
 F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331
 F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218
-P 5e74d0964b8fd99eda798e3737217aa499cc1726
-R b2a667c33a3dc036c20c07778d3a668a
+P ed11abc81e638c21ec1aa0445a6d59de91343095
+R 0dbe1e91bf7fd44e5ab325282618e3b3
 U drh
-Z 79cd389a43b2907c33c18067e98b1634
+Z c098e63f0d01ca947f8ca615049ab0d0
index d7a3d1e8d6aabd7ee556984840bca28795821852..14072de20aae566cd71728796f8b5bb162906dec 100644 (file)
@@ -1 +1 @@
-ed11abc81e638c21ec1aa0445a6d59de91343095
\ No newline at end of file
+19ae12bef210ae5fe171f10833faa38d640c129f
\ No newline at end of file
index cf523e3b8df2663c8e8cf78a00f1d3c0266a56f9..8ba7db9de6798016de7573afdfd1301fe1f73fca 100644 (file)
@@ -16,7 +16,7 @@
 ** sqliteRegisterBuildinFunctions() found at the bottom of the file.
 ** All other code has file scope.
 **
-** $Id: func.c,v 1.17 2002/05/26 21:34:58 drh Exp $
+** $Id: func.c,v 1.18 2002/05/29 23:22:23 drh Exp $
 */
 #include <ctype.h>
 #include <math.h>
@@ -254,6 +254,7 @@ static void nullifFunc(sqlite_func *context, int argc, const char **argv){
 typedef struct SumCtx SumCtx;
 struct SumCtx {
   double sum;     /* Sum of terms */
+  int cnt;        /* Number of elements summed */
 };
 
 /*
@@ -261,12 +262,12 @@ struct SumCtx {
 */
 static void sumStep(sqlite_func *context, int argc, const char **argv){
   SumCtx *p;
-  double x;
   if( argc<1 ) return;
   p = sqlite_aggregate_context(context, sizeof(*p));
-  if( p==0 ) return;
-  x = argv[0] ? atof(argv[0]) : 0.0;
-  p->sum += x;
+  if( p && argv[0] ){
+    p->sum += atof(argv[0]);
+    p->cnt++;
+  }
 }
 static void sumFinalize(sqlite_func *context){
   SumCtx *p;
@@ -275,11 +276,9 @@ static void sumFinalize(sqlite_func *context){
 }
 static void avgFinalize(sqlite_func *context){
   SumCtx *p;
-  double rN;
   p = sqlite_aggregate_context(context, sizeof(*p));
-  rN = sqlite_aggregate_count(context);
-  if( p && rN>0.0 ){
-    sqlite_set_result_double(context, p->sum/rN);
+  if( p && p->cnt>0 ){
+    sqlite_set_result_double(context, p->sum/(double)p->cnt);
   }
 }
 
@@ -291,6 +290,7 @@ typedef struct StdDevCtx StdDevCtx;
 struct StdDevCtx {
   double sum;     /* Sum of terms */
   double sum2;    /* Sum of the squares of terms */
+  int cnt;        /* Number of terms counted */
 };
 
 #if 0   /* Omit because math library is required */
@@ -302,17 +302,20 @@ static void stdDevStep(sqlite_func *context, int argc, const char **argv){
   double x;
   if( argc<1 ) return;
   p = sqlite_aggregate_context(context, sizeof(*p));
-  if( p==0 ) return;
-  x = argv[0] ? atof(argv[0]) : 0.0;
-  p->sum += x;
-  p->sum2 += x*x;
+  if( p && argv[0] ){
+    x = atof(argv[0]);
+    p->sum += x;
+    p->sum2 += x*x;
+    p->cnt++;
+  }
 }
 static void stdDevFinalize(sqlite_func *context){
   double rN = sqlite_aggregate_count(context);
   StdDevCtx *p = sqlite_aggregate_context(context, sizeof(*p));
-  if( p && rN>1.0 ){
+  if( p && p->cnt>1 ){
+    double rCnt = cnt;
     sqlite_set_result_double(context, 
-       sqrt((p->sum2 - p->sum*p->sum/rN)/(rN-1.0)));
+       sqrt((p->sum2 - p->sum*p->sum/rCnt)/(rCnt-1.0)));
   }
 }
 #endif
@@ -348,7 +351,6 @@ static void countFinalize(sqlite_func *context){
 */
 typedef struct MinMaxCtx MinMaxCtx;
 struct MinMaxCtx {
-  int isNull;      /* True if the result should be NULL */
   char *z;         /* The best so far */
   char zBuf[28];   /* Space that can be used for storage */
 };
@@ -359,11 +361,7 @@ struct MinMaxCtx {
 static void minStep(sqlite_func *context, int argc, const char **argv){
   MinMaxCtx *p;
   p = sqlite_aggregate_context(context, sizeof(*p));
-  if( p==0 || argc<1 ) return;
-  if( argv[0]==0 || p->isNull ){
-    p->isNull = 1;
-    return;
-  }
+  if( p==0 || argc<1 || argv[0]==0 ) return;
   if( sqlite_aggregate_count(context)==1 || sqliteCompare(argv[0],p->z)<0 ){
     int len;
     if( p->z && p->z!=p->zBuf ){
@@ -382,11 +380,7 @@ static void minStep(sqlite_func *context, int argc, const char **argv){
 static void maxStep(sqlite_func *context, int argc, const char **argv){
   MinMaxCtx *p;
   p = sqlite_aggregate_context(context, sizeof(*p));
-  if( p==0 || argc<1 ) return;
-  if( argv[0]==0 || p->isNull ){
-    p->isNull = 1;
-    return;
-  }
+  if( p==0 || argc<1 || argv[0]==0 ) return;
   if( sqlite_aggregate_count(context)==1 || sqliteCompare(argv[0],p->z)>0 ){
     int len;
     if( p->z && p->z!=p->zBuf ){
@@ -405,7 +399,7 @@ static void maxStep(sqlite_func *context, int argc, const char **argv){
 static void minMaxFinalize(sqlite_func *context){
   MinMaxCtx *p;
   p = sqlite_aggregate_context(context, sizeof(*p));
-  if( p && p->z && !p->isNull ){
+  if( p && p->z ){
     sqlite_set_result_string(context, p->z, strlen(p->z));
   }
   if( p && p->z && p->z!=p->zBuf ){
@@ -438,6 +432,7 @@ void sqliteRegisterBuildinFunctions(sqlite *db){
     { "coalesce",  -1, ifnullFunc },
     { "coalesce",   0, 0          },
     { "coalesce",   1, 0          },
+    { "ifnull",     2, ifnullFunc },
     { "random",    -1, randomFunc },
     { "like",       2, likeFunc   },
     { "glob",       2, globFunc   },
index 79821ed1666da1818629b7d2132db3e82079f26c..98e2a97f3cd9188062ca196d45cb8e41b3fde777 100644 (file)
@@ -11,7 +11,7 @@
 # This file implements regression tests for SQLite library.  The
 # focus of this file is testing built-in functions.
 #
-# $Id: func.test,v 1.11 2002/05/27 01:04:51 drh Exp $
+# $Id: func.test,v 1.12 2002/05/29 23:22:23 drh Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
@@ -236,5 +236,13 @@ do_test func-7.1 {
   execsql {SELECT last_insert_rowid()}
 } [db last_insert_rowid]
 
+# Tests for aggregate functions and how they handle NULLs.
+#
+do_test func-8.1 {
+  execsql {
+    SELECT sum(a), count(a), round(avg(a),2), min(a), max(a), count(*) FROM t2;
+  }
+} {68236 3 22745.33 1 67890 5}
+
 
 finish_test
index 1355121b1d693862d3a1ea8461ac3910f410c1fb..8d86f1f775b1e0b3f325082f407543d2eba3896e 100644 (file)
@@ -13,7 +13,7 @@
 # aggregate min() and max() functions and which are handled as
 # as a special case.
 #
-# $Id: minmax.test,v 1.2 2002/05/27 01:04:51 drh Exp $
+# $Id: minmax.test,v 1.3 2002/05/29 23:22:23 drh Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
@@ -127,6 +127,6 @@ do_test minmax-4.1 {
     SELECT coalesce(min(x),-1), coalesce(max(x),-1) FROM
       (SELECT * FROM t1 UNION SELECT NULL as 'x', NULL as 'y')
   }
-} {-1 -1}
+} {1 20}
 
 finish_test
index f3ab52029fac250cb4f8a3e6fce5d731b27157a3..6d3e45d360bf18a12c871104dcb1b946618bfefa 100644 (file)
@@ -11,7 +11,7 @@
 # This file implements regression tests for SQLite library.  The
 # focus of this file is testing the SELECT statement.
 #
-# $Id: select1.test,v 1.28 2002/05/27 03:25:52 drh Exp $
+# $Id: select1.test,v 1.29 2002/05/29 23:22:23 drh Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
@@ -159,7 +159,7 @@ do_test select1-2.8 {
 } {0 {11 33}}
 do_test select1-2.8.1 {
   execsql {SELECT coalesce(min(a),'xyzzy') FROM t3}
-} {xyzzy}
+} {11}
 do_test select1-2.8.2 {
   execsql {SELECT min(coalesce(a,'xyzzy')) FROM t3}
 } {11}
@@ -188,7 +188,7 @@ do_test select1-2.13 {
 } {0 34}
 do_test select1-2.13.1 {
   execsql {SELECT coalesce(max(a),'xyzzy') FROM t3}
-} {xyzzy}
+} {abc}
 do_test select1-2.13.2 {
   execsql {SELECT max(coalesce(a,'xyzzy')) FROM t3}
 } {xyzzy}