1 /**
2 *
3 * Hoel database abstraction library
4 *
5 * hoel-simple-json.c: hoel simple Json query functions
6 *
7 * Copyright 2015-2016 Nicolas Mora <mail@babelouest.org>
8 *
9 * This program is o_free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public License
11 * as published by the Free Software Foundation;
12 * version 2.1 of the License.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU GENERAL PUBLIC LICENSE for more details.
18 *
19 * You should have received a copy of the GNU General Public
20 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
21 *
22 */
23
24 #include <string.h>
25 #include <ctype.h>
26
27 #include "hoel.h"
28 #include "h-private.h"
29
h_get_insert_values_from_json_object(const struct _h_connection * conn,json_t * data)30 static char * h_get_insert_values_from_json_object(const struct _h_connection * conn, json_t * data) {
31 char * new_data = NULL, * escape, * insert_data = NULL, * tmp;
32 const char * key = NULL;
33 json_t * value = NULL, * raw;
34 int i = 0;
35
36 json_object_foreach((json_t *)data, key, value) {
37 switch (json_typeof(value)) {
38 case JSON_STRING:
39 escape = h_escape_string_with_quotes(conn, json_string_value(value));
40 if (escape == NULL) {
41 y_log_message(Y_LOG_LEVEL_ERROR, "Hoel/h_get_insert_values_from_json_object - Error escape");
42 o_free(new_data);
43 new_data = NULL;
44 } else {
45 new_data = msprintf("%s", escape);
46 o_free(escape);
47 }
48 break;
49 case JSON_INTEGER:
50 new_data = msprintf("%"JSON_INTEGER_FORMAT, json_integer_value(value));
51 break;
52 case JSON_REAL:
53 new_data = msprintf("%f", json_real_value(value));
54 break;
55 case JSON_TRUE:
56 new_data = o_strdup("1");
57 break;
58 case JSON_FALSE:
59 new_data = o_strdup("0");
60 break;
61 case JSON_NULL:
62 new_data = o_strdup("NULL");
63 break;
64 case JSON_OBJECT:
65 raw = json_object_get(value, "raw");
66 if (raw != NULL && json_is_string(raw)) {
67 new_data = o_strdup(json_string_value(raw));
68 } else {
69 new_data = o_strdup("NULL");
70 }
71 break;
72 default:
73 tmp = json_dumps(value, JSON_ENCODE_ANY);
74 y_log_message(Y_LOG_LEVEL_ERROR, "Hoel/h_get_insert_values_from_json_object - Error decoding value %s, inserting NULL value", tmp);
75 o_free(tmp);
76 new_data = o_strdup("NULL");
77 break;
78 }
79 if (new_data == NULL) {
80 y_log_message(Y_LOG_LEVEL_ERROR, "Hoel/h_get_insert_values_from_json_object - Error allocating memory for new_data");
81 return NULL;
82 }
83 if (i == 0) {
84 insert_data = msprintf("(%s", new_data);
85 if (insert_data == NULL) {
86 y_log_message(Y_LOG_LEVEL_ERROR, "Hoel/h_get_insert_values_from_json_object - Error allocating insert_data");
87 }
88 i = 1;
89 o_free(new_data);
90 } else {
91 tmp = msprintf("%s,%s", insert_data, new_data);
92 if (tmp == NULL) {
93 y_log_message(Y_LOG_LEVEL_ERROR, "Hoel/h_get_insert_values_from_json_object - Error allocating tmp");
94 o_free(insert_data);
95 o_free(new_data);
96 return NULL;
97 }
98 o_free(insert_data);
99 o_free(new_data);
100 insert_data = tmp;
101 }
102 }
103 tmp = msprintf("%s)", insert_data);
104 o_free(insert_data);
105 if (tmp == NULL) {
106 y_log_message(Y_LOG_LEVEL_ERROR, "Hoel/h_get_insert_values_from_json_object - Error final allocation for tmp");
107 }
108 return tmp;
109 }
110
h_get_insert_columns_from_json_object(json_t * data)111 static char * h_get_insert_columns_from_json_object(json_t * data) {
112 char * insert_cols = NULL, * tmp;
113 const char * key = NULL;
114 json_t * value = NULL;
115 int i = 0;
116
117 json_object_foreach((json_t *)data, key, value) {
118 if (i == 0) {
119 insert_cols = msprintf("%s", key);
120 if (insert_cols == NULL) {
121 y_log_message(Y_LOG_LEVEL_ERROR, "Hoel/h_get_insert_columns_from_json_object - Error allocating insert_cols");
122 return NULL;
123 }
124 i = 1;
125 } else {
126 tmp = msprintf("%s,%s", insert_cols, key);
127 o_free(insert_cols);
128 if (tmp == NULL) {
129 y_log_message(Y_LOG_LEVEL_ERROR, "Hoel/h_get_insert_columns_from_json_object - Error allocating insert_cols");
130 return NULL;
131 }
132 insert_cols = tmp;
133 }
134 }
135
136 return insert_cols;
137 }
138
139 /**
140 * Builds an insert query from a json object and a table name
141 * Returned value must be o_free'd after use
142 */
h_get_insert_query_from_json_object(const struct _h_connection * conn,json_t * data,const char * table)143 static char * h_get_insert_query_from_json_object(const struct _h_connection * conn, json_t * data, const char * table) {
144 char * to_return = NULL, * insert_cols, * insert_data;
145
146 insert_cols = h_get_insert_columns_from_json_object(data);
147 insert_data = h_get_insert_values_from_json_object(conn, data);
148 if (insert_cols == NULL || insert_data == NULL) {
149 y_log_message(Y_LOG_LEVEL_ERROR, "Hoel/h_get_insert_query_from_json_object - Error h_get_insert_columns_from_json_object or h_get_insert_values_from_json_object");
150 } else {
151 to_return = msprintf("INSERT INTO %s (%s) VALUES %s", table, insert_cols, insert_data);
152 }
153 o_free(insert_cols);
154 o_free(insert_data);
155 if (to_return == NULL) {
156 y_log_message(Y_LOG_LEVEL_ERROR, "Hoel/h_get_insert_query_from_json_object - Error allocating memory for h_get_insert_query_from_json_object");
157 }
158 return to_return;
159 }
160
161 /**
162 * Builds an insert query from a json object and a table name
163 * Returned value must be o_free'd after use
164 */
h_get_insert_query_from_json_array(const struct _h_connection * conn,json_t * j_array,const char * table)165 static char * h_get_insert_query_from_json_array(const struct _h_connection * conn, json_t * j_array, const char * table) {
166 json_t * j_row = NULL;
167 size_t index = 0;
168 char * to_return = NULL, * insert_cols, * insert_data, * tmp;
169
170 json_array_foreach(j_array, index, j_row) {
171 insert_data = h_get_insert_values_from_json_object(conn, j_row);
172 if (!index) {
173 insert_cols = h_get_insert_columns_from_json_object(j_row);
174 to_return = msprintf("INSERT INTO %s (%s) VALUES %s", table, insert_cols, insert_data);
175 o_free(insert_cols);
176 if (to_return == NULL) {
177 y_log_message(Y_LOG_LEVEL_ERROR, "Hoel/h_get_insert_query_from_json_array - Error allocating to_return");
178 o_free(insert_data);
179 return NULL;
180 }
181 } else {
182 tmp = msprintf("%s,%s", to_return, insert_data);
183 if (tmp == NULL) {
184 y_log_message(Y_LOG_LEVEL_ERROR, "Hoel/h_get_insert_query_from_json_array - Error allocating tmp");
185 o_free(insert_data);
186 return NULL;
187 }
188 o_free(to_return);
189 to_return = tmp;
190 }
191 o_free(insert_data);
192 }
193 return to_return;
194 }
195
196 /**
197 * Generates a where clause based on a json object
198 * the where object is a simple object like
199 * {
200 * col1: "value1",
201 * col2: "value2"
202 * }
203 * the output is a WHERE query will use only '=' and 'AND' keywords
204 * col1='value1' AND col2='value2'
205 * return a char * containing the WHERE clause, NULL on error
206 * the returned value must be o_free'd after use
207 */
h_get_where_clause_from_json_object(const struct _h_connection * conn,const json_t * where)208 static char * h_get_where_clause_from_json_object(const struct _h_connection * conn, const json_t * where) {
209 const char * key = NULL;
210 json_t * value = NULL, * ope, * val, * j_element;
211 char * where_clause = NULL, * dump = NULL, * escape = NULL, * tmp, * clause = NULL, * dump2 = NULL;
212 int i = 0;
213 size_t index = 0;
214
215 if (conn == NULL) {
216 y_log_message(Y_LOG_LEVEL_DEBUG, "Hoel/h_get_where_clause_from_json_object - Error conn is NULL");
217 return NULL;
218 } else if (where == NULL || (json_is_object(where) && json_object_size(where) == 0)) {
219 return o_strdup("1=1");
220 } else {
221 json_object_foreach((json_t *)where, key, value) {
222 if (!json_is_string(value) && !json_is_real(value) && !json_is_integer(value) && !json_is_object(value) && !json_is_null(value)) {
223 dump = json_dumps(value, JSON_ENCODE_ANY);
224 y_log_message(Y_LOG_LEVEL_DEBUG, "Hoel/h_get_where_clause_from_json_object - Error where value is invalid: %s", dump);
225 o_free(dump);
226 return NULL;
227 } else {
228 if (json_is_object(value)) {
229 ope = json_object_get(value, "operator");
230 val = json_object_get(value, "value");
231 if (ope == NULL ||
232 !json_is_string(ope) ||
233 (val == NULL && 0 != o_strcasecmp("NOT NULL", json_string_value(ope))) ||
234 (!json_is_string(val) && !json_is_real(val) && !json_is_integer(val) && 0 != o_strcasecmp("NOT NULL", json_string_value(ope)) && 0 != o_strcasecmp("IN", json_string_value(ope)))) {
235 dump = json_dumps(val, JSON_ENCODE_ANY);
236 dump2 = json_dumps(ope, JSON_ENCODE_ANY);
237 y_log_message(Y_LOG_LEVEL_DEBUG, "Hoel/h_get_where_clause_from_json_object - Error where object value is invalid: %s %s", dump, dump2);
238 o_free(dump);
239 o_free(dump2);
240 o_free(where_clause);
241 return NULL;
242 } else {
243 if (0 == o_strcasecmp("NOT NULL", json_string_value(ope))) {
244 clause = msprintf("%s IS NOT NULL", key);
245 } else if (0 == o_strcasecmp("raw", json_string_value(ope)) && json_is_string(val)) {
246 clause = msprintf("%s %s", key, json_string_value(val));
247 } else if (0 == o_strcasecmp("IN", json_string_value(ope))) {
248 if (json_is_array(val) && json_array_size(val) > 0) {
249 clause = NULL, tmp = NULL;
250 json_array_foreach(val, index, j_element) {
251 if (!json_is_string(j_element) && !json_is_real(j_element) && !json_is_integer(j_element)) {
252 o_free(clause);
253 o_free(where_clause);
254 y_log_message(Y_LOG_LEVEL_ERROR, "Hoel - Error element value in IN statement array must be real, integer or string");
255 return NULL;
256 } else {
257 if (json_is_string(j_element)) {
258 escape = h_escape_string_with_quotes(conn, json_string_value(j_element));
259 if (escape == NULL) {
260 y_log_message(Y_LOG_LEVEL_ERROR, "Hoel - Error escape");
261 o_free(clause);
262 o_free(where_clause);
263 return NULL;
264 }
265 dump = msprintf("%s", escape);
266 o_free(escape);
267 } else if (json_is_real(j_element)) {
268 dump = msprintf("%f", json_real_value(j_element));
269 } else {
270 dump = msprintf("%" JSON_INTEGER_FORMAT, json_integer_value(j_element));
271 }
272 if (clause == NULL) {
273 clause = msprintf("%s IN (%s", key, dump);
274 } else {
275 tmp = msprintf("%s,%s", clause, dump);
276 o_free(clause);
277 clause = tmp;
278 }
279 o_free(dump);
280 }
281 }
282 tmp = msprintf("%s)", clause);
283 o_free(clause);
284 clause = tmp;
285 } else {
286 o_free(where_clause);
287 y_log_message(Y_LOG_LEVEL_ERROR, "Hoel - Error value in IN statement must be a non empty JSON array");
288 return NULL;
289 }
290 } else {
291 if (json_is_real(val)) {
292 clause = msprintf("%s %s %f", key, json_string_value(ope), json_real_value(val));
293 } else if (json_is_integer(val)) {
294 clause = msprintf("%s %s %" JSON_INTEGER_FORMAT, key, json_string_value(ope), json_integer_value(val));
295 } else {
296 escape = h_escape_string_with_quotes(conn, json_string_value(val));
297 if (escape == NULL) {
298 y_log_message(Y_LOG_LEVEL_ERROR, "Hoel - Error escape");
299 o_free(where_clause);
300 return NULL;
301 }
302 clause = msprintf("%s %s %s", key, json_string_value(ope), escape);
303 o_free(escape);
304 }
305 }
306 if (clause == NULL) {
307 y_log_message(Y_LOG_LEVEL_ERROR, "Hoel - Error allocating memory for clause");
308 o_free(where_clause);
309 return NULL;
310 }
311 }
312 } else {
313 if (json_is_null(value)) {
314 clause = msprintf("%s IS NULL", key);
315 } else if (json_is_string(value)) {
316 escape = h_escape_string_with_quotes(conn, json_string_value(value));
317 if (escape == NULL) {
318 y_log_message(Y_LOG_LEVEL_ERROR, "Hoel - Error escape");
319 o_free(where_clause);
320 return NULL;
321 }
322 clause = msprintf("%s=%s", key, escape);
323 o_free(escape);
324 } else if (json_is_integer(value)) {
325 clause = msprintf("%s='%"JSON_INTEGER_FORMAT"'", key, json_integer_value(value));
326 } else if (json_is_real(value)) {
327 clause = msprintf("%s='%f'", key, json_real_value(value));
328 } else if (json_is_true(value)) {
329 clause = msprintf("%s=1");
330 } else if (json_is_false(value)) {
331 clause = msprintf("%s=0");
332 }
333 if (clause == NULL) {
334 y_log_message(Y_LOG_LEVEL_ERROR, "Hoel - Error allocating memory for clause");
335 o_free(where_clause);
336 return NULL;
337 }
338 }
339 if (i == 0) {
340 where_clause = o_strdup(clause);
341 if (where_clause == NULL) {
342 y_log_message(Y_LOG_LEVEL_DEBUG, "Hoel/h_get_where_clause_from_json_object - Error where_clause");
343 o_free(clause);
344 o_free(where_clause);
345 return NULL;
346 }
347 o_free(clause);
348 i = 1;
349 } else {
350 tmp = msprintf("%s AND %s", where_clause, clause);
351 o_free(where_clause);
352 if (tmp == NULL) {
353 y_log_message(Y_LOG_LEVEL_DEBUG, "Hoel/h_get_where_clause_from_json_object - Error tmp where_clause");
354 o_free(clause);
355 o_free(where_clause);
356 return NULL;
357 }
358 o_free(clause);
359 where_clause = tmp;
360 }
361 }
362 }
363 return where_clause;
364 }
365 }
366
367 /**
368 * Generates a set clause based on a json object
369 * the where object is a simple object like
370 * {
371 * col1: "value1",
372 * col2: "value2"
373 * }
374 * the output is a WHERE query will use only '=' and 'AND' keywords
375 * col1='value1', col2='value2'
376 * return a char * containing the WHERE clause, NULL on error
377 * the returned value must be o_free'd after use
378 */
h_get_set_clause_from_json_object(const struct _h_connection * conn,const json_t * set)379 static char * h_get_set_clause_from_json_object(const struct _h_connection * conn, const json_t * set) {
380 const char * key = NULL;
381 json_t * value = NULL, * raw;
382 char * where_clause = NULL, * escape = NULL, * tmp;
383 int i = 0;
384
385 if (conn == NULL || set == NULL || !json_is_object(set)) {
386 y_log_message(Y_LOG_LEVEL_DEBUG, "Hoel/h_get_set_clause_from_json_object - Error null input parameters");
387 return NULL;
388 } else {
389 json_object_foreach((json_t *)set, key, value) {
390 if (!json_is_string(value) && !json_is_real(value) && !json_is_integer(value) && !json_is_null(value) && !json_is_object(value)) {
391 tmp = json_dumps(value, JSON_ENCODE_ANY);
392 y_log_message(Y_LOG_LEVEL_DEBUG, "Hoel/h_get_set_clause_from_json_object - Error value invalid: %s", tmp);
393 o_free(tmp);
394 o_free(where_clause);
395 return NULL;
396 } else {
397 if (json_is_string(value)) {
398 tmp = h_escape_string_with_quotes(conn, json_string_value(value));
399 escape = msprintf("%s", tmp);
400 o_free(tmp);
401 } else if (json_is_real(value)) {
402 escape = msprintf("%f", json_real_value(value));
403 } else if (json_is_integer(value)) {
404 escape = msprintf("%" JSON_INTEGER_FORMAT, json_integer_value(value));
405 } else if (json_is_object(value)) {
406 raw = json_object_get(value, "raw");
407 if (raw != NULL && json_is_string(raw)) {
408 escape = o_strdup(json_string_value(raw));
409 } else {
410 escape = o_strdup("NULL");
411 }
412 } else {
413 escape = o_strdup("");
414 }
415 if (escape == NULL) {
416 y_log_message(Y_LOG_LEVEL_ERROR, "Hoel - Error escape");
417 return NULL;
418 }
419 if (i == 0) {
420 if (!json_is_null(value)) {
421 where_clause = msprintf("%s=%s", key, escape);
422 } else {
423 where_clause = msprintf("%s=NULL", key);
424 }
425 if (where_clause == NULL) {
426 y_log_message(Y_LOG_LEVEL_DEBUG, "Hoel/h_get_set_clause_from_json_object - Error where_clause");
427 return NULL;
428 }
429 i = 1;
430 } else {
431 if (!json_is_null(value)) {
432 tmp = msprintf("%s, %s=%s", where_clause, key, escape);
433 } else {
434 tmp = msprintf("%s, %s=NULL", where_clause, key);
435 }
436 o_free(where_clause);
437 if (tmp == NULL) {
438 y_log_message(Y_LOG_LEVEL_DEBUG, "Hoel/h_get_set_clause_from_json_object - Error tmp where_clause");
439 return NULL;
440 }
441 where_clause = tmp;
442 }
443 o_free(escape);
444 }
445 }
446 return where_clause;
447 }
448 }
449
450 /**
451 * h_select
452 * Execute a select query
453 * Uses a json_t * parameter for the query parameters
454 * Store the result of the query in j_result if specified. j_result must be decref'd after use
455 * Duplicate the generated query in generated_query if specified, must be o_free'd after use
456 * return H_OK on success
457 */
h_select(const struct _h_connection * conn,const json_t * j_query,json_t ** j_result,char ** generated_query)458 int h_select(const struct _h_connection * conn, const json_t * j_query, json_t ** j_result, char ** generated_query) {
459 const char * table;
460 const json_t * cols, * where, * order_by;
461 json_int_t limit, offset;
462 char * query, * columns = NULL, * where_clause = NULL, * tmp, * str_where_limit, * str_order_by;
463 const char * col;
464 size_t index = 0;
465 json_t * value;
466 int res;
467
468 if (conn == NULL || j_result == NULL || j_query == NULL || !json_is_object(j_query) || json_object_get(j_query, "table") == NULL || !json_is_string(json_object_get(j_query, "table"))) {
469 y_log_message(Y_LOG_LEVEL_DEBUG, "Hoel/h_select Error invalid input parameters");
470 return H_ERROR_PARAMS;
471 }
472
473 table = json_string_value((const json_t *)json_object_get(j_query, "table"));
474 cols = json_object_get(j_query, "columns");
475 where = json_object_get(j_query, "where");
476 order_by = json_object_get(j_query, "order_by");
477 limit = json_is_integer(json_object_get(j_query, "limit"))?json_integer_value(json_object_get(j_query, "limit")):0;
478 offset = json_is_integer(json_object_get(j_query, "offset"))?json_integer_value(json_object_get(j_query, "offset")):0;
479
480 where_clause = h_get_where_clause_from_json_object(conn, (json_t *)where);
481 if (where_clause == NULL) {
482 y_log_message(Y_LOG_LEVEL_DEBUG, "Hoel/h_select Error where_clause construction");
483 return H_ERROR_PARAMS;
484 }
485
486 if (cols == NULL) {
487 columns = o_strdup("*");
488 } else if (json_is_array(cols)) {
489 json_array_foreach(cols, index, value) {
490 if (json_is_string(value)) {
491 col = json_string_value(value);
492 if (col == NULL) {
493 y_log_message(Y_LOG_LEVEL_DEBUG, "Hoel/h_select Error col");
494 o_free(where_clause);
495 o_free(columns);
496 return H_ERROR_MEMORY;
497 }
498 } else {
499 y_log_message(Y_LOG_LEVEL_DEBUG, "Hoel/h_select Error column not string");
500 o_free(where_clause);
501 return H_ERROR_PARAMS;
502 }
503 if (index == 0) {
504 columns = o_strdup(col);
505 if (columns == NULL) {
506 y_log_message(Y_LOG_LEVEL_DEBUG, "Hoel/h_select Error allocating columns");
507 o_free(where_clause);
508 return H_ERROR_MEMORY;
509 }
510 } else {
511 tmp = msprintf("%s, %s", columns, col);
512 if (tmp == NULL) {
513 y_log_message(Y_LOG_LEVEL_DEBUG, "Hoel/h_select Error allocating clause");
514 o_free(where_clause);
515 o_free(columns);
516 return H_ERROR_MEMORY;
517 }
518 o_free(columns);
519 columns = tmp;
520 }
521 }
522 } else {
523 y_log_message(Y_LOG_LEVEL_DEBUG, "Hoel/h_select Error cols not array");
524 o_free(where_clause);
525 return H_ERROR_PARAMS;
526 }
527
528 if (columns == NULL) {
529 y_log_message(Y_LOG_LEVEL_ERROR, "Hoel - Error allocating memory for columns");
530 o_free(where_clause);
531 return H_ERROR_MEMORY;
532 }
533
534 if (limit > 0) {
535 if (offset > 0) {
536 str_where_limit = msprintf("LIMIT %" JSON_INTEGER_FORMAT " OFFSET %" JSON_INTEGER_FORMAT, limit, offset);
537 } else {
538 str_where_limit = msprintf("LIMIT %" JSON_INTEGER_FORMAT, limit);
539 }
540 if (str_where_limit == NULL) {
541 y_log_message(Y_LOG_LEVEL_ERROR, "Hoel - Error allocating memory for str_where_limit");
542 o_free(columns);
543 o_free(where_clause);
544 return H_ERROR_MEMORY;
545 }
546 } else {
547 str_where_limit = o_strdup("");
548 }
549 if (order_by != NULL && json_is_string(order_by)) {
550 str_order_by = msprintf("ORDER BY %s", json_string_value(order_by));
551 } else {
552 str_order_by = o_strdup("");
553 }
554 if (str_order_by == NULL) {
555 y_log_message(Y_LOG_LEVEL_ERROR, "Hoel - Error allocating memory for str_order_by");
556 o_free(columns);
557 o_free(where_clause);
558 o_free(str_where_limit);
559 return H_ERROR_MEMORY;
560 }
561
562 if (str_order_by == NULL) {
563 y_log_message(Y_LOG_LEVEL_ERROR, "Hoel - Error allocating memory for str_order_by");
564 o_free(columns);
565 o_free(where_clause);
566 o_free(str_where_limit);
567 o_free(str_order_by);
568 return H_ERROR_MEMORY;
569 }
570
571 query = msprintf("SELECT %s FROM %s WHERE %s %s %s", columns, table, where_clause, str_order_by, str_where_limit);
572 if (query == NULL) {
573 y_log_message(Y_LOG_LEVEL_DEBUG, "Hoel/h_select Error allocating query");
574 o_free(columns);
575 o_free(where_clause);
576 o_free(str_where_limit);
577 o_free(str_order_by);
578 return H_ERROR_MEMORY;
579 } else {
580 if (generated_query != NULL) {
581 *generated_query = o_strdup(query);
582 }
583 res = h_query_select_json(conn, query, j_result);
584 o_free(columns);
585 o_free(where_clause);
586 o_free(str_where_limit);
587 o_free(str_order_by);
588 o_free(query);
589 return res;
590 }
591 }
592
593 /**
594 * h_insert
595 * Execute an insert query
596 * Uses a json_t * parameter for the query parameters
597 * Duplicate the generated query in generated_query if specified, must be o_free'd after use
598 * return H_OK on success
599 */
h_insert(const struct _h_connection * conn,const json_t * j_query,char ** generated_query)600 int h_insert(const struct _h_connection * conn, const json_t * j_query, char ** generated_query) {
601 const char * table;
602 char * query;
603 json_t * values;
604 int res;
605
606 if (conn != NULL && j_query != NULL && json_is_object(j_query) && json_is_string(json_object_get(j_query, "table")) && (json_is_object(json_object_get(j_query, "values")) || json_is_array(json_object_get(j_query, "values")))) {
607 /* Construct query */
608 table = json_string_value((const json_t *)json_object_get(j_query, "table"));
609 values = json_object_get(j_query, "values");
610 switch (json_typeof(values)) {
611 case JSON_OBJECT:
612 query = h_get_insert_query_from_json_object(conn, values, table);
613 if (query != NULL) {
614 if (generated_query != NULL) {
615 *generated_query = o_strdup(query);
616 }
617 res = h_query_insert(conn, query);
618 o_free(query);
619 if (res != H_OK) {
620 y_log_message(Y_LOG_LEVEL_DEBUG, "Hoel/h_insert - Error executing query (1)");
621 return H_ERROR_QUERY;
622 }
623 return res;
624 } else {
625 y_log_message(Y_LOG_LEVEL_DEBUG, "Hoel/h_insert - Error allocating query (1)");
626 return H_ERROR_MEMORY;
627 }
628 break;
629 case JSON_ARRAY:
630 if (json_array_size(values)) {
631 query = h_get_insert_query_from_json_array(conn, values, table);
632 if (query != NULL) {
633 if (generated_query != NULL) {
634 /* Export just the first query */
635 *generated_query = o_strdup(query);
636 }
637 res = h_query_insert(conn, query);
638 o_free(query);
639 if (res != H_OK) {
640 y_log_message(Y_LOG_LEVEL_DEBUG, "Hoel/h_insert - Error executing query (2)");
641 return H_ERROR_QUERY;
642 }
643 return res;
644 } else {
645 y_log_message(Y_LOG_LEVEL_DEBUG, "Hoel/h_insert - Error allocating query (2)");
646 return H_ERROR_MEMORY;
647 }
648 } else {
649 y_log_message(Y_LOG_LEVEL_DEBUG, "Hoel/h_insert - Error no values to insert");
650 return H_ERROR_QUERY;
651 }
652 break;
653 default:
654 y_log_message(Y_LOG_LEVEL_DEBUG, "Hoel/h_insert - Error unknown object type for values");
655 return H_ERROR_PARAMS;
656 break;
657 }
658 } else {
659 y_log_message(Y_LOG_LEVEL_DEBUG, "Hoel/h_insert - Error null input parameters");
660 return H_ERROR_PARAMS;
661 }
662 }
663
664 /**
665 * h_last_insert_id
666 * return the id of the last inserted value
667 * return a pointer to json_t * on success, NULL otherwise.
668 * The returned value is of type JSON_INTEGER
669 */
h_last_insert_id(const struct _h_connection * conn)670 json_t * h_last_insert_id(const struct _h_connection * conn) {
671 json_t * j_data = NULL;
672 if (conn != NULL && conn->connection != NULL) {
673 if (0) {
674 /* Not happening */
675 #ifdef _HOEL_SQLITE
676 } else if (conn->type == HOEL_DB_TYPE_SQLITE) {
677 int last_id = h_last_insert_id_sqlite(conn);
678 if (last_id > 0) {
679 j_data = json_integer(last_id);
680 }
681 #endif
682 #ifdef _HOEL_MARIADB
683 } else if (conn->type == HOEL_DB_TYPE_MARIADB) {
684 int last_id = h_last_insert_id_mariadb(conn);
685 if (last_id > 0) {
686 j_data = json_integer(last_id);
687 }
688 #endif
689 #ifdef _HOEL_PGSQL
690 } else if (conn->type == HOEL_DB_TYPE_PGSQL) {
691 int last_id = h_last_insert_id_pgsql(conn);
692 if (last_id > 0) {
693 j_data = json_integer(last_id);
694 }
695 #endif
696 }
697 }
698 return j_data;
699 }
700
701 /**
702 * h_update
703 * Execute an update query
704 * Uses a json_t * parameter for the query parameters
705 * Duplicate the generated query in generated_query if specified, must be o_free'd after use
706 * return H_OK on success
707 */
h_update(const struct _h_connection * conn,const json_t * j_query,char ** generated_query)708 int h_update(const struct _h_connection * conn, const json_t * j_query, char ** generated_query) {
709 char * set_clause, * where_clause, * query;
710 const char * table;
711 int res;
712 json_t * set, * where;
713
714 if (j_query == NULL || !json_is_object(j_query) || !json_is_string(json_object_get(j_query, "table")) || !json_is_object(json_object_get(j_query, "set"))) {
715 y_log_message(Y_LOG_LEVEL_DEBUG, "Hoel/h_update - Error invalid input parameters");
716 return H_ERROR_PARAMS;
717 }
718
719 table = json_string_value((const json_t *)json_object_get(j_query, "table"));
720
721 set = json_object_get(j_query, "set");
722 set_clause = h_get_set_clause_from_json_object(conn, set);
723
724 if (set_clause == NULL) {
725 y_log_message(Y_LOG_LEVEL_DEBUG, "Hoel/h_update - Error generating set clause");
726 return H_ERROR_PARAMS;
727 }
728
729 if (json_is_object(json_object_get(j_query, "where")) && json_object_size(json_object_get(j_query, "where")) > 0) {
730 where = json_object_get(j_query, "where");
731 where_clause = h_get_where_clause_from_json_object(conn, where);
732 query = msprintf("UPDATE %s SET %s WHERE %s", table, set_clause, where_clause);
733 o_free(where_clause);
734 } else {
735 query = msprintf("UPDATE %s SET %s", table, set_clause);
736 }
737
738 o_free(set_clause);
739 if (query == NULL) {
740 y_log_message(Y_LOG_LEVEL_DEBUG, "Hoel/h_update - Error allocating query");
741 return H_ERROR_MEMORY;
742 }
743 if (generated_query != NULL) {
744 *generated_query = o_strdup(query);
745 }
746 res = h_query_update(conn, query);
747 o_free(query);
748 return res;
749 }
750
751 /**
752 * h_delete
753 * Execute a delete query
754 * Uses a json_t * parameter for the query parameters
755 * Duplicate the generated query in generated_query if specified, must be o_free'd after use
756 * return H_OK on success
757 */
h_delete(const struct _h_connection * conn,const json_t * j_query,char ** generated_query)758 int h_delete(const struct _h_connection * conn, const json_t * j_query, char ** generated_query) {
759 char * where_clause, * query;
760 const char * table;
761 int res;
762 json_t * where;
763
764 if (j_query == NULL || !json_is_object(j_query) || !json_is_string(json_object_get(j_query, "table"))) {
765 y_log_message(Y_LOG_LEVEL_DEBUG, "Hoel/h_delete - Error invalid input parameters");
766 return H_ERROR_PARAMS;
767 }
768
769 table = json_string_value((json_t *)json_object_get(j_query, "table"));
770
771 if (json_is_object(json_object_get(j_query, "where")) && json_object_size(json_object_get(j_query, "where")) > 0) {
772 where = json_object_get(j_query, "where");
773 where_clause = h_get_where_clause_from_json_object(conn, where);
774
775 if (where_clause == NULL) {
776 y_log_message(Y_LOG_LEVEL_DEBUG, "Hoel/h_delete - Error invalid input parameters");
777 return H_ERROR_PARAMS;
778 }
779 query = msprintf("DELETE FROM %s WHERE %s", table, where_clause);
780 o_free(where_clause);
781 } else {
782 query = msprintf("DELETE FROM %s", table);
783 }
784
785 if (query == NULL) {
786 y_log_message(Y_LOG_LEVEL_DEBUG, "Hoel/h_delete - Error allocating query");
787 return H_ERROR_MEMORY;
788 }
789 if (generated_query != NULL) {
790 *generated_query = o_strdup(query);
791 }
792 res = h_query_delete(conn, query);
793 o_free(query);
794 return res;
795 }
796