Explorar o código

modules_k/sqlops: add sql_pvquery(). Query function that stores results in arbitrary PV's

Alex Hermann %!s(int64=14) %!d(string=hai) anos
pai
achega
ab4e481be8

+ 48 - 12
modules_k/sqlops/README

@@ -33,7 +33,8 @@ Daniel-Constantin Mierla
 
               4.1. sql_query(connection, query[, result])
               4.2. sql_xquery(connection, query, result)
-              4.3. sql_result_free(result)
+              4.3. sql_pvquery(connection, query, result)
+              4.4. sql_result_free(result)
 
         5. Exported pseudo-variables
 
@@ -46,9 +47,10 @@ Daniel-Constantin Mierla
    1.2. Set sqlres parameter
    1.3. sql_query() usage
    1.4. sql_xquery() usage
-   1.5. sql_result_free() usage
-   1.6. $dbr(result=>key) usage
-   1.7. $sqlrows(con) usage
+   1.5. sql_pvquery() usage
+   1.6. sql_result_free() usage
+   1.7. $dbr(result=>key) usage
+   1.8. $sqlrows(con) usage
 
 Chapter 1. Admin Guide
 
@@ -69,7 +71,8 @@ Chapter 1. Admin Guide
 
         4.1. sql_query(connection, query[, result])
         4.2. sql_xquery(connection, query, result)
-        4.3. sql_result_free(result)
+        4.3. sql_pvquery(connection, query, result)
+        4.4. sql_result_free(result)
 
    5. Exported pseudo-variables
 
@@ -164,11 +167,12 @@ modparam("sqlops", "sqlres", "ra")
 
    4.1. sql_query(connection, query[, result])
    4.2. sql_xquery(connection, query, result)
-   4.3. sql_result_free(result)
+   4.3. sql_pvquery(connection, query, result)
+   4.4. sql_result_free(result)
 
 4.1.  sql_query(connection, query[, result])
 
-   Make a SQL query using 'connection' and store data in 'result'.
+   Make an SQL query using 'connection' and store data in 'result'.
      * connection - the name of the connection to be used for query
        (defined via the “sqlcon” parameter).
      * query - SQL query string or pseudo-variables containing SQL query.
@@ -191,7 +195,7 @@ sql_result_free("ra");
 
 4.2.  sql_xquery(connection, query, result)
 
-   Make a SQL query using 'connection' and store data in 'result' xavp.
+   Make an SQL query using 'connection' and store data in 'result' xavp.
      * connection - the name of the connection to be used for query
        (defined via the “sqlcon” parameter).
      * query - SQL query string or pseudo-variables containing SQL query.
@@ -208,13 +212,45 @@ sql_xquery("ca", "select * from domain", "ra");
   xlog("first domain: $xavp(ra=>domain) with id: $xavp(ra=>domain_id)\n");
 ...
 
-4.3.  sql_result_free(result)
+4.3.  sql_pvquery(connection, query, result)
+
+   Make an SQL query using 'connection' and store data in arbitrary PV's
+   specified by 'result' parameter.
+     * connection - the name of the connection to be used for query
+       (defined via the “sqlcon” parameter).
+     * query - SQL query string or pseudo-variables containing SQL query.
+     * result - a list with PV names where to store the result. The format
+       is “$pv;$pv;...”. Every PV that is writable may be used (for
+       example $var, $avp, $xavp, $ru, $du, $sht, etc).
+       The PV are assigned values in the following order: last row to
+       first row, first field to last field. Assignment has the same
+       behavior as assigning in the script itself with one exception for
+       avp's, a NULL value will not delete an avp, but will be skipped
+       over.
+       Beware that if multiple rows are returned, non-(x)avp variables
+       will only hold the last added value, which corresponds to the first
+       returned row.
+       The value type of the PV (string or integer) will be derived from
+       the type of the columns. Please note that only these two datatypes
+       are supported, other datatypes will/may be converted to string.
+
+   This function can be used from ANY_ROUTE.
+
+   Example 1.5. sql_pvquery() usage
+...
+modparam("sqlops","sqlcon","ca=>dbdriver://username:password@dbhost/dbname")
+...
+sql_xquery("ca", "select 'col1', 2, NULL, 'sip:[email protected]'",
+        "$var(a), $avp(col2), $xavp(item[0]=>s), $ru");
+...
+
+4.4.  sql_result_free(result)
 
    Free data in SQL 'result'.
 
    This function can be used from ANY_ROUTE.
 
-   Example 1.5. sql_result_free() usage
+   Example 1.6. sql_result_free() usage
 ...
 modparam("sqlops","sqlcon","ca=>dbdriver://username:password@dbhost/dbname")
 ...
@@ -244,7 +280,7 @@ sql_result_free("ra");
        integer.
      * colname[N] - return the name of the N-th column in the result set.
 
-   Example 1.6. $dbr(result=>key) usage
+   Example 1.7. $dbr(result=>key) usage
 ...
 modparam("sqlops","sqlcon","ca=>dbdriver://username:password@dbhost/dbname")
 ...
@@ -303,7 +339,7 @@ if (sql_xquery("ca", "select * from domain", "ra") == 1)
 
    “con” must be the name identifying an SQL connection.
 
-   Example 1.7. $sqlrows(con) usage
+   Example 1.8. $sqlrows(con) usage
 ...
 modparam("sqlops","sqlcon","ca=>dbdriver://username:password@dbhost/dbname")
 ...

+ 64 - 2
modules_k/sqlops/doc/sqlops_admin.xml

@@ -182,7 +182,7 @@ modparam("sqlops", "sqlres", "ra")
 		<function moreinfo="none">sql_query(connection, query[, result])</function>
 		</title>
 		<para>
-			Make a SQL query using 'connection' and store data in 'result'.
+			Make an SQL query using 'connection' and store data in 'result'.
 		</para>
 		<itemizedlist>
 		<listitem>
@@ -227,7 +227,7 @@ sql_result_free("ra");
 		<function moreinfo="none">sql_xquery(connection, query, result)</function>
 		</title>
 		<para>
-			Make a SQL query using 'connection' and store data in 'result' xavp.
+			Make an SQL query using 'connection' and store data in 'result' xavp.
 		</para>
 		<itemizedlist>
 		<listitem>
@@ -261,6 +261,68 @@ modparam("sqlops","sqlcon","ca=&gt;&exampledb;")
 sql_xquery("ca", "select * from domain", "ra");
   xlog("first domain: $xavp(ra=>domain) with id: $xavp(ra=>domain_id)\n");
 ...
+</programlisting>
+		</example>
+	</section>
+	<section>
+		<title>
+		<function moreinfo="none">sql_pvquery(connection, query, result)</function>
+		</title>
+		<para>
+			Make an SQL query using 'connection' and store data in arbitrary
+			PV's specified by 'result' parameter.
+		</para>
+		<itemizedlist>
+		<listitem>
+			<para>
+				<emphasis>connection</emphasis> - the name of the connection
+				to be used for query (defined via the <quote>sqlcon</quote> parameter).
+			</para>
+		</listitem>
+		<listitem>
+			<para>
+				<emphasis>query</emphasis> - SQL query string or pseudo-variables containing SQL query.
+			</para>
+		</listitem>
+		<listitem>
+			<para>
+				<emphasis>result</emphasis> - a list with PV names where
+				to store the result. The format is
+				<quote>$pv;$pv;...</quote>. Every PV that is writable may 
+				be used (for example $var, $avp, $xavp, $ru, $du, $sht, etc).
+			</para>
+			<para>
+				The PV are assigned values in the following order: last row
+				to first row, first field to last field. Assignment has the
+				same behavior as assigning in the script itself with one
+				exception for avp's, a NULL value will not delete an avp, but
+				will be skipped over.
+			</para>
+			<para>
+				Beware that if multiple rows are returned, non-(x)avp variables
+				will only hold the last added value, which corresponds to the 
+				first returned row.
+			</para>
+			<para>
+				The value type of the PV (string or integer) will
+				be derived from the type of the columns. Please note that only
+				these two datatypes are supported, other datatypes will/may be
+				converted to string.
+			</para>
+		</listitem>
+		</itemizedlist>
+		<para>
+			This function can be used from ANY_ROUTE.
+		</para>
+		<example>
+		<title><function>sql_pvquery()</function> usage</title>
+		<programlisting format="linespecific">
+...
+modparam("sqlops","sqlcon","ca=&gt;&exampledb;")
+...
+sql_xquery("ca", "select 'col1', 2, NULL, 'sip:[email protected]'",
+	"$var(a), $avp(col2), $xavp(item[0]=>s), $ru");
+...
 </programlisting>
 		</example>
 	</section>

+ 56 - 0
modules_k/sqlops/sql_api.c

@@ -540,6 +540,62 @@ error:
 }
 #endif
 
+
+int sql_do_pvquery(struct sip_msg *msg, sql_con_t *con, pv_elem_t *query,
+		pvname_list_t *res)
+{
+	db1_res_t* db_res = NULL;
+	pvname_list_t* pv;
+	str sv;
+	int i, j;
+
+	if(msg==NULL || query==NULL || res==NULL)
+	{
+		LM_ERR("bad parameters\n");
+		return -1;
+	}
+	if(pv_printf_s(msg, query, &sv)!=0)
+	{
+		LM_ERR("cannot print the sql query\n");
+		return -1;
+	}
+
+	if(con->dbf.raw_query(con->dbh, &sv, &db_res)!=0)
+	{
+		LM_ERR("cannot do the query\n");
+		return -1;
+	}
+
+	if(db_res==NULL || RES_ROW_N(db_res)<=0 || RES_COL_N(db_res)<=0)
+	{
+		LM_DBG("no result after query\n");
+		con->dbf.free_result(con->dbh, db_res);
+		return 2;
+	}
+
+	for(i=RES_ROW_N(db_res)-1; i>=0; i--)
+	{
+		pv = res;
+		for(j=0; j<RES_COL_N(db_res); j++)
+		{
+			if (db_val2pv_spec(msg, &RES_ROWS(db_res)[0].values[j], &pv->sname) != 0) {
+				LM_ERR("Failed to convert value for column %.*s\n",
+				       RES_NAMES(db_res)[j]->len, RES_NAMES(db_res)[j]->s);
+				goto error;
+			}
+			pv = pv->next;
+		}
+	}
+
+	con->dbf.free_result(con->dbh, db_res);
+	return 1;
+
+error:
+	con->dbf.free_result(con->dbh, db_res);
+	return -1;
+}
+
+
 int sql_parse_param(char *val)
 {
 	str name;

+ 2 - 0
modules_k/sqlops/sql_api.h

@@ -77,6 +77,8 @@ int sql_do_query(sql_con_t *con, str *query, sql_result_t *res);
 int sql_do_xquery(struct sip_msg *msg, sql_con_t *con, pv_elem_t *query,
 		pv_elem_t *res);
 #endif
+int sql_do_pvquery(struct sip_msg *msg, sql_con_t *con, pv_elem_t *query,
+		pvname_list_t *res);
 int pv_get_sqlrows(struct sip_msg *msg,  pv_param_t *param,
 		pv_value_t *res);
 int pv_parse_con_name(pv_spec_p sp, str *in);

+ 74 - 0
modules_k/sqlops/sqlops.c

@@ -65,6 +65,7 @@ static int sql_query2(struct sip_msg*, char*, char*);
 #ifdef WITH_XAVP
 static int sql_xquery(struct sip_msg *msg, char *dbl, char *query, char *res);
 #endif
+static int sql_pvquery(struct sip_msg *msg, char *dbl, char *query, char *res);
 static int sql_rfree(struct sip_msg*, char*, char*);
 static int child_init(int rank);
 static void destroy(void);
@@ -73,6 +74,7 @@ static int fixup_sql_query(void** param, int param_no);
 #ifdef WITH_XAVP
 static int fixup_sql_xquery(void** param, int param_no);
 #endif
+static int fixup_sql_pvquery(void** param, int param_no);
 static int fixup_sql_rfree(void** param, int param_no);
 
 static int sql_con_param(modparam_t type, void* val);
@@ -98,6 +100,9 @@ static cmd_export_t cmds[]={
 		REQUEST_ROUTE | FAILURE_ROUTE |
 		ONREPLY_ROUTE | BRANCH_ROUTE | LOCAL_ROUTE},
 #endif
+	{"sql_pvquery",  (cmd_function)sql_pvquery, 3, fixup_sql_pvquery, 0,
+		REQUEST_ROUTE | FAILURE_ROUTE |
+		ONREPLY_ROUTE | BRANCH_ROUTE | LOCAL_ROUTE},
 	{"sql_result_free",  (cmd_function)sql_rfree,  1, fixup_sql_rfree, 0, 
 		REQUEST_ROUTE | FAILURE_ROUTE |
 		ONREPLY_ROUTE | BRANCH_ROUTE | LOCAL_ROUTE},
@@ -224,6 +229,14 @@ static int sql_xquery(struct sip_msg *msg, char *dbl, char *query, char *res)
 }
 #endif
 
