diff options
author | drh <drh@noemail.net> | 2006-02-11 17:34:00 +0000 |
---|---|---|
committer | drh <drh@noemail.net> | 2006-02-11 17:34:00 +0000 |
commit | 8c08e86187ba24e74066dc0bd35c0b8dcb2503b9 (patch) | |
tree | 83bb64b218341bc39b982ece490f98b318106e51 /src/func.c | |
parent | b151ac00156bccc46a009542eb70ed2914238ad3 (diff) | |
download | sqlite-8c08e86187ba24e74066dc0bd35c0b8dcb2503b9.tar.gz sqlite-8c08e86187ba24e74066dc0bd35c0b8dcb2503b9.zip |
I give up. SUM() now throws an error on integer overflow. Those of us
who think this is goofy can use TOTAL() instead.
Tickets #1664, #1669, #1670, #1674. (CVS 3084)
FossilOrigin-Name: 1c3e6002cd9fd5d30e197448c4d98cdd59163cac
Diffstat (limited to 'src/func.c')
-rw-r--r-- | src/func.c | 37 |
1 files changed, 23 insertions, 14 deletions
diff --git a/src/func.c b/src/func.c index 0e050f80a..6d1195961 100644 --- a/src/func.c +++ b/src/func.c @@ -16,7 +16,7 @@ ** sqliteRegisterBuildinFunctions() found at the bottom of the file. ** All other code has file scope. ** -** $Id: func.c,v 1.121 2006/02/09 22:13:42 drh Exp $ +** $Id: func.c,v 1.122 2006/02/11 17:34:00 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> @@ -817,9 +817,11 @@ static void test_error( */ typedef struct SumCtx SumCtx; struct SumCtx { - LONGDOUBLE_TYPE sum; /* Sum of terms */ - i64 cnt; /* Number of elements summed */ - u8 approx; /* True if sum is approximate */ + double rSum; /* Floating point sum */ + i64 iSum; /* Integer sum */ + i64 cnt; /* Number of elements summed */ + u8 overflow; /* True if integer overflow seen */ + u8 approx; /* True if non-integer value was input to the sum */ }; /* @@ -849,13 +851,18 @@ static void sumStep(sqlite3_context *context, int argc, sqlite3_value **argv){ if( p && type!=SQLITE_NULL ){ p->cnt++; if( type==SQLITE_INTEGER ){ - p->sum += sqlite3_value_int64(argv[0]); - if( !p->approx ){ - i64 iVal; - p->approx = p->sum!=(LONGDOUBLE_TYPE)(iVal = (i64)p->sum); + i64 v = sqlite3_value_int64(argv[0]); + p->rSum += v; + if( (p->approx|p->overflow)==0 ){ + i64 iNewSum = p->iSum + v; + int s1 = p->iSum >> (sizeof(i64)*8-1); + int s2 = v >> (sizeof(i64)*8-1); + int s3 = iNewSum >> (sizeof(i64)*8-1); + p->overflow = (s1&s2&~s3) | (~s1&~s2&s3); + p->iSum = iNewSum; } }else{ - p->sum += sqlite3_value_double(argv[0]); + p->rSum += sqlite3_value_double(argv[0]); p->approx = 1; } } @@ -864,10 +871,12 @@ static void sumFinalize(sqlite3_context *context){ SumCtx *p; p = sqlite3_aggregate_context(context, 0); if( p && p->cnt>0 ){ - if( p->approx ){ - sqlite3_result_double(context, p->sum); + if( p->overflow ){ + sqlite3_result_error(context,"integer overflow",-1); + }else if( p->approx ){ + sqlite3_result_double(context, p->rSum); }else{ - sqlite3_result_int64(context, (i64)p->sum); + sqlite3_result_int64(context, p->iSum); } } } @@ -875,13 +884,13 @@ static void avgFinalize(sqlite3_context *context){ SumCtx *p; p = sqlite3_aggregate_context(context, 0); if( p && p->cnt>0 ){ - sqlite3_result_double(context, p->sum/(double)p->cnt); + sqlite3_result_double(context, p->rSum/(double)p->cnt); } } static void totalFinalize(sqlite3_context *context){ SumCtx *p; p = sqlite3_aggregate_context(context, 0); - sqlite3_result_double(context, p ? p->sum : 0.0); + sqlite3_result_double(context, p ? p->rSum : 0.0); } /* |