evsql_query_params compiles...
--- 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.