dlz_postgres_driver.c [plain text]
#ifdef DLZ_POSTGRES
#include <config.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dns/log.h>
#include <dns/sdlz.h>
#include <dns/result.h>
#include <isc/mem.h>
#include <isc/platform.h>
#include <isc/print.h>
#include <isc/result.h>
#include <isc/string.h>
#include <isc/util.h>
#include <named/globals.h>
#include <dlz/sdlz_helper.h>
#include <dlz/dlz_postgres_driver.h>
#include <time.h>
#include <libpq-fe.h>
static dns_sdlzimplementation_t *dlz_postgres = NULL;
#define dbc_search_limit 30
#define ALLNODES 1
#define ALLOWXFR 2
#define AUTHORITY 3
#define FINDZONE 4
#define LOOKUP 5
static size_t
postgres_makesafe(char *to, const char *from, size_t length)
{
const char *source = from;
char *target = to;
unsigned int remaining = length;
while (remaining > 0)
{
switch (*source)
{
case '\\':
*target = '\\';
target++;
*target = '\\';
break;
case '\'':
*target = '\'';
target++;
*target = '\'';
break;
default:
*target = *source;
}
source++;
target++;
remaining--;
}
*target = '\0';
return target - to;
}
#ifdef ISC_PLATFORM_USETHREADS
static void
postgres_destroy_dblist(db_list_t *dblist)
{
dbinstance_t *ndbi = NULL;
dbinstance_t *dbi = NULL;
ndbi = ISC_LIST_HEAD(*dblist);
while (ndbi != NULL) {
dbi = ndbi;
ndbi = ISC_LIST_NEXT(dbi, link);
if (dbi->dbconn != NULL)
PQfinish((PGconn *) dbi->dbconn);
destroy_sqldbinstance(dbi);
}
isc_mem_put(ns_g_mctx, dblist, sizeof(db_list_t));
}
static dbinstance_t *
postgres_find_avail_conn(db_list_t *dblist)
{
dbinstance_t *dbi = NULL;
dbinstance_t *head;
int count = 0;
head = dbi = ISC_LIST_HEAD(*dblist);
while (count < dbc_search_limit) {
if (isc_mutex_trylock(&dbi->instance_lock) == ISC_R_SUCCESS)
return dbi;
dbi = ISC_LIST_NEXT(dbi, link);
if (dbi == NULL) {
count++;
dbi = head;
}
}
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_DLZ, ISC_LOG_INFO,
"Postgres driver unable to find available connection "
"after searching %d times",
count);
return NULL;
}
#endif
static char *
postgres_escape_string(const char *instr) {
char *outstr;
unsigned int len;
if (instr == NULL)
return NULL;
len = strlen(instr);
outstr = isc_mem_allocate(ns_g_mctx ,(2 * len * sizeof(char)) + 1);
if (outstr == NULL)
return NULL;
postgres_makesafe(outstr, instr, len);
return outstr;
}
static isc_result_t
postgres_get_resultset(const char *zone, const char *record,
const char *client, unsigned int query,
void *dbdata, PGresult **rs)
{
isc_result_t result;
dbinstance_t *dbi = NULL;
char *querystring = NULL;
unsigned int i = 0;
unsigned int j = 0;
unsigned int dlz_thread_num = 1+(int) (1000.0*rand()/(RAND_MAX+1.0));
REQUIRE(*rs == NULL);
#if 0
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
"%d Getting DBI", dlz_thread_num);
#endif
#ifdef ISC_PLATFORM_USETHREADS
dbi = postgres_find_avail_conn((db_list_t *) dbdata);
#else
dbi = (dbinstance_t *) dbdata;
#endif
#if 0
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
"%d Got DBI - checking query", dlz_thread_num);
#endif
if (dbi == NULL) {
result = ISC_R_FAILURE;
goto cleanup;
}
switch(query) {
case ALLNODES:
if (dbi->allnodes_q == NULL) {
result = ISC_R_NOTIMPLEMENTED;
goto cleanup;
}
break;
case ALLOWXFR:
if (dbi->allowxfr_q == NULL) {
result = ISC_R_NOTIMPLEMENTED;
goto cleanup;
}
break;
case AUTHORITY:
if (dbi->authority_q == NULL) {
result = ISC_R_NOTIMPLEMENTED;
goto cleanup;
}
break;
case FINDZONE:
if (dbi->findzone_q == NULL) {
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
"No query specified for findzone. "
"Findzone requires a query");
result = ISC_R_FAILURE;
goto cleanup;
}
break;
case LOOKUP:
if (dbi->lookup_q == NULL) {
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
"No query specified for lookup. "
"Lookup requires a query");
result = ISC_R_FAILURE;
goto cleanup;
}
break;
default:
UNEXPECTED_ERROR(__FILE__, __LINE__,
"Incorrect query flag passed to "
"postgres_get_resultset");
result = ISC_R_UNEXPECTED;
goto cleanup;
}
#if 0
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
"%d checked query", dlz_thread_num);
#endif
if (zone != NULL) {
dbi->zone = postgres_escape_string(zone);
if (dbi->zone == NULL) {
result = ISC_R_NOMEMORY;
goto cleanup;
}
} else {
dbi->zone = NULL;
}
#if 0
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
"%d did zone", dlz_thread_num);
#endif
if (record != NULL) {
dbi->record = postgres_escape_string(record);
if (dbi->record == NULL) {
result = ISC_R_NOMEMORY;
goto cleanup;
}
} else {
dbi->record = NULL;
}
#if 0
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
"%d did record", dlz_thread_num);
#endif
if (client != NULL) {
dbi->client = postgres_escape_string(client);
if (dbi->client == NULL) {
result = ISC_R_NOMEMORY;
goto cleanup;
}
} else {
dbi->client = NULL;
}
#if 0
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
"%d did client", dlz_thread_num);
#endif
switch(query) {
case ALLNODES:
querystring = build_querystring(ns_g_mctx, dbi->allnodes_q);
break;
case ALLOWXFR:
querystring = build_querystring(ns_g_mctx, dbi->allowxfr_q);
break;
case AUTHORITY:
querystring = build_querystring(ns_g_mctx, dbi->authority_q);
break;
case FINDZONE:
querystring = build_querystring(ns_g_mctx, dbi->findzone_q);
break;
case LOOKUP:
querystring = build_querystring(ns_g_mctx, dbi->lookup_q);
break;
default:
UNEXPECTED_ERROR(__FILE__, __LINE__,
"Incorrect query flag passed to "
"postgres_get_resultset");
result = ISC_R_UNEXPECTED;
goto cleanup;
}
#if 0
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
"%d built query", dlz_thread_num);
#endif
if (querystring == NULL) {
result = ISC_R_NOMEMORY;
goto cleanup;
}
#if 0
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
"%d query is '%s'", dlz_thread_num, querystring);
#endif
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1),
"\nQuery String: %s\n", querystring);
for (j=0; j < 3; j++) {
#if 0
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
"%d executing query for %d time",
dlz_thread_num, j);
#endif
*rs = PQexec((PGconn *)dbi->dbconn, querystring );
result = ISC_R_SUCCESS;
for (i=0; *rs == NULL && i < 3; i++) {
#if 0
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
"%d resetting connection",
dlz_thread_num);
#endif
result = ISC_R_FAILURE;
PQreset((PGconn *) dbi->dbconn);
if (PQstatus((PGconn *) dbi->dbconn) == CONNECTION_OK)
break;
}
if (PQresultStatus(*rs) == PGRES_TUPLES_OK) {
#if 0
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
"%d rs ok", dlz_thread_num);
#endif
break;
} else {
#if 0
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
"%d clearing rs", dlz_thread_num);
#endif
PQclear(*rs);
result = ISC_R_FAILURE;
}
}
cleanup:
#if 0
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
"%d cleaning up", dlz_thread_num);
#endif
if (dbi == NULL)
return ISC_R_FAILURE;
if (dbi->zone != NULL)
isc_mem_free(ns_g_mctx, dbi->zone);
if (dbi->record != NULL)
isc_mem_free(ns_g_mctx, dbi->record);
if (dbi->client != NULL)
isc_mem_free(ns_g_mctx, dbi->client);
#ifdef ISC_PLATFORM_USETHREADS
#if 0
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
"%d unlocking mutex", dlz_thread_num);
#endif
isc_mutex_unlock(&dbi->instance_lock);
#endif
if (querystring != NULL)
isc_mem_free(ns_g_mctx, querystring );
#if 0
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
"%d returning", dlz_thread_num);
#endif
return result;
}
static isc_result_t
postgres_process_rs(dns_sdlzlookup_t *lookup, PGresult *rs)
{
isc_result_t result;
unsigned int i;
unsigned int rows;
unsigned int fields;
unsigned int j;
unsigned int len;
char *tmpString;
char *endp;
int ttl;
rows = PQntuples(rs);
fields = PQnfields(rs);
for (i=0; i < rows; i++) {
switch(fields) {
case 1:
result = dns_sdlz_putrr(lookup, "a", 86400,
PQgetvalue(rs, i, 0));
break;
case 2:
result = dns_sdlz_putrr(lookup, PQgetvalue(rs, i, 0),
86400, PQgetvalue(rs, i, 1));
break;
case 3:
ttl = strtol(PQgetvalue(rs, i, 0), &endp, 10);
if (*endp != '\0' || ttl < 0) {
isc_log_write(dns_lctx,
DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
"Postgres driver ttl must be "
"a positive number");
}
result = dns_sdlz_putrr(lookup, PQgetvalue(rs, i, 1),
ttl, PQgetvalue(rs, i, 2));
break;
default:
for (j=2, len=0; j < fields; j++) {
len += strlen(PQgetvalue(rs, i, j)) + 1;
}
tmpString = isc_mem_allocate(ns_g_mctx, len + 1);
if (tmpString == NULL) {
isc_log_write(dns_lctx,
DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
"Postgres driver unable to "
"allocate memory for "
"temporary string");
PQclear(rs);
return (ISC_R_FAILURE);
}
strcpy(tmpString, PQgetvalue(rs, i, 2));
for (j=3; j < fields; j++) {
strcat(tmpString, " ");
strcat(tmpString, PQgetvalue(rs, i, j));
}
ttl = strtol(PQgetvalue(rs, i, 0), &endp, 10);
if (*endp != '\0' || ttl < 0) {
isc_log_write(dns_lctx,
DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
"Postgres driver ttl must be "
"a postive number");
}
result = dns_sdlz_putrr(lookup, PQgetvalue(rs, i, 1),
ttl, tmpString);
isc_mem_free(ns_g_mctx, tmpString);
}
if (result != ISC_R_SUCCESS) {
PQclear(rs);
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
"dns_sdlz_putrr returned error. "
"Error code was: %s",
isc_result_totext(result));
return (ISC_R_FAILURE);
}
}
PQclear(rs);
if (rows > 0)
return (ISC_R_SUCCESS);
return (ISC_R_NOTFOUND);
}
static isc_result_t
postgres_findzone(void *driverarg, void *dbdata, const char *name)
{
isc_result_t result;
PGresult *rs = NULL;
unsigned int rows;
UNUSED(driverarg);
result = postgres_get_resultset(name, NULL, NULL,
FINDZONE, dbdata, &rs);
if (result != ISC_R_SUCCESS) {
if (rs != NULL)
PQclear(rs);
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
"Postgres driver unable to return "
"result set for findzone query");
return (ISC_R_FAILURE);
}
rows = PQntuples(rs);
PQclear(rs);
if (rows > 0)
return (ISC_R_SUCCESS);
return (ISC_R_NOTFOUND);
}
static isc_result_t
postgres_allowzonexfr(void *driverarg, void *dbdata, const char *name,
const char *client)
{
isc_result_t result;
PGresult *rs = NULL;
unsigned int rows;
UNUSED(driverarg);
result = postgres_findzone(driverarg, dbdata, name);
if (result != ISC_R_SUCCESS)
return (ISC_R_NOTFOUND);
result = postgres_get_resultset(name, NULL, client,
ALLOWXFR, dbdata, &rs);
if (result == ISC_R_NOTIMPLEMENTED)
return result;
if (result != ISC_R_SUCCESS) {
if (rs != NULL)
PQclear(rs);
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
"Postgres driver unable to return "
"result set for allow xfr query");
return (ISC_R_FAILURE);
}
rows = PQntuples(rs);
PQclear(rs);
if (rows > 0)
return (ISC_R_SUCCESS);
return (ISC_R_NOPERM);
}
static isc_result_t
postgres_allnodes(const char *zone, void *driverarg, void *dbdata,
dns_sdlzallnodes_t *allnodes)
{
isc_result_t result;
PGresult *rs = NULL;
unsigned int i;
unsigned int rows;
unsigned int fields;
unsigned int j;
unsigned int len;
char *tmpString;
char *endp;
int ttl;
UNUSED(driverarg);
result = postgres_get_resultset(zone, NULL, NULL,
ALLNODES, dbdata, &rs);
if (result == ISC_R_NOTIMPLEMENTED)
return result;
if (result != ISC_R_SUCCESS) {
if (rs != NULL)
PQclear(rs);
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
"Postgres driver unable to return "
"result set for all nodes query");
return (ISC_R_FAILURE);
}
rows = PQntuples(rs);
fields = PQnfields(rs);
for (i=0; i < rows; i++) {
if (fields < 4) {
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
"Postgres driver too few fields "
"returned by all nodes query");
}
ttl = strtol(PQgetvalue(rs, i, 0), &endp, 10);
if (*endp != '\0' || ttl < 0) {
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
"Postgres driver ttl must be "
"a postive number");
}
if (fields == 4) {
result = dns_sdlz_putnamedrr(allnodes,
PQgetvalue(rs, i, 2),
PQgetvalue(rs, i, 1),
ttl,
PQgetvalue(rs, i, 3));
} else {
for (j=3, len=0; j < fields; j++) {
len += strlen(PQgetvalue(rs, i, j)) + 1;
}
tmpString = isc_mem_allocate(ns_g_mctx, len + 1);
if (tmpString == NULL) {
isc_log_write(dns_lctx,
DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
"Postgres driver unable to "
"allocate memory for "
"temporary string");
PQclear(rs);
return (ISC_R_FAILURE);
}
strcpy(tmpString, PQgetvalue(rs, i, 3));
for (j=4; j < fields; j++) {
strcat(tmpString, " ");
strcat(tmpString, PQgetvalue(rs, i, j));
}
result = dns_sdlz_putnamedrr(allnodes,
PQgetvalue(rs, i, 2),
PQgetvalue(rs, i, 1),
ttl, tmpString);
isc_mem_free(ns_g_mctx, tmpString);
}
if (result != ISC_R_SUCCESS) {
PQclear(rs);
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
"dns_sdlz_putnamedrr returned error. "
"Error code was: %s",
isc_result_totext(result));
return (ISC_R_FAILURE);
}
}
PQclear(rs);
if (rows > 0)
return (ISC_R_SUCCESS);
return (ISC_R_NOTFOUND);
}
static isc_result_t
postgres_authority(const char *zone, void *driverarg, void *dbdata,
dns_sdlzlookup_t *lookup)
{
isc_result_t result;
PGresult *rs = NULL;
UNUSED(driverarg);
result = postgres_get_resultset(zone, NULL, NULL,
AUTHORITY, dbdata, &rs);
if (result == ISC_R_NOTIMPLEMENTED)
return result;
if (result != ISC_R_SUCCESS) {
if (rs != NULL)
PQclear(rs);
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
"Postgres driver unable to return "
"result set for authority query");
return (ISC_R_FAILURE);
}
return postgres_process_rs(lookup, rs);
}
static isc_result_t
postgres_lookup(const char *zone, const char *name, void *driverarg,
void *dbdata, dns_sdlzlookup_t *lookup)
{
isc_result_t result;
PGresult *rs = NULL;
UNUSED(driverarg);
result = postgres_get_resultset(zone, name, NULL, LOOKUP, dbdata, &rs);
if (result != ISC_R_SUCCESS) {
if (rs != NULL)
PQclear(rs);
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
"Postgres driver unable to "
"return result set for lookup query");
return (ISC_R_FAILURE);
}
return postgres_process_rs(lookup, rs);
}
static isc_result_t
postgres_create(const char *dlzname, unsigned int argc, char *argv[],
void *driverarg, void **dbdata)
{
isc_result_t result;
dbinstance_t *dbi = NULL;
unsigned int j;
#ifdef ISC_PLATFORM_USETHREADS
int dbcount;
db_list_t *dblist = NULL;
int i;
char *endp;
#endif
UNUSED(driverarg);
UNUSED(dlzname);
srand( (unsigned)time( NULL ) );
#ifdef ISC_PLATFORM_USETHREADS
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1),
"Postgres driver running multithreaded");
#else
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1),
"Postgres driver running single threaded");
#endif
if (argc < 5) {
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
"Postgres driver requires at least "
"4 command line args.");
return (ISC_R_FAILURE);
}
if (argc > 8) {
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
"Postgres driver cannot accept more than "
"7 command line args.");
return (ISC_R_FAILURE);
}
#ifdef ISC_PLATFORM_USETHREADS
dbcount = strtol(argv[1], &endp, 10);
if (*endp != '\0' || dbcount < 0) {
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
"Postgres driver database connection count "
"must be positive.");
return (ISC_R_FAILURE);
}
dblist = isc_mem_get(ns_g_mctx, sizeof(db_list_t));
if (dblist == NULL)
return (ISC_R_NOMEMORY);
ISC_LIST_INIT(*dblist);
for (i=0; i < dbcount; i++) {
#endif
switch(argc) {
case 5:
result = build_sqldbinstance(ns_g_mctx, NULL, NULL,
NULL, argv[3], argv[4],
NULL, &dbi);
break;
case 6:
result = build_sqldbinstance(ns_g_mctx, NULL, NULL,
argv[5], argv[3], argv[4],
NULL, &dbi);
break;
case 7:
result = build_sqldbinstance(ns_g_mctx, argv[6], NULL,
argv[5], argv[3], argv[4],
NULL, &dbi);
break;
case 8:
result = build_sqldbinstance(ns_g_mctx, argv[6],
argv[7], argv[5], argv[3],
argv[4], NULL, &dbi);
break;
default:
result = ISC_R_FAILURE;
}
if (result == ISC_R_SUCCESS) {
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
"Postgres driver created database "
"instance object.");
} else {
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
"Postgres driver could not create "
"database instance object.");
goto cleanup;
}
#ifdef ISC_PLATFORM_USETHREADS
ISC_LINK_INIT(dbi, link);
ISC_LIST_APPEND(*dblist, dbi, link);
#endif
dbi->dbconn = PQconnectdb(argv[2]);
if (dbi->dbconn == NULL) {
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
"Postgres driver could not allocate "
"memory for database connection");
goto cleanup;
}
for (j = 0;
PQstatus((PGconn *) dbi->dbconn) != CONNECTION_OK &&
j < 3;
j++)
PQreset((PGconn *) dbi->dbconn);
#ifdef ISC_PLATFORM_USETHREADS
if (PQstatus((PGconn *) dbi->dbconn) != CONNECTION_OK) {
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
"Postgres driver failed to create "
"database connection number %u "
"after 4 attempts",
i + 1);
goto cleanup;
}
dbi = NULL;
}
*dbdata = dblist;
#else
if (PQstatus((PGconn *) dbi->dbconn) != CONNECTION_OK) {
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
"Postgres driver failed to create database "
"connection after 4 attempts");
goto cleanup;
}
*dbdata = dbi;
#endif
return(ISC_R_SUCCESS);
cleanup:
#ifdef ISC_PLATFORM_USETHREADS
postgres_destroy_dblist(dblist);
#else
if (dbi != NULL)
destroy_sqldbinstance(dbi);
#endif
return(ISC_R_FAILURE);
}
static void
postgres_destroy(void *driverarg, void *dbdata)
{
#ifdef ISC_PLATFORM_USETHREADS
UNUSED(driverarg);
postgres_destroy_dblist((db_list_t *) dbdata);
#else
dbinstance_t *dbi;
UNUSED(driverarg);
dbi = (dbinstance_t *) dbdata;
if (dbi->dbconn != NULL)
PQfinish((PGconn *) dbi->dbconn);
destroy_sqldbinstance(dbi);
#endif
}
static dns_sdlzmethods_t dlz_postgres_methods = {
postgres_create,
postgres_destroy,
postgres_findzone,
postgres_lookup,
postgres_authority,
postgres_allnodes,
postgres_allowzonexfr,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
};
isc_result_t
dlz_postgres_init(void) {
isc_result_t result;
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
"Registering DLZ postgres driver.");
result = dns_sdlzregister("postgres", &dlz_postgres_methods, NULL,
DNS_SDLZFLAG_RELATIVEOWNER |
DNS_SDLZFLAG_RELATIVERDATA |
DNS_SDLZFLAG_THREADSAFE,
ns_g_mctx, &dlz_postgres);
if (result != ISC_R_SUCCESS) {
UNEXPECTED_ERROR(__FILE__, __LINE__,
"dns_sdlzregister() failed: %s",
isc_result_totext(result));
result = ISC_R_UNEXPECTED;
}
return result;
}
void
dlz_postgres_clear(void) {
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
"Unregistering DLZ postgres driver.");
if (dlz_postgres != NULL)
dns_sdlzunregister(&dlz_postgres);
}
#endif