/*! * \brief Free the query and the result memory in the core * \param _con database connection * \param _r result set * \return 0 on success, -1 on failure */ int db_postgres_free_result(db1_con_t* _con, db1_res_t* _r) { if ((!_con) || (!_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; } db_postgres_free_query(_con); 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 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; }
/*! * \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) { char *s=NULL; int i, retries; ExecStatusType pqresult; PGresult *res = NULL; int sock, ret; fd_set fds; time_t max_time; struct timeval wait_time; 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; s = pkg_malloc((_s->len+1)*sizeof(char)); if (s==NULL) { LM_ERR("%p db_postgres_submit_query Out of Memory: Query: %.*s\n", _con, _s->len, _s->s); return -1; } memcpy( s, _s->s, _s->len ); s[_s->len] = '\0'; 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)) { if (pg_timeout <= 0) goto do_read; max_time = time(NULL) + pg_timeout; while (1) { sock = PQsocket(CON_CONNECTION(_con)); FD_ZERO(&fds); FD_SET(sock, &fds); wait_time.tv_usec = 0; wait_time.tv_sec = max_time - time(NULL); if (wait_time.tv_sec <= 0 || wait_time.tv_sec > 0xffffff) goto timeout; ret = select(sock + 1, &fds, NULL, NULL, &wait_time); if (ret < 0) { if (errno == EINTR) continue; LM_WARN("select() error\n"); goto reset; } if (!ret) { timeout: LM_WARN("timeout waiting for postgres reply\n"); goto reset; } if (!PQconsumeInput(CON_CONNECTION(_con))) { LM_WARN("error reading data from postgres server: %s\n", PQerrorMessage(CON_CONNECTION(_con))); goto reset; } if (!PQisBusy(CON_CONNECTION(_con))) break; } do_read: /* Get the result of the query */ while ((res = PQgetResult(CON_CONNECTION(_con))) != NULL) { db_postgres_free_query(_con); CON_RESULT(_con) = res; } 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); pkg_free(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) { reset: LM_DBG("resetting 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); pkg_free(s); return -1; }