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