예제 #1
0
int cql_convert_row(oac::CqlResult& _cql_res, db1_res_t* _r)
{
	std::vector<oac::CqlRow>  res_cql_rows = _cql_res.rows;
        int rows_no = res_cql_rows.size();
        int cols_no = res_cql_rows[0].columns.size();
        str col_val;
        RES_ROW_N(_r) = rows_no;

        if (db_allocate_rows(_r) < 0) {
                LM_ERR("Could not allocate rows.\n");
                return -1;
        }

        for(int ri=0; ri < rows_no; ri++) {
                if (db_allocate_row(_r, &(RES_ROWS(_r)[ri])) != 0) {
                        LM_ERR("Could not allocate row.\n");
                        return -2;
                }

		// complete the row with the columns 
		for(int col = 0; col< cols_no; col++) {
			col_val.s = (char*)res_cql_rows[ri].columns[col].value.c_str();
                        col_val.len = strlen(col_val.s);

			RES_ROWS(_r)[ri].values[col].type = RES_TYPES(_r)[col];	
			cassa_convert_result_raw(&RES_ROWS(_r)[ri].values[col], &col_val);

			LM_DBG("Field index %d. %s = %s.\n", col,
				res_cql_rows[ri].columns[col].name.c_str(),
				res_cql_rows[ri].columns[col].value.c_str());
		}
	}
	return 0;
} 
예제 #2
0
파일: km_row.c 프로젝트: billyyh/kamailio
/*!
 * \brief Convert a row from result into DB API representation
 * \param _h database connection
 * \param _res database result in the DB API representation
 * \param _r database result row
 * \return 0 on success, -1 on failure
 */
int db_mysql_convert_row(const db1_con_t* _h, db1_res_t* _res, db_row_t* _r)
{
	unsigned long* lengths;
	int i;

	if ((!_h) || (!_res) || (!_r)) {
		LM_ERR("invalid parameter value\n");
		return -1;
	}

	if (db_allocate_row(_res, _r) != 0) {
		LM_ERR("could not allocate row");
		return -2;
	}
	
	lengths = mysql_fetch_lengths(CON_RESULT(_h));

	for(i = 0; i < RES_COL_N(_res); i++) {
		if (db_str2val(RES_TYPES(_res)[i], &(ROW_VALUES(_r)[i]),
			    ((MYSQL_ROW)CON_ROW(_h))[i], lengths[i], 0) < 0) {
			LM_ERR("failed to convert value\n");
			LM_DBG("free row at %p\n", _r);
			db_free_row(_r);
			return -3;
		}
	}
	return 0;
}
예제 #3
0
파일: km_res.c 프로젝트: kamailio/kamailio
/*!
 * \brief Convert a row from the result query into db API representation
 * \param _h database connection
 * \param _r result set
 * \param _row row
 * \param row_buf row buffer
 * \return 0 on success, negative on error
 */
int db_postgres_convert_row(const db1_con_t* _h, db1_res_t* _r, db_row_t* _row,
                            char **row_buf)
{
    int col, col_len;

    if (!_h || !_r || !_row)  {
        LM_ERR("invalid parameter value\n");
        return -1;
    }

    if (db_allocate_row(_r, _row) != 0) {
        LM_ERR("could not allocate row\n");
        return -2;
    }

    /* For each column in the row */
    for(col = 0; col < ROW_N(_row); col++) {
        /* because it can contain NULL */
        if (!row_buf[col]) {
            col_len = 0;
        } else {
            col_len = strlen(row_buf[col]);
        }
        /* Convert the string representation into the value representation */
        if (db_postgres_str2val(RES_TYPES(_r)[col], &(ROW_VALUES(_row)[col]),
                                row_buf[col], col_len) < 0) {
            LM_ERR("failed to convert value\n");
            LM_DBG("free row at %p\n", _row);
            db_free_row(_row);
            return -3;
        }
    }
    return 0;
}
예제 #4
0
/*
 * Convert a row from result into db API representation
 */
static int dbt_convert_row(db1_res_t* _res, db_row_t* _r, dbt_row_p _r1)
{
	int i;
	if (!_r || !_res || !_r1) {
		LM_ERR("invalid parameter value\n");
		return -1;
	}

	if (db_allocate_row(_res, _r) != 0) {
		LM_ERR("could not allocate row");
		return -2;
	}

	for(i = 0; i < RES_COL_N(_res); i++) {
		(ROW_VALUES(_r)[i]).nul = _r1->fields[i].nul;
		switch(RES_TYPES(_res)[i])
		{
			case DB1_INT:
				VAL_INT(&(ROW_VALUES(_r)[i])) = 
						_r1->fields[i].val.int_val;
				VAL_TYPE(&(ROW_VALUES(_r)[i])) = DB1_INT;
			break;

			case DB1_BIGINT:
				LM_ERR("BIGINT not supported");
				return -1;

			case DB1_DOUBLE:
				VAL_DOUBLE(&(ROW_VALUES(_r)[i])) = 
						_r1->fields[i].val.double_val;
				VAL_TYPE(&(ROW_VALUES(_r)[i])) = DB1_DOUBLE;
			break;

			case DB1_STRING:
				VAL_STR(&(ROW_VALUES(_r)[i])).s = 
						_r1->fields[i].val.str_val.s;
				VAL_STR(&(ROW_VALUES(_r)[i])).len =
						_r1->fields[i].val.str_val.len;
				VAL_TYPE(&(ROW_VALUES(_r)[i])) = DB1_STRING;
				VAL_FREE(&(ROW_VALUES(_r)[i])) = 0;
			break;

			case DB1_STR:
				VAL_STR(&(ROW_VALUES(_r)[i])).s = 
						_r1->fields[i].val.str_val.s;
				VAL_STR(&(ROW_VALUES(_r)[i])).len =
						_r1->fields[i].val.str_val.len;
				VAL_TYPE(&(ROW_VALUES(_r)[i])) = DB1_STR;
				VAL_FREE(&(ROW_VALUES(_r)[i])) = 0;
			break;

			case DB1_DATETIME:
				VAL_INT(&(ROW_VALUES(_r)[i])) = 
						_r1->fields[i].val.int_val;
				VAL_TYPE(&(ROW_VALUES(_r)[i])) = DB1_DATETIME;
			break;

			case DB1_BLOB:
				VAL_STR(&(ROW_VALUES(_r)[i])).s =
						_r1->fields[i].val.str_val.s;
				VAL_STR(&(ROW_VALUES(_r)[i])).len =
						_r1->fields[i].val.str_val.len;
				VAL_TYPE(&(ROW_VALUES(_r)[i])) = DB1_BLOB;
				VAL_FREE(&(ROW_VALUES(_r)[i])) = 0;
			break;

			case DB1_BITMAP:
				VAL_INT(&(ROW_VALUES(_r)[i])) =
						_r1->fields[i].val.bitmap_val;
				VAL_TYPE(&(ROW_VALUES(_r)[i])) = DB1_INT;
			break;

			default:
				LM_ERR("val type [%d] not supported", RES_TYPES(_res)[i]);
				return -1;
		}
	}
	return 0;
}
예제 #5
0
/*
 * Query table for specified rows
 * _h: structure representing database connection
 * _k: key names
 * _op: operators
 * _v: values of the keys that must match
 * _c: column names to return
 * _n: number of key=values pairs to compare
 * _nc: number of columns to return
 * _o: order by the specified column
 */
