/** Call the driver's sql_fetch_row function * * Calls the driver's sql_fetch_row logging any errors. On success, will * write row data to ``(*handle)->row``. * * @param out Where to write row data. * @param inst Instance of #rlm_sql_t. * @param request The Current request, may be NULL. * @param handle Handle to retrieve errors for. * @return * - #RLM_SQL_OK on success. * - other #sql_rcode_t constants on error. */ sql_rcode_t rlm_sql_fetch_row(rlm_sql_row_t *out, rlm_sql_t const *inst, REQUEST *request, rlm_sql_handle_t **handle) { sql_rcode_t ret; if (!*handle || !(*handle)->conn) return RLM_SQL_ERROR; /* * We can't implement reconnect logic here, because the caller * may require the original connection to free up queries or * result sets associated with that connection. */ ret = (inst->driver->sql_fetch_row)(out, *handle, inst->config); switch (ret) { case RLM_SQL_OK: rad_assert(*out != NULL); return ret; case RLM_SQL_NO_MORE_ROWS: rad_assert(*out == NULL); return ret; default: ROPTIONAL(RERROR, ERROR, "Error fetching row"); rlm_sql_print_error(inst, request, *handle, false); return ret; } }
/** Call the driver's sql_select_query method, reconnecting if necessary. * * @note Caller must call ``(inst->module->sql_finish_select_query)(handle, inst->config);`` * after they're done with the result. * * @param inst #rlm_sql_t instance data. * @param request Current request. * @param handle to query the database with. *handle should not be NULL, as this indicates * previous reconnection attempt has failed. * @param query to execute. Should not be zero length. * @return * - #RLM_SQL_OK on success. * - #RLM_SQL_RECONNECT if a new handle is required (also sets *handle = NULL). * - #RLM_SQL_QUERY_INVALID, #RLM_SQL_ERROR on invalid query or connection error. */ sql_rcode_t rlm_sql_select_query(rlm_sql_t *inst, REQUEST *request, rlm_sql_handle_t **handle, char const *query) { int ret = RLM_SQL_ERROR; int i, count; /* Caller should check they have a valid handle */ rad_assert(*handle); /* There's no query to run, return an error */ if (query[0] == '\0') { if (request) REDEBUG("Zero length query"); return RLM_SQL_QUERY_INVALID; } /* * inst->pool may be NULL is this function is called by mod_conn_create. */ count = inst->pool ? fr_connection_get_num(inst->pool) : 0; /* * For sanity, for when no connections are viable, and we can't make a new one */ for (i = 0; i < (count + 1); i++) { ROPTIONAL(RDEBUG2, DEBUG2, "Executing select query: %s", query); ret = (inst->module->sql_select_query)(*handle, inst->config, query); switch (ret) { case RLM_SQL_OK: break; /* * Run through all available sockets until we exhaust all existing * sockets in the pool and fail to establish a *new* connection. */ case RLM_SQL_RECONNECT: *handle = fr_connection_reconnect(inst->pool, *handle); /* Reconnection failed */ if (!*handle) return RLM_SQL_RECONNECT; /* Reconnection succeeded, try again with the new handle */ continue; case RLM_SQL_QUERY_INVALID: case RLM_SQL_ERROR: default: rlm_sql_print_error(inst, request, *handle, false); (inst->module->sql_finish_select_query)(*handle, inst->config); break; } return ret; } ROPTIONAL(RERROR, ERROR, "Hit reconnection limit"); return RLM_SQL_ERROR; }
/** Call the driver's sql_fetch_row function * * Calls the driver's sql_fetch_row logging any errors. On success, will * write row data to ``(*handle)->row``. * * @param out Where to write row data. * @param inst Instance of #rlm_sql_t. * @param request The Current request, may be NULL. * @param handle Handle to retrieve errors for. * @return * - #RLM_SQL_OK on success. * - other #sql_rcode_t constants on error. */ sql_rcode_t rlm_sql_fetch_row(rlm_sql_row_t *out, rlm_sql_t *inst, REQUEST *request, rlm_sql_handle_t **handle) { sql_rcode_t ret; if (!*handle || !(*handle)->conn) return RLM_SQL_ERROR; /* * We can't implement reconnect logic here, because the caller * may require the original connection to free up queries or * result sets associated with that connection. */ ret = (inst->module->sql_fetch_row)(out, *handle, inst->config); if (ret < 0) { ROPTIONAL(RERROR, ERROR, "Error fetching row"); rlm_sql_print_error(inst, request, *handle, false); } return ret; }
/** Call the driver's sql_query method, reconnecting if necessary. * * @note Caller must call ``(inst->module->sql_finish_query)(handle, inst->config);`` * after they're done with the result. * * @param handle to query the database with. *handle should not be NULL, as this indicates * previous reconnection attempt has failed. * @param request Current request. * @param inst #rlm_sql_t instance data. * @param query to execute. Should not be zero length. * @return * - #RLM_SQL_OK on success. * - #RLM_SQL_RECONNECT if a new handle is required (also sets *handle = NULL). * - #RLM_SQL_QUERY_INVALID, #RLM_SQL_ERROR on invalid query or connection error. * - #RLM_SQL_ALT_QUERY on constraints violation. */ sql_rcode_t rlm_sql_query(rlm_sql_t *inst, REQUEST *request, rlm_sql_handle_t **handle, char const *query) { int ret = RLM_SQL_ERROR; int i, count; /* Caller should check they have a valid handle */ rad_assert(*handle); /* There's no query to run, return an error */ if (query[0] == '\0') { if (request) REDEBUG("Zero length query"); return RLM_SQL_QUERY_INVALID; } /* * inst->pool may be NULL is this function is called by mod_conn_create. */ count = inst->pool ? fr_connection_get_num(inst->pool) : 0; /* * Here we try with each of the existing connections, then try to create * a new connection, then give up. */ for (i = 0; i < (count + 1); i++) { ROPTIONAL(RDEBUG2, DEBUG2, "Executing query: %s", query); ret = (inst->module->sql_query)(*handle, inst->config, query); switch (ret) { case RLM_SQL_OK: break; /* * Run through all available sockets until we exhaust all existing * sockets in the pool and fail to establish a *new* connection. */ case RLM_SQL_RECONNECT: *handle = fr_connection_reconnect(inst->pool, *handle); /* Reconnection failed */ if (!*handle) return RLM_SQL_RECONNECT; /* Reconnection succeeded, try again with the new handle */ continue; /* * These are bad and should make rlm_sql return invalid */ case RLM_SQL_QUERY_INVALID: rlm_sql_print_error(inst, request, *handle, false); (inst->module->sql_finish_query)(*handle, inst->config); break; /* * Server or client errors. * * If the driver claims to be able to distinguish between * duplicate row errors and other errors, and we hit a * general error treat it as a failure. * * Otherwise rewrite it to RLM_SQL_ALT_QUERY. */ case RLM_SQL_ERROR: if (inst->module->flags & RLM_SQL_RCODE_FLAGS_ALT_QUERY) { rlm_sql_print_error(inst, request, *handle, false); (inst->module->sql_finish_query)(*handle, inst->config); break; } ret = RLM_SQL_ALT_QUERY; /* FALL-THROUGH */ /* * Driver suggested using an alternative query */ case RLM_SQL_ALT_QUERY: rlm_sql_print_error(inst, request, *handle, true); (inst->module->sql_finish_query)(*handle, inst->config); break; } return ret; } ROPTIONAL(RERROR, ERROR, "Hit reconnection limit"); return RLM_SQL_ERROR; }