-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
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
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
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
-4db5f2f7875f6df78630a7816fc018141a6eee2e295b44fc7627eb66d07881ea
\ No newline at end of file
+6b93627b5d9819abf179a3e4a82e7afe17cbcafdabbd5f058de9ed114c9d477f
\ No newline at end of file
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
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;
+ }
}
}
** 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(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 *= 1.0/M_LN10;
+ break;
+ case 2:
+ /* Convert from natural logarithm to log base 2 */
+ ans *= 1.0/M_LN2;
+ break;
+ default:
+ break;
}
- ans /= log(y);
- }else if( sqlite3_user_data(context)!=0 ){
- /* Convert from natural logarithm to log base 10 */
- ans *= 0.43429448190325178672;
}
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
#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();
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