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