mirror of
https://github.com/tstack/lnav
synced 2024-11-15 18:13:10 +00:00
2829 lines
70 KiB
C++
2829 lines
70 KiB
C++
/*
|
|
This library will provide common mathematical and string functions in
|
|
SQL queries using the operating system libraries or provided
|
|
definitions. It includes the following functions:
|
|
|
|
Math: acos, asin, atan, atn2, atan2, acosh, asinh, atanh, difference,
|
|
degrees, radians, cos, sin, tan, cot, cosh, sinh, tanh, coth, exp,
|
|
log, log10, power, sign, sqrt, square, ceil, floor, pi.
|
|
|
|
String: replicate, charindex, leftstr, rightstr, ltrim, rtrim, trim,
|
|
replace, reverse, proper, padl, padr, padc, strfilter.
|
|
|
|
Aggregate: stdev, variance, mode, median, lower_quartile,
|
|
upper_quartile.
|
|
|
|
The string functions ltrim, rtrim, trim, replace are included in
|
|
recent versions of SQLite and so by default do not build.
|
|
|
|
Compilation instructions:
|
|
Compile this C source file into a dynamic library as follows:
|
|
* Linux:
|
|
gcc -fPIC -lm -shared extension-functions.c -o libsqlitefunctions.so
|
|
* Mac OS X:
|
|
gcc -fno-common -dynamiclib extension-functions.c -o libsqlitefunctions.dylib
|
|
(You may need to add flags
|
|
-I /opt/local/include/ -L/opt/local/lib -lsqlite3
|
|
if your sqlite3 is installed from Mac ports, or
|
|
-I /sw/include/ -L/sw/lib -lsqlite3
|
|
if installed with Fink.)
|
|
* Windows:
|
|
1. Install MinGW (http://www.mingw.org/) and you will get the gcc
|
|
(gnu compiler collection)
|
|
2. add the path to your path variable (isn't done during the
|
|
installation!)
|
|
3. compile:
|
|
gcc -shared -I "path" -o libsqlitefunctions.so extension-functions.c
|
|
(path = path of sqlite3ext.h; i.e. C:\programs\sqlite)
|
|
|
|
Usage instructions for applications calling the sqlite3 API functions:
|
|
In your application, call sqlite3_enable_load_extension(db,1) to
|
|
allow loading external libraries. Then load the library libsqlitefunctions
|
|
using sqlite3_load_extension; the third argument should be 0.
|
|
See http://www.sqlite.org/cvstrac/wiki?p=LoadableExtensions.
|
|
Select statements may now use these functions, as in
|
|
SELECT cos(radians(inclination)) FROM satsum WHERE satnum = 25544;
|
|
|
|
Usage instructions for the sqlite3 program:
|
|
If the program is built so that loading extensions is permitted,
|
|
the following will work:
|
|
sqlite> SELECT load_extension('./libsqlitefunctions.so');
|
|
sqlite> select cos(radians(45));
|
|
0.707106781186548
|
|
Note: Loading extensions is by default prohibited as a
|
|
security measure; see "Security Considerations" in
|
|
http://www.sqlite.org/cvstrac/wiki?p=LoadableExtensions.
|
|
If the sqlite3 program and library are built this
|
|
way, you cannot use these functions from the program, you
|
|
must write your own program using the sqlite3 API, and call
|
|
sqlite3_enable_load_extension as described above, or else
|
|
rebuilt the sqlite3 program to allow loadable extensions.
|
|
|
|
Alterations:
|
|
The instructions are for Linux, Mac OS X, and Windows; users of other
|
|
OSes may need to modify this procedure. In particular, if your math
|
|
library lacks one or more of the needed trig or log functions, comment
|
|
out the appropriate HAVE_ #define at the top of file. If you do not
|
|
wish to make a loadable module, comment out the define for
|
|
COMPILE_SQLITE_EXTENSIONS_AS_LOADABLE_MODULE. If you are using a
|
|
version of SQLite without the trim functions and replace, comment out
|
|
the HAVE_TRIM #define.
|
|
|
|
Liam Healy
|
|
|
|
History:
|
|
2010-01-06 Correct check for argc in squareFunc, and add Windows
|
|
compilation instructions.
|
|
2009-06-24 Correct check for argc in properFunc.
|
|
2008-09-14 Add check that memory was actually allocated after
|
|
sqlite3_malloc or sqlite3StrDup, call sqlite3_result_error_nomem if
|
|
not. Thanks to Robert Simpson.
|
|
2008-06-13 Change to instructions to indicate use of the math library
|
|
and that program might work.
|
|
2007-10-01 Minor clarification to instructions.
|
|
2007-09-29 Compilation as loadable module is optional with
|
|
COMPILE_SQLITE_EXTENSIONS_AS_LOADABLE_MODULE.
|
|
2007-09-28 Use sqlite3_extension_init and macros
|
|
SQLITE_EXTENSION_INIT1, SQLITE_EXTENSION_INIT2, so that it works with
|
|
sqlite3_load_extension. Thanks to Eric Higashino and Joe Wilson.
|
|
New instructions for Mac compilation.
|
|
2007-09-17 With help from Joe Wilson and Nuno Luca, made use of
|
|
external interfaces so that compilation is no longer dependent on
|
|
SQLite source code. Merged source, header, and README into a single
|
|
file. Added casts so that Mac will compile without warnings (unsigned
|
|
and signed char).
|
|
2007-09-05 Included some definitions from sqlite 3.3.13 so that this
|
|
will continue to work in newer versions of sqlite. Completed
|
|
description of functions available.
|
|
2007-03-27 Revised description.
|
|
2007-03-23 Small cleanup and a bug fix on the code. This was mainly
|
|
letting errno flag errors encountered in the math library and checking
|
|
the result, rather than pre-checking. This fixes a bug in power that
|
|
would cause an error if any non-positive number was raised to any
|
|
power.
|
|
2007-02-07 posted by Mikey C to sqlite mailing list.
|
|
Original code 2006 June 05 by relicoder.
|
|
|
|
*/
|
|
|
|
//#include "config.h"
|
|
|
|
// #define COMPILE_SQLITE_EXTENSIONS_AS_LOADABLE_MODULE 1
|
|
#define HAVE_ACOSH 1
|
|
#define HAVE_ASINH 1
|
|
#define HAVE_ATANH 1
|
|
#define HAVE_SINH 1
|
|
#define HAVE_COSH 1
|
|
#define HAVE_TANH 1
|
|
#define HAVE_LOG10 1
|
|
#define HAVE_ISBLANK 1
|
|
#define SQLITE_SOUNDEX 1
|
|
#define HAVE_TRIM 1 /* LMH 2007-03-25 if sqlite has trim functions */
|
|
|
|
#define __STDC_FORMAT_MACROS
|
|
|
|
#ifdef COMPILE_SQLITE_EXTENSIONS_AS_LOADABLE_MODULE
|
|
# include "sqlite3ext.h"
|
|
SQLITE_EXTENSION_INIT1
|
|
#else
|
|
# include "sqlite3.h"
|
|
#endif
|
|
|
|
#include <ctype.h>
|
|
/* relicoder */
|
|
#include <assert.h>
|
|
#include <errno.h> /* LMH 2007-03-25 */
|
|
#include <math.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#ifndef _MAP_H_
|
|
# define _MAP_H_
|
|
|
|
# include <inttypes.h>
|
|
# include <stdint.h>
|
|
|
|
# include "sqlite-extension-func.hh"
|
|
|
|
/*
|
|
** Simple binary tree implementation to use in median, mode and quartile
|
|
*calculations
|
|
** Tree is not necessarily balanced. That would require something like red&black
|
|
*trees of AVL
|
|
*/
|
|
|
|
typedef int (*cmp_func)(const void*, const void*);
|
|
typedef void (*map_iterator)(void*, int64_t, void*);
|
|
|
|
typedef struct node {
|
|
struct node* l;
|
|
struct node* r;
|
|
void* data;
|
|
int64_t count;
|
|
} node;
|
|
|
|
typedef struct map {
|
|
node* base;
|
|
cmp_func cmp;
|
|
short free;
|
|
} map;
|
|
|
|
/*
|
|
** creates a map given a comparison function
|
|
*/
|
|
map map_make(cmp_func cmp);
|
|
|
|
/*
|
|
** inserts the element e into map m
|
|
*/
|
|
void map_insert(map* m, void* e);
|
|
|
|
/*
|
|
** executes function iter over all elements in the map, in key increasing order
|
|
*/
|
|
void map_iterate(map* m, map_iterator iter, void* p);
|
|
|
|
/*
|
|
** frees all memory used by a map
|
|
*/
|
|
void map_destroy(map* m);
|
|
|
|
/*
|
|
** compares 2 integers
|
|
** to use with map_make
|
|
*/
|
|
int int_cmp(const void* a, const void* b);
|
|
|
|
/*
|
|
** compares 2 doubles
|
|
** to use with map_make
|
|
*/
|
|
int double_cmp(const void* a, const void* b);
|
|
|
|
#endif /* _MAP_H_ */
|
|
|
|
typedef uint8_t u8;
|
|
typedef uint16_t u16;
|
|
typedef int64_t i64;
|
|
|
|
static char*
|
|
sqlite3StrDup(const char* z)
|
|
{
|
|
char* res = (char*) sqlite3_malloc(strlen(z) + 1);
|
|
return strcpy(res, z);
|
|
}
|
|
|
|
/*
|
|
** These are copied verbatim from fun.c so as to not have the names exported
|
|
*/
|
|
|
|
/* LMH from sqlite3 3.3.13 */
|
|
/*
|
|
** This table maps from the first byte of a UTF-8 character to the number
|
|
** of trailing bytes expected. A value '4' indicates that the table key
|
|
** is not a legal first byte for a UTF-8 character.
|
|
*/
|
|
static const u8 xtra_utf8_bytes[256] = {
|
|
/* 0xxxxxxx */
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
|
|
/* 10wwwwww */
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
|
|
/* 110yyyyy */
|
|
1,
|
|
1,
|
|
1,
|
|
1,
|
|
1,
|
|
1,
|
|
1,
|
|
1,
|
|
1,
|
|
1,
|
|
1,
|
|
1,
|
|
1,
|
|
1,
|
|
1,
|
|
1,
|
|
1,
|
|
1,
|
|
1,
|
|
1,
|
|
1,
|
|
1,
|
|
1,
|
|
1,
|
|
1,
|
|
1,
|
|
1,
|
|
1,
|
|
1,
|
|
1,
|
|
1,
|
|
1,
|
|
|
|
/* 1110zzzz */
|
|
2,
|
|
2,
|
|
2,
|
|
2,
|
|
2,
|
|
2,
|
|
2,
|
|
2,
|
|
2,
|
|
2,
|
|
2,
|
|
2,
|
|
2,
|
|
2,
|
|
2,
|
|
2,
|
|
|
|
/* 11110yyy */
|
|
3,
|
|
3,
|
|
3,
|
|
3,
|
|
3,
|
|
3,
|
|
3,
|
|
3,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
};
|
|
|
|
/*
|
|
** This table maps from the number of trailing bytes in a UTF-8 character
|
|
** to an integer constant that is effectively calculated for each character
|
|
** read by a naive implementation of a UTF-8 character reader. The code
|
|
** in the READ_UTF8 macro explains things best.
|
|
*/
|
|
static const int xtra_utf8_bits[] = {
|
|
0,
|
|
12416, /* (0xC0 << 6) + (0x80) */
|
|
925824, /* (0xE0 << 12) + (0x80 << 6) + (0x80) */
|
|
63447168 /* (0xF0 << 18) + (0x80 << 12) + (0x80 << 6) + 0x80 */
|
|
};
|
|
|
|
/*
|
|
** If a UTF-8 character contains N bytes extra bytes (N bytes follow
|
|
** the initial byte so that the total character length is N+1) then
|
|
** masking the character with utf8_mask[N] must produce a non-zero
|
|
** result. Otherwise, we have an (illegal) overlong encoding.
|
|
*/
|
|
static const unsigned long utf_mask[] = {
|
|
0x00000000,
|
|
0xffffff80,
|
|
0xfffff800,
|
|
0xffff0000,
|
|
};
|
|
|
|
/* LMH salvaged from sqlite3 3.3.13 source code src/utf.c */
|
|
#define READ_UTF8(zIn, c) \
|
|
{ \
|
|
int xtra; \
|
|
c = *(zIn)++; \
|
|
xtra = xtra_utf8_bytes[c]; \
|
|
switch (xtra) { \
|
|
case 4: \
|
|
c = (int) 0xFFFD; \
|
|
break; \
|
|
case 3: \
|
|
c = (c << 6) + *(zIn)++; \
|
|
case 2: \
|
|
c = (c << 6) + *(zIn)++; \
|
|
case 1: \
|
|
c = (c << 6) + *(zIn)++; \
|
|
c -= xtra_utf8_bits[xtra]; \
|
|
if ((utf_mask[xtra] & c) == 0 || (c & 0xFFFFF800) == 0xD800 \
|
|
|| (c & 0xFFFFFFFE) == 0xFFFE) \
|
|
{ \
|
|
c = 0xFFFD; \
|
|
} \
|
|
} \
|
|
}
|
|
|
|
static int
|
|
sqlite3ReadUtf8(const unsigned char* z)
|
|
{
|
|
int c;
|
|
READ_UTF8(z, c);
|
|
return c;
|
|
}
|
|
|
|
#define SKIP_UTF8(zIn) \
|
|
{ \
|
|
zIn += (xtra_utf8_bytes[*(u8*) zIn] + 1); \
|
|
}
|
|
|
|
/*
|
|
** pZ is a UTF-8 encoded unicode string. If nByte is less than zero,
|
|
** return the number of unicode characters in pZ up to (but not including)
|
|
** the first 0x00 byte. If nByte is not less than zero, return the
|
|
** number of unicode characters in the first nByte of pZ (or up to
|
|
** the first 0x00, whichever comes first).
|
|
*/
|
|
static int
|
|
sqlite3Utf8CharLen(const char* z, int nByte)
|
|
{
|
|
int r = 0;
|
|
const char* zTerm;
|
|
if (nByte >= 0) {
|
|
zTerm = &z[nByte];
|
|
} else {
|
|
zTerm = (const char*) (-1);
|
|
}
|
|
assert(z <= zTerm);
|
|
while (*z != 0 && z < zTerm) {
|
|
SKIP_UTF8(z);
|
|
r++;
|
|
}
|
|
return r;
|
|
}
|
|
|
|
/*
|
|
** X is a pointer to the first byte of a UTF-8 character. Increment
|
|
** X so that it points to the next character. This only works right
|
|
** if X points to a well-formed UTF-8 string.
|
|
*/
|
|
#define sqliteNextChar(X) \
|
|
while ((0xc0 & *++(X)) == 0x80) { \
|
|
}
|
|
#define sqliteCharVal(X) sqlite3ReadUtf8(X)
|
|
|
|
/*
|
|
** This is a macro that facilitates writting wrappers for math.h functions
|
|
** it creates code for a function to use in SQlite that gets one numeric input
|
|
** and returns a floating point value.
|
|
**
|
|
** Could have been implemented using pointers to functions but this way it's
|
|
*inline
|
|
** and thus more efficient. Lower * ranking though...
|
|
**
|
|
** Parameters:
|
|
** name: function name to de defined (eg: sinFunc)
|
|
** function: function defined in math.h to wrap (eg: sin)
|
|
** domain: boolean condition that CAN'T happen in terms of the input
|
|
*parameter rVal
|
|
** (eg: rval<0 for sqrt)
|
|
*/
|
|
/* LMH 2007-03-25 Changed to use errno and remove domain; no pre-checking for
|
|
* errors. */
|
|
#define GEN_MATH_WRAP_DOUBLE_1(name, function) \
|
|
static void name(sqlite3_context* context, int argc, sqlite3_value** argv) \
|
|
{ \
|
|
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 = function(rVal); \
|
|
if (errno == 0) { \
|
|
sqlite3_result_double(context, val); \
|
|
} else { \
|
|
sqlite3_result_error(context, strerror(errno), errno); \
|
|
} \
|
|
break; \
|
|
} \
|
|
} \
|
|
}
|
|
|
|
/*
|
|
** Example of GEN_MATH_WRAP_DOUBLE_1 usage
|
|
** this creates function sqrtFunc to wrap the math.h standard function
|
|
*sqrt(x)=x^0.5
|
|
*/
|
|
GEN_MATH_WRAP_DOUBLE_1(sqrtFunc, sqrt)
|
|
|
|
/* trignometric functions */
|
|
GEN_MATH_WRAP_DOUBLE_1(acosFunc, acos)
|
|
GEN_MATH_WRAP_DOUBLE_1(asinFunc, asin)
|
|
GEN_MATH_WRAP_DOUBLE_1(atanFunc, atan)
|
|
|
|
/*
|
|
** Many of systems don't have inverse hyperbolic trig functions so this will
|
|
*emulate
|
|
** them on those systems in terms of log and sqrt (formulas are too trivial to
|
|
*demand
|
|
** written proof here)
|
|
*/
|
|
|
|
#ifndef HAVE_ACOSH
|
|
static double
|
|
acosh(double x)
|
|
{
|
|
return log(x + sqrt(x * x - 1.0));
|
|
}
|
|
#endif
|
|
|
|
GEN_MATH_WRAP_DOUBLE_1(acoshFunc, acosh)
|
|
|
|
#ifndef HAVE_ASINH
|
|
static double
|
|
asinh(double x)
|
|
{
|
|
return log(x + sqrt(x * x + 1.0));
|
|
}
|
|
#endif
|
|
|
|
GEN_MATH_WRAP_DOUBLE_1(asinhFunc, asinh)
|
|
|
|
#ifndef HAVE_ATANH
|
|
static double
|
|
atanh(double x)
|
|
{
|
|
return (1.0 / 2.0) * log((1 + x) / (1 - x));
|
|
}
|
|
#endif
|
|
|
|
GEN_MATH_WRAP_DOUBLE_1(atanhFunc, atanh)
|
|
|
|
/*
|
|
** math.h doesn't require cot (cotangent) so it's defined here
|
|
*/
|
|
static double
|
|
cot(double x)
|
|
{
|
|
return 1.0 / tan(x);
|
|
}
|
|
|
|
GEN_MATH_WRAP_DOUBLE_1(sinFunc, sin)
|
|
GEN_MATH_WRAP_DOUBLE_1(cosFunc, cos)
|
|
GEN_MATH_WRAP_DOUBLE_1(tanFunc, tan)
|
|
GEN_MATH_WRAP_DOUBLE_1(cotFunc, cot)
|
|
|
|
static double
|
|
coth(double x)
|
|
{
|
|
return 1.0 / tanh(x);
|
|
}
|
|
|
|
/*
|
|
** Many systems don't have hyperbolic trigonometric functions so this will
|
|
*emulate
|
|
** them on those systems directly from the definition in terms of exp
|
|
*/
|
|
#ifndef HAVE_SINH
|
|
static double
|
|
sinh(double x)
|
|
{
|
|
return (exp(x) - exp(-x)) / 2.0;
|
|
}
|
|
#endif
|
|
|
|
GEN_MATH_WRAP_DOUBLE_1(sinhFunc, sinh)
|
|
|
|
#ifndef HAVE_COSH
|
|
static double
|
|
cosh(double x)
|
|
{
|
|
return (exp(x) + exp(-x)) / 2.0;
|
|
}
|
|
#endif
|
|
|
|
GEN_MATH_WRAP_DOUBLE_1(coshFunc, cosh)
|
|
|
|
#ifndef HAVE_TANH
|
|
static double
|
|
tanh(double x)
|
|
{
|
|
return sinh(x) / cosh(x);
|
|
}
|
|
#endif
|
|
|
|
GEN_MATH_WRAP_DOUBLE_1(tanhFunc, tanh)
|
|
|
|
GEN_MATH_WRAP_DOUBLE_1(cothFunc, coth)
|
|
|
|
/*
|
|
** Some systems lack log in base 10. This will emulate it
|
|
*/
|
|
|
|
#ifndef HAVE_LOG10
|
|
static double
|
|
log10(double x)
|
|
{
|
|
static double l10 = -1.0;
|
|
if (l10 < 0.0) {
|
|
l10 = log(10.0);
|
|
}
|
|
return log(x) / l10;
|
|
}
|
|
#endif
|
|
|
|
GEN_MATH_WRAP_DOUBLE_1(logFunc, log)
|
|
GEN_MATH_WRAP_DOUBLE_1(log10Func, log10)
|
|
GEN_MATH_WRAP_DOUBLE_1(expFunc, exp)
|
|
|
|
/*
|
|
** Fallback for systems where math.h doesn't define M_PI
|
|
*/
|
|
#undef M_PI
|
|
#ifndef M_PI
|
|
/*
|
|
** static double PI = acos(-1.0);
|
|
** #define M_PI (PI)
|
|
*/
|
|
# define M_PI 3.14159265358979323846
|
|
#endif
|
|
|
|
/* 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;
|
|
}
|
|
|
|
GEN_MATH_WRAP_DOUBLE_1(rad2degFunc, rad2deg)
|
|
GEN_MATH_WRAP_DOUBLE_1(deg2radFunc, deg2rad)
|
|
|
|
/* constant function that returns the value of PI=3.1415... */
|
|
static void
|
|
piFunc(sqlite3_context* context, int argc, sqlite3_value** argv)
|
|
{
|
|
sqlite3_result_double(context, M_PI);
|
|
}
|
|
|
|
/*
|
|
** Implements the sqrt function, it has the peculiarity of returning an integer
|
|
*when the
|
|
** the argument is an integer.
|
|
** Since SQLite isn't strongly typed (almost untyped actually) this is a bit
|
|
*pedantic
|
|
*/
|
|
static void
|
|
squareFunc(sqlite3_context* context, int argc, sqlite3_value** argv)
|
|
{
|
|
i64 iVal = 0;
|
|
double rVal = 0.0;
|
|
assert(argc == 1);
|
|
switch (sqlite3_value_type(argv[0])) {
|
|
case SQLITE_INTEGER: {
|
|
iVal = sqlite3_value_int64(argv[0]);
|
|
sqlite3_result_int64(context, iVal * iVal);
|
|
break;
|
|
}
|
|
case SQLITE_NULL: {
|
|
sqlite3_result_null(context);
|
|
break;
|
|
}
|
|
default: {
|
|
rVal = sqlite3_value_double(argv[0]);
|
|
sqlite3_result_double(context, rVal * rVal);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
** Wraps the pow math.h function
|
|
** When both the base and the exponent are integers the result should be integer
|
|
** (see sqrt just before this). Here the result is always double
|
|
*/
|
|
/* LMH 2007-03-25 Changed to use errno; no pre-checking for errors. Also
|
|
removes but that was present in the pre-checking that called
|
|
sqlite3_result_error on
|
|
a non-positive first argument, which is not always an error. */
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
** atan2 wrapper
|
|
*/
|
|
static void
|
|
atn2Func(sqlite3_context* context, int argc, sqlite3_value** argv)
|
|
{
|
|
double r1 = 0.0;
|
|
double r2 = 0.0;
|
|
|
|
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]);
|
|
sqlite3_result_double(context, atan2(r1, r2));
|
|
}
|
|
}
|
|
|
|
/*
|
|
** Implementation of the sign() function
|
|
** return one of 3 possibilities +1,0 or -1 when the argument is respectively
|
|
** positive, 0 or negative.
|
|
** When the argument is NULL the result is also NULL (completly conventional)
|
|
*/
|
|
static void
|
|
signFunc(sqlite3_context* context, int argc, sqlite3_value** argv)
|
|
{
|
|
double rVal = 0.0;
|
|
i64 iVal = 0;
|
|
assert(argc == 1);
|
|
switch (sqlite3_value_type(argv[0])) {
|
|
case SQLITE_INTEGER: {
|
|
iVal = sqlite3_value_int64(argv[0]);
|
|
iVal = (iVal > 0) ? 1 : (iVal < 0) ? -1 : 0;
|
|
sqlite3_result_int64(context, iVal);
|
|
break;
|
|
}
|
|
case SQLITE_NULL: {
|
|
sqlite3_result_null(context);
|
|
break;
|
|
}
|
|
default: {
|
|
/* 2nd change below. Line for abs was: if( rVal<0 ) rVal = rVal *
|
|
* -1.0; */
|
|
|
|
rVal = sqlite3_value_double(argv[0]);
|
|
rVal = (rVal > 0) ? 1 : (rVal < 0) ? -1 : 0;
|
|
sqlite3_result_double(context, rVal);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
** smallest integer value not less than argument
|
|
*/
|
|
static void
|
|
ceilFunc(sqlite3_context* context, int argc, sqlite3_value** argv)
|
|
{
|
|
double rVal = 0.0;
|
|
assert(argc == 1);
|
|
switch (sqlite3_value_type(argv[0])) {
|
|
case SQLITE_INTEGER: {
|
|
i64 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, (i64) ceil(rVal));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
** largest integer value not greater than argument
|
|
*/
|
|
static void
|
|
floorFunc(sqlite3_context* context, int argc, sqlite3_value** argv)
|
|
{
|
|
double rVal = 0.0;
|
|
assert(argc == 1);
|
|
switch (sqlite3_value_type(argv[0])) {
|
|
case SQLITE_INTEGER: {
|
|
i64 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, (i64) floor(rVal));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
** Given a string (s) in the first argument and an integer (n) in the second
|
|
*returns the
|
|
** string that constains s contatenated n times
|
|
*/
|
|
static void
|
|
replicateFunc(sqlite3_context* context, int argc, sqlite3_value** argv)
|
|
{
|
|
static const char* EMPTY = "";
|
|
unsigned char* z; /* result string */
|
|
i64 iCount; /* times to repeat */
|
|
i64 nLen; /* length of the input string (no multibyte considerations) */
|
|
i64 nTLen; /* length of the result string (no multibyte considerations) */
|
|
i64 i = 0;
|
|
|
|
if (argc != 2 || SQLITE_NULL == sqlite3_value_type(argv[0]))
|
|
return;
|
|
|
|
iCount = sqlite3_value_int64(argv[1]);
|
|
|
|
if (iCount < 0) {
|
|
sqlite3_result_error(context, "domain error", -1);
|
|
return;
|
|
}
|
|
|
|
if (iCount == 0) {
|
|
sqlite3_result_text(context, EMPTY, 0, SQLITE_STATIC);
|
|
return;
|
|
}
|
|
|
|
nLen = sqlite3_value_bytes(argv[0]);
|
|
nTLen = nLen * iCount;
|
|
z = (unsigned char*) sqlite3_malloc(nTLen + 1);
|
|
if (!z) {
|
|
sqlite3_result_error_nomem(context);
|
|
if (z)
|
|
sqlite3_free(z);
|
|
return;
|
|
}
|
|
auto zo = sqlite3_value_text(argv[0]);
|
|
|
|
for (i = 0; i < iCount; ++i) {
|
|
strcpy((char*) (z + i * nLen), (char*) zo);
|
|
}
|
|
|
|
sqlite3_result_text(context, (char*) z, -1, sqlite3_free);
|
|
}
|
|
|
|
/*
|
|
** Some systems (win32 among others) don't have an isblank function, this will
|
|
*emulate it.
|
|
** This function is not UFT-8 safe since it only analyses a byte character.
|
|
*/
|
|
#ifndef HAVE_ISBLANK
|
|
int
|
|
isblank(char c)
|
|
{
|
|
return (' ' == c || '\t' == c);
|
|
}
|
|
#endif
|
|
|
|
static void
|
|
properFunc(sqlite3_context* context, int argc, sqlite3_value** argv)
|
|
{
|
|
const unsigned char* z; /* input string */
|
|
unsigned char* zo; /* output string */
|
|
unsigned char* zt; /* iterator */
|
|
char r;
|
|
int c = 1;
|
|
|
|
assert(argc == 1);
|
|
if (SQLITE_NULL == sqlite3_value_type(argv[0])) {
|
|
sqlite3_result_null(context);
|
|
return;
|
|
}
|
|
|
|
z = sqlite3_value_text(argv[0]);
|
|
zo = (unsigned char*) sqlite3StrDup((char*) z);
|
|
if (!zo) {
|
|
sqlite3_result_error_nomem(context);
|
|
return;
|
|
}
|
|
zt = zo;
|
|
|
|
while ((r = *(z++)) != 0) {
|
|
if (isblank(r)) {
|
|
c = 1;
|
|
} else {
|
|
if (c == 1) {
|
|
r = toupper(r);
|
|
} else {
|
|
r = tolower(r);
|
|
}
|
|
c = 0;
|
|
}
|
|
*(zt++) = r;
|
|
}
|
|
*zt = '\0';
|
|
|
|
sqlite3_result_text(context, (char*) zo, -1, SQLITE_TRANSIENT);
|
|
sqlite3_free(zo);
|
|
}
|
|
|
|
/*
|
|
** given an input string (s) and an integer (n) adds spaces at the begining of s
|
|
** until it has a length of n characters.
|
|
** When s has a length >=n it's a NOP
|
|
** padl(NULL) = NULL
|
|
*/
|
|
static void
|
|
padlFunc(sqlite3_context* context, int argc, sqlite3_value** argv)
|
|
{
|
|
i64 ilen; /* length to pad to */
|
|
i64 zl; /* length of the input string (UTF-8 chars) */
|
|
int i = 0;
|
|
const char* zi; /* input string */
|
|
char* zo; /* output string */
|
|
char* zt;
|
|
|
|
assert(argc == 2);
|
|
|
|
if (sqlite3_value_type(argv[0]) == SQLITE_NULL) {
|
|
sqlite3_result_null(context);
|
|
} else {
|
|
zi = (char*) sqlite3_value_text(argv[0]);
|
|
ilen = sqlite3_value_int64(argv[1]);
|
|
/* check domain */
|
|
if (ilen < 0) {
|
|
sqlite3_result_error(context, "domain error", -1);
|
|
return;
|
|
}
|
|
zl = sqlite3Utf8CharLen(zi, -1);
|
|
if (zl >= ilen) {
|
|
/* string is longer than the requested pad length, return the same
|
|
* string (dup it) */
|
|
zo = sqlite3StrDup(zi);
|
|
if (!zo) {
|
|
sqlite3_result_error_nomem(context);
|
|
return;
|
|
}
|
|
sqlite3_result_text(context, zo, -1, SQLITE_TRANSIENT);
|
|
} else {
|
|
zo = (char*) sqlite3_malloc(strlen(zi) + ilen - zl + 1);
|
|
if (!zo) {
|
|
sqlite3_result_error_nomem(context);
|
|
return;
|
|
}
|
|
zt = zo;
|
|
for (i = 1; i + zl <= ilen; ++i) {
|
|
*(zt++) = ' ';
|
|
}
|
|
/* no need to take UTF-8 into consideration here */
|
|
strcpy(zt, zi);
|
|
}
|
|
sqlite3_result_text(context, zo, -1, SQLITE_TRANSIENT);
|
|
sqlite3_free(zo);
|
|
}
|
|
}
|
|
|
|
/*
|
|
** given an input string (s) and an integer (n) appends spaces at the end of s
|
|
** until it has a length of n characters.
|
|
** When s has a length >=n it's a NOP
|
|
** padl(NULL) = NULL
|
|
*/
|
|
static void
|
|
padrFunc(sqlite3_context* context, int argc, sqlite3_value** argv)
|
|
{
|
|
i64 ilen; /* length to pad to */
|
|
i64 zl; /* length of the input string (UTF-8 chars) */
|
|
i64 zll; /* length of the input string (bytes) */
|
|
int i = 0;
|
|
const char* zi; /* input string */
|
|
char* zo; /* output string */
|
|
char* zt;
|
|
|
|
assert(argc == 2);
|
|
|
|
if (sqlite3_value_type(argv[0]) == SQLITE_NULL) {
|
|
sqlite3_result_null(context);
|
|
} else {
|
|
zi = (char*) sqlite3_value_text(argv[0]);
|
|
ilen = sqlite3_value_int64(argv[1]);
|
|
/* check domain */
|
|
if (ilen < 0) {
|
|
sqlite3_result_error(context, "domain error", -1);
|
|
return;
|
|
}
|
|
zl = sqlite3Utf8CharLen(zi, -1);
|
|
if (zl >= ilen) {
|
|
/* string is longer than the requested pad length, return the same
|
|
* string (dup it) */
|
|
zo = sqlite3StrDup(zi);
|
|
if (!zo) {
|
|
sqlite3_result_error_nomem(context);
|
|
return;
|
|
}
|
|
sqlite3_result_text(context, zo, -1, SQLITE_TRANSIENT);
|
|
} else {
|
|
zll = strlen(zi);
|
|
zo = (char*) sqlite3_malloc(zll + ilen - zl + 1);
|
|
if (!zo) {
|
|
sqlite3_result_error_nomem(context);
|
|
return;
|
|
}
|
|
zt = strcpy(zo, zi) + zll;
|
|
for (i = 1; i + zl <= ilen; ++i) {
|
|
*(zt++) = ' ';
|
|
}
|
|
*zt = '\0';
|
|
}
|
|
sqlite3_result_text(context, zo, -1, SQLITE_TRANSIENT);
|
|
sqlite3_free(zo);
|
|
}
|
|
}
|
|
|
|
/*
|
|
** given an input string (s) and an integer (n) appends spaces at the end of s
|
|
** and adds spaces at the begining of s until it has a length of n characters.
|
|
** Tries to add has many characters at the left as at the right.
|
|
** When s has a length >=n it's a NOP
|
|
** padl(NULL) = NULL
|
|
*/
|
|
static void
|
|
padcFunc(sqlite3_context* context, int argc, sqlite3_value** argv)
|
|
{
|
|
i64 ilen; /* length to pad to */
|
|
i64 zl; /* length of the input string (UTF-8 chars) */
|
|
i64 zll; /* length of the input string (bytes) */
|
|
int i = 0;
|
|
const char* zi; /* input string */
|
|
char* zo; /* output string */
|
|
char* zt;
|
|
|
|
assert(argc == 2);
|
|
|
|
if (sqlite3_value_type(argv[0]) == SQLITE_NULL) {
|
|
sqlite3_result_null(context);
|
|
} else {
|
|
zi = (char*) sqlite3_value_text(argv[0]);
|
|
ilen = sqlite3_value_int64(argv[1]);
|
|
/* check domain */
|
|
if (ilen < 0) {
|
|
sqlite3_result_error(context, "domain error", -1);
|
|
return;
|
|
}
|
|
zl = sqlite3Utf8CharLen(zi, -1);
|
|
if (zl >= ilen) {
|
|
/* string is longer than the requested pad length, return the same
|
|
* string (dup it) */
|
|
zo = sqlite3StrDup(zi);
|
|
if (!zo) {
|
|
sqlite3_result_error_nomem(context);
|
|
return;
|
|
}
|
|
sqlite3_result_text(context, zo, -1, SQLITE_TRANSIENT);
|
|
} else {
|
|
zll = strlen(zi);
|
|
zo = (char*) sqlite3_malloc(zll + ilen - zl + 1);
|
|
if (!zo) {
|
|
sqlite3_result_error_nomem(context);
|
|
return;
|
|
}
|
|
zt = zo;
|
|
for (i = 1; 2 * i + zl <= ilen; ++i) {
|
|
*(zt++) = ' ';
|
|
}
|
|
strcpy(zt, zi);
|
|
zt += zll;
|
|
for (; i + zl <= ilen; ++i) {
|
|
*(zt++) = ' ';
|
|
}
|
|
*zt = '\0';
|
|
}
|
|
sqlite3_result_text(context, zo, -1, SQLITE_TRANSIENT);
|
|
sqlite3_free(zo);
|
|
}
|
|
}
|
|
|
|
/*
|
|
** given 2 string (s1,s2) returns the string s1 with the characters NOT in s2
|
|
*removed
|
|
** assumes strings are UTF-8 encoded
|
|
*/
|
|
static void
|
|
strfilterFunc(sqlite3_context* context, int argc, sqlite3_value** argv)
|
|
{
|
|
const char* zi1; /* first parameter string (searched string) */
|
|
const char* zi2; /* second parameter string (vcontains valid characters) */
|
|
const char* z1;
|
|
const char* z21;
|
|
const char* z22;
|
|
char* zo; /* output string */
|
|
char* zot;
|
|
int c1 = 0;
|
|
int c2 = 0;
|
|
|
|
assert(argc == 2);
|
|
|
|
if (sqlite3_value_type(argv[0]) == SQLITE_NULL
|
|
|| sqlite3_value_type(argv[1]) == SQLITE_NULL)
|
|
{
|
|
sqlite3_result_null(context);
|
|
} else {
|
|
zi1 = (char*) sqlite3_value_text(argv[0]);
|
|
zi2 = (char*) sqlite3_value_text(argv[1]);
|
|
/*
|
|
** maybe I could allocate less, but that would imply 2 passes, rather
|
|
*waste
|
|
** (possibly) some memory
|
|
*/
|
|
zo = (char*) sqlite3_malloc(strlen(zi1) + 1);
|
|
if (!zo) {
|
|
sqlite3_result_error_nomem(context);
|
|
return;
|
|
}
|
|
zot = zo;
|
|
z1 = zi1;
|
|
while ((c1 = sqliteCharVal((unsigned char*) z1)) != 0) {
|
|
z21 = zi2;
|
|
while ((c2 = sqliteCharVal((unsigned char*) z21)) != 0 && c2 != c1)
|
|
{
|
|
sqliteNextChar(z21);
|
|
}
|
|
if (c2 != 0) {
|
|
z22 = z21;
|
|
sqliteNextChar(z22);
|
|
strncpy(zot, z21, z22 - z21);
|
|
zot += z22 - z21;
|
|
}
|
|
sqliteNextChar(z1);
|
|
}
|
|
*zot = '\0';
|
|
|
|
sqlite3_result_text(context, zo, -1, SQLITE_TRANSIENT);
|
|
sqlite3_free(zo);
|
|
}
|
|
}
|
|
|
|
/*
|
|
** Given a string z1, retutns the (0 based) index of it's first occurence
|
|
** in z2 after the first s characters.
|
|
** Returns -1 when there isn't a match.
|
|
** updates p to point to the character where the match occured.
|
|
** This is an auxiliary function.
|
|
*/
|
|
static int
|
|
_substr(const char* z1, const char* z2, int s, const char** p)
|
|
{
|
|
int c = 0;
|
|
int rVal = -1;
|
|
const char* zt1;
|
|
const char* zt2;
|
|
int c1, c2;
|
|
|
|
if ('\0' == *z1) {
|
|
return -1;
|
|
}
|
|
|
|
while ((sqliteCharVal((unsigned char*) z2) != 0) && (c++) < s) {
|
|
sqliteNextChar(z2);
|
|
}
|
|
|
|
c = 0;
|
|
while ((sqliteCharVal((unsigned char*) z2)) != 0) {
|
|
zt1 = z1;
|
|
zt2 = z2;
|
|
|
|
do {
|
|
c1 = sqliteCharVal((unsigned char*) zt1);
|
|
c2 = sqliteCharVal((unsigned char*) zt2);
|
|
if (c1 == 0) {
|
|
break;
|
|
}
|
|
if (c2 == 0) {
|
|
break;
|
|
}
|
|
sqliteNextChar(zt1);
|
|
sqliteNextChar(zt2);
|
|
} while (c1 == c2 && c1 != 0 && c2 != 0);
|
|
|
|
if (c1 == 0) {
|
|
rVal = c;
|
|
break;
|
|
}
|
|
|
|
sqliteNextChar(z2);
|
|
++c;
|
|
}
|
|
if (p) {
|
|
*p = z2;
|
|
}
|
|
return rVal >= 0 ? rVal + s : rVal;
|
|
}
|
|
|
|
/*
|
|
** given 2 input strings (s1,s2) and an integer (n) searches from the nth
|
|
*character
|
|
** for the string s1. Returns the position where the match occured.
|
|
** Characters are counted from 1.
|
|
** 0 is returned when no match occurs.
|
|
*/
|
|
|
|
static void
|
|
charindexFunc(sqlite3_context* context, int argc, sqlite3_value** argv)
|
|
{
|
|
const u8* z1; /* s1 string */
|
|
u8* z2; /* s2 string */
|
|
int s = 0;
|
|
int rVal = 0;
|
|
|
|
assert(argc == 3 || argc == 2);
|
|
|
|
if (SQLITE_NULL == sqlite3_value_type(argv[0])
|
|
|| SQLITE_NULL == sqlite3_value_type(argv[1]))
|
|
{
|
|
sqlite3_result_null(context);
|
|
return;
|
|
}
|
|
|
|
z1 = sqlite3_value_text(argv[0]);
|
|
if (z1 == 0)
|
|
return;
|
|
z2 = (u8*) sqlite3_value_text(argv[1]);
|
|
if (argc == 3) {
|
|
s = sqlite3_value_int(argv[2]) - 1;
|
|
if (s < 0) {
|
|
s = 0;
|
|
}
|
|
} else {
|
|
s = 0;
|
|
}
|
|
|
|
rVal = _substr((char*) z1, (char*) z2, s, NULL);
|
|
sqlite3_result_int(context, rVal + 1);
|
|
}
|
|
|
|
/*
|
|
** given a string (s) and an integer (n) returns the n leftmost (UTF-8)
|
|
*characters
|
|
** if the string has a length<=n or is NULL this function is NOP
|
|
*/
|
|
static void
|
|
leftFunc(sqlite3_context* context, int argc, sqlite3_value** argv)
|
|
{
|
|
int c = 0;
|
|
int cc = 0;
|
|
int l = 0;
|
|
const unsigned char* z; /* input string */
|
|
const unsigned char* zt;
|
|
unsigned char* rz; /* output string */
|
|
|
|
assert(argc == 2);
|
|
|
|
if (SQLITE_NULL == sqlite3_value_type(argv[0])
|
|
|| SQLITE_NULL == sqlite3_value_type(argv[1]))
|
|
{
|
|
sqlite3_result_null(context);
|
|
return;
|
|
}
|
|
|
|
z = sqlite3_value_text(argv[0]);
|
|
l = sqlite3_value_int(argv[1]);
|
|
zt = z;
|
|
|
|
while (sqliteCharVal(zt) && c++ < l)
|
|
sqliteNextChar(zt);
|
|
|
|
cc = zt - z;
|
|
|
|
rz = (unsigned char*) sqlite3_malloc(zt - z + 1);
|
|
if (!rz) {
|
|
sqlite3_result_error_nomem(context);
|
|
return;
|
|
}
|
|
strncpy((char*) rz, (char*) z, zt - z);
|
|
*(rz + cc) = '\0';
|
|
sqlite3_result_text(context, (char*) rz, -1, SQLITE_TRANSIENT);
|
|
sqlite3_free(rz);
|
|
}
|
|
|
|
/*
|
|
** given a string (s) and an integer (n) returns the n rightmost (UTF-8)
|
|
*characters
|
|
** if the string has a length<=n or is NULL this function is NOP
|
|
*/
|
|
static void
|
|
rightFunc(sqlite3_context* context, int argc, sqlite3_value** argv)
|
|
{
|
|
int l = 0;
|
|
int c = 0;
|
|
int cc = 0;
|
|
const char* z;
|
|
const char* zt;
|
|
const char* ze;
|
|
char* rz;
|
|
|
|
assert(argc == 2);
|
|
|
|
if (SQLITE_NULL == sqlite3_value_type(argv[0])
|
|
|| SQLITE_NULL == sqlite3_value_type(argv[1]))
|
|
{
|
|
sqlite3_result_null(context);
|
|
return;
|
|
}
|
|
|
|
z = (char*) sqlite3_value_text(argv[0]);
|
|
l = sqlite3_value_int(argv[1]);
|
|
zt = z;
|
|
|
|
while (sqliteCharVal((unsigned char*) zt) != 0) {
|
|
sqliteNextChar(zt);
|
|
++c;
|
|
}
|
|
|
|
ze = zt;
|
|
zt = z;
|
|
|
|
cc = c - l;
|
|
if (cc < 0)
|
|
cc = 0;
|
|
|
|
while (cc-- > 0) {
|
|
sqliteNextChar(zt);
|
|
}
|
|
|
|
rz = (char*) sqlite3_malloc(ze - zt + 1);
|
|
if (!rz) {
|
|
sqlite3_result_error_nomem(context);
|
|
return;
|
|
}
|
|
strcpy((char*) rz, (char*) (zt));
|
|
sqlite3_result_text(context, (char*) rz, -1, SQLITE_TRANSIENT);
|
|
sqlite3_free(rz);
|
|
}
|
|
|
|
#ifndef HAVE_TRIM
|
|
/*
|
|
** removes the whitespaces at the begining of a string.
|
|
*/
|
|
const char*
|
|
ltrim(const char* s)
|
|
{
|
|
while (*s == ' ')
|
|
++s;
|
|
return s;
|
|
}
|
|
|
|
/*
|
|
** removes the whitespaces at the end of a string.
|
|
** !mutates the input string!
|
|
*/
|
|
void
|
|
rtrim(char* s)
|
|
{
|
|
char* ss = s + strlen(s) - 1;
|
|
while (ss >= s && *ss == ' ')
|
|
--ss;
|
|
*(ss + 1) = '\0';
|
|
}
|
|
|
|
/*
|
|
** Removes the whitespace at the begining of a string
|
|
*/
|
|
static void
|
|
ltrimFunc(sqlite3_context* context, int argc, sqlite3_value** argv)
|
|
{
|
|
const char* z;
|
|
|
|
assert(argc == 1);
|
|
|
|
if (SQLITE_NULL == sqlite3_value_type(argv[0])) {
|
|
sqlite3_result_null(context);
|
|
return;
|
|
}
|
|
z = sqlite3_value_text(argv[0]);
|
|
sqlite3_result_text(context, ltrim(z), -1, SQLITE_TRANSIENT);
|
|
}
|
|
|
|
/*
|
|
** Removes the whitespace at the end of a string
|
|
*/
|
|
static void
|
|
rtrimFunc(sqlite3_context* context, int argc, sqlite3_value** argv)
|
|
{
|
|
const char* z;
|
|
char* rz;
|
|
/* try not to change data in argv */
|
|
|
|
assert(argc == 1);
|
|
|
|
if (SQLITE_NULL == sqlite3_value_type(argv[0])) {
|
|
sqlite3_result_null(context);
|
|
return;
|
|
}
|
|
z = sqlite3_value_text(argv[0]);
|
|
rz = sqlite3StrDup(z);
|
|
rtrim(rz);
|
|
sqlite3_result_text(context, rz, -1, SQLITE_TRANSIENT);
|
|
sqlite3_free(rz);
|
|
}
|
|
|
|
/*
|
|
** Removes the whitespace at the begining and end of a string
|
|
*/
|
|
static void
|
|
trimFunc(sqlite3_context* context, int argc, sqlite3_value** argv)
|
|
{
|
|
const char* z;
|
|
char* rz;
|
|
/* try not to change data in argv */
|
|
|
|
assert(argc == 1);
|
|
|
|
if (SQLITE_NULL == sqlite3_value_type(argv[0])) {
|
|
sqlite3_result_null(context);
|
|
return;
|
|
}
|
|
z = sqlite3_value_text(argv[0]);
|
|
rz = sqlite3StrDup(z);
|
|
rtrim(rz);
|
|
sqlite3_result_text(context, ltrim(rz), -1, SQLITE_TRANSIENT);
|
|
sqlite3_free(rz);
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
** given a pointer to a string s1, the length of that string (l1), a new string
|
|
*(s2)
|
|
** and it's length (l2) appends s2 to s1.
|
|
** All lengths in bytes.
|
|
** This is just an auxiliary function
|
|
*/
|
|
// static void _append(char **s1, int l1, const char *s2, int l2){
|
|
// *s1 = realloc(*s1, (l1+l2+1)*sizeof(char));
|
|
// strncpy((*s1)+l1, s2, l2);
|
|
// *(*(s1)+l1+l2) = '\0';
|
|
// }
|
|
|
|
#ifndef HAVE_TRIM
|
|
|
|
/*
|
|
** given strings s, s1 and s2 replaces occurrences of s1 in s by s2
|
|
*/
|
|
static void
|
|
replaceFunc(sqlite3_context* context, int argc, sqlite3_value** argv)
|
|
{
|
|
const char* z1; /* string s (first parameter) */
|
|
const char* z2; /* string s1 (second parameter) string to look for */
|
|
const char* z3; /* string s2 (third parameter) string to replace occurrences
|
|
of s1 with */
|
|
int lz1;
|
|
int lz2;
|
|
int lz3;
|
|
int lzo = 0;
|
|
char* zo = 0;
|
|
int ret = 0;
|
|
const char* zt1;
|
|
const char* zt2;
|
|
|
|
assert(3 == argc);
|
|
|
|
if (SQLITE_NULL == sqlite3_value_type(argv[0])) {
|
|
sqlite3_result_null(context);
|
|
return;
|
|
}
|
|
|
|
z1 = sqlite3_value_text(argv[0]);
|
|
z2 = sqlite3_value_text(argv[1]);
|
|
z3 = sqlite3_value_text(argv[2]);
|
|
/* handle possible null values */
|
|
if (0 == z2) {
|
|
z2 = "";
|
|
}
|
|
if (0 == z3) {
|
|
z3 = "";
|
|
}
|
|
|
|
lz1 = strlen(z1);
|
|
lz2 = strlen(z2);
|
|
lz3 = strlen(z3);
|
|
|
|
# if 0
|
|
/* special case when z2 is empty (or null) nothing will be changed */
|
|
if( 0==lz2 ){
|
|
sqlite3_result_text(context, z1, -1, SQLITE_TRANSIENT);
|
|
return;
|
|
}
|
|
# endif
|
|
|
|
zt1 = z1;
|
|
zt2 = z1;
|
|
|
|
while (1) {
|
|
ret = _substr(z2, zt1, 0, &zt2);
|
|
|
|
if (ret < 0)
|
|
break;
|
|
|
|
_append(&zo, lzo, zt1, zt2 - zt1);
|
|
lzo += zt2 - zt1;
|
|
_append(&zo, lzo, z3, lz3);
|
|
lzo += lz3;
|
|
|
|
zt1 = zt2 + lz2;
|
|
}
|
|
_append(&zo, lzo, zt1, lz1 - (zt1 - z1));
|
|
sqlite3_result_text(context, zo, -1, SQLITE_TRANSIENT);
|
|
sqlite3_free(zo);
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
** given a string returns the same string but with the characters in reverse
|
|
*order
|
|
*/
|
|
static void
|
|
reverseFunc(sqlite3_context* context, int argc, sqlite3_value** argv)
|
|
{
|
|
const char* z;
|
|
const char* zt;
|
|
char* rz;
|
|
char* rzt;
|
|
int l = 0;
|
|
int i = 0;
|
|
|
|
assert(1 == argc);
|
|
|
|
if (SQLITE_NULL == sqlite3_value_type(argv[0])) {
|
|
sqlite3_result_null(context);
|
|
return;
|
|
}
|
|
z = (char*) sqlite3_value_text(argv[0]);
|
|
l = strlen(z);
|
|
rz = (char*) sqlite3_malloc(l + 1);
|
|
if (!rz) {
|
|
sqlite3_result_error_nomem(context);
|
|
return;
|
|
}
|
|
rzt = rz + l;
|
|
*(rzt--) = '\0';
|
|
|
|
zt = z;
|
|
while (sqliteCharVal((unsigned char*) zt) != 0) {
|
|
z = zt;
|
|
sqliteNextChar(zt);
|
|
for (i = 1; zt - i >= z; ++i) {
|
|
*(rzt--) = *(zt - i);
|
|
}
|
|
}
|
|
|
|
sqlite3_result_text(context, rz, -1, SQLITE_TRANSIENT);
|
|
sqlite3_free(rz);
|
|
}
|
|
|
|
/*
|
|
** An instance of the following structure holds the context of a
|
|
** stdev() or variance() aggregate computation.
|
|
** implementaion of
|
|
*http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Algorithm_II
|
|
** less prone to rounding errors
|
|
*/
|
|
typedef struct StdevCtx StdevCtx;
|
|
struct StdevCtx {
|
|
double rM;
|
|
double rS;
|
|
i64 cnt; /* number of elements */
|
|
};
|
|
|
|
/*
|
|
** An instance of the following structure holds the context of a
|
|
** mode() or median() aggregate computation.
|
|
** Depends on structures defined in map.c (see map & map)
|
|
** These aggregate functions only work for integers and floats although
|
|
** they could be made to work for strings. This is usually considered
|
|
*meaningless.
|
|
** Only usuall order (for median), no use of collation functions (would this
|
|
*even make sense?)
|
|
*/
|
|
typedef struct ModeCtx ModeCtx;
|
|
struct ModeCtx {
|
|
i64 riM; /* integer value found so far */
|
|
double rdM; /* double value found so far */
|
|
i64 cnt; /* number of elements so far */
|
|
double pcnt; /* number of elements smaller than a percentile */
|
|
i64 mcnt; /* maximum number of occurrences (for mode) */
|
|
i64 mn; /* number of occurrences (for mode and percentiles) */
|
|
i64 is_double; /* whether the computation is being done for doubles (>0) or
|
|
integers (=0) */
|
|
map* m; /* map structure used for the computation */
|
|
int done; /* whether the answer has been found */
|
|
};
|
|
|
|
/*
|
|
** called for each value received during a calculation of stdev or variance
|
|
*/
|
|
static void
|
|
varianceStep(sqlite3_context* context, int argc, sqlite3_value** argv)
|
|
{
|
|
StdevCtx* p;
|
|
|
|
double delta;
|
|
double x;
|
|
|
|
assert(argc == 1);
|
|
p = (StdevCtx*) sqlite3_aggregate_context(context, sizeof(*p));
|
|
/* only consider non-null values */
|
|
if (SQLITE_NULL != sqlite3_value_numeric_type(argv[0])) {
|
|
p->cnt++;
|
|
x = sqlite3_value_double(argv[0]);
|
|
delta = (x - p->rM);
|
|
p->rM += delta / p->cnt;
|
|
p->rS += delta * (x - p->rM);
|
|
}
|
|
}
|
|
|
|
/*
|
|
** called for each value received during a calculation of mode of median
|
|
*/
|
|
static void
|
|
modeStep(sqlite3_context* context, int argc, sqlite3_value** argv)
|
|
{
|
|
ModeCtx* p;
|
|
i64 xi = 0;
|
|
double xd = 0.0;
|
|
i64* iptr;
|
|
double* dptr;
|
|
int type;
|
|
|
|
assert(argc == 1);
|
|
type = sqlite3_value_numeric_type(argv[0]);
|
|
|
|
if (type == SQLITE_NULL)
|
|
return;
|
|
|
|
p = (ModeCtx*) sqlite3_aggregate_context(context, sizeof(*p));
|
|
|
|
if (0 == (p->m)) {
|
|
p->m = (map*) calloc(1, sizeof(map));
|
|
if (type == SQLITE_INTEGER) {
|
|
/* map will be used for integers */
|
|
*(p->m) = map_make(int_cmp);
|
|
p->is_double = 0;
|
|
} else {
|
|
p->is_double = 1;
|
|
/* map will be used for doubles */
|
|
*(p->m) = map_make(double_cmp);
|
|
}
|
|
}
|
|
|
|
++(p->cnt);
|
|
|
|
if (0 == p->is_double) {
|
|
xi = sqlite3_value_int64(argv[0]);
|
|
iptr = (i64*) calloc(1, sizeof(i64));
|
|
*iptr = xi;
|
|
map_insert(p->m, iptr);
|
|
} else {
|
|
xd = sqlite3_value_double(argv[0]);
|
|
dptr = (double*) calloc(1, sizeof(double));
|
|
*dptr = xd;
|
|
map_insert(p->m, dptr);
|
|
}
|
|
}
|
|
|
|
/*
|
|
** Auxiliary function that iterates all elements in a map and finds the mode
|
|
** (most frequent value)
|
|
*/
|
|
static void
|
|
modeIterate(void* e, i64 c, void* pp)
|
|
{
|
|
i64 ei;
|
|
double ed;
|
|
ModeCtx* p = (ModeCtx*) pp;
|
|
|
|
if (0 == p->is_double) {
|
|
ei = *(int*) (e);
|
|
|
|
if (p->mcnt == c) {
|
|
++p->mn;
|
|
} else if (p->mcnt < c) {
|
|
p->riM = ei;
|
|
p->mcnt = c;
|
|
p->mn = 1;
|
|
}
|
|
} else {
|
|
ed = *(double*) (e);
|
|
|
|
if (p->mcnt == c) {
|
|
++p->mn;
|
|
} else if (p->mcnt < c) {
|
|
p->rdM = ed;
|
|
p->mcnt = c;
|
|
p->mn = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
** Auxiliary function that iterates all elements in a map and finds the median
|
|
** (the value such that the number of elements smaller is equal the number of
|
|
** elements larger)
|
|
*/
|
|
static void
|
|
medianIterate(void* e, i64 c, void* pp)
|
|
{
|
|
i64 ei;
|
|
double ed;
|
|
double iL;
|
|
double iR;
|
|
int il;
|
|
int ir;
|
|
ModeCtx* p = (ModeCtx*) pp;
|
|
|
|
if (p->done > 0)
|
|
return;
|
|
|
|
iL = p->pcnt;
|
|
iR = p->cnt - p->pcnt;
|
|
il = p->mcnt + c;
|
|
ir = p->cnt - p->mcnt;
|
|
|
|
if (il >= iL) {
|
|
if (ir >= iR) {
|
|
++p->mn;
|
|
if (0 == p->is_double) {
|
|
ei = *(int*) (e);
|
|
p->riM += ei;
|
|
} else {
|
|
ed = *(double*) (e);
|
|
p->rdM += ed;
|
|
}
|
|
} else {
|
|
p->done = 1;
|
|
}
|
|
}
|
|
p->mcnt += c;
|
|
}
|
|
|
|
/*
|
|
** Returns the mode value
|
|
*/
|
|
static void
|
|
modeFinalize(sqlite3_context* context)
|
|
{
|
|
ModeCtx* p;
|
|
p = (ModeCtx*) sqlite3_aggregate_context(context, 0);
|
|
if (p && p->m) {
|
|
map_iterate(p->m, modeIterate, p);
|
|
map_destroy(p->m);
|
|
free(p->m);
|
|
|
|
if (1 == p->mn) {
|
|
if (0 == p->is_double)
|
|
sqlite3_result_int64(context, p->riM);
|
|
else
|
|
sqlite3_result_double(context, p->rdM);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
** auxiliary function for percentiles
|
|
*/
|
|
static void
|
|
_medianFinalize(sqlite3_context* context)
|
|
{
|
|
ModeCtx* p;
|
|
p = (ModeCtx*) sqlite3_aggregate_context(context, 0);
|
|
if (p && p->m) {
|
|
p->done = 0;
|
|
map_iterate(p->m, medianIterate, p);
|
|
map_destroy(p->m);
|
|
free(p->m);
|
|
|
|
if (0 == p->is_double)
|
|
if (1 == p->mn)
|
|
sqlite3_result_int64(context, p->riM);
|
|
else
|
|
sqlite3_result_double(context, p->riM * 1.0 / p->mn);
|
|
else
|
|
sqlite3_result_double(context, p->rdM / p->mn);
|
|
}
|
|
}
|
|
|
|
/*
|
|
** Returns the median value
|
|
*/
|
|
static void
|
|
medianFinalize(sqlite3_context* context)
|
|
{
|
|
ModeCtx* p;
|
|
p = (ModeCtx*) sqlite3_aggregate_context(context, 0);
|
|
if (p != 0) {
|
|
p->pcnt = (p->cnt) / 2.0;
|
|
_medianFinalize(context);
|
|
}
|
|
}
|
|
|
|
/*
|
|
** Returns the lower_quartile value
|
|
*/
|
|
static void
|
|
lower_quartileFinalize(sqlite3_context* context)
|
|
{
|
|
ModeCtx* p;
|
|
p = (ModeCtx*) sqlite3_aggregate_context(context, 0);
|
|
if (p != 0) {
|
|
p->pcnt = (p->cnt) / 4.0;
|
|
_medianFinalize(context);
|
|
}
|
|
}
|
|
|
|
/*
|
|
** Returns the upper_quartile value
|
|
*/
|
|
static void
|
|
upper_quartileFinalize(sqlite3_context* context)
|
|
{
|
|
ModeCtx* p;
|
|
p = (ModeCtx*) sqlite3_aggregate_context(context, 0);
|
|
if (p != 0) {
|
|
p->pcnt = (p->cnt) * 3 / 4.0;
|
|
_medianFinalize(context);
|
|
}
|
|
}
|
|
|
|
/*
|
|
** Returns the stdev value
|
|
*/
|
|
static void
|
|
stdevFinalize(sqlite3_context* context)
|
|
{
|
|
StdevCtx* p;
|
|
p = (StdevCtx*) sqlite3_aggregate_context(context, 0);
|
|
if (p && p->cnt > 1) {
|
|
sqlite3_result_double(context, sqrt(p->rS / (p->cnt - 1)));
|
|
} else {
|
|
sqlite3_result_double(context, 0.0);
|
|
}
|
|
}
|
|
|
|
/*
|
|
** Returns the variance value
|
|
*/
|
|
static void
|
|
varianceFinalize(sqlite3_context* context)
|
|
{
|
|
StdevCtx* p;
|
|
p = (StdevCtx*) sqlite3_aggregate_context(context, 0);
|
|
if (p && p->cnt > 1) {
|
|
sqlite3_result_double(context, p->rS / (p->cnt - 1));
|
|
} else {
|
|
sqlite3_result_double(context, 0.0);
|
|
}
|
|
}
|
|
|
|
#ifdef SQLITE_SOUNDEX
|
|
|
|
/* relicoder factored code */
|
|
/*
|
|
** Calculates the soundex value of a string
|
|
*/
|
|
|
|
static void
|
|
soundex(const u8* zIn, char* zResult)
|
|
{
|
|
int i, j;
|
|
static const unsigned char iCode[] = {
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
1, 2, 3, 0, 1, 2, 0, 0, 2, 2, 4, 5, 5, 0, 1, 2, 6, 2, 3, 0, 1, 0,
|
|
2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 1, 2, 0, 0, 2, 2, 4, 5,
|
|
5, 0, 1, 2, 6, 2, 3, 0, 1, 0, 2, 0, 2, 0, 0, 0, 0, 0,
|
|
};
|
|
|
|
for (i = 0; zIn[i] && !isalpha(zIn[i]); i++) {
|
|
}
|
|
if (zIn[i]) {
|
|
zResult[0] = toupper(zIn[i]);
|
|
for (j = 1; j < 4 && zIn[i]; i++) {
|
|
int code = iCode[zIn[i] & 0x7f];
|
|
if (code > 0) {
|
|
zResult[j++] = code + '0';
|
|
}
|
|
}
|
|
while (j < 4) {
|
|
zResult[j++] = '0';
|
|
}
|
|
zResult[j] = 0;
|
|
} else {
|
|
strcpy(zResult, "?000");
|
|
}
|
|
}
|
|
|
|
/*
|
|
** computes the number of different characters between the soundex value fo 2
|
|
*strings
|
|
*/
|
|
static void
|
|
differenceFunc(sqlite3_context* context, int argc, sqlite3_value** argv)
|
|
{
|
|
char zResult1[8];
|
|
char zResult2[8];
|
|
char* zR1 = zResult1;
|
|
char* zR2 = zResult2;
|
|
int rVal = 0;
|
|
int i = 0;
|
|
const u8* zIn1;
|
|
const u8* zIn2;
|
|
|
|
assert(argc == 2);
|
|
|
|
if (sqlite3_value_type(argv[0]) == SQLITE_NULL
|
|
|| sqlite3_value_type(argv[1]) == SQLITE_NULL)
|
|
{
|
|
sqlite3_result_null(context);
|
|
return;
|
|
}
|
|
|
|
zIn1 = (u8*) sqlite3_value_text(argv[0]);
|
|
zIn2 = (u8*) sqlite3_value_text(argv[1]);
|
|
|
|
soundex(zIn1, zR1);
|
|
soundex(zIn2, zR2);
|
|
|
|
for (i = 0; i < 4; ++i) {
|
|
if (sqliteCharVal((unsigned char*) zR1)
|
|
== sqliteCharVal((unsigned char*) zR2))
|
|
++rVal;
|
|
sqliteNextChar(zR1);
|
|
sqliteNextChar(zR2);
|
|
}
|
|
sqlite3_result_int(context, rVal);
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
** This function registered all of the above C functions as SQL
|
|
** functions. This should be the only routine in this file with
|
|
** external linkage.
|
|
*/
|
|
int
|
|
common_extension_functions(struct FuncDef** basic_funcs,
|
|
struct FuncDefAgg** agg_funcs)
|
|
{
|
|
static struct FuncDef aFuncs[] = {
|
|
/* math.h */
|
|
{
|
|
"acos",
|
|
1,
|
|
SQLITE_UTF8,
|
|
0,
|
|
acosFunc,
|
|
help_text("acos")
|
|
.sql_function()
|
|
.with_summary("Returns the arccosine of a number, in radians")
|
|
.with_parameter(
|
|
{"num", "A cosine value that is between -1 and 1"})
|
|
.with_tags({"math"})
|
|
.with_example(
|
|
{"To get the arccosine of 0.2", "SELECT acos(0.2)"}),
|
|
},
|
|
{
|
|
"asin",
|
|
1,
|
|
SQLITE_UTF8,
|
|
0,
|
|
asinFunc,
|
|
help_text("asin")
|
|
.sql_function()
|
|
.with_summary("Returns the arcsine of a number, in radians")
|
|
.with_parameter(
|
|
{"num", "A sine value that is between -1 and 1"})
|
|
.with_tags({"math"})
|
|
.with_example(
|
|
{"To get the arcsine of 0.2", "SELECT asin(0.2)"}),
|
|
},
|
|
{
|
|
"atan",
|
|
1,
|
|
SQLITE_UTF8,
|
|
0,
|
|
atanFunc,
|
|
help_text("atan")
|
|
.sql_function()
|
|
.with_summary("Returns the arctangent of a number, in radians")
|
|
.with_parameter({"num", "The number"})
|
|
.with_tags({"math"})
|
|
.with_example(
|
|
{"To get the arctangent of 0.2", "SELECT atan(0.2)"}),
|
|
},
|
|
{
|
|
"atn2",
|
|
2,
|
|
SQLITE_UTF8,
|
|
0,
|
|
atn2Func,
|
|
help_text("atn2")
|
|
.sql_function()
|
|
.with_summary("Returns the angle in the plane between the "
|
|
"positive X axis "
|
|
"and the ray from (0, 0) to the point (x, y)")
|
|
.with_parameter({"y", "The y coordinate of the point"})
|
|
.with_parameter({"x", "The x coordinate of the point"})
|
|
.with_tags({"math"})
|
|
.with_example({
|
|
"To get the angle, in degrees, for the point at (5, 5)",
|
|
"SELECT degrees(atn2(5, 5))",
|
|
}),
|
|
},
|
|
/* XXX alias */
|
|
{
|
|
"atan2",
|
|
2,
|
|
SQLITE_UTF8,
|
|
0,
|
|
atn2Func,
|
|
help_text("atan2")
|
|
.sql_function()
|
|
.with_summary("Returns the angle in the plane between the "
|
|
"positive X axis "
|
|
"and the ray from (0, 0) to the point (x, y)")
|
|
.with_parameter({"y", "The y coordinate of the point"})
|
|
.with_parameter({"x", "The x coordinate of the point"})
|
|
.with_tags({"math"})
|
|
.with_example({
|
|
"To get the angle, in degrees, for the point at (5, 5)",
|
|
"SELECT degrees(atan2(5, 5))",
|
|
}),
|
|
},
|
|
{
|
|
"acosh",
|
|
1,
|
|
SQLITE_UTF8,
|
|
0,
|
|
acoshFunc,
|
|
help_text("acosh")
|
|
.sql_function()
|
|
.with_summary("Returns the hyperbolic arccosine of a number")
|
|
.with_parameter({"num", "A number that is one or more"})
|
|
.with_tags({"math"})
|
|
.with_example({
|
|
"To get the hyperbolic arccosine of 1.2",
|
|
"SELECT acosh(1.2)",
|
|
}),
|
|
},
|
|
{
|
|
"asinh",
|
|
1,
|
|
SQLITE_UTF8,
|
|
0,
|
|
asinhFunc,
|
|
help_text("asinh")
|
|
.sql_function()
|
|
.with_summary("Returns the hyperbolic arcsine of a number")
|
|
.with_parameter({"num", "The number"})
|
|
.with_tags({"math"})
|
|
.with_example({
|
|
"To get the hyperbolic arcsine of 0.2",
|
|
"SELECT asinh(0.2)",
|
|
}),
|
|
},
|
|
{
|
|
"atanh",
|
|
1,
|
|
SQLITE_UTF8,
|
|
0,
|
|
atanhFunc,
|
|
help_text("atanh")
|
|
.sql_function()
|
|
.with_summary("Returns the hyperbolic arctangent of a number")
|
|
.with_parameter({"num", "The number"})
|
|
.with_tags({"math"})
|
|
.with_example({
|
|
"To get the hyperbolic arctangent of 0.2",
|
|
"SELECT atanh(0.2)",
|
|
}),
|
|
},
|
|
|
|
{"difference", 2, SQLITE_UTF8, 0, differenceFunc},
|
|
{
|
|
"degrees",
|
|
1,
|
|
SQLITE_UTF8,
|
|
0,
|
|
rad2degFunc,
|
|
help_text("degrees")
|
|
.sql_function()
|
|
.with_summary("Converts radians to degrees")
|
|
.with_parameter(
|
|
{"radians", "The radians value to convert to degrees"})
|
|
.with_tags({"math"})
|
|
.with_example(
|
|
{"To convert PI to degrees", "SELECT degrees(pi())"}),
|
|
},
|
|
{
|
|
"radians",
|
|
1,
|
|
SQLITE_UTF8,
|
|
0,
|
|
deg2radFunc,
|
|
help_text("radians")
|
|
.sql_function()
|
|
.with_summary("Converts degrees to radians")
|
|
.with_parameter(
|
|
{"degrees", "The degrees value to convert to radians"})
|
|
.with_tags({"math"})
|
|
.with_example({
|
|
"To convert 180 degrees to radians",
|
|
"SELECT radians(180)",
|
|
}),
|
|
},
|
|
|
|
{"cos", 1, SQLITE_UTF8, 0, cosFunc},
|
|
{"sin", 1, SQLITE_UTF8, 0, sinFunc},
|
|
{"tan", 1, SQLITE_UTF8, 0, tanFunc},
|
|
{"cot", 1, SQLITE_UTF8, 0, cotFunc},
|
|
{"cosh", 1, SQLITE_UTF8, 0, coshFunc},
|
|
{"sinh", 1, SQLITE_UTF8, 0, sinhFunc},
|
|
{"tanh", 1, SQLITE_UTF8, 0, tanhFunc},
|
|
{"coth", 1, SQLITE_UTF8, 0, cothFunc},
|
|
|
|
{
|
|
"exp",
|
|
1,
|
|
SQLITE_UTF8,
|
|
0,
|
|
expFunc,
|
|
help_text("exp")
|
|
.sql_function()
|
|
.with_summary("Returns the value of e raised to the power of x")
|
|
.with_parameter({"x", "The exponent"})
|
|
.with_tags({"math"})
|
|
.with_example({"To raise e to 2", "SELECT exp(2)"}),
|
|
},
|
|
{
|
|
"log",
|
|
1,
|
|
SQLITE_UTF8,
|
|
0,
|
|
logFunc,
|
|
help_text("log")
|
|
.sql_function()
|
|
.with_summary("Returns the natural logarithm of x")
|
|
.with_parameter({"x", "The number"})
|
|
.with_tags({"math"})
|
|
.with_example(
|
|
{"To get the natual logarithm of 8", "SELECT log(8)"}),
|
|
},
|
|
{
|
|
"log10",
|
|
1,
|
|
SQLITE_UTF8,
|
|
0,
|
|
log10Func,
|
|
help_text("log10")
|
|
.sql_function()
|
|
.with_summary("Returns the base-10 logarithm of X")
|
|
.with_parameter({"x", "The number"})
|
|
.with_tags({"math"})
|
|
.with_example(
|
|
{"To get the logarithm of 100", "SELECT log10(100)"}),
|
|
},
|
|
{
|
|
"power",
|
|
2,
|
|
SQLITE_UTF8,
|
|
0,
|
|
powerFunc,
|
|
help_text("power")
|
|
.sql_function()
|
|
.with_summary("Returns the base to the given exponent")
|
|
.with_parameter({"base", "The base number"})
|
|
.with_parameter({"exp", "The exponent"})
|
|
.with_tags({"math"})
|
|
.with_example({
|
|
"To raise two to the power of three",
|
|
"SELECT power(2, 3)",
|
|
}),
|
|
},
|
|
{
|
|
"sign",
|
|
1,
|
|
SQLITE_UTF8,
|
|
0,
|
|
signFunc,
|
|
help_text("sign")
|
|
.sql_function()
|
|
.with_summary(
|
|
"Returns the sign of the given number as -1, 0, or 1")
|
|
.with_parameter({"num", "The number"})
|
|
.with_tags({"math"})
|
|
.with_example({"To get the sign of 10", "SELECT sign(10)"})
|
|
.with_example({"To get the sign of 0", "SELECT sign(0)"})
|
|
.with_example({"To get the sign of -10", "SELECT sign(-10)"}),
|
|
},
|
|
{"sqrt", 1, SQLITE_UTF8, 0, sqrtFunc},
|
|
{
|
|
"square",
|
|
1,
|
|
SQLITE_UTF8,
|
|
0,
|
|
squareFunc,
|
|
help_text("square")
|
|
.sql_function()
|
|
.with_summary("Returns the square of the argument")
|
|
.with_parameter({"num", "The number to square"})
|
|
.with_tags({"math"})
|
|
.with_example({"To get the square of two", "SELECT square(2)"}),
|
|
},
|
|
|
|
{
|
|
"ceil",
|
|
1,
|
|
SQLITE_UTF8,
|
|
0,
|
|
ceilFunc,
|
|
help_text("ceil")
|
|
.sql_function()
|
|
.with_summary(
|
|
"Returns the smallest integer that is not less than "
|
|
"the argument")
|
|
.with_parameter({"num", "The number to raise to the ceiling"})
|
|
.with_tags({"math"})
|
|
.with_example(
|
|
{"To get the ceiling of 1.23", "SELECT ceil(1.23)"}),
|
|
},
|
|
{
|
|
"floor",
|
|
1,
|
|
SQLITE_UTF8,
|
|
0,
|
|
floorFunc,
|
|
help_text("floor")
|
|
.sql_function()
|
|
.with_summary("Returns the largest integer that is not greater "
|
|
"than the argument")
|
|
.with_parameter({"num", "The number to lower to the floor"})
|
|
.with_tags({"math"})
|
|
.with_example(
|
|
{"To get the floor of 1.23", "SELECT floor(1.23)"}),
|
|
},
|
|
|
|
{
|
|
"pi",
|
|
0,
|
|
SQLITE_UTF8,
|
|
1,
|
|
piFunc,
|
|
help_text("pi")
|
|
.sql_function()
|
|
.with_summary("Returns the value of PI")
|
|
.with_tags({"math"})
|
|
.with_example({"To get the value of PI", "SELECT pi()"}),
|
|
},
|
|
|
|
/* string */
|
|
{
|
|
"replicate",
|
|
2,
|
|
SQLITE_UTF8,
|
|
0,
|
|
replicateFunc,
|
|
help_text("replicate")
|
|
.sql_function()
|
|
.with_summary("Returns the given string concatenated N times.")
|
|
.with_parameter({"str", "The string to replicate."})
|
|
.with_parameter(
|
|
{"N", "The number of times to replicate the string."})
|
|
.with_tags({"string"})
|
|
.with_example({
|
|
"To repeat the string 'abc' three times",
|
|
"SELECT replicate('abc', 3)",
|
|
}),
|
|
},
|
|
{"charindex", 2, SQLITE_UTF8, 0, charindexFunc},
|
|
{
|
|
"charindex",
|
|
3,
|
|
SQLITE_UTF8,
|
|
0,
|
|
charindexFunc,
|
|
help_text("charindex")
|
|
.sql_function()
|
|
.with_summary("Finds the first occurrence of the needle within "
|
|
"the haystack "
|
|
"and returns the number of prior characters plus "
|
|
"1, or 0 if Y "
|
|
"is nowhere found within X")
|
|
.with_parameter(
|
|
{"needle", "The string to look for in the haystack"})
|
|
.with_parameter({"haystack", "The string to search within"})
|
|
.with_parameter(help_text("start",
|
|
"The one-based index within the "
|
|
"haystack to start the search")
|
|
.optional())
|
|
.with_tags({"string"})
|
|
.with_example({
|
|
"To search for the string 'abc' within 'abcabc' "
|
|
"and starting at position 2",
|
|
"SELECT charindex('abc', 'abcabc', 2)",
|
|
})
|
|
.with_example({
|
|
"To search for the string 'abc' within 'abcdef' "
|
|
"and starting at position 2",
|
|
"SELECT charindex('abc', 'abcdef', 2)",
|
|
}),
|
|
},
|
|
{
|
|
"leftstr",
|
|
2,
|
|
SQLITE_UTF8,
|
|
0,
|
|
leftFunc,
|
|
help_text("leftstr")
|
|
.sql_function()
|
|
.with_summary(
|
|
"Returns the N leftmost (UTF-8) characters in the "
|
|
"given string.")
|
|
.with_parameter({"str", "The string to return subset."})
|
|
.with_parameter(
|
|
{"N",
|
|
"The number of characters from the left side of "
|
|
"the string to return."})
|
|
.with_tags({"string"})
|
|
.with_example({
|
|
"To get the first character of the string 'abc'",
|
|
"SELECT leftstr('abc', 1)",
|
|
})
|
|
.with_example({
|
|
"To get the first ten characters of a string, "
|
|
"regardless of size",
|
|
"SELECT leftstr('abc', 10)",
|
|
}),
|
|
},
|
|
{
|
|
"rightstr",
|
|
2,
|
|
SQLITE_UTF8,
|
|
0,
|
|
rightFunc,
|
|
help_text("rightstr")
|
|
.sql_function()
|
|
.with_summary(
|
|
"Returns the N rightmost (UTF-8) characters in the "
|
|
"given string.")
|
|
.with_parameter({"str", "The string to return subset."})
|
|
.with_parameter(
|
|
{"N",
|
|
"The number of characters from the right side of "
|
|
"the string to return."})
|
|
.with_tags({"string"})
|
|
.with_example({
|
|
"To get the last character of the string 'abc'",
|
|
"SELECT rightstr('abc', 1)",
|
|
})
|
|
.with_example({
|
|
"To get the last ten characters of a string, "
|
|
"regardless of size",
|
|
"SELECT rightstr('abc', 10)",
|
|
}),
|
|
},
|
|
#ifndef HAVE_TRIM
|
|
{"ltrim", 1, SQLITE_UTF8, 0, ltrimFunc},
|
|
{"rtrim", 1, SQLITE_UTF8, 0, rtrimFunc},
|
|
{"trim", 1, SQLITE_UTF8, 0, trimFunc},
|
|
{"replace", 3, SQLITE_UTF8, 0, replaceFunc},
|
|
#endif
|
|
{
|
|
"reverse",
|
|
1,
|
|
SQLITE_UTF8,
|
|
0,
|
|
reverseFunc,
|
|
help_text("reverse")
|
|
.sql_function()
|
|
.with_summary("Returns the reverse of the given string.")
|
|
.with_parameter({"str", "The string to reverse."})
|
|
.with_tags({"string"})
|
|
.with_example(
|
|
{"To reverse the string 'abc'", "SELECT reverse('abc')"}),
|
|
},
|
|
{
|
|
"proper",
|
|
1,
|
|
SQLITE_UTF8,
|
|
0,
|
|
properFunc,
|
|
help_text("proper")
|
|
.sql_function()
|
|
.with_summary("Capitalize the first character of words in the "
|
|
"given string")
|
|
.with_parameter({"str", "The string to capitalize."})
|
|
.with_tags({"string"})
|
|
.with_example({
|
|
"To capitalize the words in the string 'hello, world!'",
|
|
"SELECT proper('hello, world!')",
|
|
}),
|
|
},
|
|
{
|
|
"padl",
|
|
2,
|
|
SQLITE_UTF8,
|
|
0,
|
|
padlFunc,
|
|
help_text("padl")
|
|
.sql_function()
|
|
.with_summary(
|
|
"Pad the given string with leading spaces until it "
|
|
"reaches the desired length")
|
|
.with_parameter({"str", "The string to pad"})
|
|
.with_parameter(
|
|
{"len", "The minimum desired length of the output string"})
|
|
.with_tags({"string"})
|
|
.with_example(
|
|
{"To pad the string 'abc' to a length of six characters",
|
|
"SELECT padl('abc', 6)"})
|
|
.with_example({
|
|
"To pad the string 'abcdef' to a length of four "
|
|
"characters",
|
|
"SELECT padl('abcdef', 4)",
|
|
}),
|
|
},
|
|
{
|
|
"padr",
|
|
2,
|
|
SQLITE_UTF8,
|
|
0,
|
|
padrFunc,
|
|
help_text("padr")
|
|
.sql_function()
|
|
.with_summary(
|
|
"Pad the given string with trailing spaces until it "
|
|
"reaches the desired length")
|
|
.with_parameter({"str", "The string to pad"})
|
|
.with_parameter(
|
|
{"len", "The minimum desired length of the output string"})
|
|
.with_tags({"string"})
|
|
.with_example(
|
|
{"To pad the string 'abc' to a length of six characters",
|
|
"SELECT padr('abc', 6) || 'def'"})
|
|
.with_example({
|
|
"To pad the string 'abcdef' to a length of four characters",
|
|
"SELECT padr('abcdef', 4) || 'ghi'",
|
|
}),
|
|
},
|
|
{
|
|
"padc",
|
|
2,
|
|
SQLITE_UTF8,
|
|
0,
|
|
padcFunc,
|
|
help_text("padc")
|
|
.sql_function()
|
|
.with_summary(
|
|
"Pad the given string with enough spaces to make it "
|
|
"centered within the given length")
|
|
.with_parameter({"str", "The string to pad"})
|
|
.with_parameter(
|
|
{"len", "The minimum desired length of the output string"})
|
|
.with_tags({"string"})
|
|
.with_example(
|
|
{"To pad the string 'abc' to a length of six characters",
|
|
"SELECT padc('abc', 6) || 'def'"})
|
|
.with_example({
|
|
"To pad the string 'abcdef' to a length of "
|
|
"eight characters",
|
|
"SELECT padc('abcdef', 8) || 'ghi'",
|
|
}),
|
|
},
|
|
{
|
|
"strfilter",
|
|
2,
|
|
SQLITE_UTF8,
|
|
0,
|
|
strfilterFunc,
|
|
help_text("strfilter")
|
|
.sql_function()
|
|
.with_summary(
|
|
"Returns the source string with only the characters "
|
|
"given in the second parameter")
|
|
.with_parameter({"source", "The string to filter"})
|
|
.with_parameter(
|
|
{"include", "The characters to include in the result"})
|
|
.with_tags({"string"})
|
|
.with_example({
|
|
"To get the 'b', 'c', and 'd' characters from the "
|
|
"string 'abcabc'",
|
|
"SELECT strfilter('abcabc', 'bcd')",
|
|
}),
|
|
},
|
|
|
|
{nullptr},
|
|
};
|
|
|
|
/* Aggregate functions */
|
|
static struct FuncDefAgg aAggs[] = {
|
|
{"stdev", 1, 0, varianceStep, stdevFinalize},
|
|
{"stddev", 1, 0, varianceStep, stdevFinalize},
|
|
{"variance", 1, 0, varianceStep, varianceFinalize},
|
|
{"mode", 1, 0, modeStep, modeFinalize},
|
|
{"median", 1, 0, modeStep, medianFinalize},
|
|
{"lower_quartile", 1, 0, modeStep, lower_quartileFinalize},
|
|
{"upper_quartile", 1, 0, modeStep, upper_quartileFinalize},
|
|
|
|
{nullptr},
|
|
};
|
|
|
|
*basic_funcs = aFuncs;
|
|
*agg_funcs = aAggs;
|
|
|
|
return SQLITE_OK;
|
|
}
|
|
|
|
#ifdef COMPILE_SQLITE_EXTENSIONS_AS_LOADABLE_MODULE
|
|
int
|
|
sqlite3_extension_init(sqlite3* db,
|
|
char** pzErrMsg,
|
|
const sqlite3_api_routines* pApi)
|
|
{
|
|
SQLITE_EXTENSION_INIT2(pApi);
|
|
RegisterExtensionFunctions(db);
|
|
return 0;
|
|
}
|
|
#endif /* COMPILE_SQLITE_EXTENSIONS_AS_LOADABLE_MODULE */
|
|
|
|
map
|
|
map_make(cmp_func cmp)
|
|
{
|
|
map r;
|
|
r.cmp = cmp;
|
|
r.base = 0;
|
|
r.free = 0;
|
|
|
|
return r;
|
|
}
|
|
|
|
void*
|
|
xcalloc(size_t nmemb, size_t size, const char* s)
|
|
{
|
|
void* ret = calloc(nmemb, size);
|
|
return ret;
|
|
}
|
|
|
|
static void
|
|
xfree(void* p)
|
|
{
|
|
free(p);
|
|
}
|
|
|
|
void
|
|
node_insert(node** n, cmp_func cmp, void* e)
|
|
{
|
|
int c;
|
|
node* nn;
|
|
if (*n == 0) {
|
|
nn = (node*) xcalloc(1, sizeof(node), "for node");
|
|
nn->data = e;
|
|
nn->count = 1;
|
|
*n = nn;
|
|
} else {
|
|
c = cmp((*n)->data, e);
|
|
if (0 == c) {
|
|
++((*n)->count);
|
|
xfree(e);
|
|
} else if (c > 0) {
|
|
/* put it right here */
|
|
node_insert(&((*n)->l), cmp, e);
|
|
} else {
|
|
node_insert(&((*n)->r), cmp, e);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
map_insert(map* m, void* e)
|
|
{
|
|
node_insert(&(m->base), m->cmp, e);
|
|
}
|
|
|
|
void
|
|
node_iterate(node* n, map_iterator iter, void* p)
|
|
{
|
|
if (n) {
|
|
if (n->l)
|
|
node_iterate(n->l, iter, p);
|
|
iter(n->data, n->count, p);
|
|
if (n->r)
|
|
node_iterate(n->r, iter, p);
|
|
}
|
|
}
|
|
|
|
void
|
|
map_iterate(map* m, map_iterator iter, void* p)
|
|
{
|
|
node_iterate(m->base, iter, p);
|
|
}
|
|
|
|
void
|
|
node_destroy(node* n)
|
|
{
|
|
if (0 != n) {
|
|
xfree(n->data);
|
|
if (n->l)
|
|
node_destroy(n->l);
|
|
if (n->r)
|
|
node_destroy(n->r);
|
|
|
|
xfree(n);
|
|
}
|
|
}
|
|
|
|
void
|
|
map_destroy(map* m)
|
|
{
|
|
node_destroy(m->base);
|
|
}
|
|
|
|
int
|
|
int_cmp(const void* a, const void* b)
|
|
{
|
|
int64_t aa = *(int64_t*) (a);
|
|
int64_t bb = *(int64_t*) (b);
|
|
/* printf("cmp %d <=> %d\n",aa,bb); */
|
|
if (aa == bb)
|
|
return 0;
|
|
else if (aa < bb)
|
|
return -1;
|
|
else
|
|
return 1;
|
|
}
|
|
|
|
int
|
|
double_cmp(const void* a, const void* b)
|
|
{
|
|
double aa = *(double*) (a);
|
|
double bb = *(double*) (b);
|
|
/* printf("cmp %d <=> %d\n",aa,bb); */
|
|
if (aa == bb)
|
|
return 0;
|
|
else if (aa < bb)
|
|
return -1;
|
|
else
|
|
return 1;
|
|
}
|
|
|
|
void
|
|
print_elem(void* e, int64_t c, void* p)
|
|
{
|
|
int ee = *(int*) (e);
|
|
printf("%d => %" PRId64 "\n", ee, c);
|
|
}
|