+/**
+ *
+ */
+static int sql_pvquery(struct sip_msg *msg, char *dbl, char *query, char *res)
+{
+	return sql_do_pvquery(msg, (sql_con_t*)dbl, (pv_elem_t*)query, (pvname_list_t*)res);
+}
+
 /**
  *
  */
@@ -313,6 +326,67 @@ static int fixup_sql_xquery(void** param, int param_no)
 }
 #endif
 
+/**
+ *
+ */
+static int fixup_sql_pvquery(void** param, int param_no)
+{
+	sql_con_t *con = NULL;
+	pv_elem_t *pv = NULL;
+	pvname_list_t *res = NULL;
+	pvname_list_t *pvl = NULL;
+	str s;
+	int i;
+
+	if(*param == NULL)
+	{
+		LM_ERR("missing parameter %d\n", param_no);
+		return E_UNSPEC;
+	}
+	s.s = (char*)(*param);
+	s.len = strlen(s.s);
+
+	if (param_no==1) {
+		con = sql_get_connection(&s);
+		if(con==NULL)
+		{
+			LM_ERR("invalid connection [%s]\n", s.s);
+			return E_UNSPEC;
+		}
+		*param = (void*)con;
+	} else if (param_no==2) {
+		if(pv_parse_format(&s, &pv)<0)
+		{
+			LM_ERR("invalid query string [%s]\n", s.s);
+			return E_UNSPEC;
+		}
+		*param = (void*)pv;
+	} else if (param_no==3) {
+		/* parse result variables into list of pv_spec_t's */
+		res = parse_pvname_list(&s, 0);
+		if(res==NULL)
+		{
+			LM_ERR("invalid result parameter [%s]\n", s.s);
+			return E_UNSPEC;
+		}
+		/* check if all result variables are writable */
+		pvl = res;
+		i = 1;
+		while (pvl) {
+			if (pvl->sname.setf == NULL)
+			{
+				LM_ERR("result variable [%d] is read-only\n", i);
+				return E_UNSPEC;
+			}
+			i++;
+			pvl = pvl->next;
+		}
+		*param = (void*)res;
+		return 0;
+	}
+	return 0;
+}
+
 /**
  *
  */