static int free_query(db_con_t* _h) { if(CON_RESULT(_h)) { PQclear(CON_RESULT(_h)); CON_RESULT(_h) = 0; } 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; }
static int free_query(const db_con_t* _con) { if(CON_RESULT(_con)) { LM_DBG("PQclear(%p) result set\n", CON_RESULT(_con)); PQclear(CON_RESULT(_con)); CON_RESULT(_con) = 0; } return 0; }
/** * Release a result set from memory. * \param _h handle to the database * \param _r result set that should be freed * \return zero on success, negative value on failure */ int db_mysql_free_result(db1_con_t* _h, db1_res_t* _r) { if ((!_h) || (!_r)) { LM_ERR("invalid parameter value\n"); return -1; } if (db_free_result(_r) < 0) { LM_ERR("unable to free result structure\n"); return -1; } mysql_free_result(CON_RESULT(_h)); CON_RESULT(_h) = 0; return 0; }
/** * 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 a row from result into db API representation */ int convert_row(db_con_t* _h, db_res_t* _res, db_row_t* _r) { unsigned long* lengths; int i; #ifndef PARANOID if ((!_h) || (!_r) || (!_n)) { log(L_ERR, "convert_row(): Invalid parameter value\n"); return -1; } #endif ROW_VALUES(_r) = (db_val_t*)pkg_malloc(sizeof(db_val_t) * RES_COL_N(_res)); ROW_N(_r) = RES_COL_N(_res); if (!ROW_VALUES(_r)) { LOG(L_ERR, "convert_row(): No memory left\n"); return -1; } lengths = mysql_fetch_lengths(CON_RESULT(_h)); for(i = 0; i < RES_COL_N(_res); i++) { if (str2val(RES_TYPES(_res)[i], &(ROW_VALUES(_r)[i]), ((MYSQL_ROW)CON_ROW(_h))[i], lengths[i]) < 0) { LOG(L_ERR, "convert_row(): Error while converting value\n"); free_row(_r); return -3; } } return 0; }
/*! * \brief Convert a row from result into DB API representation * \param _h database connection * \param _res database result in the DB API representation * \param _r database result row * \return 0 on success, -1 on failure */ int db_mysql_convert_row(const db1_con_t* _h, db1_res_t* _res, db_row_t* _r) { unsigned long* lengths; int i; if ((!_h) || (!_res) || (!_r)) { LM_ERR("invalid parameter value\n"); return -1; } if (db_allocate_row(_res, _r) != 0) { LM_ERR("could not allocate row"); return -2; } lengths = mysql_fetch_lengths(CON_RESULT(_h)); for(i = 0; i < RES_COL_N(_res); i++) { if (db_str2val(RES_TYPES(_res)[i], &(ROW_VALUES(_r)[i]), ((MYSQL_ROW)CON_ROW(_h))[i], lengths[i], 0) < 0) { LM_ERR("failed to convert value\n"); LM_DBG("free row at %p\n", _r); db_free_row(_r); return -3; } } return 0; }
/* * Release a result set from memory */ int db_unixodbc_free_result(db1_con_t* _h, db1_res_t* _r) { if ((!_h) || (!_r)) { LM_ERR("invalid parameter value\n"); return -1; } if (db_free_result(_r) < 0) { LM_ERR("failed to free result structure\n"); return -1; } SQLFreeHandle(SQL_HANDLE_STMT, CON_RESULT(_h)); CON_RESULT(_h) = 0; return 0; }
/* * 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; }
int db_postgres_async_resume(db_con_t *_h, int fd, db_res_t **_r, void *_priv) { struct pool_con *con = (struct pool_con *)_priv; PGresult *res = NULL; #ifdef EXTRA_DEBUG if (!db_match_async_con(fd, _h)) { LM_BUG("no conn match for fd %d", fd); abort(); } #endif db_switch_to_async(_h, con); if( PQconsumeInput(CON_CONNECTION(_h)) == 0) { LM_ERR("Unable to consume input\n"); db_switch_to_sync(_h); db_store_async_con(_h, con); return -1; } if(PQisBusy(CON_CONNECTION(_h))) { async_status = ASYNC_CONTINUE; db_switch_to_sync(_h); return 1; } while (1) { if ((res = PQgetResult(CON_CONNECTION(_h)))) { CON_RESULT(_h) = res; } else { break; } } if (_r) { if (db_postgres_store_result(_h, _r) != 0) { LM_ERR("failed to store result\n"); db_switch_to_sync(_h); db_store_async_con(_h, con); return -2; } } db_switch_to_sync(_h); db_store_async_con(_h, con); 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; }
/* * Retrieve result set */ int get_result(db_con_t* _h, db_res_t** _r) { *_r = new_result_pg(CON_SQLURL(_h)); if (!CON_RESULT(_h)) { LOG(L_ERR, "get_result(): error"); free_result(*_r); *_r = 0; return -3; } if (convert_result(_h, *_r) < 0) { LOG(L_ERR, "get_result(): Error while converting result\n"); free_result(*_r); *_r = 0; return -4; } return 0; }
/* * Reconnect if connection is broken */ static int reconnect(const db1_con_t* _h) { int ret = 0; SQLCHAR outstr[1024]; SQLSMALLINT outstrlen; char conn_str[MAX_CONN_STR_LEN]; LM_ERR("Attempting DB reconnect\n"); /* Disconnect */ SQLDisconnect (CON_CONNECTION(_h)); /* Reconnect */ if (!db_unixodbc_build_conn_str(CON_ID(_h), conn_str)) { LM_ERR("failed to build connection string\n"); return ret; } ret = SQLDriverConnect(CON_CONNECTION(_h), (void *)1, (SQLCHAR*)conn_str, SQL_NTS, outstr, sizeof(outstr), &outstrlen, SQL_DRIVER_COMPLETE); if (!SQL_SUCCEEDED(ret)) { LM_ERR("failed to connect\n"); db_unixodbc_extract_error("SQLDriverConnect", CON_CONNECTION(_h), SQL_HANDLE_DBC, NULL); return ret; } ret = SQLAllocHandle(SQL_HANDLE_STMT, CON_CONNECTION(_h), &CON_RESULT(_h)); if (!SQL_SUCCEEDED(ret)) { LM_ERR("Statement allocation error %d\n", (int)(long)CON_CONNECTION(_h)); db_unixodbc_extract_error("SQLAllocStmt", CON_CONNECTION(_h), SQL_HANDLE_DBC,NULL); return ret; } return ret; }
/** * Convert a row from result into db API representation */ int db_mysql_convert_row(const db_con_t* _h, db_res_t* _res, db_row_t* _r) { unsigned long* lengths; int i; if ((!_h) || (!_res) || (!_r)) { LM_ERR("invalid parameter value\n"); return -1; } /* Save the number of columns in the ROW structure */ ROW_N(_r) = RES_COL_N(_res); if (CON_HAS_PS(_h)) { for(i=0; i < CON_MYSQL_PS(_h)->cols_out; i++) { if (db_mysql_str2val(RES_TYPES(_res)[i], &(ROW_VALUES(_r)[i]), CON_PS_OUTCOL(_h, i).null?NULL:CON_PS_OUTCOL(_h, i).buf, CON_PS_OUTCOL(_h,i).len) < 0) { LM_ERR("failed to convert value from stmt\n"); db_free_row(_r); return -3; } } } else { lengths = mysql_fetch_lengths(CON_RESULT(_h)); for(i = 0; i < RES_COL_N(_res); i++) { if (db_mysql_str2val(RES_TYPES(_res)[i], &(ROW_VALUES(_r)[i]), ((MYSQL_ROW)CON_ROW(_h))[i], lengths[i]) < 0) { LM_ERR("failed to convert value\n"); LM_DBG("free row at %p\n", _r); db_free_row(_r); return -3; } } } return 0; }
/* * Get and convert columns from a result */ int db_mysql_get_columns(db_con_t* _h, db_res_t* _r) { int n, i; MYSQL_FIELD* fields; if ((!_h) || (!_r)) { LM_ERR("invalid parameter\n"); return -1; } n = mysql_field_count(CON_CONNECTION(_h)); if (!n) { LM_ERR("no columns\n"); return -2; } RES_NAMES(_r) = (db_key_t*)pkg_malloc(sizeof(db_key_t) * n); if (!RES_NAMES(_r)) { LM_ERR("no private memory left\n"); return -3; } RES_TYPES(_r) = (db_type_t*)pkg_malloc(sizeof(db_type_t) * n); if (!RES_TYPES(_r)) { LM_ERR("no private memory left\n"); pkg_free(RES_NAMES(_r)); return -4; } RES_COL_N(_r) = n; fields = mysql_fetch_fields(CON_RESULT(_h)); for(i = 0; i < n; i++) { RES_NAMES(_r)[i] = fields[i].name; switch(fields[i].type) { case FIELD_TYPE_TINY: case FIELD_TYPE_SHORT: case FIELD_TYPE_LONG: case FIELD_TYPE_INT24: case FIELD_TYPE_LONGLONG: case FIELD_TYPE_DECIMAL: case FIELD_TYPE_TIMESTAMP: RES_TYPES(_r)[i] = DB_INT; break; case FIELD_TYPE_FLOAT: case FIELD_TYPE_DOUBLE: RES_TYPES(_r)[i] = DB_DOUBLE; break; case FIELD_TYPE_DATETIME: RES_TYPES(_r)[i] = DB_DATETIME; break; case FIELD_TYPE_BLOB: case FIELD_TYPE_TINY_BLOB: case FIELD_TYPE_MEDIUM_BLOB: case FIELD_TYPE_LONG_BLOB: RES_TYPES(_r)[i] = DB_BLOB; break; case FIELD_TYPE_SET: RES_TYPES(_r)[i] = DB_BITMAP; break; default: RES_TYPES(_r)[i] = DB_STRING; break; } } return 0; }
/** * \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; }
/* * 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; }
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); }
/* * 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; }
/* * * 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; }
/*! * \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; }
/*! * \brief Submit_query, run a query * \param _con database connection * \param _s query string * \return 0 on success, negative on failure */ static int db_postgres_submit_query(const db1_con_t* _con, const str* _s) { int i, retries; ExecStatusType pqresult; if(! _con || !_s || !_s->s) { LM_ERR("invalid parameter value\n"); return(-1); } /* this bit of nonsense in case our connection get screwed up */ switch(PQstatus(CON_CONNECTION(_con))) { case CONNECTION_OK: break; case CONNECTION_BAD: LM_DBG("connection reset\n"); PQreset(CON_CONNECTION(_con)); break; case CONNECTION_STARTED: case CONNECTION_MADE: case CONNECTION_AWAITING_RESPONSE: case CONNECTION_AUTH_OK: case CONNECTION_SETENV: case CONNECTION_SSL_STARTUP: case CONNECTION_NEEDED: default: LM_ERR("%p PQstatus(%s) invalid: %.*s\n", _con, PQerrorMessage(CON_CONNECTION(_con)), _s->len, _s->s); return -1; } if (CON_TRANSACTION(_con) == 1) retries = 0; else retries = pg_retries; for(i = 0; i <= retries; i++) { /* free any previous query that is laying about */ db_postgres_free_query(_con); /* exec the query */ if (PQsendQuery(CON_CONNECTION(_con), _s->s)) { pqresult = PQresultStatus(CON_RESULT(_con)); if((pqresult!=PGRES_FATAL_ERROR) || (PQstatus(CON_CONNECTION(_con))==CONNECTION_OK)) { LM_DBG("sending query ok: %p (%d) - [%.*s]\n", _con, pqresult, _s->len, _s->s); return 0; } LM_WARN("postgres result check failed with code %d (%s)\n", pqresult, PQresStatus(pqresult)); } LM_WARN("postgres query command failed, connection status %d," " error [%s]\n", PQstatus(CON_CONNECTION(_con)), PQerrorMessage(CON_CONNECTION(_con))); if(PQstatus(CON_CONNECTION(_con))!=CONNECTION_OK) { LM_DBG("reseting the connection to postgress server\n"); PQreset(CON_CONNECTION(_con)); } } LM_ERR("%p PQsendQuery Error: %s Query: %.*s\n", _con, PQerrorMessage(CON_CONNECTION(_con)), _s->len, _s->s); return -1; }
static int db_postgres_submit_query(const db_con_t* _con, const str* _s) { int i; ExecStatusType result; PGresult *res = NULL; if(! _con || !_s || !_s->s) { LM_ERR("invalid parameter value\n"); return(-1); } submit_func_called = 1; /* this bit of nonsense in case our connection get screwed up */ switch(PQstatus(CON_CONNECTION(_con))) { case CONNECTION_OK: break; case CONNECTION_BAD: LM_DBG("connection reset\n"); PQreset(CON_CONNECTION(_con)); break; case CONNECTION_STARTED: case CONNECTION_MADE: case CONNECTION_AWAITING_RESPONSE: case CONNECTION_AUTH_OK: case CONNECTION_SETENV: case CONNECTION_SSL_STARTUP: case CONNECTION_NEEDED: default: LM_ERR("%p PQstatus(%s) invalid: %.*s\n", _con, PQerrorMessage(CON_CONNECTION(_con)), _s->len, _s->s); return -1; } for (i=0;i<2;i++) { /* free any previous query that is laying about */ if(CON_RESULT(_con)) { free_query(_con); } /* exec the query */ if (PQsendQuery(CON_CONNECTION(_con), _s->s)) { LM_DBG("%p PQsendQuery(%.*s)\n", _con, _s->len, _s->s); while (1) { if ((res = PQgetResult(CON_CONNECTION(_con)))) { CON_RESULT(_con) = res; } else { break; } } result = PQresultStatus(CON_RESULT(_con)); if(result==PGRES_FATAL_ERROR) goto reconnect; else return 0; } else { reconnect: /* reconnection attempt - if this is the case */ LM_DBG("%p PQsendQuery failed: %s Query: %.*s\n", _con, PQerrorMessage(CON_CONNECTION(_con)), _s->len, _s->s); if(PQstatus(CON_CONNECTION(_con))!=CONNECTION_OK) { LM_DBG("connection reset\n"); PQreset(CON_CONNECTION(_con)); } else { /* failure not due to connection loss - no point in retrying */ if(CON_RESULT(_con)) { free_query(_con); } break; } } } LM_ERR("%p PQsendQuery Error: %s Query: %.*s\n", _con, PQerrorMessage(CON_CONNECTION(_con)), _s->len, _s->s); return 0; }
static int db_postgres_submit_async_query(const db_con_t* _con, const str* _s) { int i,ret=0; struct timeval start; if(! _con || !_s || !_s->s) { LM_ERR("invalid parameter value\n"); return(-1); } submit_func_called = 1; /* this bit of nonsense in case our connection get screwed up */ switch(PQstatus(CON_CONNECTION(_con))) { case CONNECTION_OK: break; case CONNECTION_BAD: LM_DBG("connection reset\n"); PQreset(CON_CONNECTION(_con)); break; case CONNECTION_STARTED: case CONNECTION_MADE: case CONNECTION_AWAITING_RESPONSE: case CONNECTION_AUTH_OK: case CONNECTION_SETENV: case CONNECTION_SSL_STARTUP: case CONNECTION_NEEDED: default: LM_ERR("%p PQstatus(%s) invalid: %.*s\n", _con, PQerrorMessage(CON_CONNECTION(_con)), _s->len, _s->s); return -1; } for (i=0;i<max_db_queries;i++) { /* free any previous query that is laying about */ if(CON_RESULT(_con)) { free_query(_con); } start_expire_timer(start,db_postgres_exec_query_threshold); ret = PQsendQuery(CON_CONNECTION(_con), _s->s); _stop_expire_timer(start, db_postgres_exec_query_threshold, "pgsql query", _s->s, _s->len, 0, sql_slow_queries, sql_total_queries); /* exec the query */ if (ret) { LM_DBG("%p PQsendQuery(%.*s)\n", _con, _s->len, _s->s); return 0; } else { LM_DBG("%p PQsendQuery failed: %s Query: %.*s\n", _con, PQerrorMessage(CON_CONNECTION(_con)), _s->len, _s->s); if(PQstatus(CON_CONNECTION(_con))!=CONNECTION_OK) { LM_DBG("connection reset\n"); PQreset(CON_CONNECTION(_con)); } else { /* failure not due to connection loss - no point in retrying */ if(CON_RESULT(_con)) { free_query(_con); } break; } } } LM_ERR("%p PQsendQuery Error: %s Query: %.*s\n", _con, PQerrorMessage(CON_CONNECTION(_con)), _s->len, _s->s); return -1; }
/* * Send an SQL query to the server */ static int db_unixodbc_submit_query(const db1_con_t* _h, const str* _s) { int ret = 0; SQLCHAR sqlstate[7]; if (!_h || !_s || !_s->s) { LM_ERR("invalid parameter value\n"); return -1; } /* first do some cleanup if required */ if(CON_RESULT(_h)) { SQLCloseCursor(CON_RESULT(_h)); SQLFreeHandle(SQL_HANDLE_STMT, CON_RESULT(_h)); } ret = SQLAllocHandle(SQL_HANDLE_STMT, CON_CONNECTION(_h), &CON_RESULT(_h)); if (!SQL_SUCCEEDED(ret)) { LM_ERR("statement allocation error %d\n", (int)(long)CON_CONNECTION(_h)); db_unixodbc_extract_error("SQLAllocStmt", CON_CONNECTION(_h), SQL_HANDLE_DBC, (char*)sqlstate); /* Connection broken */ if( !strncmp((char*)sqlstate,"08003",5) || !strncmp((char*)sqlstate,"08S01",5) ) { ret = reconnect(_h); if( !SQL_SUCCEEDED(ret) ) return ret; } else { return ret; } } ret=SQLExecDirect(CON_RESULT(_h), (SQLCHAR*)_s->s, _s->len); /* Handle SQL_NO_DATA as a valid return code. DELETE and UPDATE statements may return this return code if nothing was deleted/updated. */ if (!SQL_SUCCEEDED(ret) && (ret != SQL_NO_DATA)) { SQLCHAR sqlstate[7]; LM_ERR("rv=%d. Query= %.*s\n", ret, _s->len, _s->s); db_unixodbc_extract_error("SQLExecDirect", CON_RESULT(_h), SQL_HANDLE_STMT, (char*)sqlstate); /* Connection broken */ if( !strncmp((char*)sqlstate,"08003",5) || !strncmp((char*)sqlstate,"08S01",5) || !strncmp((char*)sqlstate,"HY000",5) /* ODBC 3 General error */ ) { ret = reconnect(_h); if( SQL_SUCCEEDED(ret) ) { /* Try again */ ret=SQLExecDirect(CON_RESULT(_h), (SQLCHAR*)_s->s, _s->len); if (!SQL_SUCCEEDED(ret)) { LM_ERR("rv=%d. Query= %.*s\n", ret, _s->len, _s->s); db_unixodbc_extract_error("SQLExecDirect", CON_RESULT(_h), SQL_HANDLE_STMT, (char*)sqlstate); /* Close the cursor */ SQLCloseCursor(CON_RESULT(_h)); SQLFreeHandle(SQL_HANDLE_STMT, CON_RESULT(_h)); } } } else { /* Close the cursor */ SQLCloseCursor(CON_RESULT(_h)); SQLFreeHandle(SQL_HANDLE_STMT, CON_RESULT(_h)); } } /* Store the ODBC query result */ CON_QUERY_RESULT(_h) = ret; return ret; }
/*! * \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); }
/** * Get and convert columns from a result set */ int db_postgres_get_columns(const db_con_t* _h, db_res_t* _r) { int col, datatype; if (!_h || !_r) { LM_ERR("invalid parameter value\n"); return -1; } /* Get the number of rows (tuples) in the query result. */ RES_ROW_N(_r) = PQntuples(CON_RESULT(_h)); /* Get the number of columns (fields) in each row of the query result. */ RES_COL_N(_r) = PQnfields(CON_RESULT(_h)); if (!RES_COL_N(_r)) { LM_DBG("no columns returned from the query\n"); return -2; } else { LM_DBG("%d columns returned from the query\n", RES_COL_N(_r)); } if (db_allocate_columns(_r, RES_COL_N(_r)) != 0) { LM_ERR("could not allocate columns\n"); return -3; } /* For each column both the name and the OID number of the * data type are saved. */ for(col = 0; col < RES_COL_N(_r); col++) { /* The pointer that is here returned is part of the result structure.*/ RES_NAMES(_r)[col]->s = PQfname(CON_RESULT(_h), col); RES_NAMES(_r)[col]->len = strlen(PQfname(CON_RESULT(_h), col)); LM_DBG("RES_NAMES(%p)[%d]=[%.*s]\n", RES_NAMES(_r)[col], col, RES_NAMES(_r)[col]->len, RES_NAMES(_r)[col]->s); /* get the datatype of the column */ switch(datatype = PQftype(CON_RESULT(_h),col)) { case INT2OID: case INT4OID: case INT8OID: LM_DBG("use DB_INT result type\n"); RES_TYPES(_r)[col] = DB_INT; break; case FLOAT4OID: case FLOAT8OID: case NUMERICOID: LM_DBG("use DB_DOUBLE result type\n"); RES_TYPES(_r)[col] = DB_DOUBLE; break; case DATEOID: case TIMESTAMPOID: case TIMESTAMPTZOID: LM_DBG("use DB_DATETIME result type\n"); RES_TYPES(_r)[col] = DB_DATETIME; break; case BOOLOID: case CHAROID: case VARCHAROID: case BPCHAROID: LM_DBG("use DB_STRING result type\n"); RES_TYPES(_r)[col] = DB_STRING; break; case TEXTOID: case BYTEAOID: LM_DBG("use DB_BLOB result type\n"); RES_TYPES(_r)[col] = DB_BLOB; break; case BITOID: case VARBITOID: LM_DBG("use DB_BITMAP result type\n"); RES_TYPES(_r)[col] = DB_BITMAP; break; default: LM_WARN("unhandled data type column (%.*s) type id (%d), " "use DB_STRING as default\n", RES_NAMES(_r)[col]->len, RES_NAMES(_r)[col]->s, datatype); RES_TYPES(_r)[col] = DB_STRING; break; } } return 0; }
/* * Get and convert columns from a result */ int db_unixodbc_get_columns(const db1_con_t* _h, db1_res_t* _r) { int col; SQLSMALLINT cols; /* because gcc don't like RES_COL_N */ if ((!_h) || (!_r)) { LM_ERR("invalid parameter\n"); return -1; } /* Save number of columns in the result structure */ SQLNumResultCols(CON_RESULT(_h), &cols); RES_COL_N(_r) = cols; if (!RES_COL_N(_r)) { LM_ERR("no columns returned from the query\n"); return -2; } else { LM_DBG("%d columns returned from the query\n", RES_COL_N(_r)); } if (db_allocate_columns(_r, RES_COL_N(_r)) != 0) { LM_ERR("could not allocate columns\n"); return -3; } for(col = 0; col < RES_COL_N(_r); col++) { RES_NAMES(_r)[col] = (str*)pkg_malloc(sizeof(str)); if (! RES_NAMES(_r)[col]) { LM_ERR("no private memory left\n"); db_free_columns(_r); return -4; } LM_DBG("allocate %lu bytes for RES_NAMES[%d] at %p\n", (unsigned long)sizeof(str),col, RES_NAMES(_r)[col]); char columnname[80]; SQLRETURN ret; SQLSMALLINT namelength, datatype, decimaldigits, nullable; SQLULEN columnsize; ret = SQLDescribeCol(CON_RESULT(_h), col + 1, (SQLCHAR *)columnname, 80, &namelength, &datatype, &columnsize, &decimaldigits, &nullable); if(!SQL_SUCCEEDED(ret)) { LM_ERR("SQLDescribeCol failed: %d\n", ret); db_unixodbc_extract_error("SQLExecDirect", CON_RESULT(_h), SQL_HANDLE_STMT, NULL); // FIXME should we fail here completly? } /* The pointer that is here returned is part of the result structure. */ RES_NAMES(_r)[col]->s = columnname; RES_NAMES(_r)[col]->len = namelength; LM_DBG("RES_NAMES(%p)[%d]=[%.*s]\n", RES_NAMES(_r)[col], col, RES_NAMES(_r)[col]->len, RES_NAMES(_r)[col]->s); switch(datatype) { case SQL_SMALLINT: case SQL_INTEGER: case SQL_TINYINT: case SQL_DECIMAL: case SQL_NUMERIC: LM_DBG("use DB1_INT result type\n"); RES_TYPES(_r)[col] = DB1_INT; break; case SQL_BIGINT: LM_DBG("use DB1_BIGINT result type\n"); RES_TYPES(_r)[col] = DB1_BIGINT; break; case SQL_REAL: case SQL_FLOAT: case SQL_DOUBLE: LM_DBG("use DB1_DOUBLE result type\n"); RES_TYPES(_r)[col] = DB1_DOUBLE; break; case SQL_TYPE_TIMESTAMP: case SQL_DATE: case SQL_TIME: case SQL_TIMESTAMP: case SQL_TYPE_DATE: case SQL_TYPE_TIME: LM_DBG("use DB1_DATETIME result type\n"); RES_TYPES(_r)[col] = DB1_DATETIME; break; case SQL_CHAR: case SQL_VARCHAR: case SQL_WCHAR: case SQL_WVARCHAR: LM_DBG("use DB1_STRING result type\n"); RES_TYPES(_r)[col] = DB1_STRING; break; case SQL_BINARY: case SQL_VARBINARY: case SQL_LONGVARBINARY: case SQL_BIT: case SQL_LONGVARCHAR: case SQL_WLONGVARCHAR: LM_DBG("use DB1_BLOB result type\n"); RES_TYPES(_r)[col] = DB1_BLOB; break; default: LM_WARN("unhandled data type column (%.*s) type id (%d), " "use DB1_STRING as default\n", RES_NAMES(_r)[col]->len, RES_NAMES(_r)[col]->s, datatype); RES_TYPES(_r)[col] = DB1_STRING; break; } } return 0; }
/** * Get and convert columns from a result */ int db_mysql_get_columns(const db_con_t* _h, db_res_t* _r) { int col; MYSQL_FIELD* fields; if ((!_h) || (!_r)) { LM_ERR("invalid parameter\n"); return -1; } if (CON_HAS_PS(_h)) { RES_COL_N(_r) = CON_MYSQL_PS(_h)->cols_out; } else { RES_COL_N(_r) = mysql_field_count(CON_CONNECTION(_h)); } if (!RES_COL_N(_r)) { LM_ERR("no columns returned from the query\n"); return -2; } else { LM_DBG("%d columns returned from the query\n", RES_COL_N(_r)); } if (db_allocate_columns(_r, RES_COL_N(_r)) != 0) { LM_ERR("could not allocate columns\n"); return -3; } fields = mysql_fetch_fields(CON_RESULT(_h)); for(col = 0; col < RES_COL_N(_r); col++) { /* The pointer that is here returned is part of the result structure */ RES_NAMES(_r)[col]->s = fields[col].name; RES_NAMES(_r)[col]->len = strlen(fields[col].name); LM_DBG("RES_NAMES(%p)[%d]=[%.*s]\n", RES_NAMES(_r)[col], col, RES_NAMES(_r)[col]->len, RES_NAMES(_r)[col]->s); switch(fields[col].type) { case MYSQL_TYPE_TINY: case MYSQL_TYPE_SHORT: case MYSQL_TYPE_LONG: case MYSQL_TYPE_INT24: case MYSQL_TYPE_DECIMAL: #if MYSQL_VERSION_ID > 49999 case MYSQL_TYPE_NEWDECIMAL: #endif case MYSQL_TYPE_TIMESTAMP: LM_DBG("use DB_INT result type\n"); RES_TYPES(_r)[col] = DB_INT; break; case MYSQL_TYPE_FLOAT: case MYSQL_TYPE_DOUBLE: LM_DBG("use DB_DOUBLE result type\n"); RES_TYPES(_r)[col] = DB_DOUBLE; break; case MYSQL_TYPE_DATETIME: case MYSQL_TYPE_DATE: LM_DBG("use DB_DATETIME result type\n"); RES_TYPES(_r)[col] = DB_DATETIME; break; case MYSQL_TYPE_TINY_BLOB: case MYSQL_TYPE_MEDIUM_BLOB: case MYSQL_TYPE_LONG_BLOB: case MYSQL_TYPE_BLOB: LM_DBG("use DB_BLOB result type\n"); RES_TYPES(_r)[col] = DB_BLOB; break; case FIELD_TYPE_SET: LM_DBG("use DB_BITMAP result type\n"); RES_TYPES(_r)[col] = DB_BITMAP; break; case MYSQL_TYPE_STRING: case MYSQL_TYPE_VAR_STRING: LM_DBG("use DB_STRING result type\n"); RES_TYPES(_r)[col] = DB_STRING; break; case MYSQL_TYPE_LONGLONG: LM_DBG("use DB_BIGINT result type\n"); RES_TYPES(_r)[col] = DB_BIGINT; break; default: LM_WARN("unhandled data type column (%.*s) type id (%d), " "use DB_STRING as default\n", RES_NAMES(_r)[col]->len, RES_NAMES(_r)[col]->s, fields[col].type); RES_TYPES(_r)[col] = DB_STRING; break; } } return 0; }
/* * 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; }