mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-05 15:55:57 +03:00
Built-in aggregate functions (MIN, SUM, AVG, etc) should ignore NULL entires. (CVS 597)
FossilOrigin-Name: 19ae12bef210ae5fe171f10833faa38d640c129f
This commit is contained in:
18
manifest
18
manifest
@@ -1,5 +1,5 @@
|
|||||||
C Remove\sextra\s\\\scharacters\sfrom\stemporary\sfilenames\sunder\swindows.\n(Ticket\s#52)\s(CVS\s596)
|
C Built-in\saggregate\sfunctions\s(MIN,\sSUM,\sAVG,\setc)\sshould\signore\sNULL\sentires.\s(CVS\s597)
|
||||||
D 2002-05-29T12:44:53
|
D 2002-05-29T23:22:23
|
||||||
F Makefile.in 6291a33b87d2a395aafd7646ee1ed562c6f2c28c
|
F Makefile.in 6291a33b87d2a395aafd7646ee1ed562c6f2c28c
|
||||||
F Makefile.template 4e11752e0b5c7a043ca50af4296ec562857ba495
|
F Makefile.template 4e11752e0b5c7a043ca50af4296ec562857ba495
|
||||||
F README a4c0ba11354ef6ba0776b400d057c59da47a4cc0
|
F README a4c0ba11354ef6ba0776b400d057c59da47a4cc0
|
||||||
@@ -24,7 +24,7 @@ F src/build.c 36e42718a7a94f554ea39508993378482f5335c7
|
|||||||
F src/delete.c a2b098cbbf518e6b641847e26de85827793bc523
|
F src/delete.c a2b098cbbf518e6b641847e26de85827793bc523
|
||||||
F src/encode.c 346b12b46148506c32038524b95c4631ab46d760
|
F src/encode.c 346b12b46148506c32038524b95c4631ab46d760
|
||||||
F src/expr.c 1a7a2f5f2b7dd37659783cdb6efaac74a092ba71
|
F src/expr.c 1a7a2f5f2b7dd37659783cdb6efaac74a092ba71
|
||||||
F src/func.c 16e994eea8cceb0cd451938e63d337f7d9d089bf
|
F src/func.c 2cd4922913234ad384ccb75dd41bc35259a8338c
|
||||||
F src/hash.c 6a6236b89c8c060c65dabd300a1c8ce7c10edb72
|
F src/hash.c 6a6236b89c8c060c65dabd300a1c8ce7c10edb72
|
||||||
F src/hash.h dca065dda89d4575f3176e75e9a3dc0f4b4fb8b9
|
F src/hash.h dca065dda89d4575f3176e75e9a3dc0f4b4fb8b9
|
||||||
F src/insert.c 24b4e146319bada6f82a1d5eae6b38b3065d132f
|
F src/insert.c 24b4e146319bada6f82a1d5eae6b38b3065d132f
|
||||||
@@ -64,7 +64,7 @@ F test/conflict.test 5149646703d3930c9111068b5cda7e2e938476e3
|
|||||||
F test/copy.test b3cefcb520c64d7e7dfedbab06b4d4c31fa5b99a
|
F test/copy.test b3cefcb520c64d7e7dfedbab06b4d4c31fa5b99a
|
||||||
F test/delete.test c904a62129fe102b314a96111a8417f10249e4d8
|
F test/delete.test c904a62129fe102b314a96111a8417f10249e4d8
|
||||||
F test/expr.test 518ee35ec8d2c8883544d75a031219c75391fb21
|
F test/expr.test 518ee35ec8d2c8883544d75a031219c75391fb21
|
||||||
F test/func.test 1505ac9ebc11ca5c0300192d1519a542d5cbcfe1
|
F test/func.test 628ab513b0d9c54251a63e026a26b7b4347e54ab
|
||||||
F test/in.test c09312672e3f0709fa02c8e2e9cd8fb4bd6269aa
|
F test/in.test c09312672e3f0709fa02c8e2e9cd8fb4bd6269aa
|
||||||
F test/index.test c8a471243bbf878974b99baf5badd59407237cf3
|
F test/index.test c8a471243bbf878974b99baf5badd59407237cf3
|
||||||
F test/insert.test 58d44c19b3557f67f4aeb5110ed9ef02038c3684
|
F test/insert.test 58d44c19b3557f67f4aeb5110ed9ef02038c3684
|
||||||
@@ -76,7 +76,7 @@ F test/limit.test 6f98bcefc92209103bb3764c81975a6ec21d6702
|
|||||||
F test/lock.test 3fcfd46a73119f6a18094673328a32c7b3047a8f
|
F test/lock.test 3fcfd46a73119f6a18094673328a32c7b3047a8f
|
||||||
F test/main.test c66b564554b770ee7fdbf6a66c0cd90329bc2c85
|
F test/main.test c66b564554b770ee7fdbf6a66c0cd90329bc2c85
|
||||||
F test/malloc.test 7ba32a9ebd3aeed52ae4aaa6d42ca37e444536fd
|
F test/malloc.test 7ba32a9ebd3aeed52ae4aaa6d42ca37e444536fd
|
||||||
F test/minmax.test c50bcc760433acd7ca8e22bc4c525b9ae82762e2
|
F test/minmax.test a234053455ffd42d785ba6edc5425374e064ff0d
|
||||||
F test/misc1.test df281e9b26cd1db5808939c7cf2703072d555be0
|
F test/misc1.test df281e9b26cd1db5808939c7cf2703072d555be0
|
||||||
F test/misuse.test a3aa2b18a97e4c409a1fcaff5151a4dd804a0162
|
F test/misuse.test a3aa2b18a97e4c409a1fcaff5151a4dd804a0162
|
||||||
F test/notnull.test b1f3e42fc475b0b5827b27b2e9b562081995ff30
|
F test/notnull.test b1f3e42fc475b0b5827b27b2e9b562081995ff30
|
||||||
@@ -86,7 +86,7 @@ F test/printf.test 3cb415073754cb8ff076f26173143c3cd293a9da
|
|||||||
F test/quick.test 6f023c7a73fc413e6d65b7a1879c79764038dc05
|
F test/quick.test 6f023c7a73fc413e6d65b7a1879c79764038dc05
|
||||||
F test/quote.test 08f23385c685d3dc7914ec760d492cacea7f6e3d
|
F test/quote.test 08f23385c685d3dc7914ec760d492cacea7f6e3d
|
||||||
F test/rowid.test 4c55943300cddf73dd0f88d40a268cab14c83274
|
F test/rowid.test 4c55943300cddf73dd0f88d40a268cab14c83274
|
||||||
F test/select1.test 1842aa108d0d780b71fd1250d3518188498d737b
|
F test/select1.test a19a8026b5c2c5bdf5384d761f3d446954b7ebf9
|
||||||
F test/select2.test aceea74fd895b9d007512f72499db589735bd8e4
|
F test/select2.test aceea74fd895b9d007512f72499db589735bd8e4
|
||||||
F test/select3.test 9469c332250a75a0ef1771fb5da62dc04ec77f18
|
F test/select3.test 9469c332250a75a0ef1771fb5da62dc04ec77f18
|
||||||
F test/select4.test 2ea8c7b7feceb853da167a39e4cce996a5c3ad88
|
F test/select4.test 2ea8c7b7feceb853da167a39e4cce996a5c3ad88
|
||||||
@@ -135,7 +135,7 @@ F www/speed.tcl da8afcc1d3ccc5696cfb388a68982bc3d9f7f00f
|
|||||||
F www/sqlite.tcl 8b5884354cb615049aed83039f8dfe1552a44279
|
F www/sqlite.tcl 8b5884354cb615049aed83039f8dfe1552a44279
|
||||||
F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331
|
F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331
|
||||||
F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218
|
F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218
|
||||||
P 5e74d0964b8fd99eda798e3737217aa499cc1726
|
P ed11abc81e638c21ec1aa0445a6d59de91343095
|
||||||
R b2a667c33a3dc036c20c07778d3a668a
|
R 0dbe1e91bf7fd44e5ab325282618e3b3
|
||||||
U drh
|
U drh
|
||||||
Z 79cd389a43b2907c33c18067e98b1634
|
Z c098e63f0d01ca947f8ca615049ab0d0
|
||||||
|
@@ -1 +1 @@
|
|||||||
ed11abc81e638c21ec1aa0445a6d59de91343095
|
19ae12bef210ae5fe171f10833faa38d640c129f
|
49
src/func.c
49
src/func.c
@@ -16,7 +16,7 @@
|
|||||||
** sqliteRegisterBuildinFunctions() found at the bottom of the file.
|
** sqliteRegisterBuildinFunctions() found at the bottom of the file.
|
||||||
** All other code has file scope.
|
** 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 <ctype.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
@@ -254,6 +254,7 @@ static void nullifFunc(sqlite_func *context, int argc, const char **argv){
|
|||||||
typedef struct SumCtx SumCtx;
|
typedef struct SumCtx SumCtx;
|
||||||
struct SumCtx {
|
struct SumCtx {
|
||||||
double sum; /* Sum of terms */
|
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){
|
static void sumStep(sqlite_func *context, int argc, const char **argv){
|
||||||
SumCtx *p;
|
SumCtx *p;
|
||||||
double x;
|
|
||||||
if( argc<1 ) return;
|
if( argc<1 ) return;
|
||||||
p = sqlite_aggregate_context(context, sizeof(*p));
|
p = sqlite_aggregate_context(context, sizeof(*p));
|
||||||
if( p==0 ) return;
|
if( p && argv[0] ){
|
||||||
x = argv[0] ? atof(argv[0]) : 0.0;
|
p->sum += atof(argv[0]);
|
||||||
p->sum += x;
|
p->cnt++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
static void sumFinalize(sqlite_func *context){
|
static void sumFinalize(sqlite_func *context){
|
||||||
SumCtx *p;
|
SumCtx *p;
|
||||||
@@ -275,11 +276,9 @@ static void sumFinalize(sqlite_func *context){
|
|||||||
}
|
}
|
||||||
static void avgFinalize(sqlite_func *context){
|
static void avgFinalize(sqlite_func *context){
|
||||||
SumCtx *p;
|
SumCtx *p;
|
||||||
double rN;
|
|
||||||
p = sqlite_aggregate_context(context, sizeof(*p));
|
p = sqlite_aggregate_context(context, sizeof(*p));
|
||||||
rN = sqlite_aggregate_count(context);
|
if( p && p->cnt>0 ){
|
||||||
if( p && rN>0.0 ){
|
sqlite_set_result_double(context, p->sum/(double)p->cnt);
|
||||||
sqlite_set_result_double(context, p->sum/rN);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -291,6 +290,7 @@ typedef struct StdDevCtx StdDevCtx;
|
|||||||
struct StdDevCtx {
|
struct StdDevCtx {
|
||||||
double sum; /* Sum of terms */
|
double sum; /* Sum of terms */
|
||||||
double sum2; /* Sum of the squares of terms */
|
double sum2; /* Sum of the squares of terms */
|
||||||
|
int cnt; /* Number of terms counted */
|
||||||
};
|
};
|
||||||
|
|
||||||
#if 0 /* Omit because math library is required */
|
#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;
|
double x;
|
||||||
if( argc<1 ) return;
|
if( argc<1 ) return;
|
||||||
p = sqlite_aggregate_context(context, sizeof(*p));
|
p = sqlite_aggregate_context(context, sizeof(*p));
|
||||||
if( p==0 ) return;
|
if( p && argv[0] ){
|
||||||
x = argv[0] ? atof(argv[0]) : 0.0;
|
x = atof(argv[0]);
|
||||||
p->sum += x;
|
p->sum += x;
|
||||||
p->sum2 += x*x;
|
p->sum2 += x*x;
|
||||||
|
p->cnt++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
static void stdDevFinalize(sqlite_func *context){
|
static void stdDevFinalize(sqlite_func *context){
|
||||||
double rN = sqlite_aggregate_count(context);
|
double rN = sqlite_aggregate_count(context);
|
||||||
StdDevCtx *p = sqlite_aggregate_context(context, sizeof(*p));
|
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,
|
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
|
#endif
|
||||||
@@ -348,7 +351,6 @@ static void countFinalize(sqlite_func *context){
|
|||||||
*/
|
*/
|
||||||
typedef struct MinMaxCtx MinMaxCtx;
|
typedef struct MinMaxCtx MinMaxCtx;
|
||||||
struct MinMaxCtx {
|
struct MinMaxCtx {
|
||||||
int isNull; /* True if the result should be NULL */
|
|
||||||
char *z; /* The best so far */
|
char *z; /* The best so far */
|
||||||
char zBuf[28]; /* Space that can be used for storage */
|
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){
|
static void minStep(sqlite_func *context, int argc, const char **argv){
|
||||||
MinMaxCtx *p;
|
MinMaxCtx *p;
|
||||||
p = sqlite_aggregate_context(context, sizeof(*p));
|
p = sqlite_aggregate_context(context, sizeof(*p));
|
||||||
if( p==0 || argc<1 ) return;
|
if( p==0 || argc<1 || argv[0]==0 ) return;
|
||||||
if( argv[0]==0 || p->isNull ){
|
|
||||||
p->isNull = 1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if( sqlite_aggregate_count(context)==1 || sqliteCompare(argv[0],p->z)<0 ){
|
if( sqlite_aggregate_count(context)==1 || sqliteCompare(argv[0],p->z)<0 ){
|
||||||
int len;
|
int len;
|
||||||
if( p->z && p->z!=p->zBuf ){
|
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){
|
static void maxStep(sqlite_func *context, int argc, const char **argv){
|
||||||
MinMaxCtx *p;
|
MinMaxCtx *p;
|
||||||
p = sqlite_aggregate_context(context, sizeof(*p));
|
p = sqlite_aggregate_context(context, sizeof(*p));
|
||||||
if( p==0 || argc<1 ) return;
|
if( p==0 || argc<1 || argv[0]==0 ) return;
|
||||||
if( argv[0]==0 || p->isNull ){
|
|
||||||
p->isNull = 1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if( sqlite_aggregate_count(context)==1 || sqliteCompare(argv[0],p->z)>0 ){
|
if( sqlite_aggregate_count(context)==1 || sqliteCompare(argv[0],p->z)>0 ){
|
||||||
int len;
|
int len;
|
||||||
if( p->z && p->z!=p->zBuf ){
|
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){
|
static void minMaxFinalize(sqlite_func *context){
|
||||||
MinMaxCtx *p;
|
MinMaxCtx *p;
|
||||||
p = sqlite_aggregate_context(context, sizeof(*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));
|
sqlite_set_result_string(context, p->z, strlen(p->z));
|
||||||
}
|
}
|
||||||
if( p && p->z && p->z!=p->zBuf ){
|
if( p && p->z && p->z!=p->zBuf ){
|
||||||
@@ -438,6 +432,7 @@ void sqliteRegisterBuildinFunctions(sqlite *db){
|
|||||||
{ "coalesce", -1, ifnullFunc },
|
{ "coalesce", -1, ifnullFunc },
|
||||||
{ "coalesce", 0, 0 },
|
{ "coalesce", 0, 0 },
|
||||||
{ "coalesce", 1, 0 },
|
{ "coalesce", 1, 0 },
|
||||||
|
{ "ifnull", 2, ifnullFunc },
|
||||||
{ "random", -1, randomFunc },
|
{ "random", -1, randomFunc },
|
||||||
{ "like", 2, likeFunc },
|
{ "like", 2, likeFunc },
|
||||||
{ "glob", 2, globFunc },
|
{ "glob", 2, globFunc },
|
||||||
|
@@ -11,7 +11,7 @@
|
|||||||
# This file implements regression tests for SQLite library. The
|
# This file implements regression tests for SQLite library. The
|
||||||
# focus of this file is testing built-in functions.
|
# 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]
|
set testdir [file dirname $argv0]
|
||||||
source $testdir/tester.tcl
|
source $testdir/tester.tcl
|
||||||
@@ -236,5 +236,13 @@ do_test func-7.1 {
|
|||||||
execsql {SELECT last_insert_rowid()}
|
execsql {SELECT last_insert_rowid()}
|
||||||
} [db 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
|
finish_test
|
||||||
|
@@ -13,7 +13,7 @@
|
|||||||
# aggregate min() and max() functions and which are handled as
|
# aggregate min() and max() functions and which are handled as
|
||||||
# as a special case.
|
# 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]
|
set testdir [file dirname $argv0]
|
||||||
source $testdir/tester.tcl
|
source $testdir/tester.tcl
|
||||||
@@ -127,6 +127,6 @@ do_test minmax-4.1 {
|
|||||||
SELECT coalesce(min(x),-1), coalesce(max(x),-1) FROM
|
SELECT coalesce(min(x),-1), coalesce(max(x),-1) FROM
|
||||||
(SELECT * FROM t1 UNION SELECT NULL as 'x', NULL as 'y')
|
(SELECT * FROM t1 UNION SELECT NULL as 'x', NULL as 'y')
|
||||||
}
|
}
|
||||||
} {-1 -1}
|
} {1 20}
|
||||||
|
|
||||||
finish_test
|
finish_test
|
||||||
|
@@ -11,7 +11,7 @@
|
|||||||
# This file implements regression tests for SQLite library. The
|
# This file implements regression tests for SQLite library. The
|
||||||
# focus of this file is testing the SELECT statement.
|
# 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]
|
set testdir [file dirname $argv0]
|
||||||
source $testdir/tester.tcl
|
source $testdir/tester.tcl
|
||||||
@@ -159,7 +159,7 @@ do_test select1-2.8 {
|
|||||||
} {0 {11 33}}
|
} {0 {11 33}}
|
||||||
do_test select1-2.8.1 {
|
do_test select1-2.8.1 {
|
||||||
execsql {SELECT coalesce(min(a),'xyzzy') FROM t3}
|
execsql {SELECT coalesce(min(a),'xyzzy') FROM t3}
|
||||||
} {xyzzy}
|
} {11}
|
||||||
do_test select1-2.8.2 {
|
do_test select1-2.8.2 {
|
||||||
execsql {SELECT min(coalesce(a,'xyzzy')) FROM t3}
|
execsql {SELECT min(coalesce(a,'xyzzy')) FROM t3}
|
||||||
} {11}
|
} {11}
|
||||||
@@ -188,7 +188,7 @@ do_test select1-2.13 {
|
|||||||
} {0 34}
|
} {0 34}
|
||||||
do_test select1-2.13.1 {
|
do_test select1-2.13.1 {
|
||||||
execsql {SELECT coalesce(max(a),'xyzzy') FROM t3}
|
execsql {SELECT coalesce(max(a),'xyzzy') FROM t3}
|
||||||
} {xyzzy}
|
} {abc}
|
||||||
do_test select1-2.13.2 {
|
do_test select1-2.13.2 {
|
||||||
execsql {SELECT max(coalesce(a,'xyzzy')) FROM t3}
|
execsql {SELECT max(coalesce(a,'xyzzy')) FROM t3}
|
||||||
} {xyzzy}
|
} {xyzzy}
|
||||||
|
Reference in New Issue
Block a user