/** * Convert rows from mysql to db API representation */ static inline int db_mysql_convert_rows(const db_con_t* _h, db_res_t* _r) { int row; if ((!_h) || (!_r)) { LM_ERR("invalid parameter\n"); return -1; } if (CON_HAS_PS(_h)) { RES_ROW_N(_r) = mysql_stmt_num_rows(CON_PS_STMT(_h)); } else { RES_ROW_N(_r) = mysql_num_rows(CON_RESULT(_h)); } if (!RES_ROW_N(_r)) { LM_DBG("no rows returned from the query\n"); RES_ROWS(_r) = 0; return 0; } if (db_allocate_rows( _r, RES_ROW_N(_r))!=0) { LM_ERR("no private memory left\n"); return -2; } for(row = 0; row < RES_ROW_N(_r); row++) { if (CON_HAS_PS(_h)) { mysql_stmt_fetch(CON_PS_STMT(_h)); //if(mysql_stmt_fetch(CON_PS_STMT(_h))!=1) // LM_ERR("STMT ERR=%s\n",mysql_stmt_error(CON_PS_STMT(_h))); } else { 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) = row; db_free_rows(_r); return -3; } } if (db_mysql_convert_row(_h, _r, &(RES_ROWS(_r)[row])) < 0) { LM_ERR("error while converting row #%d\n", row); RES_ROW_N(_r) = row; db_free_rows(_r); return -4; } } return 0; }
/* * Convert rows from internal to db API representation */ static int dbt_convert_rows(db1_res_t* _r, dbt_result_p _dres) { int row; dbt_row_p _rp = NULL; if (!_r || !_dres) { LM_ERR("invalid parameter\n"); return -1; } RES_ROW_N(_r) = _dres->nrrows; if (!RES_ROW_N(_r)) { return 0; } if (db_allocate_rows(_r) < 0) { LM_ERR("could not allocate rows"); return -2; } row = 0; _rp = _dres->rows; while(_rp) { if (dbt_convert_row(_r, &(RES_ROWS(_r)[row]), _rp) < 0) { LM_ERR("failed to convert row #%d\n", row); RES_ROW_N(_r) = row; db_free_rows(_r); return -4; } row++; _rp = _rp->next; } 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; }
/* * Release memory used by a result structure */ int db_mysql_free_dbresult(db_res_t* _r) { if (!_r) { LM_ERR("invalid parameter\n"); return -1; } db_free_columns(_r); db_free_rows(_r); pkg_free(_r); return 0; }
/*! * \brief Convert rows from mysql to db API representation * \param _h database connection * \param _r database result set * \return 0 on success, negative on failure */ static inline int db_mysql_convert_rows(const db1_con_t* _h, db1_res_t* _r) { int row; if ((!_h) || (!_r)) { LM_ERR("invalid parameter\n"); return -1; } RES_ROW_N(_r) = mysql_num_rows(RES_RESULT(_r)); if (!RES_ROW_N(_r)) { LM_DBG("no rows returned from the query\n"); RES_ROWS(_r) = 0; return 0; } if (db_allocate_rows(_r) < 0) { LM_ERR("could not allocate rows"); RES_ROW_N(_r) = 0; return -2; } for(row = 0; row < RES_ROW_N(_r); row++) { RES_ROW(_r) = mysql_fetch_row(RES_RESULT(_r)); if (!RES_ROW(_r)) { LM_ERR("driver error: %s\n", mysql_error(CON_CONNECTION(_h))); RES_ROW_N(_r) = row; db_free_rows(_r); return -3; } if (db_mysql_convert_row(_h, _r, &(RES_ROWS(_r)[row])) < 0) { LM_ERR("error while converting row #%d\n", row); RES_ROW_N(_r) = row; db_free_rows(_r); return -4; } } return 0; }
/* * Convert rows from internal to db API representation */ static int dbt_convert_rows(db_con_t* _h, db_res_t* _r) { int col; dbt_row_p _rp = NULL; if (!_h || !_r) { LM_ERR("invalid parameter\n"); return -1; } RES_ROW_N(_r) = DBT_CON_RESULT(_h)->nrrows; if (!RES_ROW_N(_r)) { return 0; } if (db_allocate_rows( _r, RES_ROW_N(_r))!=0) { LM_ERR("no private memory left\n"); return -2; } col = 0; _rp = DBT_CON_RESULT(_h)->rows; while(_rp) { DBT_CON_ROW(_h) = _rp; if (!DBT_CON_ROW(_h)) { LM_ERR("failed to get current row\n"); RES_ROW_N(_r) = col; db_free_rows(_r); return -3; } if (dbt_convert_row(_h, _r, &(RES_ROWS(_r)[col])) < 0) { LM_ERR("failed to convert row #%d\n", col); RES_ROW_N(_r) = col; db_free_rows(_r); return -4; } col++; _rp = _rp->next; } return 0; }
/* * Convert rows from mysql to db API representation */ static inline int db_mysql_convert_rows(db_con_t* _h, db_res_t* _r) { int n, i; if ((!_h) || (!_r)) { LM_ERR("invalid parameter\n"); return -1; } n = mysql_num_rows(CON_RESULT(_h)); RES_ROW_N(_r) = n; if (!n) { RES_ROWS(_r) = 0; return 0; } RES_ROWS(_r) = (struct db_row*)pkg_malloc(sizeof(db_row_t) * n); if (!RES_ROWS(_r)) { LM_ERR("no private memory left\n"); return -2; } 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 -3; } 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 -4; } } return 0; }
/* * 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; }
int dbt_fetch_result(db1_con_t* _h, db1_res_t** _r, const int nrows) { int rows; if (!_h || !_r || nrows < 0) { LM_ERR("Invalid parameter value\n"); return -1; } /* exit if the fetch count is zero */ if (nrows == 0) { dbt_free_result(_h, *_r); *_r = 0; return 0; } if(*_r==0) { /* Allocate a new result structure */ dbt_init_result(_r, last_temp_table); } 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; return dbt_get_next_result(_r, RES_LAST_ROW(*_r), rows); }
/* * * 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; }
/* * Convert rows from UNIXODBC to db API representation */ static inline int db_unixodbc_convert_rows(const db_con_t* _h, db_res_t* _r) { int row_n = 0, i = 0, ret = 0; SQLSMALLINT columns; strn* temp_row = NULL; str *rows = NULL; if((!_h) || (!_r)) { LM_ERR("invalid parameter\n"); return -1; } SQLNumResultCols(CON_RESULT(_h), (SQLSMALLINT *)&columns); temp_row = (strn*)pkg_malloc( columns*sizeof(strn) ); if(!temp_row) { LM_ERR("no private memory left\n"); return E_OUT_OF_MEM; } while (SQL_SUCCEEDED(ret = SQLFetch(CON_RESULT(_h)))) { for(i=0; i < columns; i++) { SQLLEN indicator; ret = SQLGetData(CON_RESULT(_h), i+1, SQL_C_CHAR, temp_row[i].s, STRN_LEN, &indicator); if (SQL_SUCCEEDED(ret)) { if (indicator == SQL_NULL_DATA) strcpy(temp_row[i].s, "NULL"); } else { LM_ERR("SQLGetData failed\n"); } } rows = db_unixodbc_dup_row(temp_row, row_n, columns); if (!rows) { LM_ERR("no more pkg mem\n"); return E_OUT_OF_MEM; } row_n++; } /* free temporary row data */ pkg_free(temp_row); CON_ROW(_h) = NULL; RES_ROW_N(_r) = row_n; if (row_n == 0) { RES_ROWS(_r) = NULL; return 0; } if (db_allocate_rows(_r, row_n) != 0) { LM_ERR("no private memory left\n"); return E_OUT_OF_MEM; } for (i = 0; i < row_n; i++) { if (db_unixodbc_convert_row(&rows[i * columns], _r, &RES_ROWS(_r)[i]) < 0) { LM_ERR("converting row failed #%d\n", i); RES_ROW_N(_r) = 0; db_free_rows(_r); return -4; } } return 0; }
/** * 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 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; }
/*! * \brief Convert rows from PostgreSQL to db API representation * \param _h database connection * \param _r result set * \return 0 on success, negative on error */ int db_postgres_convert_rows(const db1_con_t* _h, db1_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); if (db_allocate_rows(_r) < 0) { LM_ERR("could not allocate rows\n"); LM_DBG("freeing row buffer at %p\n", row_buf); pkg_free(row_buf); return -2; } for(row = RES_LAST_ROW(_r); row < (RES_LAST_ROW(_r) + RES_ROW_N(_r)); row++) { /* reset row buf content */ memset(row_buf, 0, len); 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. */ s = PQgetvalue(CON_RESULT(_h), row, col); LM_DBG("PQgetvalue(%p,%d,%d)=[%s]\n", _h, row, col, s); /* * A empty string can be a NULL value, or just an empty string. * This differs from the mysql behaviour, that further processing * steps expect. So we need to simulate this here unfortunally. */ if (PQgetisnull(CON_RESULT(_h), row, col) == 0) { row_buf[col] = s; 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); LM_DBG("freeing row buffer at %p\n", row_buf); pkg_free(row_buf); db_free_rows(_r); return -4; } } LM_DBG("freeing row buffer at %p\n", row_buf); pkg_free(row_buf); row_buf = NULL; return 0; }
/* * Get rows and convert it from oracle to db API representation */ static int get_rows(ora_con_t* con, db_res_t* _r, OCIStmt* _c, dmap_t* _d) { ub4 rcnt; sword status; unsigned n = RES_COL_N(_r); memcpy(_d->len, _d->ilen, sizeof(_d->len[0]) * n); // timelimited operation status = begin_timelimit(con, 0); if (status != OCI_SUCCESS) goto ora_err; do status = OCIStmtFetch2(_c, con->errhp, 1, OCI_FETCH_NEXT, 0, OCI_DEFAULT); while (wait_timelimit(con, status)); if (done_timelimit(con, status)) goto stop_load; if (status != OCI_SUCCESS) { if (status != OCI_NO_DATA) goto ora_err; RES_ROW_N(_r) = 0; RES_ROWS(_r) = NULL; return 0; } status = OCIAttrGet(_c, OCI_HTYPE_STMT, &rcnt, NULL, OCI_ATTR_CURRENT_POSITION, con->errhp); if (status != OCI_SUCCESS) goto ora_err; if (!rcnt) { LM_ERR("lastpos==0\n"); goto stop_load; } RES_ROW_N(_r) = rcnt; if (db_allocate_rows( _r, rcnt)!=0) { LM_ERR("no private memory left\n"); return -1; } while ( 1 ) { if (convert_row(_r, &RES_ROWS(_r)[--rcnt], _d) < 0) { LM_ERR("error convert row\n"); goto stop_load; } if (!rcnt) return 0; memcpy(_d->len, _d->ilen, sizeof(_d->len[0]) * n); // timelimited operation status = begin_timelimit(con, 0); if (status != OCI_SUCCESS) goto ora_err; do status = OCIStmtFetch2(_c, con->errhp, 1, OCI_FETCH_PRIOR, 0, OCI_DEFAULT); while (wait_timelimit(con, status)); if (done_timelimit(con, status)) goto stop_load; if (status != OCI_SUCCESS) break; } ora_err: LM_ERR("driver: %s\n", db_oracle_error(con, status)); stop_load: db_free_rows(_r); RES_ROW_N(_r) = 0; /* TODO: skipped in db_res.c :) */ return -3; }
/*! * \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; }
/* * 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; }
/* * Convert rows from UNIXODBC to db API representation */ static inline int db_unixodbc_convert_rows(const db1_con_t* _h, db1_res_t* _r) { int i = 0, ret = 0; SQLSMALLINT columns; list* rows = NULL; list* rowstart = NULL; strn* temp_row = NULL; if((!_h) || (!_r)) { LM_ERR("invalid parameter\n"); return -1; } SQLNumResultCols(CON_RESULT(_h), (SQLSMALLINT *)&columns); temp_row = (strn*)pkg_malloc( columns*sizeof(strn) ); if(!temp_row) { LM_ERR("no private memory left\n"); return -1; } while(SQL_SUCCEEDED(ret = SQLFetch(CON_RESULT(_h)))) { for(i=0; i < columns; i++) { SQLLEN indicator; ret = SQLGetData(CON_RESULT(_h), i+1, SQL_C_CHAR, temp_row[i].s, STRN_LEN, &indicator); if (SQL_SUCCEEDED(ret)) { if (indicator == SQL_NULL_DATA) strcpy(temp_row[i].s, "NULL"); } else { LM_ERR("SQLGetData failed\n"); } } if (db_unixodbc_list_insert(&rowstart, &rows, columns, temp_row) < 0) { LM_ERR("insert failed\n"); pkg_free(temp_row); temp_row= NULL; return -5; } RES_ROW_N(_r)++; } /* free temporary row data */ pkg_free(temp_row); CON_ROW(_h) = NULL; if (!RES_ROW_N(_r)) { RES_ROWS(_r) = 0; return 0; } if (db_allocate_rows(_r) != 0) { LM_ERR("could not allocate rows"); db_unixodbc_list_destroy(rowstart); return -2; } i = 0; rows = rowstart; while(rows) { CON_ROW(_h) = rows->data; if (!CON_ROW(_h)) { LM_ERR("string null\n"); RES_ROW_N(_r) = i; db_free_rows(_r); db_unixodbc_list_destroy(rowstart); return -3; } if (db_unixodbc_convert_row(_h, _r, &(RES_ROWS(_r)[i]), rows->lengths) < 0) { LM_ERR("converting row failed #%d\n", i); RES_ROW_N(_r) = i; db_free_rows(_r); db_unixodbc_list_destroy(rowstart); return -4; } i++; rows = rows->next; } db_unixodbc_list_destroy(rowstart); return 0; }