extension-functions.c
Transcript of extension-functions.c
-
7/28/2019 extension-functions.c
1/51
/*This library will provide commonmathematical and string functions inSQL queries using the operating systemlibraries or provideddefinitions. It includes the followingfunctions:
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 inrecent versions of SQLite and so by defaultdo 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 -lsqlite3if your sqlite3 is installed from Mac ports,
or-I /sw/include/ -L/sw/lib -lsqlite3if installed with Fink.)* Windows:1. Install MinGW (http://www.mingw.org/)
and you will get the gcc
-
7/28/2019 extension-functions.c
2/51
(gnu compiler collection)2. add the path to your path variable (isn't
done during theinstallation!)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 callingthe sqlite3 API functions:
In your application, callsqlite3_enable_load_extension(db,1) to
allow loading external libraries. Then loadthe library libsqlitefunctions
using sqlite3_load_extension; the thirdargument should be 0.
See http://www.sqlite.org/cvstrac/wiki?p=LoadableExtensions.
Select statements may now use thesefunctions, as in
SELECT cos(radians(inclination)) FROMsatsum 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.707106781186548Note: Loading extensions is by default
prohibited as asecurity measure; see "Security
Considerations" inhttp://www.sqlite.org/cvstrac/wiki?
p=LoadableExtensions.If the sqlite3 program and library are built
thisway, you cannot use these functions from
the program, you
must write your own program using thesqlite3 API, and call
sqlite3_enable_load_extension asdescribed above, or else
-
7/28/2019 extension-functions.c
3/51
rebuilt the sqlite3 program to allowloadable extensions.
Alterations:The instructions are for Linux, Mac OS X,and Windows; users of otherOSes may need to modify this procedure.
In particular, if your mathlibrary lacks one or more of the needed trigor log functions, commentout the appropriate HAVE_ #define at thetop of file. If you do notwish to make a loadable module, commentout the define forCOMPILE_SQLITE_EXTENSIONS_AS_LOADABLE_MODULE.If you are using a
version of SQLite without the trim functionsand replace, comment outthe HAVE_TRIM #define.
Liam Healy
History:2010-01-06 Correct check for argc insquareFunc, and add Windows
compilation instructions.2009-06-24 Correct check for argc inproperFunc.2008-09-14 Add check that memory wasactually allocated aftersqlite3_malloc or sqlite3StrDup, callsqlite3_result_error_nomem ifnot. Thanks to Robert Simpson.2008-06-13 Change to instructions to
indicate use of the math libraryand that program might work.2007-10-01 Minor clarification toinstructions.2007-09-29 Compilation as loadable moduleis optional withCOMPILE_SQLITE_EXTENSIONS_AS_LOADABLE_MODULE.2007-09-28 Use sqlite3_extension_init andmacros
SQLITE_EXTENSION_INIT1,SQLITE_EXTENSION_INIT2, so that it workswithsqlite3_load_extension. Thanks to Eric
-
7/28/2019 extension-functions.c
4/51
Higashino and Joe Wilson.New instructions for Mac compilation.2007-09-17 With help from Joe Wilson andNuno Luca, made use ofexternal interfaces so that compilation is nolonger dependent onSQLite source code. Merged source,
header, and README into a singlefile. Added casts so that Mac will compilewithout warnings (unsignedand signed char).2007-09-05 Included some definitions fromsqlite 3.3.13 so that thiswill continue to work in newer versions ofsqlite. Completeddescription of functions available.
2007-03-27 Revised description.2007-03-23 Small cleanup and a bug fix onthe code. This was mainlyletting errno flag errors encountered in themath library and checkingthe result, rather than pre-checking. Thisfixes a bug in power thatwould cause an error if any non-positivenumber was raised to any
power.2007-02-07 posted by Mikey C to sqlitemailing list.Original code 2006 June 05 by relicoder.
*/
//#include "config.h"
#defineCOMPILE_SQLITE_EXTENSIONS_AS_LOADABLE_MODULE1#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
-
7/28/2019 extension-functions.c
5/51
if sqlite has trim functions */
#ifdefCOMPILE_SQLITE_EXTENSIONS_AS_LOADABLE_MODULE#include "sqlite3ext.h"SQLITE_EXTENSION_INIT1#else
#include "sqlite3.h"#endif
#include /* relicoder */#include #include #include #include /* LMH 2007-03-25 */
#include #include
#ifndef _MAP_H_#define _MAP_H_
#include
/*** Simple binary tree implementation to usein median, mode and quartile calculations** Tree is not necessarily balanced. Thatwould require something like red&blacktrees 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;
-
7/28/2019 extension-functions.c
6/51
cmp_func cmp;short free;
} map;
/*** creates a map given a comparisonfunction
*/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 inthe 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 ) {
-
7/28/2019 extension-functions.c
7/51
char *res = sqlite3_malloc( strlen(z)+1 );return strcpy( res, z );
}
/*** These are copied verbatim from fun.c soas to not have the names exported
*/
/* LMH from sqlite3 3.3.13 *//*** This table maps from the first byte of aUTF-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,};
-
7/28/2019 extension-functions.c
8/51
/*** This table maps from the number oftrailing bytes in a UTF-8 character** to an integer constant that is effectivelycalculated for each character** read by a naive implementation of a UTF-8character reader. The code
** in the READ_UTF8 macro explains thingsbest.*/static const int xtra_utf8_bits[] = {
0,12416, /* (0xC0
-
7/28/2019 extension-functions.c
9/51
case 1: c = (c
-
7/28/2019 extension-functions.c
10/51
return r;}
/*** X is a pointer to the first byte of a UTF-8character. 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 writtingwrappers for math.h functions** it creates code for a function to use inSQlite that gets one numeric input** and returns a floating point value.**** Could have been implemented usingpointers 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 towrap (eg: sin)** domain: boolean condition that CAN'Thappen in terms of the input parameter rVal
** (eg: rval
-
7/28/2019 extension-functions.c
11/51
-
7/28/2019 extension-functions.c
12/51
static double acosh(double x){return log(x + sqrt(x*x - 1.0));
}#endif
GEN_MATH_WRAP_DOUBLE_1(acoshFunc,acosh)
#ifndef HAVE_ASINHstatic double asinh(double x){
return log(x + sqrt(x*x + 1.0));}#endif
GEN_MATH_WRAP_DOUBLE_1(asinhFunc,asinh)
#ifndef HAVE_ATANHstatic 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) soit'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);
}
-
7/28/2019 extension-functions.c
13/51
/*** Many systems don't have hyperbolictrigonometric functions so this will emulate** them on those systems directly from thedefinition 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. Thiswill emulate it*/
#ifndef HAVE_LOG10static double log10(double x){
static double l10 = -1.0;if( l10
-
7/28/2019 extension-functions.c
14/51
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.hdoesn'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 ofPI=3.1415... */static void piFunc(sqlite3_context *context,int argc, sqlite3_value **argv){
sqlite3_result_double(context, M_PI);}
/*
-
7/28/2019 extension-functions.c
15/51
** Implements the sqrt function, it has thepeculiarity of returning an integer when the** the argument is an integer.** Since SQLite isn't strongly typed (almostuntyped 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 areintegers the result should be integer
** (see sqrt just before this). Here the resultis always double*//* LMH 2007-03-25 Changed to use errno; nopre-checking for errors. Also removes
but that was present in the pre-checkingthat called sqlite3_result_error on
a non-positive first argument, which is notalways an error. */
static void powerFunc(sqlite3_context*context, int argc, sqlite3_value **argv){
double r1 = 0.0;double r2 = 0.0;
-
7/28/2019 extension-functions.c
16/51
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
-
7/28/2019 extension-functions.c
17/51
when the argument is respectively** positive, 0 or negative.** When the argument is NULL the result isalso 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) ? 1: ( rVal < 0 ) ? -1: 0;sqlite3_result_double(context, rVal);break;
}}
}
/*** smallest integer value not less thanargument*/static void ceilFunc(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: {
i64 iVal = sqlite3_value_int64(argv[0]);sqlite3_result_int64(context, iVal);
-
7/28/2019 extension-functions.c
18/51
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 thanargument*/static void floorFunc(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: {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 argumentand an integer (n) in the second returns the** string that constains s contatenated n
-
7/28/2019 extension-functions.c
19/51
times*/static void replicateFunc(sqlite3_context*context, int argc, sqlite3_value **argv){
unsigned char *z; /* input string */unsigned char *zo; /* result string */i64 iCount; /* times to repeat */
i64 nLen; /* length of the inputstring (no multibyte considerations) */
i64 nTLen; /* length of the resultstring (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
-
7/28/2019 extension-functions.c
20/51
}
/*** Some systems (win32 among others)don't have an isblank function, this willemulate it.** This function is not UFT-8 safe since it
only analyses a byte character.*/#ifndef HAVE_ISBLANKint 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{
-
7/28/2019 extension-functions.c
21/51
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=ilen ){
/* string is longer than the requested
-
7/28/2019 extension-functions.c
22/51
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 = sqlite3_malloc(strlen(zi)+ilen-zl+1);if (!zo){sqlite3_result_error_nomem(context);return;
}zt = zo;for(i=1; i+zl=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;
-
7/28/2019 extension-functions.c
23/51
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=ilen ){
/* string is longer than the requestedpad 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 = sqlite3_malloc(zll+ilen-zl+1);if (!zo){sqlite3_result_error_nomem(context);return;
}zt = strcpy(zo,zi)+zll;for(i=1; i+zl
-
7/28/2019 extension-functions.c
24/51
** and adds spaces at the begining of s untilit has a length of n characters.** Tries to add has many characters at theleft 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=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 = sqlite3_malloc(zll+ilen-zl+1);
-
7/28/2019 extension-functions.c
25/51
if (!zo){sqlite3_result_error_nomem(context);return;
}zt = zo;for(i=1; 2*i+zl
-
7/28/2019 extension-functions.c
26/51
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 = 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*
-
7/28/2019 extension-functions.c
27/51
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++)=0 ? rVal+s : rVal;
}
/*** given 2 input strings (s1,s2) and aninteger (n) searches from the nth character** for the string s1. Returns the position
-
7/28/2019 extension-functions.c
28/51
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
-
7/28/2019 extension-functions.c
29/51
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++
-
7/28/2019 extension-functions.c
30/51
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 ){sqliteNextChar(zt);
}
rz = 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);
-
7/28/2019 extension-functions.c
31/51
}
#ifndef HAVE_TRIM/*** removes the whitespaces at the beginingof a string.*/
const char* ltrim(const char* s){while( *s==' ' )
++s;return s;
}
/*** removes the whitespaces at the end of astring.
** !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 beginingof 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);}
/*
-
7/28/2019 extension-functions.c
32/51
** Removes the whitespace at the end of astring*/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 beginingand 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,
-
7/28/2019 extension-functions.c
33/51
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, constchar *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 replacesoccurrences of s1 in s by s2*/
static void replaceFunc(sqlite3_context*context, int argc, sqlite3_value **argv){
const char *z1; /* string s (firstparameter) */
const char *z2; /* string s1 (secondparameter) string to look for */
const char *z3; /* string s2 (thirdparameter) string to replace occurrences ofs1 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])
-
7/28/2019 extension-functions.c
34/51
){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
-
7/28/2019 extension-functions.c
35/51
sqlite3_result_text(context, zo, -1,SQLITE_TRANSIENT);
sqlite3_free(zo);}#endif
/*
** given a string returns the same string butwith 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 = 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);}
}
-
7/28/2019 extension-functions.c
36/51
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() aggregatecomputation.** implementaion ofhttp://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 structureholds the context of a** mode() or median() aggregate
computation.** Depends on structures defined in map.c(see map & map)** These aggregate functions only work forintegers and floats although** they could be made to work for strings.This is usually considered meaningless.** Only usuall order (for median), no use ofcollation functions (would this even make
sense?)*/typedef struct ModeCtx ModeCtx;struct ModeCtx {
i64 riM; /* integer value found so far*/
double rdM; /* double value found sofar */
i64 cnt; /* number of elements so far
*/double pcnt; /* number of elements
smaller than a percentile */i64 mcnt; /* maximum number of
-
7/28/2019 extension-functions.c
37/51
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 acalculation 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 = 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 acalculation 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;
-
7/28/2019 extension-functions.c
38/51
double *dptr;int type;
assert( argc==1 );type =
sqlite3_value_numeric_type(argv[0]);
if( type == SQLITE_NULL)return;
p = sqlite3_aggregate_context(context,
sizeof(*p));
if( 0==(p->m) ){p->m = 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*
-
7/28/2019 extension-functions.c
39/51
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->mcntriM = ei;p->mcnt = c;p->mn=1;
}}else{
ed = *(double*)(e);
if( p->mcnt==c ){++p->mn;
}else if(p->mcntrdM = ed;p->mcnt = c;p->mn=1;
}
}}
/*** Auxiliary function that iterates allelements in a map and finds the median** (the value such that the number ofelements smaller is equal the 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;
-
7/28/2019 extension-functions.c
40/51
-
7/28/2019 extension-functions.c
41/51
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 voidlower_quartileFinalize(sqlite3_context*context){
ModeCtx *p;p = (ModeCtx*)
sqlite3_aggregate_context(context, 0);if( p!=0 ){
-
7/28/2019 extension-functions.c
42/51
p->pcnt = (p->cnt)/4.0;_medianFinalize(context);
}}
/*** Returns the upper_quartile value
*/static voidupper_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 = 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 = 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);
-
7/28/2019 extension-functions.c
43/51
-
7/28/2019 extension-functions.c
44/51
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
-
7/28/2019 extension-functions.c
45/51
int RegisterExtensionFunctions(sqlite3*db){
static const struct FuncDef {char *zName;signed char nArg;u8 argType; /* 0: none. 1: db 2: (-
1) */
u8 eTextRep; /* 1: UTF-16. 0: UTF-8*/
u8 needCollSeq;void
(*xFunc)(sqlite3_context*,int,sqlite3_value**);
} aFuncs[] = {/* math.h */{ "acos", 1, 0, SQLITE_UTF8, 0,
acosFunc },{ "asin", 1, 0, SQLITE_UTF8, 0,
asinFunc },{ "atan", 1, 0, SQLITE_UTF8, 0,
atanFunc },{ "atn2", 2, 0, SQLITE_UTF8, 0,
atn2Func },/* XXX alias */{ "atan2", 2, 0, SQLITE_UTF8, 0,
atn2Func },{ "acosh", 1, 0, SQLITE_UTF8, 0,
acoshFunc },{ "asinh", 1, 0, SQLITE_UTF8, 0,
asinhFunc },{ "atanh", 1, 0, SQLITE_UTF8, 0,
atanhFunc },
{ "difference", 2, 0, SQLITE_UTF8,
0, differenceFunc},{ "degrees", 1, 0, SQLITE_UTF8,
0, rad2degFunc },{ "radians", 1, 0, SQLITE_UTF8, 0,
deg2radFunc },
{ "cos", 1, 0, SQLITE_UTF8, 0,cosFunc },
{ "sin", 1, 0, SQLITE_UTF8, 0,
sinFunc },{ "tan", 1, 0, SQLITE_UTF8, 0,
tanFunc },{ "cot", 1, 0, SQLITE_UTF8, 0,
-
7/28/2019 extension-functions.c
46/51
-
7/28/2019 extension-functions.c
47/51
ltrimFunc },{ "rtrim", 1, 0, SQLITE_UTF8, 0,
rtrimFunc },{ "trim", 1, 0, SQLITE_UTF8, 0,
trimFunc },{ "replace", 3, 0, SQLITE_UTF8, 0,
replaceFunc },
#endif{ "reverse", 1, 0, SQLITE_UTF8, 0,
reverseFunc },{ "proper", 1, 0, SQLITE_UTF8, 0,
properFunc },{ "padl", 2, 0, SQLITE_UTF8, 0,
padlFunc },{ "padr", 2, 0, SQLITE_UTF8, 0,
padrFunc },
{ "padc", 2, 0, SQLITE_UTF8, 0,padcFunc },
{ "strfilter", 2, 0, SQLITE_UTF8, 0,strfilterFunc },
};/* Aggregate functions */static const struct FuncDefAgg {
char *zName;
signed char nArg;u8 argType;u8 needCollSeq;void
(*xStep)(sqlite3_context*,int,sqlite3_value**);void (*xFinalize)(sqlite3_context*);
} aAggs[] = {{ "stdev", 1, 0, 0, varianceStep,
stdevFinalize },
{ "variance", 1, 0, 0, varianceStep,varianceFinalize },
{ "mode", 1, 0, 0, modeStep,modeFinalize },
{ "median", 1, 0, 0, modeStep,medianFinalize },
{ "lower_quartile", 1, 0, 0, modeStep,lower_quartileFinalize },
{ "upper_quartile", 1, 0, 0, modeStep,
upper_quartileFinalize },};int i;
-
7/28/2019 extension-functions.c
48/51
for(i=0; ineedCollSeq = 1;
}}
#endif}
for(i=0; i
-
7/28/2019 extension-functions.c
49/51
pFunc->needCollSeq = 1;}
}#endif
}return 0;
}
#ifdefCOMPILE_SQLITE_EXTENSIONS_AS_LOADABLE_MODULEint sqlite3_extension_init(
sqlite3 *db, char **pzErrMsg, constsqlite3_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;
return r;}
void* xcalloc(size_t nmemb, size_t size,char* s){
void* ret = calloc(nmemb, size);return ret;
}
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;
-
7/28/2019 extension-functions.c
50/51
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);}
}
-
7/28/2019 extension-functions.c
51/51