Skip to content

Commit 01bfa40

Browse files
committed
UDFs from Gary
added unit tests
1 parent ed8f31a commit 01bfa40

File tree

2 files changed

+515
-0
lines changed

2 files changed

+515
-0
lines changed

src/addqueryfuncs.c

Lines changed: 299 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,295 @@ static void sqlite3_strftime(sqlite3_context *context, int argc, sqlite3_value *
229229
sqlite3_result_text(context, buf, -1, SQLITE_TRANSIENT);
230230
}
231231

232+
/*
233+
* Uses any integer. It provides the category that integer is in from
234+
* Zero, O for less than 1000, K for less than 1 million, M less than
235+
* billion, B for less than Trillion, T for less than quadrillion, q
236+
* for less than quintillion, Q for more than Quintillion. (using
237+
* 1000)
238+
*
239+
* Usage:
240+
* SELECT COUNT(*), intcat(int) AS cat
241+
* FROM ..
242+
* GROUP BY cat;
243+
*/
244+
static void intcat(sqlite3_context *context, int argc, sqlite3_value **argv) {
245+
(void) argc;
246+
247+
static const double itK = 1000ULL;
248+
static const double itM = 1000ULL * 1000ULL;
249+
static const double itB = 1000ULL * 1000ULL * 1000ULL;
250+
static const double itT = 1000ULL * 1000ULL * 1000ULL * 1000ULL;
251+
static const double itq = 1000ULL * 1000ULL * 1000ULL * 1000ULL * 1000ULL;
252+
static const double itQ = 1000ULL * 1000ULL * 1000ULL * 1000ULL * 1000ULL * 1000ULL;
253+
254+
const char *intin_s = (const char *) sqlite3_value_text(argv[0]);
255+
256+
double intin = 0;
257+
if (sscanf(intin_s, "%lf", &intin) != 1) {
258+
sqlite3_result_error(context, "Bad size", -1);
259+
return;
260+
}
261+
262+
if (intin < 0) {
263+
sqlite3_result_error(context, "Bad size", -1);
264+
return;
265+
}
266+
267+
char returnintcat[8];
268+
269+
if (intin == 0) {
270+
sprintf(returnintcat, "%s", "Zero");
271+
}
272+
else if (intin < itK) {
273+
sprintf(returnintcat, "%s", "O");
274+
}
275+
else if (intin < itM) {
276+
sprintf(returnintcat, "%s", "K");
277+
}
278+
else if (intin < itB) {
279+
sprintf(returnintcat, "%s", "M");
280+
}
281+
else if (intin < itT) {
282+
sprintf(returnintcat, "%s", "B");
283+
}
284+
else if (intin < itq) {
285+
sprintf(returnintcat, "%s", "T");
286+
}
287+
else if (intin < itQ) {
288+
sprintf(returnintcat, "%s", "q");
289+
}
290+
else {
291+
sprintf(returnintcat, "%s", "Q");
292+
}
293+
294+
sqlite3_result_text(context, returnintcat, -1, SQLITE_TRANSIENT);
295+
}
296+
297+
/*
298+
* Uses any integer. Provides category from Zero, B for less than 1k,
299+
* K for less than 1M, M for less than 1G, G for less than 1T, T for
300+
* less than one P, P for less than 1E, E for more than 1E. (using
301+
* 1024)
302+
*
303+
* Usage:
304+
* SELECT COUNT(*), bytecat(int) AS cat
305+
* FROM ..
306+
* GROUP BY cat;
307+
*/
308+
static void bytecat(sqlite3_context *context, int argc, sqlite3_value **argv) {
309+
(void) argc;
310+
311+
static const double btk = 1024ULL;
312+
static const double btm = 1024ULL * 1024ULL;
313+
static const double btg = 1024ULL * 1024ULL * 1024ULL;
314+
static const double btt = 1024ULL * 1024ULL * 1024ULL * 1024ULL;
315+
static const double btp = 1024ULL * 1024ULL * 1024ULL * 1024ULL * 1024ULL;
316+
static const double bte = 1024ULL * 1024ULL * 1024ULL * 1024ULL * 1024ULL * 1024ULL;
317+
318+
const char *bytein_s = (const char *) sqlite3_value_text(argv[0]);
319+
fprintf(stderr, "%s %lf %lf\n", bytein_s, btp, bte);
320+
321+
double bytein = 0;
322+
if (sscanf(bytein_s, "%lf", &bytein) != 1) {
323+
sqlite3_result_error(context, "Bad size", -1);
324+
return;
325+
}
326+
327+
if (bytein < 0) {
328+
sqlite3_result_error(context, "Bad size", -1);
329+
return;
330+
}
331+
332+
char returnbytecat[8];
333+
334+
if (bytein == 0) {
335+
sprintf(returnbytecat, "%s", "Zero");
336+
}
337+
else if (bytein < btk) {
338+
sprintf(returnbytecat, "%s", "B");
339+
}
340+
else if (bytein < btm) {
341+
sprintf(returnbytecat, "%s", "K");
342+
}
343+
else if (bytein < btg) {
344+
sprintf(returnbytecat, "%s", "M");
345+
}
346+
else if (bytein < btt) {
347+
sprintf(returnbytecat, "%s", "G");
348+
}
349+
else if (bytein < btp) {
350+
sprintf(returnbytecat, "%s", "T");
351+
}
352+
else if (bytein < bte) {
353+
sprintf(returnbytecat, "%s", "P");
354+
}
355+
else {
356+
sprintf(returnbytecat, "%s", "E");
357+
}
358+
359+
sqlite3_result_text(context, returnbytecat, -1, SQLITE_TRANSIENT);
360+
}
361+
362+
/*
363+
* Uses any unix epoch like mtime as input. It subtracts that from
364+
* current time and categorizes into S seconds, M minutes, H hours, d
365+
* days, W weeks, M months, Y years, D decades as categories. (for use
366+
* in group by)
367+
*
368+
* Usage:
369+
* SELECT COUNT(*), agecat(time) AS cat
370+
* FROM ..
371+
* GROUP BY cat;
372+
*/
373+
static void agecat(sqlite3_context *context, int argc, sqlite3_value **argv) {
374+
(void) argc;
375+
376+
static const double secinm = 60;
377+
static const double secinh = secinm * 60;
378+
static const double secind = secinh * 24;
379+
static const double secinw = secind * 7;
380+
static const double secinM = secind * 30;
381+
static const double seciny = secind * 365;
382+
static const double secinD = seciny * 10;
383+
384+
const char *timein_s = (const char *) sqlite3_value_text(argv[0]);
385+
386+
double timein;
387+
if (sscanf(timein_s, "%lf", &timein) != 1) {
388+
sqlite3_result_error(context, "Bad size", -1);
389+
return;
390+
}
391+
392+
const double ageinsec = time(NULL) - timein;
393+
394+
char returnagecat[32];
395+
396+
if (ageinsec < 0) {
397+
sqlite3_result_error(context, "Bad timestamp", -1);
398+
return;
399+
}
400+
else if (ageinsec == 0) {
401+
sprintf(returnagecat, "%s", "Zero");
402+
}
403+
else if (ageinsec < secinm) {
404+
sprintf(returnagecat, "%s", "Secs");
405+
}
406+
else if (ageinsec < secinh) {
407+
sprintf(returnagecat, "%s", "Mins");
408+
}
409+
else if (ageinsec < secind) {
410+
sprintf(returnagecat, "%s", "Hrs");
411+
}
412+
else if (ageinsec < secinw) {
413+
sprintf(returnagecat, "%s", "Days");
414+
}
415+
else if (ageinsec < secinM) {
416+
sprintf(returnagecat, "%s", "Wks");
417+
}
418+
else if (ageinsec < seciny) {
419+
sprintf(returnagecat, "%s", "Mos");
420+
}
421+
else if (ageinsec < secinD) {
422+
sprintf(returnagecat, "%s", "Yrs");
423+
}
424+
else {
425+
sprintf(returnagecat, "%s", "Decs");
426+
}
427+
428+
sqlite3_result_text(context, returnagecat, -1, SQLITE_TRANSIENT);
429+
}
430+
431+
/*
432+
* Provides age from now from unix epoch time fields like mtime,
433+
* ctime, atime, crtime. Unit s (seconds), m (minutes), h (hours), d
434+
* (days), w (weeks), M (months), y (years), D (decades). (for use in
435+
* group by)
436+
*
437+
* Usage:
438+
* SELECT COUNT(*), epochtoage(time, unit) AS cat
439+
* FROM ..
440+
* GROUP BY cat;
441+
*/
442+
static void epochtoage(sqlite3_context *context, int argc, sqlite3_value **argv) {
443+
(void) argc;
444+
445+
static const int64_t secins = 1;
446+
static const int64_t secinm = 60;
447+
static const int64_t secinh = secinm * 60;
448+
static const int64_t secind = secinh * 24;
449+
static const int64_t secinw = secind * 7;
450+
static const int64_t secinM = secind * 30;
451+
static const int64_t seciny = secind * 365;
452+
static const int64_t secinD = seciny * 10;
453+
454+
const char *timein_s = (const char *) sqlite3_value_text(argv[0]);
455+
const char *unit_s = (const char *) sqlite3_value_text(argv[1]);
456+
457+
double timein;
458+
if (sscanf(timein_s, "%lf", &timein) != 1) {
459+
sqlite3_result_error(context, "Bad size", -1);
460+
return;
461+
}
462+
463+
const int64_t ageinsec = time(NULL) - timein;
464+
if (ageinsec < 0) {
465+
sqlite3_result_error(context, "Bad timestamp", -1);
466+
return;
467+
}
468+
469+
/* default to day */
470+
int64_t unit = 0;
471+
switch (*unit_s) {
472+
case 's':
473+
unit = secins;
474+
break;
475+
case 'm':
476+
unit = secinm;
477+
break;
478+
case 'h':
479+
unit = secinh;
480+
break;
481+
case 'd':
482+
unit = secind;
483+
break;
484+
case 'w':
485+
unit = secinw;
486+
break;
487+
case 'M':
488+
unit = secinM;
489+
break;
490+
case 'y':
491+
unit = seciny;
492+
break;
493+
case 'D':
494+
unit = secinD;
495+
break;
496+
default:
497+
unit = secind;
498+
break;
499+
}
500+
501+
sqlite3_result_int64(context, ageinsec / unit);
502+
}
503+
504+
/*
505+
* return the hostname running gufi_query
506+
*
507+
* Usage:
508+
* SELECT hostname();
509+
*/
510+
static void hostname(sqlite3_context *context, int argc, sqlite3_value **argv)
511+
{
512+
(void) argc; (void) argv;
513+
514+
char hostname[256] = "NOHOST";
515+
gethostname(hostname, sizeof(hostname));
516+
hostname[255] = '\0'; /* force terminate in case gethostname(2) errored */
517+
518+
sqlite3_result_text(context, hostname, -1, SQLITE_TRANSIENT);
519+
}
520+
232521
/* uint64_t goes up to E */
233522
static const char SIZE[] = {'K', 'M', 'G', 'T', 'P', 'E'};
234523

