static isc_result_t mysql_get_resultset(const char *zone, const char *record, const char *client, unsigned int query, void *dbdata, MYSQL_RES **rs) { isc_result_t result; dbinstance_t *dbi = NULL; char *querystring = NULL; unsigned int i = 0; unsigned int j = 0; int qres = 0; if (query != COUNTZONE) REQUIRE(*rs == NULL); else REQUIRE(rs == NULL); /* get db instance / connection */ dbi = (dbinstance_t *) dbdata; /* if DBI is null, can't do anything else */ if (dbi == NULL) { result = ISC_R_FAILURE; goto cleanup; } /* what type of query are we going to run? */ switch(query) { case ALLNODES: /* * if the query was not passed in from the config file * then we can't run it. return not_implemented, so * it's like the code for that operation was never * built into the driver.... AHHH flexibility!!! */ if (dbi->allnodes_q == NULL) { result = ISC_R_NOTIMPLEMENTED; goto cleanup; } break; case ALLOWXFR: /* same as comments as ALLNODES */ if (dbi->allowxfr_q == NULL) { result = ISC_R_NOTIMPLEMENTED; goto cleanup; } break; case AUTHORITY: /* same as comments as ALLNODES */ if (dbi->authority_q == NULL) { result = ISC_R_NOTIMPLEMENTED; goto cleanup; } break; case FINDZONE: /* this is required. It's the whole point of DLZ! */ 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 COUNTZONE: /* same as comments as ALLNODES */ if (dbi->countzone_q == NULL) { result = ISC_R_NOTIMPLEMENTED; goto cleanup; } break; case LOOKUP: /* this is required. It's also a major point of DLZ! */ 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: /* * this should never happen. If it does, the code is * screwed up! */ UNEXPECTED_ERROR(__FILE__, __LINE__, "Incorrect query flag passed to " "mysql_get_resultset"); result = ISC_R_UNEXPECTED; goto cleanup; } /* * was a zone string passed? If so, make it safe for use in * queries. */ if (zone != NULL) { dbi->zone = mysqldrv_escape_string((MYSQL *) dbi->dbconn, zone); if (dbi->zone == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } } else { /* no string passed, set the string pointer to NULL */ dbi->zone = NULL; } /* * was a record string passed? If so, make it safe for use in * queries. */ if (record != NULL) { dbi->record = mysqldrv_escape_string((MYSQL *) dbi->dbconn, record); if (dbi->record == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } } else { /* no string passed, set the string pointer to NULL */ dbi->record = NULL; } /* * was a client string passed? If so, make it safe for use in * queries. */ if (client != NULL) { dbi->client = mysqldrv_escape_string((MYSQL *) dbi->dbconn, client); if (dbi->client == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } } else { /* no string passed, set the string pointer to NULL */ dbi->client = NULL; } /* * what type of query are we going to run? this time we build * the actual query to run. */ 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 COUNTZONE: querystring = build_querystring(ns_g_mctx, dbi->countzone_q); break; case LOOKUP: querystring = build_querystring(ns_g_mctx, dbi->lookup_q); break; default: /* * this should never happen. If it does, the code is * screwed up! */ UNEXPECTED_ERROR(__FILE__, __LINE__, "Incorrect query flag passed to " "mysql_get_resultset"); result = ISC_R_UNEXPECTED; goto cleanup; } /* if the querystring is null, Bummer, outta RAM. UPGRADE TIME!!! */ if (querystring == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } /* * output the full query string during debug so we can see * what lame error the query has. */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1), "\nQuery String: %s\n", querystring); /* attempt query up to 3 times. */ for (i=0; i < 3; i++) { qres = mysql_query((MYSQL *) dbi->dbconn, querystring); if (qres == 0) break; for (j=0; mysql_ping((MYSQL *) dbi->dbconn) != 0 && j < 4; j++) ; } if (qres == 0) { result = ISC_R_SUCCESS; if (query != COUNTZONE) { *rs = mysql_store_result((MYSQL *) dbi->dbconn); if (*rs == NULL) result = ISC_R_FAILURE; } } else { result = ISC_R_FAILURE; } cleanup: /* it's always good to cleanup after yourself */ /* if we couldn't even get DBI, just return NULL */ if (dbi == NULL) return ISC_R_FAILURE; /* free dbi->zone string */ if (dbi->zone != NULL) isc_mem_free(ns_g_mctx, dbi->zone); /* free dbi->record string */ if (dbi->record != NULL) isc_mem_free(ns_g_mctx, dbi->record); /* free dbi->client string */ if (dbi->client != NULL) isc_mem_free(ns_g_mctx, dbi->client); /* release query string */ if (querystring != NULL) isc_mem_free(ns_g_mctx, querystring); /* return result */ return result; }
/*% * This function is the real core of the module. Zone, record * and client strings are passed in (or NULL is passed if the * string is not available). The type of query we want to run * is indicated by the query flag, and the dbdata object is passed * passed in to. dbdata really holds a single database instance. * The function will construct and run the query, hopefully getting * a result set. */ static isc_result_t mysql_get_resultset(const char *zone, const char *record, const char *client, unsigned int query, void *dbdata, MYSQL_RES **rs) { isc_result_t result; dbinstance_t *dbi = NULL; mysql_instance_t *db = (mysql_instance_t *)dbdata; char *querystring = NULL; unsigned int i = 0; unsigned int j = 0; int qres = 0; #if PTHREADS /* find an available DBI from the list */ dbi = mysql_find_avail_conn(db); #else /* PTHREADS */ /* * only 1 DBI - no need to lock instance lock either * only 1 thread in the whole process, no possible contention. */ dbi = (dbinstance_t *)(db->db); #endif /* PTHREADS */ if (dbi == NULL) { result = ISC_R_FAILURE; goto cleanup; } /* what type of query are we going to run? */ 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) { db->log(ISC_LOG_DEBUG(2), "No query specified for findzone. " "Findzone requires a query"); result = ISC_R_FAILURE; goto cleanup; } break; case COUNTZONE: if (dbi->countzone_q == NULL) { result = ISC_R_NOTIMPLEMENTED; goto cleanup; } break; case LOOKUP: if (dbi->lookup_q == NULL) { db->log(ISC_LOG_DEBUG(2), "No query specified for lookup. " "Lookup requires a query"); result = ISC_R_FAILURE; goto cleanup; } break; default: db->log(ISC_LOG_ERROR, "Incorrect query flag passed to " "mysql_get_resultset"); result = ISC_R_UNEXPECTED; goto cleanup; } if (zone != NULL) { if (dbi->zone != NULL) free(dbi->zone); dbi->zone = mysqldrv_escape_string((MYSQL *) dbi->dbconn, zone); if (dbi->zone == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } } else dbi->zone = NULL; if (record != NULL) { if (dbi->record != NULL) free(dbi->record); dbi->record = mysqldrv_escape_string((MYSQL *) dbi->dbconn, record); if (dbi->record == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } } else dbi->record = NULL; if (client != NULL) { if (dbi->client != NULL) free(dbi->client); dbi->client = mysqldrv_escape_string((MYSQL *) dbi->dbconn, client); if (dbi->client == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } } else dbi->client = NULL; /* * what type of query are we going to run? this time we build * the actual query to run. */ switch(query) { case ALLNODES: querystring = build_querystring(dbi->allnodes_q); break; case ALLOWXFR: querystring = build_querystring(dbi->allowxfr_q); break; case AUTHORITY: querystring = build_querystring(dbi->authority_q); break; case FINDZONE: querystring = build_querystring(dbi->findzone_q); break; case COUNTZONE: querystring = build_querystring(dbi->countzone_q); break; case LOOKUP: querystring = build_querystring(dbi->lookup_q); break; default: db->log(ISC_LOG_ERROR, "Incorrect query flag passed to " "mysql_get_resultset"); result = ISC_R_UNEXPECTED; goto cleanup; } if (querystring == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } /* output the full query string when debugging */ db->log(ISC_LOG_DEBUG(1), "\nQuery String: %s\n", querystring); /* attempt query up to 3 times. */ for (i = 0; i < 3; i++) { qres = mysql_query((MYSQL *) dbi->dbconn, querystring); if (qres == 0) break; for (j = 0; j < 4; j++) if (mysql_ping((MYSQL *) dbi->dbconn) == 0) break; } if (qres == 0) { result = ISC_R_SUCCESS; if (query != COUNTZONE) { *rs = mysql_store_result((MYSQL *) dbi->dbconn); if (*rs == NULL) result = ISC_R_FAILURE; } } else result = ISC_R_FAILURE; cleanup: if (dbi == NULL) return (ISC_R_FAILURE); if (dbi->zone != NULL) { free(dbi->zone); dbi->zone = NULL; } if (dbi->record != NULL) { free(dbi->record); dbi->record = NULL; } if (dbi->client != NULL) { free(dbi->client); dbi->client = NULL; } /* release the lock so another thread can use this dbi */ (void) dlz_mutex_unlock(&dbi->lock); if (querystring != NULL) free(querystring); return (result); }