Use a proper rcode for no more rows
[freeradius.git] / src / modules / rlm_sql / sql.c
index 9cad610..51ba11d 100644 (file)
@@ -44,26 +44,16 @@ RCSID("$Id$")
  *     readable reason strings.
  */
 const FR_NAME_NUMBER sql_rcode_table[] = {
-       { "none",               RLM_SQL_OK              },
+       { "success",            RLM_SQL_OK              },
        { "need alt query",     RLM_SQL_ALT_QUERY       },
        { "server error",       RLM_SQL_ERROR           },
        { "query invalid",      RLM_SQL_QUERY_INVALID   },
        { "no connection",      RLM_SQL_RECONNECT       },
+       { "no more rows",       RLM_SQL_NO_MORE_ROWS    },
        { NULL, 0 }
 };
 
 
-static int _mod_conn_free(rlm_sql_handle_t *conn)
-{
-       rlm_sql_t *inst = conn->inst;
-
-       rad_assert(inst);
-
-       exec_trigger(NULL, inst->cs, "modules.sql.close", false);
-
-       return 0;
-}
-
 void *mod_conn_create(TALLOC_CTX *ctx, void *instance)
 {
        int rcode;
@@ -89,19 +79,9 @@ void *mod_conn_create(TALLOC_CTX *ctx, void *instance)
         */
        handle->inst = inst;
 
-       /*
-        *      When something frees this handle the destructor set by
-        *      the driver will be called first, closing any open sockets.
-        *      Then we call our destructor to trigger an modules.sql.close
-        *      event, then all the memory is freed.
-        */
-       talloc_set_destructor(handle, _mod_conn_free);
-
        rcode = (inst->module->sql_socket_init)(handle, inst->config);
        if (rcode != 0) {
        fail:
-               exec_trigger(NULL, inst->cs, "modules.sql.fail", true);
-
                /*
                 *      Destroy any half opened connections.
                 */
@@ -114,30 +94,29 @@ void *mod_conn_create(TALLOC_CTX *ctx, void *instance)
                (inst->module->sql_finish_select_query)(handle, inst->config);
        }
 
-       exec_trigger(NULL, inst->cs, "modules.sql.open", false);
        return handle;
 }
 
 /*************************************************************************
  *
- *     Function: sql_userparse
+ *     Function: sql_fr_pair_list_afrom_str
  *
  *     Purpose: Read entries from the database and fill VALUE_PAIR structures
  *
  *************************************************************************/
-int sql_userparse(TALLOC_CTX *ctx, REQUEST *request, VALUE_PAIR **head, rlm_sql_row_t row)
+int sql_fr_pair_list_afrom_str(TALLOC_CTX *ctx, REQUEST *request, VALUE_PAIR **head, rlm_sql_row_t row)
 {
        VALUE_PAIR *vp;
        char const *ptr, *value;
        char buf[MAX_STRING_LEN];
        char do_xlat = 0;
-       FR_TOKEN token, operator = T_EOL;
+       FR_TOKEN token, op = T_EOL;
 
        /*
         *      Verify the 'Attribute' field
         */
        if (!row[2] || row[2][0] == '\0') {
-               REDEBUG("The 'Attribute' field is empty or NULL, skipping the entire row");
+               REDEBUG("Attribute field is empty or NULL, skipping the entire row");
                return -1;
        }
 
@@ -146,10 +125,9 @@ int sql_userparse(TALLOC_CTX *ctx, REQUEST *request, VALUE_PAIR **head, rlm_sql_
         */
        if (row[4] != NULL && row[4][0] != '\0') {
                ptr = row[4];
-               operator = gettoken(&ptr, buf, sizeof(buf), false);
-               if ((operator < T_OP_ADD) ||
-                   (operator > T_OP_CMP_EQ)) {
-                       REDEBUG("Invalid operator \"%s\" for attribute %s", row[4], row[2]);
+               op = gettoken(&ptr, buf, sizeof(buf), false);
+               if (!fr_assignment_op[op] && !fr_equality_op[op]) {
+                       REDEBUG("Invalid op \"%s\" for attribute %s", row[4], row[2]);
                        return -1;
                }
 
@@ -157,15 +135,21 @@ int sql_userparse(TALLOC_CTX *ctx, REQUEST *request, VALUE_PAIR **head, rlm_sql_
                /*
                 *  Complain about empty or invalid 'op' field
                 */
-               operator = T_OP_CMP_EQ;
-               REDEBUG("The 'op' field for attribute '%s = %s' is NULL, or non-existent.", row[2], row[3]);
+               op = T_OP_CMP_EQ;
+               REDEBUG("The op field for attribute '%s = %s' is NULL, or non-existent.", row[2], row[3]);
                REDEBUG("You MUST FIX THIS if you want the configuration to behave as you expect");
        }
 
        /*
         *      The 'Value' field may be empty or NULL
         */
+       if (!row[3]) {
+               REDEBUG("Value field is empty or NULL, skipping the entire row");
+               return -1;
+       }
+
        value = row[3];
+
        /*
         *      If we have a new-style quoted string, where the
         *      *entire* string is quoted, do xlat's.
@@ -188,9 +172,9 @@ int sql_userparse(TALLOC_CTX *ctx, REQUEST *request, VALUE_PAIR **head, rlm_sql_
                 *      Mark the pair to be allocated later.
                 */
                case T_BACK_QUOTED_STRING:
-                       value = NULL;
                        do_xlat = 1;
-                       break;
+
+                       /* FALL-THROUGH */
 
                /*
                 *      Keep the original string.
@@ -204,21 +188,21 @@ int sql_userparse(TALLOC_CTX *ctx, REQUEST *request, VALUE_PAIR **head, rlm_sql_
        /*
         *      Create the pair
         */
-       vp = pairmake(ctx, NULL, row[2], NULL, operator);
+       vp = fr_pair_make(ctx, NULL, row[2], NULL, op);
        if (!vp) {
                REDEBUG("Failed to create the pair: %s", fr_strerror());
                return -1;
        }
 
        if (do_xlat) {
-               if (pairmark_xlat(vp, value) < 0) {
-                       REDEBUG("Error marking pair for xlat");
+               if (fr_pair_mark_xlat(vp, value) < 0) {
+                       REDEBUG("Error marking pair for xlat: %s", fr_strerror());
 
                        talloc_free(vp);
                        return -1;
                }
        } else {
-               if (pairparsevalue(vp, value, -1) < 0) {
+               if (fr_pair_value_from_str(vp, value, -1) < 0) {
                        REDEBUG("Error parsing value: %s", fr_strerror());
 
                        talloc_free(vp);
@@ -229,7 +213,7 @@ int sql_userparse(TALLOC_CTX *ctx, REQUEST *request, VALUE_PAIR **head, rlm_sql_
        /*
         *      Add the pair into the packet
         */
-       pairadd(head, vp);
+       fr_pair_add(head, vp);
        return 0;
 }
 
@@ -256,7 +240,7 @@ sql_rcode_t rlm_sql_fetch_row(rlm_sql_t *inst, REQUEST *request, rlm_sql_handle_
         */
        ret = (inst->module->sql_fetch_row)(*handle, inst->config);
        if (ret < 0) {
-               ROPTIONAL(RERROR, ERROR, "Error fetching row");
+               MOD_ROPTIONAL(RERROR, ERROR, "Error fetching row");
 
                rlm_sql_print_error(inst, request, *handle, false);
        }
@@ -282,7 +266,7 @@ void rlm_sql_print_error(rlm_sql_t *inst, REQUEST *request, rlm_sql_handle_t *ha
 
        num = (inst->module->sql_error)(handle->log_ctx, log, (sizeof(log) / sizeof(*log)), handle, inst->config);
        if (num == 0) {
-               ROPTIONAL(RERROR, ERROR, "Unknown error");
+               MOD_ROPTIONAL(RERROR, ERROR, "Unknown error");
                return;
        }
 
@@ -293,21 +277,21 @@ void rlm_sql_print_error(rlm_sql_t *inst, REQUEST *request, rlm_sql_handle_t *ha
 
                switch (log[i].type) {
                case L_ERR:
-                       ROPTIONAL(RERROR, ERROR, "%s: %s", driver, log[i].msg);
+                       MOD_ROPTIONAL(RERROR, ERROR, "%s: %s", driver, log[i].msg);
                        break;
 
                case L_WARN:
-                       ROPTIONAL(RWARN, WARN, "%s: %s", driver, log[i].msg);
+                       MOD_ROPTIONAL(RWARN, WARN, "%s: %s", driver, log[i].msg);
                        break;
 
                case L_INFO:
-                       ROPTIONAL(RINFO, INFO, "%s: %s", driver, log[i].msg);
+                       MOD_ROPTIONAL(RINFO, INFO, "%s: %s", driver, log[i].msg);
                        break;
 
                case L_DBG:
                default:
                debug:
-                       ROPTIONAL(RDEBUG, DEBUG, "%s: %s", driver, log[i].msg);
+                       MOD_ROPTIONAL(RDEBUG, DEBUG, "%s: %s", driver, log[i].msg);
                        break;
                }
        }
@@ -346,14 +330,14 @@ sql_rcode_t rlm_sql_query(rlm_sql_t *inst, REQUEST *request, rlm_sql_handle_t **
        /*
         *  inst->pool may be NULL is this function is called by mod_conn_create.
         */
-       count = inst->pool ? fr_connection_get_num(inst->pool) : 0;
+       count = inst->pool ? fr_connection_pool_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);
+               MOD_ROPTIONAL(RDEBUG2, DEBUG2, "Executing query: %s", query);
 
                ret = (inst->module->sql_query)(*handle, inst->config, query);
                switch (ret) {
@@ -410,7 +394,7 @@ sql_rcode_t rlm_sql_query(rlm_sql_t *inst, REQUEST *request, rlm_sql_handle_t **
                return ret;
        }
 
-       ROPTIONAL(RERROR, ERROR, "Hit reconnection limit");
+       MOD_ROPTIONAL(RERROR, ERROR, "Hit reconnection limit");
 
        return RLM_SQL_ERROR;
 }
@@ -446,13 +430,13 @@ sql_rcode_t rlm_sql_select_query(rlm_sql_t *inst, REQUEST *request, rlm_sql_hand
        /*
         *  inst->pool may be NULL is this function is called by mod_conn_create.
         */
-       count = inst->pool ? fr_connection_get_num(inst->pool) : 0;
+       count = inst->pool ? fr_connection_pool_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);
+               MOD_ROPTIONAL(RDEBUG2, DEBUG2, "Executing select query: %s", query);
 
                ret = (inst->module->sql_select_query)(*handle, inst->config, query);
                switch (ret) {
@@ -481,7 +465,7 @@ sql_rcode_t rlm_sql_select_query(rlm_sql_t *inst, REQUEST *request, rlm_sql_hand
                return ret;
        }
 
-       ROPTIONAL(RERROR, ERROR, "Hit reconnection limit");
+       MOD_ROPTIONAL(RERROR, ERROR, "Hit reconnection limit");
 
        return RLM_SQL_ERROR;
 }
@@ -506,10 +490,10 @@ int sql_getvpdata(TALLOC_CTX *ctx, rlm_sql_t *inst, REQUEST *request, rlm_sql_ha
        rcode = rlm_sql_select_query(inst, request, handle, query);
        if (rcode != RLM_SQL_OK) return -1; /* error handled by rlm_sql_select_query */
 
-       while (rlm_sql_fetch_row(inst, request, handle) == 0) {
+       while (rlm_sql_fetch_row(inst, request, handle) == RLM_SQL_OK) {
                row = (*handle)->row;
                if (!row) break;
-               if (sql_userparse(ctx, request, pair, row) != 0) {
+               if (sql_fr_pair_list_afrom_str(ctx, request, pair, row) != 0) {
                        REDEBUG("Error parsing user data from database result");
 
                        (inst->module->sql_finish_select_query)(*handle, inst->config);
@@ -535,13 +519,10 @@ void rlm_sql_query_log(rlm_sql_t *inst, REQUEST *request,
        size_t len;
        bool failed = false;    /* Write the log message outside of the critical region */
 
-       if (section) {
-               filename = section->logfile;
-       } else {
-               filename = inst->config->logfile;
-       }
+       filename = inst->config->logfile;
+       if (section && section->logfile) filename = section->logfile;
 
-       if (!filename) {
+       if (!filename || !*filename) {
                return;
        }