@@ -925,6 +1214,16 @@ int addqueryfuncs(sqlite3 *db) {
9251214
NULL, &sqlite3_strftime, NULL, NULL) == SQLITE_OK) &&
9261215
(sqlite3_create_function(db, "blocksize", 2, SQLITE_UTF8,
9271216
NULL, &blocksize, NULL, NULL) == SQLITE_OK) &&
1217+
(sqlite3_create_function(db, "intcat", 1, SQLITE_UTF8,
1218+
NULL, &intcat, NULL, NULL) == SQLITE_OK) &&
1219+
(sqlite3_create_function(db, "bytecat", 1, SQLITE_UTF8,
1220+
NULL, &bytecat, NULL, NULL) == SQLITE_OK) &&
1221+
(sqlite3_create_function(db, "agecat", 1, SQLITE_UTF8,
1222+
NULL, &agecat, NULL, NULL) == SQLITE_OK) &&
1223+
(sqlite3_create_function(db, "epochtoage", 2, SQLITE_UTF8,
1224+
NULL, &epochtoage, NULL, NULL) == SQLITE_OK) &&
1225+
(sqlite3_create_function(db, "hostname", 0, SQLITE_UTF8,
1226+
NULL, &hostname, NULL, NULL) == SQLITE_OK) &&
9281227
(sqlite3_create_function(db, "human_readable_size", 1, SQLITE_UTF8,
9291228
NULL, &human_readable_size, NULL, NULL) == SQLITE_OK) &&
9301229
(sqlite3_create_function(db, "basename", 1, SQLITE_UTF8,

0 commit comments

Comments
 (0)