1 /*
2 * SysDB - src/include/core/data.h
3 * Copyright (C) 2012-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 #ifndef SDB_CORE_DATA_H
29 #define SDB_CORE_DATA_H 1
31 #include "core/time.h"
33 #include <inttypes.h>
34 #include <stdbool.h>
35 #include <stddef.h>
37 #include <sys/types.h>
38 #include <regex.h>
40 #ifdef __cplusplus
41 extern "C" {
42 #endif
44 enum {
45 SDB_TYPE_NULL = 0,
46 SDB_TYPE_INTEGER,
47 SDB_TYPE_DECIMAL,
48 SDB_TYPE_STRING,
49 SDB_TYPE_DATETIME,
50 SDB_TYPE_BINARY,
51 SDB_TYPE_REGEX, /* extended, case-insensitive POSIX regex */
53 /* flags: */
54 SDB_TYPE_ARRAY = 1 << 8,
55 };
57 #define SDB_TYPE_TO_STRING(t) \
58 (((t) == SDB_TYPE_NULL) ? "NULL" \
59 : ((t) == SDB_TYPE_INTEGER) ? "INTEGER" \
60 : ((t) == SDB_TYPE_DECIMAL) ? "DECIMAL" \
61 : ((t) == SDB_TYPE_STRING) ? "STRING" \
62 : ((t) == SDB_TYPE_DATETIME) ? "DATETIME" \
63 : ((t) == SDB_TYPE_BINARY) ? "BINARY" \
64 : ((t) == SDB_TYPE_REGEX) ? "REGEX" \
65 : ((t) == (SDB_TYPE_ARRAY | SDB_TYPE_INTEGER)) ? "[]INTEGER" \
66 : ((t) == (SDB_TYPE_ARRAY | SDB_TYPE_DECIMAL)) ? "[]DECIMAL" \
67 : ((t) == (SDB_TYPE_ARRAY | SDB_TYPE_STRING)) ? "[]STRING" \
68 : ((t) == (SDB_TYPE_ARRAY | SDB_TYPE_DATETIME)) ? "[]DATETIME" \
69 : ((t) == (SDB_TYPE_ARRAY | SDB_TYPE_BINARY)) ? "[]BINARY" \
70 : ((t) == (SDB_TYPE_ARRAY | SDB_TYPE_REGEX)) ? "[]REGEX" \
71 : "UNKNOWN")
73 union sdb_datum;
74 typedef union sdb_datum sdb_datum_t;
76 union sdb_datum {
77 int64_t integer; /* SDB_TYPE_INTEGER */
78 double decimal; /* SDB_TYPE_DECIMAL */
79 char *string; /* SDB_TYPE_STRING */
80 sdb_time_t datetime; /* SDB_TYPE_DATETIME */
81 struct {
82 size_t length;
83 unsigned char *datum;
84 } binary; /* SDB_TYPE_BINARY */
85 struct {
86 char *raw;
87 regex_t regex;
88 } re; /* SDB_TYPE_REGEX */
90 struct {
91 size_t length;
92 void *values;
93 } array;
94 };
96 /*
97 * sdb_data_t:
98 * An arbitrary value of a specified type.
99 */
100 typedef struct {
101 int type; /* type of the datum */
102 sdb_datum_t data;
103 } sdb_data_t;
104 #define SDB_DATA_INIT { SDB_TYPE_NULL, { .integer = 0 } }
106 extern const sdb_data_t SDB_DATA_NULL;
108 /*
109 * sdb_data_copy:
110 * Copy the datum stored in 'src' to the memory location pointed to by 'dst'.
111 * Any dynamic data (strings, binary data) is copied to newly allocated
112 * memory. Use, for example, sdb_data_free_datum() to free any dynamic memory
113 * stored in a datum. On error, 'dst' is unchanged. Else, any dynamic memory
114 * in 'dst' will be freed.
115 *
116 * Returns:
117 * - 0 on success
118 * - a negative value else
119 */
120 int
121 sdb_data_copy(sdb_data_t *dst, const sdb_data_t *src);
123 /*
124 * sdb_data_free_datum:
125 * Free any dynamic memory referenced by the specified datum. Does not free
126 * the memory allocated by the sdb_data_t object itself. This function must
127 * not be used if any static or stack memory is referenced from the data
128 * object.
129 */
130 void
131 sdb_data_free_datum(sdb_data_t *datum);
133 /*
134 * sdb_data_cmp:
135 * Compare two data points. A NULL datum is considered less than any non-NULL
136 * datum. On data-type mismatch, the function always returns a non-zero value.
137 *
138 * Returns:
139 * - a value less than zero if d1 compares less than d2
140 * - zero if d1 compares equal to d2
141 * - a value greater than zero if d1 compares greater than d2
142 */
143 int
144 sdb_data_cmp(const sdb_data_t *d1, const sdb_data_t *d2);
146 /*
147 * sdb_data_strcmp:
148 * Compare the string values of two data points. A NULL datum is considered
149 * less than any non-NULL. This function works for arbitrary combination of
150 * data-types.
151 *
152 * Returns:
153 * - a value less than zero if d1 compares less than d2
154 * - zero if d1 compares equal to d2
155 * - a value greater than zero if d1 compares greater than d2
156 */
157 int
158 sdb_data_strcmp(const sdb_data_t *d1, const sdb_data_t *d2);
160 /*
161 * sdb_data_isnull:
162 * Determine whether a datum is NULL. A datum is considered to be NULL if
163 * either datum is NULL or if the type is SDB_TYPE_NULL or if the string or
164 * binary datum is NULL.
165 */
166 bool
167 sdb_data_isnull(const sdb_data_t *datum);
169 /*
170 * sdb_data_inarray:
171 * Determine whether a datum is included in an array based on the usual
172 * comparison function of the value's type. The element type of the array has
173 * to match the type of the value. The value may be another array. In that
174 * case, the element types have to match and the function returns true if all
175 * elements of the first array are included in the second where order does not
176 * matter.
177 */
178 bool
179 sdb_data_inarray(const sdb_data_t *value, const sdb_data_t *array);
181 /*
182 * sdb_data_array_get:
183 * Get the i-th value stored in the specified array and store an alias in
184 * 'value'. Storing an alias means that the value points to the actual array
185 * element. Do *not* free the value after using it (i.e., don't use
186 * sdb_data_free_datum).
187 *
188 * Returns:
189 * - 0 on success
190 * - a negative value else
191 */
192 int
193 sdb_data_array_get(const sdb_data_t *array, size_t i, sdb_data_t *value);
195 /*
196 * Operators supported by sdb_data_eval_expr.
197 */
198 enum {
199 SDB_DATA_ADD = 1, /* addition */
200 SDB_DATA_SUB, /* substraction */
201 SDB_DATA_MUL, /* multiplication */
202 SDB_DATA_DIV, /* division */
203 SDB_DATA_MOD, /* modulo */
204 SDB_DATA_CONCAT, /* string / binary data concatenation */
205 };
207 #define SDB_DATA_OP_TO_STRING(op) \
208 (((op) == SDB_DATA_ADD) ? "+" \
209 : ((op) == SDB_DATA_SUB) ? "-" \
210 : ((op) == SDB_DATA_MUL) ? "*" \
211 : ((op) == SDB_DATA_DIV) ? "/" \
212 : ((op) == SDB_DATA_MOD) ? "%" \
213 : ((op) == SDB_DATA_CONCAT) ? "||" : "UNKNOWN")
215 /*
216 * sdb_data_parse_op:
217 * Parse the string representation of an operator supported by
218 * sdb_data_expr_eval.
219 *
220 * Returns:
221 * - the ID of the operator
222 * - a negative value in case the operator does not exist
223 */
224 int
225 sdb_data_parse_op(const char *op);
227 /*
228 * sdb_data_expr_eval:
229 * Evaluate a simple arithmetic expression on two data points. String and
230 * binary data only support concatenation and all other data types only
231 * support the other operators. The result may be allocated dynamically and
232 * has to be freed by the caller (using sdb_data_free_datum).
233 *
234 * If any of the data points is a NULL value, the result is also NULL.
235 *
236 * The data-types of d1 and d2 have to be the same, except for the following
237 * cases:
238 * - <integer> or <decimal> <mul> <datetime>
239 * - <datetime> <mul> or <div> or <mod> <integer> or <decimal>
240 *
241 * Returns:
242 * - 0 on success
243 * - a negative value else
244 */
245 int
246 sdb_data_expr_eval(int op, const sdb_data_t *d1, const sdb_data_t *d2,
247 sdb_data_t *res);
249 /*
250 * sdb_data_expr_type:
251 * Determine the type of the expression when applying the specified operator
252 * to the specified types. Note that if an actual value is a typed NULL value
253 * (e.g. a NULL string value), the return value of this function does not
254 * match the return type of sdb_data_expr_eval.
255 *
256 * See the documentation of sdb_data_expr_eval() for a description of which
257 * operations are supported.
258 *
259 * Returns:
260 * - the type id on success
261 * - a negative value else
262 */
263 int
264 sdb_data_expr_type(int op, int type1, int type2);
266 /*
267 * sdb_data_strlen:
268 * Returns a (worst-case) estimate for the number of bytes required to format
269 * the datum as a string. Does not take the terminating null byte into
270 * account.
271 */
272 size_t
273 sdb_data_strlen(const sdb_data_t *datum);
275 enum {
276 SDB_UNQUOTED = 0,
277 SDB_SINGLE_QUOTED,
278 SDB_DOUBLE_QUOTED,
279 };
281 /*
282 * sdb_data_format:
283 * Output the specified datum to the specified string using a default format.
284 * The value of 'quoted' determines whether and how non-integer and
285 * non-decimal values are quoted. If the buffer size is less than the return
286 * value of sdb_data_strlen, the datum may be truncated. The buffer will
287 * always be nul-terminated after calling this function.
288 *
289 * Returns:
290 * - the number of characters written to the buffer (excluding the terminated
291 * null byte) or the number of characters which would have been written in
292 * case the output was truncated
293 */
294 size_t
295 sdb_data_format(const sdb_data_t *datum, char *buf, size_t buflen, int quoted);
297 /*
298 * sdb_data_parse:
299 * Parse the specified string into a datum using the specified type. The
300 * string value is expected to be a raw value of the specified type. Integer
301 * and decimal numbers may be signed or unsigned octal (base 8, if the first
302 * character of the string is "0"), sedecimal (base 16, if the string includes
303 * the "0x" prefix), or decimal. Decimal numbers may also be "infinity" or
304 * "NaN" or may use a decimal exponent. Date-time values are expected to be
305 * specified as (floating point) number of seconds since the epoch. New memory
306 * will be allocated as necessary and will have to be free'd using
307 * sdb_data_free_datum().
308 *
309 * Returns:
310 * - 0 on success
311 * - a negative value else
312 */
313 int
314 sdb_data_parse(const char *str, int type, sdb_data_t *data);
316 /*
317 * sdb_data_sizeof:
318 * Return the size of the data-type identified by the specified type.
319 *
320 * Returns:
321 * - the size of the data-type on success
322 * - 0 else
323 */
324 size_t
325 sdb_data_sizeof(int type);
327 #ifdef __cplusplus
328 } /* extern "C" */
329 #endif
331 #endif /* ! SDB_CORE_DATA_H */
333 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */