]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Add query_number_attribute option to rlm_sql
authorNick Porter <nick@portercomputing.co.uk>
Fri, 9 May 2025 12:39:33 +0000 (13:39 +0100)
committerNick Porter <nick@portercomputing.co.uk>
Fri, 9 May 2025 13:30:18 +0000 (14:30 +0100)
An optional attribute which can be used to record which out of a series
of queries updated records.

raddb/mods-available/sql
src/modules/rlm_sql/rlm_sql.c
src/modules/rlm_sql/rlm_sql.h

index 9216fe818d8cfafe47d3351e07528d0a2d0baeab..609a922682787eb710bca32b639e771448fc0605 100644 (file)
@@ -349,6 +349,23 @@ sql {
        #
 #      cache_groups = no
 
+       #
+       #  query_number_attribute:: An attribute to write the successful query number to.
+       #
+       #  When calling the `sql` module in a section such as `accounting` where there are a list of queries to
+       #  try, and success is determined by a query modifying one or more records, this option can be used to
+       #  record which query succeeded.
+       #
+       #  The attribute named here will be populated in the `control` list with the number of the query
+       #  which succeeded.
+       #
+       #  If, as is the case with the default Interim-Update queries, the first query is an `UPDATE` and the
+       #  second is an `INSERT`, this can be used to determine if calling the module resulted in a new record
+       #  being written or an existing one being updated. I.e. if the `UPDATE` succeeds, the attribute will be
+       #  populated with 1, whereas if the `INSERT` succeeds, the attribute will be populated with 2.
+       #
+#      query_number_attribute = 'Query-Number'
+
        #
        #  .Read database-specific queries.
        #
index 12e82042a25973079c2cf741c1a3d7c6a53240b2..a236eadfd98920d4d98fbfeef187338497f2c56b 100644 (file)
@@ -52,6 +52,7 @@ static int submodule_parse(TALLOC_CTX *ctx, void *out, void *parent, CONF_ITEM *
 
 typedef struct {
        fr_dict_attr_t const *group_da;
+       fr_dict_attr_t const *query_number_da;
 } rlm_sql_boot_t;
 
 static const conf_parser_t module_config[] = {
@@ -67,6 +68,7 @@ static const conf_parser_t module_config[] = {
        { FR_CONF_OFFSET("cache_groups", rlm_sql_config_t, cache_groups) },
        { FR_CONF_OFFSET("read_profiles", rlm_sql_config_t, read_profiles), .dflt = "yes" },
        { FR_CONF_OFFSET("open_query", rlm_sql_config_t, connect_query) },
+       { FR_CONF_OFFSET("query_number_attribute", rlm_sql_config_t, query_number_attribute) },
 
        { FR_CONF_OFFSET("safe_characters", rlm_sql_config_t, allowed_chars), .dflt = "@abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_: /" },
 
@@ -1812,7 +1814,15 @@ static unlang_action_t mod_sql_redundant_query_resume(rlm_rcode_t *p_result, UNU
        TALLOC_FREE(query_ctx);
        RDEBUG2("%i record(s) updated", numaffected);
 
-       if (numaffected > 0) RETURN_MODULE_OK;  /* A query succeeded, were done! */
+       if (numaffected > 0) {
+               if (inst->query_number_da) {
+                       fr_pair_t       *vp;
+                       pair_update_control(&vp, inst->query_number_da);
+                       vp->vp_uint32 = redundant_ctx->query_no + 1;
+                       RDEBUG2("control.%pP", vp);
+               }
+               RETURN_MODULE_OK;       /* A query succeeded, were done! */
+       }
 next:
        /*
         *      Look to see if there are any more queries to expand
@@ -2094,6 +2104,7 @@ static int mod_instantiate(module_inst_ctx_t const *mctx)
         *      point in making rlm_sql_boot_t available everywhere.
         */
        inst->group_da = boot->group_da;
+       inst->query_number_da = boot->query_number_da;
 
        inst->name = mctx->mi->name;    /* Need this for functions in sql.c */
        inst->mi = mctx->mi;            /* For looking up thread instance data */
@@ -2245,6 +2256,35 @@ static int mod_bootstrap(module_inst_ctx_t const *mctx)
                xlat_func_args_set(xlat, sql_xlat_arg);
        }
 
+       /*
+        *      If we need to record which query from a redundant set succeeds, find / create the attribute to use.
+        */
+       if (inst->config.query_number_attribute) {
+               boot->query_number_da = fr_dict_attr_by_name(NULL, fr_dict_root(dict_freeradius),
+                                                            inst->config.query_number_attribute);
+               if (!boot->query_number_da) {
+                       if (fr_dict_attr_add_name_only(fr_dict_unconst(dict_freeradius), fr_dict_root(dict_freeradius),
+                           inst->config.query_number_attribute, FR_TYPE_UINT32, NULL) < 0) {
+                               ERROR("Failed defining query number attribute \"%s\"", inst->config.query_number_attribute);
+                               return -1;
+                       }
+
+                       boot->query_number_da = fr_dict_attr_search_by_qualified_oid(NULL, dict_freeradius,
+                                                                                    inst->config.query_number_attribute,
+                                                                                    false, false);
+                       if (!boot->query_number_da) {
+                               ERROR("Failed resolving query number attribute \"%s\"", inst->config.query_number_attribute);
+                               return -1;
+                       }
+               } else {
+                       if (boot->query_number_da->type != FR_TYPE_UINT32) {
+                               ERROR("Query number attribute \"%s\" is type \"%s\", needs to be uint32",
+                                     inst->config.query_number_attribute, fr_type_to_str(boot->query_number_da->type));
+                               return -1;
+                       }
+               }
+       }
+
        /*
         *      Register the SQL xlat function
         */
index d3db49d9a664f9751b9d26601f6d292aeea5c6e5..4c1c68398e1ffa60c35d00c8269b36985cc4092a 100644 (file)
@@ -98,6 +98,10 @@ typedef struct {
        char const              *connect_query;                 //!< Query executed after establishing
                                                                //!< new connection.
 
+       char const              *query_number_attribute;        //!< Name of the attribute to populate with the
+                                                               ///< query number which succeeded when running a
+                                                               ///< series of redundant queries.
+
        trunk_conf_t            trunk_conf;                     //!< Configuration for trunk connections.
 } rlm_sql_config_t;
 
@@ -240,6 +244,7 @@ struct sql_inst {
 
        char const              *name;                  //!< Module instance name.
        fr_dict_attr_t const    *group_da;              //!< Group dictionary attribute.
+       fr_dict_attr_t const    *query_number_da;       //!< Query number attribute.
        module_instance_t const *mi;                    //!< Module instance data for thread lookups.
 };