/* * Retrieve result set */ static int db_unixodbc_store_result(const db1_con_t* _h, db1_res_t** _r) { if ((!_h) || (!_r)) { LM_ERR("invalid parameter value\n"); return -1; } *_r = db_new_result(); if (*_r == 0) { LM_ERR("no memory left\n"); return -2; } if (db_unixodbc_convert_result(_h, *_r) < 0) { LM_ERR("failed to convert result\n"); LM_DBG("freeing result set at %p\n", _r); pkg_free(*_r); *_r = 0; return -4; } return 0; }
/** * \brief Gets a partial result set, fetch rows from a result * * Gets a partial result set, fetch a number of rows from a database 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 zero on success, negative value on failure */ int erlang_srdb1_fetch_result(const db1_con_t* _h, db1_res_t** _r, const int nrows) { int rows, i, code; LM_DBG("erlang_srdb1_fetch_result\n"); if (!_h || !_r || nrows < 0) { LM_ERR("Invalid parameter value\n"); return -1; } /* exit if the fetch count is zero */ if (nrows == 0) { db_free_result(*_r); *_r = 0; return 0; } if(*_r==0) { /* Allocate a new result structure */ *_r = db_new_result(); if (*_r == 0) { LM_ERR("no memory left\n"); return -2; } } else { /* free old rows */ if(RES_ROWS(*_r)!=0) db_free_rows(*_r); RES_ROWS(*_r) = 0; RES_ROW_N(*_r) = 0; } /* determine the number of rows remaining to be processed */ rows = RES_NUM_ROWS(*_r) - RES_LAST_ROW(*_r); /* If there aren't any more rows left to process, exit */ if(rows<=0) return 0; /* if the fetch count is less than the remaining rows to process */ /* set the number of rows to process (during this call) equal to the fetch count */ if(nrows < rows) rows = nrows; RES_ROW_N(*_r) = rows; LM_DBG("converting row %d of %d count %d\n", RES_LAST_ROW(*_r), RES_NUM_ROWS(*_r), RES_ROW_N(*_r)); RES_ROWS(*_r) = (struct db_row*)pkg_malloc(sizeof(db_row_t) * rows); if (!RES_ROWS(*_r)) { LM_ERR("no memory left\n"); return -5; } /* update the total number of rows processed */ RES_LAST_ROW(*_r) += rows; return 0; }
/* * Retrieve result set */ int dbt_get_result(db_con_t* _h, db_res_t** _r) { if (!_h || !_r) { LM_ERR("invalid parameter value\n"); return -1; } if (!DBT_CON_RESULT(_h)) { LM_ERR("failed to get result\n"); *_r = 0; return -3; } *_r = db_new_result(); if (*_r == 0) { LM_ERR("no private memory left\n"); return -2; } if (dbt_convert_result(_h, *_r) < 0) { LM_ERR("failed to convert result\n"); pkg_free(*_r); return -4; } return 0; }
/* * Retrieve result set */ int dbt_get_result(db1_res_t** _r, dbt_result_p _dres) { if ( !_r) { LM_ERR("invalid parameter value\n"); return -1; } if (!_dres) { LM_ERR("failed to get result\n"); *_r = 0; return -3; } *_r = db_new_result(); if (*_r == 0) { LM_ERR("no private memory left\n"); return -2; } if (dbt_convert_result(*_r, _dres) < 0) { LM_ERR("failed to convert result\n"); pkg_free(*_r); return -4; } (*_r)->ptr = _dres; return 0; }
/* * Retrieve result set */ static int db_mysql_store_result(db_con_t* _h, db_res_t** _r) { if ((!_h) || (!_r)) { LM_ERR("invalid parameter value\n"); return -1; } *_r = db_new_result(); if (*_r == 0) { LM_ERR("no memory left\n"); return -2; } CON_RESULT(_h) = mysql_store_result(CON_CONNECTION(_h)); if (!CON_RESULT(_h)) { if (mysql_field_count(CON_CONNECTION(_h)) == 0) { (*_r)->col.n = 0; (*_r)->n = 0; goto done; } else { LM_ERR("driver error: %s\n", mysql_error(CON_CONNECTION(_h))); db_mysql_free_dbresult(*_r); *_r = 0; return -3; } } if (db_mysql_convert_result(_h, *_r) < 0) { LM_ERR("error while converting result\n"); pkg_free(*_r); *_r = 0; /* all mem on openser API side is already freed by * db_mysql_convert_result in case of error, but we also need * to free the mem from the mysql lib side */ mysql_free_result(CON_RESULT(_h)); #if (MYSQL_VERSION_ID >= 40100) while( mysql_next_result( CON_CONNECTION(_h) ) > 0 ) { MYSQL_RES *res = mysql_store_result( CON_CONNECTION(_h) ); mysql_free_result( res ); } #endif CON_RESULT(_h) = 0; return -4; } done: #if (MYSQL_VERSION_ID >= 40100) while( mysql_next_result( CON_CONNECTION(_h) ) > 0 ) { MYSQL_RES *res = mysql_store_result( CON_CONNECTION(_h) ); mysql_free_result( res ); } #endif return 0; }
/* * Read database answer and fill the structure */ int db_oracle_store_result(const db_con_t* _h, db_res_t** _r) { dmap_t dmap; int rc; db_res_t* r; ora_con_t* con; OCIStmt* hs; if (!_h || !_r) { badparam: LM_ERR("invalid parameter\n"); return -1; } con = CON_ORA(_h); { query_data_t *pcb = con->pqdata; if (!pcb || !pcb->_rs) goto badparam; hs = *pcb->_rs; pcb->_rs = NULL; /* paranoid for next call */ } rc = -1; if (_r) *_r = NULL; /* unification for all errors */ r = db_new_result(); if (!r) { LM_ERR("no memory left\n"); goto done; } if (get_columns(con, r, hs, &dmap) < 0) { LM_ERR("error while getting column names\n"); goto done; } if (get_rows(con, r, hs, &dmap) < 0) { LM_ERR("error while converting rows\n"); db_free_columns(r); goto done; } rc = 0; *_r = r; done: OCIHandleFree(hs, OCI_HTYPE_STMT); return rc; }
/*! * \brief Allocate new result set with private structure * \return db1_res_t object on success, NULL on failure */ db1_res_t* db_mysql_new_result(void) { db1_res_t* obj; obj = db_new_result(); if (!obj) return NULL; RES_PTR(obj) = pkg_malloc(sizeof(struct my_res)); if (!RES_PTR(obj)) { db_free_result(obj); return NULL; } return obj; }
db1_res_t* db_mongodb_new_result(void) { db1_res_t* obj; obj = db_new_result(); if (!obj) return NULL; RES_PTR(obj) = pkg_malloc(sizeof(db_mongodb_result_t)); if (!RES_PTR(obj)) { db_free_result(obj); return NULL; } memset(RES_PTR(obj), 0, sizeof(db_mongodb_result_t)); return obj; }
/* * Retrieve result set */ static int db_unixodbc_store_result(const db_con_t* _h, db_res_t** _r) { SQLSMALLINT cols; SQLLEN aff_cols; if ((!_h) || (!_r)) { LM_ERR("invalid parameter value\n"); return -1; } *_r = db_new_result(); if (*_r == 0) { LM_ERR("no memory left\n"); return -2; } SQLNumResultCols(CON_RESULT(_h), &cols); if (!cols) { SQLRowCount(CON_RESULT(_h), &aff_cols); if (aff_cols > 0) { (*_r)->col.n = 0; (*_r)->n = 0; return 0; } else { LM_ERR(" invalid SQL query\n"); db_free_result(*_r); *_r = 0; return -3; } } if (db_unixodbc_convert_result(_h, *_r) < 0) { LM_ERR("failed to convert result\n"); pkg_free(*_r); *_r = 0; return -4; } 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; }
static int db_sqlite_store_result(const db_con_t* _h, db_res_t** _r, const db_val_t* _v, const int _n) { int rows; if ((!_h) || (!_r)) { LM_ERR("invalid parameter value\n"); return -1; } *_r = db_new_result(); if (*_r == 0) { LM_ERR("no memory left\n"); return -2; } rows=db_sqlite_get_query_rows(_h, &count_str, _v, _n); /* reset the length to initial for future uses */ if (rows < 0) { LM_ERR("failed to fetch number of rows\n"); return -1; } /* trying to fetch all rows * these values are not final values as, in the * meantime, the db can be changed by another process */ RES_NUM_ROWS(*_r) = RES_ROW_N(*_r) = rows; if (db_sqlite_convert_result(_h, *_r) < 0) { LM_ERR("error while converting result\n"); pkg_free(*_r); *_r = 0; return -4; } return 0; }
/** * Execute a raw SQL query. * \param _h handle for the database * \param _s raw query string * \param _r result set for storage * \return zero on success, negative value on failure */ int db_cassa_raw_query(const db1_con_t* _h, const str* _s, db1_res_t** _r) { db1_res_t* db_res = 0; str table_name; dbcassa_table_p tbc; std::vector<oac::CqlRow> res_cql_rows; if (!_h || !_r) { LM_ERR("Invalid parameter value\n"); return -1; } if (get_table_from_query(_s, &table_name) < 0) { LM_ERR("Error parsing table name in CQL string"); return -1; } LM_DBG("query table=%.*s\n", table_name.len, table_name.s); LM_DBG("CQL=%s\n", _s->s); tbc = dbcassa_db_get_table(&CON_CASSA(_h)->db_name, &table_name); if(!tbc) { LM_ERR("table %.*s does not exist!\n", table_name.len, table_name.s); return -1; } std::string cql_query(_s->s); oac::CqlResult cassa_cql_res; try { CON_CASSA(_h)->con->execute_cql_query(cassa_cql_res, cql_query , oac::Compression::NONE); } catch (const oac::InvalidRequestException &irx) { LM_ERR("Invalid Request caused error details: %s.\n", irx.why.c_str()); } catch (const at::TException &tx) { LM_ERR("T Exception %s\n", tx.what()); } catch (const std::exception &ex) { LM_ERR("Failed: %s\n", ex.what()); } catch (...) { LM_ERR("Failed to open connection to Cassandra cluster\n"); } if (!cassa_cql_res.__isset.rows) { LM_ERR("The resultype rows was not set, no point trying to parse result.\n"); goto error; } res_cql_rows = cassa_cql_res.rows; /* TODO Handle the other types */ switch(cassa_cql_res.type) { case 1: LM_DBG("Result set is an ROW Type.\n"); break; case 2: LM_DBG("Result set is an VOID Type.\n"); break; case 3: LM_DBG("Result set is an INT Type.\n"); break; } db_res = db_new_result(); if (!db_res) { LM_ERR("no memory left\n"); goto error; } if(res_cql_rows.size() == 0) { LM_DBG("The query returned no result\n"); RES_ROW_N(db_res) = 0; RES_COL_N(db_res)= 0; *_r = db_res; goto done; } if (cql_get_columns(cassa_cql_res, db_res, tbc) < 0) { LM_ERR("Error getting column names."); goto error; } if (cql_convert_row(cassa_cql_res, db_res) < 0) { LM_ERR("Error converting rows"); goto error; } *_r = db_res; done: dbcassa_lock_release(tbc); LM_DBG("Exited with success\n"); return 0; error: if(db_res) db_free_result(db_res); dbcassa_lock_release(tbc); return -1; }
/** * Gets a partial result set. * \param _h structure representing the database connection * \param _r pointer to a structure representing the result * \param nrows number of fetched rows * \return zero on success, negative value on failure */ int db_sqlite_fetch_result(const db_con_t* _h, db_res_t** _r, const int nrows) { int ret; int rows, i; sqlite3_stmt* stmt; if (!_h || !_r || nrows < 0) { LM_ERR("Invalid parameter value\n"); return -1; } /* exit if the fetch count is zero */ if (nrows == 0) { db_free_result(*_r); *_r = 0; return 0; } if(*_r==0) { /* Allocate a new result structure */ *_r = db_new_result(); if (*_r == 0) { LM_ERR("no memory left\n"); return -2; } if (db_sqlite_get_columns(_h, *_r) < 0) { LM_ERR("error while getting column names\n"); return -4; } RES_NUM_ROWS(*_r) = CON_PS_ROWS(_h); if (!RES_NUM_ROWS(*_r)) { LM_DBG("no rows returned from the query\n"); RES_ROWS(*_r) = 0; return 0; } } else { /* free old rows */ if(RES_ROWS(*_r)!=0) db_free_rows(*_r); RES_ROWS(*_r) = 0; RES_ROW_N(*_r) = 0; } /* determine the number of rows remaining to be processed */ rows = RES_NUM_ROWS(*_r) - RES_LAST_ROW(*_r); /* If there aren't any more rows left to process, exit */ if(rows<=0) return 0; /* if the fetch count is less than the remaining rows to process */ /* set the number of rows to process (during this call) equal to the fetch count */ if(nrows < rows) rows = nrows; RES_ROW_N(*_r) = rows; if (db_sqlite_allocate_rows(*_r, rows)!=0) { LM_ERR("no memory left\n"); return -5; } i = 0; ret=-1; stmt = CON_SQLITE_PS(_h); while (ret != SQLITE_DONE) { if (i == nrows) { RES_LAST_ROW(*_r) = i - 1; break; } ret = sqlite3_step(stmt); if (ret == SQLITE_DONE) { RES_ROW_N(*_r) = RES_LAST_ROW(*_r) = RES_NUM_ROWS(*_r) = i; sqlite3_finalize(CON_SQLITE_PS(_h)); CON_SQLITE_PS(_h) = NULL; break; } if (i >= RES_ROW_N(*_r) && i < nrows) { db_sqlite_realloc_rows(*_r, RES_ROW_N(*_r) + db_sqlite_alloc_limit); RES_ROW_N(*_r) += db_sqlite_alloc_limit; } if ((ret=db_sqlite_convert_row(_h, *_r, &(RES_ROWS(*_r)[i]))) < 0) { LM_ERR("error while converting row #%d\n", i); RES_ROW_N(*_r) = i; db_free_rows(*_r); return -4; } i++; } return 0; }
/*! * \brief Retrieve result set * \param _con structure representing the database connection * \param _r pointer to a structure represending the result set * \return 0 If the status of the last command produced a result set and, * If the result set contains data or the convert_result() routine * completed successfully. Negative if the status of the last command was * not handled or if the convert_result() returned an error. * \note A new result structure is allocated on every call to this routine. * If this routine returns 0, it is the callers responsbility to free the * result structure. If this routine returns < 0, then the result structure * is freed before returning to the caller. */ int db_postgres_store_result(const db1_con_t* _con, db1_res_t** _r) { PGresult *res = NULL; ExecStatusType pqresult; int rc = 0; *_r = db_new_result(); if (*_r==NULL) { LM_ERR("failed to init new result\n"); rc = -1; goto done; } while (1) { if ((res = PQgetResult(CON_CONNECTION(_con)))) { CON_RESULT(_con) = res; } else { break; } } pqresult = PQresultStatus(CON_RESULT(_con)); LM_DBG("%p PQresultStatus(%s) PQgetResult(%p)\n", _con, PQresStatus(pqresult), CON_RESULT(_con)); CON_AFFECTED(_con) = 0; switch(pqresult) { case PGRES_COMMAND_OK: /* Successful completion of a command returning no data * (such as INSERT or UPDATE). */ rc = 0; CON_AFFECTED(_con) = atoi(PQcmdTuples(CON_RESULT(_con))); break; case PGRES_TUPLES_OK: /* Successful completion of a command returning data * (such as a SELECT or SHOW). */ if (db_postgres_convert_result(_con, *_r) < 0) { LM_ERR("error while converting result\n"); LM_DBG("freeing result set at %p\n", _r); pkg_free(*_r); *_r = 0; rc = -4; break; } rc = 0; CON_AFFECTED(_con) = atoi(PQcmdTuples(CON_RESULT(_con))); break; /* query failed */ case PGRES_FATAL_ERROR: LM_ERR("invalid query, execution aborted\n"); LM_ERR("driver error: %s, %s\n", PQresStatus(pqresult), PQresultErrorMessage(CON_RESULT(_con))); db_free_result(*_r); *_r = 0; rc = -3; break; case PGRES_EMPTY_QUERY: /* notice or warning */ case PGRES_NONFATAL_ERROR: /* status for COPY command, not used */ case PGRES_COPY_OUT: case PGRES_COPY_IN: /* unexpected response */ case PGRES_BAD_RESPONSE: default: LM_ERR("probable invalid query, execution aborted\n"); LM_ERR("driver message: %s, %s\n", PQresStatus(pqresult), PQresultErrorMessage(CON_RESULT(_con))); db_free_result(*_r); *_r = 0; rc = -4; break; } done: db_postgres_free_query(_con); return (rc); }
/** * \brief Gets a partial result set, fetch rows from a result * * Gets a partial result set, fetch a number of rows from a database 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 zero on success, negative value on failure */ int db_mysql_fetch_result(const db1_con_t* _h, db1_res_t** _r, const int nrows) { int rows, i, code; if (!_h || !_r || nrows < 0) { LM_ERR("Invalid parameter value\n"); return -1; } /* exit if the fetch count is zero */ if (nrows == 0) { db_free_result(*_r); *_r = 0; return 0; } if(*_r==0) { /* Allocate a new result structure */ *_r = db_new_result(); if (*_r == 0) { LM_ERR("no memory left\n"); return -2; } CON_RESULT(_h) = mysql_store_result(CON_CONNECTION(_h)); if (!CON_RESULT(_h)) { if (mysql_field_count(CON_CONNECTION(_h)) == 0) { (*_r)->col.n = 0; (*_r)->n = 0; return 0; } else { LM_ERR("driver error: %s\n", mysql_error(CON_CONNECTION(_h))); code = mysql_errno(CON_CONNECTION(_h)); if (code == CR_SERVER_GONE_ERROR || code == CR_SERVER_LOST) { counter_inc(mysql_cnts_h.driver_err); } db_free_result(*_r); *_r = 0; return -3; } } if (db_mysql_get_columns(_h, *_r) < 0) { LM_ERR("error while getting column names\n"); return -4; } RES_NUM_ROWS(*_r) = mysql_num_rows(CON_RESULT(_h)); if (!RES_NUM_ROWS(*_r)) { LM_DBG("no rows returned from the query\n"); RES_ROWS(*_r) = 0; return 0; } } else { /* free old rows */ if(RES_ROWS(*_r)!=0) db_free_rows(*_r); RES_ROWS(*_r) = 0; RES_ROW_N(*_r) = 0; } /* determine the number of rows remaining to be processed */ rows = RES_NUM_ROWS(*_r) - RES_LAST_ROW(*_r); /* If there aren't any more rows left to process, exit */ if(rows<=0) return 0; /* if the fetch count is less than the remaining rows to process */ /* set the number of rows to process (during this call) equal to the fetch count */ if(nrows < rows) rows = nrows; RES_ROW_N(*_r) = rows; LM_DBG("converting row %d of %d count %d\n", RES_LAST_ROW(*_r), RES_NUM_ROWS(*_r), RES_ROW_N(*_r)); RES_ROWS(*_r) = (struct db_row*)pkg_malloc(sizeof(db_row_t) * rows); if (!RES_ROWS(*_r)) { LM_ERR("no memory left\n"); return -5; } for(i = 0; i < rows; i++) { CON_ROW(_h) = mysql_fetch_row(CON_RESULT(_h)); if (!CON_ROW(_h)) { LM_ERR("driver error: %s\n", mysql_error(CON_CONNECTION(_h))); RES_ROW_N(*_r) = i; db_free_rows(*_r); return -6; } if (db_mysql_convert_row(_h, *_r, &(RES_ROWS(*_r)[i])) < 0) { LM_ERR("error while converting row #%d\n", i); RES_ROW_N(*_r) = i; db_free_rows(*_r); return -7; } } /* update the total number of rows processed */ RES_LAST_ROW(*_r) += rows; return 0; }
/* * Query table for specified rows * _con: 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 bdb_query(db_con_t* _con, db_key_t* _k, db_op_t* _op, db_val_t* _v, db_key_t* _c, int _n, int _nc, db_key_t _o, db_res_t** _r) { tbl_cache_p _tbc = NULL; table_p _tp = NULL; char kbuf[MAX_ROW_SIZE]; char dbuf[MAX_ROW_SIZE]; u_int32_t i, len, ret; int klen=MAX_ROW_SIZE; int *lkey=NULL, *lres=NULL; str s; DBT key, data; DB *db; DBC *dbcp; if ((!_con) || (!_r) || !CON_TABLE(_con)) { #ifdef BDB_EXTRA_DEBUG LM_ERR("Invalid parameter value\n"); #endif return -1; } *_r = NULL; /*check if underlying DB file has changed inode */ if(auto_reload) bdb_check_reload(_con); s.s = (char*)CON_TABLE(_con); s.len = strlen(CON_TABLE(_con)); _tbc = bdblib_get_table(BDB_CON_CONNECTION(_con), &s); if(!_tbc) { LM_WARN("table does not exist!\n"); return -1; } _tp = _tbc->dtp; if(!_tp) { LM_WARN("table not loaded!\n"); return -1; } #ifdef BDB_EXTRA_DEBUG LM_DBG("QUERY in %.*s\n", _tp->name.len, _tp->name.s); if (_o) LM_DBG("DONT-CARE : _o: order by the specified column \n"); if (_op) LM_DBG("DONT-CARE : _op: operators for refining query \n"); #endif db = _tp->db; if(!db) return -1; memset(&key, 0, sizeof(DBT)); memset(kbuf, 0, MAX_ROW_SIZE); memset(&data, 0, sizeof(DBT)); memset(dbuf, 0, MAX_ROW_SIZE); data.data = dbuf; data.ulen = MAX_ROW_SIZE; data.flags = DB_DBT_USERMEM; /* if _c is NULL and _nc is zero, you will get all table columns in the result */ if (_c) { lres = bdb_get_colmap(_tbc->dtp, _c, _nc); if(!lres) { ret = -1; goto error; } } if(_k) { lkey = bdb_get_colmap(_tbc->dtp, _k, _n); if(!lkey) { ret = -1; goto error; } } else { DB_HASH_STAT st; memset(&st, 0, sizeof(DB_HASH_STAT)); i =0 ; #ifdef BDB_EXTRA_DEBUG LM_DBG("SELECT * FROM %.*s\n", _tp->name.len, _tp->name.s); #endif /* Acquire a cursor for the database. */ if ((ret = db->cursor(db, NULL, &dbcp, 0)) != 0) { LM_ERR("Error creating cursor\n"); goto error; } /*count the number of records*/ while ((ret = dbcp->c_get(dbcp, &key, &data, DB_NEXT)) == 0) { if(!strncasecmp((char*)key.data,"METADATA",8)) continue; i++; } dbcp->c_close(dbcp); ret=0; #ifdef BDB_EXTRA_DEBUG LM_DBG("%i = SELECT COUNT(*) FROM %.*s\n", i, _tp->name.len, _tp->name.s); #endif *_r = db_new_result(); if (!*_r) { LM_ERR("no memory left for result \n"); ret = -2; goto error; } if(i == 0) { /*return empty table*/ RES_ROW_N(*_r) = 0; BDB_CON_RESULT(_con) = *_r; return 0; } /*allocate N rows in the result*/ RES_ROW_N(*_r) = i; len = sizeof(db_row_t) * i; RES_ROWS(*_r) = (db_row_t*)pkg_malloc( len ); memset(RES_ROWS(*_r), 0, len); /*fill in the column part of db_res_t (metadata) */ if ((ret = bdb_get_columns(_tbc->dtp, *_r, lres, _nc)) < 0) { LM_ERR("Error while getting column names\n"); goto error; } /* Acquire a cursor for the database. */ if ((ret = db->cursor(db, NULL, &dbcp, 0)) != 0) { LM_ERR("Error creating cursor\n"); goto error; } /*convert each record into a row in the result*/ i =0 ; while ((ret = dbcp->c_get(dbcp, &key, &data, DB_NEXT)) == 0) { if(!strncasecmp((char*)key.data,"METADATA",8)) continue; #ifdef BDB_EXTRA_DEBUG LM_DBG("KEY: [%.*s]\nDATA: [%.*s]\n" , (int) key.size , (char *)key.data , (int) data.size , (char *)data.data); #endif /*fill in the row part of db_res_t */ if ((ret=bdb_append_row( *_r, dbuf, lres, i)) < 0) { LM_ERR("Error while converting row\n"); goto error; } i++; } dbcp->c_close(dbcp); BDB_CON_RESULT(_con) = *_r; return 0; } if ( (ret = bdblib_valtochar(_tp, lkey, kbuf, &klen, _v, _n, BDB_KEY)) != 0 ) { LM_ERR("error in query key \n"); goto error; } key.data = kbuf; key.ulen = MAX_ROW_SIZE; key.flags = DB_DBT_USERMEM; key.size = klen; data.data = dbuf; data.ulen = MAX_ROW_SIZE; data.flags = DB_DBT_USERMEM; /*create an empty db_res_t which gets returned even if no result*/ *_r = db_new_result(); if (!*_r) { LM_ERR("no memory left for result \n"); ret = -2; goto error; } RES_ROW_N(*_r) = 0; BDB_CON_RESULT(_con) = *_r; #ifdef BDB_EXTRA_DEBUG LM_DBG("SELECT KEY: [%.*s]\n" , (int) key.size , (char *)key.data ); #endif /*query Berkely DB*/ if ((ret = db->get(db, NULL, &key, &data, 0)) == 0) { #ifdef BDB_EXTRA_DEBUG LM_DBG("RESULT\nKEY: [%.*s]\nDATA: [%.*s]\n" , (int) key.size , (char *)key.data , (int) data.size , (char *)data.data); #endif /*fill in the col part of db_res_t */ if ((ret = bdb_get_columns(_tbc->dtp, *_r, lres, _nc)) < 0) { LM_ERR("Error while getting column names\n"); goto error; } /*fill in the row part of db_res_t */ if ((ret=bdb_convert_row( *_r, dbuf, lres)) < 0) { LM_ERR("Error while converting row\n"); goto error; } } else { /*Berkeley DB error handler*/ switch(ret) { case DB_NOTFOUND: #ifdef BDB_EXTRA_DEBUG LM_DBG("NO RESULT for QUERY \n"); #endif ret=0; break; /*The following are all critical/fatal */ case DB_LOCK_DEADLOCK: // The operation was selected to resolve a deadlock. case DB_SECONDARY_BAD: // A secondary index references a nonexistent primary key. case DB_RUNRECOVERY: default: LM_CRIT("DB->get error: %s.\n", db_strerror(ret)); bdblib_recover(_tp,ret); goto error; } } if(lkey) pkg_free(lkey); if(lres) pkg_free(lres); return ret; error: if(lkey) pkg_free(lkey); if(lres) pkg_free(lres); if(*_r) bdb_free_result(*_r); *_r = NULL; return ret; }
/* _bdb_delete_cursor -- called from bdb_delete when the query involves operators other than equal '='. Adds support for queries like this: DELETE from SomeTable WHERE _k[0] < _v[0] In this case, the keys _k are not the actually schema keys, so we need to iterate via cursor to perform this operation. */ int _bdb_delete_cursor(db_con_t* _h, db_key_t* _k, db_op_t* _op, db_val_t* _v, int _n) { tbl_cache_p _tbc = NULL; table_p _tp = NULL; db_res_t* _r = NULL; char kbuf[MAX_ROW_SIZE]; char dbuf[MAX_ROW_SIZE]; int i, ret, klen=MAX_ROW_SIZE; DBT key, data; DB *db; DBC *dbcp; int *lkey=NULL; str s; i = ret = 0; if ((!_h) || !CON_TABLE(_h)) return -1; s.s = (char*)CON_TABLE(_h); s.len = strlen(CON_TABLE(_h)); _tbc = bdblib_get_table(BDB_CON_CONNECTION(_h), &s); if(!_tbc) { LM_WARN("table does not exist!\n"); return -3; } _tp = _tbc->dtp; if(!_tp) { LM_WARN("table not loaded!\n"); return -4; } #ifdef BDB_EXTRA_DEBUG LM_DBG("DELETE by cursor in %.*s\n", _tp->name.len, _tp->name.s ); #endif if(_k) { lkey = bdb_get_colmap(_tp, _k, _n); if(!lkey) { ret = -1; goto error; } } /* create an empty db_res_t which gets returned even if no result */ _r = db_new_result(); if (!_r) { LM_ERR("no memory for result \n"); } RES_ROW_N(_r) = 0; /* fill in the col part of db_res_t */ if ((ret = bdb_get_columns(_tp, _r, 0, 0)) != 0) { LM_ERR("Error while getting column names\n"); goto error; } db = _tp->db; memset(&key, 0, sizeof(DBT)); memset(kbuf, 0, klen); memset(&data, 0, sizeof(DBT)); memset(dbuf, 0, MAX_ROW_SIZE); data.data = dbuf; data.ulen = MAX_ROW_SIZE; data.flags = DB_DBT_USERMEM; /* Acquire a cursor for the database. */ if ((ret = db->cursor(db, NULL, &dbcp, DB_WRITECURSOR)) != 0) { LM_ERR("Error creating cursor\n"); } while ((ret = dbcp->c_get(dbcp, &key, &data, DB_NEXT)) == 0) { if(!strncasecmp((char*)key.data,"METADATA",8)) continue; /*fill in the row part of db_res_t */ if ((ret=bdb_convert_row( _r, dbuf, 0)) < 0) { LM_ERR("Error while converting row\n"); goto error; } if(bdb_row_match(_k, _op, _v, _n, _r, lkey )) { #ifdef BDB_EXTRA_DEBUG LM_DBG("DELETE ROW by KEY: [%.*s]\n", (int) key.size, (char *)key.data); #endif if((ret = dbcp->c_del(dbcp, 0)) != 0) { /* Berkeley DB error handler */ LM_CRIT("DB->get error: %s.\n", db_strerror(ret)); bdblib_recover(_tp,ret); } } memset(dbuf, 0, MAX_ROW_SIZE); bdb_free_rows( _r); } ret = 0; error: if(dbcp) dbcp->c_close(dbcp); if(_r) bdb_free_result(_r); if(lkey) pkg_free(lkey); return ret; }
int db_postgres_store_result(const db_con_t* _con, db_res_t** _r) { ExecStatusType pqresult; int rc = 0; *_r = db_new_result(); if (*_r==NULL) { LM_ERR("failed to init new result\n"); rc = -1; goto done; } pqresult = PQresultStatus(CON_RESULT(_con)); LM_DBG("%p PQresultStatus(%s) PQgetResult(%p)\n", _con, PQresStatus(pqresult), CON_RESULT(_con)); switch(pqresult) { case PGRES_COMMAND_OK: /* Successful completion of a command returning no data * (such as INSERT or UPDATE). */ rc = 0; break; case PGRES_TUPLES_OK: /* Successful completion of a command returning data * (such as a SELECT or SHOW). */ if (db_postgres_convert_result(_con, *_r) < 0) { LM_ERR("%p Error returned from convert_result()\n", _con); db_free_result(*_r); *_r = 0; rc = -4; break; } rc = 0; break; /* query failed */ case PGRES_FATAL_ERROR: LM_ERR("%p - invalid query, execution aborted\n", _con); LM_ERR("%p: %s\n", _con, PQresStatus(pqresult)); LM_ERR("%p: %s\n", _con, PQresultErrorMessage(CON_RESULT(_con))); db_free_result(*_r); *_r = 0; rc = -3; break; case PGRES_EMPTY_QUERY: /* notice or warning */ case PGRES_NONFATAL_ERROR: /* status for COPY command, not used */ case PGRES_COPY_OUT: case PGRES_COPY_IN: /* unexpected response */ case PGRES_BAD_RESPONSE: default: LM_ERR("%p Probable invalid query\n", _con); LM_ERR("%p: %s\n", _con, PQresStatus(pqresult)); LM_ERR("%p: %s\n", _con, PQresultErrorMessage(CON_RESULT(_con))); db_free_result(*_r); *_r = 0; rc = -4; break; } done: free_query(_con); return (rc); }
/* * * pg_fetch_result: Gets a partial result set. * */ int db_postgres_fetch_result(const db_con_t* _con, db_res_t** _res, const int nrows) { int rows; ExecStatusType pqresult; if (!_con || !_res || nrows < 0) { LM_ERR("invalid parameter value\n"); return -1; } /* exit if the fetch count is zero */ if (nrows == 0) { if (*_res) db_free_result(*_res); *_res = 0; return 0; } if (*_res == NULL) { /* Allocate a new result structure */ *_res = db_new_result(); pqresult = PQresultStatus(CON_RESULT(_con)); LM_DBG("%p PQresultStatus(%s) PQgetResult(%p)\n", _con, PQresStatus(pqresult), CON_RESULT(_con)); switch(pqresult) { case PGRES_COMMAND_OK: /* Successful completion of a command returning no data * (such as INSERT or UPDATE). */ return 0; case PGRES_TUPLES_OK: /* Successful completion of a command returning data * (such as a SELECT or SHOW). */ if (db_postgres_get_columns(_con, *_res) < 0) { LM_ERR("failed to get column names\n"); return -2; } break; case PGRES_FATAL_ERROR: LM_ERR("%p - invalid query, execution aborted\n", _con); LM_ERR("%p - PQresultStatus(%s)\n",_con,PQresStatus(pqresult)); LM_ERR("%p: %s\n",_con,PQresultErrorMessage(CON_RESULT(_con))); if (*_res) db_free_result(*_res); *_res = 0; return -3; case PGRES_EMPTY_QUERY: /* notice or warning */ case PGRES_NONFATAL_ERROR: /* status for COPY command, not used */ case PGRES_COPY_OUT: case PGRES_COPY_IN: /* unexpected response */ case PGRES_BAD_RESPONSE: default: LM_ERR("%p - probable invalid query\n", _con); LM_ERR("%p - PQresultStatus(%s)\n",_con,PQresStatus(pqresult)); LM_ERR("%p: %s\n",_con,PQresultErrorMessage(CON_RESULT(_con))); if (*_res) db_free_result(*_res); *_res = 0; return -4; } } else { if(RES_ROWS(*_res) != NULL) { db_free_rows(*_res); } RES_ROWS(*_res) = 0; RES_ROW_N(*_res) = 0; } /* Get the number of rows (tuples) in the query result. */ RES_NUM_ROWS(*_res) = PQntuples(CON_RESULT(_con)); /* determine the number of rows remaining to be processed */ rows = RES_NUM_ROWS(*_res) - RES_LAST_ROW(*_res); /* If there aren't any more rows left to process, exit */ if (rows <= 0) return 0; /* if the fetch count is less than the remaining rows to process */ /* set the number of rows to process (during this call) equal to * the fetch count */ if (nrows < rows) rows = nrows; RES_ROW_N(*_res) = rows; LM_DBG("converting row %d of %d count %d\n", RES_LAST_ROW(*_res), RES_NUM_ROWS(*_res), RES_ROW_N(*_res)); if (db_postgres_convert_rows(_con, *_res) < 0) { LM_ERR("failed to convert rows\n"); if (*_res) db_free_result(*_res); *_res = 0; return -3; } /* update the total number of rows processed */ RES_LAST_ROW(*_res) += rows; return 0; }
int perlresult2dbres(SV *perlres, db_res_t **r) { HV * result = NULL; SV *colarrayref = NULL; AV *colarray = NULL; SV *acol = NULL; int colcount = 0; SV *rowarrayref = NULL; AV *rowarray = NULL; int rowcount = 0; SV *arowref = NULL; AV *arow = NULL; int arowlen = 0; SV *aelement = NULL; SV *atypesv = 0; int atype = 0; SV *aval = NULL; char *charbuf; char *currentstring; int i, j; int retval = 0; STRLEN len; SV *d1; /* helper variables */ /*db_val_t cur_val;*/ /* Abbreviation in "switch" below. The currently modified db result value. */ if (!(SvROK(perlres) && (sv_derived_from(perlres, "OpenSIPS::VDB::Result")))) { goto error; } result = (HV*)SvRV(perlres); /* Memory allocation for C side result structure */ *r = db_new_result(); /* Fetch column definitions */ colarrayref = *hv_fetchs(result, PERL_VDB_COLDEFSMETHOD, 0); /* colarrayref = perlvdb_perlmethod(perlres, PERL_VDB_COLDEFSMETHOD, NULL, NULL, NULL, NULL); */ if (!(SvROK(colarrayref))) goto error; colarray = (AV *)SvRV(colarrayref); /* SvREFCNT_dec(colarray); */ if (!(SvTYPE(colarray) == SVt_PVAV)) goto error; colcount = av_len(colarray) + 1; RES_COL_N(*r) = colcount; db_allocate_columns(*r, colcount); /* reverse direction, as elements are removed by "SvREFCNT_dec" */ for (i = colcount-1; i >= 0; i--) { acol = *av_fetch(colarray, i, 0); d1 = perlvdb_perlmethod(acol, PERL_VDB_TYPEMETHOD, NULL, NULL, NULL, NULL); if (!SvIOK(d1)) goto error; (*r)->col.types[i] = SvIV(d1); SvREFCNT_dec(d1); d1 = perlvdb_perlmethod(acol, PERL_VDB_NAMEMETHOD, NULL, NULL, NULL, NULL); if (!SvPOK(d1)) goto error; currentstring = SvPV(d1, len); charbuf = pkg_malloc(len+1); /* Column names buffers are freed in the perlvdb free function */ strncpy(charbuf, currentstring, len+1); (*r)->col.names[i]->s = charbuf; (*r)->col.names[i]->len = strlen(charbuf); SvREFCNT_dec(d1); } if(hv_exists(result, "rows", 4)){ rowarrayref =(SV*) hv_fetchs(result, "rows", 0); }else{ (*r)->n = 0; (*r)->res_rows = 0; (*r)->last_row = 0; goto end; } if(rowarrayref){ rowarrayref = *((SV**)rowarrayref); }else{ (*r)->n = 0; (*r)->res_rows = 0; (*r)->last_row = 0; goto end; } if (!(SvROK(rowarrayref))) { /* Empty result set */ (*r)->n = 0; (*r)->res_rows = 0; (*r)->last_row = 0; goto end; } rowarray = (AV *)SvRV(rowarrayref); if (!(SvTYPE(rowarray) == SVt_PVAV)) goto error; rowcount = av_len(rowarray) + 1; (*r)->n = rowcount; (*r)->res_rows = rowcount; (*r)->last_row = rowcount; db_allocate_rows(*r, rowcount); /* (rows * (sizeof(db_row_t) + sizeof(db_val_t) * RES_COL_N(_res)) */ /* LM_DBG("We got %d rows each row requres %d bytes because the row struct is %d and" "the values in that row take up %d. That is %d values each size is %d\n", rowcount, sizeof(db_row_t) + sizeof(db_val_t) * RES_COL_N(*r), sizeof(db_row_t), sizeof(db_val_t) * RES_COL_N(*r), RES_COL_N(*r), sizeof(db_val_t)); */ for (i = 0; i < rowcount; i++) { arowref = *av_fetch(rowarray, i, 0); if (!SvROK(arowref)) goto error; arow = (AV *)SvRV(arowref); if (!(SvTYPE(colarray) == SVt_PVAV)) goto error; arowlen = av_len(arow) + 1; (*r)->rows[i].n = arowlen; for (j = 0; j < arowlen; j++) { aelement = *av_fetch(arow, j, 0); #define cur_val (((*r)->rows)[i].values)[j] /*cur_val = (((*r)->rows)[i].values)[j];*/ /* cur_val is just an "abbreviation" */ if (!(sv_isobject(aelement) && sv_derived_from(aelement, PERL_CLASS_VALUE))) { cur_val.nul = 1; continue; } atypesv = *hv_fetchs((HV*)SvRV(aelement),PERL_VDB_TYPEMETHOD,0); /*aelement->{type} */ atype = SvIV(atypesv); /*atypesv = perlvdb_perlmethod(aelement, PERL_VDB_TYPEMETHOD, NULL, NULL, NULL, NULL);*/ aval = perlvdb_perlmethod(aelement, PERL_VDB_DATAMETHOD, NULL, NULL, NULL, NULL); (*r)->rows[i].values[j].type = atype; /* SvREFCNT_dec(atypesv); */ if (!SvOK(aval)) { cur_val.nul = 1; } else { switch (atype) { case DB_INT: cur_val.val.int_val = SvIV(aval); cur_val.nul = 0; break; case DB_DOUBLE: cur_val.val.double_val = SvNV(aval); cur_val.nul = 0; break; case DB_STRING: case DB_STR: /* We dont support DB_STR for now. * Set DB_STRING instead */ cur_val.type = DB_STRING; currentstring = SvPV(aval, len); charbuf = pkg_malloc(len+1); strncpy(charbuf, currentstring, len+1); cur_val.val.string_val = charbuf; cur_val.nul = 0; break; case DB_DATETIME: cur_val.val.time_val = (time_t)SvIV(aval); cur_val.nul = 0; break; case DB_BLOB: currentstring = SvPV(aval, len); charbuf = pkg_malloc(len+1); strncpy(charbuf, currentstring, len+1); cur_val.val.blob_val.s = charbuf; cur_val.val.blob_val.len = len; cur_val.nul = 0; break; case DB_BITMAP: cur_val.val.bitmap_val = SvIV(aval); cur_val.nul = 0; break; default: LM_CRIT("cannot handle this data type.\n"); return -1; break; } } SvREFCNT_dec(aval); } } end: return retval; error: LM_CRIT("broken result set. Exiting, leaving OpenSIPS in unknown state.\n"); return -1; }
/* * gets a partial result set * _h: structure representing the database connection * _r: pointer to a structure representing the result * nrows: number of fetched rows */ int db_mysql_fetch_result(db_con_t* _h, db_res_t** _r, int nrows) { int n; int i; if (!_h || !_r || nrows<0) { LM_ERR("Invalid parameter value\n"); return -1; } /* exit if the fetch count is zero */ if (nrows == 0) { db_mysql_free_dbresult(*_r); *_r = 0; return 0; } if(*_r==0) { /* Allocate a new result structure */ *_r = db_new_result(); if (*_r == 0) { LM_ERR("no memory left\n"); return -2; } CON_RESULT(_h) = mysql_store_result(CON_CONNECTION(_h)); if (!CON_RESULT(_h)) { if (mysql_field_count(CON_CONNECTION(_h)) == 0) { (*_r)->col.n = 0; (*_r)->n = 0; return 0; } else { LM_ERR("driver error: %s\n", mysql_error(CON_CONNECTION(_h))); db_mysql_free_dbresult(*_r); *_r = 0; return -3; } } if (db_mysql_get_columns(_h, *_r) < 0) { LM_ERR("error while getting column names\n"); return -4; } RES_NUM_ROWS(*_r) = mysql_num_rows(CON_RESULT(_h)); if (!RES_NUM_ROWS(*_r)) { RES_ROWS(*_r) = 0; return 0; } } else { /* free old rows */ if(RES_ROWS(*_r)!=0) db_free_rows(*_r); RES_ROWS(*_r) = 0; RES_ROW_N(*_r) = 0; } /* determine the number of rows remaining to be processed */ n = RES_NUM_ROWS(*_r) - RES_LAST_ROW(*_r); /* If there aren't any more rows left to process, exit */ if(n<=0) return 0; /* if the fetch count is less than the remaining rows to process */ /* set the number of rows to process (during this call) equal to the fetch count */ if(nrows < n) n = nrows; RES_LAST_ROW(*_r) += n; RES_ROW_N(*_r) = n; RES_ROWS(*_r) = (struct db_row*)pkg_malloc(sizeof(db_row_t) * n); if (!RES_ROWS(*_r)) { LM_ERR("no memory left\n"); return -5; } for(i = 0; i < n; i++) { CON_ROW(_h) = mysql_fetch_row(CON_RESULT(_h)); if (!CON_ROW(_h)) { LM_ERR("driver error: %s\n", mysql_error(CON_CONNECTION(_h))); RES_ROW_N(*_r) = i; db_free_rows(*_r); return -6; } if (db_mysql_convert_row(_h, *_r, &(RES_ROWS(*_r)[i])) < 0) { LM_ERR("error while converting row #%d\n", i); RES_ROW_N(*_r) = i; db_free_rows(*_r); return -7; } } return 0; }
/*! * \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; }
/* * 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; }
/** * 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; }