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 else if (type == SDB_TYPE_BINARY) {
170 struct {
171 size_t length;
172 unsigned char *datum;
173 } *v = datum->data.array.values;
174 size_t i;
176 for (i = 0; i < datum->data.array.length; ++i) {
177 if (v[i].datum)
178 free(v[i].datum);
179 v[i].datum = NULL;
180 }
181 }
182 else if (type == SDB_TYPE_REGEX) {
183 struct {
184 char *raw;
185 regex_t regex;
186 } *v = datum->data.array.values;
187 size_t i;
189 for (i = 0; i < datum->data.array.length; ++i) {
190 if (v[i].raw) {
191 free(v[i].raw);
192 regfree(&v[i].regex);
193 }
194 v[i].raw = NULL;
195 }
196 }
197 } /* free_array_values */
199 /* compare two arrays element-by-element returning how the first non-equal
200 * elements compare to each other */
201 static int
202 array_cmp(const sdb_data_t *a1, const sdb_data_t *a2)
203 {
204 int type = a1->type & 0xff;
205 size_t len, i;
207 assert((a1->type == a2->type) && (a1->type & SDB_TYPE_ARRAY));
209 len = SDB_MIN(a1->data.array.length, a2->data.array.length);
211 if (type == SDB_TYPE_INTEGER) {
212 int64_t *v1 = a1->data.array.values;
213 int64_t *v2 = a2->data.array.values;
215 for (i = 0; i < len; ++i)
216 if (v1[i] != v2[i])
217 return SDB_CMP(v1[i], v2[i]);
218 }
219 else if (type == SDB_TYPE_DECIMAL) {
220 double *v1 = a1->data.array.values;
221 double *v2 = a2->data.array.values;
223 for (i = 0; i < len; ++i)
224 if (v1[i] != v2[i])
225 return SDB_CMP(v1[i], v2[i]);
226 }
227 else if (type == SDB_TYPE_STRING) {
228 char **v1 = a1->data.array.values;
229 char **v2 = a2->data.array.values;
231 for (i = 0; i < len; ++i) {
232 int diff = strcasecmp(v1[i], v2[i]);
233 if (diff)
234 return diff;
235 }
236 }
237 else if (type == SDB_TYPE_DATETIME) {
238 sdb_time_t *v1 = a1->data.array.values;
239 sdb_time_t *v2 = a2->data.array.values;
241 for (i = 0; i < len; ++i)
242 if (v1[i] != v2[i])
243 return SDB_CMP(v1[i], v2[i]);
244 }
245 else if (type == SDB_TYPE_BINARY) {
246 struct {
247 size_t length;
248 unsigned char *datum;
249 } *v1 = a1->data.array.values;
250 struct {
251 size_t length;
252 unsigned char *datum;
253 } *v2 = a2->data.array.values;
255 for (i = 0; i < len; ++i) {
256 int diff;
258 /* on a common prefix, the shorter datum sorts less */
259 if (v1[i].length < v2[i].length) {
260 diff = memcmp(v1[i].datum, v2[i].datum, v1[i].length);
261 diff = diff ? diff : -1;
262 }
263 else if (v1[i].length > v2[i].length) {
264 diff = memcmp(v1[i].datum, v2[i].datum, v2[i].length);
265 diff = diff ? diff : 1;
266 }
267 else
268 diff = memcmp(v1[i].datum, v2[i].datum, v1[i].length);
270 if (diff)
271 return diff;
272 }
273 }
274 else if (type == SDB_TYPE_REGEX) {
275 struct {
276 char *raw;
277 regex_t regex;
278 } *v1 = a1->data.array.values;
279 struct {
280 char *raw;
281 regex_t regex;
282 } *v2 = a2->data.array.values;
284 for (i = 0; i < len; ++i) {
285 int diff = strcasecmp(v1[i].raw, v2[i].raw);
286 if (diff)
287 return diff;
288 }
289 }
290 else {
291 errno = EINVAL;
292 /* but fall through to ensure stable sorting: */
293 }
294 return SDB_CMP(a1->data.array.length, a2->data.array.length);
295 } /* array_cmp */
297 /* Calculate the linear function 'd1 + n * d2'. */
298 static int
299 data_lin(const sdb_data_t *d1, int n, const sdb_data_t *d2, sdb_data_t *res)
300 {
301 if (d1->type != d2->type)
302 return -1;
304 if (d1->type == SDB_TYPE_INTEGER)
305 res->data.integer = d1->data.integer + (int64_t)n * d2->data.integer;
306 else if (d1->type == SDB_TYPE_DECIMAL)
307 res->data.decimal = d1->data.decimal + (double)n * d2->data.decimal;
308 else if (d1->type == SDB_TYPE_DATETIME)
309 res->data.datetime = d1->data.datetime + (sdb_time_t)n * d2->data.datetime;
310 else
311 return -1;
312 res->type = d1->type;
313 return 0;
314 } /* data_lin */
316 /* Multiply d1 with d2. */
317 static int
318 data_mul(const sdb_data_t *d1, const sdb_data_t *d2, sdb_data_t *res)
319 {
320 if (d1->type == SDB_TYPE_INTEGER) {
321 if (d2->type == SDB_TYPE_INTEGER)
322 res->data.integer = d1->data.integer * d2->data.integer;
323 else if (d2->type == SDB_TYPE_DATETIME) {
324 res->data.datetime = (sdb_time_t)d1->data.integer
325 * d2->data.datetime;
326 res->type = SDB_TYPE_DATETIME;
327 return 0;
328 }
329 else
330 return -1;
331 }
332 else if (d1->type == SDB_TYPE_DECIMAL) {
333 if (d2->type == SDB_TYPE_DECIMAL)
334 res->data.decimal = d1->data.decimal * d2->data.decimal;
335 else if (d2->type == SDB_TYPE_DATETIME) {
336 res->data.datetime = (sdb_time_t)(d1->data.decimal
337 * (double)d2->data.datetime);
338 res->type = SDB_TYPE_DATETIME;
339 return 0;
340 }
341 else
342 return -1;
343 }
344 else if (d1->type == SDB_TYPE_DATETIME) {
345 if (d2->type == SDB_TYPE_DATETIME)
346 res->data.datetime = d1->data.datetime
347 * d2->data.datetime;
348 else if (d2->type == SDB_TYPE_INTEGER)
349 res->data.datetime = d1->data.datetime
350 * (sdb_time_t)d2->data.integer;
351 else if (d2->type == SDB_TYPE_DECIMAL)
352 res->data.datetime = (sdb_time_t)((double)d1->data.datetime
353 * d2->data.decimal);
354 else
355 return -1;
356 }
357 else
358 return -1;
360 res->type = d1->type;
361 return 0;
362 } /* data_mul */
364 /* Device d1 by d2 and return the result and the remainder. */
365 static int
366 data_div(const sdb_data_t *d1, const sdb_data_t *d2,
367 sdb_data_t *res, sdb_data_t *rem)
368 {
369 if (d1->type == SDB_TYPE_INTEGER) {
370 if (d2->type != SDB_TYPE_INTEGER)
371 return -1;
372 if (res)
373 res->data.integer = d1->data.integer / d2->data.integer;
374 if (rem)
375 rem->data.integer = d1->data.integer % d2->data.integer;
376 }
377 else if (d1->type == SDB_TYPE_DECIMAL) {
378 if (d2->type != SDB_TYPE_DECIMAL)
379 return -1;
380 if (res)
381 res->data.decimal = d1->data.decimal / d2->data.decimal;
382 if (rem)
383 rem->data.decimal = fmod(d1->data.decimal, d2->data.decimal);
384 }
385 else if (d1->type == SDB_TYPE_DATETIME) {
386 if (d2->type == SDB_TYPE_DECIMAL) {
387 if (res)
388 res->data.datetime = (sdb_time_t)((double)d1->data.datetime
389 / d2->data.decimal);
390 if (rem) {
391 double tmp = fmod((double)d1->data.datetime, d2->data.decimal);
392 rem->data.datetime = (sdb_time_t)tmp;
393 }
394 }
395 else {
396 sdb_time_t a, b;
397 if (d2->type == SDB_TYPE_DATETIME) {
398 a = d1->data.datetime;
399 b = d2->data.datetime;
400 }
401 else if (d2->type == SDB_TYPE_INTEGER) {
402 a = d1->data.datetime;
403 b = (sdb_time_t)d2->data.integer;
404 }
405 else
406 return -1;
407 if (res)
408 res->data.datetime = a / b;
409 if (rem)
410 rem->data.datetime = a % b;
411 }
412 }
413 else
414 return -1;
416 if (res)
417 res->type = d1->type;
418 if (rem)
419 rem->type = d1->type;
420 return 0;
421 } /* data_div */
423 /* Concatenate d1 and d2. */
424 static int
425 data_concat(const sdb_data_t *d1, const sdb_data_t *d2, sdb_data_t *res)
426 {
427 unsigned char *new;
428 const unsigned char *s1, *s2;
429 size_t len1, len2, array1_len = 0, array2_len = 0;
431 if ((d1->type & 0xff) != (d2->type & 0xff))
432 return -1;
434 if ((d1->type & SDB_TYPE_ARRAY) || (d2->type & SDB_TYPE_ARRAY)) {
435 size_t elem_size = sdb_data_sizeof(d1->type & 0xff);
436 if (d1->type & SDB_TYPE_ARRAY) {
437 s1 = (const unsigned char *)d1->data.array.values;
438 array1_len = d1->data.array.length;
439 }
440 else {
441 /* As per C99, section 6.7.2.1, paragraph 14:
442 * "A pointer to a union object, suitably converted, points to
443 * each of its members" */
444 s1 = (const unsigned char *)&d1->data;
445 array1_len = 1;
446 }
447 if (d2->type & SDB_TYPE_ARRAY) {
448 s2 = (const unsigned char *)d2->data.array.values;
449 array2_len = d2->data.array.length;
450 }
451 else {
452 s2 = (const unsigned char *)&d2->data;
453 array2_len = 1;
454 }
455 len1 = array1_len * elem_size;
456 len2 = array2_len * elem_size;
457 }
458 else if (d1->type == SDB_TYPE_STRING) {
459 s1 = (unsigned char *)d1->data.string;
460 s2 = (unsigned char *)d2->data.string;
461 len1 = s1 ? strlen((const char *)s1) : 0;
462 len2 = s2 ? strlen((const char *)s2) : 0;
463 }
464 else if (d1->type == SDB_TYPE_BINARY) {
465 s1 = d1->data.binary.datum;
466 s2 = d2->data.binary.datum;
467 len1 = d1->data.binary.length;
468 len2 = d2->data.binary.length;
469 }
470 else
471 return -1;
473 new = malloc(len1 + len2 + 1);
474 if (! new)
475 return -1;
477 if (len1)
478 memcpy(new, s1, len1);
479 if (len2)
480 memcpy(new + len1, s2, len2);
481 new[len1 + len2] = '\0';
483 /* element types match and if either datum is an array,
484 * the result is an array as well */
485 res->type = d1->type | d2->type;
486 if (res->type == SDB_TYPE_STRING) {
487 res->data.string = (char *)new;
488 }
489 else if (res->type == SDB_TYPE_BINARY) {
490 res->data.binary.datum = new;
491 res->data.binary.length = len1 + len2;
492 }
493 else if (res->type & SDB_TYPE_ARRAY) {
494 res->data.array.values = new;
495 res->data.array.length = array1_len + array2_len;
496 if (copy_array_values(res, res, sdb_data_sizeof(res->type & 0xff))) {
497 /* this leaks already copied values but there's not much we can
498 * do and this should only happen if we're in trouble anyway */
499 free(new);
500 res->data.array.values = NULL;
501 res->data.array.length = 0;
502 return -1;
503 }
504 }
505 return 0;
506 } /* data_concat */
508 /*
509 * public API
510 */
512 const sdb_data_t SDB_DATA_NULL = SDB_DATA_INIT;
514 int
515 sdb_data_copy(sdb_data_t *dst, const sdb_data_t *src)
516 {
517 sdb_data_t tmp;
519 if ((! dst) || (! src))
520 return -1;
522 tmp = *src;
523 if (src->type == SDB_TYPE_STRING) {
524 if (src->data.string) {
525 tmp.data.string = strdup(src->data.string);
526 if (! tmp.data.string)
527 return -1;
528 }
529 }
530 else if (src->type == SDB_TYPE_BINARY) {
531 if (src->data.binary.datum) {
532 tmp.data.binary.datum = malloc(src->data.binary.length);
533 if (! tmp.data.binary.datum)
534 return -1;
535 memcpy(tmp.data.binary.datum, src->data.binary.datum,
536 src->data.binary.length);
537 }
538 }
539 else if (src->type == SDB_TYPE_REGEX) {
540 if (src->data.re.raw) {
541 tmp.data.re.raw = strdup(src->data.re.raw);
542 if (! tmp.data.re.raw)
543 return -1;
544 /* we need to recompile because the regex might point to
545 * dynamically allocated memory */
546 if (regcomp(&tmp.data.re.regex, tmp.data.re.raw,
547 REG_EXTENDED | REG_ICASE | REG_NOSUB)) {
548 free(tmp.data.re.raw);
549 return -1;
550 }
551 }
552 else
553 memset(&tmp.data.re.regex, 0, sizeof(tmp.data.re.regex));
554 }
555 else if (src->type & SDB_TYPE_ARRAY) {
556 if (src->data.array.values) {
557 size_t elem_size = sdb_data_sizeof(src->type & 0xff);
558 tmp.data.array.values = calloc(src->data.array.length, elem_size);
559 if (! tmp.data.array.values)
560 return -1;
561 if (copy_array_values(&tmp, src, elem_size)) {
562 sdb_data_free_datum(&tmp);
563 return -1;
564 }
565 }
566 }
568 sdb_data_free_datum(dst);
569 *dst = tmp;
570 return 0;
571 } /* sdb_data_copy */
573 void
574 sdb_data_free_datum(sdb_data_t *datum)
575 {
576 if (! datum)
577 return;
579 if (datum->type == SDB_TYPE_STRING) {
580 if (datum->data.string)
581 free(datum->data.string);
582 datum->data.string = NULL;
583 }
584 else if (datum->type == SDB_TYPE_BINARY) {
585 if (datum->data.binary.datum)
586 free(datum->data.binary.datum);
587 datum->data.binary.datum = NULL;
588 datum->data.binary.length = 0;
589 }
590 else if (datum->type == SDB_TYPE_REGEX) {
591 if (datum->data.re.raw) {
592 free(datum->data.re.raw);
593 regfree(&datum->data.re.regex);
594 }
595 datum->data.re.raw = NULL;
596 memset(&datum->data.re.regex, 0, sizeof(datum->data.re.regex));
597 }
598 else if (datum->type & SDB_TYPE_ARRAY) {
599 free_array_values(datum);
600 if (datum->data.array.values)
601 free(datum->data.array.values);
602 datum->data.array.values = NULL;
603 datum->data.array.length = 0;
604 }
605 } /* sdb_data_free_datum */
607 int
608 sdb_data_cmp(const sdb_data_t *d1, const sdb_data_t *d2)
609 {
610 #define CMP_NULL(a, b) \
611 do { \
612 if (!(a) && !(b)) return 0; \
613 if (!(a)) return -1; \
614 if (!(b)) return 1; \
615 } while (0)
617 CMP_NULL(d1, d2);
619 if (d1->type != d2->type)
620 return SDB_CMP(d1->type, d2->type);
622 if (d1->type == SDB_TYPE_INTEGER)
623 return SDB_CMP(d1->data.integer, d2->data.integer);
624 else if (d1->type == SDB_TYPE_DECIMAL)
625 return SDB_CMP(d1->data.decimal, d2->data.decimal);
626 else if (d1->type == SDB_TYPE_STRING) {
627 CMP_NULL(d1->data.string, d2->data.string);
628 return strcasecmp(d1->data.string, d2->data.string);
629 }
630 else if (d1->type == SDB_TYPE_DATETIME)
631 return SDB_CMP(d1->data.datetime, d2->data.datetime);
632 else if (d1->type == SDB_TYPE_BINARY) {
633 int diff;
635 CMP_NULL(d1->data.binary.datum, d2->data.binary.datum);
637 /* on a common prefix, the shorter datum sorts less */
638 if (d1->data.binary.length < d2->data.binary.length) {
639 diff = memcmp(d1->data.binary.datum, d2->data.binary.datum,
640 d1->data.binary.length);
641 diff = diff ? diff : -1;
642 }
643 else if (d1->data.binary.length > d2->data.binary.length) {
644 diff = memcmp(d1->data.binary.datum, d2->data.binary.datum,
645 d2->data.binary.length);
646 diff = diff ? diff : 1;
647 }
648 else
649 diff = memcmp(d1->data.binary.datum, d2->data.binary.datum,
650 d1->data.binary.length);
652 return diff;
653 }
654 else if (d1->type == SDB_TYPE_REGEX) {
655 CMP_NULL(d1->data.re.raw, d2->data.re.raw);
656 return strcmp(d1->data.re.raw, d2->data.re.raw);
657 }
658 else if (d1->type & SDB_TYPE_ARRAY) {
659 CMP_NULL(d1->data.array.values, d2->data.array.values);
660 return array_cmp(d1, d2);
661 }
662 return -1;
663 } /* sdb_data_cmp */
665 int
666 sdb_data_strcmp(const sdb_data_t *d1, const sdb_data_t *d2)
667 {
668 char d1_str[sdb_data_strlen(d1) + 1];
669 char d2_str[sdb_data_strlen(d2) + 1];
671 if (sdb_data_isnull(d1))
672 d1 = NULL;
673 if (sdb_data_isnull(d2))
674 d2 = NULL;
676 CMP_NULL(d1, d2);
678 if (! sdb_data_format(d1, d1_str, sizeof(d1_str), SDB_UNQUOTED))
679 return SDB_CMP(sizeof(d1_str), sizeof(d2_str));
680 if (! sdb_data_format(d2, d2_str, sizeof(d2_str), SDB_UNQUOTED))
681 return SDB_CMP(sizeof(d1_str), sizeof(d2_str));
683 return strcasecmp(d1_str, d2_str);
684 #undef CMP_NULL
685 } /* sdb_data_strcmp */
687 bool
688 sdb_data_isnull(const sdb_data_t *datum)
689 {
690 if (! datum)
691 return 1;
692 if (datum->type == SDB_TYPE_NULL)
693 return 1;
694 if ((datum->type == SDB_TYPE_STRING) && (! datum->data.string))
695 return 1;
696 if ((datum->type == SDB_TYPE_BINARY) && (! datum->data.binary.datum))
697 return 1;
698 if ((datum->type == SDB_TYPE_REGEX) && (! datum->data.re.raw))
699 return 1;
700 return 0;
701 } /* sdb_data_isnull */
703 bool
704 sdb_data_inarray(const sdb_data_t *value, const sdb_data_t *array)
705 {
706 const void *values;
707 size_t length, i;
708 int type = value->type & 0xff;
710 if (sdb_data_isnull(value) || sdb_data_isnull(array))
711 return 0;
712 if (! (array->type & SDB_TYPE_ARRAY))
713 return 0;
714 if ((value->type & 0xff) != (array->type & 0xff))
715 return 0;
717 if (value->type & SDB_TYPE_ARRAY) {
718 values = value->data.array.values;
719 length = value->data.array.length;
720 }
721 else {
722 values = &value->data;
723 length = 1;
724 }
726 for (i = 0; i < length; ++i) {
727 size_t j;
729 if (type == SDB_TYPE_INTEGER) {
730 int64_t *v = array->data.array.values;
731 for (j = 0; j < array->data.array.length; ++j)
732 if (((const int64_t *)values)[i] == v[j])
733 break;
734 }
735 else if (type == SDB_TYPE_DECIMAL) {
736 double *v = array->data.array.values;
737 for (j = 0; j < array->data.array.length; ++j)
738 if (((const double *)values)[i] == v[j])
739 break;
740 }
741 else if (type == SDB_TYPE_STRING) {
742 char **v = array->data.array.values;
743 for (j = 0; j < array->data.array.length; ++j)
744 if (!strcasecmp(((const char * const*)values)[i], v[j]))
745 break;
746 }
747 else {
748 /* TODO */
749 errno = ENOTSUP;
750 return 0;
751 }
753 if (j >= array->data.array.length)
754 /* value not found */
755 return 0;
756 }
757 return 1;
758 } /* sdb_data_inarray */
760 int
761 sdb_data_array_get(const sdb_data_t *array, size_t i, sdb_data_t *value)
762 {
763 sdb_data_t tmp = SDB_DATA_INIT;
764 int type;
766 if ((! array) || (! (array->type & SDB_TYPE_ARRAY)))
767 return -1;
768 if (i >= array->data.array.length)
769 return -1;
771 type = array->type & 0xff;
772 if (type == SDB_TYPE_INTEGER) {
773 int64_t *v = array->data.array.values;
774 tmp.data.integer = v[i];
775 }
776 else if (type == SDB_TYPE_DECIMAL) {
777 double *v = array->data.array.values;
778 tmp.data.decimal = v[i];
779 }
780 else if (type == SDB_TYPE_STRING) {
781 char **v = array->data.array.values;
782 tmp.data.string = v[i];
783 }
784 else if (type == SDB_TYPE_DATETIME) {
785 sdb_time_t *v = array->data.array.values;
786 tmp.data.datetime = v[i];
787 }
788 else if (type == SDB_TYPE_BINARY) {
789 struct {
790 size_t length;
791 unsigned char *datum;
792 } *v = array->data.array.values;
793 assert(sizeof(tmp.data.binary) == sizeof(v[i]));
794 memcpy(&tmp.data.binary, &v[i], sizeof(v[i]));
795 }
796 else if (type == SDB_TYPE_REGEX) {
797 struct {
798 char *raw;
799 regex_t regex;
800 } *v = array->data.array.values;
801 assert(sizeof(tmp.data.re) == sizeof(v[i]));
802 memcpy(&tmp.data.re, &v[i], sizeof(v[i]));
803 }
804 else {
805 errno = EINVAL;
806 return -1;
807 }
809 if (value) {
810 *value = tmp;
811 value->type = type;
812 }
813 return 0;
814 } /* sdb_data_array_get */
816 int
817 sdb_data_parse_op(const char *op)
818 {
819 if (! strcmp(op, "+"))
820 return SDB_DATA_ADD;
821 else if (! strcmp(op, "-"))
822 return SDB_DATA_SUB;
823 else if (! strcmp(op, "*"))
824 return SDB_DATA_MUL;
825 else if (! strcmp(op, "/"))
826 return SDB_DATA_DIV;
827 else if (! strcmp(op, "%"))
828 return SDB_DATA_MOD;
829 else if (! strcmp(op, "||"))
830 return SDB_DATA_CONCAT;
831 return -1;
832 } /* sdb_data_parse_op */
834 int
835 sdb_data_expr_eval(int op, const sdb_data_t *d1, const sdb_data_t *d2,
836 sdb_data_t *res)
837 {
838 if ((! d1) || (! d2) || (! res))
839 return -1;
840 if (sdb_data_isnull(d1) || sdb_data_isnull(d2)) {
841 *res = SDB_DATA_NULL;
842 return 0;
843 }
844 switch (op) {
845 case SDB_DATA_CONCAT: return data_concat(d1, d2, res);
846 case SDB_DATA_ADD: return data_lin(d1, 1, d2, res);
847 case SDB_DATA_SUB: return data_lin(d1, -1, d2, res);
848 case SDB_DATA_MUL: return data_mul(d1, d2, res);
849 case SDB_DATA_DIV: return data_div(d1, d2, res, NULL);
850 case SDB_DATA_MOD: return data_div(d1, d2, NULL, res);
851 }
852 return -1;
853 } /* sdb_data_expr_eval */
855 int
856 sdb_data_expr_type(int op, int type1, int type2)
857 {
858 int types_num = (int)SDB_STATIC_ARRAY_LEN(op_matrix[0]);
860 assert(SDB_STATIC_ARRAY_LEN(op_matrix[0])
861 == SDB_STATIC_ARRAY_LEN(op_matrix[0][0]));
863 if ((op <= 0) || (SDB_STATIC_ARRAY_LEN(op_matrix) < (size_t)op))
864 return -1;
866 /* arrays only support concat; element type has to match */
867 if ((type1 & SDB_TYPE_ARRAY) || (type2 & SDB_TYPE_ARRAY)) {
868 if (((type1 & 0xff) != (type2 & 0xff)) || (op != SDB_DATA_CONCAT))
869 return -1;
870 return type1 | SDB_TYPE_ARRAY;
871 }
872 if ((type1 < 0) || (types_num < type1)
873 || (type2 < 0) || (types_num < type2))
874 return -1;
876 if ((type1 == SDB_TYPE_NULL) || (type2 == SDB_TYPE_NULL))
877 return SDB_TYPE_NULL;
878 return op_matrix[op - 1][type1 - 1][type2 - 1];
879 } /* sdb_data_expr_type */
881 size_t
882 sdb_data_strlen(const sdb_data_t *datum)
883 {
884 if (! datum)
885 return 0;
887 if (sdb_data_isnull(datum)) {
888 /* NULL */
889 return 4;
890 }
891 else if (datum->type == SDB_TYPE_INTEGER) {
892 /* log(64) */
893 return 20;
894 }
895 else if (datum->type == SDB_TYPE_DECIMAL) {
896 /* XXX: -d.dddddde+dd or -ddddd.dddddd */
897 return 42;
898 }
899 else if (datum->type == SDB_TYPE_STRING) {
900 if (! datum->data.string)
901 return 6; /* NULL */
902 /* in the worst case, each character needs to be escaped */
903 return 2 * strlen(datum->data.string) + 2;
904 }
905 else if (datum->type == SDB_TYPE_DATETIME) {
906 /* "YYYY-MM-DD HH:MM:SS +zzzz" */
907 return 27;
908 }
909 else if (datum->type == SDB_TYPE_BINARY) {
910 if (! datum->data.binary.datum)
911 return 6; /* NULL */
912 /* "\xNN" */
913 return 4 * datum->data.binary.length + 2;
914 }
915 else if (datum->type == SDB_TYPE_REGEX) {
916 if (! datum->data.re.raw)
917 return 6; /* NULL */
918 /* "/.../" */
919 return strlen(datum->data.re.raw) + 4;
920 }
921 else if (datum->type & SDB_TYPE_ARRAY) {
922 size_t len = 2; /* [] */
923 size_t i;
924 for (i = 0; i < datum->data.array.length; ++i) {
925 sdb_data_t v = SDB_DATA_INIT;
926 sdb_data_array_get(datum, i, &v);
927 len += sdb_data_strlen(&v) + 1;
928 }
929 return len;
930 }
931 return 0;
932 } /* sdb_data_strlen */
934 size_t
935 sdb_data_format(const sdb_data_t *datum, char *buf, size_t buflen, int quoted)
936 {
937 char tmp[sdb_data_strlen(datum) + 1];
938 char *data = NULL;
939 bool is_null = 0;
940 size_t ret = 0;
942 size_t i, pos;
944 if (! datum)
945 return 0;
947 if (datum->type == SDB_TYPE_NULL) {
948 strncpy(buf, "NULL", buflen);
949 ret = 4;
950 }
951 else if (datum->type == SDB_TYPE_INTEGER) {
952 ret = snprintf(buf, buflen, "%"PRIi64, datum->data.integer);
953 }
954 else if (datum->type == SDB_TYPE_DECIMAL) {
955 if (isnan(datum->data.decimal))
956 ret = snprintf(buf, buflen, "nan");
957 else
958 ret = snprintf(buf, buflen, "%g", datum->data.decimal);
959 }
960 else if (datum->type == SDB_TYPE_STRING) {
961 if (! datum->data.string)
962 is_null = 1;
963 else {
964 pos = 0;
965 for (i = 0; i < strlen(datum->data.string); ++i) {
966 char byte = datum->data.string[i];
968 if ((byte == '\\') || (byte == '"')) {
969 tmp[pos] = '\\';
970 ++pos;
971 }
972 tmp[pos] = byte;
973 ++pos;
974 }
975 tmp[pos] = '\0';
976 data = tmp;
977 }
978 }
979 else if (datum->type == SDB_TYPE_DATETIME) {
980 if (! sdb_strftime(tmp, sizeof(tmp), "%F %T %z",
981 datum->data.datetime))
982 return -1;
983 tmp[sizeof(tmp) - 1] = '\0';
984 data = tmp;
985 }
986 else if (datum->type == SDB_TYPE_BINARY) {
987 pos = 0;
988 for (i = 0; i < datum->data.binary.length; ++i) {
989 int byte = (int)datum->data.binary.datum[i];
990 char hex[] = {'0', '1', '2', '3', '4', '5', '6', '7',
991 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
993 tmp[pos] = '\\';
994 tmp[pos + 1] = 'x';
995 pos += 2;
997 if (byte > 0xf) {
998 tmp[pos] = hex[byte >> 4];
999 ++pos;
1000 }
1001 tmp[pos] = hex[byte & 0xf];
1002 ++pos;
1003 }
1004 if (datum->data.binary.datum) {
1005 tmp[pos] = '\0';
1006 data = tmp;
1007 }
1008 else
1009 is_null = 1;
1010 }
1011 else if (datum->type == SDB_TYPE_REGEX) {
1012 if (! datum->data.re.raw)
1013 is_null = 1;
1014 else {
1015 snprintf(tmp, sizeof(tmp), "/%s/", datum->data.re.raw);
1016 data = tmp;
1017 }
1018 }
1019 else if (datum->type & SDB_TYPE_ARRAY) {
1020 ret = 1;
1021 if (buflen > 0)
1022 buf[0] = '[';
1023 for (i = 0; i < datum->data.array.length; ++i) {
1024 sdb_data_t v = SDB_DATA_INIT;
1025 size_t n;
1027 if (ret > 1) {
1028 if (buflen > ret + 1) {
1029 buf[ret] = ',';
1030 buf[ret + 1] = ' ';
1031 }
1032 ret += 2;
1033 }
1035 sdb_data_array_get(datum, i, &v);
1036 if (buflen > ret)
1037 n = sdb_data_format(&v, buf + ret, buflen - ret, quoted);
1038 else
1039 n = sdb_data_format(&v, NULL, 0, quoted);
1040 if (n > 0)
1041 ret += n;
1042 else
1043 break;
1044 }
1045 if (buflen > ret + 1) {
1046 buf[ret] = ']';
1047 buf[ret + 1] = '\0';
1048 }
1049 ++ret;
1050 }
1052 if (is_null) {
1053 /* never quote NULL */
1054 strncpy(buf, "NULL", buflen);
1055 ret = 4;
1056 }
1057 else if (data) {
1058 if (quoted == SDB_UNQUOTED)
1059 ret = snprintf(buf, buflen, "%s", data);
1060 else if (quoted == SDB_SINGLE_QUOTED)
1061 ret = snprintf(buf, buflen, "'%s'", data);
1062 else
1063 ret = snprintf(buf, buflen, "\"%s\"", data);
1064 }
1065 if (buflen > 0)
1066 buf[buflen - 1] = '\0';
1067 return ret;
1068 } /* sdb_data_format */
1070 int
1071 sdb_data_parse(const char *str, int type, sdb_data_t *data)
1072 {
1073 sdb_data_t tmp;
1075 char *endptr = NULL;
1077 if (! str) {
1078 errno = EINVAL;
1079 return -1;
1080 }
1082 errno = 0;
1083 if (type == SDB_TYPE_INTEGER) {
1084 tmp.data.integer = strtoll(str, &endptr, 0);
1085 }
1086 else if (type == SDB_TYPE_DECIMAL) {
1087 tmp.data.decimal = strtod(str, &endptr);
1088 }
1089 else if (type == SDB_TYPE_STRING) {
1090 tmp.data.string = strdup(str);
1091 if (! tmp.data.string)
1092 return -1;
1093 }
1094 else if (type == SDB_TYPE_DATETIME) {
1095 double datetime = strtod(str, &endptr);
1096 tmp.data.datetime = DOUBLE_TO_SDB_TIME(datetime);
1097 }
1098 else if (type == SDB_TYPE_BINARY) {
1099 /* we don't support any binary information containing 0-bytes here */
1100 tmp.data.binary.datum = (unsigned char *)strdup(str);
1101 if (! tmp.data.binary.datum)
1102 return -1;
1103 tmp.data.binary.length = strlen(str);
1104 }
1105 else if (type == SDB_TYPE_REGEX) {
1106 tmp.data.re.raw = strdup(str);
1107 if (! tmp.data.re.raw)
1108 return -1;
1109 if (regcomp(&tmp.data.re.regex, tmp.data.re.raw,
1110 REG_EXTENDED | REG_ICASE | REG_NOSUB)) {
1111 sdb_log(SDB_LOG_ERR, "core: Failed to compile regular "
1112 "expression '%s'", tmp.data.re.raw);
1113 free(tmp.data.re.raw);
1114 return -1;
1115 }
1116 if (! data) {
1117 tmp.type = SDB_TYPE_REGEX;
1118 sdb_data_free_datum(&tmp);
1119 }
1120 }
1121 else if (type & SDB_TYPE_ARRAY) {
1122 /* TODO */
1123 errno = ENOTSUP;
1124 return -1;
1125 }
1126 else {
1127 errno = EINVAL;
1128 return -1;
1129 }
1131 if ((type == SDB_TYPE_INTEGER) || (type == SDB_TYPE_DECIMAL)
1132 || (type == SDB_TYPE_DATETIME)) {
1133 if (errno || (str == endptr)) {
1134 char errbuf[1024];
1135 sdb_log(SDB_LOG_ERR, "core: Failed to parse string "
1136 "'%s' as numeric value (type %i): %s", str, type,
1137 sdb_strerror(errno, errbuf, sizeof(errbuf)));
1138 return -1;
1139 }
1140 else if (endptr && (*endptr != '\0'))
1141 sdb_log(SDB_LOG_WARNING, "core: Ignoring garbage after "
1142 "number while parsing numeric value (type %i): %s.",
1143 type, endptr);
1144 }
1146 if (data) {
1147 *data = tmp;
1148 data->type = type;
1149 }
1150 return 0;
1151 } /* sdb_data_parse */
1153 size_t
1154 sdb_data_sizeof(int type)
1155 {
1156 sdb_data_t v;
1157 if (type == SDB_TYPE_INTEGER)
1158 return sizeof(v.data.integer);
1159 else if (type == SDB_TYPE_DECIMAL)
1160 return sizeof(v.data.decimal);
1161 else if (type == SDB_TYPE_STRING)
1162 return sizeof(v.data.string);
1163 else if (type == SDB_TYPE_DATETIME)
1164 return sizeof(v.data.datetime);
1165 else if (type == SDB_TYPE_BINARY)
1166 return sizeof(v.data.binary);
1167 else if (type == SDB_TYPE_REGEX)
1168 return sizeof(v.data.re);
1169 return 0;
1170 } /* sdb_data_sizeof */
1172 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */