Просмотр исходного кода

mtree: allow specifying column names per tree

- at least two columns must be specified, first is the one corresponding
  to tprefix
- if more than two, then the values of those columns are concatenated
  with a comma delimiter
- columns can be specified with cols attribute in mtree definition and
  they must be enclosed in quotes in order to be a valid sip parameter
  value and be separated by comma

modparam("mtree", "mtree",
  "name=mt;dbtable=mtree;cols='tprefix,tvalue1,tvalue2'")
Daniel-Constantin Mierla 9 лет назад
Родитель
Сommit
27e3ecb607
3 измененных файлов с 149 добавлено и 14 удалено
  1. 64 6
      modules/mtree/mtree.c
  2. 7 2
      modules/mtree/mtree.h
  3. 78 6
      modules/mtree/mtree_mod.c

+ 64 - 6
modules/mtree/mtree.c

@@ -99,9 +99,12 @@ int mt_init_list_head(void)
 /**
 /**
  *
  *
  */
  */
-m_tree_t* mt_init_tree(str* tname, str *dbtable, int type, int multi)
+m_tree_t* mt_init_tree(str* tname, str *dbtable, str *scols, int type,
+		int multi)
 {
 {
 	m_tree_t *pt = NULL;
 	m_tree_t *pt = NULL;
+	int i;
+	int c;
 
 
 	pt = (m_tree_t*)shm_malloc(sizeof(m_tree_t));
 	pt = (m_tree_t*)shm_malloc(sizeof(m_tree_t));
 	if(pt==NULL)
 	if(pt==NULL)
@@ -137,6 +140,53 @@ m_tree_t* mt_init_tree(str* tname, str *dbtable, int type, int multi)
 	memcpy(pt->dbtable.s, dbtable->s, dbtable->len);
 	memcpy(pt->dbtable.s, dbtable->s, dbtable->len);
 	pt->dbtable.len = dbtable->len;
 	pt->dbtable.len = dbtable->len;
 
 
+	if(scols!=NULL && scols->s!=NULL && scols->len>0) {
+		pt->scols[0].s = (char*)shm_malloc((1+scols->len)*sizeof(char));
+		if(pt->scols[0].s==NULL) {
+			shm_free(pt->tname.s);
+			shm_free(pt->dbtable.s);
+			shm_free(pt);
+			LM_ERR("no more shm memory\n");
+			return NULL;
+		}
+		memset(pt->scols[0].s, 0, (1+scols->len)*sizeof(char));
+		memcpy(pt->scols[0].s, scols->s, scols->len);
+		pt->scols[0].len = scols->len;
+		c = 0;
+		for(i=0; i<scols->len; i++) {
+			if(pt->scols[0].s[i]==',') {
+				pt->scols[c].len = (pt->scols[0].s + i - pt->scols[c].s);
+				LM_DBG("db table column[%d]='%.*s'\n", c,
+						pt->scols[c].len, pt->scols[c].s);
+				c++;
+				if(c>=MT_MAX_COLS) {
+					LM_ERR("too many columns %d\n", c);
+					shm_free(pt->scols[0].s);
+					shm_free(pt->tname.s);
+					shm_free(pt->dbtable.s);
+					shm_free(pt);
+					return NULL;
+				}
+				pt->scols[c].s = pt->scols[0].s + i + 1;
+				pt->scols[c].len = pt->scols[0].s + scols->len - pt->scols[c].s;
+			}
+		}
+		LM_DBG("db table column[%d]='%.*s'\n", c,
+				pt->scols[c].len, pt->scols[c].s);
+		if(c==0) {
+			LM_ERR("there must be at least two columns (prefix, value)\n");
+			shm_free(pt->scols[0].s);
+			shm_free(pt->tname.s);
+			shm_free(pt->dbtable.s);
+			shm_free(pt);
+			return NULL;
+		}
+		pt->ncols = c + 1;
+		pt->pack[0] = 'l';
+		pt->pack[1] = ',';
+		pt->pack[2] = '*';
+	}
+
 	return pt;
 	return pt;
 }
 }
 
 
@@ -723,11 +773,14 @@ int mt_table_spec(char* val)
 	s.len = strlen(s.s);
 	s.len = strlen(s.s);
 	if(s.s[s.len-1]==';')
 	if(s.s[s.len-1]==';')
 		s.len--;
 		s.len--;
