58c8b524e1111c662e7587aa5e1614d10d084b5d
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][7][7] = {
59 /* SDB_DATA_ADD */
60 {
61 { -1, -1, -1, -1, -1, -1, -1, },
62 { -1, SDB_TYPE_INTEGER, -1, -1, -1, -1, -1 },
63 { -1, -1, SDB_TYPE_DECIMAL, -1, -1, -1, -1 },
64 { -1, -1, -1, -1, -1, -1, -1 },
65 { -1, -1, -1, -1, SDB_TYPE_DATETIME, -1, -1 },
66 { -1, -1, -1, -1, -1, -1, -1 },
67 { -1, -1, -1, -1, -1, -1, -1 },
68 },
70 /* SDB_DATA_SUB */
71 {
72 { -1, -1, -1, -1, -1, -1, -1, },
73 { -1, SDB_TYPE_INTEGER, -1, -1, -1, -1, -1 },
74 { -1, -1, SDB_TYPE_DECIMAL, -1, -1, -1, -1 },
75 { -1, -1, -1, -1, -1, -1, -1 },
76 { -1, -1, -1, -1, SDB_TYPE_DATETIME, -1, -1 },
77 { -1, -1, -1, -1, -1, -1, -1 },
78 { -1, -1, -1, -1, -1, -1, -1 },
79 },
81 /* SDB_DATA_MUL */
82 {
83 { -1, -1, -1, -1, -1, -1, -1, },
84 { -1, SDB_TYPE_INTEGER, -1, -1, SDB_TYPE_DATETIME, -1, -1 },
85 { -1, -1, SDB_TYPE_DECIMAL, -1, SDB_TYPE_DATETIME, -1, -1 },
86 { -1, -1, -1, -1, -1, -1, -1 },
87 { -1, SDB_TYPE_DATETIME, SDB_TYPE_DATETIME, -1, SDB_TYPE_DATETIME, -1, -1 },
88 { -1, -1, -1, -1, -1, -1, -1 },
89 { -1, -1, -1, -1, -1, -1, -1 },
90 },
92 /* SDB_DATA_DIV */
93 {
94 { -1, -1, -1, -1, -1, -1, -1, },
95 { -1, SDB_TYPE_INTEGER, -1, -1, -1, -1, -1 },
96 { -1, -1, SDB_TYPE_DECIMAL, -1, -1, -1, -1 },
97 { -1, -1, -1, -1, -1, -1, -1 },
98 { -1, SDB_TYPE_DATETIME, SDB_TYPE_DATETIME, -1, SDB_TYPE_DATETIME, -1, -1 },
99 { -1, -1, -1, -1, -1, -1, -1 },
100 { -1, -1, -1, -1, -1, -1, -1 },
101 },
103 /* SDB_DATA_MOD */
104 {
105 { -1, -1, -1, -1, -1, -1, -1, },
106 { -1, SDB_TYPE_INTEGER, -1, -1, -1, -1, -1 },
107 { -1, -1, SDB_TYPE_DECIMAL, -1, -1, -1, -1 },
108 { -1, -1, -1, -1, -1, -1, -1 },
109 { -1, SDB_TYPE_DATETIME, SDB_TYPE_DATETIME, -1, SDB_TYPE_DATETIME, -1, -1 },
110 { -1, -1, -1, -1, -1, -1, -1 },
111 { -1, -1, -1, -1, -1, -1, -1 },
112 },
114 /* SDB_DATA_CONCAT */
115 {
116 { -1, -1, -1, -1, -1, -1, -1, },
117 { -1, -1, -1, -1, -1, -1, -1 },
118 { -1, -1, -1, -1, -1, -1, -1 },
119 { -1, -1, -1, SDB_TYPE_STRING, -1, -1, -1 },
120 { -1, -1, -1, -1, -1, -1, -1 },
121 { -1, -1, -1, -1, -1, SDB_TYPE_BINARY, -1 },
122 { -1, -1, -1, -1, -1, -1, -1 },
123 },
124 };
126 /*
127 * private helper functions
128 */
130 /* this function supports in-place copies */
131 static int
132 copy_array_values(sdb_data_t *dst, const sdb_data_t *src, size_t elem_size)
133 {
134 int type = src->type & 0xff;
136 if ((type == SDB_TYPE_BOOLEAN) || (type == SDB_TYPE_INTEGER)
137 || (type == SDB_TYPE_DECIMAL)) {
138 if (dst != src)
139 memcpy(dst->data.array.values, src->data.array.values,
140 src->data.array.length * elem_size);
141 }
142 else if (type == SDB_TYPE_STRING) {
143 char **s = src->data.array.values;
144 char **d = dst->data.array.values;
145 size_t i;
147 for (i = 0; i < src->data.array.length; ++i) {
148 d[i] = strdup(s[i]);
149 if (! d[i])
150 return -1;
151 }
152 }
153 else {
154 /* TODO */
155 errno = ENOTSUP;
156 return -1;
157 }
158 return 0;
159 } /* copy_array_values */
161 static void
162 free_array_values(sdb_data_t *datum)
163 {
164 int type = datum->type & 0xff;
166 if (type == SDB_TYPE_STRING) {
167 char **v = datum->data.array.values;
168 size_t i;
170 for (i = 0; i < datum->data.array.length; ++i) {
171 if (v[i])
172 free(v[i]);
173 v[i] = NULL;
174 }
175 }
176 else if (type == SDB_TYPE_BINARY) {
177 struct {
178 size_t length;
179 unsigned char *datum;
180 } *v = datum->data.array.values;
181 size_t i;
183 for (i = 0; i < datum->data.array.length; ++i) {
184 if (v[i].datum)
185 free(v[i].datum);
186 v[i].datum = NULL;
187 }
188 }
189 else if (type == SDB_TYPE_REGEX) {
190 struct {
191 char *raw;
192 regex_t regex;
193 } *v = datum->data.array.values;
194 size_t i;
196 for (i = 0; i < datum->data.array.length; ++i) {
197 if (v[i].raw) {
198 free(v[i].raw);
199 regfree(&v[i].regex);
200 }
201 v[i].raw = NULL;
202 }
203 }
204 } /* free_array_values */
206 /* compare two arrays element-by-element returning how the first non-equal
207 * elements compare to each other */
208 static int
209 array_cmp(const sdb_data_t *a1, const sdb_data_t *a2)
210 {
211 int type = a1->type & 0xff;
212 size_t len, i;
214 assert((a1->type == a2->type) && (a1->type & SDB_TYPE_ARRAY));
216 len = SDB_MIN(a1->data.array.length, a2->data.array.length);
218 if (type == SDB_TYPE_BOOLEAN) {
219 bool *v1 = a1->data.array.values;
220 bool *v2 = a2->data.array.values;
222 for (i = 0; i < len; ++i)
223 if (v1[i] != v2[i])
224 return SDB_CMP(v1[i], v2[i]);
225 }
226 else if (type == SDB_TYPE_INTEGER) {
227 int64_t *v1 = a1->data.array.values;
228 int64_t *v2 = a2->data.array.values;
230 for (i = 0; i < len; ++i)
231 if (v1[i] != v2[i])
232 return SDB_CMP(v1[i], v2[i]);
233 }
234 else if (type == SDB_TYPE_DECIMAL) {
235 double *v1 = a1->data.array.values;
236 double *v2 = a2->data.array.values;
238 for (i = 0; i < len; ++i)
239 if (v1[i] != v2[i])
240 return SDB_CMP(v1[i], v2[i]);
241 }
242 else if (type == SDB_TYPE_STRING) {
243 char **v1 = a1->data.array.values;
244 char **v2 = a2->data.array.values;
246 for (i = 0; i < len; ++i) {
247 int diff = strcasecmp(v1[i], v2[i]);
248 if (diff)
249 return diff;
250 }
251 }
252 else if (type == SDB_TYPE_DATETIME) {
253 sdb_time_t *v1 = a1->data.array.values;
254 sdb_time_t *v2 = a2->data.array.values;
256 for (i = 0; i < len; ++i)
257 if (v1[i] != v2[i])
258 return SDB_CMP(v1[i], v2[i]);
259 }
260 else if (type == SDB_TYPE_BINARY) {
261 struct {
262 size_t length;
263 unsigned char *datum;
264 } *v1 = a1->data.array.values;
265 struct {
266 size_t length;
267 unsigned char *datum;
268 } *v2 = a2->data.array.values;
270 for (i = 0; i < len; ++i) {
271 int diff;
273 /* on a common prefix, the shorter datum sorts less */
274 if (v1[i].length < v2[i].length) {
275 diff = memcmp(v1[i].datum, v2[i].datum, v1[i].length);
276 diff = diff ? diff : -1;
277 }
278 else if (v1[i].length > v2[i].length) {
279 diff = memcmp(v1[i].datum, v2[i].datum, v2[i].length);
280 diff = diff ? diff : 1;
281 }
282 else
283 diff = memcmp(v1[i].datum, v2[i].datum, v1[i].length);
285 if (diff)
286 return diff;
287 }
288 }
289 else if (type == SDB_TYPE_REGEX) {
290 struct {
291 char *raw;
292 regex_t regex;
293 } *v1 = a1->data.array.values;
294 struct {
295 char *raw;
296 regex_t regex;
297 } *v2 = a2->data.array.values;
299 for (i = 0; i < len; ++i) {
300 int diff = strcasecmp(v1[i].raw, v2[i].raw);
301 if (diff)
302 return diff;
303 }
304 }
305 else {
306 errno = EINVAL;
307 /* but fall through to ensure stable sorting: */
308 }
309 return SDB_CMP(a1->data.array.length, a2->data.array.length);
310 } /* array_cmp */
312 /* Calculate the linear function 'd1 + n * d2'. */
313 static int
314 data_lin(const sdb_data_t *d1, int n, const sdb_data_t *d2, sdb_data_t *res)
315 {
316 if (d1->type != d2->type)
317 return -1;
319 if (d1->type == SDB_TYPE_INTEGER)
320 res->data.integer = d1->data.integer + (int64_t)n * d2->data.integer;
321 else if (d1->type == SDB_TYPE_DECIMAL)
322 res->data.decimal = d1->data.decimal + (double)n * d2->data.decimal;
323 else if (d1->type == SDB_TYPE_DATETIME)
324 res->data.datetime = d1->data.datetime + (sdb_time_t)n * d2->data.datetime;
325 else
326 return -1;
327 res->type = d1->type;
328 return 0;
329 } /* data_lin */
331 /* Multiply d1 with d2. */
332 static int
333 data_mul(const sdb_data_t *d1, const sdb_data_t *d2, sdb_data_t *res)
334 {
335 if (d1->type == SDB_TYPE_INTEGER) {
336 if (d2->type == SDB_TYPE_INTEGER)
337 res->data.integer = d1->data.integer * d2->data.integer;
338 else if (d2->type == SDB_TYPE_DATETIME) {
339 res->data.datetime = (sdb_time_t)d1->data.integer
340 * d2->data.datetime;
341 res->type = SDB_TYPE_DATETIME;
342 return 0;
343 }
344 else
345 return -1;
346 }
347 else if (d1->type == SDB_TYPE_DECIMAL) {
348 if (d2->type == SDB_TYPE_DECIMAL)
349 res->data.decimal = d1->data.decimal * d2->data.decimal;
350 else if (d2->type == SDB_TYPE_DATETIME) {
351 res->data.datetime = (sdb_time_t)(d1->data.decimal
352 * (double)d2->data.datetime);
353 res->type = SDB_TYPE_DATETIME;
354 return 0;
355 }
356 else
357 return -1;
358 }
359 else if (d1->type == SDB_TYPE_DATETIME) {
360 if (d2->type == SDB_TYPE_DATETIME)
361 res->data.datetime = d1->data.datetime
362 * d2->data.datetime;
363 else if (d2->type == SDB_TYPE_INTEGER)
364 res->data.datetime = d1->data.datetime
365 * (sdb_time_t)d2->data.integer;
366 else if (d2->type == SDB_TYPE_DECIMAL)
367 res->data.datetime = (sdb_time_t)((double)d1->data.datetime
368 * d2->data.decimal);
369 else
370 return -1;
371 }
372 else
373 return -1;
375 res->type = d1->type;
376 return 0;
377 } /* data_mul */
379 /* Device d1 by d2 and return the result and the remainder. */
380 static int
381 data_div(const sdb_data_t *d1, const sdb_data_t *d2,
382 sdb_data_t *res, sdb_data_t *rem)
383 {
384 if (d1->type == SDB_TYPE_INTEGER) {
385 if (d2->type != SDB_TYPE_INTEGER)
386 return -1;
387 if (res)
388 res->data.integer = d1->data.integer / d2->data.integer;
389 if (rem)
390 rem->data.integer = d1->data.integer % d2->data.integer;
391 }
392 else if (d1->type == SDB_TYPE_DECIMAL) {
393 if (d2->type != SDB_TYPE_DECIMAL)
394 return -1;
395 if (res)
396 res->data.decimal = d1->data.decimal / d2->data.decimal;
397 if (rem)
398 rem->data.decimal = fmod(d1->data.decimal, d2->data.decimal);
399 }
400 else if (d1->type == SDB_TYPE_DATETIME) {
401 if (d2->type == SDB_TYPE_DECIMAL) {
402 if (res)
403 res->data.datetime = (sdb_time_t)((double)d1->data.datetime
404 / d2->data.decimal);
405 if (rem) {
406 double tmp = fmod((double)d1->data.datetime, d2->data.decimal);
407 rem->data.datetime = (sdb_time_t)tmp;
408 }
409 }
410 else {
411 sdb_time_t a, b;
412 if (d2->type == SDB_TYPE_DATETIME) {
413 a = d1->data.datetime;
414 b = d2->data.datetime;
415 }
416 else if (d2->type == SDB_TYPE_INTEGER) {
417 a = d1->data.datetime;
418 b = (sdb_time_t)d2->data.integer;
419 }
420 else
421 return -1;
422 if (res)
423 res->data.datetime = a / b;
424 if (rem)
425 rem->data.datetime = a % b;
426 }
427 }
428 else
429 return -1;
431 if (res)
432 res->type = d1->type;
433 if (rem)
434 rem->type = d1->type;
435 return 0;
436 } /* data_div */
438 /* Concatenate d1 and d2. */
439 static int
440 data_concat(const sdb_data_t *d1, const sdb_data_t *d2, sdb_data_t *res)
441 {
442 unsigned char *new;
443 const unsigned char *s1, *s2;
444 size_t len1, len2, array1_len = 0, array2_len = 0;
446 if ((d1->type & 0xff) != (d2->type & 0xff))
447 return -1;
449 if ((d1->type & SDB_TYPE_ARRAY) || (d2->type & SDB_TYPE_ARRAY)) {
450 size_t elem_size = sdb_data_sizeof(d1->type & 0xff);
451 if (d1->type & SDB_TYPE_ARRAY) {
452 s1 = (const unsigned char *)d1->data.array.values;
453 array1_len = d1->data.array.length;
454 }
455 else {
456 /* As per C99, section 6.7.2.1, paragraph 14:
457 * "A pointer to a union object, suitably converted, points to
458 * each of its members" */
459 s1 = (const unsigned char *)&d1->data;
460 array1_len = 1;
461 }
462 if (d2->type & SDB_TYPE_ARRAY) {
463 s2 = (const unsigned char *)d2->data.array.values;
464 array2_len = d2->data.array.length;
465 }
466 else {
467 s2 = (const unsigned char *)&d2->data;
468 array2_len = 1;
469 }
470 len1 = array1_len * elem_size;
471 len2 = array2_len * elem_size;
472 }
473 else if (d1->type == SDB_TYPE_STRING) {
474 s1 = (unsigned char *)d1->data.string;
475 s2 = (unsigned char *)d2->data.string;
476 len1 = s1 ? strlen((const char *)s1) : 0;
477 len2 = s2 ? strlen((const char *)s2) : 0;
478 }
479 else if (d1->type == SDB_TYPE_BINARY) {
480 s1 = d1->data.binary.datum;
481 s2 = d2->data.binary.datum;
482 len1 = d1->data.binary.length;
483 len2 = d2->data.binary.length;
484 }
485 else
486 return -1;
488 new = malloc(len1 + len2 + 1);
489 if (! new)
490 return -1;
492 if (len1)
493 memcpy(new, s1, len1);
494 if (len2)
495 memcpy(new + len1, s2, len2);
496 new[len1 + len2] = '\0';
498 /* element types match and if either datum is an array,
499 * the result is an array as well */
500 res->type = d1->type | d2->type;
501 if (res->type == SDB_TYPE_STRING) {
502 res->data.string = (char *)new;
503 }
504 else if (res->type == SDB_TYPE_BINARY) {
505 res->data.binary.datum = new;
506 res->data.binary.length = len1 + len2;
507 }
508 else if (res->type & SDB_TYPE_ARRAY) {
509 res->data.array.values = new;
510 res->data.array.length = array1_len + array2_len;
511 if (copy_array_values(res, res, sdb_data_sizeof(res->type & 0xff))) {
512 /* this leaks already copied values but there's not much we can
513 * do and this should only happen if we're in trouble anyway */
514 free(new);
515 res->data.array.values = NULL;
516 res->data.array.length = 0;
517 return -1;
518 }
519 }
520 return 0;
521 } /* data_concat */
523 /*
524 * public API
525 */
527 const sdb_data_t SDB_DATA_NULL = SDB_DATA_INIT;
529 int
530 sdb_data_copy(sdb_data_t *dst, const sdb_data_t *src)
531 {
532 sdb_data_t tmp;
534 if ((! dst) || (! src))
535 return -1;
537 tmp = *src;
538 if (src->type == SDB_TYPE_STRING) {
539 if (src->data.string) {
540 tmp.data.string = strdup(src->data.string);
541 if (! tmp.data.string)
542 return -1;
543 }
544 }
545 else if (src->type == SDB_TYPE_BINARY) {
546 if (src->data.binary.datum) {
547 tmp.data.binary.datum = malloc(src->data.binary.length);
548 if (! tmp.data.binary.datum)
549 return -1;
550 memcpy(tmp.data.binary.datum, src->data.binary.datum,
551 src->data.binary.length);
552 }
553 }
554 else if (src->type == SDB_TYPE_REGEX) {
555 if (src->data.re.raw) {
556 tmp.data.re.raw = strdup(src->data.re.raw);
557 if (! tmp.data.re.raw)
558 return -1;
559 /* we need to recompile because the regex might point to
560 * dynamically allocated memory */
561 if (regcomp(&tmp.data.re.regex, tmp.data.re.raw,
562 REG_EXTENDED | REG_ICASE | REG_NOSUB)) {
563 free(tmp.data.re.raw);
564 return -1;
565 }
566 }
567 else
568 memset(&tmp.data.re.regex, 0, sizeof(tmp.data.re.regex));
569 }
570 else if (src->type & SDB_TYPE_ARRAY) {
571 if (src->data.array.values) {
572 size_t elem_size = sdb_data_sizeof(src->type & 0xff);
573 tmp.data.array.values = calloc(src->data.array.length, elem_size);
574 if (! tmp.data.array.values)
575 return -1;
576 if (copy_array_values(&tmp, src, elem_size)) {
577 sdb_data_free_datum(&tmp);
578 return -1;
579 }
580 }
581 }
583 sdb_data_free_datum(dst);
584 *dst = tmp;
585 return 0;
586 } /* sdb_data_copy */
588 void
589 sdb_data_free_datum(sdb_data_t *datum)
590 {
591 if (! datum)
592 return;
594 if (datum->type == SDB_TYPE_STRING) {
595 if (datum->data.string)
596 free(datum->data.string);
597 datum->data.string = NULL;
598 }
599 else if (datum->type == SDB_TYPE_BINARY) {
600 if (datum->data.binary.datum)
601 free(datum->data.binary.datum);
602 datum->data.binary.datum = NULL;
603 datum->data.binary.length = 0;
604 }
605 else if (datum->type == SDB_TYPE_REGEX) {
606 if (datum->data.re.raw) {
607 free(datum->data.re.raw);
608 regfree(&datum->data.re.regex);
609 }
610 datum->data.re.raw = NULL;
611 memset(&datum->data.re.regex, 0, sizeof(datum->data.re.regex));
612 }
613 else if (datum->type & SDB_TYPE_ARRAY) {
614 free_array_values(datum);
615 if (datum->data.array.values)
616 free(datum->data.array.values);
617 datum->data.array.values = NULL;
618 datum->data.array.length = 0;
619 }
620 } /* sdb_data_free_datum */
622 int
623 sdb_data_cmp(const sdb_data_t *d1, const sdb_data_t *d2)
624 {
625 #define CMP_NULL(a, b) \
626 do { \
627 if (!(a) && !(b)) return 0; \
628 if (!(a)) return -1; \
629 if (!(b)) return 1; \
630 } while (0)
632 CMP_NULL(d1, d2);
634 if (d1->type != d2->type)
635 return SDB_CMP(d1->type, d2->type);
637 if (d1->type == SDB_TYPE_BOOLEAN)
638 return SDB_CMP(d1->data.boolean, d2->data.boolean);
639 else if (d1->type == SDB_TYPE_INTEGER)
640 return SDB_CMP(d1->data.integer, d2->data.integer);
641 else if (d1->type == SDB_TYPE_DECIMAL)
642 return SDB_CMP(d1->data.decimal, d2->data.decimal);
643 else if (d1->type == SDB_TYPE_STRING) {
644 CMP_NULL(d1->data.string, d2->data.string);
645 return strcasecmp(d1->data.string, d2->data.string);
646 }
647 else if (d1->type == SDB_TYPE_DATETIME)
648 return SDB_CMP(d1->data.datetime, d2->data.datetime);
649 else if (d1->type == SDB_TYPE_BINARY) {
650 int diff;
652 CMP_NULL(d1->data.binary.datum, d2->data.binary.datum);
654 /* on a common prefix, the shorter datum sorts less */
655 if (d1->data.binary.length < d2->data.binary.length) {
656 diff = memcmp(d1->data.binary.datum, d2->data.binary.datum,
657 d1->data.binary.length);
658 diff = diff ? diff : -1;
659 }
660 else if (d1->data.binary.length > d2->data.binary.length) {
661 diff = memcmp(d1->data.binary.datum, d2->data.binary.datum,
662 d2->data.binary.length);
663 diff = diff ? diff : 1;
664 }
665 else
666 diff = memcmp(d1->data.binary.datum, d2->data.binary.datum,
667 d1->data.binary.length);
669 return diff;
670 }
671 else if (d1->type == SDB_TYPE_REGEX) {
672 CMP_NULL(d1->data.re.raw, d2->data.re.raw);
673 return strcmp(d1->data.re.raw, d2->data.re.raw);
674 }
675 else if (d1->type & SDB_TYPE_ARRAY) {
676 CMP_NULL(d1->data.array.values, d2->data.array.values);
677 return array_cmp(d1, d2);
678 }
679 return -1;
680 } /* sdb_data_cmp */
682 int
683 sdb_data_strcmp(const sdb_data_t *d1, const sdb_data_t *d2)
684 {
685 char d1_str[sdb_data_strlen(d1) + 1];
686 char d2_str[sdb_data_strlen(d2) + 1];
688 if (sdb_data_isnull(d1))
689 d1 = NULL;
690 if (sdb_data_isnull(d2))
691 d2 = NULL;
693 CMP_NULL(d1, d2);
695 if (! sdb_data_format(d1, d1_str, sizeof(d1_str), SDB_UNQUOTED))
696 return SDB_CMP(sizeof(d1_str), sizeof(d2_str));
697 if (! sdb_data_format(d2, d2_str, sizeof(d2_str), SDB_UNQUOTED))
698 return SDB_CMP(sizeof(d1_str), sizeof(d2_str));
700 return strcasecmp(d1_str, d2_str);
701 #undef CMP_NULL
702 } /* sdb_data_strcmp */
704 bool
705 sdb_data_isnull(const sdb_data_t *datum)
706 {
707 if (! datum)
708 return 1;
709 if (datum->type == SDB_TYPE_NULL)
710 return 1;
711 if ((datum->type == SDB_TYPE_STRING) && (! datum->data.string))
712 return 1;
713 if ((datum->type == SDB_TYPE_BINARY) && (! datum->data.binary.datum))
714 return 1;
715 if ((datum->type == SDB_TYPE_REGEX) && (! datum->data.re.raw))
716 return 1;
717 return 0;
718 } /* sdb_data_isnull */
720 bool
721 sdb_data_inarray(const sdb_data_t *value, const sdb_data_t *array)
722 {
723 const void *values;
724 size_t length, i;
725 int type = value->type & 0xff;
727 if (sdb_data_isnull(value) || sdb_data_isnull(array))
728 return 0;
729 if (! (array->type & SDB_TYPE_ARRAY))
730 return 0;
731 if ((value->type & 0xff) != (array->type & 0xff))
732 return 0;
734 if (value->type & SDB_TYPE_ARRAY) {
735 values = value->data.array.values;
736 length = value->data.array.length;
737 }
738 else {
739 values = &value->data;
740 length = 1;
741 }
743 for (i = 0; i < length; ++i) {
744 size_t j;
746 if (type == SDB_TYPE_BOOLEAN) {
747 bool *v = array->data.array.values;
748 for (j = 0; j < array->data.array.length; ++j)
749 if (((const bool *)values)[i] == v[j])
750 break;
751 }
752 else if (type == SDB_TYPE_INTEGER) {
753 int64_t *v = array->data.array.values;
754 for (j = 0; j < array->data.array.length; ++j)
755 if (((const int64_t *)values)[i] == v[j])
756 break;
757 }
758 else if (type == SDB_TYPE_DECIMAL) {
759 double *v = array->data.array.values;
760 for (j = 0; j < array->data.array.length; ++j)
761 if (((const double *)values)[i] == v[j])
762 break;
763 }
764 else if (type == SDB_TYPE_STRING) {
765 char **v = array->data.array.values;
766 for (j = 0; j < array->data.array.length; ++j)
767 if (!strcasecmp(((const char * const*)values)[i], v[j]))
768 break;
769 }
770 else {
771 /* TODO */
772 errno = ENOTSUP;
773 return 0;
774 }
776 if (j >= array->data.array.length)
777 /* value not found */
778 return 0;
779 }
780 return 1;
781 } /* sdb_data_inarray */
783 int
784 sdb_data_array_get(const sdb_data_t *array, size_t i, sdb_data_t *value)
785 {
786 sdb_data_t tmp = SDB_DATA_INIT;
787 int type;
789 if ((! array) || (! (array->type & SDB_TYPE_ARRAY)))
790 return -1;
791 if (i >= array->data.array.length)
792 return -1;
794 type = array->type & 0xff;
795 if (type == SDB_TYPE_BOOLEAN) {
796 bool *v = array->data.array.values;
797 tmp.data.boolean = v[i];
798 }
799 else if (type == SDB_TYPE_INTEGER) {
800 int64_t *v = array->data.array.values;
801 tmp.data.integer = v[i];
802 }
803 else if (type == SDB_TYPE_DECIMAL) {
804 double *v = array->data.array.values;
805 tmp.data.decimal = v[i];
806 }
807 else if (type == SDB_TYPE_STRING) {
808 char **v = array->data.array.values;
809 tmp.data.string = v[i];
810 }
811 else if (type == SDB_TYPE_DATETIME) {
812 sdb_time_t *v = array->data.array.values;
813 tmp.data.datetime = v[i];
814 }
815 else if (type == SDB_TYPE_BINARY) {
816 struct {
817 size_t length;
818 unsigned char *datum;
819 } *v = array->data.array.values;
820 assert(sizeof(tmp.data.binary) == sizeof(v[i]));
821 memcpy(&tmp.data.binary, &v[i], sizeof(v[i]));
822 }
823 else if (type == SDB_TYPE_REGEX) {
824 struct {
825 char *raw;
826 regex_t regex;
827 } *v = array->data.array.values;
828 assert(sizeof(tmp.data.re) == sizeof(v[i]));
829 memcpy(&tmp.data.re, &v[i], sizeof(v[i]));
830 }
831 else {
832 errno = EINVAL;
833 return -1;
834 }
836 if (value) {
837 *value = tmp;
838 value->type = type;
839 }
840 return 0;
841 } /* sdb_data_array_get */
843 int
844 sdb_data_parse_op(const char *op)
845 {
846 if (! strcmp(op, "+"))
847 return SDB_DATA_ADD;
848 else if (! strcmp(op, "-"))
849 return SDB_DATA_SUB;
850 else if (! strcmp(op, "*"))
851 return SDB_DATA_MUL;
852 else if (! strcmp(op, "/"))
853 return SDB_DATA_DIV;
854 else if (! strcmp(op, "%"))
855 return SDB_DATA_MOD;
856 else if (! strcmp(op, "||"))
857 return SDB_DATA_CONCAT;
858 return -1;
859 } /* sdb_data_parse_op */
861 int
862 sdb_data_expr_eval(int op, const sdb_data_t *d1, const sdb_data_t *d2,
863 sdb_data_t *res)
864 {
865 if ((! d1) || (! d2) || (! res))
866 return -1;
867 if (sdb_data_isnull(d1) || sdb_data_isnull(d2)) {
868 *res = SDB_DATA_NULL;
869 return 0;
870 }
871 switch (op) {
872 case SDB_DATA_CONCAT: return data_concat(d1, d2, res);
873 case SDB_DATA_ADD: return data_lin(d1, 1, d2, res);
874 case SDB_DATA_SUB: return data_lin(d1, -1, d2, res);
875 case SDB_DATA_MUL: return data_mul(d1, d2, res);
876 case SDB_DATA_DIV: return data_div(d1, d2, res, NULL);
877 case SDB_DATA_MOD: return data_div(d1, d2, NULL, res);
878 }
879 return -1;
880 } /* sdb_data_expr_eval */
882 int
883 sdb_data_expr_type(int op, int type1, int type2)
884 {
885 int types_num = (int)SDB_STATIC_ARRAY_LEN(op_matrix[0]);
887 assert(SDB_STATIC_ARRAY_LEN(op_matrix[0])
888 == SDB_STATIC_ARRAY_LEN(op_matrix[0][0]));
890 if ((op <= 0) || (SDB_STATIC_ARRAY_LEN(op_matrix) < (size_t)op))
891 return -1;
893 /* arrays only support concat; element type has to match */
894 if ((type1 & SDB_TYPE_ARRAY) || (type2 & SDB_TYPE_ARRAY)) {
895 if (((type1 & 0xff) != (type2 & 0xff)) || (op != SDB_DATA_CONCAT))
896 return -1;
897 return type1 | SDB_TYPE_ARRAY;
898 }
899 if ((type1 < 0) || (types_num < type1)
900 || (type2 < 0) || (types_num < type2))
901 return -1;
903 if ((type1 == SDB_TYPE_NULL) || (type2 == SDB_TYPE_NULL))
904 return SDB_TYPE_NULL;
905 return op_matrix[op - 1][type1 - 1][type2 - 1];
906 } /* sdb_data_expr_type */
908 size_t
909 sdb_data_strlen(const sdb_data_t *datum)
910 {
911 if (! datum)
912 return 0;
914 if (sdb_data_isnull(datum)) {
915 /* NULL */
916 return 4;
917 }
918 switch (datum->type) {
919 case SDB_TYPE_BOOLEAN:
920 /* true | false */
921 return 5;
922 case SDB_TYPE_INTEGER:
923 /* log(64) */
924 return 20;
925 case SDB_TYPE_DECIMAL:
926 /* XXX: -d.dddddde+dd or -ddddd.dddddd */
927 return 42;
928 case SDB_TYPE_STRING:
929 if (! datum->data.string)
930 return 6; /* NULL */
931 /* in the worst case, each character needs to be escaped */
932 return 2 * strlen(datum->data.string) + 2;
933 case SDB_TYPE_DATETIME:
934 /* "YYYY-MM-DD HH:MM:SS[.nnnnnnnnn] +zzzz" */
935 return 37;
936 case SDB_TYPE_BINARY:
937 if (! datum->data.binary.datum)
938 return 6; /* NULL */
939 /* "\xNN" */
940 return 4 * datum->data.binary.length + 2;
941 case SDB_TYPE_REGEX:
942 if (! datum->data.re.raw)
943 return 6; /* NULL */
944 /* "/.../" */
945 return strlen(datum->data.re.raw) + 4;
946 }
947 if (datum->type & SDB_TYPE_ARRAY) {
948 size_t len = 2; /* [] */
949 size_t i;
950 for (i = 0; i < datum->data.array.length; ++i) {
951 sdb_data_t v = SDB_DATA_INIT;
952 sdb_data_array_get(datum, i, &v);
953 len += sdb_data_strlen(&v) + 1;
954 }
955 return len;
956 }
957 return 0;
958 } /* sdb_data_strlen */
960 size_t
961 sdb_data_format(const sdb_data_t *datum, char *buf, size_t buflen, int quoted)
962 {
963 char tmp[sdb_data_strlen(datum) + 1];
964 char *data = NULL;
965 bool is_null = 0;
966 size_t ret = 0;
968 size_t i, pos;
970 if (! datum)
971 return 0;
973 if (datum->type == SDB_TYPE_NULL) {
974 strncpy(buf, "NULL", buflen);
975 ret = 4;
976 }
977 else if (datum->type == SDB_TYPE_BOOLEAN) {
978 if (datum->data.boolean) {
979 strncpy(buf, "true", buflen);
980 ret = 4;
981 }
982 else {
983 strncpy(buf, "false", buflen);
984 ret = 5;
985 }
986 }
987 else if (datum->type == SDB_TYPE_INTEGER) {
988 ret = snprintf(buf, buflen, "%"PRIi64, datum->data.integer);
989 }
990 else if (datum->type == SDB_TYPE_DECIMAL) {
991 if (isnan(datum->data.decimal))
992 ret = snprintf(buf, buflen, "nan");
993 else
994 ret = snprintf(buf, buflen, "%g", datum->data.decimal);
995 }
996 else if (datum->type == SDB_TYPE_STRING) {
997 if (! datum->data.string)
998 is_null = 1;
999 else {
1000 pos = 0;
1001 for (i = 0; i < strlen(datum->data.string); ++i) {
1002 char byte = datum->data.string[i];
1004 if ((byte == '\\') || (byte == '"')) {
1005 tmp[pos] = '\\';
1006 ++pos;
1007 }
1008 tmp[pos] = byte;
1009 ++pos;
1010 }
1011 tmp[pos] = '\0';
1012 data = tmp;
1013 }
1014 }
1015 else if (datum->type == SDB_TYPE_DATETIME) {
1016 if (! sdb_strftime(tmp, sizeof(tmp), datum->data.datetime))
1017 return -1;
1018 tmp[sizeof(tmp) - 1] = '\0';
1019 data = tmp;
1020 }
1021 else if (datum->type == SDB_TYPE_BINARY) {
1022 pos = 0;
1023 for (i = 0; i < datum->data.binary.length; ++i) {
1024 int byte = (int)datum->data.binary.datum[i];
1025 char hex[] = {'0', '1', '2', '3', '4', '5', '6', '7',
1026 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
1028 tmp[pos] = '\\';
1029 tmp[pos + 1] = 'x';
1030 pos += 2;
1032 if (byte > 0xf) {
1033 tmp[pos] = hex[byte >> 4];
1034 ++pos;
1035 }
1036 tmp[pos] = hex[byte & 0xf];
1037 ++pos;
1038 }
1039 if (datum->data.binary.datum) {
1040 tmp[pos] = '\0';
1041 data = tmp;
1042 }
1043 else
1044 is_null = 1;
1045 }
1046 else if (datum->type == SDB_TYPE_REGEX) {
1047 if (! datum->data.re.raw)
1048 is_null = 1;
1049 else {
1050 snprintf(tmp, sizeof(tmp), "/%s/", datum->data.re.raw);
1051 data = tmp;
1052 }
1053 }
1054 else if (datum->type & SDB_TYPE_ARRAY) {
1055 ret = 1;
1056 if (buflen > 0)
1057 buf[0] = '[';
1058 for (i = 0; i < datum->data.array.length; ++i) {
1059 sdb_data_t v = SDB_DATA_INIT;
1060 size_t n;
1062 if (ret > 1) {
1063 if (buflen > ret + 1) {
1064 buf[ret] = ',';
1065 buf[ret + 1] = ' ';
1066 }
1067 ret += 2;
1068 }
1070 sdb_data_array_get(datum, i, &v);
1071 if (buflen > ret)
1072 n = sdb_data_format(&v, buf + ret, buflen - ret, quoted);
1073 else
1074 n = sdb_data_format(&v, NULL, 0, quoted);
1075 if (n > 0)
1076 ret += n;
1077 else
1078 break;
1079 }
1080 if (buflen > ret + 1) {
1081 buf[ret] = ']';
1082 buf[ret + 1] = '\0';
1083 }
1084 ++ret;
1085 }
1087 if (is_null) {
1088 /* never quote NULL */
1089 strncpy(buf, "NULL", buflen);
1090 ret = 4;
1091 }
1092 else if (data) {
1093 if (quoted == SDB_UNQUOTED)
1094 ret = snprintf(buf, buflen, "%s", data);
1095 else if (quoted == SDB_SINGLE_QUOTED)
1096 ret = snprintf(buf, buflen, "'%s'", data);
1097 else
1098 ret = snprintf(buf, buflen, "\"%s\"", data);
1099 }
1100 if (buflen > 0)
1101 buf[buflen - 1] = '\0';
1102 return ret;
1103 } /* sdb_data_format */
1105 int
1106 sdb_data_parse(const char *str, int type, sdb_data_t *data)
1107 {
1108 sdb_data_t tmp;
1110 char *endptr = NULL;
1112 if (! str) {
1113 errno = EINVAL;
1114 return -1;
1115 }
1117 errno = 0;
1118 if (type == SDB_TYPE_BOOLEAN) {
1119 if (! strcasecmp(str, "true"))
1120 tmp.data.boolean = true;
1121 else if (! strcasecmp(str, "false"))
1122 tmp.data.boolean = false;
1123 else
1124 return -1;
1125 }
1126 else if (type == SDB_TYPE_INTEGER) {
1127 tmp.data.integer = strtoll(str, &endptr, 0);
1128 }
1129 else if (type == SDB_TYPE_DECIMAL) {
1130 tmp.data.decimal = strtod(str, &endptr);
1131 }
1132 else if (type == SDB_TYPE_STRING) {
1133 tmp.data.string = strdup(str);
1134 if (! tmp.data.string)
1135 return -1;
1136 }
1137 else if (type == SDB_TYPE_DATETIME) {
1138 double datetime = strtod(str, &endptr);
1139 tmp.data.datetime = DOUBLE_TO_SDB_TIME(datetime);
1140 }
1141 else if (type == SDB_TYPE_BINARY) {
1142 /* we don't support any binary information containing 0-bytes here */
1143 tmp.data.binary.datum = (unsigned char *)strdup(str);
1144 if (! tmp.data.binary.datum)
1145 return -1;
1146 tmp.data.binary.length = strlen(str);
1147 }
1148 else if (type == SDB_TYPE_REGEX) {
1149 tmp.data.re.raw = strdup(str);
1150 if (! tmp.data.re.raw)
1151 return -1;
1152 if (regcomp(&tmp.data.re.regex, tmp.data.re.raw,
1153 REG_EXTENDED | REG_ICASE | REG_NOSUB)) {
1154 sdb_log(SDB_LOG_ERR, "core: Failed to compile regular "
1155 "expression '%s'", tmp.data.re.raw);
1156 free(tmp.data.re.raw);
1157 return -1;
1158 }
1159 if (! data) {
1160 tmp.type = SDB_TYPE_REGEX;
1161 sdb_data_free_datum(&tmp);
1162 }
1163 }
1164 else if (type & SDB_TYPE_ARRAY) {
1165 /* TODO */
1166 errno = ENOTSUP;
1167 return -1;
1168 }
1169 else {
1170 errno = EINVAL;
1171 return -1;
1172 }
1174 if ((type == SDB_TYPE_INTEGER) || (type == SDB_TYPE_DECIMAL)
1175 || (type == SDB_TYPE_DATETIME)) {
1176 if (errno || (str == endptr)) {
1177 char errbuf[1024];
1178 sdb_log(SDB_LOG_ERR, "core: Failed to parse string "
1179 "'%s' as numeric value (type %i): %s", str, type,
1180 sdb_strerror(errno, errbuf, sizeof(errbuf)));
1181 return -1;
1182 }
1183 else if (endptr && (*endptr != '\0'))
1184 sdb_log(SDB_LOG_WARNING, "core: Ignoring garbage after "
1185 "number while parsing numeric value (type %i): %s.",
1186 type, endptr);
1187 }
1189 if (data) {
1190 *data = tmp;
1191 data->type = type;
1192 }
1193 return 0;
1194 } /* sdb_data_parse */
1196 size_t
1197 sdb_data_sizeof(int type)
1198 {
1199 sdb_data_t v;
1200 if (type == SDB_TYPE_BOOLEAN)
1201 return sizeof(v.data.boolean);
1202 else if (type == SDB_TYPE_INTEGER)
1203 return sizeof(v.data.integer);
1204 else if (type == SDB_TYPE_DECIMAL)
1205 return sizeof(v.data.decimal);
1206 else if (type == SDB_TYPE_STRING)
1207 return sizeof(v.data.string);
1208 else if (type == SDB_TYPE_DATETIME)
1209 return sizeof(v.data.datetime);
1210 else if (type == SDB_TYPE_BINARY)
1211 return sizeof(v.data.binary);
1212 else if (type == SDB_TYPE_REGEX)
1213 return sizeof(v.data.re);
1214 return 0;
1215 } /* sdb_data_sizeof */
1217 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */