[Debian-iot-packaging] [hoel] 01/02: Import Upstream version 1.2.1

Thorsten Alteholz alteholz at moszumanska.debian.org
Thu Oct 5 20:21:17 UTC 2017


This is an automated email from the git hooks/post-receive script.

alteholz pushed a commit to branch master
in repository hoel.

commit 1940cc85d9dd96e0c016fc728a1c834b78a002a0
Author: Thorsten Alteholz <debian at alteholz.de>
Date:   Thu Oct 5 22:21:07 2017 +0200

    Import Upstream version 1.2.1
---
 .gitignore               |   2 +
 README.md                |  54 +++++++-------
 examples/Makefile        |  13 +++-
 examples/example_pgsql.c |  34 +++++++--
 src/Makefile             |  10 +--
 src/hoel-pgsql.c         | 184 ++++++++++++++++++++++++++++++++++++++++++++---
 src/hoel-simple-json.c   |  48 ++++---------
 src/hoel.c               |  10 +--
 src/hoel.h               |   9 ++-
 test/core.c              |  17 +++++
 10 files changed, 294 insertions(+), 87 deletions(-)

diff --git a/.gitignore b/.gitignore
index b1d711a..c12118a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,3 +5,5 @@ example_sqlite3
 example_mariadb
 example_pgsql
 example_mariadb_json
+core
+valgrind.txt
diff --git a/README.md b/README.md
index 7fe53d1..91b5ffd 100644
--- a/README.md
+++ b/README.md
@@ -2,21 +2,22 @@
 
 Database abstraction library written in C.
 
-Simple and easy to use database access library. Works with SQLite 3, MariaDB/Mysql and (barely) PostgreSQL databases. Uses a json-based language with `jansson` to execute simples queries based on one table.
+Simple and easy to use database access library. Works with SQLite 3, MariaDB/Mysql and PostgreSQL databases. Uses a JSON-based language with `jansson` to execute simples queries based on one table.
 
 # Installation
 
-Clone, compile and install [yder](https://github.com/babelouest/yder) and [orcania](https://github.com/babelouest/orcania) librares.
+## Linux distribution package
 
-### Yder (simple logs library)
+Hoel is now available in Debian Buster (testing), Debian Sid, and soon in Ubuntu. To install the development package on your system, run the command as root:
 
 ```shell
-$ git clone https://github.com/babelouest/yder.git
-$ cd yder
-$ make
-$ sudo make install
+# apt install libhoel-dev
 ```
 
+## Install from the source
+
+Clone, compile and install [Orcania](https://github.com/babelouest/orcania) and [Yder](https://github.com/babelouest/yder) librares.
+
 ### Orcania (Miscellaneous functions)
 
 ```shell
@@ -25,7 +26,16 @@ $ cd orcania
 $ make && sudo make install
 ```
 
-Install [Jansson](http://www.digip.org/jansson/) library for json manipulation. On a debian-based platform, run the following command:
+### Yder (simple logs library)
+
+```shell
+$ git clone https://github.com/babelouest/yder.git
+$ cd yder
+$ make
+$ sudo make install
+```
+
+Install [Jansson](http://www.digip.org/jansson/) library for JSON manipulation. On a debian-based platform, run the following command:
 
 ```shell
 $ sudo apt-get install libjansson-dev
@@ -41,7 +51,7 @@ Compile hoel for the backend you need, go to hoel source folder, depending on yo
 
 ## SQLite 3
 
-Install libsqlite3-dev and uncomment the following lines in the `src/Makefile`
+Install `libsqlite3-dev` and uncomment the following lines in the `src/Makefile`
 
 ```Makefile
 # HAS_SQLITE=-D_HOEL_SQLITE
@@ -50,7 +60,7 @@ Install libsqlite3-dev and uncomment the following lines in the `src/Makefile`
 
 ## MariaDB/Mysql
 
-Install libmysqlclient-dev and uncomment the following lines in the `src/Makefile`
+Install `libmysqlclient-dev` and uncomment the following lines in the `src/Makefile`
 
 ```Makefile
 # FLAGS_MARIADB=-D_HOEL_MARIADB -I/usr/include/mysql/
@@ -59,17 +69,13 @@ Install libmysqlclient-dev and uncomment the following lines in the `src/Makefil
 
 ## Postgre SQL
 
-Install libpq-dev and uncomment the following lines in the `src/Makefile`
+Install `libpq-dev` and uncomment the following lines in the `src/Makefile`
 
 ```Makefile
 # HAS_PGSQL=-D_HOEL_PGSQL -I/usr/include/postgresql/
 # LIBS_PGSQL=-lpq
 ```
 
-### Postgre SQL limitations
-
-For some reasons, the Postgre SQL backend has some limitations. The `*_last_insert_id` functions don't work, and a select statement returns only string values. The reason is I couldn't find on the documentation how to implement those, if it's possible...
-
 ### Use different backends
 
 You can use different backends at the same time, simply install the required libraries and uncomment all the required backend requirements in the `src/Makefile`.
@@ -357,9 +363,9 @@ int h_query_delete(const struct _h_connection * conn, const char * query);
 int h_query_select(const struct _h_connection * conn, const char * query, struct _h_result * result);
 ```
 
-### Simple json queries
+### Simple JSON queries
 
-Hoel allows to use json objects for simple queries with `jansson` library. In the simple json queries, a json object called `json_t * j_query` is used to generate the query.
+Hoel allows to use JSON objects for simple queries with `jansson` library. In the simple JSON queries, a JSON object called `json_t * j_query` is used to generate the query.
 
 All `json_t *` returned and updated values must be free after use.
 
@@ -371,19 +377,19 @@ A `j_query` has the following form:
   "order_by": "col_name [asc|desc]" // String, available for h_select, specify the order by clause, optional
   "limit": integer_value            // Integer, available for h_select, specify the limit value, optional
   "offset"                          // Integer, available for h_select, specify the limit value, optional but available only if limit is set
-  "values": [{                      // json object or json array of json objects, available for h_insert, mandatory, specify the values to update
+  "values": [{                      // JSON object or JSON array of JSON objects, available for h_insert, mandatory, specify the values to update
     "col1": "value1",               // Generates col1='value1' for an update query
     "col2": value_integer,          // Generates col2=value_integer for an update query
     "col3", "value3",               // Generates col3='value3' for an update query
     "col4", null                    // Generates col4=NULL for an update query
   }]
-  "set": {                          // json object, available for h_update, mandatory, specify the values to update
+  "set": {                          // JSON object, available for h_update, mandatory, specify the values to update
     "col1": "value1",               // Generates col1='value1' for an update query
     "col2": value_integer,          // Generates col2=value_integer for an update query
     "col3", "value3",               // Generates col3='value3' for an update query
     "col4", null                    // Generates col4=NULL for an update query
   }
-  "where": {                        // json object, available for h_select, h_update and h_delete, mandatory, specify the where clause. All clauses are separated with an AND operator
+  "where": {                        // JSON object, available for h_select, h_update and h_delete, mandatory, specify the where clause. All clauses are separated with an AND operator
     "col1": "value1",               // Generates col1='value1'
     "col2": value_integer,          // Generates col2=value_integer
     "col3": null,                   // Generates col3=NULL
@@ -404,7 +410,7 @@ A `j_query` has the following form:
 
 #### Where clause construction
 
-A `where` clause is a json object containing a series of clauses. A clause can have 2 different forms:
+A `where` clause is a JSON object containing a series of clauses. A clause can have 2 different forms:
 
 - `col_name: value`
 - `col_name: {operator: "operator_value", value: value}`
@@ -418,7 +424,7 @@ In the second case, `col_name: {operator: "operator_value", value: value}`, depe
 
 All clauses are separated by an `AND` operator.
 
-As en axample, here is a json object and its generated where clause:
+As en axample, here is a JSON object and its generated where clause:
 
 JSON object:
 ```javascript
@@ -446,7 +452,7 @@ WHERE col1 = 'value1'
 
 If you need less simple clauses, you can build it on your own and use the `h_execute_query` or the `h_execute_query_json` functions.
 
-The simple json queries functions are:
+The simple JSON queries functions are:
 
 ```c
 /**
@@ -495,7 +501,7 @@ int h_update(const struct _h_connection * conn, const json_t * j_query, char **
 int h_delete(const struct _h_connection * conn, const json_t * j_query, char ** generated_query);
 ```
 
-#### json last insert id
+#### JSON last insert id
 
 The function `h_last_insert_id` returns the last inserted id in a `json_t *` format.
 
diff --git a/examples/Makefile b/examples/Makefile
index d44c9db..2c0100c 100644
--- a/examples/Makefile
+++ b/examples/Makefile
@@ -13,11 +13,10 @@
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 # GNU GENERAL PUBLIC LICENSE for more details.
 #
-PREFIX=/usr/local
 CC=gcc
 CFLAGS=-c -Wall -D_REENTRANT -I$(PREFIX)/include $(ADDITIONALFLAGS)
 HOEL_LOCATION=../src
-LIBS=-lc -lhoel -ljansson -lyder -L$(PREFIX)/lib -L$(HOEL_LOCATION)
+LIBS=-lc -lhoel -ljansson -lyder -L$(HOEL_LOCATION)
 ADDITIONALFLAGS=-O3
 
 all: libhoel.so example_sqlite3 example_mariadb example_pgsql example_mariadb_json
@@ -48,8 +47,16 @@ example_mariadb_json: example_mariadb_json.c
 	$(CC) -c $(CFLAGS) example_mariadb_json.c
 	$(CC) -o example_mariadb_json example_mariadb_json.o $(LIBS)
 
-test: example_sqlite3 example_mariadb example_pgsql
+test: test_pgsql test_mariadb test_sqlite3 test_mariadb_json
+
+test_pgsql: example_pgsql
 	LD_LIBRARY_PATH=$(HOEL_LOCATION):${LD_LIBRARY_PATH} ./example_pgsql
+
+test_mariadb: example_mariadb
 	LD_LIBRARY_PATH=$(HOEL_LOCATION):${LD_LIBRARY_PATH} ./example_mariadb
+
+test_sqlite3: example_sqlite3
 	LD_LIBRARY_PATH=$(HOEL_LOCATION):${LD_LIBRARY_PATH} ./example_sqlite3
+
+test_mariadb_json: example_mariadb_json
 	LD_LIBRARY_PATH=$(HOEL_LOCATION):${LD_LIBRARY_PATH} ./example_mariadb_json
diff --git a/examples/example_pgsql.c b/examples/example_pgsql.c
index 6179e8b..601b2bc 100644
--- a/examples/example_pgsql.c
+++ b/examples/example_pgsql.c
@@ -1,12 +1,14 @@
 #include <stdio.h>
 #include <jansson.h>
+#include <yder.h>
+
 #define _HOEL_PGSQL
 #include "../src/hoel.h"
 
 void print_result(struct _h_result result) {
   int col, row, i;
   char buf[64];
-  printf("rows: %d, col: %d\n", result.nb_rows, result.nb_columns);
+  y_log_message(Y_LOG_LEVEL_DEBUG, "rows: %d, col: %d", result.nb_rows, result.nb_columns);
   for (row = 0; row<result.nb_rows; row++) {
     for (col=0; col<result.nb_columns; col++) {
       switch(result.data[row][col].type) {
@@ -42,31 +44,51 @@ void print_result(struct _h_result result) {
 int main(int argc, char ** argv) {
   struct _h_result result;
   struct _h_connection * conn;
-  char * query = "select * from test", * connectionstring = "host=localhost dbname=test user=test password=test", * dump = NULL;
+  char * query = "select * from test",
+			 * insert_query = "insert into test (name, age, birthdate) values ('bob', 21, '1997-05-09')",
+			 * connectionstring = "host=girflet dbname=test user=test password=test",
+			 * dump = NULL;
   int res;
   json_t * j_result;
   
+	y_init_logs("example_pgsql", Y_LOG_MODE_CONSOLE, Y_LOG_LEVEL_DEBUG, NULL, "Starting example_pgsql");
+	
   conn = h_connect_pgsql(connectionstring);
-  
+	
+	res = h_query_insert(conn, insert_query);
+	
+  if (res == H_OK) {
+    y_log_message(Y_LOG_LEVEL_DEBUG, "insert query executed");
+		j_result = h_last_insert_id(conn);
+		dump = json_dumps(j_result, JSON_ENCODE_ANY);
+		y_log_message(Y_LOG_LEVEL_DEBUG, "last id is %s", dump);
+		free(dump);
+		json_decref(j_result);
+  } else {
+    y_log_message(Y_LOG_LEVEL_ERROR, "Error executing query: %d", res);
+  }
+	
   res = h_query_select(conn, query, &result);
   
   if (res == H_OK) {
     print_result(result);
     h_clean_result(&result);
   } else {
-    printf("Error executing query: %d\n", res);
+    y_log_message(Y_LOG_LEVEL_ERROR, "Error executing query: %d", res);
   }
   
   res = h_execute_query_json(conn, query, &j_result);
   
   if (res == H_OK) {
     dump = json_dumps(j_result, JSON_INDENT(2));
-    printf("json result is\n%s\n", dump);
+    y_log_message(Y_LOG_LEVEL_DEBUG, "json result is\n%s", dump);
     json_decref(j_result);
     free(dump);
   } else {
-    printf("Error executing json query: %d\n", res);
+    y_log_message(Y_LOG_LEVEL_ERROR, "Error executing json query: %d", res);
   }
   h_close_db(conn);
+	y_close_logs();
+	
   return h_clean_connection(conn);
 }
diff --git a/src/Makefile b/src/Makefile
index d275c4c..2ec14b2 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -1,5 +1,5 @@
 #
-# Ulfius Framework
+# Hoel Framework
 #
 # Makefile used to build the software
 #
@@ -26,17 +26,17 @@ LIBS_SQLITE=-lsqlite3
 
 # comment/uncomment these lines to disable/enable mysql/mariadb support
 FLAGS_MARIADB=-D_HOEL_MARIADB $(shell mysql_config --cflags)
-LIBS_MARIADB=$(shell mysql_config --libs)
+LIBS_MARIADB=$(shell mysql_config --libs_r)
 
 # comment/uncomment these lines to disable/enable postgresql support
-# FLAGS_PGSQL=-D_HOEL_PGSQL -I/usr/include/postgresql/
-# LIBS_PGSQL=-lpq
+FLAGS_PGSQL=-D_HOEL_PGSQL -I/usr/include/postgresql/
+LIBS_PGSQL=-lpq
 
 PREFIX=/usr/local
 CFLAGS=-c -fPIC -Wall -I$(PREFIX)/include $(FLAGS_SQLITE) $(FLAGS_MARIADB) $(FLAGS_PGSQL) -D_REENTRANT $(ADDITIONALFLAGS)
 LIBS=-L$(PREFIX)/lib -lc -ljansson -lyder -lorcania $(LIBS_SQLITE) $(LIBS_PGSQL) $(LIBS_MARIADB)
 OUTPUT=libhoel.so
-VERSION=1.1.1
+VERSION=1.2
 
 all: release
 
diff --git a/src/hoel-pgsql.c b/src/hoel-pgsql.c
index d591de3..e28e7c6 100644
--- a/src/hoel-pgsql.c
+++ b/src/hoel-pgsql.c
@@ -28,12 +28,19 @@
 #include <libpq-fe.h>
 #include <string.h>
 
+struct _h_pg_type {
+	Oid            pg_type;
+	unsigned short h_type;
+};
+
 /**
  * Postgre SQL handle
  */
 struct _h_pgsql {
-  char * conninfo;
-  PGconn * db_handle;
+  char              * conninfo;
+  PGconn            * db_handle;
+	unsigned int        nb_type;
+	struct _h_pg_type * list_type;
 };
 
 /**
@@ -44,11 +51,15 @@ struct _h_pgsql {
 struct _h_connection * h_connect_pgsql(char * conninfo) {
   // TODO get oids and types
   struct _h_connection * conn = NULL;
+	struct _h_result result_types;
+	int res_types, row;
+	char * cur_type_name, * endptr = NULL;
+	Oid cur_type_oid;
+	
   if (conninfo != NULL) {
     conn = malloc(sizeof(struct _h_connection));
     if (conn == NULL) {
       y_log_message(Y_LOG_LEVEL_ERROR, "Hoel - Error allocating memory for conn");
-      return NULL;
     }
     
     conn->type = HOEL_DB_TYPE_PGSQL;
@@ -56,9 +67,11 @@ struct _h_connection * h_connect_pgsql(char * conninfo) {
     if (conn->connection == NULL) {
       y_log_message(Y_LOG_LEVEL_ERROR, "Hoel - Error allocating memory for conn->connection");
       free(conn);
-      return NULL;
+			conn = NULL;
     }
     ((struct _h_pgsql *)conn->connection)->db_handle = PQconnectdb(conninfo);
+		((struct _h_pgsql *)conn->connection)->nb_type = 0;
+		((struct _h_pgsql *)conn->connection)->list_type = NULL;
     
     if (PQstatus(((struct _h_pgsql *)conn->connection)->db_handle) != CONNECTION_OK) {
       y_log_message(Y_LOG_LEVEL_ERROR, "Hoel - Error connecting to PostgreSQL Database");
@@ -66,8 +79,57 @@ struct _h_connection * h_connect_pgsql(char * conninfo) {
       PQfinish(((struct _h_pgsql *)conn->connection)->db_handle);
       free(conn->connection);
       free(conn);
-      return NULL;
-    }
+      conn = NULL;
+    } else {
+			res_types = h_execute_query_pgsql(conn, "select oid, typname from pg_type", &result_types);
+			if (res_types == H_OK) {
+				if (result_types.nb_columns == 2) {
+					for (row=0; row<result_types.nb_rows; row++) {
+						cur_type_oid = strtol(((struct _h_type_text *)result_types.data[row][0].t_data)->value, &endptr, 10);
+						cur_type_name = ((struct _h_type_text *)result_types.data[row][1].t_data)->value;
+						if (*endptr == '\0' && endptr != ((struct _h_type_text *)result_types.data[row][0].t_data)->value) {
+							((struct _h_pgsql *)conn->connection)->list_type = o_realloc(((struct _h_pgsql *)conn->connection)->list_type, (((struct _h_pgsql *)conn->connection)->nb_type + 1) * sizeof(struct _h_pg_type));
+							if (((struct _h_pgsql *)conn->connection)->list_type != NULL) {
+								((struct _h_pgsql *)conn->connection)->list_type[((struct _h_pgsql *)conn->connection)->nb_type].pg_type = cur_type_oid;
+								if (o_strcmp(cur_type_name, "bool") == 0) {
+									((struct _h_pgsql *)conn->connection)->list_type[((struct _h_pgsql *)conn->connection)->nb_type].h_type = HOEL_COL_TYPE_BOOL;
+								} else if (o_strncmp(cur_type_name, "int", 3) == 0 || (o_strncmp(cur_type_name+1, "id", 2) == 0 && o_strlen(cur_type_name) == 3)) {
+									((struct _h_pgsql *)conn->connection)->list_type[((struct _h_pgsql *)conn->connection)->nb_type].h_type = HOEL_COL_TYPE_INT;
+								} else if (o_strcmp(cur_type_name, "numeric") == 0 || o_strncmp(cur_type_name, "float", 5) == 0) {
+									((struct _h_pgsql *)conn->connection)->list_type[((struct _h_pgsql *)conn->connection)->nb_type].h_type = HOEL_COL_TYPE_DOUBLE;
+								} else if (o_strcmp(cur_type_name, "date") == 0 || o_strncmp(cur_type_name, "time", 4) == 0) {
+									((struct _h_pgsql *)conn->connection)->list_type[((struct _h_pgsql *)conn->connection)->nb_type].h_type = HOEL_COL_TYPE_DATE;
+								} else if (o_strcmp(cur_type_name, "bytea") == 0) {
+									((struct _h_pgsql *)conn->connection)->list_type[((struct _h_pgsql *)conn->connection)->nb_type].h_type = HOEL_COL_TYPE_BLOB;
+								} else if (o_strcmp(cur_type_name, "bool") == 0) {
+									((struct _h_pgsql *)conn->connection)->list_type[((struct _h_pgsql *)conn->connection)->nb_type].h_type = HOEL_COL_TYPE_BOOL;
+								} else {
+									((struct _h_pgsql *)conn->connection)->list_type[((struct _h_pgsql *)conn->connection)->nb_type].h_type = HOEL_COL_TYPE_TEXT;
+								}
+								((struct _h_pgsql *)conn->connection)->nb_type++;
+							} else {
+								y_log_message(Y_LOG_LEVEL_ERROR, "Hoel - Error allocating resources for list_type");
+							}
+						} else {
+							y_log_message(Y_LOG_LEVEL_ERROR, "Hoel - Error converting pg_type.oid to integer");
+						}
+					}
+				} else {
+					y_log_message(Y_LOG_LEVEL_ERROR, "Hoel - Error pg_type result");
+					PQfinish(((struct _h_pgsql *)conn->connection)->db_handle);
+					free(conn->connection);
+					free(conn);
+					conn = NULL;
+				}
+				h_clean_result(&result_types);
+			} else {
+				y_log_message(Y_LOG_LEVEL_ERROR, "Hoel - Error getting pg_type");
+				PQfinish(((struct _h_pgsql *)conn->connection)->db_handle);
+				free(conn->connection);
+				free(conn);
+				conn = NULL;
+			}
+		}
   }
   return conn;
 }
@@ -77,6 +139,9 @@ struct _h_connection * h_connect_pgsql(char * conninfo) {
  */
 void h_close_pgsql(struct _h_connection * conn) {
   PQfinish(((struct _h_pgsql *)conn->connection)->db_handle);
+	o_free(((struct _h_pgsql *)conn->connection)->list_type);
+	((struct _h_pgsql *)conn->connection)->list_type = NULL;
+	((struct _h_pgsql *)conn->connection)->nb_type = 0;
 }
 
 /**
@@ -88,6 +153,21 @@ char * h_escape_string_pgsql(const struct _h_connection * conn, const char * uns
 }
 
 /**
+ * Return the hoel type of a column given its Oid
+ * If type is not found, return HOEL_COL_TYPE_TEXT
+ */
+static unsigned short h_get_type_from_oid(const struct _h_connection * conn, Oid pg_type) {
+	int i;
+	
+	for (i = 0; i < ((struct _h_pgsql *)conn->connection)->nb_type; i++) {
+		if (((struct _h_pgsql *)conn->connection)->list_type[i].pg_type == pg_type) {
+			return ((struct _h_pgsql *)conn->connection)->list_type[i].h_type;
+		}
+	}
+	return HOEL_COL_TYPE_TEXT;
+}
+
+/**
  * h_execute_query_pgsql
  * Execute a query on a pgsql connection, set the result structure with the returned values
  * Should not be executed by the user because all parameters are supposed to be correct
@@ -100,7 +180,7 @@ int h_execute_query_pgsql(const struct _h_connection * conn, const char * query,
   struct _h_data * data, * cur_row = NULL;
   
   res = PQexec(((struct _h_pgsql *)conn->connection)->db_handle, query);
-  if (PQresultStatus(res) != PGRES_TUPLES_OK) {
+  if (PQresultStatus(res) != PGRES_TUPLES_OK && PQresultStatus(res) != PGRES_COMMAND_OK) {
     y_log_message(Y_LOG_LEVEL_ERROR, "Error executing sql query");
     y_log_message(Y_LOG_LEVEL_DEBUG, "Error message: \"%s\"", PQerrorMessage(((struct _h_pgsql *)conn->connection)->db_handle));
     y_log_message(Y_LOG_LEVEL_DEBUG, "Query: \"%s\"", query);
@@ -117,10 +197,34 @@ int h_execute_query_pgsql(const struct _h_connection * conn, const char * query,
       cur_row = NULL;
       for(j = 0; j < nfields; j++) {
         char * val = PQgetvalue(res, i, j);
-        if (val == NULL || strlen(val) == 0) {
+        if (val == NULL) {
           data = h_new_data_null();
         } else {
-          data = h_new_data_text(PQgetvalue(res, i, j));
+					switch (h_get_type_from_oid(conn, PQftype(res, j))) {
+						case HOEL_COL_TYPE_INT:
+							data = h_new_data_int(strtol(PQgetvalue(res, i, j), NULL, 10));
+							break;
+						case HOEL_COL_TYPE_DOUBLE:
+							data = h_new_data_double(strtod(PQgetvalue(res, i, j), NULL));
+							break;
+						case HOEL_COL_TYPE_BLOB:
+							data = h_new_data_blob(PQgetvalue(res, i, j), PQfsize(res, i));
+							break;
+						case HOEL_COL_TYPE_BOOL:
+							if (o_strcasecmp(PQgetvalue(res, i, j), "t") == 0) {
+								data = h_new_data_int(1);
+							} else if (o_strcasecmp(PQgetvalue(res, i, j), "f") == 0) {
+								data = h_new_data_int(0);
+							} else {
+								data = h_new_data_null();
+							}
+							break;
+						case HOEL_COL_TYPE_DATE:
+						case HOEL_COL_TYPE_TEXT:
+						default:
+							data = h_new_data_text(PQgetvalue(res, i, j));
+							break;
+					}
         }
         h_res = h_row_add_data(&cur_row, data, j);
         h_clean_data_full(data);
@@ -162,7 +266,7 @@ int h_execute_query_json_pgsql(const struct _h_connection * conn, const char * q
   }
   
   res = PQexec(((struct _h_pgsql *)conn->connection)->db_handle, query);
-  if (PQresultStatus(res) != PGRES_TUPLES_OK) {
+  if (PQresultStatus(res) != PGRES_TUPLES_OK && PQresultStatus(res) != PGRES_COMMAND_OK) {
     y_log_message(Y_LOG_LEVEL_ERROR, "Error executing sql query");
     y_log_message(Y_LOG_LEVEL_DEBUG, "Error message: \"%s\"", PQerrorMessage(((struct _h_pgsql *)conn->connection)->db_handle));
     y_log_message(Y_LOG_LEVEL_DEBUG, "Query: \"%s\"", query);
@@ -183,7 +287,31 @@ int h_execute_query_json_pgsql(const struct _h_connection * conn, const char * q
       if (val == NULL || strlen(val) == 0) {
         json_object_set_new(j_data, PQfname(res, j), json_null());
       } else {
-        json_object_set_new(j_data, PQfname(res, j), json_string(PQgetvalue(res, i, j)));
+				switch (h_get_type_from_oid(conn, PQftype(res, j))) {
+					case HOEL_COL_TYPE_INT:
+						json_object_set_new(j_data, PQfname(res, j), json_integer(strtol(PQgetvalue(res, i, j), NULL, 10)));
+						break;
+					case HOEL_COL_TYPE_DOUBLE:
+						json_object_set_new(j_data, PQfname(res, j), json_real(strtod(PQgetvalue(res, i, j), NULL)));
+						break;
+					case HOEL_COL_TYPE_BLOB:
+						json_object_set_new(j_data, PQfname(res, j), json_stringn(PQgetvalue(res, i, j), PQfsize(res, i)));
+						break;
+					case HOEL_COL_TYPE_BOOL:
+						if (o_strcasecmp(PQgetvalue(res, i, j), "t") == 0) {
+							json_object_set_new(j_data, PQfname(res, j), json_integer(1));
+						} else if (o_strcasecmp(PQgetvalue(res, i, j), "f") == 0) {
+							json_object_set_new(j_data, PQfname(res, j), json_integer(0));
+						} else {
+							json_object_set_new(j_data, PQfname(res, j), json_null());
+						}
+						break;
+					case HOEL_COL_TYPE_DATE:
+					case HOEL_COL_TYPE_TEXT:
+					default:
+						json_object_set_new(j_data, PQfname(res, j), json_string(PQgetvalue(res, i, j)));
+						break;
+				}
       }
     }
     json_array_append_new(*j_result, j_data);
@@ -192,4 +320,38 @@ int h_execute_query_json_pgsql(const struct _h_connection * conn, const char * q
   PQclear(res);
   return H_OK;
 }
+
+/**
+ * Return the id of the last inserted value
+ * Assuming you use sequences for automatically generated ids
+ */
+int h_last_insert_id_pgsql(const struct _h_connection * conn) {
+  PGresult *res;
+  int int_res = 0;
+	char * str_res, * endptr = NULL;
+	
+	res = PQexec(((struct _h_pgsql *)conn->connection)->db_handle, "SELECT lastval()");
+  if (PQresultStatus(res) != PGRES_TUPLES_OK && PQresultStatus(res) != PGRES_COMMAND_OK) {
+    y_log_message(Y_LOG_LEVEL_ERROR, "Error executing h_last_insert_id");
+    y_log_message(Y_LOG_LEVEL_DEBUG, "Error message: \"%s\"", PQerrorMessage(((struct _h_pgsql *)conn->connection)->db_handle));
+    return H_ERROR_QUERY;
+  }
+	
+	if (PQnfields(res) && PQntuples(res)) {
+		str_res = PQgetvalue(res, 0, 0);
+		if (str_res != NULL) {
+			int_res = strtol(str_res, &endptr, 10);
+			if (*endptr != '\0' || endptr == str_res) {
+				y_log_message(Y_LOG_LEVEL_ERROR, "Error h_last_insert_id, returned value can't be converted to numeric");
+				int_res = 0;
+			}
+		} else {
+			y_log_message(Y_LOG_LEVEL_ERROR, "Error h_last_insert_id, returned value is NULL");
+		}
+	} else {
+		y_log_message(Y_LOG_LEVEL_ERROR, "Error h_last_insert_id, returned value has no data available");
+	}
+	PQclear(res);
+	return int_res;
+}
 #endif
diff --git a/src/hoel-simple-json.c b/src/hoel-simple-json.c
index f8945c1..cbc3820 100644
--- a/src/hoel-simple-json.c
+++ b/src/hoel-simple-json.c
@@ -28,29 +28,6 @@
 #include "h-private.h"
 
 /**
- * trim_whitespace_and_double_quotes
- * Return the string without its beginning and ending whitespaces or double quotes
- */
-static char * trim_whitespace_and_double_quotes(char *str) {
-  char *end;
-
-  // Trim leading space
-  while(isspace(*str) || *str == '"') str++;
-
-  if(*str == 0)  // All spaces?
-    return str;
-
-  // Trim trailing space
-  end = str + strlen(str) - 1;
-  while(end > str && (isspace(*end) || *end == '"')) end--;
-
-  // Write new null terminator
-  *(end+1) = 0;
-
-  return str;
-}
-
-/**
  * Builds an insert query from a json object and a table name
  * Returned value must be o_free'd after use
  */
@@ -73,9 +50,7 @@ static char * h_get_insert_query_from_json_object(const struct _h_connection * c
         }
         break;
       case JSON_INTEGER:
-        tmp = json_dumps(value, JSON_ENCODE_ANY);
-        new_data = msprintf("%s", tmp);
-        o_free(tmp);
+        new_data = msprintf("%"JSON_INTEGER_FORMAT, json_integer_value(value));
         break;
       case JSON_REAL:
         new_data = msprintf("%f", json_real_value(value));
@@ -221,16 +196,22 @@ static char * h_get_where_clause_from_json_object(const struct _h_connection * c
         } else {
           if (json_is_null(value)) {
             clause = msprintf("%s IS NULL", key);
-          } else {
-            dump = json_dumps(value, JSON_ENCODE_ANY);
-            escape = h_escape_string(conn, trim_whitespace_and_double_quotes(dump));
+          } else if (json_is_string(value)) {
+            escape = h_escape_string(conn, json_string_value(value));
             if (escape == NULL) {
               y_log_message(Y_LOG_LEVEL_ERROR, "Hoel - Error escape");
               return NULL;
             }
             clause = msprintf("%s='%s'", key, escape);
-            o_free(dump);
             o_free(escape);
+          } else if (json_is_integer(value)) {
+            clause = msprintf("%s='%"JSON_INTEGER_FORMAT"'", key, json_integer_value(value));
+          } else if (json_is_real(value)) {
+            clause = msprintf("%s='%f'", key, json_real_value(value));
+          } else if (json_is_true(value)) {
+            clause = msprintf("%s=1");
+          } else if (json_is_false(value)) {
+            clause = msprintf("%s=0");
           }
           if (clause == NULL) {
             y_log_message(Y_LOG_LEVEL_ERROR, "Hoel - Error allocating memory for clause");
@@ -582,9 +563,10 @@ json_t * h_last_insert_id(const struct _h_connection * conn) {
 #endif
 #ifdef _HOEL_PGSQL
     } else if (conn->type == HOEL_DB_TYPE_PGSQL) {
-      // TODO
-      // Not possible ?
-      y_log_message(Y_LOG_LEVEL_ERROR, "Hoel/h_last_insert_id Error feature not supported");
+      int last_id = h_last_insert_id_pgsql(conn);
+      if (last_id > 0) {
+        j_data = json_integer(last_id);
+      }
 #endif
     }
   }
diff --git a/src/hoel.c b/src/hoel.c
index d4f10a9..52376a4 100644
--- a/src/hoel.c
+++ b/src/hoel.c
@@ -311,10 +311,12 @@ struct _h_data * h_query_last_insert_id(const struct _h_connection * conn) {
 #endif
 #ifdef _HOEL_PGSQL
     } else if (conn->type == HOEL_DB_TYPE_PGSQL) {
-      // TODO
-      // Not possible ?
-      y_log_message(Y_LOG_LEVEL_ERROR, "Error feature not supported");
-      data = h_new_data_null();
+      int last_id = h_last_insert_id_pgsql(conn);
+      if (last_id > 0) {
+        data = h_new_data_int(last_id);
+      } else {
+        data = h_new_data_null();
+      }
 #endif
     } else {
       data = h_new_data_null();
diff --git a/src/hoel.h b/src/hoel.h
index 3722b3f..5f181c0 100644
--- a/src/hoel.h
+++ b/src/hoel.h
@@ -24,7 +24,7 @@
 #ifndef __HOEL_H__
 #define __HOEL_H__
 
-#define HOEL_VERSION 1.1.1
+#define HOEL_VERSION 1.2
 
 #include <jansson.h>
 
@@ -53,6 +53,7 @@
 #define HOEL_COL_TYPE_TEXT   2
 #define HOEL_COL_TYPE_DATE   3
 #define HOEL_COL_TYPE_BLOB   4
+#define HOEL_COL_TYPE_BOOL   5
 #define HOEL_COL_TYPE_NULL   5
 
 #define H_OK                0  // No error
@@ -460,6 +461,12 @@ void h_close_pgsql(struct _h_connection * conn);
  * returned value must be free'd after use
  */
 char * h_escape_string_pgsql(const struct _h_connection * conn, const char * unsafe);
+
+/**
+ * Return the id of the last inserted value
+ * Assuming you use sequences for automatically generated ids
+ */
+int h_last_insert_id_pgsql(const struct _h_connection * conn);
 #endif
 
 #endif // __HOEL_H__
diff --git a/test/core.c b/test/core.c
index ab09122..d0336ca 100644
--- a/test/core.c
+++ b/test/core.c
@@ -15,6 +15,8 @@
 #define DEFAULT_BD_PATH "/tmp/test.db"
 #define WRONG_BD_PATH "nope.db"
 
+#define UNSAFE_STRING "un'safe' (\"string\")#!/$%*];"
+
 #define SELECT_DATA_1 "SELECT `integer_col`, `string_col`, `date_col` FROM `test_table` WHERE `integer_col` = 1"
 #define SELECT_DATA_2 "SELECT `integer_col`, `string_col`, `date_col` FROM `test_table` WHERE `integer_col` = 2"
 #define SELECT_DATA_ERROR "SELECT `integer_col`, `string_col`, `date_col` FROM `test_table` WHERE `integer_col` = 'error'"
@@ -82,6 +84,9 @@ START_TEST(test_hoel_escape_string)
 {
   struct _h_connection * conn;
   char * escaped;
+  json_t * j_query, * j_result;
+  int res;
+  
   conn = h_connect_sqlite(db_path);
   ck_assert_ptr_ne(conn, NULL);
   escaped = h_escape_string(conn, "value");
@@ -90,6 +95,18 @@ START_TEST(test_hoel_escape_string)
   escaped = h_escape_string(conn, "`unsafe ' value\"!");
   ck_assert_str_eq(escaped, "`unsafe '' value\"!");
   h_free(escaped);
+  
+  j_query = json_pack("{sss{siss}}", "table", "test_table", "values", "integer_col", 666, "string_col", UNSAFE_STRING);
+  res = h_insert(conn, j_query, NULL);
+  json_decref(j_query);
+  ck_assert_int_eq(res, H_OK);
+  j_query = json_pack("{sss[s]s{si}}", "table", "test_table", "columns", "string_col", "where", "integer_col", 666);
+  res = h_select(conn, j_query, &j_result, NULL);
+  json_decref(j_query);
+  ck_assert_int_eq(res, H_OK);
+  ck_assert_str_eq(UNSAFE_STRING, json_string_value(json_object_get(json_array_get(j_result, 0), "string_col")));
+  json_decref(j_result);
+  
   ck_assert_int_eq(h_close_db(conn), H_OK);
   ck_assert_int_eq(h_clean_connection(conn), H_OK);
 }

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-iot/hoel.git



More information about the Debian-iot-packaging mailing list