1beb9def0Sdrh /*
2beb9def0Sdrh ** 2020-06-22
3beb9def0Sdrh **
4beb9def0Sdrh ** The author disclaims copyright to this source code. In place of
5beb9def0Sdrh ** a legal notice, here is a blessing:
6beb9def0Sdrh **
7beb9def0Sdrh ** May you do good and not evil.
8beb9def0Sdrh ** May you find forgiveness for yourself and forgive others.
9beb9def0Sdrh ** May you share freely, never taking more than you give.
10beb9def0Sdrh **
11beb9def0Sdrh ******************************************************************************
12beb9def0Sdrh **
13beb9def0Sdrh ** Routines to implement arbitrary-precision decimal math.
14beb9def0Sdrh **
15beb9def0Sdrh ** The focus here is on simplicity and correctness, not performance.
16beb9def0Sdrh */
17beb9def0Sdrh #include "sqlite3ext.h"
18beb9def0Sdrh SQLITE_EXTENSION_INIT1
19beb9def0Sdrh #include <assert.h>
20beb9def0Sdrh #include <string.h>
21beb9def0Sdrh #include <ctype.h>
22beb9def0Sdrh #include <stdlib.h>
23beb9def0Sdrh
24a7c74006Sdrh /* Mark a function parameter as unused, to suppress nuisance compiler
25a7c74006Sdrh ** warnings. */
26a7c74006Sdrh #ifndef UNUSED_PARAMETER
27a7c74006Sdrh # define UNUSED_PARAMETER(X) (void)(X)
28a7c74006Sdrh #endif
29a7c74006Sdrh
30beb9def0Sdrh
31beb9def0Sdrh /* A decimal object */
32beb9def0Sdrh typedef struct Decimal Decimal;
33beb9def0Sdrh struct Decimal {
34beb9def0Sdrh char sign; /* 0 for positive, 1 for negative */
35beb9def0Sdrh char oom; /* True if an OOM is encountered */
36beb9def0Sdrh char isNull; /* True if holds a NULL rather than a number */
37beb9def0Sdrh char isInit; /* True upon initialization */
38beb9def0Sdrh int nDigit; /* Total number of digits */
39beb9def0Sdrh int nFrac; /* Number of digits to the right of the decimal point */
40beb9def0Sdrh signed char *a; /* Array of digits. Most significant first. */
41beb9def0Sdrh };
42beb9def0Sdrh
43beb9def0Sdrh /*
44beb9def0Sdrh ** Release memory held by a Decimal, but do not free the object itself.
45beb9def0Sdrh */
decimal_clear(Decimal * p)46beb9def0Sdrh static void decimal_clear(Decimal *p){
47beb9def0Sdrh sqlite3_free(p->a);
48beb9def0Sdrh }
49beb9def0Sdrh
50beb9def0Sdrh /*
51beb9def0Sdrh ** Destroy a Decimal object
52beb9def0Sdrh */
decimal_free(Decimal * p)53beb9def0Sdrh static void decimal_free(Decimal *p){
54beb9def0Sdrh if( p ){
55beb9def0Sdrh decimal_clear(p);
56beb9def0Sdrh sqlite3_free(p);
57beb9def0Sdrh }
58beb9def0Sdrh }
59beb9def0Sdrh
60beb9def0Sdrh /*
61beb9def0Sdrh ** Allocate a new Decimal object. Initialize it to the number given
62beb9def0Sdrh ** by the input string.
63beb9def0Sdrh */
decimal_new(sqlite3_context * pCtx,sqlite3_value * pIn,int nAlt,const unsigned char * zAlt)64beb9def0Sdrh static Decimal *decimal_new(
65beb9def0Sdrh sqlite3_context *pCtx,
66beb9def0Sdrh sqlite3_value *pIn,
67beb9def0Sdrh int nAlt,
68beb9def0Sdrh const unsigned char *zAlt
69beb9def0Sdrh ){
70beb9def0Sdrh Decimal *p;
71beb9def0Sdrh int n, i;
72beb9def0Sdrh const unsigned char *zIn;
73beb9def0Sdrh int iExp = 0;
74beb9def0Sdrh p = sqlite3_malloc( sizeof(*p) );
75beb9def0Sdrh if( p==0 ) goto new_no_mem;
76beb9def0Sdrh p->sign = 0;
77beb9def0Sdrh p->oom = 0;
78beb9def0Sdrh p->isInit = 1;
79beb9def0Sdrh p->isNull = 0;
80beb9def0Sdrh p->nDigit = 0;
81beb9def0Sdrh p->nFrac = 0;
82beb9def0Sdrh if( zAlt ){
83beb9def0Sdrh n = nAlt,
84beb9def0Sdrh zIn = zAlt;
85beb9def0Sdrh }else{
86beb9def0Sdrh if( sqlite3_value_type(pIn)==SQLITE_NULL ){
87beb9def0Sdrh p->a = 0;
88beb9def0Sdrh p->isNull = 1;
89beb9def0Sdrh return p;
90beb9def0Sdrh }
91beb9def0Sdrh n = sqlite3_value_bytes(pIn);
92beb9def0Sdrh zIn = sqlite3_value_text(pIn);
93beb9def0Sdrh }
94beb9def0Sdrh p->a = sqlite3_malloc64( n+1 );
95beb9def0Sdrh if( p->a==0 ) goto new_no_mem;
96beb9def0Sdrh for(i=0; isspace(zIn[i]); i++){}
97beb9def0Sdrh if( zIn[i]=='-' ){
98beb9def0Sdrh p->sign = 1;
99beb9def0Sdrh i++;
100beb9def0Sdrh }else if( zIn[i]=='+' ){
101beb9def0Sdrh i++;
102beb9def0Sdrh }
103beb9def0Sdrh while( i<n && zIn[i]=='0' ) i++;
104beb9def0Sdrh while( i<n ){
105beb9def0Sdrh char c = zIn[i];
106beb9def0Sdrh if( c>='0' && c<='9' ){
107beb9def0Sdrh p->a[p->nDigit++] = c - '0';
108beb9def0Sdrh }else if( c=='.' ){
109beb9def0Sdrh p->nFrac = p->nDigit + 1;
110beb9def0Sdrh }else if( c=='e' || c=='E' ){
111beb9def0Sdrh int j = i+1;
112beb9def0Sdrh int neg = 0;
113beb9def0Sdrh if( j>=n ) break;
114beb9def0Sdrh if( zIn[j]=='-' ){
115beb9def0Sdrh neg = 1;
116beb9def0Sdrh j++;
117beb9def0Sdrh }else if( zIn[j]=='+' ){
118beb9def0Sdrh j++;
119beb9def0Sdrh }
120beb9def0Sdrh while( j<n && iExp<1000000 ){
121beb9def0Sdrh if( zIn[j]>='0' && zIn[j]<='9' ){
122beb9def0Sdrh iExp = iExp*10 + zIn[j] - '0';
123beb9def0Sdrh }
124beb9def0Sdrh j++;
125beb9def0Sdrh }
126beb9def0Sdrh if( neg ) iExp = -iExp;
127beb9def0Sdrh break;
128beb9def0Sdrh }
129beb9def0Sdrh i++;
130beb9def0Sdrh }
131beb9def0Sdrh if( p->nFrac ){
132beb9def0Sdrh p->nFrac = p->nDigit - (p->nFrac - 1);
133beb9def0Sdrh }
134beb9def0Sdrh if( iExp>0 ){
135beb9def0Sdrh if( p->nFrac>0 ){
136beb9def0Sdrh if( iExp<=p->nFrac ){
137beb9def0Sdrh p->nFrac -= iExp;
138beb9def0Sdrh iExp = 0;
139beb9def0Sdrh }else{
140beb9def0Sdrh iExp -= p->nFrac;
141beb9def0Sdrh p->nFrac = 0;
142beb9def0Sdrh }
143beb9def0Sdrh }
144beb9def0Sdrh if( iExp>0 ){
145beb9def0Sdrh p->a = sqlite3_realloc64(p->a, p->nDigit + iExp + 1 );
146beb9def0Sdrh if( p->a==0 ) goto new_no_mem;
147beb9def0Sdrh memset(p->a+p->nDigit, 0, iExp);
148beb9def0Sdrh p->nDigit += iExp;
149beb9def0Sdrh }
150beb9def0Sdrh }else if( iExp<0 ){
151beb9def0Sdrh int nExtra;
152beb9def0Sdrh iExp = -iExp;
153beb9def0Sdrh nExtra = p->nDigit - p->nFrac - 1;
154beb9def0Sdrh if( nExtra ){
155beb9def0Sdrh if( nExtra>=iExp ){
156beb9def0Sdrh p->nFrac += iExp;
157beb9def0Sdrh iExp = 0;
158beb9def0Sdrh }else{
159beb9def0Sdrh iExp -= nExtra;
160beb9def0Sdrh p->nFrac = p->nDigit - 1;
161beb9def0Sdrh }
162beb9def0Sdrh }
163beb9def0Sdrh if( iExp>0 ){
164beb9def0Sdrh p->a = sqlite3_realloc64(p->a, p->nDigit + iExp + 1 );
165beb9def0Sdrh if( p->a==0 ) goto new_no_mem;
166beb9def0Sdrh memmove(p->a+iExp, p->a, p->nDigit);
167beb9def0Sdrh memset(p->a, 0, iExp);
168beb9def0Sdrh p->nDigit += iExp;
169beb9def0Sdrh p->nFrac += iExp;
170beb9def0Sdrh }
171beb9def0Sdrh }
172beb9def0Sdrh return p;
173beb9def0Sdrh
174beb9def0Sdrh new_no_mem:
175beb9def0Sdrh if( pCtx ) sqlite3_result_error_nomem(pCtx);
176beb9def0Sdrh sqlite3_free(p);
177beb9def0Sdrh return 0;
178beb9def0Sdrh }
179beb9def0Sdrh
180beb9def0Sdrh /*
181beb9def0Sdrh ** Make the given Decimal the result.
182beb9def0Sdrh */
decimal_result(sqlite3_context * pCtx,Decimal * p)183beb9def0Sdrh static void decimal_result(sqlite3_context *pCtx, Decimal *p){
184beb9def0Sdrh char *z;
185beb9def0Sdrh int i, j;
186beb9def0Sdrh int n;
187beb9def0Sdrh if( p==0 || p->oom ){
188beb9def0Sdrh sqlite3_result_error_nomem(pCtx);
189beb9def0Sdrh return;
190beb9def0Sdrh }
191beb9def0Sdrh if( p->isNull ){
192beb9def0Sdrh sqlite3_result_null(pCtx);
193beb9def0Sdrh return;
194beb9def0Sdrh }
195beb9def0Sdrh z = sqlite3_malloc( p->nDigit+4 );
196beb9def0Sdrh if( z==0 ){
197beb9def0Sdrh sqlite3_result_error_nomem(pCtx);
198beb9def0Sdrh return;
199beb9def0Sdrh }
200beb9def0Sdrh i = 0;
201beb9def0Sdrh if( p->nDigit==0 || (p->nDigit==1 && p->a[0]==0) ){
202beb9def0Sdrh p->sign = 0;
203beb9def0Sdrh }
204beb9def0Sdrh if( p->sign ){
205beb9def0Sdrh z[0] = '-';
206beb9def0Sdrh i = 1;
207beb9def0Sdrh }
208beb9def0Sdrh n = p->nDigit - p->nFrac;
209beb9def0Sdrh if( n<=0 ){
210beb9def0Sdrh z[i++] = '0';
211beb9def0Sdrh }
212beb9def0Sdrh j = 0;
2136b647186Sdrh while( n>1 && p->a[j]==0 ){
2146b647186Sdrh j++;
2156b647186Sdrh n--;
2166b647186Sdrh }
217beb9def0Sdrh while( n>0 ){
218beb9def0Sdrh z[i++] = p->a[j] + '0';
219beb9def0Sdrh j++;
220beb9def0Sdrh n--;
221beb9def0Sdrh }
222beb9def0Sdrh if( p->nFrac ){
223beb9def0Sdrh z[i++] = '.';
224beb9def0Sdrh do{
225beb9def0Sdrh z[i++] = p->a[j] + '0';
226beb9def0Sdrh j++;
227beb9def0Sdrh }while( j<p->nDigit );
228beb9def0Sdrh }
229beb9def0Sdrh z[i] = 0;
230beb9def0Sdrh sqlite3_result_text(pCtx, z, i, sqlite3_free);
231beb9def0Sdrh }
232beb9def0Sdrh
233beb9def0Sdrh /*
234beb9def0Sdrh ** SQL Function: decimal(X)
235beb9def0Sdrh **
236beb9def0Sdrh ** Convert input X into decimal and then back into text
237beb9def0Sdrh */
decimalFunc(sqlite3_context * context,int argc,sqlite3_value ** argv)238beb9def0Sdrh static void decimalFunc(
239beb9def0Sdrh sqlite3_context *context,
240beb9def0Sdrh int argc,
241beb9def0Sdrh sqlite3_value **argv
242beb9def0Sdrh ){
243beb9def0Sdrh Decimal *p = decimal_new(context, argv[0], 0, 0);
244a7c74006Sdrh UNUSED_PARAMETER(argc);
245beb9def0Sdrh decimal_result(context, p);
246beb9def0Sdrh decimal_free(p);
247beb9def0Sdrh }
248beb9def0Sdrh
249beb9def0Sdrh /*
250beb9def0Sdrh ** Compare to Decimal objects. Return negative, 0, or positive if the
251beb9def0Sdrh ** first object is less than, equal to, or greater than the second.
252beb9def0Sdrh **
253beb9def0Sdrh ** Preconditions for this routine:
254beb9def0Sdrh **
255beb9def0Sdrh ** pA!=0
256beb9def0Sdrh ** pA->isNull==0
257beb9def0Sdrh ** pB!=0
258beb9def0Sdrh ** pB->isNull==0
259beb9def0Sdrh */
decimal_cmp(const Decimal * pA,const Decimal * pB)260beb9def0Sdrh static int decimal_cmp(const Decimal *pA, const Decimal *pB){
261beb9def0Sdrh int nASig, nBSig, rc, n;
262beb9def0Sdrh if( pA->sign!=pB->sign ){
263beb9def0Sdrh return pA->sign ? -1 : +1;
264beb9def0Sdrh }
265beb9def0Sdrh if( pA->sign ){
266beb9def0Sdrh const Decimal *pTemp = pA;
267beb9def0Sdrh pA = pB;
268beb9def0Sdrh pB = pTemp;
269beb9def0Sdrh }
270beb9def0Sdrh nASig = pA->nDigit - pA->nFrac;
271beb9def0Sdrh nBSig = pB->nDigit - pB->nFrac;
272beb9def0Sdrh if( nASig!=nBSig ){
273beb9def0Sdrh return nASig - nBSig;
274beb9def0Sdrh }
275beb9def0Sdrh n = pA->nDigit;
276beb9def0Sdrh if( n>pB->nDigit ) n = pB->nDigit;
277beb9def0Sdrh rc = memcmp(pA->a, pB->a, n);
278beb9def0Sdrh if( rc==0 ){
279beb9def0Sdrh rc = pA->nDigit - pB->nDigit;
280beb9def0Sdrh }
281beb9def0Sdrh return rc;
282beb9def0Sdrh }
283beb9def0Sdrh
284beb9def0Sdrh /*
285beb9def0Sdrh ** SQL Function: decimal_cmp(X, Y)
286beb9def0Sdrh **
287beb9def0Sdrh ** Return negative, zero, or positive if X is less then, equal to, or
288beb9def0Sdrh ** greater than Y.
289beb9def0Sdrh */
decimalCmpFunc(sqlite3_context * context,int argc,sqlite3_value ** argv)290beb9def0Sdrh static void decimalCmpFunc(
291beb9def0Sdrh sqlite3_context *context,
292beb9def0Sdrh int argc,
293beb9def0Sdrh sqlite3_value **argv
294beb9def0Sdrh ){
295beb9def0Sdrh Decimal *pA = 0, *pB = 0;
296beb9def0Sdrh int rc;
297beb9def0Sdrh
298a7c74006Sdrh UNUSED_PARAMETER(argc);
299beb9def0Sdrh pA = decimal_new(context, argv[0], 0, 0);
300beb9def0Sdrh if( pA==0 || pA->isNull ) goto cmp_done;
301beb9def0Sdrh pB = decimal_new(context, argv[1], 0, 0);
302beb9def0Sdrh if( pB==0 || pB->isNull ) goto cmp_done;
303beb9def0Sdrh rc = decimal_cmp(pA, pB);
304beb9def0Sdrh if( rc<0 ) rc = -1;
305beb9def0Sdrh else if( rc>0 ) rc = +1;
306beb9def0Sdrh sqlite3_result_int(context, rc);
307beb9def0Sdrh cmp_done:
308beb9def0Sdrh decimal_free(pA);
309beb9def0Sdrh decimal_free(pB);
310beb9def0Sdrh }
311beb9def0Sdrh
312beb9def0Sdrh /*
313beb9def0Sdrh ** Expand the Decimal so that it has a least nDigit digits and nFrac
314beb9def0Sdrh ** digits to the right of the decimal point.
315beb9def0Sdrh */
decimal_expand(Decimal * p,int nDigit,int nFrac)316beb9def0Sdrh static void decimal_expand(Decimal *p, int nDigit, int nFrac){
317beb9def0Sdrh int nAddSig;
318beb9def0Sdrh int nAddFrac;
319beb9def0Sdrh if( p==0 ) return;
320beb9def0Sdrh nAddFrac = nFrac - p->nFrac;
321beb9def0Sdrh nAddSig = (nDigit - p->nDigit) - nAddFrac;
322beb9def0Sdrh if( nAddFrac==0 && nAddSig==0 ) return;
323beb9def0Sdrh p->a = sqlite3_realloc64(p->a, nDigit+1);
324beb9def0Sdrh if( p->a==0 ){
325beb9def0Sdrh p->oom = 1;
326beb9def0Sdrh return;
327beb9def0Sdrh }
328beb9def0Sdrh if( nAddSig ){
329beb9def0Sdrh memmove(p->a+nAddSig, p->a, p->nDigit);
330beb9def0Sdrh memset(p->a, 0, nAddSig);
331beb9def0Sdrh p->nDigit += nAddSig;
332beb9def0Sdrh }
333beb9def0Sdrh if( nAddFrac ){
334beb9def0Sdrh memset(p->a+p->nDigit, 0, nAddFrac);
335beb9def0Sdrh p->nDigit += nAddFrac;
336beb9def0Sdrh p->nFrac += nAddFrac;
337beb9def0Sdrh }
338beb9def0Sdrh }
339beb9def0Sdrh
340beb9def0Sdrh /*
341beb9def0Sdrh ** Add the value pB into pA.
342beb9def0Sdrh **
3436b647186Sdrh ** Both pA and pB might become denormalized by this routine.
344beb9def0Sdrh */
decimal_add(Decimal * pA,Decimal * pB)345beb9def0Sdrh static void decimal_add(Decimal *pA, Decimal *pB){
346beb9def0Sdrh int nSig, nFrac, nDigit;
347beb9def0Sdrh int i, rc;
348beb9def0Sdrh if( pA==0 ){
349beb9def0Sdrh return;
350beb9def0Sdrh }
351beb9def0Sdrh if( pA->oom || pB==0 || pB->oom ){
352beb9def0Sdrh pA->oom = 1;
353beb9def0Sdrh return;
354beb9def0Sdrh }
355beb9def0Sdrh if( pA->isNull || pB->isNull ){
356beb9def0Sdrh pA->isNull = 1;
357beb9def0Sdrh return;
358beb9def0Sdrh }
359beb9def0Sdrh nSig = pA->nDigit - pA->nFrac;
3606b647186Sdrh if( nSig && pA->a[0]==0 ) nSig--;
3616b647186Sdrh if( nSig<pB->nDigit-pB->nFrac ){
3626b647186Sdrh nSig = pB->nDigit - pB->nFrac;
3636b647186Sdrh }
364beb9def0Sdrh nFrac = pA->nFrac;
365beb9def0Sdrh if( nFrac<pB->nFrac ) nFrac = pB->nFrac;
366beb9def0Sdrh nDigit = nSig + nFrac + 1;
367beb9def0Sdrh decimal_expand(pA, nDigit, nFrac);
368beb9def0Sdrh decimal_expand(pB, nDigit, nFrac);
369beb9def0Sdrh if( pA->oom || pB->oom ){
370beb9def0Sdrh pA->oom = 1;
371beb9def0Sdrh }else{
372beb9def0Sdrh if( pA->sign==pB->sign ){
373beb9def0Sdrh int carry = 0;
374beb9def0Sdrh for(i=nDigit-1; i>=0; i--){
375beb9def0Sdrh int x = pA->a[i] + pB->a[i] + carry;
376beb9def0Sdrh if( x>=10 ){
377beb9def0Sdrh carry = 1;
378beb9def0Sdrh pA->a[i] = x - 10;
379beb9def0Sdrh }else{
380beb9def0Sdrh carry = 0;
381beb9def0Sdrh pA->a[i] = x;
382beb9def0Sdrh }
383beb9def0Sdrh }
384beb9def0Sdrh }else{
385beb9def0Sdrh signed char *aA, *aB;
386beb9def0Sdrh int borrow = 0;
387beb9def0Sdrh rc = memcmp(pA->a, pB->a, nDigit);
388beb9def0Sdrh if( rc<0 ){
389beb9def0Sdrh aA = pB->a;
390beb9def0Sdrh aB = pA->a;
391beb9def0Sdrh pA->sign = !pA->sign;
392beb9def0Sdrh }else{
393beb9def0Sdrh aA = pA->a;
394beb9def0Sdrh aB = pB->a;
395beb9def0Sdrh }
396beb9def0Sdrh for(i=nDigit-1; i>=0; i--){
397beb9def0Sdrh int x = aA[i] - aB[i] - borrow;
398beb9def0Sdrh if( x<0 ){
399beb9def0Sdrh pA->a[i] = x+10;
400beb9def0Sdrh borrow = 1;
401beb9def0Sdrh }else{
402beb9def0Sdrh pA->a[i] = x;
403beb9def0Sdrh borrow = 0;
404beb9def0Sdrh }
405beb9def0Sdrh }
406beb9def0Sdrh }
407beb9def0Sdrh }
408beb9def0Sdrh }
409beb9def0Sdrh
410beb9def0Sdrh /*
411beb9def0Sdrh ** Compare text in decimal order.
412beb9def0Sdrh */
decimalCollFunc(void * notUsed,int nKey1,const void * pKey1,int nKey2,const void * pKey2)413beb9def0Sdrh static int decimalCollFunc(
414beb9def0Sdrh void *notUsed,
415beb9def0Sdrh int nKey1, const void *pKey1,
416beb9def0Sdrh int nKey2, const void *pKey2
417beb9def0Sdrh ){
418beb9def0Sdrh const unsigned char *zA = (const unsigned char*)pKey1;
419beb9def0Sdrh const unsigned char *zB = (const unsigned char*)pKey2;
420beb9def0Sdrh Decimal *pA = decimal_new(0, 0, nKey1, zA);
421beb9def0Sdrh Decimal *pB = decimal_new(0, 0, nKey2, zB);
422beb9def0Sdrh int rc;
423a7c74006Sdrh UNUSED_PARAMETER(notUsed);
424beb9def0Sdrh if( pA==0 || pB==0 ){
425beb9def0Sdrh rc = 0;
426beb9def0Sdrh }else{
427beb9def0Sdrh rc = decimal_cmp(pA, pB);
428beb9def0Sdrh }
429beb9def0Sdrh decimal_free(pA);
430beb9def0Sdrh decimal_free(pB);
431beb9def0Sdrh return rc;
432beb9def0Sdrh }
433beb9def0Sdrh
434beb9def0Sdrh
435beb9def0Sdrh /*
436beb9def0Sdrh ** SQL Function: decimal_add(X, Y)
437beb9def0Sdrh ** decimal_sub(X, Y)
438beb9def0Sdrh **
439beb9def0Sdrh ** Return the sum or difference of X and Y.
440beb9def0Sdrh */
decimalAddFunc(sqlite3_context * context,int argc,sqlite3_value ** argv)441beb9def0Sdrh static void decimalAddFunc(
442beb9def0Sdrh sqlite3_context *context,
443beb9def0Sdrh int argc,
444beb9def0Sdrh sqlite3_value **argv
445beb9def0Sdrh ){
446beb9def0Sdrh Decimal *pA = decimal_new(context, argv[0], 0, 0);
447beb9def0Sdrh Decimal *pB = decimal_new(context, argv[1], 0, 0);
448a7c74006Sdrh UNUSED_PARAMETER(argc);
449beb9def0Sdrh decimal_add(pA, pB);
450beb9def0Sdrh decimal_result(context, pA);
451beb9def0Sdrh decimal_free(pA);
452beb9def0Sdrh decimal_free(pB);
453beb9def0Sdrh }
decimalSubFunc(sqlite3_context * context,int argc,sqlite3_value ** argv)454beb9def0Sdrh static void decimalSubFunc(
455beb9def0Sdrh sqlite3_context *context,
456beb9def0Sdrh int argc,
457beb9def0Sdrh sqlite3_value **argv
458beb9def0Sdrh ){
459beb9def0Sdrh Decimal *pA = decimal_new(context, argv[0], 0, 0);
460beb9def0Sdrh Decimal *pB = decimal_new(context, argv[1], 0, 0);
461a7c74006Sdrh UNUSED_PARAMETER(argc);
462*e103a8deSdrh if( pB ){
463beb9def0Sdrh pB->sign = !pB->sign;
464beb9def0Sdrh decimal_add(pA, pB);
465beb9def0Sdrh decimal_result(context, pA);
466*e103a8deSdrh }
467beb9def0Sdrh decimal_free(pA);
468beb9def0Sdrh decimal_free(pB);
469beb9def0Sdrh }
470beb9def0Sdrh
471beb9def0Sdrh /* Aggregate funcion: decimal_sum(X)
472beb9def0Sdrh **
473beb9def0Sdrh ** Works like sum() except that it uses decimal arithmetic for unlimited
474beb9def0Sdrh ** precision.
475beb9def0Sdrh */
decimalSumStep(sqlite3_context * context,int argc,sqlite3_value ** argv)476beb9def0Sdrh static void decimalSumStep(
477beb9def0Sdrh sqlite3_context *context,
478beb9def0Sdrh int argc,
479beb9def0Sdrh sqlite3_value **argv
480beb9def0Sdrh ){
481beb9def0Sdrh Decimal *p;
482beb9def0Sdrh Decimal *pArg;
483a7c74006Sdrh UNUSED_PARAMETER(argc);
484beb9def0Sdrh p = sqlite3_aggregate_context(context, sizeof(*p));
485beb9def0Sdrh if( p==0 ) return;
486beb9def0Sdrh if( !p->isInit ){
487beb9def0Sdrh p->isInit = 1;
488beb9def0Sdrh p->a = sqlite3_malloc(2);
489beb9def0Sdrh if( p->a==0 ){
490beb9def0Sdrh p->oom = 1;
491beb9def0Sdrh }else{
492beb9def0Sdrh p->a[0] = 0;
493beb9def0Sdrh }
494beb9def0Sdrh p->nDigit = 1;
495beb9def0Sdrh p->nFrac = 0;
496beb9def0Sdrh }
497beb9def0Sdrh if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
498beb9def0Sdrh pArg = decimal_new(context, argv[0], 0, 0);
499beb9def0Sdrh decimal_add(p, pArg);
500beb9def0Sdrh decimal_free(pArg);
501beb9def0Sdrh }
decimalSumInverse(sqlite3_context * context,int argc,sqlite3_value ** argv)502beb9def0Sdrh static void decimalSumInverse(
503beb9def0Sdrh sqlite3_context *context,
504beb9def0Sdrh int argc,
505beb9def0Sdrh sqlite3_value **argv
506beb9def0Sdrh ){
507beb9def0Sdrh Decimal *p;
508beb9def0Sdrh Decimal *pArg;
509a7c74006Sdrh UNUSED_PARAMETER(argc);
510beb9def0Sdrh p = sqlite3_aggregate_context(context, sizeof(*p));
511beb9def0Sdrh if( p==0 ) return;
512beb9def0Sdrh if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
513beb9def0Sdrh pArg = decimal_new(context, argv[0], 0, 0);
514beb9def0Sdrh if( pArg ) pArg->sign = !pArg->sign;
515beb9def0Sdrh decimal_add(p, pArg);
516beb9def0Sdrh decimal_free(pArg);
517beb9def0Sdrh }
decimalSumValue(sqlite3_context * context)518beb9def0Sdrh static void decimalSumValue(sqlite3_context *context){
519beb9def0Sdrh Decimal *p = sqlite3_aggregate_context(context, 0);
520beb9def0Sdrh if( p==0 ) return;
521beb9def0Sdrh decimal_result(context, p);
522beb9def0Sdrh }
decimalSumFinalize(sqlite3_context * context)523beb9def0Sdrh static void decimalSumFinalize(sqlite3_context *context){
524beb9def0Sdrh Decimal *p = sqlite3_aggregate_context(context, 0);
525beb9def0Sdrh if( p==0 ) return;
526beb9def0Sdrh decimal_result(context, p);
527beb9def0Sdrh decimal_clear(p);
528beb9def0Sdrh }
529beb9def0Sdrh
530427af8dcSdrh /*
531427af8dcSdrh ** SQL Function: decimal_mul(X, Y)
532427af8dcSdrh **
533427af8dcSdrh ** Return the product of X and Y.
5346b647186Sdrh **
5356b647186Sdrh ** All significant digits after the decimal point are retained.
5366b647186Sdrh ** Trailing zeros after the decimal point are omitted as long as
5376b647186Sdrh ** the number of digits after the decimal point is no less than
5386b647186Sdrh ** either the number of digits in either input.
539427af8dcSdrh */
decimalMulFunc(sqlite3_context * context,int argc,sqlite3_value ** argv)540427af8dcSdrh static void decimalMulFunc(
541427af8dcSdrh sqlite3_context *context,
542427af8dcSdrh int argc,
543427af8dcSdrh sqlite3_value **argv
544427af8dcSdrh ){
545427af8dcSdrh Decimal *pA = decimal_new(context, argv[0], 0, 0);
546427af8dcSdrh Decimal *pB = decimal_new(context, argv[1], 0, 0);
547427af8dcSdrh signed char *acc = 0;
548427af8dcSdrh int i, j, k;
5496b647186Sdrh int minFrac;
550a7c74006Sdrh UNUSED_PARAMETER(argc);
551427af8dcSdrh if( pA==0 || pA->oom || pA->isNull
552427af8dcSdrh || pB==0 || pB->oom || pB->isNull
553427af8dcSdrh ){
554427af8dcSdrh goto mul_end;
555427af8dcSdrh }
556427af8dcSdrh acc = sqlite3_malloc64( pA->nDigit + pB->nDigit + 2 );
557427af8dcSdrh if( acc==0 ){
558427af8dcSdrh sqlite3_result_error_nomem(context);
559427af8dcSdrh goto mul_end;
560427af8dcSdrh }
561427af8dcSdrh memset(acc, 0, pA->nDigit + pB->nDigit + 2);
5626b647186Sdrh minFrac = pA->nFrac;
5636b647186Sdrh if( pB->nFrac<minFrac ) minFrac = pB->nFrac;
564427af8dcSdrh for(i=pA->nDigit-1; i>=0; i--){
565427af8dcSdrh signed char f = pA->a[i];
566427af8dcSdrh int carry = 0, x;
567427af8dcSdrh for(j=pB->nDigit-1, k=i+j+3; j>=0; j--, k--){
568e78c027bSdrh x = acc[k] + f*pB->a[j] + carry;
569427af8dcSdrh acc[k] = x%10;
570427af8dcSdrh carry = x/10;
571427af8dcSdrh }
572427af8dcSdrh x = acc[k] + carry;
573427af8dcSdrh acc[k] = x%10;
574427af8dcSdrh acc[k-1] += x/10;
575427af8dcSdrh }
576427af8dcSdrh sqlite3_free(pA->a);
577427af8dcSdrh pA->a = acc;
578427af8dcSdrh acc = 0;
579427af8dcSdrh pA->nDigit += pB->nDigit + 2;
580427af8dcSdrh pA->nFrac += pB->nFrac;
581427af8dcSdrh pA->sign ^= pB->sign;
5826b647186Sdrh while( pA->nFrac>minFrac && pA->a[pA->nDigit-1]==0 ){
5836b647186Sdrh pA->nFrac--;
5846b647186Sdrh pA->nDigit--;
5856b647186Sdrh }
586427af8dcSdrh decimal_result(context, pA);
587427af8dcSdrh
588427af8dcSdrh mul_end:
589427af8dcSdrh sqlite3_free(acc);
590427af8dcSdrh decimal_free(pA);
591427af8dcSdrh decimal_free(pB);
592427af8dcSdrh }
593beb9def0Sdrh
594beb9def0Sdrh #ifdef _WIN32
595beb9def0Sdrh __declspec(dllexport)
596beb9def0Sdrh #endif
sqlite3_decimal_init(sqlite3 * db,char ** pzErrMsg,const sqlite3_api_routines * pApi)597beb9def0Sdrh int sqlite3_decimal_init(
598beb9def0Sdrh sqlite3 *db,
599beb9def0Sdrh char **pzErrMsg,
600beb9def0Sdrh const sqlite3_api_routines *pApi
601beb9def0Sdrh ){
602beb9def0Sdrh int rc = SQLITE_OK;
603beb9def0Sdrh static const struct {
604beb9def0Sdrh const char *zFuncName;
605beb9def0Sdrh int nArg;
606beb9def0Sdrh void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
607beb9def0Sdrh } aFunc[] = {
608beb9def0Sdrh { "decimal", 1, decimalFunc },
609beb9def0Sdrh { "decimal_cmp", 2, decimalCmpFunc },
610beb9def0Sdrh { "decimal_add", 2, decimalAddFunc },
611beb9def0Sdrh { "decimal_sub", 2, decimalSubFunc },
612427af8dcSdrh { "decimal_mul", 2, decimalMulFunc },
613beb9def0Sdrh };
614a7c74006Sdrh unsigned int i;
615beb9def0Sdrh (void)pzErrMsg; /* Unused parameter */
616beb9def0Sdrh
6177033ce4fSdrh SQLITE_EXTENSION_INIT2(pApi);
6187033ce4fSdrh
619beb9def0Sdrh for(i=0; i<sizeof(aFunc)/sizeof(aFunc[0]) && rc==SQLITE_OK; i++){
620beb9def0Sdrh rc = sqlite3_create_function(db, aFunc[i].zFuncName, aFunc[i].nArg,
621beb9def0Sdrh SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC,
622beb9def0Sdrh 0, aFunc[i].xFunc, 0, 0);
623beb9def0Sdrh }
624beb9def0Sdrh if( rc==SQLITE_OK ){
625beb9def0Sdrh rc = sqlite3_create_window_function(db, "decimal_sum", 1,
626beb9def0Sdrh SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC, 0,
627beb9def0Sdrh decimalSumStep, decimalSumFinalize,
628beb9def0Sdrh decimalSumValue, decimalSumInverse, 0);
629beb9def0Sdrh }
630beb9def0Sdrh if( rc==SQLITE_OK ){
631beb9def0Sdrh rc = sqlite3_create_collation(db, "decimal", SQLITE_UTF8,
632beb9def0Sdrh 0, decimalCollFunc);
633beb9def0Sdrh }
634beb9def0Sdrh return rc;
635beb9def0Sdrh }
636