-
Notifications
You must be signed in to change notification settings - Fork 0
/
mode.c
128 lines (121 loc) · 3.05 KB
/
mode.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#include "sqlite3ext.h"
SQLITE_EXTENSION_INIT1
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include "modemath.h"
typedef struct AggregateData
{
int init;
ModeData modeData;
} AggregateData;
static AggregateData *
getData(sqlite3_context *context)
{
AggregateData *data = (AggregateData *)sqlite3_aggregate_context(context, sizeof(AggregateData));
if (!data)
{
sqlite3_result_error_nomem(context);
}
if (!data->init)
{
if (modeDataInit(&data->modeData) != MODE_OK)
{
char *err = "mode data init error";
sqlite3_result_error(context, err, strlen(err));
return NULL;
}
data->init = 1;
}
return data;
}
static void modeStep(
sqlite3_context *context,
int argc,
sqlite3_value **argv)
{
assert(argc == 1);
AggregateData *data = getData(context);
if (!data)
{
return;
}
switch (sqlite3_value_type(argv[0]))
{
case SQLITE_INTEGER:
// TODO: support ints natively, without float conversion
case SQLITE_FLOAT:
{
double value = sqlite3_value_double(argv[0]);
if (modeAddValue(&data->modeData, value) != MODE_OK)
{
char *err = "mode calculation error in step";
sqlite3_result_error(context, err, strlen(err));
goto stop;
}
}
break;
}
return;
stop:
modeDataFinish(&data->modeData);
}
static void modeFinal(
sqlite3_context *context)
{
AggregateData *data = getData(context);
if (!data)
{
return;
}
double result;
int hasResult;
if (computeMode(&data->modeData, &result, &hasResult) != MODE_OK)
{
char *err = "mode calculation error in final";
sqlite3_result_error(context, err, strlen(err));
goto finish;
}
if (hasResult)
{
sqlite3_result_double(context, result);
}
else
{
sqlite3_result_null(context);
}
finish:
modeDataFinish(&data->modeData);
}
int sqlite3_mode_init(
sqlite3 *db,
char **pzErrMsg,
const sqlite3_api_routines *pApi)
{
int rc = SQLITE_OK;
SQLITE_EXTENSION_INIT2(pApi);
// // register as auto extension
// rc = sqlite3_auto_extension((void (*)(void))mode_EntryPoint);
// // set error message
// char *errStr = "Hey!";
// *pzErrMsg = (char *)sqlite3_malloc64(strlen(errStr));
// if (*pzErrMsg)
// {
// strcpy(*pzErrMsg, errStr);
// }
// // register scalar function
// rc = sqlite3_create_function(db, "one", 1,
// SQLITE_UTF8 | SQLITE_DIRECTONLY | SQLITE_DETERMINISTIC,
// 0, one, 0, 0);
// register aggregate function
if (rc == SQLITE_OK)
{
rc = sqlite3_create_function(db, "mode", 1,
SQLITE_UTF8 | SQLITE_DIRECTONLY | SQLITE_DETERMINISTIC,
0, 0, modeStep, modeFinal);
}
// // is this ok?
// if (rc == SQLITE_OK)
// rc = SQLITE_OK_LOAD_PERMANENTLY;
return rc;
}