/* * Release memory used by a result structure */ int db_free_result(db1_res_t* _r) { if (!_r) { LM_ERR("invalid parameter\n"); return -1; } db_free_columns(_r); db_free_rows(_r); LM_DBG("freeing result set at %p\n", _r); pkg_free(_r); _r = NULL; return 0; }
/* * Fill the structure with data from database */ static int dbt_convert_result(db1_res_t* _r, dbt_result_p _dres) { if (!_r || !_dres) { LM_ERR("invalid parameter\n"); return -1; } if (dbt_get_columns(_r, _dres) < 0) { LM_ERR("failed to get column names\n"); return -2; } if (dbt_convert_rows(_r, _dres) < 0) { LM_ERR("failed to convert rows\n"); db_free_columns(_r); return -3; } return 0; }
/*! * \brief Fill the result structure with data from database * \param _h database connection * \param _r database result * \return 0 on success, negative on failure */ int db_mysql_convert_result(const db1_con_t* _h, db1_res_t* _r) { if ((!_h) || (!_r)) { LM_ERR("invalid parameter\n"); return -1; } if (db_mysql_get_columns(_h, _r) < 0) { LM_ERR("error while getting column names\n"); return -2; } if (db_mysql_convert_rows(_h, _r) < 0) { LM_ERR("error while converting rows\n"); db_free_columns(_r); return -3; } return 0; }
/* * Fill the structure with data from database */ int db_unixodbc_convert_result(const db1_con_t* _h, db1_res_t* _r) { if (!_h || !_r) { LM_ERR("invalid parameter\n"); return -1; } if (db_unixodbc_get_columns(_h, _r) < 0) { LM_ERR("getting column names failed\n"); return -2; } if (db_unixodbc_convert_rows(_h, _r) < 0) { LM_ERR("converting rows failed\n"); db_free_columns(_r); return -3; } return 0; }
/** * Fill the result structure with data from the query */ int db_postgres_convert_result(const db_con_t* _h, db_res_t* _r) { if (!_h || !_r) { LM_ERR("invalid parameter value\n"); return -1; } if (db_postgres_get_columns(_h, _r) < 0) { LM_ERR("failed to get column names\n"); return -2; } if (db_postgres_convert_rows(_h, _r) < 0) { LM_ERR("failed to convert rows\n"); db_free_columns(_r); return -3; } return 0; }
db_res_t * new_full_db_res(int rows, int cols) { db_res_t * res; int i; res = db_new_result(); if( res == NULL) { LM_ERR("Error allocating db result\n"); return NULL; } if( db_allocate_columns(res,cols) < 0) { LM_ERR("Error allocating db result columns\n"); pkg_free(res); return NULL; } res->col.n = cols; if( db_allocate_rows(res,rows) < 0 ) { LM_ERR("Error allocating db result rows\n"); db_free_columns( res ); pkg_free(res); return NULL; } res->n = rows; res->res_rows = rows; res->last_row = rows; for( i=0;i<rows;i++) res->rows[i].n = cols; return res; }
/*! * \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; }
/* * 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; }
/** * 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, dbcassa_table_p tbc) { 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); /* search the column in table schema to get the type */ dbcassa_column_p colp = cassa_search_col(tbc, (db_key_t) RES_NAMES(_r)[col]); if(!colp) { LM_ERR("No column with name [%.*s] found\n", RES_NAMES(_r)[col]->len, RES_NAMES(_r)[col]->s); RES_COL_N(_r) = col; db_free_columns(_r); return -4; } RES_TYPES(_r)[col] = colp->type; LM_DBG("Column with name [%.*s] found: %d\n", RES_NAMES(_r)[col]->len, RES_NAMES(_r)[col]->s, colp->type); 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; }
/*! * \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; }
/*! * \brief Gets a partial result set, fetch rows from a result * * Gets a partial result set, fetch a number of rows from a databae result. * This function initialize the given result structure on the first run, and * fetches the nrows number of rows. On subsequenting runs, it uses the * existing result and fetches more rows, until it reaches the end of the * result set. Because of this the result needs to be null in the first * invocation of the function. If the number of wanted rows is zero, the * function returns anything with a result of zero. * \param _h structure representing the database connection * \param _r pointer to a structure representing the result * \param nrows number of fetched rows * \return return zero on success, negative value on failure */ int db_unixodbc_fetch_result(const db1_con_t* _h, db1_res_t** _r, const int nrows) { int row_n = 0, i = 0, ret = 0, len; SQLSMALLINT columns; list* rows = NULL; list* rowstart = NULL; strn* temp_row = NULL; if ((!_h) || (!_r) || nrows < 0) { LM_ERR("invalid parameter value\n"); return -1; } /* exit if the fetch count is zero */ if (nrows == 0) { if (*_r) db_free_result(*_r); *_r = 0; return 0; } /* On the first fetch for a query, allocate structures and get columns */ if(*_r == NULL) { /* Allocate a new result structure */ *_r = db_new_result(); LM_DBG("just allocated a new db result structure"); if (*_r == NULL) { LM_ERR("no memory left\n"); return -2; } /* Get columns names and count */ if (db_unixodbc_get_columns(_h, *_r) < 0) { LM_ERR("getting column names failed\n"); db_free_columns(*_r); return -2; } /* On subsequent fetch attempts, reuse already allocated structures */ } else { LM_DBG("db result structure already exist, reusing\n"); /* free old rows */ if(RES_ROWS(*_r) != NULL) db_free_rows(*_r); RES_ROWS(*_r) = 0; RES_ROW_N(*_r) = 0; } SQLNumResultCols(CON_RESULT(_h), (SQLSMALLINT *)&columns); /* Now fetch nrows at most */ len = sizeof(db_row_t) * nrows; RES_ROWS(*_r) = (struct db_row*)pkg_malloc(len); if (!RES_ROWS(*_r)) { LM_ERR("no memory left\n"); return -5; } LM_DBG("allocated %d bytes for RES_ROWS at %p\n", len, RES_ROWS(*_r)); LM_DBG("Now fetching %i rows at most\n", nrows); while(SQL_SUCCEEDED(ret = SQLFetch(CON_RESULT(_h)))) { /* Allocate a temporary row */ temp_row = db_unixodbc_new_cellrow(columns); if (!temp_row) { LM_ERR("no private memory left\n"); pkg_free(RES_ROWS(*_r)); pkg_free(*_r); *_r = 0; return -1; } LM_DBG("fetching %d columns for row %d...\n",columns, row_n); for(i=0; i < columns; i++) { LM_DBG("fetching column %d\n",i); if (!db_unixodbc_load_cell(_h, i+1, temp_row + i, RES_TYPES(*_r)[i])) { pkg_free(RES_ROWS(*_r)); db_unixodbc_free_cellrow(columns, temp_row); pkg_free(*_r); *_r = 0; return -5; } } LM_DBG("got temp_row at %p\n", temp_row); if (db_unixodbc_list_insert(&rowstart, &rows, columns, temp_row) < 0) { LM_ERR("SQL result row insert failed\n"); pkg_free(RES_ROWS(*_r)); db_unixodbc_free_cellrow(columns, temp_row); pkg_free(*_r); *_r = 0; return -5; } /* Free temporary row data */ LM_DBG("freeing temp_row at %p\n", temp_row); db_unixodbc_free_cellrow(columns, temp_row); temp_row = NULL; row_n++; if (row_n == nrows) { break; } } CON_ROW(_h) = NULL; RES_ROW_N(*_r) = row_n; if (!row_n) { LM_DBG("no more rows to process for db fetch"); pkg_free(RES_ROWS(*_r)); RES_ROWS(*_r) = 0; return 0; } /* Convert rows to internal format */ memset(RES_ROWS(*_r), 0, len); i = 0; rows = rowstart; while(rows) { LM_DBG("converting row #%d\n", i); CON_ROW(_h) = rows->data; if (!CON_ROW(_h)) { LM_ERR("string null\n"); RES_ROW_N(*_r) = row_n; db_free_rows(*_r); return -3; } if (db_unixodbc_convert_row(_h, *_r, &(RES_ROWS(*_r)[i]), rows->lengths) < 0) { LM_ERR("converting fetched row #%d failed\n", i); RES_ROW_N(*_r) = i; db_free_rows(*_r); return -4; } i++; rows = rows->next; } db_unixodbc_list_destroy(rowstart); /* update the total number of rows processed */ RES_LAST_ROW(*_r) += row_n; LM_DBG("fetch from db processed %d rows so far\n", RES_LAST_ROW(*_r)); return 0; }
/* * 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; }
/*! * \brief Get and convert columns from a result set * \param _h database connection * \param _r result set * \return 0 on success, negative on error */ int db_postgres_get_columns(const db1_con_t* _h, db1_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++) { 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\n", (unsigned int) sizeof(str), col, RES_NAMES(_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: LM_DBG("use DB1_INT result type\n"); RES_TYPES(_r)[col] = DB1_INT; break; case INT8OID: LM_DBG("use DB1_BIGINT result type\n"); RES_TYPES(_r)[col] = DB1_BIGINT; case FLOAT4OID: case FLOAT8OID: case NUMERICOID: LM_DBG("use DB1_DOUBLE result type\n"); RES_TYPES(_r)[col] = DB1_DOUBLE; break; case DATEOID: case TIMESTAMPOID: case TIMESTAMPTZOID: LM_DBG("use DB1_DATETIME result type\n"); RES_TYPES(_r)[col] = DB1_DATETIME; break; case BOOLOID: case CHAROID: case VARCHAROID: case BPCHAROID: LM_DBG("use DB1_STRING result type\n"); RES_TYPES(_r)[col] = DB1_STRING; break; case TEXTOID: case BYTEAOID: LM_DBG("use DB1_BLOB result type\n"); RES_TYPES(_r)[col] = DB1_BLOB; break; case BITOID: case VARBITOID: LM_DBG("use DB1_BITMAP result type\n"); RES_TYPES(_r)[col] = DB1_BITMAP; 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; }