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

Many more math functions. Semantics follows PG wherever possible.

FossilOrigin-Name: 6b93627b5d9819abf179a3e4a82e7afe17cbcafdabbd5f058de9ed114c9d477f
This commit is contained in:
drh
2020-12-07 21:13:06 +00:00
parent f6e904bd92
commit 63f8f98a63
4 changed files with 386 additions and 34 deletions

View File

@ -1,5 +1,5 @@
C Begin\sadding\snew\sSQL\sfunctions\sthat\sdepend\son\s-lm:\s\sceil(),\sceiling(),\nfloor(),\sln(),\slog(),\sand\slog10()\sso\sfar.\s\sMore\sto\sfollow.
D 2020-12-07T17:15:32.150
C Many\smore\smath\sfunctions.\s\sSemantics\sfollows\sPG\swherever\spossible.
D 2020-12-07T21:13:06.475
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@ -495,7 +495,7 @@ F src/delete.c 927cf8f900583e79aca8f1a321979e0a8f053babd9a690b44b38f79de2cc09fe
F src/expr.c 0d196ed5a2ebf96be7e8df88add4fabfad0dce16c0fed81a4b8f6a26e259797f
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
F src/fkey.c 83372403298e6a7dd989a47aaacdbaa5b4307b5199dbd56e07d4896066b3de72
F src/func.c d3113a23625daeb54331752421442af772abd851123550459dec96fedbe068e7
F src/func.c 7c3a41213179cce249d46283fc2237bc3424a041343866dbdb31914fed0edddc
F src/global.c ed55af196a9b66e198aaeda3f5454c3aa7d7d050c6c938181fd044b70d180a81
F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19
F src/hash.h 9d56a9079d523b648774c1784b74b89bd93fac7b365210157482e4319a468f38
@ -1026,7 +1026,7 @@ F test/func3.test 2bb0f31ab7baaed690b962a88544d7be6b34fa389364bc36a44e441ed3e3f1
F test/func4.test 2285fb5792d593fef442358763f0fd9de806eda47dbc7a5934df57ffdc484c31
F test/func5.test 863e6d1bd0013d09c17236f8a13ea34008dd857d87d85a13a673960e4c25d82a
F test/func6.test 90e42b64c4f9fb6f04f44cb8a1da586c8542502e926b19c76504fe74ff2a9b7c
F test/func7.test 7414f1ffb7aba86b6bcfdf0c3739a4e4717026ff583acd8b43ab21189300bcdc
F test/func7.test bb05a77daedf0e3f8764f323a49bc3b8d98f280a0bc6a370387117f4596bde05
F test/fuzz-oss1.test e58330d01cbbd8215ee636b17a03fe220b37dbfa
F test/fuzz.test 96083052bf5765e4518c1ba686ce2bab785670d1
F test/fuzz2.test 76dc35b32b6d6f965259508508abce75a6c4d7e1
@ -1888,7 +1888,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P 1db7c751912beb57a697ac8e85b9c29e30da7b6c89207e9828bf08e56c58242f
R 6662031cc76e6cb57f52d5a4ee0696ea
P 4db5f2f7875f6df78630a7816fc018141a6eee2e295b44fc7627eb66d07881ea
R 5f3694d6742f321a9a8686c5ca8182de
U drh
Z 99632da1aa8e30b2d9d751e33b863567
Z 1fdfc343d2601875f5f91cade0f6a5bf

View File

@ -1 +1 @@
4db5f2f7875f6df78630a7816fc018141a6eee2e295b44fc7627eb66d07881ea
6b93627b5d9819abf179a3e4a82e7afe17cbcafdabbd5f058de9ed114c9d477f

View File

