mirror of
https://github.com/sqlite/sqlite.git
synced 2025-10-24 09:53:10 +03:00
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
This commit is contained in:
37
src/func.c
37
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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user