/* * Free all memory allocated by get_result */ int bdb_free_result(db_con_t* _h, db_res_t* _r) { db_row_t* r; db_val_t* v; int i, j; if (!_r) { #ifdef BDB_EXTRA_DEBUG LOG(L_NOTICE, "BDB:bdb_free_result: NULL pointer\n"); #endif return 0; } for (i = 0; i < RES_ROW_N(_r); i++) { r = &(RES_ROWS(_r)[i]); for (j = 0; j < RES_COL_N(_r); j++) { v = &(ROW_VALUES(r)[j]); if (VAL_TYPE(v) == DB_STRING || VAL_TYPE(v) == DB_STR || VAL_TYPE(v) == DB_BLOB) { free(VAL_STR(v).s); } } free(ROW_VALUES(r)); } free(RES_ROWS(_r)); for (i = 0; i < RES_COL_N(_r); i++) { pkg_free((void *)RES_NAMES(_r)[i]); } pkg_free(RES_NAMES(_r)); pkg_free(RES_TYPES(_r)); pkg_free(_r); return 0; }
/* * Allocate storage for column names and type in existing * result structure. */ int db_allocate_columns(db1_res_t* _r, const unsigned int cols) { RES_NAMES(_r) = (db_key_t*)pkg_malloc(sizeof(db_key_t) * cols); if (!RES_NAMES(_r)) { LM_ERR("no private memory left\n"); return -1; } memset(RES_NAMES(_r), 0, sizeof(db_key_t) * cols); LM_DBG("allocate %d bytes for result names at %p\n", (int)(sizeof(db_key_t) * cols), RES_NAMES(_r)); RES_TYPES(_r) = (db_type_t*)pkg_malloc(sizeof(db_type_t) * cols); if (!RES_TYPES(_r)) { LM_ERR("no private memory left\n"); pkg_free(RES_NAMES(_r)); return -1; } memset(RES_TYPES(_r), 0, sizeof(db_type_t) * cols); LM_DBG("allocate %d bytes for result types at %p\n", (int)(sizeof(db_type_t) * cols), RES_TYPES(_r)); return 0; }
/* * Get and convert columns from a result */ int dbt_get_columns(db_con_t* _h, db_res_t* _r) { int n, i; if ((!_h) || (!_r)) { #ifdef DBT_EXTRA_DEBUG LOG(L_ERR, "DBT:dbt_get_columns: Invalid parameter\n"); #endif return -1; } n = DBT_CON_RESULT(_h)->nrcols; if (!n) { LOG(L_ERR, "DBT:get_columns: No columns\n"); return -2; } RES_NAMES(_r) = (db_key_t*)pkg_malloc(sizeof(db_key_t) * n); if (!RES_NAMES(_r)) { LOG(L_ERR, "DBT:get_columns: No memory left\n"); return -3; } RES_TYPES(_r) = (db_type_t*)pkg_malloc(sizeof(db_type_t) * n); if (!RES_TYPES(_r)) { LOG(L_ERR, "DBT:get_columns: No memory left\n"); pkg_free(RES_NAMES(_r)); return -4; } RES_COL_N(_r) = n; for(i = 0; i < n; i++) { RES_NAMES(_r)[i] = DBT_CON_RESULT(_h)->colv[i].name.s; switch( DBT_CON_RESULT(_h)->colv[i].type) { case DB_INT: case DB_DATETIME: RES_TYPES(_r)[i] = DB_INT; break; case DB_DOUBLE: RES_TYPES(_r)[i] = DB_DOUBLE; break; default: RES_TYPES(_r)[i] = DB_STR; break; } } return 0; }
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 (pv == NULL) { LM_ERR("Missing pv spec for column %d\n", j+1); goto error; } if (db_val2pv_spec(msg, &RES_ROWS(db_res)[i].values[j], &pv->sname) != 0) { LM_ERR("Failed to convert value for column %.*s (row %d)\n", RES_NAMES(db_res)[j]->len, RES_NAMES(db_res)[j]->s, i); 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; }
/* * Generate AVPs from the database result */ static int generate_avps(struct sip_msg* msg, db1_res_t* db_res) { pv_elem_t *cred; int i; for (cred=credentials, i=1; cred; cred=cred->next, i++) { if (db_val2pv_spec(msg, &RES_ROWS(db_res)[0].values[i], cred->spec) != 0) { LM_ERR("Failed to convert value for column %.*s\n", RES_NAMES(db_res)[i]->len, RES_NAMES(db_res)[i]->s); return -1; } } return 0; }
/* * Release memory used by columns */ int db_free_columns(db1_res_t* _r) { int col; if (!_r) { LM_ERR("invalid parameter value\n"); return -1; } LM_DBG("freeing %d columns\n", RES_COL_N(_r)); /* free memory previously allocated to save column names */ for(col = 0; col < RES_COL_N(_r); col++) { if (RES_NAMES(_r)[col]!=NULL) { LM_DBG("freeing RES_NAMES[%d] at %p\n", col, RES_NAMES(_r)[col]); pkg_free((str *)RES_NAMES(_r)[col]); RES_NAMES(_r)[col] = NULL; } } RES_COL_N(_r) = 0; /* free names and types */ if (RES_NAMES(_r)) { LM_DBG("freeing result names at %p\n", RES_NAMES(_r)); pkg_free(RES_NAMES(_r)); RES_NAMES(_r) = NULL; } if (RES_TYPES(_r)) { LM_DBG("freeing result types at %p\n", RES_TYPES(_r)); pkg_free(RES_TYPES(_r)); RES_TYPES(_r) = NULL; } return 0; }
/* * Release memory used by columns */ int db_free_columns(db_res_t* _r) { if (!_r) { LM_ERR("invalid parameter value\n"); return -1; } /* free names and types */ if (RES_NAMES(_r)) { LM_DBG("freeing result columns at %p\n", RES_NAMES(_r)); RES_TYPES(_r) = NULL; pkg_free(RES_NAMES(_r)); RES_NAMES(_r) = NULL; } return 0; }
/* * Release memory used by columns */ int dbt_free_columns(db_res_t* _r) { if (!_r) { #ifdef DBT_EXTRA_DEBUG LOG(L_ERR, "DBT:dbt_free_columns: Invalid parameter\n"); #endif return -1; } if (RES_NAMES(_r)) pkg_free(RES_NAMES(_r)); if (RES_TYPES(_r)) pkg_free(RES_TYPES(_r)); return 0; }
/** * This function check the CQLresult of the CQL query and * adds the columns to the returning result structure. * * \param _cql_res handle for the CQLResult * \param _r result set for storage * \return zero on success, negative value on failure */ int cql_get_columns(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 = 0; LM_DBG("cqlrow Vector size =%d\n", rows_no); if (rows_no > 0) { cols_no = res_cql_rows[0].columns.size(); LM_DBG("There are %d columns available, this should be the case for all %d rows (consider cql).\n", cols_no, rows_no); } else { LM_DBG("Got 0 rows. There is no result from the query.\n"); return 0; } RES_COL_N(_r) = cols_no; if (!RES_COL_N(_r)) { LM_ERR("no columns returned from the query\n"); return -2; } else { LM_DBG("%d columns returned from the query\n", RES_COL_N(_r)); } if (db_allocate_columns(_r, RES_COL_N(_r)) != 0) { LM_ERR("Could not allocate columns\n"); return -3; } /* For fields we will use the columns inside the first columns */ for(int col = 0; col < RES_COL_N(_r); col++) { RES_NAMES(_r)[col] = (str*)pkg_malloc(sizeof(str)); if (! RES_NAMES(_r)[col]) { LM_ERR("no private memory left\n"); RES_COL_N(_r) = col; db_free_columns(_r); return -4; } LM_DBG("Allocated %lu bytes for RES_NAMES[%d] at %p\n", (unsigned long)sizeof(str), col, RES_NAMES(_r)[col]); /* The pointer that is here returned is part of the result structure. */ RES_NAMES(_r)[col]->s = (char*) res_cql_rows[0].columns[col].name.c_str(); RES_NAMES(_r)[col]->len = strlen(RES_NAMES(_r)[col]->s); RES_TYPES(_r)[col] = DB1_STR; LM_DBG("RES_NAMES(%p)[%d]=[%.*s]\n", RES_NAMES(_r)[col], col, RES_NAMES(_r)[col]->len, RES_NAMES(_r)[col]->s); } return 0; }
int bdb_get_columns(table_p _tp, db_res_t* _res, int* _lres, int _nc) { int col; if (!_res) { LM_ERR("invalid parameter\n"); return -1; } if (_nc < 0 ) { LM_ERR("_nc parameter cannot be negative \n"); return -1; } /* the number of rows (tuples) in the query result. */ RES_NUM_ROWS(_res) = 1; if (!_lres) _nc = _tp->ncols; /* Save number of columns in the result structure */ RES_COL_N(_res) = _nc; if (db_allocate_columns(_res, RES_COL_N(_res)) != 0) { LM_ERR("could not allocate columns"); return -2; } /* * For each column both the name and the data type are saved. */ for(col = 0; col < RES_COL_N(_res); col++) { column_p cp = NULL; cp = (_lres) ? _tp->colp[_lres[col]] : _tp->colp[col]; /* The pointer that is here returned is part of the result structure.*/ RES_NAMES(_res)[col]->s = cp->name.s; RES_NAMES(_res)[col]->len = cp->name.len; LM_DBG("RES_NAMES(%p)[%d]=[%.*s]\n", RES_NAMES(_res)[col] , col, RES_NAMES(_res)[col]->len, RES_NAMES(_res)[col]->s); RES_TYPES(_res)[col] = cp->type; } return 0; }
/* * Get and convert columns from a result */ static int dbt_get_columns(db_con_t* _h, db_res_t* _r) { int col; if (!_h || !_r) { LM_ERR("invalid parameter\n"); return -1; } RES_COL_N(_r) = DBT_CON_RESULT(_h)->nrcols; if (!RES_COL_N(_r)) { LM_ERR("no columns\n"); return -2; } if (db_allocate_columns(_r, RES_COL_N(_r)) != 0) { LM_ERR("could not allocate columns\n"); return -3; } for(col = 0; col < RES_COL_N(_r); col++) { RES_NAMES(_r)[col]->s = DBT_CON_RESULT(_h)->colv[col].name.s; RES_NAMES(_r)[col]->len = DBT_CON_RESULT(_h)->colv[col].name.len; switch(DBT_CON_RESULT(_h)->colv[col].type) { case DB_STR: case DB_STRING: case DB_BLOB: case DB_INT: case DB_BIGINT: case DB_DATETIME: case DB_DOUBLE: RES_TYPES(_r)[col] = DBT_CON_RESULT(_h)->colv[col].type; break; default: LM_WARN("unhandled data type column (%.*s) type id (%d), " "use STR as default\n", RES_NAMES(_r)[col]->len, RES_NAMES(_r)[col]->s, DBT_CON_RESULT(_h)->colv[col].type); RES_TYPES(_r)[col] = DB_STR; break; } } return 0; }
/* * Get and convert columns from a result */ static int dbt_get_columns(db1_res_t* _r, dbt_result_p _dres) { int col; if (!_r || !_dres) { LM_ERR("invalid parameter\n"); return -1; } RES_COL_N(_r) = _dres->nrcols; if (!RES_COL_N(_r)) { LM_ERR("no columns\n"); return -2; } if (db_allocate_columns(_r, RES_COL_N(_r)) != 0) { LM_ERR("could not allocate columns"); return -3; } for(col = 0; col < RES_COL_N(_r); col++) { /* * Its would be not necessary to allocate here new memory, because of * the internal structure of the db_text module. But we do this anyway * to stay confirm to the other database modules. */ RES_NAMES(_r)[col] = (str*)pkg_malloc(sizeof(str)); if (! RES_NAMES(_r)[col]) { LM_ERR("no private memory left\n"); db_free_columns(_r); return -4; } LM_DBG("allocate %d bytes for RES_NAMES[%d] at %p", (int)sizeof(str), col, RES_NAMES(_r)[col]); RES_NAMES(_r)[col]->s = _dres->colv[col].name.s; RES_NAMES(_r)[col]->len = _dres->colv[col].name.len; switch(_dres->colv[col].type) { case DB1_STR: case DB1_STRING: case DB1_BLOB: case DB1_INT: case DB1_DATETIME: case DB1_DOUBLE: RES_TYPES(_r)[col] = _dres->colv[col].type; break; default: LM_WARN("unhandled data type column (%.*s) type id (%d), " "use STR as default\n", RES_NAMES(_r)[col]->len, RES_NAMES(_r)[col]->s, _dres->colv[col].type); RES_TYPES(_r)[col] = DB1_STR; break; } } return 0; }
/* * Release a result set from memory */ int db_oracle_free_result(db_con_t* _h, db_res_t* _r) { ub4 i; if (!_h || !_r) { LM_ERR("invalid parameter value\n"); return -1; } if (RES_NAMES(_r)) for (i=0; i < RES_COL_N(_r); ++i) if (RES_NAMES(_r)[i]->s) pkg_free(RES_NAMES(_r)[i]->s); if (db_free_result(_r) < 0) { LM_ERR("failed to free result structure\n"); return -1; } return 0; }
static int print_res(db_res_t* _r) { int i, j; for(i = 0; i < RES_COL_N(_r); i++) { printf("%s ", RES_NAMES(_r)[i]); } printf("\n"); for(i = 0; i < RES_ROW_N(_r); i++) { for(j = 0; j < RES_COL_N(_r); j++) { if (RES_ROWS(_r)[i].values[j].nul == TRUE) { printf("NULL "); continue; } switch(RES_ROWS(_r)[i].values[j].type) { case DB_INT: printf("%d ", RES_ROWS(_r)[i].values[j].val.int_val); break; case DB_DOUBLE: printf("%f ", RES_ROWS(_r)[i].values[j].val.double_val); break; case DB_DATETIME: printf("%s ", ctime(&(RES_ROWS(_r)[i].values[j].val.time_val))); break; case DB_STRING: printf("%s ", RES_ROWS(_r)[i].values[j].val.string_val); break; case DB_STR: printf("%.*s ", RES_ROWS(_r)[i].values[j].val.str_val.len, RES_ROWS(_r)[i].values[j].val.str_val.s); break; case DB_BLOB: printf("%.*s ", RES_ROWS(_r)[i].values[j].val.blob_val.len, RES_ROWS(_r)[i].values[j].val.blob_val.s); break; case DB_BITMAP: printf("%d ", RES_ROWS(_r)[i].values[j].val.bitmap_val); break; } } printf("\n"); } return TRUE; }
/* * Create a new result structure and initialize it */ db_res_t* dbt_new_result(void) { db_res_t* r; r = (db_res_t*)pkg_malloc(sizeof(db_res_t)); if (!r) { LOG(L_ERR, "new_result(): No memory left\n"); return 0; } RES_NAMES(r) = 0; RES_TYPES(r) = 0; RES_COL_N(r) = 0; RES_ROWS(r) = 0; RES_ROW_N(r) = 0; return r; }
/* * Release a result set from memory */ int perlvdb_db_free_result(db_con_t* _h, db_res_t* _r) { int i,j; SV* temp; /* free result set * use the order of allocation * first free values */ if(_r){ /* for each row */ for(i=0; i < RES_ROW_N(_r); i++){ /* for each column in row i */ for(j=0; j < RES_ROWS(_r)[i].n; j++){ switch ( (RES_ROWS(_r)[i].values)[j].type ) { /* the type of a value j in row i */ case DB_STRING: case DB_STR: pkg_free((RES_ROWS(_r)[i].values)[j].val.str_val.s); break; case DB_BLOB: pkg_free((RES_ROWS(_r)[i].values)[j].val.blob_val.s) ; break; case DB_INT: case DB_BIGINT: case DB_DOUBLE: case DB_BITMAP: case DB_DATETIME: break; } } /* for each column in row i*/ } /* for each row */ for(i=0; i< RES_COL_N(_r); i++){ pkg_free(RES_NAMES(_r)[i]->s); } db_free_result(_r); } return 0; }
/* * Allocate storage for column names and type in existing * result structure. */ int db_allocate_columns(db_res_t* _r, const unsigned int cols) { unsigned int i; RES_NAMES(_r) = (db_key_t*)pkg_malloc ( cols * (sizeof(db_key_t)+sizeof(db_type_t)+sizeof(str)) ); if (!RES_NAMES(_r)) { LM_ERR("no private memory left\n"); return -1; } LM_DBG("allocate %d bytes for result columns at %p\n", (int)(cols * (sizeof(db_key_t)+sizeof(db_type_t)+sizeof(str))), RES_NAMES(_r)); for ( i=0 ; i<cols ; i++) RES_NAMES(_r)[i] = (str*)(RES_NAMES(_r)+cols)+i; RES_TYPES(_r) = (db_type_t*)(RES_NAMES(_r)[0]+cols); return 0; }
/*! * \brief Get and convert columns from a result * * Get and convert columns from a result, fills the result structure * with data from the database. * \param _h database connection * \param _r database result set * \return 0 on success, negative on failure */ int db_mysql_get_columns(const db1_con_t* _h, db1_res_t* _r) { int col; MYSQL_FIELD* fields; if ((!_h) || (!_r)) { LM_ERR("invalid parameter\n"); return -1; } RES_COL_N(_r) = mysql_field_count(CON_CONNECTION(_h)); if (!RES_COL_N(_r)) { LM_ERR("no columns returned from the query\n"); return -2; } else { LM_DBG("%d columns returned from the query\n", RES_COL_N(_r)); } if (db_allocate_columns(_r, RES_COL_N(_r)) != 0) { RES_COL_N(_r) = 0; LM_ERR("could not allocate columns\n"); return -3; } fields = mysql_fetch_fields(RES_RESULT(_r)); for(col = 0; col < RES_COL_N(_r); col++) { RES_NAMES(_r)[col] = (str*)pkg_malloc(sizeof(str)); if (! RES_NAMES(_r)[col]) { LM_ERR("no private memory left\n"); db_free_columns(_r); return -4; } LM_DBG("allocate %lu bytes for RES_NAMES[%d] at %p\n", (unsigned long)sizeof(str), col, RES_NAMES(_r)[col]); /* The pointer that is here returned is part of the result structure. */ RES_NAMES(_r)[col]->s = fields[col].name; RES_NAMES(_r)[col]->len = strlen(fields[col].name); LM_DBG("RES_NAMES(%p)[%d]=[%.*s]\n", RES_NAMES(_r)[col], col, RES_NAMES(_r)[col]->len, RES_NAMES(_r)[col]->s); switch(fields[col].type) { case MYSQL_TYPE_TINY: case MYSQL_TYPE_SHORT: case MYSQL_TYPE_LONG: case MYSQL_TYPE_INT24: case MYSQL_TYPE_TIMESTAMP: LM_DBG("use DB1_INT result type\n"); RES_TYPES(_r)[col] = DB1_INT; break; case MYSQL_TYPE_LONGLONG: LM_DBG("use DB1_BIGINT result type\n"); RES_TYPES(_r)[col] = DB1_BIGINT; break; case MYSQL_TYPE_FLOAT: case MYSQL_TYPE_DOUBLE: LM_DBG("use DB1_DOUBLE result type\n"); RES_TYPES(_r)[col] = DB1_DOUBLE; break; case MYSQL_TYPE_DATETIME: LM_DBG("use DB1_DATETIME result type\n"); RES_TYPES(_r)[col] = DB1_DATETIME; break; case MYSQL_TYPE_BLOB: LM_DBG("use DB1_BLOB result type\n"); RES_TYPES(_r)[col] = DB1_BLOB; break; case FIELD_TYPE_SET: LM_DBG("use DB1_BITMAP result type\n"); RES_TYPES(_r)[col] = DB1_BITMAP; break; case MYSQL_TYPE_DECIMAL: #if MYSQL_VERSION_ID > 49999 case MYSQL_TYPE_NEWDECIMAL: #endif case MYSQL_TYPE_STRING: case MYSQL_TYPE_VAR_STRING: LM_DBG("use DB1_STRING result type\n"); RES_TYPES(_r)[col] = DB1_STRING; break; 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, fields[col].type); RES_TYPES(_r)[col] = DB1_STRING; break; } } return 0; }
int sql_do_query(sql_con_t *con, str *query, sql_result_t *res) { db1_res_t* db_res = NULL; int i, j; str sv; if(res) sql_reset_result(res); if(query==NULL) { LM_ERR("bad parameters\n"); return -1; } if(con->dbf.raw_query(con->dbh, query, &db_res)!=0) { LM_ERR("cannot do the query [%.*s]\n", (query->len>32)?32:query->len, query->s); 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; } if(!res) { LM_DBG("no sqlresult parameter, ignoring result from query\n"); con->dbf.free_result(con->dbh, db_res); return 3; } res->ncols = RES_COL_N(db_res); res->nrows = RES_ROW_N(db_res); LM_DBG("rows [%d] cols [%d]\n", res->nrows, res->ncols); res->cols = (sql_col_t*)pkg_malloc(res->ncols*sizeof(sql_col_t)); if(res->cols==NULL) { res->ncols = 0; res->nrows = 0; LM_ERR("no more memory\n"); return -1; } memset(res->cols, 0, res->ncols*sizeof(sql_col_t)); for(i=0; i<res->ncols; i++) { res->cols[i].name.len = (RES_NAMES(db_res)[i])->len; res->cols[i].name.s = (char*)pkg_malloc((res->cols[i].name.len+1) *sizeof(char)); if(res->cols[i].name.s==NULL) { LM_ERR("no more memory\n"); goto error; } memcpy(res->cols[i].name.s, RES_NAMES(db_res)[i]->s, res->cols[i].name.len); res->cols[i].name.s[res->cols[i].name.len]='\0'; res->cols[i].colid = core_case_hash(&res->cols[i].name, 0, 0); } res->vals = (sql_val_t**)pkg_malloc(res->nrows*sizeof(sql_val_t*)); if(res->vals==NULL) { LM_ERR("no more memory\n"); goto error; } memset(res->vals, 0, res->nrows*sizeof(sql_val_t*)); for(i=0; i<res->nrows; i++) { res->vals[i] = (sql_val_t*)pkg_malloc(res->ncols*sizeof(sql_val_t)); if(res->vals[i]==NULL) { LM_ERR("no more memory\n"); goto error; } memset(res->vals[i], 0, res->ncols*sizeof(sql_val_t)); for(j=0; j<res->ncols; j++) { if(RES_ROWS(db_res)[i].values[j].nul) { res->vals[i][j].flags = PV_VAL_NULL; continue; } sv.s = NULL; sv.len = 0; switch(RES_ROWS(db_res)[i].values[j].type) { case DB1_STRING: res->vals[i][j].flags = PV_VAL_STR; sv.s= (char*)RES_ROWS(db_res)[i].values[j].val.string_val; sv.len=strlen(sv.s); break; case DB1_STR: res->vals[i][j].flags = PV_VAL_STR; sv.len= RES_ROWS(db_res)[i].values[j].val.str_val.len; sv.s= (char*)RES_ROWS(db_res)[i].values[j].val.str_val.s; break; case DB1_BLOB: res->vals[i][j].flags = PV_VAL_STR; sv.len= RES_ROWS(db_res)[i].values[j].val.blob_val.len; sv.s= (char*)RES_ROWS(db_res)[i].values[j].val.blob_val.s; break; case DB1_INT: res->vals[i][j].flags = PV_VAL_INT; res->vals[i][j].value.n = (int)RES_ROWS(db_res)[i].values[j].val.int_val; break; case DB1_DATETIME: res->vals[i][j].flags = PV_VAL_INT; res->vals[i][j].value.n = (int)RES_ROWS(db_res)[i].values[j].val.time_val; break; case DB1_BITMAP: res->vals[i][j].flags = PV_VAL_INT; res->vals[i][j].value.n = (int)RES_ROWS(db_res)[i].values[j].val.bitmap_val; break; case DB1_BIGINT: res->vals[i][j].flags = PV_VAL_STR; res->vals[i][j].value.s.len = 21*sizeof(char); res->vals[i][j].value.s.s = (char*)pkg_malloc(res->vals[i][j].value.s.len); if(res->vals[i][j].value.s.s==NULL) { LM_ERR("no more memory\n"); goto error; } db_longlong2str(RES_ROWS(db_res)[i].values[j].val.ll_val, res->vals[i][j].value.s.s, &res->vals[i][j].value.s.len); break; default: res->vals[i][j].flags = PV_VAL_NULL; } if(res->vals[i][j].flags == PV_VAL_STR && sv.s) { if(sv.len<=0) { res->vals[i][j].value.s.s = _sql_empty_buf; res->vals[i][j].value.s.len = 0; continue; } res->vals[i][j].value.s.s = (char*)pkg_malloc(sv.len*sizeof(char)); if(res->vals[i][j].value.s.s==NULL) { LM_ERR("no more memory\n"); goto error; } memcpy(res->vals[i][j].value.s.s, sv.s, sv.len); res->vals[i][j].value.s.len = sv.len; } } } con->dbf.free_result(con->dbh, db_res); return 1; error: con->dbf.free_result(con->dbh, db_res); sql_reset_result(res); return -1; }
/* * Get and convert columns from a result */ int db_mysql_get_columns(db_con_t* _h, db_res_t* _r) { int n, i; MYSQL_FIELD* fields; if ((!_h) || (!_r)) { LM_ERR("invalid parameter\n"); return -1; } n = mysql_field_count(CON_CONNECTION(_h)); if (!n) { LM_ERR("no columns\n"); return -2; } RES_NAMES(_r) = (db_key_t*)pkg_malloc(sizeof(db_key_t) * n); if (!RES_NAMES(_r)) { LM_ERR("no private memory left\n"); return -3; } RES_TYPES(_r) = (db_type_t*)pkg_malloc(sizeof(db_type_t) * n); if (!RES_TYPES(_r)) { LM_ERR("no private memory left\n"); pkg_free(RES_NAMES(_r)); return -4; } RES_COL_N(_r) = n; fields = mysql_fetch_fields(CON_RESULT(_h)); for(i = 0; i < n; i++) { RES_NAMES(_r)[i] = fields[i].name; switch(fields[i].type) { case FIELD_TYPE_TINY: case FIELD_TYPE_SHORT: case FIELD_TYPE_LONG: case FIELD_TYPE_INT24: case FIELD_TYPE_LONGLONG: case FIELD_TYPE_DECIMAL: case FIELD_TYPE_TIMESTAMP: RES_TYPES(_r)[i] = DB_INT; break; case FIELD_TYPE_FLOAT: case FIELD_TYPE_DOUBLE: RES_TYPES(_r)[i] = DB_DOUBLE; break; case FIELD_TYPE_DATETIME: RES_TYPES(_r)[i] = DB_DATETIME; break; case FIELD_TYPE_BLOB: case FIELD_TYPE_TINY_BLOB: case FIELD_TYPE_MEDIUM_BLOB: case FIELD_TYPE_LONG_BLOB: RES_TYPES(_r)[i] = DB_BLOB; break; case FIELD_TYPE_SET: RES_TYPES(_r)[i] = DB_BITMAP; break; default: RES_TYPES(_r)[i] = DB_STRING; break; } } return 0; }
/** * Get and convert columns from a result */ int db_mysql_get_columns(const db_con_t* _h, db_res_t* _r) { int col; MYSQL_FIELD* fields; if ((!_h) || (!_r)) { LM_ERR("invalid parameter\n"); return -1; } if (CON_HAS_PS(_h)) { RES_COL_N(_r) = CON_MYSQL_PS(_h)->cols_out; } else { RES_COL_N(_r) = mysql_field_count(CON_CONNECTION(_h)); } if (!RES_COL_N(_r)) { LM_ERR("no columns returned from the query\n"); return -2; } else { LM_DBG("%d columns returned from the query\n", RES_COL_N(_r)); } if (db_allocate_columns(_r, RES_COL_N(_r)) != 0) { LM_ERR("could not allocate columns\n"); return -3; } fields = mysql_fetch_fields(CON_RESULT(_h)); for(col = 0; col < RES_COL_N(_r); col++) { /* The pointer that is here returned is part of the result structure */ RES_NAMES(_r)[col]->s = fields[col].name; RES_NAMES(_r)[col]->len = strlen(fields[col].name); LM_DBG("RES_NAMES(%p)[%d]=[%.*s]\n", RES_NAMES(_r)[col], col, RES_NAMES(_r)[col]->len, RES_NAMES(_r)[col]->s); switch(fields[col].type) { case MYSQL_TYPE_TINY: case MYSQL_TYPE_SHORT: case MYSQL_TYPE_LONG: case MYSQL_TYPE_INT24: case MYSQL_TYPE_DECIMAL: #if MYSQL_VERSION_ID > 49999 case MYSQL_TYPE_NEWDECIMAL: #endif case MYSQL_TYPE_TIMESTAMP: LM_DBG("use DB_INT result type\n"); RES_TYPES(_r)[col] = DB_INT; break; case MYSQL_TYPE_FLOAT: case MYSQL_TYPE_DOUBLE: LM_DBG("use DB_DOUBLE result type\n"); RES_TYPES(_r)[col] = DB_DOUBLE; break; case MYSQL_TYPE_DATETIME: case MYSQL_TYPE_DATE: LM_DBG("use DB_DATETIME result type\n"); RES_TYPES(_r)[col] = DB_DATETIME; break; case MYSQL_TYPE_TINY_BLOB: case MYSQL_TYPE_MEDIUM_BLOB: case MYSQL_TYPE_LONG_BLOB: case MYSQL_TYPE_BLOB: LM_DBG("use DB_BLOB result type\n"); RES_TYPES(_r)[col] = DB_BLOB; break; case FIELD_TYPE_SET: LM_DBG("use DB_BITMAP result type\n"); RES_TYPES(_r)[col] = DB_BITMAP; break; case MYSQL_TYPE_STRING: case MYSQL_TYPE_VAR_STRING: LM_DBG("use DB_STRING result type\n"); RES_TYPES(_r)[col] = DB_STRING; break; case MYSQL_TYPE_LONGLONG: LM_DBG("use DB_BIGINT result type\n"); RES_TYPES(_r)[col] = DB_BIGINT; break; default: LM_WARN("unhandled data type column (%.*s) type id (%d), " "use DB_STRING as default\n", RES_NAMES(_r)[col]->len, RES_NAMES(_r)[col]->s, fields[col].type); RES_TYPES(_r)[col] = DB_STRING; break; } } return 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; }
/* * Get and convert columns from a result */ int db_unixodbc_get_columns(const db1_con_t* _h, db1_res_t* _r) { int col; SQLSMALLINT cols; /* because gcc don't like RES_COL_N */ if ((!_h) || (!_r)) { LM_ERR("invalid parameter\n"); return -1; } /* Save number of columns in the result structure */ SQLNumResultCols(CON_RESULT(_h), &cols); RES_COL_N(_r) = cols; if (!RES_COL_N(_r)) { LM_ERR("no columns returned from the query\n"); return -2; } else { LM_DBG("%d columns returned from the query\n", RES_COL_N(_r)); } if (db_allocate_columns(_r, RES_COL_N(_r)) != 0) { LM_ERR("could not allocate columns\n"); return -3; } for(col = 0; col < RES_COL_N(_r); col++) { RES_NAMES(_r)[col] = (str*)pkg_malloc(sizeof(str)); if (! RES_NAMES(_r)[col]) { LM_ERR("no private memory left\n"); db_free_columns(_r); return -4; } LM_DBG("allocate %lu bytes for RES_NAMES[%d] at %p\n", (unsigned long)sizeof(str),col, RES_NAMES(_r)[col]); char columnname[80]; SQLRETURN ret; SQLSMALLINT namelength, datatype, decimaldigits, nullable; SQLULEN columnsize; ret = SQLDescribeCol(CON_RESULT(_h), col + 1, (SQLCHAR *)columnname, 80, &namelength, &datatype, &columnsize, &decimaldigits, &nullable); if(!SQL_SUCCEEDED(ret)) { LM_ERR("SQLDescribeCol failed: %d\n", ret); db_unixodbc_extract_error("SQLExecDirect", CON_RESULT(_h), SQL_HANDLE_STMT, NULL); // FIXME should we fail here completly? } /* The pointer that is here returned is part of the result structure. */ RES_NAMES(_r)[col]->s = columnname; RES_NAMES(_r)[col]->len = namelength; LM_DBG("RES_NAMES(%p)[%d]=[%.*s]\n", RES_NAMES(_r)[col], col, RES_NAMES(_r)[col]->len, RES_NAMES(_r)[col]->s); switch(datatype) { case SQL_SMALLINT: case SQL_INTEGER: case SQL_TINYINT: case SQL_DECIMAL: case SQL_NUMERIC: LM_DBG("use DB1_INT result type\n"); RES_TYPES(_r)[col] = DB1_INT; break; case SQL_BIGINT: LM_DBG("use DB1_BIGINT result type\n"); RES_TYPES(_r)[col] = DB1_BIGINT; break; case SQL_REAL: case SQL_FLOAT: case SQL_DOUBLE: LM_DBG("use DB1_DOUBLE result type\n"); RES_TYPES(_r)[col] = DB1_DOUBLE; break; case SQL_TYPE_TIMESTAMP: case SQL_DATE: case SQL_TIME: case SQL_TIMESTAMP: case SQL_TYPE_DATE: case SQL_TYPE_TIME: LM_DBG("use DB1_DATETIME result type\n"); RES_TYPES(_r)[col] = DB1_DATETIME; break; case SQL_CHAR: case SQL_VARCHAR: case SQL_WCHAR: case SQL_WVARCHAR: LM_DBG("use DB1_STRING result type\n"); RES_TYPES(_r)[col] = DB1_STRING; break; case SQL_BINARY: case SQL_VARBINARY: case SQL_LONGVARBINARY: case SQL_BIT: case SQL_LONGVARCHAR: case SQL_WLONGVARCHAR: LM_DBG("use DB1_BLOB result type\n"); RES_TYPES(_r)[col] = DB1_BLOB; break; 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, datatype); RES_TYPES(_r)[col] = DB1_STRING; break; } } return 0; }
/** * Get and convert columns from a result set */ int db_postgres_get_columns(const db_con_t* _h, db_res_t* _r) { int col, datatype; if (!_h || !_r) { LM_ERR("invalid parameter value\n"); return -1; } /* Get the number of rows (tuples) in the query result. */ RES_ROW_N(_r) = PQntuples(CON_RESULT(_h)); /* Get the number of columns (fields) in each row of the query result. */ RES_COL_N(_r) = PQnfields(CON_RESULT(_h)); if (!RES_COL_N(_r)) { LM_DBG("no columns returned from the query\n"); return -2; } else { LM_DBG("%d columns returned from the query\n", RES_COL_N(_r)); } if (db_allocate_columns(_r, RES_COL_N(_r)) != 0) { LM_ERR("could not allocate columns\n"); return -3; } /* For each column both the name and the OID number of the * data type are saved. */ for(col = 0; col < RES_COL_N(_r); col++) { /* The pointer that is here returned is part of the result structure.*/ RES_NAMES(_r)[col]->s = PQfname(CON_RESULT(_h), col); RES_NAMES(_r)[col]->len = strlen(PQfname(CON_RESULT(_h), col)); LM_DBG("RES_NAMES(%p)[%d]=[%.*s]\n", RES_NAMES(_r)[col], col, RES_NAMES(_r)[col]->len, RES_NAMES(_r)[col]->s); /* get the datatype of the column */ switch(datatype = PQftype(CON_RESULT(_h),col)) { case INT2OID: case INT4OID: case INT8OID: LM_DBG("use DB_INT result type\n"); RES_TYPES(_r)[col] = DB_INT; break; case FLOAT4OID: case FLOAT8OID: case NUMERICOID: LM_DBG("use DB_DOUBLE result type\n"); RES_TYPES(_r)[col] = DB_DOUBLE; break; case DATEOID: case TIMESTAMPOID: case TIMESTAMPTZOID: LM_DBG("use DB_DATETIME result type\n"); RES_TYPES(_r)[col] = DB_DATETIME; break; case BOOLOID: case CHAROID: case VARCHAROID: case BPCHAROID: LM_DBG("use DB_STRING result type\n"); RES_TYPES(_r)[col] = DB_STRING; break; case TEXTOID: case BYTEAOID: LM_DBG("use DB_BLOB result type\n"); RES_TYPES(_r)[col] = DB_BLOB; break; case BITOID: case VARBITOID: LM_DBG("use DB_BITMAP result type\n"); RES_TYPES(_r)[col] = DB_BITMAP; break; default: LM_WARN("unhandled data type column (%.*s) type id (%d), " "use DB_STRING as default\n", RES_NAMES(_r)[col]->len, RES_NAMES(_r)[col]->s, datatype); RES_TYPES(_r)[col] = DB_STRING; break; } } return 0; }
int fetch_credentials(sip_msg_t *msg, str *user, str* domain, str *table, int flags) { pv_elem_t *cred; db_key_t keys[2]; db_val_t vals[2]; db_key_t *col; db1_res_t *res = NULL; int n, nc; if(flags&AUTH_DB_SUBS_SKIP_CREDENTIALS) { nc = 1; } else { nc = credentials_n; } col = pkg_malloc(sizeof(*col) * (nc+1)); if (col == NULL) { LM_ERR("no more pkg memory\n"); return -1; } keys[0] = &user_column; keys[1] = &domain_column; if(flags&AUTH_DB_SUBS_SKIP_CREDENTIALS) { col[0] = &user_column; } else { for (n = 0, cred=credentials; cred ; n++, cred=cred->next) { col[n] = &cred->text; } } VAL_TYPE(vals) = VAL_TYPE(vals + 1) = DB1_STR; VAL_NULL(vals) = VAL_NULL(vals + 1) = 0; n = 1; VAL_STR(vals) = *user; if (domain && domain->len) { VAL_STR(vals + 1) = *domain; n = 2; } if (auth_dbf.use_table(auth_db_handle, table) < 0) { LM_ERR("failed to use_table\n"); pkg_free(col); return -1; } if (auth_dbf.query(auth_db_handle, keys, 0, vals, col, n, nc, 0, &res) < 0) { LM_ERR("failed to query database\n"); pkg_free(col); if(res) auth_dbf.free_result(auth_db_handle, res); return -1; } pkg_free(col); if (RES_ROW_N(res) == 0) { if(res) auth_dbf.free_result(auth_db_handle, res); LM_DBG("no result for user \'%.*s%s%.*s\' in [%.*s]\n", user->len, user->s, (n==2)?"@":"", (n==2)?domain->len:0, (n==2)?domain->s:"", table->len, table->s); return -2; } if(flags&AUTH_DB_SUBS_SKIP_CREDENTIALS) { /* there is a result and flag to skip loading credentials is set */ goto done; } for (cred=credentials, n=0; cred; cred=cred->next, n++) { if (db_val2pv_spec(msg, &RES_ROWS(res)[0].values[n], cred->spec) != 0) { if(res) auth_dbf.free_result(auth_db_handle, res); LM_ERR("Failed to convert value for column %.*s\n", RES_NAMES(res)[n]->len, RES_NAMES(res)[n]->s); return -3; } } done: if(res) auth_dbf.free_result(auth_db_handle, res); return 0; }
int sql_exec_xquery(struct sip_msg *msg, sql_con_t *con, str *query, str *xavp) { db1_res_t* db_res = NULL; sr_xavp_t *row = NULL; sr_xval_t val; int i, j; if(msg==NULL || query==NULL || xavp==NULL) { LM_ERR("bad parameters\n"); return -1; } if(con->dbf.raw_query(con->dbh, query, &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--) { row = NULL; for(j=RES_COL_N(db_res)-1; j>=0; j--) { if(RES_ROWS(db_res)[i].values[j].nul) { val.type = SR_XTYPE_NULL; } else { switch(RES_ROWS(db_res)[i].values[j].type) { case DB1_STRING: val.type = SR_XTYPE_STR; val.v.s.s= (char*)RES_ROWS(db_res)[i].values[j].val.string_val; val.v.s.len=strlen(val.v.s.s); break; case DB1_STR: val.type = SR_XTYPE_STR; val.v.s.len= RES_ROWS(db_res)[i].values[j].val.str_val.len; val.v.s.s= (char*)RES_ROWS(db_res)[i].values[j].val.str_val.s; break; case DB1_BLOB: val.type = SR_XTYPE_STR; val.v.s.len= RES_ROWS(db_res)[i].values[j].val.blob_val.len; val.v.s.s= (char*)RES_ROWS(db_res)[i].values[j].val.blob_val.s; break; case DB1_INT: val.type = SR_XTYPE_INT; val.v.i = (int)RES_ROWS(db_res)[i].values[j].val.int_val; break; case DB1_DATETIME: val.type = SR_XTYPE_INT; val.v.i = (int)RES_ROWS(db_res)[i].values[j].val.time_val; break; case DB1_BITMAP: val.type = SR_XTYPE_INT; val.v.i = (int)RES_ROWS(db_res)[i].values[j].val.bitmap_val; break; case DB1_BIGINT: val.type = SR_XTYPE_LLONG; val.v.ll = RES_ROWS(db_res)[i].values[j].val.ll_val; break; default: val.type = SR_XTYPE_NULL; } } /* Add column to current row, under the column's name */ LM_DBG("Adding column: %.*s\n", RES_NAMES(db_res)[j]->len, RES_NAMES(db_res)[j]->s); xavp_add_value(RES_NAMES(db_res)[j], &val, &row); } /* Add row to result xavp */ val.type = SR_XTYPE_XAVP; val.v.xavp = row; LM_DBG("Adding row\n"); xavp_add_value(xavp, &val, NULL); } con->dbf.free_result(con->dbh, db_res); return 1; }
/** * Convert rows from PostgreSQL to db API representation */ int db_postgres_convert_rows(const db_con_t* _h, db_res_t* _r) { char **row_buf, *s; int row, col, len; if (!_h || !_r) { LM_ERR("invalid parameter\n"); return -1; } if (!RES_ROW_N(_r)) { LM_DBG("no rows returned from the query\n"); RES_ROWS(_r) = 0; return 0; } /* Allocate an array of pointers per column to holds the string * representation */ len = sizeof(char *) * RES_COL_N(_r); row_buf = (char**)pkg_malloc(len); if (!row_buf) { LM_ERR("no private memory left\n"); return -1; } LM_DBG("allocate for %d columns %d bytes in row buffer at %p\n", RES_COL_N(_r), len, row_buf); memset(row_buf, 0, len); if (db_allocate_rows( _r, RES_ROW_N(_r))!=0) { LM_ERR("no private memory left\n"); return -2; } for(row=RES_LAST_ROW(_r); row<(RES_LAST_ROW(_r)+RES_ROW_N(_r)) ; row++) { for(col = 0; col < RES_COL_N(_r); col++) { /* * The row data pointer returned by PQgetvalue points to * storage that is part of the PGresult structure. One should * not modify the data it points to, and one must explicitly * copy the data into other storage if it is to be used past * the lifetime of the PGresult structure itself. */ /* * There's a weird bug (or just weird behavior) in the postgres * API - if the result is a BLOB (like 'text') and is with * zero length, we get a pointer to nowhere, which is not * null-terminated. The fix for this is to check what does the * DB think about the length and use that as a correction. */ if (PQgetisnull(CON_RESULT(_h), row, col) == 0) { /* not null value */ if ( (len=PQgetlength(CON_RESULT(_h), row, col))==0 ) { s=""; LM_DBG("PQgetvalue(%p,%d,%d)=[], zero len\n", _h, row,col); } else { s = PQgetvalue(CON_RESULT(_h), row, col); LM_DBG("PQgetvalue(%p,%d,%d)=[%.*s]\n", _h, row,col,len,s); } row_buf[col] = pkg_malloc(len+1); if (!row_buf[col]) { LM_ERR("no private memory left\n"); return -1; } memset(row_buf[col], 0, len+1); LM_DBG("allocated %d bytes for row_buf[%d] at %p\n", len, col, row_buf[col]); strncpy(row_buf[col], s, len); LM_DBG("[%d][%d] Column[%.*s]=[%s]\n", row, col, RES_NAMES(_r)[col]->len, RES_NAMES(_r)[col]->s, row_buf[col]); } } /* ASSERT: row_buf contains an entire row in strings */ if(db_postgres_convert_row(_h, _r, &(RES_ROWS(_r)[row - RES_LAST_ROW(_r)]), row_buf)<0){ LM_ERR("failed to convert row #%d\n", row); RES_ROW_N(_r) = row - RES_LAST_ROW(_r); for (col = 0; col < RES_COL_N(_r); col++) { LM_DBG("freeing row_buf[%d] at %p\n", col, row_buf[col]); if (row_buf[col] && !row_buf[col][0]) pkg_free(row_buf[col]); } LM_DBG("freeing row buffer at %p\n", row_buf); pkg_free(row_buf); return -4; } /* * pkg_free() must be done for the above allocations now that the row * has been converted. During pg_convert_row (and subsequent pg_str2val) * processing, data types that don't need to be converted (namely STRINGS * and STR) have their addresses saved. These data types should not have * their pkg_malloc() allocations freed here because they are still * needed. However, some data types (ex: INT, DOUBLE) should have their * pkg_malloc() allocations freed because during the conversion process, * their converted values are saved in the union portion of the db_val_t * structure. BLOB will be copied during PQunescape in str2val, thus it * has to be freed here AND in pg_free_row(). * * Warning: when the converted row is no longer needed, the data types * whose addresses were saved in the db_val_t structure must be freed * or a memory leak will happen. This processing should happen in the * pg_free_row() subroutine. The caller of this routine should ensure * that pg_free_rows(), pg_free_row() or pg_free_result() is eventually * called. */ for (col = 0; col < RES_COL_N(_r); col++) { switch (RES_TYPES(_r)[col]) { case DB_STRING: case DB_STR: break; default: LM_DBG("freeing row_buf[%d] at %p\n", col, row_buf[col]); if (row_buf[col]) pkg_free(row_buf[col]); } /* * The following housekeeping may not be technically required, but it * is a good practice to NULL pointer fields that are no longer valid. * Note that DB_STRING fields have not been pkg_free(). NULLing DB_STRING * fields would normally not be good to do because a memory leak would * occur. However, the pg_convert_row() routine has saved the DB_STRING * pointer in the db_val_t structure. The db_val_t structure will * eventually be used to pkg_free() the DB_STRING storage. */ row_buf[col] = (char *)NULL; } } LM_DBG("freeing row buffer at %p\n", row_buf); pkg_free(row_buf); row_buf = NULL; return 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; }
/*! * \brief Get and convert columns from a result * * Get and convert columns from a result, fills the result structure * with data from the database. * \param _h database connection * \param _r database result set * \return 0 on success, negative on failure */ int db_mongodb_get_columns(const db1_con_t* _h, db1_res_t* _r) { int col; db_mongodb_result_t *mgres; bson_iter_t riter; bson_iter_t citer; bson_t *cdoc; const char *colname; bson_type_t coltype; if ((!_h) || (!_r)) { LM_ERR("invalid parameter\n"); return -1; } mgres = (db_mongodb_result_t*)RES_PTR(_r); if(!mgres->rdoc) { mgres->nrcols = 0; return 0; } if(mgres->nrcols==0 || mgres->colsdoc==NULL) { mgres->nrcols = (int)bson_count_keys(mgres->rdoc); if(mgres->nrcols==0) { LM_ERR("no keys in bson document\n"); return -1; } cdoc = mgres->rdoc; } else { cdoc = mgres->colsdoc; } RES_COL_N(_r) = mgres->nrcols; if (!RES_COL_N(_r)) { LM_ERR("no columns returned from the query\n"); return -2; } else { LM_DBG("%d columns returned from the query\n", RES_COL_N(_r)); } if (db_allocate_columns(_r, RES_COL_N(_r)) != 0) { RES_COL_N(_r) = 0; LM_ERR("could not allocate columns\n"); return -3; } if (!bson_iter_init (&citer, cdoc)) { LM_ERR("failed to initialize columns iterator\n"); return -3; } if(mgres->colsdoc) { if (!bson_iter_init (&riter, mgres->rdoc)) { LM_ERR("failed to initialize result iterator\n"); return -3; } } 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("Found a 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; } coltype = bson_iter_type(&riter); } else { coltype = bson_iter_type(&citer); } RES_NAMES(_r)[col] = (str*)pkg_malloc(sizeof(str)); if (! RES_NAMES(_r)[col]) { LM_ERR("no private memory left\n"); db_free_columns(_r); return -4; } LM_DBG("allocate %lu bytes for RES_NAMES[%d] at %p\n", (unsigned long)sizeof(str), col, RES_NAMES(_r)[col]); /* pointer linked here is part of the result structure */ RES_NAMES(_r)[col]->s = (char*)colname; RES_NAMES(_r)[col]->len = strlen(colname); switch(coltype) { case BSON_TYPE_BOOL: case BSON_TYPE_INT32: case BSON_TYPE_TIMESTAMP: LM_DBG("use DB1_INT result type\n"); RES_TYPES(_r)[col] = DB1_INT; break; case BSON_TYPE_INT64: LM_DBG("use DB1_BIGINT result type\n"); RES_TYPES(_r)[col] = DB1_BIGINT; break; case BSON_TYPE_DOUBLE: LM_DBG("use DB1_DOUBLE result type\n"); RES_TYPES(_r)[col] = DB1_DOUBLE; break; case BSON_TYPE_DATE_TIME: LM_DBG("use DB1_DATETIME result type\n"); RES_TYPES(_r)[col] = DB1_DATETIME; break; case BSON_TYPE_BINARY: LM_DBG("use DB1_BLOB result type\n"); RES_TYPES(_r)[col] = DB1_BLOB; break; case BSON_TYPE_UTF8: LM_DBG("use DB1_STRING result type\n"); RES_TYPES(_r)[col] = DB1_STRING; break; #if 0 case BSON_TYPE_EOD: case BSON_TYPE_DOCUMENT: case BSON_TYPE_ARRAY: case BSON_TYPE_UNDEFINED: case BSON_TYPE_OID: case BSON_TYPE_NULL: 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_INFO("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; }
/* * Get and convert columns from a result. Define handlers and buffers */ static int get_columns(ora_con_t* con, db_res_t* _r, OCIStmt* _c, dmap_t* _d) { OCIParam *param; size_t tsz; ub4 i, n; sword status; status = OCIAttrGet(_c, OCI_HTYPE_STMT, &n, NULL, OCI_ATTR_PARAM_COUNT, con->errhp); if (status != OCI_SUCCESS) { LM_ERR("driver: %s\n", db_oracle_error(con, status)); return -1; } if (!n) { LM_ERR("no columns\n"); return -2; } if (n >= MAX_DEF_HANDLES) { LM_ERR("too many res. Rebuild with MAX_DEF_HANDLES >= %u\n", n); return -3; } if (db_allocate_columns(_r, n) != 0) { LM_ERR("could not allocate columns\n"); return -4; } for (i = 0; i < n; ++i) memset(RES_NAMES(_r)[i], 0, sizeof(db_key_t)); RES_COL_N(_r) = n; tsz = 0; memset(_d->defh, 0, sizeof(_d->defh[0]) * n); for (i = 0; i < n; i++) { ub4 len; ub2 dtype; status = OCIParamGet(_c, OCI_HTYPE_STMT, con->errhp, (dvoid**)(dvoid*)¶m, i+1); if (status != OCI_SUCCESS) goto ora_err; { text* name; status = OCIAttrGet(param, OCI_DTYPE_PARAM, (dvoid**)(dvoid*)&name, &len, OCI_ATTR_NAME, con->errhp); if (status != OCI_SUCCESS) goto ora_err; RES_NAMES(_r)[i]->s = (char*)pkg_malloc(len+1); if (!RES_NAMES(_r)[i]->s) { db_free_columns(_r); LM_ERR("no private memory left\n"); return -5; } RES_NAMES(_r)[i]->len = len; memcpy(RES_NAMES(_r)[i]->s, name, len); RES_NAMES(_r)[i]->s[len] = '\0'; } status = OCIAttrGet(param, OCI_DTYPE_PARAM, (dvoid**)(dvoid*)&dtype, NULL, OCI_ATTR_DATA_TYPE, con->errhp); if (status != OCI_SUCCESS) goto ora_err; switch (dtype) { case SQLT_UIN: /* unsigned integer */ set_bitmap: LM_DBG("use DB_BITMAP type\n"); RES_TYPES(_r)[i] = DB_BITMAP; len = sizeof(VAL_BITMAP((db_val_t*)NULL)); break; case SQLT_INT: /* (ORANET TYPE) integer */ set_int: LM_DBG("use DB_INT result type\n"); RES_TYPES(_r)[i] = DB_INT; len = sizeof(VAL_INT((db_val_t*)NULL)); break; case SQLT_LNG: /* long */ case SQLT_VNU: /* NUM with preceding length byte */ case SQLT_NUM: /* (ORANET TYPE) oracle numeric */ len = 0; /* PRECISION is ub1 */ status = OCIAttrGet(param, OCI_DTYPE_PARAM, (dvoid**)(dvoid*)&len, NULL, OCI_ATTR_PRECISION, con->errhp); if (status != OCI_SUCCESS) goto ora_err; if (len <= 11) { sb1 sc; status = OCIAttrGet(param, OCI_DTYPE_PARAM, (dvoid**)(dvoid*)&sc, NULL, OCI_ATTR_SCALE, con->errhp); if (status != OCI_SUCCESS) goto ora_err; if (!sc) { dtype = SQLT_INT; if (len != 11) goto set_int; dtype = SQLT_UIN; goto set_bitmap; } } LM_DBG("use DB_BIGINT result type\n"); RES_TYPES(_r)[i] = DB_BIGINT; len = sizeof(VAL_BIGINT((db_val_t*)NULL)); dtype = SQLT_NUM; break; case SQLT_FLT: /* (ORANET TYPE) Floating point number */ case SQLT_BFLOAT: /* Native Binary float*/ case SQLT_BDOUBLE: /* NAtive binary double */ case SQLT_IBFLOAT: /* binary float canonical */ case SQLT_IBDOUBLE: /* binary double canonical */ case SQLT_PDN: /* (ORANET TYPE) Packed Decimal Numeric */ LM_DBG("use DB_DOUBLE result type\n"); RES_TYPES(_r)[i] = DB_DOUBLE; len = sizeof(VAL_DOUBLE((db_val_t*)NULL)); dtype = SQLT_FLT; break; // case SQLT_TIME: /* TIME */ // case SQLT_TIME_TZ: /* TIME WITH TIME ZONE */ case SQLT_DATE: /* ANSI Date */ case SQLT_DAT: /* date in oracle format */ case SQLT_ODT: /* OCIDate type */ case SQLT_TIMESTAMP: /* TIMESTAMP */ case SQLT_TIMESTAMP_TZ: /* TIMESTAMP WITH TIME ZONE */ case SQLT_TIMESTAMP_LTZ:/* TIMESTAMP WITH LOCAL TZ */ // case SQLT_INTERVAL_YM: /* INTERVAL YEAR TO MONTH */ // case SQLT_INTERVAL_DS: /* INTERVAL DAY TO SECOND */ LM_DBG("use DB_DATETIME result type\n"); RES_TYPES(_r)[i] = DB_DATETIME; len = sizeof(OCIDate); dtype = SQLT_ODT; break; case SQLT_CLOB: /* character lob */ case SQLT_BLOB: /* binary lob */ // case SQLT_BFILEE: /* binary file lob */ // case SQLT_CFILEE: /* character file lob */ // case SQLT_BIN: /* binary data(DTYBIN) */ // case SQLT_LBI: /* long binary */ LM_DBG("use DB_BLOB result type\n"); RES_TYPES(_r)[i] = DB_BLOB; goto dyn_str; case SQLT_CHR: /* (ORANET TYPE) character string */ case SQLT_STR: /* zero terminated string */ case SQLT_VST: /* OCIString type */ case SQLT_VCS: /* Variable character string */ case SQLT_AFC: /* Ansi fixed char */ case SQLT_AVC: /* Ansi Var char */ // case SQLT_RID: /* rowid */ LM_DBG("use DB_STR result type\n"); RES_TYPES(_r)[i] = DB_STR; dyn_str: dtype = SQLT_CHR; len = 0; /* DATA_SIZE is ub2 */ status = OCIAttrGet(param, OCI_DTYPE_PARAM, (dvoid**)(dvoid*)&len, NULL, OCI_ATTR_DATA_SIZE, con->errhp); if (status != OCI_SUCCESS) goto ora_err; if (len >= 4000) { LM_DBG("use DB_BLOB result type\n"); RES_TYPES(_r)[i] = DB_BLOB; } ++len; break; default: LM_ERR("unsupported datatype %d\n", dtype); goto stop_load; } _d->ilen[i] = (ub2)len; _d->pv[i].v = st_buf + tsz; tsz += len; status = OCIDefineByPos(_c, &_d->defh[i], con->errhp, i+1, _d->pv[i].v, len, dtype, &_d->ind[i], &_d->len[i], NULL, OCI_DEFAULT); if (status != OCI_SUCCESS) goto ora_err; } #if STATIC_BUF_LEN < 65536 #error #endif if (tsz > 65536) { LM_ERR("Row size exceed 65K. IOB's are not supported\n"); goto stop_load; } return 0; ora_err: LM_ERR("driver: %s\n", db_oracle_error(con, status)); stop_load: db_free_columns(_r); return -6; }