struct sql_result api;
PGresult *pgres;
+ char *query;
unsigned int rownum, rows;
unsigned int fields_count;
const char **fields;
sql_query_callback_t *callback;
void *context;
+
+ unsigned int retry_query:1;
};
struct pgsql_queue {
extern struct sql_db driver_pgsql_db;
extern struct sql_result driver_pgsql_result;
+static void
+driver_pgsql_query_full(struct sql_db *db, const char *query,
+ sql_query_callback_t *callback, void *context,
+ bool retry_query);
static void queue_send_next(struct pgsql_db *db);
static void result_finish(struct pgsql_result *result);
i_free(result->fields);
i_free(result->values);
+ i_free(result->query);
i_free(result);
if (db->queue != NULL && !db->querying && db->connected)
static void result_finish(struct pgsql_result *result)
{
struct pgsql_db *db = (struct pgsql_db *)result->api.db;
- bool free_result = TRUE;
-
- if (result->callback != NULL) {
+ bool free_result = TRUE, retry = FALSE;
+ bool disconnected;
+
+ disconnected = PQstatus(db->pg) == CONNECTION_BAD;
+ if (disconnected && result->pgres == NULL && result->retry_query) {
+ /* retry the query */
+ i_error("pgsql: Query failed, retrying: %s", last_error(db));
+ retry = TRUE;
+ } else if (result->callback != NULL) {
result->api.callback = TRUE;
T_BEGIN {
result->callback(&result->api, result->context);
result->api.callback = FALSE;
free_result = db->sync_result != &result->api;
}
- if (free_result)
- driver_pgsql_result_free(&result->api);
- if (PQstatus(db->pg) == CONNECTION_BAD) {
+ if (disconnected) {
/* disconnected */
driver_pgsql_close(db);
+
+ if (retry) {
+ /* retry the query */
+ driver_pgsql_query_full(&db->api, result->query,
+ result->callback,
+ result->context, FALSE);
+ }
}
+ if (free_result)
+ driver_pgsql_result_free(&result->api);
}
static void get_result(struct pgsql_result *result)
}
}
-static void exec_callback(struct sql_result *result,
+static void exec_callback(struct sql_result *_result,
void *context ATTR_UNUSED)
{
- struct pgsql_db *db = (struct pgsql_db *)result->db;
+ struct pgsql_db *db = (struct pgsql_db *)_result->db;
i_error("pgsql: sql_exec() failed: %s", last_error(db));
}
return to;
}
-static void driver_pgsql_exec(struct sql_db *db, const char *query)
+static void driver_pgsql_exec_full(struct sql_db *db, const char *query,
+ bool retry_query)
{
struct pgsql_result *result;
result->api = driver_pgsql_result;
result->api.db = db;
result->callback = exec_callback;
-
+ if (retry_query) {
+ result->query = i_strdup(query);
+ result->retry_query = TRUE;
+ }
do_query(result, query);
}
-static void driver_pgsql_query(struct sql_db *db, const char *query,
- sql_query_callback_t *callback, void *context)
+static void driver_pgsql_exec(struct sql_db *db, const char *query)
+{
+ driver_pgsql_exec_full(db, query, TRUE);
+}
+
+static void
+driver_pgsql_query_full(struct sql_db *db, const char *query,
+ sql_query_callback_t *callback, void *context,
+ bool retry_query)
{
struct pgsql_result *result;
result->api.db = db;
result->callback = callback;
result->context = context;
-
+ if (retry_query) {
+ result->query = i_strdup(query);
+ result->retry_query = TRUE;
+ }
do_query(result, query);
}
+static void driver_pgsql_query(struct sql_db *db, const char *query,
+ sql_query_callback_t *callback, void *context)
+{
+ driver_pgsql_query_full(db, query, callback, context, TRUE);
+}
+
static void pgsql_query_s_callback(struct sql_result *result, void *context)
{
struct pgsql_db *db = context;
ctx->callback = callback;
ctx->context = context;
- sql_query(_ctx->db, "COMMIT", transaction_commit_callback, ctx);
+ driver_pgsql_query_full(_ctx->db, "COMMIT",
+ transaction_commit_callback, ctx, FALSE);
}
static int
}
static void
-transaction_update_callback(struct sql_result *result,
- struct pgsql_transaction_context *ctx)
+transaction_update_callback(struct sql_result *result, void *context)
{
+ struct pgsql_transaction_context *ctx = context;
+
if (sql_result_next_row(result) < 0) {
ctx->failed = TRUE;
ctx->error = sql_result_get_error(result);
sql_query(_ctx->db, "BEGIN", transaction_update_callback, ctx);
}
- sql_query(_ctx->db, query, transaction_update_callback, ctx);
+ driver_pgsql_query_full(_ctx->db, query,
+ transaction_update_callback, ctx, FALSE);
}
struct sql_db driver_pgsql_db = {