2665165a0970e98075a702bbea020e3803e35cab
1 /*
2 * SysDB - src/core/data.c
3 * Copyright (C) 2014 Sebastian 'tokkee' Harl <sh@tokkee.org>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
28 #if HAVE_CONFIG_H
29 # include "config.h"
30 #endif /* HAVE_CONFIG_H */
32 #include "sysdb.h"
34 #include "core/data.h"
35 #include "utils/error.h"
37 #include <assert.h>
39 #include <errno.h>
41 #include <inttypes.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
47 #include <math.h>
49 /*
50 * Operator support maxtrix.
51 * <type1> <op> <type2> -> op_matrix[<op>][<type1>][<type2>]
52 */
54 /* add, sub, mul, div, mod, concat */
56 /* integer, decimal, string, datetime, binary, regex */
58 static int op_matrix[6][6][6] = {
59 /* SDB_DATA_ADD */
60 {
61 { SDB_TYPE_INTEGER, -1, -1, -1, -1, -1 },
62 { -1, SDB_TYPE_DECIMAL, -1, -1, -1, -1 },
63 { -1, -1, -1, -1, -1, -1 },
64 { -1, -1, -1, SDB_TYPE_DATETIME, -1, -1 },
65 { -1, -1, -1, -1, -1, -1 },
66 { -1, -1, -1, -1, -1, -1 },
67 },
69 /* SDB_DATA_SUB */
70 {
71 { SDB_TYPE_INTEGER, -1, -1, -1, -1, -1 },
72 { -1, SDB_TYPE_DECIMAL, -1, -1, -1, -1 },
73 { -1, -1, -1, -1, -1, -1 },
74 { -1, -1, -1, SDB_TYPE_DATETIME, -1, -1 },
75 { -1, -1, -1, -1, -1, -1 },
76 { -1, -1, -1, -1, -1, -1 },
77 },
79 /* SDB_DATA_MUL */
80 {
81 { SDB_TYPE_INTEGER, -1, -1, SDB_TYPE_DATETIME, -1, -1 },
82 { -1, SDB_TYPE_DECIMAL, -1, SDB_TYPE_DATETIME, -1, -1 },
83 { -1, -1, -1, -1, -1, -1 },
84 { SDB_TYPE_DATETIME, SDB_TYPE_DATETIME, -1, SDB_TYPE_DATETIME, -1, -1 },
85 { -1, -1, -1, -1, -1, -1 },
86 { -1, -1, -1, -1, -1, -1 },
87 },
89 /* SDB_DATA_DIV */
90 {
91 { SDB_TYPE_INTEGER, -1, -1, -1, -1, -1 },
92 { -1, SDB_TYPE_DECIMAL, -1, -1, -1, -1 },
93 { -1, -1, -1, -1, -1, -1 },
94 { SDB_TYPE_DATETIME, SDB_TYPE_DATETIME, -1, SDB_TYPE_DATETIME, -1, -1 },
95 { -1, -1, -1, -1, -1, -1 },
96 { -1, -1, -1, -1, -1, -1 },
97 },
99 /* SDB_DATA_MOD */
100 {
101 { SDB_TYPE_INTEGER, -1, -1, -1, -1, -1 },
102 { -1, SDB_TYPE_DECIMAL, -1, -1, -1, -1 },
103 { -1, -1, -1, -1, -1, -1 },
104 { SDB_TYPE_DATETIME, SDB_TYPE_DATETIME, -1, SDB_TYPE_DATETIME, -1, -1 },
105 { -1, -1, -1, -1, -1, -1 },
106 { -1, -1, -1, -1, -1, -1 },
107 },
109 /* SDB_DATA_CONCAT */
110 {
111 { -1, -1, -1, -1, -1, -1 },
112 { -1, -1, -1, -1, -1, -1 },
113 { -1, -1, SDB_TYPE_STRING, -1, -1, -1 },
114 { -1, -1, -1, -1, -1, -1 },
115 { -1, -1, -1, -1, SDB_TYPE_BINARY, -1 },
116 { -1, -1, -1, -1, -1, -1 },
117 },
118 };
120 /*
121 * private helper functions
122 */
124 /* this function supports in-place copies */
125 static int
126 copy_array_values(sdb_data_t *dst, const sdb_data_t *src, size_t elem_size)
127 {
128 int type = src->type & 0xff;
130 if ((type == SDB_TYPE_INTEGER) || (type == SDB_TYPE_DECIMAL)) {
131 if (dst != src)
132 memcpy(dst->data.array.values, src->data.array.values,
133 src->data.array.length * elem_size);
134 }
135 else if (type == SDB_TYPE_STRING) {
136 char **s = src->data.array.values;
137 char **d = dst->data.array.values;
138 size_t i;
140 for (i = 0; i < src->data.array.length; ++i) {
141 d[i] = strdup(s[i]);
142 if (! d[i])
143 return -1;
144 }
145 }
146 else {
147 /* TODO */
148 errno = ENOTSUP;
149 return -1;
150 }
151 return 0;
152 } /* copy_array_values */
154 static void
155 free_array_values(sdb_data_t *datum)
156 {
157 int type = datum->type & 0xff;
159 if (type == SDB_TYPE_STRING) {
160 char **v = datum->data.array.values;
161 size_t i;
163 for (i = 0; i < datum->data.array.length; ++i) {
164 if (v[i])
165 free(v[i]);
166 v[i] = NULL;
167 }
168 }
169 } /* free_array_values */
171 /* compare two arrays element-by-element returning how the first non-equal
172 * elements compare to each other */
173 static int
174 array_cmp(const sdb_data_t *a1, const sdb_data_t *a2)
175 {
176 int type = a1->type & 0xff;
177 size_t len, i;
179 assert((a1->type == a2->type) && (a1->type & SDB_TYPE_ARRAY));
181 len = SDB_MIN(a1->data.array.length, a2->data.array.length);
183 if (type == SDB_TYPE_INTEGER) {
184 int64_t *v1 = a1->data.array.values;
185 int64_t *v2 = a2->data.array.values;
187 for (i = 0; i < len; ++i)
188 if (v1[i] != v2[i])
189 return SDB_CMP(v1[i], v2[i]);
190 }
191 else if (type == SDB_TYPE_DECIMAL) {
192 double *v1 = a1->data.array.values;
193 double *v2 = a2->data.array.values;
195 for (i = 0; i < len; ++i)
196 if (v1[i] != v2[i])
197 return SDB_CMP(v1[i], v2[i]);
198 }
199 else if (type == SDB_TYPE_STRING) {
200 char **v1 = a1->data.array.values;
201 char **v2 = a2->data.array.values;
203 for (i = 0; i < len; ++i) {
204 int diff = strcasecmp(v1[i], v2[i]);
205 if (diff)
206 return diff;
207 }
208 }
209 else if (type == SDB_TYPE_DATETIME) {
210 sdb_time_t *v1 = a1->data.array.values;
211 sdb_time_t *v2 = a2->data.array.values;
213 for (i = 0; i < len; ++i)
214 if (v1[i] != v2[i])
215 return SDB_CMP(v1[i], v2[i]);
216 }
217 else if (type == SDB_TYPE_BINARY) {
218 struct {
219 size_t length;
220 unsigned char *datum;
221 } *v1 = a1->data.array.values;
222 struct {
223 size_t length;
224 unsigned char *datum;
225 } *v2 = a2->data.array.values;
227 for (i = 0; i < len; ++i) {
228 int diff;
230 /* on a common prefix, the shorter datum sorts less */
231 if (v1[i].length < v2[i].length) {
232 diff = memcmp(v1[i].datum, v2[i].datum, v1[i].length);
233 diff = diff ? diff : -1;
234 }
235 else if (v1[i].length > v2[i].length) {
236 diff = memcmp(v1[i].datum, v2[i].datum, v2[i].length);
237 diff = diff ? diff : 1;
238 }
239 else
240 diff = memcmp(v1[i].datum, v2[i].datum, v1[i].length);
242 if (diff)
243 return diff;
244 }
245 }
246 else if (type == SDB_TYPE_REGEX) {
247 struct {
248 char *raw;
249 regex_t regex;
250 } *v1 = a1->data.array.values;
251 struct {
252 char *raw;
253 regex_t regex;
254 } *v2 = a2->data.array.values;
256 for (i = 0; i < len; ++i) {
257 int diff = strcasecmp(v1[i].raw, v2[i].raw);
258 if (diff)
259 return diff;
260 }
261 }
262 else {
263 errno = EINVAL;
264 /* but fall through to ensure stable sorting: */
265 }
266 return SDB_CMP(a1->data.array.length, a2->data.array.length);
267 } /* array_cmp */
269 /* Calculate the linear function 'd1 + n * d2'. */
270 static int
271 data_lin(const sdb_data_t *d1, int n, const sdb_data_t *d2, sdb_data_t *res)
272 {
273 if (d1->type != d2->type)
274 return -1;
276 if (d1->type == SDB_TYPE_INTEGER)
277 res->data.integer = d1->data.integer + (int64_t)n * d2->data.integer;
278 else if (d1->type == SDB_TYPE_DECIMAL)
279 res->data.decimal = d1->data.decimal + (double)n * d2->data.decimal;
280 else if (d1->type == SDB_TYPE_DATETIME)
281 res->data.datetime = d1->data.datetime + (sdb_time_t)n * d2->data.datetime;
282 else
283 return -1;
284 res->type = d1->type;
285 return 0;
286 } /* data_lin */
288 /* Multiply d1 with d2. */
289 static int
290 data_mul(const sdb_data_t *d1, const sdb_data_t *d2, sdb_data_t *res)
291 {
292 if (d1->type == SDB_TYPE_INTEGER) {
293 if (d2->type == SDB_TYPE_INTEGER)
294 res->data.integer = d1->data.integer * d2->data.integer;
295 else if (d2->type == SDB_TYPE_DATETIME) {
296 res->data.datetime = (sdb_time_t)d1->data.integer
297 * d2->data.datetime;
298 res->type = SDB_TYPE_DATETIME;
299 return 0;
300 }
301 else
302 return -1;
303 }
304 else if (d1->type == SDB_TYPE_DECIMAL) {
305 if (d2->type == SDB_TYPE_DECIMAL)
306 res->data.decimal = d1->data.decimal * d2->data.decimal;
307 else if (d2->type == SDB_TYPE_DATETIME) {
308 res->data.datetime = (sdb_time_t)(d1->data.decimal
309 * (double)d2->data.datetime);
310 res->type = SDB_TYPE_DATETIME;
311 return 0;
312 }
313 else
314 return -1;
315 }
316 else if (d1->type == SDB_TYPE_DATETIME) {
317 if (d2->type == SDB_TYPE_DATETIME)
318 res->data.datetime = d1->data.datetime
319 * d2->data.datetime;
320 else if (d2->type == SDB_TYPE_INTEGER)
321 res->data.datetime = d1->data.datetime
322 * (sdb_time_t)d2->data.integer;
323 else if (d2->type == SDB_TYPE_DECIMAL)
324 res->data.datetime = (sdb_time_t)((double)d1->data.datetime
325 * d2->data.decimal);
326 else
327 return -1;
328 }
329 else
330 return -1;
332 res->type = d1->type;
333 return 0;
334 } /* data_mul */
336 /* Device d1 by d2 and return the result and the remainder. */
337 static int
338 data_div(const sdb_data_t *d1, const sdb_data_t *d2,
339 sdb_data_t *res, sdb_data_t *rem)
340 {
341 if (d1->type == SDB_TYPE_INTEGER) {
342 if (d2->type != SDB_TYPE_INTEGER)
343 return -1;
344 if (res)
345 res->data.integer = d1->data.integer / d2->data.integer;
346 if (rem)
347 rem->data.integer = d1->data.integer % d2->data.integer;
348 }
349 else if (d1->type == SDB_TYPE_DECIMAL) {
350 if (d2->type != SDB_TYPE_DECIMAL)
351 return -1;
352 if (res)
353 res->data.decimal = d1->data.decimal / d2->data.decimal;
354 if (rem)
355 rem->data.decimal = fmod(d1->data.decimal, d2->data.decimal);
356 }
357 else if (d1->type == SDB_TYPE_DATETIME) {
358 if (d2->type == SDB_TYPE_DECIMAL) {
359 if (res)
360 res->data.datetime = (sdb_time_t)((double)d1->data.datetime
361 / d2->data.decimal);
362 if (rem) {
363 double tmp = fmod((double)d1->data.datetime, d2->data.decimal);
364 rem->data.datetime = (sdb_time_t)tmp;
365 }
366 }
367 else {
368 sdb_time_t a, b;
369 if (d2->type == SDB_TYPE_DATETIME) {
370 a = d1->data.datetime;
371 b = d2->data.datetime;
372 }
373 else if (d2->type == SDB_TYPE_INTEGER) {
374 a = d1->data.datetime;
375 b = (sdb_time_t)d2->data.integer;
376 }
377 else
378 return -1;
379 if (res)
380 res->data.datetime = a / b;
381 if (rem)
382 rem->data.datetime = a % b;
383 }
384 }
385 else
386 return -1;
388 if (res)
389 res->type = d1->type;
390 if (rem)
391 rem->type = d1->type;
392 return 0;
393 } /* data_div */
395 /* Concatenate d1 and d2. */
396 static int
397 data_concat(const sdb_data_t *d1, const sdb_data_t *d2, sdb_data_t *res)
398 {
399 unsigned char *new;
400 const unsigned char *s1, *s2;
401 size_t len1, len2, array1_len = 0, array2_len = 0;
403 if ((d1->type & 0xff) != (d2->type & 0xff))
404 return -1;
406 if ((d1->type & SDB_TYPE_ARRAY) || (d2->type & SDB_TYPE_ARRAY)) {
407 size_t elem_size = sdb_data_sizeof(d1->type & 0xff);
408 if (d1->type & SDB_TYPE_ARRAY) {
409 s1 = (const unsigned char *)d1->data.array.values;
410 array1_len = d1->data.array.length;
411 }
412 else {
413 /* As per C99, section 6.7.2.1, paragraph 14:
414 * "A pointer to a union object, suitably converted, points to
415 * each of its members" */
416 s1 = (const unsigned char *)&d1->data;
417 array1_len = 1;
418 }
419 if (d2->type & SDB_TYPE_ARRAY) {
420 s2 = (const unsigned char *)d2->data.array.values;
421 array2_len = d2->data.array.length;
422 }
423 else {
424 s2 = (const unsigned char *)&d2->data;
425 array2_len = 1;
426 }
427 len1 = array1_len * elem_size;
428 len2 = array2_len * elem_size;
429 }
430 else if (d1->type == SDB_TYPE_STRING) {
431 s1 = (unsigned char *)d1->data.string;
432 s2 = (unsigned char *)d2->data.string;
433 len1 = s1 ? strlen((const char *)s1) : 0;
434 len2 = s2 ? strlen((const char *)s2) : 0;
435 }
436 else if (d1->type == SDB_TYPE_BINARY) {
437 s1 = d1->data.binary.datum;
438 s2 = d2->data.binary.datum;
439 len1 = d1->data.binary.length;
440 len2 = d2->data.binary.length;
441 }
442 else
443 return -1;
445 new = malloc(len1 + len2 + 1);
446 if (! new)
447 return -1;
449 if (len1)
450 memcpy(new, s1, len1);
451 if (len2)
452 memcpy(new + len1, s2, len2);
453 new[len1 + len2] = '\0';
455 /* element types match and if either datum is an array,
456 * the result is an array as well */
457 res->type = d1->type | d2->type;
458 if (res->type == SDB_TYPE_STRING) {
459 res->data.string = (char *)new;
460 }
461 else if (res->type == SDB_TYPE_BINARY) {
462 res->data.binary.datum = new;
463 res->data.binary.length = len1 + len2;
464 }
465 else if (res->type & SDB_TYPE_ARRAY) {
466 res->data.array.values = new;
467 res->data.array.length = array1_len + array2_len;
468 if (copy_array_values(res, res, sdb_data_sizeof(res->type & 0xff))) {
469 /* this leaks already copied values but there's not much we can
470 * do and this should only happen if we're in trouble anyway */
471 free(new);
472 res->data.array.values = NULL;
473 res->data.array.length = 0;
474 return -1;
475 }
476 }
477 return 0;
478 } /* data_concat */
480 /*
481 * public API
482 */
484 const sdb_data_t SDB_DATA_NULL = SDB_DATA_INIT;
486 int
487 sdb_data_copy(sdb_data_t *dst, const sdb_data_t *src)
488 {
489 sdb_data_t tmp;
491 if ((! dst) || (! src))
492 return -1;
494 tmp = *src;
495 if (src->type == SDB_TYPE_STRING) {
496 if (src->data.string) {
497 tmp.data.string = strdup(src->data.string);
498 if (! tmp.data.string)
499 return -1;
500 }
501 }
502 else if (src->type == SDB_TYPE_BINARY) {
503 if (src->data.binary.datum) {
504 tmp.data.binary.datum = malloc(src->data.binary.length);
505 if (! tmp.data.binary.datum)
506 return -1;
507 memcpy(tmp.data.binary.datum, src->data.binary.datum,
508 src->data.binary.length);
509 }
510 }
511 else if (src->type == SDB_TYPE_REGEX) {
512 if (src->data.re.raw) {
513 tmp.data.re.raw = strdup(src->data.re.raw);
514 if (! tmp.data.re.raw)
515 return -1;
516 /* we need to recompile because the regex might point to
517 * dynamically allocated memory */
518 if (regcomp(&tmp.data.re.regex, tmp.data.re.raw,
519 REG_EXTENDED | REG_ICASE | REG_NOSUB)) {
520 free(tmp.data.re.raw);
521 return -1;
522 }
523 }
524 else
525 memset(&tmp.data.re.regex, 0, sizeof(tmp.data.re.regex));
526 }
527 else if (src->type & SDB_TYPE_ARRAY) {
528 if (src->data.array.values) {
529 size_t elem_size = sdb_data_sizeof(src->type & 0xff);
530 tmp.data.array.values = calloc(src->data.array.length, elem_size);
531 if (! tmp.data.array.values)
532 return -1;
533 if (copy_array_values(&tmp, src, elem_size)) {
534 sdb_data_free_datum(&tmp);
535 return -1;
536 }
537 }
538 }
540 sdb_data_free_datum(dst);
541 *dst = tmp;
542 return 0;
543 } /* sdb_data_copy */
545 void
546 sdb_data_free_datum(sdb_data_t *datum)
547 {
548 if (! datum)
549 return;
551 if (datum->type == SDB_TYPE_STRING) {
552 if (datum->data.string)
553 free(datum->data.string);
554 datum->data.string = NULL;
555 }
556 else if (datum->type == SDB_TYPE_BINARY) {
557 if (datum->data.binary.datum)
558 free(datum->data.binary.datum);
559 datum->data.binary.datum = NULL;
560 datum->data.binary.length = 0;
561 }
562 else if (datum->type == SDB_TYPE_REGEX) {
563 if (datum->data.re.raw) {
564 free(datum->data.re.raw);
565 regfree(&datum->data.re.regex);
566 }
567 datum->data.re.raw = NULL;
568 memset(&datum->data.re.regex, 0, sizeof(datum->data.re.regex));
569 }
570 else if (datum->type & SDB_TYPE_ARRAY) {
571 free_array_values(datum);
572 if (datum->data.array.values)
573 free(datum->data.array.values);
574 datum->data.array.values = NULL;
575 datum->data.array.length = 0;
576 }
577 } /* sdb_data_free_datum */
579 int
580 sdb_data_cmp(const sdb_data_t *d1, const sdb_data_t *d2)
581 {
582 #define CMP_NULL(a, b) \
583 do { \
584 if (!(a) && !(b)) return 0; \
585 if (!(a)) return -1; \
586 if (!(b)) return 1; \
587 } while (0)
589 CMP_NULL(d1, d2);
591 if (d1->type != d2->type)
592 return SDB_CMP(d1->type, d2->type);
594 if (d1->type == SDB_TYPE_INTEGER)
595 return SDB_CMP(d1->data.integer, d2->data.integer);
596 else if (d1->type == SDB_TYPE_DECIMAL)
597 return SDB_CMP(d1->data.decimal, d2->data.decimal);
598 else if (d1->type == SDB_TYPE_STRING) {
599 CMP_NULL(d1->data.string, d2->data.string);
600 return strcasecmp(d1->data.string, d2->data.string);
601 }
602 else if (d1->type == SDB_TYPE_DATETIME)
603 return SDB_CMP(d1->data.datetime, d2->data.datetime);
604 else if (d1->type == SDB_TYPE_BINARY) {
605 int diff;
607 CMP_NULL(d1->data.binary.datum, d2->data.binary.datum);
609 /* on a common prefix, the shorter datum sorts less */
610 if (d1->data.binary.length < d2->data.binary.length) {
611 diff = memcmp(d1->data.binary.datum, d2->data.binary.datum,
612 d1->data.binary.length);
613 diff = diff ? diff : -1;
614 }
615 else if (d1->data.binary.length > d2->data.binary.length) {
616 diff = memcmp(d1->data.binary.datum, d2->data.binary.datum,
617 d2->data.binary.length);
618 diff = diff ? diff : 1;
619 }
620 else
621 diff = memcmp(d1->data.binary.datum, d2->data.binary.datum,
622 d1->data.binary.length);
624 return diff;
625 }
626 else if (d1->type == SDB_TYPE_REGEX) {
627 CMP_NULL(d1->data.re.raw, d2->data.re.raw);
628 return strcmp(d1->data.re.raw, d2->data.re.raw);
629 }
630 else if (d1->type & SDB_TYPE_ARRAY) {
631 CMP_NULL(d1->data.array.values, d2->data.array.values);
632 return array_cmp(d1, d2);
633 }
634 return -1;
635 } /* sdb_data_cmp */
637 int
638 sdb_data_strcmp(const sdb_data_t *d1, const sdb_data_t *d2)
639 {
640 char d1_str[sdb_data_strlen(d1) + 1];
641 char d2_str[sdb_data_strlen(d2) + 1];
643 if ((d1->type & SDB_TYPE_ARRAY) || (d2->type & SDB_TYPE_ARRAY)) {
644 /* TODO */
645 errno = ENOTSUP;
646 return -1;
647 }
649 if (sdb_data_isnull(d1))
650 d1 = NULL;
651 if (sdb_data_isnull(d2))
652 d2 = NULL;
654 CMP_NULL(d1, d2);
656 if (sdb_data_format(d1, d1_str, sizeof(d1_str), SDB_UNQUOTED) < 0)
657 return SDB_CMP(sizeof(d1_str), sizeof(d2_str));
658 if (sdb_data_format(d2, d2_str, sizeof(d2_str), SDB_UNQUOTED) < 0)
659 return SDB_CMP(sizeof(d1_str), sizeof(d2_str));
661 return strcasecmp(d1_str, d2_str);
662 #undef CMP_NULL
663 } /* sdb_data_strcmp */
665 bool
666 sdb_data_isnull(const sdb_data_t *datum)
667 {
668 if (! datum)
669 return 1;
670 if (datum->type == SDB_TYPE_NULL)
671 return 1;
672 if ((datum->type == SDB_TYPE_STRING) && (! datum->data.string))
673 return 1;
674 if ((datum->type == SDB_TYPE_BINARY) && (! datum->data.binary.datum))
675 return 1;
676 if ((datum->type == SDB_TYPE_REGEX) && (! datum->data.re.raw))
677 return 1;
678 return 0;
679 } /* sdb_data_isnull */
681 bool
682 sdb_data_inarray(const sdb_data_t *value, const sdb_data_t *array)
683 {
684 const void *values;
685 size_t length, i;
686 int type = value->type & 0xff;
688 if (sdb_data_isnull(value) || sdb_data_isnull(array))
689 return 0;
690 if (! (array->type & SDB_TYPE_ARRAY))
691 return 0;
692 if ((value->type & 0xff) != (array->type & 0xff))
693 return 0;
695 if (value->type & SDB_TYPE_ARRAY) {
696 values = value->data.array.values;
697 length = value->data.array.length;
698 }
699 else {
700 values = &value->data;
701 length = 1;
702 }
704 for (i = 0; i < length; ++i) {
705 size_t j;
707 if (type == SDB_TYPE_INTEGER) {
708 int64_t *v = array->data.array.values;
709 for (j = 0; j < array->data.array.length; ++j)
710 if (((const int64_t *)values)[i] == v[j])
711 break;
712 }
713 else if (type == SDB_TYPE_DECIMAL) {
714 double *v = array->data.array.values;
715 for (j = 0; j < array->data.array.length; ++j)
716 if (((const double *)values)[i] == v[j])
717 break;
718 }
719 else if (type == SDB_TYPE_STRING) {
720 char **v = array->data.array.values;
721 for (j = 0; j < array->data.array.length; ++j)
722 if (!strcasecmp(((const char * const*)values)[i], v[j]))
723 break;
724 }
725 else {
726 /* TODO */
727 errno = ENOTSUP;
728 return 0;
729 }
731 if (j >= array->data.array.length)
732 /* value not found */
733 return 0;
734 }
735 return 1;
736 } /* sdb_data_inarray */
738 int
739 sdb_data_array_get(const sdb_data_t *array, size_t i, sdb_data_t *value)
740 {
741 sdb_data_t tmp = SDB_DATA_INIT;
742 int type;
744 if ((! array) || (! (array->type & SDB_TYPE_ARRAY)))
745 return -1;
746 if (i >= array->data.array.length)
747 return -1;
749 type = array->type & 0xff;
750 if (type == SDB_TYPE_INTEGER) {
751 int64_t *v = array->data.array.values;
752 tmp.data.integer = v[i];
753 }
754 else if (type == SDB_TYPE_DECIMAL) {
755 double *v = array->data.array.values;
756 tmp.data.decimal = v[i];
757 }
758 else if (type == SDB_TYPE_STRING) {
759 char **v = array->data.array.values;
760 tmp.data.string = v[i];
761 }
762 else {
763 /* TODO */
764 errno = ENOTSUP;
765 return -1;
766 }
768 if (value) {
769 *value = tmp;
770 value->type = type;
771 }
772 return 0;
773 } /* sdb_data_array_get */
775 int
776 sdb_data_parse_op(const char *op)
777 {
778 if (! strcmp(op, "+"))
779 return SDB_DATA_ADD;
780 else if (! strcmp(op, "-"))
781 return SDB_DATA_SUB;
782 else if (! strcmp(op, "*"))
783 return SDB_DATA_MUL;
784 else if (! strcmp(op, "/"))
785 return SDB_DATA_DIV;
786 else if (! strcmp(op, "%"))
787 return SDB_DATA_MOD;
788 else if (! strcmp(op, "||"))
789 return SDB_DATA_CONCAT;
790 return -1;
791 } /* sdb_data_parse_op */
793 int
794 sdb_data_expr_eval(int op, const sdb_data_t *d1, const sdb_data_t *d2,
795 sdb_data_t *res)
796 {
797 if ((! d1) || (! d2) || (! res))
798 return -1;
799 if (sdb_data_isnull(d1) || sdb_data_isnull(d2)) {
800 *res = SDB_DATA_NULL;
801 return 0;
802 }
803 switch (op) {
804 case SDB_DATA_CONCAT: return data_concat(d1, d2, res);
805 case SDB_DATA_ADD: return data_lin(d1, 1, d2, res);
806 case SDB_DATA_SUB: return data_lin(d1, -1, d2, res);
807 case SDB_DATA_MUL: return data_mul(d1, d2, res);
808 case SDB_DATA_DIV: return data_div(d1, d2, res, NULL);
809 case SDB_DATA_MOD: return data_div(d1, d2, NULL, res);
810 }
811 return -1;
812 } /* sdb_data_expr_eval */
814 int
815 sdb_data_expr_type(int op, int type1, int type2)
816 {
817 int types_num = (int)SDB_STATIC_ARRAY_LEN(op_matrix[0]);
819 assert(SDB_STATIC_ARRAY_LEN(op_matrix[0])
820 == SDB_STATIC_ARRAY_LEN(op_matrix[0][0]));
822 if ((op <= 0) || (SDB_STATIC_ARRAY_LEN(op_matrix) < (size_t)op))
823 return -1;
825 /* arrays only support concat; element type has to match */
826 if ((type1 & SDB_TYPE_ARRAY) || (type2 & SDB_TYPE_ARRAY)) {
827 if (((type1 & 0xff) != (type2 & 0xff)) || (op != SDB_DATA_CONCAT))
828 return -1;
829 return type1 | SDB_TYPE_ARRAY;
830 }
831 if ((type1 < 0) || (types_num < type1)
832 || (type2 < 0) || (types_num < type2))
833 return -1;
835 if ((type1 == SDB_TYPE_NULL) || (type2 == SDB_TYPE_NULL))
836 return SDB_TYPE_NULL;
837 return op_matrix[op - 1][type1 - 1][type2 - 1];
838 } /* sdb_data_expr_type */
840 size_t
841 sdb_data_strlen(const sdb_data_t *datum)
842 {
843 if (! datum)
844 return 0;
846 if (datum->type == SDB_TYPE_INTEGER) {
847 /* log(64) */
848 return 20;
849 }
850 else if (datum->type == SDB_TYPE_DECIMAL) {
851 /* XXX: -d.dddddde+dd or -ddddd.dddddd */
852 return 42;
853 }
854 else if (datum->type == SDB_TYPE_STRING) {
855 if (! datum->data.string)
856 return 6; /* NULL */
857 /* in the worst case, each character needs to be escaped */
858 return 2 * strlen(datum->data.string) + 2;
859 }
860 else if (datum->type == SDB_TYPE_DATETIME) {
861 /* "YYYY-MM-DD HH:MM:SS +zzzz" */
862 return 27;
863 }
864 else if (datum->type == SDB_TYPE_BINARY) {
865 if (! datum->data.binary.datum)
866 return 6; /* NULL */
867 /* "\xNN" */
868 return 4 * datum->data.binary.length + 2;
869 }
870 else if (datum->type == SDB_TYPE_REGEX) {
871 if (! datum->data.re.raw)
872 return 6; /* NULL */
873 /* "/.../" */
874 return strlen(datum->data.re.raw) + 4;
875 }
876 else if (datum->type & SDB_TYPE_ARRAY) {
877 size_t len = 2; /* [] */
878 size_t i;
879 for (i = 0; i < datum->data.array.length; ++i) {
880 sdb_data_t v = SDB_DATA_INIT;
881 sdb_data_array_get(datum, i, &v);
882 len += sdb_data_strlen(&v) + 1;
883 }
884 return len;
885 }
886 return 0;
887 } /* sdb_data_strlen */
889 int
890 sdb_data_format(const sdb_data_t *datum, char *buf, size_t buflen, int quoted)
891 {
892 char tmp[sdb_data_strlen(datum) + 1];
893 char *data = NULL;
894 bool is_null = 0;
895 int ret = -1;
897 size_t i, pos;
899 if ((! datum) || (! buf) || (! buflen))
900 return -1;
902 if (datum->type == SDB_TYPE_INTEGER) {
903 ret = snprintf(buf, buflen, "%"PRIi64, datum->data.integer);
904 }
905 else if (datum->type == SDB_TYPE_DECIMAL) {
906 if (isnan(datum->data.decimal))
907 ret = snprintf(buf, buflen, "nan");
908 else
909 ret = snprintf(buf, buflen, "%g", datum->data.decimal);
910 }
911 else if (datum->type == SDB_TYPE_STRING) {
912 if (! datum->data.string)
913 is_null = 1;
914 else {
915 pos = 0;
916 for (i = 0; i < strlen(datum->data.string); ++i) {
917 char byte = datum->data.string[i];
919 if ((byte == '\\') || (byte == '"')) {
920 tmp[pos] = '\\';
921 ++pos;
922 }
923 tmp[pos] = byte;
924 ++pos;
925 }
926 tmp[pos] = '\0';
927 data = tmp;
928 }
929 }
930 else if (datum->type == SDB_TYPE_DATETIME) {
931 if (! sdb_strftime(tmp, sizeof(tmp), "%F %T %z",
932 datum->data.datetime))
933 return -1;
934 tmp[sizeof(tmp) - 1] = '\0';
935 data = tmp;
936 }
937 else if (datum->type == SDB_TYPE_BINARY) {
938 pos = 0;
939 for (i = 0; i < datum->data.binary.length; ++i) {
940 int byte = (int)datum->data.binary.datum[i];
941 char hex[] = {'0', '1', '2', '3', '4', '5', '6', '7',
942 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
944 tmp[pos] = '\\';
945 tmp[pos + 1] = 'x';
946 pos += 2;
948 if (byte > 0xf) {
949 tmp[pos] = hex[byte >> 4];
950 ++pos;
951 }
952 tmp[pos] = hex[byte & 0xf];
953 ++pos;
954 }
955 if (datum->data.binary.datum) {
956 tmp[pos] = '\0';
957 data = tmp;
958 }
959 else
960 is_null = 1;
961 }
962 else if (datum->type == SDB_TYPE_REGEX) {
963 if (! datum->data.re.raw)
964 is_null = 1;
965 else {
966 snprintf(tmp, sizeof(tmp), "/%s/", datum->data.re.raw);
967 data = tmp;
968 }
969 }
970 else if (datum->type & SDB_TYPE_ARRAY) {
971 ret = 1;
972 buf[0] = '[';
973 for (i = 0; i < datum->data.array.length; ++i) {
974 sdb_data_t v = SDB_DATA_INIT;
975 int n;
976 if ((size_t)ret >= buflen - 1)
977 break;
979 if (ret > 1) {
980 buf[ret] = ',';
981 buf[ret + 1] = ' ';
982 ret += 2;
983 }
985 sdb_data_array_get(datum, i, &v);
986 n = sdb_data_format(&v, buf + ret, buflen - ret, quoted);
987 if (n > 0)
988 ret += n;
989 else
990 break;
991 }
992 if ((size_t)ret < buflen - 1) {
993 buf[ret] = ']';
994 buf[ret + 1] = '\0';
995 ++ret;
996 }
997 }
999 if (is_null) {
1000 /* never quote NULL */
1001 strncpy(buf, "NULL", buflen);
1002 ret = (int)SDB_MIN(buflen, 4);
1003 }
1004 else if (data) {
1005 if (quoted == SDB_UNQUOTED)
1006 ret = snprintf(buf, buflen, "%s", data);
1007 else if (quoted == SDB_SINGLE_QUOTED)
1008 ret = snprintf(buf, buflen, "'%s'", data);
1009 else
1010 ret = snprintf(buf, buflen, "\"%s\"", data);
1011 }
1012 buf[buflen - 1] = '\0';
1013 return ret;
1014 } /* sdb_data_format */
1016 int
1017 sdb_data_parse(char *str, int type, sdb_data_t *data)
1018 {
1019 sdb_data_t tmp;
1021 char *endptr = NULL;
1023 errno = 0;
1024 if (type == SDB_TYPE_INTEGER) {
1025 tmp.data.integer = strtoll(str, &endptr, 0);
1026 }
1027 else if (type == SDB_TYPE_DECIMAL) {
1028 tmp.data.decimal = strtod(str, &endptr);
1029 }
1030 else if (type == SDB_TYPE_STRING) {
1031 tmp.data.string = str;
1032 }
1033 else if (type == SDB_TYPE_DATETIME) {
1034 double datetime = strtod(str, &endptr);
1035 tmp.data.datetime = DOUBLE_TO_SDB_TIME(datetime);
1036 }
1037 else if (type == SDB_TYPE_BINARY) {
1038 /* we don't support any binary information containing 0-bytes */
1039 tmp.data.binary.length = strlen(str);
1040 tmp.data.binary.datum = (unsigned char *)str;
1041 }
1042 else if (type == SDB_TYPE_REGEX) {
1043 tmp.data.re.raw = strdup(str);
1044 if (! tmp.data.re.raw)
1045 return -1;
1046 if (regcomp(&tmp.data.re.regex, tmp.data.re.raw,
1047 REG_EXTENDED | REG_ICASE | REG_NOSUB)) {
1048 sdb_log(SDB_LOG_ERR, "core: Failed to compile regular "
1049 "expression '%s'", tmp.data.re.raw);
1050 free(tmp.data.re.raw);
1051 return -1;
1052 }
1053 if (! data) {
1054 tmp.type = SDB_TYPE_REGEX;
1055 sdb_data_free_datum(&tmp);
1056 }
1057 }
1058 else if (type & SDB_TYPE_ARRAY) {
1059 /* TODO */
1060 errno = ENOTSUP;
1061 return -1;
1062 }
1063 else {
1064 errno = EINVAL;
1065 return -1;
1066 }
1068 if ((type == SDB_TYPE_INTEGER) || (type == SDB_TYPE_DECIMAL)
1069 || (type == SDB_TYPE_DATETIME)) {
1070 if (errno || (str == endptr)) {
1071 char errbuf[1024];
1072 sdb_log(SDB_LOG_ERR, "core: Failed to parse string "
1073 "'%s' as numeric value (type %i): %s", str, type,
1074 sdb_strerror(errno, errbuf, sizeof(errbuf)));
1075 return -1;
1076 }
1077 else if (endptr && (*endptr != '\0'))
1078 sdb_log(SDB_LOG_WARNING, "core: Ignoring garbage after "
1079 "number while parsing numeric value (type %i): %s.",
1080 type, endptr);
1081 }
1083 if (data) {
1084 *data = tmp;
1085 data->type = type;
1086 }
1087 return 0;
1088 } /* sdb_data_parse */
1090 size_t
1091 sdb_data_sizeof(int type)
1092 {
1093 sdb_data_t v;
1094 if (type == SDB_TYPE_INTEGER)
1095 return sizeof(v.data.integer);
1096 else if (type == SDB_TYPE_DECIMAL)
1097 return sizeof(v.data.decimal);
1098 else if (type == SDB_TYPE_STRING)
1099 return sizeof(v.data.string);
1100 else if (type == SDB_TYPE_DATETIME)
1101 return sizeof(v.data.datetime);
1102 else if (type == SDB_TYPE_BINARY)
1103 return sizeof(v.data.binary);
1104 else if (type == SDB_TYPE_REGEX)
1105 return sizeof(v.data.re);
1106 return 0;
1107 } /* sdb_data_sizeof */
1109 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */