evsql_query_params compiles...
authorTero Marttila <terom@fixme.fi>
Sun, 12 Oct 2008 01:09:00 +0300
changeset 23 1dee73ae4ad0
parent 22 85ba190a9e68
child 24 82cfdb6680d1
evsql_query_params compiles...
src/evpq.c
src/evpq.h
src/evsql.c
src/evsql.h
--- a/src/evpq.c	Sun Oct 12 00:18:30 2008 +0300
+++ b/src/evpq.c	Sun Oct 12 01:09:00 2008 +0300
@@ -249,15 +249,19 @@
     return NULL;
 }
 
-int evpq_query (struct evpq_conn *conn, const char *command) {
-    // check state
+static int _evpq_check_query (struct evpq_conn *conn) {
+    // just check the state
     if (conn->state != EVPQ_CONNECTED)
         ERROR("invalid evpq state: %d", conn->state);
     
-    // do the query
-    if (PQsendQuery(conn->pg_conn, command) == 0)
-        ERROR("PQsendQuery: %s", PQerrorMessage(conn->pg_conn));
-    
+    // ok
+    return 0;
+
+error:
+    return -1;
+}
+
+static int _evpq_handle_query (struct evpq_conn *conn) {
     // update state
     conn->state = EVPQ_QUERY;
     
@@ -274,6 +278,47 @@
     return -1;
 }
 
+int evpq_query (struct evpq_conn *conn, const char *command) {
+    // check state
+    if (_evpq_check_query(conn))
+        goto error;
+    
+    // do the query
+    if (PQsendQuery(conn->pg_conn, command) == 0)
+        ERROR("PQsendQuery: %s", PQerrorMessage(conn->pg_conn));
+    
+    // handle it
+    if (_evpq_handle_query(con))
+        goto error;
+
+    // success
+    return 0;
+
+error:
+    return -1;
+}
+
+int evpq_query_params (struct evpq_conn *conn, const char *command, int nParams, const Oid *paramTypes, const char * const *paramValues, const int *paramLengths, const int *paramFormats, int resultFormat) {
+    // check state
+    if (_evpq_check_query(conn))
+        goto error;
+    
+    // do the query
+    if (PQsendQueryParams(conn->pg_conn, command, nParams, paramTypes, paramValues, paramLengths, paramFormats, resultFormat) == 0)
+        ERROR("PQsendQueryParams: %s", PQerrorMessage(conn->pg_conn));
+    
+    // handle it
+    if (_evpq_handle_query(con))
+        goto error;
+
+    // success
+    return 0;
+
+error:
+    return -1;
+
+}
+
 enum evpq_state evpq_state (struct evpq_conn *conn) {
     return conn->state;
 }
--- a/src/evpq.h	Sun Oct 12 00:18:30 2008 +0300
+++ b/src/evpq.h	Sun Oct 12 01:09:00 2008 +0300
@@ -80,6 +80,13 @@
 int evpq_query (struct evpq_conn *conn, const char *command);
 
 /*
+ * Execute a query with params.
+ *
+ * See evpq_query and PQsendQueryParams/PQexecParams
+ */
+int evpq_query_params (struct evpq_conn *conn, const char *command, int nParams, const Oid *paramTypes, const char * const *paramValues, const int *paramLengths, const int *paramFormats, int resultFormat);
+
+/*
  * Connection state à la evpq.
  */
 enum evpq_state evpq_state (struct evpq_conn *conn);
--- a/src/evsql.c	Sun Oct 12 00:18:30 2008 +0300
+++ b/src/evsql.c	Sun Oct 12 01:09:00 2008 +0300
@@ -36,6 +36,18 @@
 
     // the actual SQL query, this may or may not be ours, see _evsql_query_exec
     char *command;
+    
+    // possible query params
+    struct evsql_query_param_info {
+        int count;
+
+        Oid *types;
+        const char **values;
+        int *lengths;
+        int *formats;
+
+        int result_format;
+    } params;
 
     // our callback
     evsql_query_cb cb_fn;
@@ -50,6 +62,7 @@
     } result;
 };
 
+
 /*
  * Actually execute the given query.
  *
@@ -61,8 +74,21 @@
 static int _evsql_query_exec (struct evsql *evsql, struct evsql_query *query, const char *command) {
     switch (evsql->type) {
         case EVSQL_EVPQ:
-            // just pass it through
-            return evpq_query(evsql->engine.evpq, command);
+            // got params?
+            if (query->params.count) {
+                return evpq_query_params(evsql->engine.evpq, command,
+                    query->params.count, 
+                    query->params.types, 
+                    query->params.values, 
+                    query->params.lengths, 
+                    query->params.formats, 
+                    query->params.result_format
+                );
+
+            } else {
+                // plain 'ole query
+                return evpq_query(evsql->engine.evpq, command);
+            }
         
         default:
             FATAL("evsql->type");
@@ -70,10 +96,25 @@
 }
 
 /*
+ * Free the query and related resources, doesn't trigger any callbacks or remove from any queues
+ */
+static void _evsql_query_free (struct evsql_query *query) {
+    assert(query->command == NULL);
+    
+    // free params if present
+    free(query->params.types);
+    free(query->params.values);
+    free(query->params.lengths);
+    free(query->params.formats);
+
+    // free the query itself
+    free(query);
+}
+
+/*
  * Dequeue the query, execute the callback, and free it.
  */
 static void _evsql_query_done (struct evsql_query *query, const struct evsql_result_info *result_info) {
-    assert(query->command == NULL);
 
     // dequeue
     TAILQ_REMOVE(&query->evsql->queue, query, entry);
@@ -83,7 +124,7 @@
         query->cb_fn(*result_info, query->cb_arg);
     
     // free
-    free(query);
+    _evsql_query_free(query);
 }
 
 /*
@@ -298,11 +339,9 @@
     }
 }
 
-
-struct evsql_query *evsql_query (struct evsql *evsql, const char *command, evsql_query_cb query_fn, void *cb_arg) {
+static struct evsql_query *_evsql_query_new (struct evsql *evsql, evsql_query_cb query_fn, void *cb_arg) {
     struct evsql_query *query;
-    int idle;
-
+    
     // allocate it
     if ((query = calloc(1, sizeof(*query))) == NULL)
         ERROR("calloc");
@@ -311,6 +350,16 @@
     query->evsql = evsql;
     query->cb_fn = query_fn;
     query->cb_arg = cb_arg;
+
+    // success
+    return query;
+
+error:
+    return NULL;
+}
+
+static int _evsql_query_enqueue (struct evsql *evsql, struct evsql_query *query, const char *command) {
+    int idle;
     
     // check state
     if ((idle = _evsql_query_idle(evsql)) < 0)
@@ -331,14 +380,85 @@
     
     // store it on the list
     TAILQ_INSERT_TAIL(&evsql->queue, query, entry);
+
+    // ok, good
+    return 0;
+
+error:
+    return -1;
+}
+
+struct evsql_query *evsql_query (struct evsql *evsql, const char *command, evsql_query_cb query_fn, void *cb_arg) {
+    struct evsql_query *query = NULL;
     
-    // success
+    // alloc new query
+    if ((query = _evsql_query_new(evsql, query_fn, cb_arg)) == NULL)
+        goto error;
+    
+    // just execute the command string directly
+    if (_evsql_query_enqueue(evsql, query, command))
+        goto error;
+
+    // ok
     return query;
 
 error:
-    // do *NOT* free query->command, ever
-    free(query);
+    _evsql_query_free(query);
 
     return NULL;
 }
 
+struct evsql_query *evsql_query_params (struct evsql *evsql, const char *command, struct evsql_query_params params, evsql_query_cb query_fn, void *cb_arg) {
+    struct evsql_query *query = NULL;
+    struct evsql_query_param *param;
+    int idx;
+    
+    // alloc new query
+    if ((query = _evsql_query_new(evsql, query_fn, cb_arg)) == NULL)
+        goto error;
+
+    // count the params
+    for (param = params.list; param->value || param->length; param++) 
+        query->params.count++;
+
+    // allocate the vertical storage for the parameters
+    if (0
+        
+//            !(query->params.types    = calloc(query->params.count, sizeof(Oid)))
+        ||  !(query->params.values   = calloc(query->params.count, sizeof(char *)))
+        ||  !(query->params.lengths  = calloc(query->params.count, sizeof(int)))
+        ||  !(query->params.formats  = calloc(query->params.count, sizeof(int)))
+    )
+        ERROR("calloc");
+
+    // transform
+    for (param = params.list, idx = 0; param->value || param->length; param++, idx++) {
+        // `types` stays NULL
+        // query->params.types[idx] = 0;
+        
+        // values
+        query->params.values[idx] = param->value;
+
+        // lengths (nonzero for NULLs)
+        query->params.lengths[idx] = param->value ? param->length : 0;
+
+        // formats, binary if length is nonzero
+        query->params.formats[idx] = param->value && param->length;
+    }
+
+    // result format
+    query->params.result_format = params.result_binary ? 1 : 0;
+
+    // execute it
+    if (_evsql_query_enqueue(evsql, query, command))
+        goto error;
+
+    // ok
+    return query;
+
+error:
+    _evsql_query_free(query);
+    
+    return NULL;
+}
+
--- a/src/evsql.h	Sun Oct 12 00:18:30 2008 +0300
+++ b/src/evsql.h	Sun Oct 12 01:09:00 2008 +0300
@@ -20,15 +20,28 @@
 struct evsql_query;
 
 /*
- * Query parameter info
- * /
+ * Query parameter info.
+ *
+ * Use the EVSQL_PARAM_* macros to define the value of list
+ */
 struct evsql_query_params {
-    int count;
-    const char * const *values;
-    const int *lengths;
-    const int *formats;
-    int result_format;
-}; */
+    // nonzero to get results in binary format
+    int result_binary;
+    
+    // the list of parameters, terminated by { 0, 0 }
+    struct evsql_query_param {
+        // the textual or binary value for this parameter
+        char *value;
+
+        // the explicit length of the parameter if it's binary. Must be non-zero for NULL values.
+        int length;
+    } list[];
+};
+
+// macros for defining evsql_query_params
+#define EVSQL_PARAM_NULL                    { NULL, 1 }
+#define EVSQL_PARAM_TEXT(value)             { value, 0 }
+#define EVSQL_PARAM_BINARY(value, length)   { value, length }
 
 /*
  * Result type
@@ -71,6 +84,11 @@
 struct evsql_query *evsql_query (struct evsql *evsql, const char *command, evsql_query_cb query_fn, void *cb_arg);
 
 /*
+ * Same, but uses the SQL-level support for binding parameters.
+ */
+struct evsql_query *evsql_query_params (struct evsql *evsql, const char *command, struct evsql_query_params params, evsql_query_cb query_fn, void *cb_arg);
+
+/*
  * Close a connection. Callbacks for waiting queries will not be run.
  *
  * XXX: not implemented yet.