1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-07-30 19:03:16 +03:00

Cleanup and commenting of the new DECIMAL extension code. No functional

changes.

FossilOrigin-Name: 5124481663eb8e74a9f861be98adb7075ea911fcff0216d98c658e955acadf14
This commit is contained in:
drh
2023-06-29 23:03:30 +00:00
parent ec3e57fa92
commit 2ddfa6a360
3 changed files with 110 additions and 86 deletions

View File

@ -58,41 +58,24 @@ static void decimal_free(Decimal *p){
} }
/* /*
** Allocate a new Decimal object. Initialize it to the number given ** Allocate a new Decimal object initialized to the text in zIn[].
** by the input string. ** Return NULL if any kind of error occurs.
*/ */
static Decimal *decimal_new( static Decimal *decimalNewFromText(const char *zIn, int n){
sqlite3_context *pCtx, Decimal *p = 0;
sqlite3_value *pIn, int i;
int nAlt,
const unsigned char *zAlt
){
Decimal *p;
int n, i;
const unsigned char *zIn;
int iExp = 0; int iExp = 0;
p = sqlite3_malloc( sizeof(*p) ); p = sqlite3_malloc( sizeof(*p) );
if( p==0 ) goto new_no_mem; if( p==0 ) goto new_from_text_failed;
p->sign = 0; p->sign = 0;
p->oom = 0; p->oom = 0;
p->isInit = 1; p->isInit = 1;
p->isNull = 0; p->isNull = 0;
p->nDigit = 0; p->nDigit = 0;
p->nFrac = 0; p->nFrac = 0;
if( zAlt ){
n = nAlt,
zIn = zAlt;
}else{
if( sqlite3_value_type(pIn)==SQLITE_NULL ){
p->a = 0;
p->isNull = 1;
return p;
}
n = sqlite3_value_bytes(pIn);
zIn = sqlite3_value_text(pIn);
}
p->a = sqlite3_malloc64( n+1 ); p->a = sqlite3_malloc64( n+1 );
if( p->a==0 ) goto new_no_mem; if( p->a==0 ) goto new_from_text_failed;
for(i=0; isspace(zIn[i]); i++){} for(i=0; isspace(zIn[i]); i++){}
if( zIn[i]=='-' ){ if( zIn[i]=='-' ){
p->sign = 1; p->sign = 1;
@ -143,7 +126,7 @@ static Decimal *decimal_new(
} }
if( iExp>0 ){ if( iExp>0 ){
p->a = sqlite3_realloc64(p->a, p->nDigit + iExp + 1 ); p->a = sqlite3_realloc64(p->a, p->nDigit + iExp + 1 );
if( p->a==0 ) goto new_no_mem; if( p->a==0 ) goto new_from_text_failed;
memset(p->a+p->nDigit, 0, iExp); memset(p->a+p->nDigit, 0, iExp);
p->nDigit += iExp; p->nDigit += iExp;
} }
@ -162,7 +145,7 @@ static Decimal *decimal_new(
} }
if( iExp>0 ){ if( iExp>0 ){
p->a = sqlite3_realloc64(p->a, p->nDigit + iExp + 1 ); p->a = sqlite3_realloc64(p->a, p->nDigit + iExp + 1 );
if( p->a==0 ) goto new_no_mem; if( p->a==0 ) goto new_from_text_failed;
memmove(p->a+iExp, p->a, p->nDigit); memmove(p->a+iExp, p->a, p->nDigit);
memset(p->a, 0, iExp); memset(p->a, 0, iExp);
p->nDigit += iExp; p->nDigit += iExp;
@ -171,7 +154,76 @@ static Decimal *decimal_new(
} }
return p; return p;
new_no_mem: new_from_text_failed:
if( p ){
if( p->a ) sqlite3_free(p->a);
sqlite3_free(p);
}
return 0;
}
/* Forward reference */
static Decimal *decimalFromDouble(double);
/*
** Allocate a new Decimal object from an sqlite3_value. Return a pointer
** to the new object, or NULL if there is an error. If the pCtx argument
** is not NULL, then errors are reported on it as well.
**
** If the pIn argument is SQLITE_TEXT or SQLITE_INTEGER, it is converted
** directly into a Decimal. For SQLITE_FLOAT or for SQLITE_BLOB of length
** 8 bytes, the resulting double value is expanded into its decimal equivalent.
** If pIn is NULL or if it is a BLOB that is not exactly 8 bytes in length,
** then NULL is returned.
*/
static Decimal *decimal_new(
sqlite3_context *pCtx, /* Report error here, if not null */
sqlite3_value *pIn, /* Construct the decimal object from this */
int bTextOnly /* Always interpret pIn as text if true */
){
Decimal *p = 0;
int eType = sqlite3_value_type(pIn);
if( bTextOnly && (eType==SQLITE_FLOAT || eType==SQLITE_BLOB) ){
eType = SQLITE_TEXT;
}
switch( eType ){
case SQLITE_TEXT:
case SQLITE_INTEGER: {
const char *zIn = (const char*)sqlite3_value_text(pIn);
int n = sqlite3_value_bytes(pIn);
p = decimalNewFromText(zIn, n);
if( p==0 ) goto new_failed;
break;
}
case SQLITE_FLOAT: {
p = decimalFromDouble(sqlite3_value_double(pIn));
break;
}
case SQLITE_BLOB: {
const unsigned char *x;
unsigned int i;
sqlite3_uint64 v = 0;
double r;
if( sqlite3_value_bytes(pIn)!=sizeof(r) ) break;
x = sqlite3_value_blob(pIn);
for(i=0; i<sizeof(r); i++){
v = (v<<8) | x[i];
}
memcpy(&r, &v, sizeof(r));
p = decimalFromDouble(r);
break;
}
case SQLITE_NULL: {
break;
}
}
return p;
new_failed:
if( pCtx ) sqlite3_result_error_nomem(pCtx); if( pCtx ) sqlite3_result_error_nomem(pCtx);
sqlite3_free(p); sqlite3_free(p);
return 0; return 0;
@ -341,9 +393,9 @@ static void decimalCmpFunc(
int rc; int rc;
UNUSED_PARAMETER(argc); UNUSED_PARAMETER(argc);
pA = decimal_new(context, argv[0], 0, 0); pA = decimal_new(context, argv[0], 1);
if( pA==0 || pA->isNull ) goto cmp_done; if( pA==0 || pA->isNull ) goto cmp_done;
pB = decimal_new(context, argv[1], 0, 0); pB = decimal_new(context, argv[1], 1);
if( pB==0 || pB->isNull ) goto cmp_done; if( pB==0 || pB->isNull ) goto cmp_done;
rc = decimal_cmp(pA, pB); rc = decimal_cmp(pA, pB);
if( rc<0 ) rc = -1; if( rc<0 ) rc = -1;
@ -512,14 +564,14 @@ static Decimal *decimalPow2(int N){
Decimal *pA = 0; /* The result to be returned */ Decimal *pA = 0; /* The result to be returned */
Decimal *pX = 0; /* Multiplier */ Decimal *pX = 0; /* Multiplier */
if( N<-20000 || N>20000 ) goto pow2_fault; if( N<-20000 || N>20000 ) goto pow2_fault;
pA = decimal_new(0, 0, 3, (unsigned char*)"1.0"); pA = decimalNewFromText("1.0", 3);
if( pA==0 || pA->oom ) goto pow2_fault; if( pA==0 || pA->oom ) goto pow2_fault;
if( N==0 ) return pA; if( N==0 ) return pA;
if( N>0 ){ if( N>0 ){
pX = decimal_new(0, 0, 3, (unsigned char*)"2.0"); pX = decimalNewFromText("2.0", 3);
}else{ }else{
N = -N; N = -N;
pX = decimal_new(0, 0, 3, (unsigned char*)"0.5"); pX = decimalNewFromText("0.5", 3);
} }
if( pX==0 || pX->oom ) goto pow2_fault; if( pX==0 || pX->oom ) goto pow2_fault;
while( 1 /* Exit by break */ ){ while( 1 /* Exit by break */ ){
@ -581,7 +633,7 @@ static Decimal *decimalFromDouble(double r){
/* At this point m is the integer significand and e is the exponent */ /* At this point m is the integer significand and e is the exponent */
sqlite3_snprintf(sizeof(zNum), zNum, "%lld", m); sqlite3_snprintf(sizeof(zNum), zNum, "%lld", m);
pA = decimal_new(0, 0, (int)strlen(zNum), (unsigned char*)zNum); pA = decimalNewFromText(zNum, (int)strlen(zNum));
pX = decimalPow2(e); pX = decimalPow2(e);
decimalMul(pA, pX); decimalMul(pA, pX);
decimal_free(pX); decimal_free(pX);
@ -590,52 +642,24 @@ static Decimal *decimalFromDouble(double r){
/* /*
** SQL Function: decimal(X) ** SQL Function: decimal(X)
** OR: decimal_sci(X)
** **
** Convert input X into decimal and then back into text. ** Convert input X into decimal and then back into text.
** **
** If X is originally a float, then a full decoding of that floating ** If X is originally a float, then a full decimal expansion of that floating
** point value is done. Or if X is an 8-byte blob, it is interpreted ** point value is done. Or if X is an 8-byte blob, it is interpreted
** as a float and similarly expanded. ** as a float and similarly expanded.
**
** The decimal_sci(X) function returns the result in scientific notation.
** decimal(X) returns a complete decimal, without the e+NNN at the end.
*/ */
static void decimalFunc( static void decimalFunc(
sqlite3_context *context, sqlite3_context *context,
int argc, int argc,
sqlite3_value **argv sqlite3_value **argv
){ ){
Decimal *p = 0; Decimal *p = decimal_new(context, argv[0], 0);
UNUSED_PARAMETER(argc); UNUSED_PARAMETER(argc);
switch( sqlite3_value_type(argv[0]) ){
case SQLITE_TEXT:
case SQLITE_INTEGER: {
p = decimal_new(context, argv[0], 0, 0);
break;
}
case SQLITE_FLOAT: {
p = decimalFromDouble(sqlite3_value_double(argv[0]));
break;
}
case SQLITE_BLOB: {
const unsigned char *x;
unsigned int i;
sqlite3_uint64 v = 0;
double r;
if( sqlite3_value_bytes(argv[0])!=sizeof(r) ) break;
x = sqlite3_value_blob(argv[0]);
for(i=0; i<sizeof(r); i++){
v = (v<<8) | x[i];
}
memcpy(&r, &v, sizeof(r));
p = decimalFromDouble(r);
break;
}
case SQLITE_NULL: {
break;
}
}
if( p ){ if( p ){
if( sqlite3_user_data(context)!=0 ){ if( sqlite3_user_data(context)!=0 ){
decimal_result_sci(context, p); decimal_result_sci(context, p);
@ -656,8 +680,8 @@ static int decimalCollFunc(
){ ){
const unsigned char *zA = (const unsigned char*)pKey1; const unsigned char *zA = (const unsigned char*)pKey1;
const unsigned char *zB = (const unsigned char*)pKey2; const unsigned char *zB = (const unsigned char*)pKey2;
Decimal *pA = decimal_new(0, 0, nKey1, zA); Decimal *pA = decimalNewFromText((const char*)zA, nKey1);
Decimal *pB = decimal_new(0, 0, nKey2, zB); Decimal *pB = decimalNewFromText((const char*)zB, nKey2);
int rc; int rc;
UNUSED_PARAMETER(notUsed); UNUSED_PARAMETER(notUsed);
if( pA==0 || pB==0 ){ if( pA==0 || pB==0 ){
@ -682,8 +706,8 @@ static void decimalAddFunc(
int argc, int argc,
sqlite3_value **argv sqlite3_value **argv
){ ){
Decimal *pA = decimal_new(context, argv[0], 0, 0); Decimal *pA = decimal_new(context, argv[0], 1);
Decimal *pB = decimal_new(context, argv[1], 0, 0); Decimal *pB = decimal_new(context, argv[1], 1);
UNUSED_PARAMETER(argc); UNUSED_PARAMETER(argc);
decimal_add(pA, pB); decimal_add(pA, pB);
decimal_result(context, pA); decimal_result(context, pA);
@ -695,8 +719,8 @@ static void decimalSubFunc(
int argc, int argc,
sqlite3_value **argv sqlite3_value **argv
){ ){
Decimal *pA = decimal_new(context, argv[0], 0, 0); Decimal *pA = decimal_new(context, argv[0], 1);
Decimal *pB = decimal_new(context, argv[1], 0, 0); Decimal *pB = decimal_new(context, argv[1], 1);
UNUSED_PARAMETER(argc); UNUSED_PARAMETER(argc);
if( pB ){ if( pB ){
pB->sign = !pB->sign; pB->sign = !pB->sign;
@ -734,7 +758,7 @@ static void decimalSumStep(
p->nFrac = 0; p->nFrac = 0;
} }
if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return; if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
pArg = decimal_new(context, argv[0], 0, 0); pArg = decimal_new(context, argv[0], 1);
decimal_add(p, pArg); decimal_add(p, pArg);
decimal_free(pArg); decimal_free(pArg);
} }
@ -749,7 +773,7 @@ static void decimalSumInverse(
p = sqlite3_aggregate_context(context, sizeof(*p)); p = sqlite3_aggregate_context(context, sizeof(*p));
if( p==0 ) return; if( p==0 ) return;
if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return; if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
pArg = decimal_new(context, argv[0], 0, 0); pArg = decimal_new(context, argv[0], 1);
if( pArg ) pArg->sign = !pArg->sign; if( pArg ) pArg->sign = !pArg->sign;
decimal_add(p, pArg); decimal_add(p, pArg);
decimal_free(pArg); decimal_free(pArg);
@ -776,8 +800,8 @@ static void decimalMulFunc(
int argc, int argc,
sqlite3_value **argv sqlite3_value **argv
){ ){
Decimal *pA = decimal_new(context, argv[0], 0, 0); Decimal *pA = decimal_new(context, argv[0], 1);
Decimal *pB = decimal_new(context, argv[1], 0, 0); Decimal *pB = decimal_new(context, argv[1], 1);
UNUSED_PARAMETER(argc); UNUSED_PARAMETER(argc);
if( pA==0 || pA->oom || pA->isNull if( pA==0 || pA->oom || pA->isNull
|| pB==0 || pB->oom || pB->isNull || pB==0 || pB->oom || pB->isNull
@ -829,11 +853,11 @@ int sqlite3_decimal_init(
void (*xFunc)(sqlite3_context*,int,sqlite3_value**); void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
} aFunc[] = { } aFunc[] = {
{ "decimal", 1, 0, decimalFunc }, { "decimal", 1, 0, decimalFunc },
{ "decimal_sci", 1, 1, decimalFunc },
{ "decimal_cmp", 2, 0, decimalCmpFunc }, { "decimal_cmp", 2, 0, decimalCmpFunc },
{ "decimal_add", 2, 0, decimalAddFunc }, { "decimal_add", 2, 0, decimalAddFunc },
{ "decimal_sub", 2, 0, decimalSubFunc }, { "decimal_sub", 2, 0, decimalSubFunc },
{ "decimal_mul", 2, 0, decimalMulFunc }, { "decimal_mul", 2, 0, decimalMulFunc },
{ "decimal_sci", 1, 1, decimalFunc },
{ "decimal_pow2", 1, 0, decimalPow2Func }, { "decimal_pow2", 1, 0, decimalPow2Func },
}; };
unsigned int i; unsigned int i;

View File

@ -1,5 +1,5 @@
C Enhancements\sto\sthe\sDECIMAL\sextension:\n(1)\sIf\sthe\sargument\sto\sdecimal(X)\sis\sa\sfloating\spoint\svalue\s(or\san\s8-byte\sblob),\nthe\sfloating\spoint\svalue\sis\sexpanded\sinto\sits\sexact\sdecimal\srepresentation.\n(2)\sFunction\sdecimal_sci(X)\sworks\sthe\ssame\sexcept\sit\sreturns\sthe\sresult\sin\nscientific\snotation.\n(3)\sNew\sfunction\sdecimal_pow2(N)\sreturns\sthe\sfull\sdecimal\sexpansion\sof\sthe\sN-th\ninteger\spower\sof\s2. C Cleanup\sand\scommenting\sof\sthe\snew\sDECIMAL\sextension\scode.\s\sNo\sfunctional\nchanges.
D 2023-06-29T20:28:03.266 D 2023-06-29T23:03:30.242
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@ -287,7 +287,7 @@ F ext/misc/completion.c 6dafd7f4348eecc7be9e920d4b419d1fb2af75d938cd9c59a20cfe8b
F ext/misc/compress.c 3354c77a7c8e86e07d849916000cdac451ed96500bfb5bd83b20eb61eee012c9 F ext/misc/compress.c 3354c77a7c8e86e07d849916000cdac451ed96500bfb5bd83b20eb61eee012c9
F ext/misc/csv.c ca8d6dafc5469639de81937cb66ae2e6b358542aba94c4f791910d355a8e7f73 F ext/misc/csv.c ca8d6dafc5469639de81937cb66ae2e6b358542aba94c4f791910d355a8e7f73
F ext/misc/dbdump.c b8592f6f2da292c62991a13864a60d6c573c47a9cc58362131b9e6a64f823e01 F ext/misc/dbdump.c b8592f6f2da292c62991a13864a60d6c573c47a9cc58362131b9e6a64f823e01
F ext/misc/decimal.c 9899f6c3d2622f12a658530bdaff931ad1633d6e65d58e4a5092122dd188d97d F ext/misc/decimal.c a61343b36672760e1d6d5b20a42cb52264db55bcd11d0a44e2e06e8ce23227e3
F ext/misc/eval.c 04bc9aada78c888394204b4ed996ab834b99726fb59603b0ee3ed6e049755dc1 F ext/misc/eval.c 04bc9aada78c888394204b4ed996ab834b99726fb59603b0ee3ed6e049755dc1
F ext/misc/explain.c 0086fab288d4352ea638cf40ac382aad3b0dc5e845a1ea829a694c015fd970fe F ext/misc/explain.c 0086fab288d4352ea638cf40ac382aad3b0dc5e845a1ea829a694c015fd970fe
F ext/misc/fileio.c 4e7f7cd30de8df4820c552f14af3c9ca451c5ffe1f2e7bef34d598a12ebfb720 F ext/misc/fileio.c 4e7f7cd30de8df4820c552f14af3c9ca451c5ffe1f2e7bef34d598a12ebfb720
@ -2041,8 +2041,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P 24927c1377314a10177da4a57191593440aa97fd0c5949fdf25a22df1d947600 P 8baf8c10aecb261751f2b154356ab224b79d07230929ec9f123791278e601bba
R 3c66bdef3f553aa91a9987834f7b8233 R 675d9c81a919ee8e5fecf85fab690bbe
U drh U drh
Z 21790c2ceaea39dee44b1391a0c9d87f Z 280a7e7c456f8f31c265ce2d679ab403
# Remove this line to create a well-formed Fossil manifest. # Remove this line to create a well-formed Fossil manifest.

View File

@ -1 +1 @@
8baf8c10aecb261751f2b154356ab224b79d07230929ec9f123791278e601bba 5124481663eb8e74a9f861be98adb7075ea911fcff0216d98c658e955acadf14