int db_cassa_query(const db1_con_t* _h, const db_key_t* _k, const db_op_t* _op,
		const db_val_t* _v, const db_key_t* _c, int _n, int _nc,
		const db_key_t _o, db1_res_t** _r)
{
	db1_res_t* db_res = 0;
	int rows_no;
	ColumnVecPtr cassa_result;
	dbcassa_table_p tbc;
	int seckey_len;

	if (!_h || !CON_TABLE(_h) || !_r) {
		LM_ERR("invalid parameter value\n");
		return -1;
	}
	LM_DBG("query table=%s\n", _h->table->s);

	/** Construct and send the query to Cassandra Cluster **/

	cassa_result = cassa_translate_query(_h, _k, _v, _c, _n, _nc, &rows_no);

	if(cassa_result.get() == NULL) {
		LM_ERR("Failed to query Cassandra cluster\n");
		return -1;
	}

	/* compare the number of queried cols with the key cols*/
//	if(no_kc + no_sec_kc < _n) { /* TODO */
		/* filter manually for the rest of the values */
//	}

	db_res = db_new_result();
	if (!db_res) {
		LM_ERR("no memory left\n");
		goto error;
	}
	RES_COL_N(db_res)= _nc;
	if(!db_allocate_columns(db_res, _nc) < 0) {
		LM_ERR("no more memory\n");
		goto error;
	}

	tbc = dbcassa_db_get_table(&CON_CASSA(_h)->db_name, CON_TABLE(_h));
	if(!tbc) {
		LM_ERR("table %.*s does not exist!\n", CON_TABLE(_h)->len, CON_TABLE(_h)->s);
		return -1;
	}

	/** Convert the result from Cassandra **/
	/* fill in the columns name and type */
	for(int col = 0; col < _nc; col++) {
		RES_NAMES(db_res)[col] = (str*)pkg_malloc(sizeof(str));
		if (! RES_NAMES(db_res)[col]) {
			LM_ERR("no private memory left\n");
			dbcassa_lock_release(tbc);
			RES_COL_N(db_res) = col;
			db_free_columns(db_res);
			goto error;
		}

		*RES_NAMES(db_res)[col]   = *_c[col];

		/* search the column in table schema to get the type */
		dbcassa_column_p colp = cassa_search_col(tbc, _c[col]);
		if(!colp) {
			LM_ERR("No column with name [%.*s] found\n", _c[col]->len, _c[col]->s);
			dbcassa_lock_release(tbc);
			RES_COL_N(db_res) = col;
			db_free_columns(db_res);
			goto error;
		}
		RES_TYPES(db_res)[col] = colp->type;

		LM_DBG("RES_NAMES(%p)[%d]=[%.*s]\n", RES_NAMES(db_res)[col], col,
				RES_NAMES(db_res)[col]->len, RES_NAMES(db_res)[col]->s);
	}
	/* TODO  if all columns asked - take from table schema */
	seckey_len = tbc->seckey_len;
	dbcassa_lock_release(tbc);

	if(!cassa_result->size()) {
		LM_DBG("The query returned no result\n");
		RES_ROW_N(db_res) = 0;
		goto done;
	}

	/* Initialize the row_slices vector for the case with one column and no secondary key */
	if(rows_no == 1) {
		row_slices[0][0]= cassa_result->size();
		row_slices[0][1]= 0;

		if(seckey_len) { /* if the table has a secondary key defined */
			/* pass through the result once to see how many rows there are */
			rows_no = cassa_result_separate_rows(*cassa_result);
			if(rows_no < 0) {
				LM_ERR("Wrong formated column names\n");
				goto error;
			}
		}
	}

	RES_ROW_N(db_res) = rows_no;

	if (db_allocate_rows(db_res) < 0) {
		LM_ERR("could not allocate rows");
		goto error;
	}

	for(int ri=0; ri < rows_no; ri++) {
		if (db_allocate_row(db_res, &(RES_ROWS(db_res)[ri])) != 0) {
			LM_ERR("could not allocate row");
			goto error;
		}

		/* complete the row with the columns */
		for(int col = 0; col< _nc; col++) {
			RES_ROWS(db_res)[ri].values[col].type = RES_TYPES(db_res)[col];
			cassa_convert_result(_c[col], *cassa_result, (ri>0?row_slices[ri-1][0]:0),  row_slices[ri][0],
					row_slices[ri][1], &RES_ROWS(db_res)[ri].values[col]);
		}
	}

done:
	*_r = db_res;
	LM_DBG("Exited with success\n");
	return 0;

error:
	if(db_res)
		db_free_result(db_res);
	return -1;
}
예제 #6
0
/*!
 * \brief Convert rows from mongodb to db API representation
 * \param _h database connection
 * \param _r database result set
 * \return 0 on success, negative on failure
 */
static int db_mongodb_convert_bson(const db1_con_t* _h, db1_res_t* _r,
		int _row, const bson_t *_rdoc)
{
	static str dummy_string = {"", 0};
	int col;
	db_mongodb_result_t *mgres;
	const char *colname;
	bson_type_t coltype;
	bson_iter_t riter;
	bson_iter_t citer;
	bson_iter_t *piter;
	db_val_t* dval;
	uint32_t i32tmp;
    bson_subtype_t subtype;
	bson_t *cdoc;

	mgres = (db_mongodb_result_t*)RES_PTR(_r);
	if(mgres->nrcols==0) {
		LM_ERR("no fields to convert\n");
		return -1;
	}
	if(mgres->colsdoc==NULL) {
		cdoc = (bson_t*)_rdoc;
	} else {
		cdoc = (bson_t*)mgres->colsdoc;
	}

	if (!bson_iter_init (&citer, cdoc)) {
		LM_ERR("failed to initialize columns iterator\n");
		return -3;
	}
	if(mgres->colsdoc) {
		if (!bson_iter_init (&riter, _rdoc)) {
			LM_ERR("failed to initialize result iterator\n");
			return -3;
		}
	}
	if (db_allocate_row(_r, &(RES_ROWS(_r)[_row])) != 0) {
		LM_ERR("could not allocate row: %d\n", _row);
		return -2;
	}
	col = 0;
	while (bson_iter_next (&citer)) {
		if(col >= RES_COL_N(_r)) {
			LM_ERR("invalid number of columns (%d/%d)\n", col, RES_COL_N(_r));
			return -4;
		}

		colname = bson_iter_key (&citer);
		LM_DBG("looking for field[%d] named: %s\n", col, colname);
		if(mgres->colsdoc) {
			if(!bson_iter_find(&riter, colname)) {
				LM_ERR("field [%s] not found in result iterator\n",
						colname);
				return -4;
			}
			piter = &riter;
		} else {
			piter = &citer;
		}
		coltype = bson_iter_type(piter);

		dval = &(ROW_VALUES(&(RES_ROWS(_r)[_row]))[col]);
		VAL_TYPE(dval) = RES_TYPES(_r)[col];

		switch(coltype) {
			case BSON_TYPE_BOOL:
				VAL_INT(dval) = (int)bson_iter_bool (piter);
				break;
			case BSON_TYPE_INT32:
				VAL_INT(dval) = bson_iter_int32 (piter);
				break;
			case BSON_TYPE_TIMESTAMP:
				bson_iter_timestamp (piter,
						(uint32_t*)&VAL_INT(dval), &i32tmp);
				break;

			case BSON_TYPE_INT64:
				VAL_BIGINT(dval) = bson_iter_int64 (piter);
				break;

			case BSON_TYPE_DOUBLE:
				VAL_DOUBLE(dval) = bson_iter_double (piter);
				break;

			case BSON_TYPE_DATE_TIME:
				VAL_TIME(dval) = (time_t)(bson_iter_date_time (piter)/1000);
				break;

			case BSON_TYPE_BINARY:
				bson_iter_binary (piter, &subtype,
                  (uint32_t*)&VAL_BLOB(dval).len, (const uint8_t**)&VAL_BLOB(dval).s);
				break;

			case BSON_TYPE_UTF8:
				VAL_STRING(dval) = (char*)bson_iter_utf8 (piter, &i32tmp);
				break;

			case BSON_TYPE_OID:
				break;

			case BSON_TYPE_NULL:
				memset(dval, 0, sizeof(db_val_t));
				/* Initialize the string pointers to a dummy empty
				 * string so that we do not crash when the NULL flag
				 * is set but the module does not check it properly
				 */
				VAL_STRING(dval) = dummy_string.s;
				VAL_STR(dval) = dummy_string;
				VAL_BLOB(dval) = dummy_string;
				VAL_TYPE(dval) = RES_TYPES(_r)[col];
				VAL_NULL(dval) = 1;
				break;

#if 0
			case BSON_TYPE_EOD:
			case BSON_TYPE_DOCUMENT:
			case BSON_TYPE_ARRAY:
			case BSON_TYPE_UNDEFINED:
			case BSON_TYPE_REGEX:
			case BSON_TYPE_DBPOINTER:
			case BSON_TYPE_CODE:
			case BSON_TYPE_SYMBOL:
			case BSON_TYPE_CODEWSCOPE:
			case BSON_TYPE_MAXKEY:
			case BSON_TYPE_MINKEY:
#endif

			default:
				LM_WARN("unhandled data type column (%.*s) type id (%d), "
						"use DB1_STRING as default\n", RES_NAMES(_r)[col]->len,
						RES_NAMES(_r)[col]->s, coltype);
				RES_TYPES(_r)[col] = DB1_STRING;
				break;
		}

		LM_DBG("RES_NAMES(%p)[%d]=[%.*s] (%d)\n", RES_NAMES(_r)[col], col,
				RES_NAMES(_r)[col]->len, RES_NAMES(_r)[col]->s, coltype);
		col++;
	}
	return 0;
}
/**
 * Query a table for specified rows.
 * \param _h structure representing database connection
 * \param _k key names
 * \param _op operators
 *\param  _v values of the keys that must match
 * \param _c column names to return
 * \param _n number of key=values pairs to compare
 * \param _nc number of columns to return
 * \param _o order by the specified column
 * \param _r pointer to a structure representing the result
 * \return zero on success, negative value on failure
 */
