@@ -1406,6 +1406,25 @@ struct ModeCtx {
14061406 int done; /* whether the answer has been found */
14071407};
14081408
1409+ /*
1410+ ** Like ModeCtx, but with an additional integer or double argument.
1411+ ** Used for computing arbitrary quantiles as aggregates with quantile()
1412+ */
1413+ typedef struct ModeArgCtx ModeArgCtx;
1414+ struct ModeArgCtx {
1415+ i64 riM; /* integer value found so far */
1416+ double rdM; /* double value found so far */
1417+ i64 cnt; /* number of elements so far */
1418+ double pcnt; /* number of elements smaller than a percentile */
1419+ i64 mcnt; /* maximum number of occurrences (for mode) */
1420+ i64 mn; /* number of occurrences (for mode and percentiles) */
1421+ i64 is_double; /* whether the computation is being done for doubles (>0) or integers (=0) */
1422+ map* m; /* map structure used for the computation */
1423+ i64 argi; /* integer argument */
1424+ double argd; /* double argument */
1425+ int done; /* whether the answer has been found */
1426+ };
1427+
14091428/*
14101429** called for each value received during a calculation of stdev or variance
14111430*/
@@ -1474,6 +1493,63 @@ static void modeStep(sqlite3_context *context, int argc, sqlite3_value **argv){
14741493 }
14751494}
14761495
1496+
1497+ /*
1498+ ** called for each value received during a calculation of mode of median
1499+ */
1500+ static void modeStepArg (sqlite3_context *context, int argc, sqlite3_value **argv){
1501+ ModeArgCtx *p;
1502+ i64 xi=0 ;
1503+ double xd=0.0 ;
1504+ i64 *iptr;
1505+ double *dptr;
1506+ int type1, type2;
1507+
1508+ ASSERT ( argc==2 );
1509+ type1 = sqlite3_value_numeric_type (argv[0 ]);
1510+ type2 = sqlite3_value_numeric_type (argv[1 ]);
1511+
1512+ if ( type1 == SQLITE_NULL || type2 == SQLITE_NULL)
1513+ return ;
1514+
1515+ p = (ModeArgCtx*)sqlite3_aggregate_context (context, sizeof (*p));
1516+
1517+ if ( 0 ==(p->m ) ){
1518+ p->m = (map*)calloc (1 , sizeof (map));
1519+ if ( type1==SQLITE_INTEGER ){
1520+ /* map will be used for integers */
1521+ *(p->m ) = map_make (int_cmp);
1522+ p->is_double = 0 ;
1523+ }else {
1524+ p->is_double = 1 ;
1525+ /* map will be used for doubles */
1526+ *(p->m ) = map_make (double_cmp);
1527+ }
1528+ /* parse the argument */
1529+ if ( type2==SQLITE_INTEGER ){
1530+ /* integer argument */
1531+ p->argi = sqlite3_value_int64 (argv[0 ]);
1532+ }else {
1533+ /* double argument */
1534+ p->argd = sqlite3_value_double (argv[1 ]);
1535+ }
1536+ }
1537+
1538+ ++(p->cnt );
1539+
1540+ if ( 0 ==p->is_double ){
1541+ xi = sqlite3_value_int64 (argv[0 ]);
1542+ iptr = (i64 *)calloc (1 ,sizeof (i64 ));
1543+ *iptr = xi;
1544+ map_insert (p->m , iptr);
1545+ }else {
1546+ xd = sqlite3_value_double (argv[0 ]);
1547+ dptr = (double *)calloc (1 ,sizeof (double ));
1548+ *dptr = xd;
1549+ map_insert (p->m , dptr);
1550+ }
1551+ }
1552+
14771553/*
14781554** Auxiliary function that iterates all elements in a map and finds the mode
14791555** (most frequent value)
@@ -1623,6 +1699,20 @@ static void upper_quartileFinalize(sqlite3_context *context){
16231699 }
16241700}
16251701
1702+ /*
1703+ ** Returns an arbitrary quantile
1704+ ** The quantile was passed to the step function
1705+ */
1706+ static void quantileFinalize (sqlite3_context *context){
1707+ ModeArgCtx *p;
1708+ p = (ModeArgCtx*) sqlite3_aggregate_context (context, 0 );
1709+ if ( p!=0 ){
1710+ /* quantile is stored in p->arg */
1711+ p->pcnt = (p->cnt )*(p->argd );
1712+ _medianFinalize (context);
1713+ }
1714+ }
1715+
16261716/*
16271717** Returns the stdev value
16281718*/
@@ -1812,6 +1902,7 @@ int RegisterExtensionFunctions(sqlite3 *db){
18121902 { " median" , 1 , 0 , 0 , modeStep, medianFinalize },
18131903 { " lower_quartile" , 1 , 0 , 0 , modeStep, lower_quartileFinalize },
18141904 { " upper_quartile" , 1 , 0 , 0 , modeStep, upper_quartileFinalize },
1905+ { " quantile" , 2 , 0 , 0 , modeStepArg, quantileFinalize },
18151906 };
18161907 unsigned int i;
18171908
0 commit comments