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 ((d1->type & SDB_TYPE_ARRAY) || (d2->type & SDB_TYPE_ARRAY)) {
672 /* TODO */
673 errno = ENOTSUP;
674 return -1;
675 }
677 if (sdb_data_isnull(d1))
678 d1 = NULL;
679 if (sdb_data_isnull(d2))
680 d2 = NULL;
682 CMP_NULL(d1, d2);
684 if (sdb_data_format(d1, d1_str, sizeof(d1_str), SDB_UNQUOTED) < 0)
685 return SDB_CMP(sizeof(d1_str), sizeof(d2_str));
686 if (sdb_data_format(d2, d2_str, sizeof(d2_str), SDB_UNQUOTED) < 0)
687 return SDB_CMP(sizeof(d1_str), sizeof(d2_str));
689 return strcasecmp(d1_str, d2_str);
690 #undef CMP_NULL
691 } /* sdb_data_strcmp */
693 bool
694 sdb_data_isnull(const sdb_data_t *datum)
695 {
696 if (! datum)
697 return 1;
698 if (datum->type == SDB_TYPE_NULL)
699 return 1;
700 if ((datum->type == SDB_TYPE_STRING) && (! datum->data.string))
701 return 1;
702 if ((datum->type == SDB_TYPE_BINARY) && (! datum->data.binary.datum))
703 return 1;
704 if ((datum->type == SDB_TYPE_REGEX) && (! datum->data.re.raw))
705 return 1;
706 return 0;
707 } /* sdb_data_isnull */
709 bool
710 sdb_data_inarray(const sdb_data_t *value, const sdb_data_t *array)
711 {
712 const void *values;
713 size_t length, i;
714 int type = value->type & 0xff;
716 if (sdb_data_isnull(value) || sdb_data_isnull(array))
717 return 0;
718 if (! (array->type & SDB_TYPE_ARRAY))
719 return 0;
720 if ((value->type & 0xff) != (array->type & 0xff))
721 return 0;
723 if (value->type & SDB_TYPE_ARRAY) {
724 values = value->data.array.values;
725 length = value->data.array.length;
726 }
727 else {
728 values = &value->data;
729 length = 1;
730 }
732 for (i = 0; i < length; ++i) {
733 size_t j;
735 if (type == SDB_TYPE_INTEGER) {
736 int64_t *v = array->data.array.values;
737 for (j = 0; j < array->data.array.length; ++j)
738 if (((const int64_t *)values)[i] == v[j])
739 break;
740 }
741 else if (type == SDB_TYPE_DECIMAL) {
742 double *v = array->data.array.values;
743 for (j = 0; j < array->data.array.length; ++j)
744 if (((const double *)values)[i] == v[j])
745 break;
746 }
747 else if (type == SDB_TYPE_STRING) {
748 char **v = array->data.array.values;
749 for (j = 0; j < array->data.array.length; ++j)
750 if (!strcasecmp(((const char * const*)values)[i], v[j]))
751 break;
752 }
753 else {
754 /* TODO */
755 errno = ENOTSUP;
756 return 0;
757 }
759 if (j >= array->data.array.length)
760 /* value not found */
761 return 0;
762 }
763 return 1;
764 } /* sdb_data_inarray */
766 int
767 sdb_data_array_get(const sdb_data_t *array, size_t i, sdb_data_t *value)
768 {
769 sdb_data_t tmp = SDB_DATA_INIT;
770 int type;
772 if ((! array) || (! (array->type & SDB_TYPE_ARRAY)))
773 return -1;
774 if (i >= array->data.array.length)
775 return -1;
777 type = array->type & 0xff;
778 if (type == SDB_TYPE_INTEGER) {
779 int64_t *v = array->data.array.values;
780 tmp.data.integer = v[i];
781 }
782 else if (type == SDB_TYPE_DECIMAL) {
783 double *v = array->data.array.values;
784 tmp.data.decimal = v[i];
785 }
786 else if (type == SDB_TYPE_STRING) {
787 char **v = array->data.array.values;
788 tmp.data.string = v[i];
789 }
790 else {
791 /* TODO */
792 errno = ENOTSUP;
793 return -1;
794 }
796 if (value) {
797 *value = tmp;
798 value->type = type;
799 }
800 return 0;
801 } /* sdb_data_array_get */
803 int
804 sdb_data_parse_op(const char *op)
805 {
806 if (! strcmp(op, "+"))
807 return SDB_DATA_ADD;
808 else if (! strcmp(op, "-"))
809 return SDB_DATA_SUB;
810 else if (! strcmp(op, "*"))
811 return SDB_DATA_MUL;
812 else if (! strcmp(op, "/"))
813 return SDB_DATA_DIV;
814 else if (! strcmp(op, "%"))
815 return SDB_DATA_MOD;
816 else if (! strcmp(op, "||"))
817 return SDB_DATA_CONCAT;
818 return -1;
819 } /* sdb_data_parse_op */
821 int
822 sdb_data_expr_eval(int op, const sdb_data_t *d1, const sdb_data_t *d2,
823 sdb_data_t *res)
824 {
825 if ((! d1) || (! d2) || (! res))
826 return -1;
827 if (sdb_data_isnull(d1) || sdb_data_isnull(d2)) {
828 *res = SDB_DATA_NULL;
829 return 0;
830 }
831 switch (op) {
832 case SDB_DATA_CONCAT: return data_concat(d1, d2, res);
833 case SDB_DATA_ADD: return data_lin(d1, 1, d2, res);
834 case SDB_DATA_SUB: return data_lin(d1, -1, d2, res);
835 case SDB_DATA_MUL: return data_mul(d1, d2, res);
836 case SDB_DATA_DIV: return data_div(d1, d2, res, NULL);
837 case SDB_DATA_MOD: return data_div(d1, d2, NULL, res);
838 }
839 return -1;
840 } /* sdb_data_expr_eval */
842 int
843 sdb_data_expr_type(int op, int type1, int type2)
844 {
845 int types_num = (int)SDB_STATIC_ARRAY_LEN(op_matrix[0]);
847 assert(SDB_STATIC_ARRAY_LEN(op_matrix[0])
848 == SDB_STATIC_ARRAY_LEN(op_matrix[0][0]));
850 if ((op <= 0) || (SDB_STATIC_ARRAY_LEN(op_matrix) < (size_t)op))
851 return -1;
853 /* arrays only support concat; element type has to match */
854 if ((type1 & SDB_TYPE_ARRAY) || (type2 & SDB_TYPE_ARRAY)) {
855 if (((type1 & 0xff) != (type2 & 0xff)) || (op != SDB_DATA_CONCAT))
856 return -1;
857 return type1 | SDB_TYPE_ARRAY;
858 }
859 if ((type1 < 0) || (types_num < type1)
860 || (type2 < 0) || (types_num < type2))
861 return -1;
863 if ((type1 == SDB_TYPE_NULL) || (type2 == SDB_TYPE_NULL))
864 return SDB_TYPE_NULL;
865 return op_matrix[op - 1][type1 - 1][type2 - 1];
866 } /* sdb_data_expr_type */
868 size_t
869 sdb_data_strlen(const sdb_data_t *datum)
870 {
871 if (! datum)
872 return 0;
874 if (datum->type == SDB_TYPE_INTEGER) {
875 /* log(64) */
876 return 20;
877 }
878 else if (datum->type == SDB_TYPE_DECIMAL) {
879 /* XXX: -d.dddddde+dd or -ddddd.dddddd */
880 return 42;
881 }
882 else if (datum->type == SDB_TYPE_STRING) {
883 if (! datum->data.string)
884 return 6; /* NULL */
885 /* in the worst case, each character needs to be escaped */
886 return 2 * strlen(datum->data.string) + 2;
887 }
888 else if (datum->type == SDB_TYPE_DATETIME) {
889 /* "YYYY-MM-DD HH:MM:SS +zzzz" */
890 return 27;
891 }
892 else if (datum->type == SDB_TYPE_BINARY) {
893 if (! datum->data.binary.datum)
894 return 6; /* NULL */
895 /* "\xNN" */
896 return 4 * datum->data.binary.length + 2;
897 }
898 else if (datum->type == SDB_TYPE_REGEX) {
899 if (! datum->data.re.raw)
900 return 6; /* NULL */
901 /* "/.../" */
902 return strlen(datum->data.re.raw) + 4;
903 }
904 else if (datum->type & SDB_TYPE_ARRAY) {
905 size_t len = 2; /* [] */
906 size_t i;
907 for (i = 0; i < datum->data.array.length; ++i) {
908 sdb_data_t v = SDB_DATA_INIT;
909 sdb_data_array_get(datum, i, &v);
910 len += sdb_data_strlen(&v) + 1;
911 }
912 return len;
913 }
914 return 0;
915 } /* sdb_data_strlen */
917 int
918 sdb_data_format(const sdb_data_t *datum, char *buf, size_t buflen, int quoted)
919 {
920 char tmp[sdb_data_strlen(datum) + 1];
921 char *data = NULL;
922 bool is_null = 0;
923 int ret = -1;
925 size_t i, pos;
927 if ((! datum) || (! buf) || (! buflen))
928 return -1;
930 if (datum->type == SDB_TYPE_INTEGER) {
931 ret = snprintf(buf, buflen, "%"PRIi64, datum->data.integer);
932 }
933 else if (datum->type == SDB_TYPE_DECIMAL) {
934 if (isnan(datum->data.decimal))
935 ret = snprintf(buf, buflen, "nan");
936 else
937 ret = snprintf(buf, buflen, "%g", datum->data.decimal);
938 }
939 else if (datum->type == SDB_TYPE_STRING) {
940 if (! datum->data.string)
941 is_null = 1;
942 else {
943 pos = 0;
944 for (i = 0; i < strlen(datum->data.string); ++i) {
945 char byte = datum->data.string[i];
947 if ((byte == '\\') || (byte == '"')) {
948 tmp[pos] = '\\';
949 ++pos;
950 }
951 tmp[pos] = byte;
952 ++pos;
953 }
954 tmp[pos] = '\0';
955 data = tmp;
956 }
957 }
958 else if (datum->type == SDB_TYPE_DATETIME) {
959 if (! sdb_strftime(tmp, sizeof(tmp), "%F %T %z",
960 datum->data.datetime))
961 return -1;
962 tmp[sizeof(tmp) - 1] = '\0';
963 data = tmp;
964 }
965 else if (datum->type == SDB_TYPE_BINARY) {
966 pos = 0;
967 for (i = 0; i < datum->data.binary.length; ++i) {
968 int byte = (int)datum->data.binary.datum[i];
969 char hex[] = {'0', '1', '2', '3', '4', '5', '6', '7',
970 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
972 tmp[pos] = '\\';
973 tmp[pos + 1] = 'x';
974 pos += 2;
976 if (byte > 0xf) {
977 tmp[pos] = hex[byte >> 4];
978 ++pos;
979 }
980 tmp[pos] = hex[byte & 0xf];
981 ++pos;
982 }
983 if (datum->data.binary.datum) {
984 tmp[pos] = '\0';
985 data = tmp;
986 }
987 else
988 is_null = 1;
989 }
990 else if (datum->type == SDB_TYPE_REGEX) {
991 if (! datum->data.re.raw)
992 is_null = 1;
993 else {
994 snprintf(tmp, sizeof(tmp), "/%s/", datum->data.re.raw);
995 data = tmp;
996 }
997 }
998 else if (datum->type & SDB_TYPE_ARRAY) {
999 ret = 1;
1000 buf[0] = '[';
1001 for (i = 0; i < datum->data.array.length; ++i) {
1002 sdb_data_t v = SDB_DATA_INIT;
1003 int n;
1004 if ((size_t)ret >= buflen - 1)
1005 break;
1007 if (ret > 1) {
1008 buf[ret] = ',';
1009 buf[ret + 1] = ' ';
1010 ret += 2;
1011 }
1013 sdb_data_array_get(datum, i, &v);
1014 n = sdb_data_format(&v, buf + ret, buflen - ret, quoted);
1015 if (n > 0)
1016 ret += n;
1017 else
1018 break;
1019 }
1020 if ((size_t)ret < buflen - 1) {
1021 buf[ret] = ']';
1022 buf[ret + 1] = '\0';
1023 ++ret;
1024 }
1025 }
1027 if (is_null) {
1028 /* never quote NULL */
1029 strncpy(buf, "NULL", buflen);
1030 ret = (int)SDB_MIN(buflen, 4);
1031 }
1032 else if (data) {
1033 if (quoted == SDB_UNQUOTED)
1034 ret = snprintf(buf, buflen, "%s", data);
1035 else if (quoted == SDB_SINGLE_QUOTED)
1036 ret = snprintf(buf, buflen, "'%s'", data);
1037 else
1038 ret = snprintf(buf, buflen, "\"%s\"", data);
1039 }
1040 buf[buflen - 1] = '\0';
1041 return ret;
1042 } /* sdb_data_format */
1044 int
1045 sdb_data_parse(const char *str, int type, sdb_data_t *data)
1046 {
1047 sdb_data_t tmp;
1049 char *endptr = NULL;
1051 if (! str) {
1052 errno = EINVAL;
1053 return -1;
1054 }
1056 errno = 0;
1057 if (type == SDB_TYPE_INTEGER) {
1058 tmp.data.integer = strtoll(str, &endptr, 0);
1059 }
1060 else if (type == SDB_TYPE_DECIMAL) {
1061 tmp.data.decimal = strtod(str, &endptr);
1062 }
1063 else if (type == SDB_TYPE_STRING) {
1064 tmp.data.string = strdup(str);
1065 if (! tmp.data.string)
1066 return -1;
1067 }
1068 else if (type == SDB_TYPE_DATETIME) {
1069 double datetime = strtod(str, &endptr);
1070 tmp.data.datetime = DOUBLE_TO_SDB_TIME(datetime);
1071 }
1072 else if (type == SDB_TYPE_BINARY) {
1073 /* we don't support any binary information containing 0-bytes here */
1074 tmp.data.binary.datum = (unsigned char *)strdup(str);
1075 if (! tmp.data.binary.datum)
1076 return -1;
1077 tmp.data.binary.length = strlen(str);
1078 }
1079 else if (type == SDB_TYPE_REGEX) {
1080 tmp.data.re.raw = strdup(str);
1081 if (! tmp.data.re.raw)
1082 return -1;
1083 if (regcomp(&tmp.data.re.regex, tmp.data.re.raw,
1084 REG_EXTENDED | REG_ICASE | REG_NOSUB)) {
1085 sdb_log(SDB_LOG_ERR, "core: Failed to compile regular "
1086 "expression '%s'", tmp.data.re.raw);
1087 free(tmp.data.re.raw);
1088 return -1;
1089 }
1090 if (! data) {
1091 tmp.type = SDB_TYPE_REGEX;
1092 sdb_data_free_datum(&tmp);
1093 }
1094 }
1095 else if (type & SDB_TYPE_ARRAY) {
1096 /* TODO */
1097 errno = ENOTSUP;
1098 return -1;
1099 }
1100 else {
1101 errno = EINVAL;
1102 return -1;
1103 }
1105 if ((type == SDB_TYPE_INTEGER) || (type == SDB_TYPE_DECIMAL)
1106 || (type == SDB_TYPE_DATETIME)) {
1107 if (errno || (str == endptr)) {
1108 char errbuf[1024];
1109 sdb_log(SDB_LOG_ERR, "core: Failed to parse string "
1110 "'%s' as numeric value (type %i): %s", str, type,
1111 sdb_strerror(errno, errbuf, sizeof(errbuf)));
1112 return -1;
1113 }
1114 else if (endptr && (*endptr != '\0'))
1115 sdb_log(SDB_LOG_WARNING, "core: Ignoring garbage after "
1116 "number while parsing numeric value (type %i): %s.",
1117 type, endptr);
1118 }
1120 if (data) {
1121 *data = tmp;
1122 data->type = type;
1123 }
1124 return 0;
1125 } /* sdb_data_parse */
1127 size_t
1128 sdb_data_sizeof(int type)
1129 {
1130 sdb_data_t v;
1131 if (type == SDB_TYPE_INTEGER)
1132 return sizeof(v.data.integer);
1133 else if (type == SDB_TYPE_DECIMAL)
1134 return sizeof(v.data.decimal);
1135 else if (type == SDB_TYPE_STRING)
1136 return sizeof(v.data.string);
1137 else if (type == SDB_TYPE_DATETIME)
1138 return sizeof(v.data.datetime);
1139 else if (type == SDB_TYPE_BINARY)
1140 return sizeof(v.data.binary);
1141 else if (type == SDB_TYPE_REGEX)
1142 return sizeof(v.data.re);
1143 return 0;
1144 } /* sdb_data_sizeof */
1146 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */