modernc.org/cc@v1.0.1/v2/testdata/_sqlite/ext/misc/percentile.c (about) 1 /* 2 ** 2013-05-28 3 ** 4 ** The author disclaims copyright to this source code. In place of 5 ** a legal notice, here is a blessing: 6 ** 7 ** May you do good and not evil. 8 ** May you find forgiveness for yourself and forgive others. 9 ** May you share freely, never taking more than you give. 10 ** 11 ****************************************************************************** 12 ** 13 ** This file contains code to implement the percentile(Y,P) SQL function 14 ** as described below: 15 ** 16 ** (1) The percentile(Y,P) function is an aggregate function taking 17 ** exactly two arguments. 18 ** 19 ** (2) If the P argument to percentile(Y,P) is not the same for every 20 ** row in the aggregate then an error is thrown. The word "same" 21 ** in the previous sentence means that the value differ by less 22 ** than 0.001. 23 ** 24 ** (3) If the P argument to percentile(Y,P) evaluates to anything other 25 ** than a number in the range of 0.0 to 100.0 inclusive then an 26 ** error is thrown. 27 ** 28 ** (4) If any Y argument to percentile(Y,P) evaluates to a value that 29 ** is not NULL and is not numeric then an error is thrown. 30 ** 31 ** (5) If any Y argument to percentile(Y,P) evaluates to plus or minus 32 ** infinity then an error is thrown. (SQLite always interprets NaN 33 ** values as NULL.) 34 ** 35 ** (6) Both Y and P in percentile(Y,P) can be arbitrary expressions, 36 ** including CASE WHEN expressions. 37 ** 38 ** (7) The percentile(Y,P) aggregate is able to handle inputs of at least 39 ** one million (1,000,000) rows. 40 ** 41 ** (8) If there are no non-NULL values for Y, then percentile(Y,P) 42 ** returns NULL. 43 ** 44 ** (9) If there is exactly one non-NULL value for Y, the percentile(Y,P) 45 ** returns the one Y value. 46 ** 47 ** (10) If there N non-NULL values of Y where N is two or more and 48 ** the Y values are ordered from least to greatest and a graph is 49 ** drawn from 0 to N-1 such that the height of the graph at J is 50 ** the J-th Y value and such that straight lines are drawn between 51 ** adjacent Y values, then the percentile(Y,P) function returns 52 ** the height of the graph at P*(N-1)/100. 53 ** 54 ** (11) The percentile(Y,P) function always returns either a floating 55 ** point number or NULL. 56 ** 57 ** (12) The percentile(Y,P) is implemented as a single C99 source-code 58 ** file that compiles into a shared-library or DLL that can be loaded 59 ** into SQLite using the sqlite3_load_extension() interface. 60 */ 61 #include "sqlite3ext.h" 62 SQLITE_EXTENSION_INIT1 63 #include <assert.h> 64 #include <string.h> 65 #include <stdlib.h> 66 67 /* The following object is the session context for a single percentile() 68 ** function. We have to remember all input Y values until the very end. 69 ** Those values are accumulated in the Percentile.a[] array. 70 */ 71 typedef struct Percentile Percentile; 72 struct Percentile { 73 unsigned nAlloc; /* Number of slots allocated for a[] */ 74 unsigned nUsed; /* Number of slots actually used in a[] */ 75 double rPct; /* 1.0 more than the value for P */ 76 double *a; /* Array of Y values */ 77 }; 78 79 /* 80 ** Return TRUE if the input floating-point number is an infinity. 81 */ 82 static int isInfinity(double r){ 83 sqlite3_uint64 u; 84 assert( sizeof(u)==sizeof(r) ); 85 memcpy(&u, &r, sizeof(u)); 86 return ((u>>52)&0x7ff)==0x7ff; 87 } 88 89 /* 90 ** Return TRUE if two doubles differ by 0.001 or less 91 */ 92 static int sameValue(double a, double b){ 93 a -= b; 94 return a>=-0.001 && a<=0.001; 95 } 96 97 /* 98 ** The "step" function for percentile(Y,P) is called once for each 99 ** input row. 100 */ 101 static void percentStep(sqlite3_context *pCtx, int argc, sqlite3_value **argv){ 102 Percentile *p; 103 double rPct; 104 int eType; 105 double y; 106 assert( argc==2 ); 107 108 /* Requirement 3: P must be a number between 0 and 100 */ 109 eType = sqlite3_value_numeric_type(argv[1]); 110 rPct = sqlite3_value_double(argv[1]); 111 if( (eType!=SQLITE_INTEGER && eType!=SQLITE_FLOAT) || 112 ((rPct = sqlite3_value_double(argv[1]))<0.0 || rPct>100.0) ){ 113 sqlite3_result_error(pCtx, "2nd argument to percentile() is not " 114 "a number between 0.0 and 100.0", -1); 115 return; 116 } 117 118 /* Allocate the session context. */ 119 p = (Percentile*)sqlite3_aggregate_context(pCtx, sizeof(*p)); 120 if( p==0 ) return; 121 122 /* Remember the P value. Throw an error if the P value is different 123 ** from any prior row, per Requirement (2). */ 124 if( p->rPct==0.0 ){ 125 p->rPct = rPct+1.0; 126 }else if( !sameValue(p->rPct,rPct+1.0) ){ 127 sqlite3_result_error(pCtx, "2nd argument to percentile() is not the " 128 "same for all input rows", -1); 129 return; 130 } 131 132 /* Ignore rows for which Y is NULL */ 133 eType = sqlite3_value_type(argv[0]); 134 if( eType==SQLITE_NULL ) return; 135 136 /* If not NULL, then Y must be numeric. Otherwise throw an error. 137 ** Requirement 4 */ 138 if( eType!=SQLITE_INTEGER && eType!=SQLITE_FLOAT ){ 139 sqlite3_result_error(pCtx, "1st argument to percentile() is not " 140 "numeric", -1); 141 return; 142 } 143 144 /* Throw an error if the Y value is infinity or NaN */ 145 y = sqlite3_value_double(argv[0]); 146 if( isInfinity(y) ){ 147 sqlite3_result_error(pCtx, "Inf input to percentile()", -1); 148 return; 149 } 150 151 /* Allocate and store the Y */ 152 if( p->nUsed>=p->nAlloc ){ 153 unsigned n = p->nAlloc*2 + 250; 154 double *a = sqlite3_realloc(p->a, sizeof(double)*n); 155 if( a==0 ){ 156 sqlite3_free(p->a); 157 memset(p, 0, sizeof(*p)); 158 sqlite3_result_error_nomem(pCtx); 159 return; 160 } 161 p->nAlloc = n; 162 p->a = a; 163 } 164 p->a[p->nUsed++] = y; 165 } 166 167 /* 168 ** Compare to doubles for sorting using qsort() 169 */ 170 static int SQLITE_CDECL doubleCmp(const void *pA, const void *pB){ 171 double a = *(double*)pA; 172 double b = *(double*)pB; 173 if( a==b ) return 0; 174 if( a<b ) return -1; 175 return +1; 176 } 177 178 /* 179 ** Called to compute the final output of percentile() and to clean 180 ** up all allocated memory. 181 */ 182 static void percentFinal(sqlite3_context *pCtx){ 183 Percentile *p; 184 unsigned i1, i2; 185 double v1, v2; 186 double ix, vx; 187 p = (Percentile*)sqlite3_aggregate_context(pCtx, 0); 188 if( p==0 ) return; 189 if( p->a==0 ) return; 190 if( p->nUsed ){ 191 qsort(p->a, p->nUsed, sizeof(double), doubleCmp); 192 ix = (p->rPct-1.0)*(p->nUsed-1)*0.01; 193 i1 = (unsigned)ix; 194 i2 = ix==(double)i1 || i1==p->nUsed-1 ? i1 : i1+1; 195 v1 = p->a[i1]; 196 v2 = p->a[i2]; 197 vx = v1 + (v2-v1)*(ix-i1); 198 sqlite3_result_double(pCtx, vx); 199 } 200 sqlite3_free(p->a); 201 memset(p, 0, sizeof(*p)); 202 } 203 204 205 #ifdef _WIN32 206 __declspec(dllexport) 207 #endif 208 int sqlite3_percentile_init( 209 sqlite3 *db, 210 char **pzErrMsg, 211 const sqlite3_api_routines *pApi 212 ){ 213 int rc = SQLITE_OK; 214 SQLITE_EXTENSION_INIT2(pApi); 215 (void)pzErrMsg; /* Unused parameter */ 216 rc = sqlite3_create_function(db, "percentile", 2, SQLITE_UTF8, 0, 217 0, percentStep, percentFinal); 218 return rc; 219 }