+	LM_DBG("parsing [%.*s]\n", s.len, s.s);
 	if (parse_params(&s, CLASS_ANY, &phooks, &params_list)<0)
 	if (parse_params(&s, CLASS_ANY, &phooks, &params_list)<0)
 		return -1;
 		return -1;
 	memset(&tmp, 0, sizeof(m_tree_t));
 	memset(&tmp, 0, sizeof(m_tree_t));
 	for (pit = params_list; pit; pit=pit->next)
 	for (pit = params_list; pit; pit=pit->next)
 	{
 	{
+		LM_DBG("parm: %.*s=%.*s\n", pit->name.len, pit->name.s,
+				pit->body.len, pit->body.s);
 		if (pit->name.len==4
 		if (pit->name.len==4
 				&& strncasecmp(pit->name.s, "name", 4)==0) {
 				&& strncasecmp(pit->name.s, "name", 4)==0) {
 			tmp.tname = pit->body;
 			tmp.tname = pit->body;
@@ -740,6 +793,10 @@ int mt_table_spec(char* val)
 		}  else if(pit->name.len==7
 		}  else if(pit->name.len==7
 				&& strncasecmp(pit->name.s, "dbtable", 7)==0) {
 				&& strncasecmp(pit->name.s, "dbtable", 7)==0) {
 			tmp.dbtable = pit->body;
 			tmp.dbtable = pit->body;
+		}  else if(pit->name.len==4
+				&& strncasecmp(pit->name.s, "cols", 4)==0) {
+			tmp.ncols = 1;
+			tmp.scols[0] = pit->body;
 		}
 		}
 	}
 	}
 	if(tmp.tname.s==NULL)
 	if(tmp.tname.s==NULL)
@@ -794,11 +851,12 @@ int mt_table_spec(char* val)
 	{
 	{
 		LM_DBG("adding new tname [%s]\n", tmp.tname.s);
 		LM_DBG("adding new tname [%s]\n", tmp.tname.s);
 
 
-		ndl = mt_init_tree(&tmp.tname, &tmp.dbtable, tmp.type,
+		ndl = mt_init_tree(&tmp.tname, &tmp.dbtable, &tmp.scols[0], tmp.type,
 				   tmp.multi);
 				   tmp.multi);
 		if(ndl==NULL)
 		if(ndl==NULL)
 		{
 		{
-			LM_ERR("no more shm memory\n");
+			LM_ERR("cannot init the tree [%.*s]\n",
+					tmp.tname.len, tmp.tname.s);
 			goto error; 
 			goto error; 
 		}
 		}
 
 
@@ -819,8 +877,8 @@ error:
 	return -1;
 	return -1;
 }
 }
 
 