int erlang_srdb1_query(const db1_con_t* _h, const db_key_t* _k, const db_op_t* _op,
	     const db_val_t* _v, const db_key_t* _c, const int _n, const int _nc,
	     const db_key_t _o, db1_res_t** _r) {
	ei_x_buff argbuf,retbuf;
	int retcode,i,j,x;
	int n_cols,n_rows,len;
	db1_res_t *res;
	db_row_t *rows = NULL, *row;
	db_val_t *val;
	char atom[MAXATOMLEN], *p;
	ei_term term;
	int ei_type,size;
	str *sname;

	if (!_h || !_r) {
		LM_ERR("invalid parameter value\n");
		return -1;
	}
	*_r=NULL;
	LM_DBG("erlang_srdb1_query table %.*s\n",CON_TABLE(_h)->len, CON_TABLE(_h)->s);
	ei_x_new(&argbuf);
	//encode tuple {db_op, table, [cols], [params]}
	ei_x_encode_tuple_header(&argbuf, 5);
	ei_x_encode_atom(&argbuf,"select");
	ei_x_encode_atom_len(&argbuf,CON_TABLE(_h)->s,CON_TABLE(_h)->len);

	srdb1_encode_c(_c, _nc, &argbuf);
	srdb1_encode_k(_k, _op, _v, _n, &argbuf);
//	ei_x_encode_atom_len(&argbuf,_o->s,_o->len);
	ei_x_encode_list_header(&argbuf, 0);

	retcode=erl_bind.do_erlang_call(&(CON_ERLANG(_h)->con),&(CON_ERLANG(_h)->regname), &argbuf, &retbuf);
	ei_x_free(&argbuf);
	if (retcode<0) {
		if(retbuf.buff) shm_free(retbuf.buff);
		return retcode;
	}
	// we have a tuple there:
	ei_decode_tuple_header(retbuf.buff, &(retbuf.index), &i);
	x=retbuf.index;
	ei_skip_term(retbuf.buff, &x);
	LM_DBG("erlang_srdb1_query: position of end of field list should be %d\n",x);
	//first is list of 5-element tuples containing name and type of field
	ei_decode_list_header(retbuf.buff, &(retbuf.index), &n_cols);
	LM_DBG("erlang_srdb1_query: length -f field_list is %d\n",n_cols);
	res=db_new_result();
	if (db_allocate_columns(res, n_cols) != 0) {
		LM_ERR("erlang_srdb1_query: db_allocate_columns failed\n");
		goto error;
	}
	RES_COL_N(res) = n_cols;
	for(i=0; i < n_cols; i++) {
		x=retbuf.index;
		ei_skip_term(retbuf.buff, &x);
		LM_DBG("erlang_srdb1_query: position of end of this field should be %d\n",x);
		ei_decode_tuple_header(retbuf.buff, &(retbuf.index), &j);
		if( j!=5) LM_ERR("erlang_srdb1_query name&type list element tuple is not 5\n");
		ei_decode_atom(retbuf.buff, &(retbuf.index), atom);  //1  name
		len=strlen(atom);
		sname = (str*)pkg_malloc(sizeof(str)+len+1);
		if (!sname) {
			LM_ERR("no private memory left\n");
			goto error;
		}
		sname->len = len;
		sname->s = (char*)sname + sizeof(str);
		memcpy(sname->s, atom, len);
		sname->s[len] = '\0';
		RES_NAMES(res)[i] = sname;
		LM_DBG("decoded header %d, fieled 1: %s\n",i,atom);
		ei_decode_atom(retbuf.buff, &(retbuf.index), atom); //2 type atom
		if(strcmp("int",atom)==0) { RES_TYPES(res)[i]=DB1_INT; }
		if(strcmp("string",atom)==0) { RES_TYPES(res)[i]=DB1_STRING; }
		if(strcmp("float",atom)==0) { RES_TYPES(res)[i]=DB1_DOUBLE; }
		if(strcmp("datetime",atom)==0) { RES_TYPES(res)[i]=DB1_DATETIME; }
//		if(strcmp("string",atom)==0) { RES_TYPES(res)[i]=DB1_BLOB; }
		ei_skip_term(retbuf.buff, &(retbuf.index));  //3 size (ignored)
		ei_skip_term(retbuf.buff, &(retbuf.index));  //4 default value (ignored)
		ei_skip_term(retbuf.buff, &(retbuf.index));  //3 null status (ignored)
		LM_DBG("end of %d record: %d\n",i,retbuf.index);
	}
	ei_decode_ei_term(retbuf.buff, &(retbuf.index), &term); // List tail,
	LM_DBG("erlang_srdb1_query: position after scanning is %d\n",retbuf.index);
	//now rows, list of tuples
	ei_decode_list_header(retbuf.buff, &(retbuf.index), &n_rows);
	LM_DBG("erlang_srdb1_query values list size is %d\n",n_rows);
	if (n_rows<=0) {
		LM_DBG("erlang_srdb1_query no rows returned\n");
		RES_ROWS(res) = NULL;
		RES_NUM_ROWS(res)=0;
		*_r=res;
		return 0;
	}
	RES_NUM_ROWS(res)=n_rows;
	rows = pkg_realloc(rows, sizeof(db_row_t) * n_rows);
	if (rows == NULL) {
		LM_ERR("erlang_srdb1_query: pkg_realloc rows failed\n");
		goto error;
	}
	RES_ROWS(res) = rows;
	for(i=0; i < n_rows; i++) {
		RES_ROW_N(res)=i+1;
		row = &RES_ROWS(res)[i];
		if (db_allocate_row(res, row) != 0) {
			LM_ERR("erlang_srdb1_query: db_allocate_row failed for row %d\n",i);
			goto error;
		}
		ei_decode_tuple_header(retbuf.buff, &(retbuf.index), &j);
		if(j!=n_cols) {
			LM_ERR("erlang_srdb1_query: mismatch:values list element tuple size is %d n_cols from header was %d\n",j, n_cols);
		}
		for (j = 0, val = ROW_VALUES(row); j < RES_COL_N(res); j++, val++) {
			VAL_TYPE(val) = RES_TYPES(res)[j];
			VAL_NULL(val) = 0;
			VAL_FREE(val) = 0;
			retcode=ei_get_type_internal(retbuf.buff, &(retbuf.index), &ei_type, &size);
			if (retcode < 0) {
				LM_ERR("erlang_srdb1_query: error getting type for element %d %d\n",i,j);
				goto error;
			}
			LM_DBG("erlang_srdb1_query: element %d %d ei_type=%d size=%d\n",i,j,ei_type, size);
			switch(ei_type) {
				case ERL_SMALL_INTEGER_EXT:
				case ERL_INTEGER_EXT:
					retcode=ei_decode_long(retbuf.buff, &(retbuf.index), &VAL_INT(val));
					if(retcode < 0) goto error;
					LM_DBG("decoded interger %d\n",VAL_INT(val));
					break;
				case ERL_FLOAT_EXT:
				case NEW_FLOAT_EXT:
					retcode=ei_decode_double(retbuf.buff, &(retbuf.index), &VAL_DOUBLE(val));
					if(retcode < 0) goto error;
					LM_DBG("decoded float %f\n",VAL_DOUBLE(val));
					break;
				case ERL_ATOM_EXT:
				case ERL_SMALL_ATOM_EXT:
				case ERL_ATOM_UTF8_EXT:
				case ERL_SMALL_ATOM_UTF8_EXT:
					p=pkg_malloc(size+1);
					if(!p) { LM_ERR("erlang_srdb1_query: no memory\n"); goto error; }
					retcode=ei_decode_atom(retbuf.buff, &(retbuf.index), p);
					if(retcode < 0) {
						pkg_free(p);
						goto error;
					}
					LM_DBG("decoded small_atom_utf %s\n",p);
					VAL_STRING(val)=p;
					VAL_FREE(val)=1;
					break;
				case ERL_STRING_EXT:
					p=pkg_malloc(size+1);
					if(!p) { LM_ERR("erlang_srdb1_query: no memory\n"); goto error; }
					retcode=ei_decode_string(retbuf.buff, &(retbuf.index), p);
					if(retcode < 0) {
						pkg_free(p);
						goto error;
					}
					LM_DBG("decoded string %s\n",p);
					VAL_STRING(val)=p;
					VAL_FREE(val)=1;
					break;
				case ERL_SMALL_TUPLE_EXT:
				case ERL_LARGE_TUPLE_EXT:
					LM_DBG("got tuple)\n");
					if (VAL_TYPE(val)==DB1_DATETIME) {
					    struct tm tm;
					    LM_DBG("and col type is datetime\n");
					    retcode=ei_decode_tuple_header(retbuf.buff, &(retbuf.index), &x);
					    if(retcode < 0) goto error;
					    retcode=ei_decode_tuple_header(retbuf.buff, &(retbuf.index), &x);
					    if(retcode < 0) goto error;
					    retcode=ei_decode_long(retbuf.buff, &(retbuf.index), (long int *)&tm.tm_year);tm.tm_year -=1900;
					    if(retcode < 0) goto error;
					    retcode=ei_decode_long(retbuf.buff, &(retbuf.index), (long int *)&tm.tm_mon); tm.tm_mon -=1;
					    if(retcode < 0) goto error;
					    retcode=ei_decode_long(retbuf.buff, &(retbuf.index), (long int *)&tm.tm_mday);
					    if(retcode < 0) goto error;
					    retcode=ei_decode_tuple_header(retbuf.buff, &(retbuf.index), &x);
					    if(retcode < 0) goto error;
					    retcode=ei_decode_long(retbuf.buff, &(retbuf.index), (long int *)&tm.tm_hour);
					    if(retcode < 0) goto error;
					    retcode=ei_decode_long(retbuf.buff, &(retbuf.index), (long int *)&tm.tm_min);
					    if(retcode < 0) goto error;
					    retcode=ei_decode_long(retbuf.buff, &(retbuf.index), (long int *)&tm.tm_sec);
					    if(retcode < 0) goto error;
					    VAL_TIME(val)=mktime(&tm);
					    break;
					}
					LM_ERR("erlang_srdb1_query: got tuple but valtype is not datetime element %d in row %d in response\n",j,i);
					break;
				case ERL_REFERENCE_EXT:
				case ERL_NEW_REFERENCE_EXT:
				case ERL_PORT_EXT:
				case ERL_PID_EXT:
				case ERL_NIL_EXT:
				case ERL_LIST_EXT:
				case ERL_BINARY_EXT:
				case ERL_SMALL_BIG_EXT:
				case ERL_LARGE_BIG_EXT:
				case ERL_NEW_FUN_EXT:
				case ERL_FUN_EXT:
				default:
				    LM_ERR("erlang_srdb1_query: don't know how to handle element %d in row %d in response\n",j,i);
			}
		}
	}
	ei_decode_ei_term(retbuf.buff, &(retbuf.index), &term); // List tail,
	*_r=res;
	return 0;
error:
	if (res)
		db_free_result(res);
	LM_ERR("erlang_srdb1_query: Failed\n");
	return -1;
}