2016-05-29 00:46:24 +00:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2014-present, Facebook, Inc.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* This source code is licensed under the BSD-style license found in the
|
|
|
|
* LICENSE file in the root directory of this source tree. An additional grant
|
|
|
|
* of patent rights can be found in the PATENTS file in the same directory.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <assert.h>
|
|
|
|
#include <errno.h>
|
2016-07-01 21:56:07 +00:00
|
|
|
|
|
|
|
#ifdef WIN32
|
|
|
|
#define _USE_MATH_DEFINES
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <cmath>
|
|
|
|
|
2016-05-29 00:46:24 +00:00
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include <functional>
|
|
|
|
|
|
|
|
#include <sqlite3.h>
|
|
|
|
|
|
|
|
namespace osquery {
|
|
|
|
|
|
|
|
using DoubleDoubleFunction = std::function<double(double)>;
|
|
|
|
|
2016-07-01 21:56:07 +00:00
|
|
|
// force use of the double(double) math functions
|
|
|
|
// without these lambda functions, MSVC will error
|
|
|
|
// because it fails to select an overload compatible with
|
|
|
|
// DoubleDoubleFunction
|
|
|
|
#define SIN_FUNC [](double a)->double { return sin(a); }
|
|
|
|
#define COS_FUNC [](double a)->double { return cos(a); }
|
|
|
|
#define TAN_FUNC [](double a)->double { return tanl(a); }
|
|
|
|
#define ASIN_FUNC [](double a)->double { return asin(a); }
|
|
|
|
#define ACOS_FUNC [](double a)->double { return acos(a); }
|
|
|
|
#define ATAN_FUNC [](double a)->double { return atan(a); }
|
|
|
|
#define LOG_FUNC [](double a)->double { return log(a); }
|
|
|
|
#define LOG10_FUNC [](double a)->double { return log10(a); }
|
|
|
|
#define SQRT_FUNC [](double a)->double { return sqrt(a); }
|
|
|
|
#define EXP_FUNC [](double a)->double { return expl(a); }
|
|
|
|
#define CEIL_FUNC [](double a)->double { return ceil(a); }
|
|
|
|
#define FLOOR_FUNC [](double a)->double { return floor(a); }
|
|
|
|
|
|
|
|
|
2016-05-29 00:46:24 +00:00
|
|
|
/**
|
|
|
|
* @brief Call a math function that takes a double and returns a double.
|
|
|
|
*/
|
|
|
|
static void callDoubleFunc(sqlite3_context *context,
|
|
|
|
int argc,
|
|
|
|
sqlite3_value **argv,
|
|
|
|
DoubleDoubleFunction f) {
|
|
|
|
double rVal = 0.0, val;
|
|
|
|
assert(argc == 1);
|
|
|
|
switch (sqlite3_value_type(argv[0])) {
|
|
|
|
case SQLITE_NULL:
|
|
|
|
sqlite3_result_null(context);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
rVal = sqlite3_value_double(argv[0]);
|
|
|
|
errno = 0;
|
|
|
|
val = f(rVal);
|
|
|
|
if (errno == 0) {
|
|
|
|
sqlite3_result_double(context, val);
|
|
|
|
} else {
|
|
|
|
sqlite3_result_error(context, strerror(errno), errno);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void sinFunc(sqlite3_context *context, int argc, sqlite3_value **argv) {
|
2016-07-01 21:56:07 +00:00
|
|
|
callDoubleFunc(context, argc, argv, SIN_FUNC);
|
2016-05-29 00:46:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void cosFunc(sqlite3_context *context, int argc, sqlite3_value **argv) {
|
2016-07-01 21:56:07 +00:00
|
|
|
callDoubleFunc(context, argc, argv, COS_FUNC);
|
2016-05-29 00:46:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void tanFunc(sqlite3_context *context, int argc, sqlite3_value **argv) {
|
2016-07-01 21:56:07 +00:00
|
|
|
callDoubleFunc(context, argc, argv, TAN_FUNC);
|
2016-05-29 00:46:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void asinFunc(sqlite3_context *context, int argc, sqlite3_value **argv) {
|
2016-07-01 21:56:07 +00:00
|
|
|
callDoubleFunc(context, argc, argv, ASIN_FUNC);
|
2016-05-29 00:46:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void acosFunc(sqlite3_context *context, int argc, sqlite3_value **argv) {
|
2016-07-01 21:56:07 +00:00
|
|
|
callDoubleFunc(context, argc, argv, ACOS_FUNC);
|
2016-05-29 00:46:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void atanFunc(sqlite3_context *context, int argc, sqlite3_value **argv) {
|
2016-07-01 21:56:07 +00:00
|
|
|
callDoubleFunc(context, argc, argv, ATAN_FUNC);
|
2016-05-29 00:46:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static double cot(double x) { return 1.0 / tan(x); }
|
|
|
|
|
|
|
|
static void cotFunc(sqlite3_context *context, int argc, sqlite3_value **argv) {
|
|
|
|
callDoubleFunc(context, argc, argv, cot);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void logFunc(sqlite3_context *context, int argc, sqlite3_value **argv) {
|
2016-07-01 21:56:07 +00:00
|
|
|
callDoubleFunc(context, argc, argv, LOG_FUNC);
|
2016-05-29 00:46:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void log10Func(sqlite3_context *context,
|
|
|
|
int argc,
|
|
|
|
sqlite3_value **argv) {
|
2016-07-01 21:56:07 +00:00
|
|
|
callDoubleFunc(context, argc, argv, LOG10_FUNC);
|
2016-05-29 00:46:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void sqrtFunc(sqlite3_context *context, int argc, sqlite3_value **argv) {
|
2016-07-01 21:56:07 +00:00
|
|
|
callDoubleFunc(context, argc, argv, SQRT_FUNC);
|
2016-05-29 00:46:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void expFunc(sqlite3_context *context, int argc, sqlite3_value **argv) {
|
2016-07-01 21:56:07 +00:00
|
|
|
callDoubleFunc(context, argc, argv, EXP_FUNC);
|
2016-05-29 00:46:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void powerFunc(sqlite3_context *context,
|
|
|
|
int argc,
|
|
|
|
sqlite3_value **argv) {
|
|
|
|
double r1 = 0.0;
|
|
|
|
double r2 = 0.0;
|
|
|
|
double val;
|
|
|
|
|
|
|
|
assert(argc == 2);
|
|
|
|
|
|
|
|
if (sqlite3_value_type(argv[0]) == SQLITE_NULL ||
|
|
|
|
sqlite3_value_type(argv[1]) == SQLITE_NULL) {
|
|
|
|
sqlite3_result_null(context);
|
|
|
|
} else {
|
|
|
|
r1 = sqlite3_value_double(argv[0]);
|
|
|
|
r2 = sqlite3_value_double(argv[1]);
|
|
|
|
errno = 0;
|
|
|
|
val = pow(r1, r2);
|
|
|
|
if (errno == 0) {
|
|
|
|
sqlite3_result_double(context, val);
|
|
|
|
} else {
|
|
|
|
sqlite3_result_error(context, strerror(errno), errno);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void callCastedDoubleFunc(sqlite3_context *context,
|
|
|
|
int argc,
|
|
|
|
sqlite3_value **argv,
|
|
|
|
DoubleDoubleFunction f) {
|
|
|
|
double rVal = 0.0;
|
|
|
|
assert(argc == 1);
|
|
|
|
switch (sqlite3_value_type(argv[0])) {
|
|
|
|
case SQLITE_INTEGER: {
|
|
|
|
int64_t iVal = sqlite3_value_int64(argv[0]);
|
|
|
|
sqlite3_result_int64(context, iVal);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case SQLITE_NULL:
|
|
|
|
sqlite3_result_null(context);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
rVal = sqlite3_value_double(argv[0]);
|
|
|
|
sqlite3_result_int64(context, (int64_t)f(rVal));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ceilFunc(sqlite3_context *context, int argc, sqlite3_value **argv) {
|
2016-07-01 21:56:07 +00:00
|
|
|
callCastedDoubleFunc(context, argc, argv, CEIL_FUNC);
|
2016-05-29 00:46:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void floorFunc(sqlite3_context *context,
|
|
|
|
int argc,
|
|
|
|
sqlite3_value **argv) {
|
2016-07-01 21:56:07 +00:00
|
|
|
callCastedDoubleFunc(context, argc, argv, FLOOR_FUNC);
|
2016-05-29 00:46:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Convert Degrees into Radians */
|
|
|
|
static double deg2rad(double x) { return x * M_PI / 180.0; }
|
|
|
|
|
|
|
|
/** Convert Radians into Degrees */
|
|
|
|
static double rad2deg(double x) { return 180.0 * x / M_PI; }
|
|
|
|
|
|
|
|
static void rad2degFunc(sqlite3_context *context,
|
|
|
|
int argc,
|
|
|
|
sqlite3_value **argv) {
|
|
|
|
callDoubleFunc(context, argc, argv, rad2deg);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void deg2radFunc(sqlite3_context *context,
|
|
|
|
int argc,
|
|
|
|
sqlite3_value **argv) {
|
|
|
|
callDoubleFunc(context, argc, argv, deg2rad);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void piFunc(sqlite3_context *context, int argc, sqlite3_value **argv) {
|
|
|
|
sqlite3_result_double(context, M_PI);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct FuncDef {
|
|
|
|
const char *zFunctionName;
|
|
|
|
int nArg;
|
|
|
|
void (*xFunc)(sqlite3_context *, int, sqlite3_value **);
|
|
|
|
};
|
|
|
|
|
|
|
|
void registerMathExtensions(sqlite3 *db) {
|
|
|
|
// This approach to adding non-standard Math functions was inspired by the
|
|
|
|
// somewhat deprecated/legacy work by Liam Healy from 2010 in the extension
|
|
|
|
// functions contribution.
|
|
|
|
static const struct FuncDef aFuncs[] = {
|
|
|
|
{"sqrt", 1, sqrtFunc}, {"acos", 1, acosFunc},
|
|
|
|
{"asin", 1, asinFunc}, {"atan", 1, atanFunc},
|
|
|
|
{"cos", 1, cosFunc}, {"sin", 1, sinFunc},
|
|
|
|
{"tan", 1, tanFunc}, {"cot", 1, cotFunc},
|
|
|
|
{"exp", 1, expFunc}, {"log", 1, logFunc},
|
|
|
|
{"log10", 1, log10Func}, {"power", 2, powerFunc},
|
|
|
|
{"ceil", 1, ceilFunc}, {"floor", 1, floorFunc},
|
|
|
|
{"degrees", 1, rad2degFunc}, {"radians", 1, deg2radFunc},
|
|
|
|
{"pi", 0, piFunc},
|
|
|
|
};
|
|
|
|
|
|
|
|
for (size_t i = 0; i < sizeof(aFuncs) / sizeof(struct FuncDef); i++) {
|
|
|
|
sqlite3_create_function(db, aFuncs[i].zFunctionName, aFuncs[i].nArg,
|
|
|
|
SQLITE_UTF8, nullptr, aFuncs[i].xFunc, nullptr,
|
|
|
|
nullptr);
|
|
|
|
}
|
|
|
|
}
|
2016-07-01 21:56:07 +00:00
|
|
|
}
|
|
|
|
|