-m_tree_t *mt_add_tree(m_tree_t **dpt, str *tname, str *dbtable, int type,
-		      int multi)
+m_tree_t *mt_add_tree(m_tree_t **dpt, str *tname, str *dbtable, str *cols,
+		int type, int multi)
 {
 {
 	m_tree_t *it = NULL;
 	m_tree_t *it = NULL;
 	m_tree_t *prev = NULL;
 	m_tree_t *prev = NULL;
@@ -847,7 +905,7 @@ m_tree_t *mt_add_tree(m_tree_t **dpt, str *tname, str *dbtable, int type,
 	{
 	{
 		LM_DBG("adding new tname [%s]\n", tname->s);
 		LM_DBG("adding new tname [%s]\n", tname->s);
 
 
-		ndl = mt_init_tree(tname, dbtable, type, multi);
+		ndl = mt_init_tree(tname, dbtable, cols, type, multi);
 		if(ndl==NULL)
 		if(ndl==NULL)
 		{
 		{
 			LM_ERR("no more shm memory\n");
 			LM_ERR("no more shm memory\n");

+ 7 - 2
modules/mtree/mtree.h

@@ -63,12 +63,16 @@ typedef struct _mt_node
 
 
 #define MT_NODE_SIZE	mt_char_list.len
 #define MT_NODE_SIZE	mt_char_list.len
 
 
+#define MT_MAX_COLS	8
 typedef struct _m_tree
 typedef struct _m_tree
 {
 {
 	str tname;
 	str tname;
 	str dbtable;
 	str dbtable;
 	int type;
 	int type;
 	int multi;
 	int multi;
+	int ncols;
+	str scols[MT_MAX_COLS];
+	char pack[4];
 	unsigned int nrnodes;
 	unsigned int nrnodes;
 	unsigned int nritems;
 	unsigned int nritems;
 	unsigned int memsize;
 	unsigned int memsize;
@@ -89,7 +93,8 @@ is_t* mt_get_tvalue(m_tree_t *pt, str *tomatch, int *len);
 int mt_match_prefix(struct sip_msg *msg, m_tree_t *pt,
 int mt_match_prefix(struct sip_msg *msg, m_tree_t *pt,
 		    str *tomatch, int mode);
 		    str *tomatch, int mode);
 
 
-m_tree_t* mt_init_tree(str* tname, str* dbtable, int type, int multi);
+m_tree_t* mt_init_tree(str* tname, str* dbtable, str *scols, int type,
+		int multi);
 void mt_free_tree(m_tree_t *pt);
 void mt_free_tree(m_tree_t *pt);
 int mt_print_tree(m_tree_t *pt);
 int mt_print_tree(m_tree_t *pt);
 void mt_free_node(mt_node_t *pn, int type);
 void mt_free_node(mt_node_t *pn, int type);
@@ -105,7 +110,7 @@ int mt_defined_trees(void);
 m_tree_t *mt_swap_list_head(m_tree_t *ntree);
 m_tree_t *mt_swap_list_head(m_tree_t *ntree);
 int mt_init_list_head(void);
 int mt_init_list_head(void);
 m_tree_t *mt_add_tree(m_tree_t **dpt, str *tname, str *dbtable,
 m_tree_t *mt_add_tree(m_tree_t **dpt, str *tname, str *dbtable,
-		      int type, int multi);
+		      str *cols, int type, int multi);
 
 
 int mt_mi_match_prefix(struct mi_node *rpl, m_tree_t *pt,
 int mt_mi_match_prefix(struct mi_node *rpl, m_tree_t *pt,
 		    str *tomatch, int mode);
 		    str *tomatch, int mode);

+ 78 - 6
modules/mtree/mtree_mod.c

@@ -481,19 +481,84 @@ error:
 
 
 }
 }
 
 
+static int mt_pack_values(m_tree_t *pt, db1_res_t* db_res,
+		int row, int cols, str *tvalue)
+{
+	static char vbuf[4096];
+	int c;
+	int len;
+	char *p;
+	str iv;
+
+	len = 0;
+	for(c=1; c<cols; c++) {
+		if(VAL_NULL(&RES_ROWS(db_res)[row].values[c])) {
+			len += 1;
+		} else if(RES_ROWS(db_res)[row].values[c].type == DB1_STRING) {
+			len += strlen(RES_ROWS(db_res)[row].values[c].val.string_val);
+		} else if(RES_ROWS(db_res)[row].values[c].type == DB1_STR) {
+			len += RES_ROWS(db_res)[row].values[c].val.str_val.len;
+		} else if(RES_ROWS(db_res)[row].values[c].type == DB1_INT) {
+			len += 12;
+		} else {
+			LM_ERR("unsupported data type for column %d\n", c);
+			return -1;
+		}
+	}
+	if(len + c>=4096) {
+		LM_ERR("too large values (need %d)\n", len+c);
+		return -1;
+	}
+	p = vbuf;
+	for(c=1; c<cols; c++) {
+		if(VAL_NULL(&RES_ROWS(db_res)[row].values[c])) {
+			*p = pt->pack[2];
+			p++;
+		} else if(RES_ROWS(db_res)[row].values[c].type == DB1_STRING) {
+			strcpy(p, RES_ROWS(db_res)[row].values[c].val.string_val);
+			p += strlen(RES_ROWS(db_res)[row].values[c].val.string_val);
+		} else if(RES_ROWS(db_res)[row].values[c].type == DB1_STR) {
+			strncpy(p, RES_ROWS(db_res)[row].values[c].val.str_val.s,
+				RES_ROWS(db_res)[row].values[c].val.str_val.len);
+			p += RES_ROWS(db_res)[row].values[c].val.str_val.len;
+		} else if(RES_ROWS(db_res)[row].values[c].type == DB1_INT) {
+			iv.s = sint2str(RES_ROWS(db_res)[row].values[c].val.int_val, &iv.len);
+			strncpy(p, iv.s, iv.len);
+			p += iv.len;
+		}
+		if(c+1<cols) {
+			*p = pt->pack[1];
+			p++;
+		}
+	}
+	tvalue->s = vbuf;
+	tvalue->len = p - vbuf;
+	LM_DBG("packed: [%.*s]\n", tvalue->len, tvalue->s);
+	return 0;
+}
+
 static int mt_load_db(m_tree_t *pt)
 static int mt_load_db(m_tree_t *pt)
 {
 {
-	db_key_t db_cols[3] = {&tprefix_column, &tvalue_column};
+	db_key_t db_cols[MT_MAX_COLS] = {&tprefix_column, &tvalue_column};
 	db_key_t key_cols[1];
 	db_key_t key_cols[1];
 	db_op_t op[1] = {OP_EQ};
 	db_op_t op[1] = {OP_EQ};
 	db_val_t vals[1];
 	db_val_t vals[1];
 	str tprefix, tvalue;
 	str tprefix, tvalue;
 	db1_res_t* db_res = NULL;
 	db1_res_t* db_res = NULL;
-	int i, ret;
+	int i, ret, c;
 	m_tree_t new_tree; 
 	m_tree_t new_tree; 
 	m_tree_t *old_tree = NULL; 
 	m_tree_t *old_tree = NULL; 
 	mt_node_t *bk_head = NULL; 
 	mt_node_t *bk_head = NULL; 
 
 
+	if(pt->ncols>0) {
+		for(c=0; c<pt->ncols; c++) {
+			db_cols[c] = &pt->scols[c];
+		}
+	} else {
+		db_cols[0] = &tprefix_column;
+		db_cols[1] = &tvalue_column;
+		c = 2;
+	}
 	key_cols[0] = &tname_column;
 	key_cols[0] = &tname_column;
 	VAL_TYPE(vals) = DB1_STRING;
 	VAL_TYPE(vals) = DB1_STRING;
 	VAL_NULL(vals) = 0;
 	VAL_NULL(vals) = 0;
@@ -530,7 +595,7 @@ static int mt_load_db(m_tree_t *pt)
 
 
 	if (DB_CAPABILITY(mt_dbf, DB_CAP_FETCH)) {
 	if (DB_CAPABILITY(mt_dbf, DB_CAP_FETCH)) {
 		if(mt_dbf.query(db_con, key_cols, op, vals, db_cols, pt->multi,
 		if(mt_dbf.query(db_con, key_cols, op, vals, db_cols, pt->multi,
-				2, 0, 0) < 0)
+				c, 0, 0) < 0)
 		{
 		{
 			LM_ERR("Error while querying db\n");
 			LM_ERR("Error while querying db\n");
 			return -1;
 			return -1;
@@ -578,8 +643,15 @@ static int mt_load_db(m_tree_t *pt)
 			tprefix.s = (char*)(RES_ROWS(db_res)[i].values[0].val.string_val);
 			tprefix.s = (char*)(RES_ROWS(db_res)[i].values[0].val.string_val);
 			tprefix.len = strlen(ZSW(tprefix.s));
 			tprefix.len = strlen(ZSW(tprefix.s));
 
 
-			tvalue.s = (char*)(RES_ROWS(db_res)[i].values[1].val.string_val);
-			tvalue.len = strlen(ZSW(tvalue.s));
+			if(c>2) {
+				if(mt_pack_values(&new_tree, db_res, i, c, &tvalue)<0) {
+					LM_ERR("Error packing values\n");
+					goto error;
+				}
+			} else {
+				tvalue.s = (char*)(RES_ROWS(db_res)[i].values[1].val.string_val);
+				tvalue.len = strlen(ZSW(tvalue.s));
+			}
 
 
 			if(tprefix.s==NULL || tvalue.s==NULL
 			if(tprefix.s==NULL || tvalue.s==NULL
 					|| tprefix.len<=0 || tvalue.len<=0)
 					|| tprefix.len<=0 || tvalue.len<=0)
@@ -719,7 +791,7 @@ static int mt_load_db_trees()
 				LM_ERR("Error - bad values in db\n");
 				LM_ERR("Error - bad values in db\n");
 				continue;
 				continue;
 			}
 			}
-			new_tree = mt_add_tree(&new_head, &tname, &db_table,
+			new_tree = mt_add_tree(&new_head, &tname, &db_table, NULL,
 					       _mt_tree_type, 0);
 					       _mt_tree_type, 0);
 			if(new_tree==NULL)
 			if(new_tree==NULL)
 			{
 			{