@ -1904,6 +1904,18 @@ int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){
return 1;
}
/* Mathematical Constants */
#ifndef M_PI
# define M_PI 3.141592653589793238462643383279502884
#endif
#ifndef M_LN10
# define M_LN10 2.302585092994045684017991454684364208
#endif
#ifndef M_LN2
# define M_LN2 0.693147180559945309417232121458176568
#endif
/* Extra math functions that require linking with -lm
*/
#ifdef SQLITE_ENABLE_MATH_FUNCTIONS
@ -1923,17 +1935,19 @@ static void ceilingFunc(
sqlite3_value **argv
){
assert( argc==1 );
switch( sqlite3_value_type(argv[0]) ){
case SQLITE_INTEGER:
switch( sqlite3_value_numeric_type(argv[0]) ){
case SQLITE_INTEGER: {
sqlite3_result_int64(context, sqlite3_value_int64(argv[0]));
break;
case SQLITE_NULL:
break;
default: {
}
case SQLITE_FLOAT: {
double (*x)(double) = (double(*)(double))sqlite3_user_data(context);
sqlite3_result_double(context, x(sqlite3_value_double(argv[0])));
break;
}
default: {
break;
}
}
}
@ -1941,38 +1955,142 @@ static void ceilingFunc(
** Implementation of SQL functions:
**
** ln(X) - natural logarithm
** log(X) - log base 10
** log10(X) - log base 10
** log(X,Y) - log base Y
** log(X) - log X base 10
** log10(X) - log X base 10
** log(B,X) - log X base B
*/
static void logFunc(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
double x, y, ans;
double x, b, ans;
assert( argc==1 || argc==2 );
if( sqlite3_value_type(argv[0])==SQLITE_NULL
|| (x = sqlite3_value_double(argv[0]))<0.0
){
return; /* Return NULL for a domain error */
switch( sqlite3_value_numeric_type(argv[0]) ){
case SQLITE_INTEGER:
case SQLITE_FLOAT:
x = sqlite3_value_double(argv[0]);
if( x<0.0 ) return;
break;
default:
return;
}
ans = log(x);
if( argc==2 ){
if( sqlite3_value_type(argv[1])==SQLITE_NULL
|| (y = sqlite3_value_double(argv[1]))<0.0
){
return; /* Return NULL for a domain error */
switch( sqlite3_value_numeric_type(argv[0]) ){
case SQLITE_INTEGER:
case SQLITE_FLOAT:
b = x;
x = sqlite3_value_double(argv[1]);
if( x<0.0 ) return;
break;
default:
return;
}
ans /= log(y);
}else if( sqlite3_user_data(context)!=0 ){
ans = log(x)/log(b);
}else{
ans = log(x);
switch( SQLITE_PTR_TO_INT(sqlite3_user_data(context)) ){
case 1:
/* Convert from natural logarithm to log base 10 */
ans *= 0.43429448190325178672;
ans *= 1.0/M_LN10;
break;
case 2:
/* Convert from natural logarithm to log base 2 */
ans *= 1.0/M_LN2;
break;
default:
break;
}
}
sqlite3_result_double(context, ans);
}
/*
** Functions to converts degrees to radians and radians to degrees.
*/
static double degToRad(double x){ return x*(M_PI/180.0); }
static double radToDeg(double x){ return x*(180.0/M_PI); }
/*
** Implementation of 1-argument SQL math functions:
**
** exp(X) - Compute e to the X-th power
*/
static void math1Func(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
assert( argc==2 );
int type0;
double v0, ans;
double (*x)(double);
type0 = sqlite3_value_numeric_type(argv[0]);
if( type0!=SQLITE_INTEGER && type0!=SQLITE_FLOAT ) return;
v0 = sqlite3_value_double(argv[0]);
x = (double(*)(double))sqlite3_user_data(context);
ans = x(v0);
sqlite3_result_double(context, ans);
}
/*
** Implementation of 2-argument SQL math functions:
**
** power(X,Y) - Compute X to the Y-th power
*/
static void math2Func(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
assert( argc==2 );
int type0, type1;
double v0, v1, ans;
double (*x)(double,double);
type0 = sqlite3_value_numeric_type(argv[0]);
if( type0!=SQLITE_INTEGER && type0!=SQLITE_FLOAT ) return;
type1 = sqlite3_value_numeric_type(argv[1]);
if( type1!=SQLITE_INTEGER && type1!=SQLITE_FLOAT ) return;
v0 = sqlite3_value_double(argv[0]);
v1 = sqlite3_value_double(argv[1]);
x = (double(*)(double,double))sqlite3_user_data(context);
ans = x(v0, v1);
sqlite3_result_double(context, ans);
}
/*
** Implementation of 2-argument SQL math functions:
**
** power(X,Y) - Compute X to the Y-th power
*/
static void piFunc(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
assert( argc==0 );
sqlite3_result_double(context, M_PI);
}
#endif /* SQLITE_ENABLE_MATH_FUNCTIONS */
/*
** Implementation of sign(X) function.
*/
static void signFunc(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
assert( argc==1 );
int type0;
double x;
type0 = sqlite3_value_numeric_type(argv[0]);
if( type0!=SQLITE_INTEGER && type0!=SQLITE_FLOAT ) return;
x = sqlite3_value_double(argv[0]);
sqlite3_result_int(context, x<0.0 ? -1 : x>0.0 ? +1 : 0);
}
/*
** All of the FuncDef structures in the aBuiltinFunc[] array above
** to the global function hash table. This occurs at start-time (as
@ -2091,17 +2209,41 @@ void sqlite3RegisterBuiltinFunctions(void){
#endif
FUNCTION(coalesce, 1, 0, 0, 0 ),
FUNCTION(coalesce, 0, 0, 0, 0 ),
INLINE_FUNC(coalesce, -1, INLINEFUNC_coalesce, 0 ),
INLINE_FUNC(iif, 3, INLINEFUNC_iif, 0 ),
#ifdef SQLITE_ENABLE_MATH_FUNCTIONS
MFUNCTION(ceil, 1, ceil, ceilingFunc ),
MFUNCTION(ceiling, 1, ceil, ceilingFunc ),
MFUNCTION(floor, 1, floor, ceilingFunc ),
MFUNCTION(trunc, 1, trunc, ceilingFunc ),
FUNCTION(ln, 1, 0, 0, logFunc ),
FUNCTION(log, 1, 1, 0, logFunc ),
FUNCTION(log10, 1, 1, 0, logFunc ),
FUNCTION(log2, 1, 2, 0, logFunc ),
FUNCTION(log, 2, 0, 0, logFunc ),
MFUNCTION(exp, 1, exp, math1Func ),
MFUNCTION(pow, 2, pow, math2Func ),
MFUNCTION(power, 2, pow, math2Func ),
MFUNCTION(mod, 2, fmod, math2Func ),
MFUNCTION(acos, 1, acos, math1Func ),
MFUNCTION(asin, 1, asin, math1Func ),
MFUNCTION(atan, 1, atan, math1Func ),
MFUNCTION(atan2, 2, atan2, math2Func ),
MFUNCTION(cos, 1, cos, math1Func ),
MFUNCTION(sin, 1, sin, math1Func ),
MFUNCTION(tan, 1, tan, math1Func ),
MFUNCTION(cosh, 1, cosh, math1Func ),
MFUNCTION(sinh, 1, sinh, math1Func ),
MFUNCTION(tanh, 1, tanh, math1Func ),
MFUNCTION(acosh, 1, acosh, math1Func ),
MFUNCTION(asinh, 1, asinh, math1Func ),
MFUNCTION(atanh, 1, atanh, math1Func ),
MFUNCTION(sqrt, 1, sqrt, math1Func ),
MFUNCTION(radians, 1, degToRad, math1Func ),
MFUNCTION(degrees, 1, radToDeg, math1Func ),
FUNCTION(pi, 0, 0, 0, piFunc ),
#endif /* SQLITE_ENABLE_MATH_FUNCTIONS */
FUNCTION(sign, 1, 0, 0, signFunc ),
INLINE_FUNC(coalesce, -1, INLINEFUNC_coalesce, 0 ),
INLINE_FUNC(iif, 3, INLINEFUNC_iif, 0 ),
};
#ifndef SQLITE_OMIT_ALTERTABLE
sqlite3AlterFunctions();

View File

@ -25,11 +25,221 @@ do_execsql_test func7-110 {
SELECT quote(ceil(NULL)), ceil('-99.99');
} {NULL -99.0}
do_execsql_test func7-200 {
SELECT round(ln(5),2), log(100.0), log(100), log('256',2);
SELECT round(ln(5),2), log(100.0), log(100), log(2,'256');
} {1.61 2.0 2.0 8.0}
do_execsql_test func7-210 {
SELECT ln(-5), log(100.0,-5);
SELECT ln(-5), log(-5,100.0);
} {{} {}}
# Test cases derived from PostgreSQL documentation
#
do_execsql_test func7-pg-100 {
SELECT abs(-17.4)
} {17.4}
do_execsql_test func7-pg-110 {
SELECT ceil(42.2)
} {43.0}
do_execsql_test func7-pg-120 {
SELECT ceil(-42.2)
} {-42.0}
do_execsql_test func7-pg-130 {
SELECT round(exp(1.0),7)
} {2.7182818}
do_execsql_test func7-pg-140 {
SELECT floor(42.8)
} {42.0}
do_execsql_test func7-pg-150 {
SELECT floor(-42.8)
} {-43.0}
do_execsql_test func7-pg-160 {
SELECT round(ln(2.0),7)
} {0.6931472}
do_execsql_test func7-pg-170 {
SELECT log(100.0)
} {2.0}
do_execsql_test func7-pg-180 {
SELECT log10(1000.0)
} {3.0}
do_execsql_test func7-pg-190 {
SELECT log(2.0, 64.0)
} {6.0}
do_execsql_test func7-pg-200 {
SELECT mod(9,4);
} {1.0}
do_execsql_test func7-pg-210 {
SELECT round(pi(),7);
} {3.1415927}
do_execsql_test func7-pg-220 {
SELECT power(9,3);
} {729.0}
do_execsql_test func7-pg-230 {
SELECT round(radians(45.0),7);
} {0.7853982}
do_execsql_test func7-pg-240 {
SELECT round(42.4);
} {42.0}
do_execsql_test func7-pg-250 {
SELECT round(42.4382,2);
} {42.44}
do_execsql_test func7-pg-260 {
SELECT sign(-8.4);
} {-1}
do_execsql_test func7-pg-270 {
SELECT round( sqrt(2), 7);
} {1.4142136}
do_execsql_test func7-pg-280 {
SELECT trunc(42.8), trunc(-42.8);
} {42.0 -42.0}
do_execsql_test func7-pg-300 {
SELECT acos(1);
} {0.0}
do_execsql_test func7-pg-301 {
SELECT degrees(acos(0.5));
} {60.0}
do_execsql_test func7-pg-310 {
SELECT round( asin(1), 7);
} {1.5707963}
do_execsql_test func7-pg-311 {
SELECT degrees( asin(0.5) );
} {30.0}
do_execsql_test func7-pg-320 {
SELECT round( atan(1), 7);
} {0.7853982}
do_execsql_test func7-pg-321 {
SELECT degrees( atan(1) );
} {45.0}
do_execsql_test func7-pg-330 {
SELECT round( atan2(1,0), 7);
} {1.5707963}
do_execsql_test func7-pg-331 {
SELECT degrees( atan2(1,0) );
} {90.0}
do_execsql_test func7-pg-400 {
SELECT cos(0);
} {1.0}
do_execsql_test func7-pg-401 {
SELECT cos( radians(60.0) );
} {0.5}
do_execsql_test func7-pg-400 {
SELECT cos(0);
} {1.0}
do_execsql_test func7-pg-410 {
SELECT round( sin(1), 7);
} {0.841471}
do_execsql_test func7-pg-411 {
SELECT sin( radians(30) );
} {0.5}
do_execsql_test func7-pg-420 {
SELECT round( tan(1), 7);
} {1.5574077}
do_execsql_test func7-pg-421 {
SELECT tan( radians(45) );
} {1.0}
do_execsql_test func7-pg-500 {
SELECT round( sinh(1), 7);
} {1.1752012}
do_execsql_test func7-pg-510 {
SELECT round( cosh(0), 7);
} {1.0}
do_execsql_test func7-pg-520 {
SELECT round( tanh(1), 7);
} {0.7615942}
do_execsql_test func7-pg-530 {
SELECT round( asinh(1), 7);
} {0.8813736}
do_execsql_test func7-pg-540 {
SELECT round( acosh(1), 7);
} {0.0}
do_execsql_test func7-pg-550 {
SELECT round( atanh(0.5), 7);
} {0.5493061}
# Test cases derived from MySQL documentation
#
do_execsql_test func7-mysql-100 {
SELECT acos(1);
} {0.0}
do_execsql_test func7-mysql-110 {
SELECT acos(1.0001);
} {{}}
do_execsql_test func7-mysql-120 {
SELECT round( acos(0.0), 7);
} {1.5707963}
do_execsql_test func7-mysql-130 {
SELECT round( asin(0.2), 7);
} {0.2013579}
do_execsql_test func7-mysql-140 {
SELECT asin('foo');
} {{}} ;# Note: MySQL returns 0 here, not NULL.
# SQLite deliberately returns NULL.
# SQLServer and Oracle throw an error.
do_execsql_test func7-mysql-150 {
SELECT round( atan(2), 7), round( atan(-2), 7);
} {1.1071487 -1.1071487}
do_execsql_test func7-mysql-160 {
SELECT round( atan2(-2,2), 7), round( atan2(pi(),0), 7);
} {-0.7853982 1.5707963}
do_execsql_test func7-mysql-170 {
SELECT ceiling(1.23), ceiling(-1.23);
} {2.0 -1.0}
do_execsql_test func7-mysql-180 {
SELECT cos(pi());
} {-1.0}
do_execsql_test func7-mysql-190 {
SELECT degrees(pi()), degrees(pi()/2);
} {180.0 90.0}
do_execsql_test func7-mysql-190 {
SELECT round( exp(2), 7), round( exp(-2), 7), exp(0);
} {7.3890561 0.1353353 1.0}
do_execsql_test func7-mysql-200 {
SELECT floor(1.23), floor(-1.23);
} {1.0 -2.0}
do_execsql_test func7-mysql-210 {
SELECT round(ln(2),7), quote(ln(-2));
} {0.6931472 NULL}
#do_execsql_test func7-mysql-220 {
# SELECT round(log(2),7), log(-2);
#} {0.6931472 NULL}
# log() means natural logarithm in MySQL
do_execsql_test func7-mysql-230 {
SELECT log(2,65536), log(10,100), quote(log(1,100));
} {16.0 2.0 Inf}
do_execsql_test func7-mysql-240 {
SELECT log2(65536), quote(log2(-100));
} {16.0 NULL}
do_execsql_test func7-mysql-250 {
SELECT round(log10(2),7), log10(100), quote(log10(-100));
} {0.30103 2.0 NULL}
do_execsql_test func7-mysql-260 {
SELECT mod(234,10), 253%7, mod(29,9), 29%9;
} {4.0 1 2.0 2}
do_execsql_test func7-mysql-270 {
SELECT mod(34.5,3);
} {1.5}
do_execsql_test func7-mysql-280 {
SELECT pow(2,2), pow(2,-2);
} {4.0 0.25}
do_execsql_test func7-mysql-281 {
SELECT power(2,2), power(2,-2);
} {4.0 0.25}
do_execsql_test func7-mysql-290 {
SELECT round(radians(90),7);
} {1.5707963}
do_execsql_test func7-mysql-300 {
SELECT sign(-32), sign(0), sign(234);
} {-1 0 1}
do_execsql_test func7-mysql-310 {
SELECT sin(pi()) BETWEEN -1.0e-15 AND 1.0e-15;
} {1}
do_execsql_test func7-mysql-320 {
SELECT sqrt(4), round(sqrt(20),7), quote(sqrt(-16));
} {2.0 4.472136 NULL}
do_execsql_test func7-mysql-330 {
SELECT tan(pi()) BETWEEN -1.0e-15 AND 1.0e-15;
} {1}
do_execsql_test func7-mysql-331 {
SELECT round(tan(pi()+1),7);
} {1.5574077}
finish_test