commit a281fd57130c9e9cdee4eb31029734cd51ce6d00
parent 8368f6d47199834e6ca005a8c0f4a242161c0ccb
Author: Joris Vink <joris@coders.se>
Date: Mon, 4 Jan 2016 11:12:43 +0100
Introduce synchronous pgsql queries.
Semantics for using pgsql API have changed quite heavily
with this commit. See the examples for more information.
Based on Github issue #95 by PauloMelo (paulo.melo@vintageform.pt)
with several modifications by me.
Diffstat:
6 files changed, 355 insertions(+), 106 deletions(-)
diff --git a/examples/pgsql-sync/.gitignore b/examples/pgsql-sync/.gitignore
@@ -0,0 +1,5 @@
+*.o
+.objs
+pgsql-sync.so
+assets.h
+cert
diff --git a/examples/pgsql-sync/conf/pgsql-sync.conf b/examples/pgsql-sync/conf/pgsql-sync.conf
@@ -0,0 +1,11 @@
+# Placeholder configuration
+
+bind 127.0.0.1 8888
+load ./pgsql-sync.so init
+tls_dhparam dh2048.pem
+
+domain 127.0.0.1 {
+ certfile cert/server.crt
+ certkey cert/server.key
+ static / page
+}
diff --git a/examples/pgsql-sync/src/pgsql-sync.c b/examples/pgsql-sync/src/pgsql-sync.c
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2015 Joris Vink <joris@coders.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * This example demonstrates how to use synchronous PGSQL queries
+ * with Kore. For an asynchronous example see pgsql/ under examples/.
+ *
+ * This example does the same as the asynchronous one, select all entries
+ * from a table called "coders".
+ */
+
+#include <kore/kore.h>
+#include <kore/http.h>
+#include <kore/pgsql.h>
+
+int init(int);
+int page(struct http_request *);
+
+/* Called when our module is loaded (see config) */
+int
+init(int state)
+{
+ /* Register our database. */
+ kore_pgsql_register("db", "host=/tmp dbname=test");
+
+ return (KORE_RESULT_OK);
+}
+
+/* Page handler entry point (see config) */
+int
+page(struct http_request *req)
+{
+ struct kore_pgsql sql;
+ char *name;
+ int rows, i;
+
+ req->status = HTTP_STATUS_INTERNAL_ERROR;
+
+ /*
+ * Initialise our kore_pgsql data structure with the database name
+ * we want to connect to (note that we registered this earlier with
+ * kore_pgsql_register()). We also say we will perform a synchronous
+ * query (KORE_PGSQL_SYNC) and we do not need to pass our http_request
+ * so we pass NULL instead.
+ */
+ if (!kore_pgsql_query_init(&sql, NULL, "db", KORE_PGSQL_SYNC)) {
+ kore_pgsql_logerror(&sql);
+ goto out;
+ }
+
+ /*
+ * Now we can fire off the query, once it returns we either have
+ * a result on which we can operate or an error occured.
+ */
+ if (!kore_pgsql_query(&sql, "SELECT * FROM coders")) {
+ kore_pgsql_logerror(&sql);
+ goto out;
+ }
+
+ /*
+ * Iterate over the result and dump it to somewhere.
+ */
+ rows = kore_pgsql_ntuples(&sql);
+ for (i = 0; i < rows; i++) {
+ name = kore_pgsql_getvalue(&sql, i, 0);
+ kore_log(LOG_NOTICE, "name: '%s'", name);
+ }
+
+ /* All good. */
+ req->status = HTTP_STATUS_OK;
+
+out:
+ http_response(req, req->status, NULL, 0);
+
+ /* Don't forget to cleanup the kore_pgsql data structure. */
+ kore_pgsql_cleanup(&sql);
+
+ return (KORE_RESULT_OK);
+}
diff --git a/examples/pgsql/src/pgsql.c b/examples/pgsql/src/pgsql.c
@@ -16,7 +16,8 @@
/*
* This example demonstrates on how to use state machines and
- * asynchronous pgsql queries.
+ * asynchronous pgsql queries. For a synchronous query example
+ * see the pgsql-sync/ example under the examples/ directory.
*
* While this example might seem overly complex for a simple pgsql
* query, there is a reason behind its complexity:
@@ -36,15 +37,17 @@
#include <kore/http.h>
#include <kore/pgsql.h>
-#define REQ_STATE_QUERY 0
-#define REQ_STATE_DB_WAIT 1
-#define REQ_STATE_DB_READ 2
-#define REQ_STATE_ERROR 3
-#define REQ_STATE_DONE 4
+#define REQ_STATE_INIT 0
+#define REQ_STATE_QUERY 1
+#define REQ_STATE_DB_WAIT 2
+#define REQ_STATE_DB_READ 3
+#define REQ_STATE_ERROR 4
+#define REQ_STATE_DONE 5
int init(int);
int page(struct http_request *);
+static int request_perform_init(struct http_request *);
static int request_perform_query(struct http_request *);
static int request_db_wait(struct http_request *);
static int request_db_read(struct http_request *);
@@ -52,6 +55,7 @@ static int request_error(struct http_request *);
static int request_done(struct http_request *);
struct http_state mystates[] = {
+ { "REQ_STATE_INIT", request_perform_init },
{ "REQ_STATE_QUERY", request_perform_query },
{ "REQ_STATE_DB_WAIT", request_db_wait },
{ "REQ_STATE_DB_READ", request_db_read },
@@ -62,6 +66,7 @@ struct http_state mystates[] = {
#define mystates_size (sizeof(mystates) / sizeof(mystates[0]))
struct rstate {
+ int cnt;
struct kore_pgsql sql;
};
@@ -69,8 +74,8 @@ struct rstate {
int
init(int state)
{
- /* Set our connection string. */
- pgsql_conn_string = "host=/var/run/postgresql/ dbname=test";
+ /* Register our database. */
+ kore_pgsql_register("db", "host=/tmp dbname=test");
return (KORE_RESULT_OK);
}
@@ -84,29 +89,48 @@ page(struct http_request *req)
return (http_state_run(mystates, mystates_size, req));
}
-/* The initial state, we setup our context and fire off the pgsql query. */
+/* Initialize our PGSQL data structure and prepare for an async query. */
int
-request_perform_query(struct http_request *req)
+request_perform_init(struct http_request *req)
{
struct rstate *state;
- /* Setup our state context. */
- state = kore_malloc(sizeof(*state));
-
- /* Attach the state to our request. */
- req->hdlr_extra = state;
-
- /* We want to move to read result after this. */
- req->fsm_state = REQ_STATE_DB_WAIT;
+ /* Setup our state context (if not yet set). */
+ if (req->hdlr_extra == NULL) {
+ state = kore_malloc(sizeof(*state));
+ req->hdlr_extra = state;
+ } else {
+ state = req->hdlr_extra;
+ }
- /* Fire off the query. */
- if (!kore_pgsql_query(&state->sql, req, "SELECT * FROM coders")) {
+ /* Initialize our kore_pgsql data structure. */
+ if (!kore_pgsql_query_init(&state->sql, req, "db", KORE_PGSQL_ASYNC)) {
/* If the state was still INIT, we'll try again later. */
if (state->sql.state == KORE_PGSQL_STATE_INIT) {
- req->fsm_state = REQ_STATE_QUERY;
+ req->fsm_state = REQ_STATE_INIT;
return (HTTP_STATE_RETRY);
}
+ kore_pgsql_logerror(&state->sql);
+ req->fsm_state = REQ_STATE_ERROR;
+ } else {
+ req->fsm_state = REQ_STATE_QUERY;
+ }
+
+ return (HTTP_STATE_CONTINUE);
+}
+
+/* After setting everything up we will execute our async query. */
+int
+request_perform_query(struct http_request *req)
+{
+ struct rstate *state = req->hdlr_extra;
+
+ /* We want to move to read result after this. */
+ req->fsm_state = REQ_STATE_DB_WAIT;
+
+ /* Fire off the query. */
+ if (!kore_pgsql_query(&state->sql, "SELECT * FROM coders")) {
/*
* Let the state machine continue immediately since we
* have an error anyway.
diff --git a/includes/pgsql.h b/includes/pgsql.h
@@ -22,6 +22,9 @@
#define KORE_PGSQL_FORMAT_TEXT 0
#define KORE_PGSQL_FORMAT_BINARY 1
+#define KORE_PGSQL_SYNC 0x0001
+#define KORE_PGSQL_ASYNC 0x0002
+
#if defined(__cplusplus)
extern "C" {
#endif
@@ -29,14 +32,23 @@ extern "C" {
struct pgsql_conn {
u_int8_t type;
u_int8_t flags;
+ char *name;
PGconn *db;
struct pgsql_job *job;
TAILQ_ENTRY(pgsql_conn) list;
};
+struct pgsql_db {
+ char *name;
+ char *conn_string;
+
+ LIST_ENTRY(pgsql_db) rlist;
+};
+
struct kore_pgsql {
u_int8_t state;
+ int flags;
char *error;
PGresult *result;
struct pgsql_conn *conn;
@@ -45,17 +57,17 @@ struct kore_pgsql {
};
extern u_int16_t pgsql_conn_max;
-extern char *pgsql_conn_string;
void kore_pgsql_init(void);
+int kore_pgsql_query_init(struct kore_pgsql *, struct http_request *,
+ const char *, int);
void kore_pgsql_handle(void *, int);
void kore_pgsql_cleanup(struct kore_pgsql *);
void kore_pgsql_continue(struct http_request *, struct kore_pgsql *);
-int kore_pgsql_query(struct kore_pgsql *, struct http_request *,
- const char *);
-int kore_pgsql_query_params(struct kore_pgsql *, struct http_request *,
+int kore_pgsql_query(struct kore_pgsql *, const char *);
+int kore_pgsql_query_params(struct kore_pgsql *,
const char *, int, u_int8_t, ...);
-
+int kore_pgsql_register(const char *, const char *);
int kore_pgsql_ntuples(struct kore_pgsql *);
void kore_pgsql_logerror(struct kore_pgsql *);
void kore_pgsql_queue_remove(struct http_request *);
diff --git a/src/pgsql.c b/src/pgsql.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014 Joris Vink <joris@coders.se>
+ * Copyright (c) 2014-2015 Joris Vink <joris@coders.se>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -25,7 +25,6 @@
#include "pgsql.h"
struct pgsql_job {
- char *query;
struct http_request *req;
struct kore_pgsql *pgsql;
@@ -37,28 +36,30 @@ struct pgsql_wait {
TAILQ_ENTRY(pgsql_wait) list;
};
-#define PGSQL_IS_BLOCKING 0
-#define PGSQL_IS_ASYNC 1
-
#define PGSQL_CONN_MAX 2
#define PGSQL_CONN_FREE 0x01
+#define PGSQL_LIST_INSERTED 0x0100
static void pgsql_queue_wakeup(void);
-static int pgsql_conn_create(struct kore_pgsql *);
+static void pgsql_set_error(struct kore_pgsql *, const char *);
static void pgsql_queue_add(struct http_request *);
static void pgsql_conn_release(struct kore_pgsql *);
static void pgsql_conn_cleanup(struct pgsql_conn *);
-static void pgsql_read_result(struct kore_pgsql *, int);
-static void pgsql_schedule(struct kore_pgsql *, struct http_request *);
-static int pgsql_prepare(struct kore_pgsql *, struct http_request *,
- const char *);
+static void pgsql_read_result(struct kore_pgsql *);
+static void pgsql_schedule(struct kore_pgsql *);
+
+static struct pgsql_conn *pgsql_conn_create(struct kore_pgsql *,
+ struct pgsql_db *);
+static struct pgsql_conn *pgsql_conn_next(struct kore_pgsql *,
+ struct pgsql_db *,
+ struct http_request *);
static struct kore_pool pgsql_job_pool;
static struct kore_pool pgsql_wait_pool;
static TAILQ_HEAD(, pgsql_conn) pgsql_conn_free;
static TAILQ_HEAD(, pgsql_wait) pgsql_wait_queue;
+static LIST_HEAD(, pgsql_db) pgsql_db_conn_strings;
static u_int16_t pgsql_conn_count;
-char *pgsql_conn_string = NULL;
u_int16_t pgsql_conn_max = PGSQL_CONN_MAX;
void
@@ -67,6 +68,7 @@ kore_pgsql_init(void)
pgsql_conn_count = 0;
TAILQ_INIT(&pgsql_conn_free);
TAILQ_INIT(&pgsql_wait_queue);
+ LIST_INIT(&pgsql_db_conn_strings);
kore_pool_init(&pgsql_job_pool, "pgsql_job_pool",
sizeof(struct pgsql_job), 100);
@@ -75,32 +77,91 @@ kore_pgsql_init(void)
}
int
-kore_pgsql_query(struct kore_pgsql *pgsql, struct http_request *req,
- const char *query)
+kore_pgsql_query_init(struct kore_pgsql *pgsql, struct http_request *req,
+ const char *dbname, int flags)
{
- if (!pgsql_prepare(pgsql, req, query))
+ struct pgsql_db *db;
+
+ memset(pgsql, 0, sizeof(*pgsql));
+ pgsql->flags = flags;
+ pgsql->state = KORE_PGSQL_STATE_INIT;
+
+ if ((req == NULL && (flags & KORE_PGSQL_ASYNC)) ||
+ ((flags & KORE_PGSQL_ASYNC) && (flags & KORE_PGSQL_SYNC))) {
+ pgsql_set_error(pgsql, "invalid query init parameters");
return (KORE_RESULT_ERROR);
+ }
+
+ db = NULL;
+ LIST_FOREACH(db, &pgsql_db_conn_strings, rlist) {
+ if (!strcmp(db->name, dbname))
+ break;
+ }
+
+ if (db == NULL) {
+ pgsql_set_error(pgsql, "no database found");
+ return (KORE_RESULT_ERROR);
+ }
- if (!PQsendQuery(pgsql->conn->db, query)) {
- pgsql_conn_cleanup(pgsql->conn);
+ if ((pgsql->conn = pgsql_conn_next(pgsql, db, req)) == NULL)
+ return (KORE_RESULT_ERROR);
+
+ if (pgsql->flags & KORE_PGSQL_ASYNC) {
+ pgsql->conn->job = kore_pool_get(&pgsql_job_pool);
+ pgsql->conn->job->req = req;
+ pgsql->conn->job->pgsql = pgsql;
+
+ http_request_sleep(req);
+ pgsql->flags |= PGSQL_LIST_INSERTED;
+ LIST_INSERT_HEAD(&(req->pgsqls), pgsql, rlist);
+ }
+
+ return (KORE_RESULT_OK);
+}
+
+int
+kore_pgsql_query(struct kore_pgsql *pgsql, const char *query)
+{
+ if (pgsql->conn == NULL) {
+ pgsql_set_error(pgsql, "no connection was set before query");
return (KORE_RESULT_ERROR);
}
- pgsql_schedule(pgsql, req);
+ if (pgsql->flags & KORE_PGSQL_SYNC) {
+ pgsql->result = PQexec(pgsql->conn->db, query);
+
+ if ((PQresultStatus(pgsql->result) != PGRES_TUPLES_OK) &&
+ (PQresultStatus(pgsql->result) != PGRES_COMMAND_OK)) {
+ pgsql_set_error(pgsql, PQerrorMessage(pgsql->conn->db));
+ return (KORE_RESULT_ERROR);
+ }
+
+ pgsql->state = KORE_PGSQL_STATE_DONE;
+ } else {
+ if (!PQsendQuery(pgsql->conn->db, query)) {
+ pgsql_set_error(pgsql, PQerrorMessage(pgsql->conn->db));
+ return (KORE_RESULT_ERROR);
+ }
+
+ pgsql_schedule(pgsql);
+ }
+
return (KORE_RESULT_OK);
}
int
-kore_pgsql_query_params(struct kore_pgsql *pgsql, struct http_request *req,
+kore_pgsql_query_params(struct kore_pgsql *pgsql,
const char *query, int result, u_int8_t count, ...)
{
u_int8_t i;
va_list args;
char **values;
- int *lengths, *formats;
+ int *lengths, *formats, ret;
- if (!pgsql_prepare(pgsql, req, query))
+ if (pgsql->conn == NULL) {
+ pgsql_set_error(pgsql, "no connection was set before query");
return (KORE_RESULT_ERROR);
+ }
if (count > 0) {
va_start(args, count);
@@ -120,20 +181,55 @@ kore_pgsql_query_params(struct kore_pgsql *pgsql, struct http_request *req,
values = NULL;
}
- if (!PQsendQueryParams(pgsql->conn->db, query, count, NULL,
- (const char * const *)values, lengths, formats, result)) {
- kore_mem_free(values);
- kore_mem_free(lengths);
- kore_mem_free(formats);
- pgsql_conn_cleanup(pgsql->conn);
- return (KORE_RESULT_ERROR);
+ ret = KORE_RESULT_ERROR;
+
+ if (pgsql->flags & KORE_PGSQL_SYNC) {
+ pgsql->result = PQexecParams(pgsql->conn->db, query, count,
+ NULL, (const char * const *)values, lengths, formats,
+ result);
+
+ if ((PQresultStatus(pgsql->result) != PGRES_TUPLES_OK) &&
+ (PQresultStatus(pgsql->result) != PGRES_COMMAND_OK)) {
+ pgsql_set_error(pgsql, PQerrorMessage(pgsql->conn->db));
+ goto cleanup;
+ }
+
+ pgsql->state = KORE_PGSQL_STATE_DONE;
+ } else {
+ if (!PQsendQueryParams(pgsql->conn->db, query, count, NULL,
+ (const char * const *)values, lengths, formats, result)) {
+ pgsql_set_error(pgsql, PQerrorMessage(pgsql->conn->db));
+ goto cleanup;
+ }
+
+ pgsql_schedule(pgsql);
}
+ ret = KORE_RESULT_OK;
+
+cleanup:
kore_mem_free(values);
kore_mem_free(lengths);
kore_mem_free(formats);
- pgsql_schedule(pgsql, req);
+ return (ret);
+}
+
+int
+kore_pgsql_register(const char *dbname, const char *connstring)
+{
+ struct pgsql_db *pgsqldb;
+
+ LIST_FOREACH(pgsqldb, &pgsql_db_conn_strings, rlist) {
+ if (!strcmp(pgsqldb->name, dbname))
+ return (KORE_RESULT_ERROR);
+ }
+
+ pgsqldb = kore_malloc(sizeof(*pgsqldb));
+ pgsqldb->name = kore_strdup(dbname);
+ pgsqldb->conn_string = kore_strdup(connstring);
+ LIST_INSERT_HEAD(&pgsql_db_conn_strings, pgsqldb, rlist);
+
return (KORE_RESULT_OK);
}
@@ -157,7 +253,7 @@ kore_pgsql_handle(void *c, int err)
pgsql->state = KORE_PGSQL_STATE_ERROR;
pgsql->error = kore_strdup(PQerrorMessage(conn->db));
} else {
- pgsql_read_result(pgsql, PGSQL_IS_ASYNC);
+ pgsql_read_result(pgsql);
}
if (pgsql->state == KORE_PGSQL_STATE_WAIT) {
@@ -218,7 +314,10 @@ kore_pgsql_cleanup(struct kore_pgsql *pgsql)
pgsql->error = NULL;
pgsql->conn = NULL;
- LIST_REMOVE(pgsql, rlist);
+ if (pgsql->flags & PGSQL_LIST_INSERTED) {
+ LIST_REMOVE(pgsql, rlist);
+ pgsql->flags &= ~PGSQL_LIST_INSERTED;
+ }
}
void
@@ -262,47 +361,55 @@ kore_pgsql_queue_remove(struct http_request *req)
}
}
-static int
-pgsql_prepare(struct kore_pgsql *pgsql, struct http_request *req,
- const char *query)
+static struct pgsql_conn *
+pgsql_conn_next(struct kore_pgsql *pgsql, struct pgsql_db *db,
+ struct http_request *req)
{
struct pgsql_conn *conn;
- pgsql->state = KORE_PGSQL_STATE_INIT;
- pgsql->result = NULL;
- pgsql->error = NULL;
- pgsql->conn = NULL;
+ conn = NULL;
- if (TAILQ_EMPTY(&pgsql_conn_free)) {
+ TAILQ_FOREACH(conn, &pgsql_conn_free, list) {
+ if (!(conn->flags & PGSQL_CONN_FREE))
+ fatal("got a pgsql connection that was not free?");
+ if (!strcmp(conn->name, db->name))
+ break;
+ }
+
+ if (conn == NULL) {
if (pgsql_conn_count >= pgsql_conn_max) {
- pgsql_queue_add(req);
- return (KORE_RESULT_ERROR);
+ if (pgsql->flags & KORE_PGSQL_ASYNC) {
+ pgsql_queue_add(req);
+ } else {
+ pgsql_set_error(pgsql,
+ "no available connection");
+ }
+
+ return (NULL);
}
- if (!pgsql_conn_create(pgsql))
- return (KORE_RESULT_ERROR);
+ if ((conn = pgsql_conn_create(pgsql, db)) == NULL)
+ return (NULL);
}
- http_request_sleep(req);
- conn = TAILQ_FIRST(&pgsql_conn_free);
- if (!(conn->flags & PGSQL_CONN_FREE))
- fatal("received a pgsql conn that was not free?");
-
conn->flags &= ~PGSQL_CONN_FREE;
TAILQ_REMOVE(&pgsql_conn_free, conn, list);
- pgsql->conn = conn;
- conn->job = kore_pool_get(&pgsql_job_pool);
- conn->job->query = kore_strdup(query);
- conn->job->pgsql = pgsql;
- conn->job->req = req;
+ return (conn);
+}
- LIST_INSERT_HEAD(&(req->pgsqls), pgsql, rlist);
- return (KORE_RESULT_OK);
+static void
+pgsql_set_error(struct kore_pgsql *pgsql, const char *msg)
+{
+ if (pgsql->error != NULL)
+ kore_mem_free(pgsql->error);
+
+ pgsql->error = kore_strdup(msg);
+ pgsql->state = KORE_PGSQL_STATE_ERROR;
}
static void
-pgsql_schedule(struct kore_pgsql *pgsql, struct http_request *req)
+pgsql_schedule(struct kore_pgsql *pgsql)
{
int fd;
@@ -347,33 +454,32 @@ pgsql_queue_wakeup(void)
}
}
-static int
-pgsql_conn_create(struct kore_pgsql *pgsql)
+static struct pgsql_conn *
+pgsql_conn_create(struct kore_pgsql *pgsql, struct pgsql_db *db)
{
struct pgsql_conn *conn;
- if (pgsql_conn_string == NULL)
+ if (db == NULL || db->conn_string == NULL)
fatal("pgsql_conn_create: no connection string");
pgsql_conn_count++;
conn = kore_malloc(sizeof(*conn));
kore_debug("pgsql_conn_create(): %p", conn);
- memset(conn, 0, sizeof(*conn));
- conn->db = PQconnectdb(pgsql_conn_string);
+ conn->db = PQconnectdb(db->conn_string);
if (conn->db == NULL || (PQstatus(conn->db) != CONNECTION_OK)) {
- pgsql->state = KORE_PGSQL_STATE_ERROR;
- pgsql->error = kore_strdup(PQerrorMessage(conn->db));
+ pgsql_set_error(pgsql, PQerrorMessage(conn->db));
pgsql_conn_cleanup(conn);
- return (KORE_RESULT_ERROR);
+ return (NULL);
}
conn->job = NULL;
conn->flags = PGSQL_CONN_FREE;
conn->type = KORE_TYPE_PGSQL_CONN;
+ conn->name = kore_strdup(db->name);
TAILQ_INSERT_TAIL(&pgsql_conn_free, conn, list);
- return (KORE_RESULT_OK);
+ return (conn);
}
static void
@@ -384,8 +490,14 @@ pgsql_conn_release(struct kore_pgsql *pgsql)
if (pgsql->conn == NULL)
return;
- kore_mem_free(pgsql->conn->job->query);
- kore_pool_put(&pgsql_job_pool, pgsql->conn->job);
+ /* Async query cleanup */
+ if (pgsql->flags & KORE_PGSQL_ASYNC) {
+ if (pgsql->conn != NULL) {
+ fd = PQsocket(pgsql->conn->db);
+ kore_platform_disable_read(fd);
+ kore_pool_put(&pgsql_job_pool, pgsql->conn->job);
+ }
+ }
/* Drain just in case. */
while (PQgetResult(pgsql->conn->db) != NULL)
@@ -395,9 +507,6 @@ pgsql_conn_release(struct kore_pgsql *pgsql)
pgsql->conn->flags |= PGSQL_CONN_FREE;
TAILQ_INSERT_TAIL(&pgsql_conn_free, pgsql->conn, list);
- fd = PQsocket(pgsql->conn->db);
- kore_platform_disable_read(fd);
-
pgsql->conn = NULL;
pgsql->state = KORE_PGSQL_STATE_COMPLETE;
@@ -421,10 +530,8 @@ pgsql_conn_cleanup(struct pgsql_conn *conn)
http_request_wakeup(req);
pgsql->conn = NULL;
- pgsql->state = KORE_PGSQL_STATE_ERROR;
- pgsql->error = kore_strdup(PQerrorMessage(conn->db));
+ pgsql_set_error(pgsql, PQerrorMessage(conn->db));
- kore_mem_free(conn->job->query);
kore_pool_put(&pgsql_job_pool, conn->job);
conn->job = NULL;
}
@@ -433,17 +540,16 @@ pgsql_conn_cleanup(struct pgsql_conn *conn)
PQfinish(conn->db);
pgsql_conn_count--;
+ kore_mem_free(conn->name);
kore_mem_free(conn);
}
static void
-pgsql_read_result(struct kore_pgsql *pgsql, int async)
+pgsql_read_result(struct kore_pgsql *pgsql)
{
- if (async) {
- if (PQisBusy(pgsql->conn->db)) {
- pgsql->state = KORE_PGSQL_STATE_WAIT;
- return;
- }
+ if (PQisBusy(pgsql->conn->db)) {
+ pgsql->state = KORE_PGSQL_STATE_WAIT;
+ return;
}
pgsql->result = PQgetResult(pgsql->conn->db);
@@ -470,8 +576,7 @@ pgsql_read_result(struct kore_pgsql *pgsql, int async)
case PGRES_EMPTY_QUERY:
case PGRES_BAD_RESPONSE:
case PGRES_FATAL_ERROR:
- pgsql->state = KORE_PGSQL_STATE_ERROR;
- pgsql->error = kore_strdup(PQresultErrorMessage(pgsql->result));
+ pgsql_set_error(pgsql, PQresultErrorMessage(pgsql->result));
break;
}
}