#include "PostGresDatabase.h" #include "debug.h" #include //timing on the sql statements #include using namespace std; PostGresDatabase::PostGresDatabase(const char *_host, const char *_db, const char *_username, const char *_password): Database(_host, _db, _username, _password) {} PostGresDatabase::~PostGresDatabase() {PQfinish(m_DB);} bool PostGresDatabase::connect() { char sConnStr[1024]; _SNPRINTF(sConnStr, 1024, "host=%s dbname=%s user=%s password=%s", m_host, m_db, m_username, m_password); m_DB = PQconnectdb(sConnStr); return connected(); } bool PostGresDatabase::connected() const {return (PQstatus(m_DB)==CONNECTION_OK);} int PostGresDatabase::execute(const char *sql, RecordSet **result, char **sError, const bool manageResults) { //caller also frees sError if there is an error and it has been requested //the template class defines the return type. Not all are supported: RecordSet, char, int //note that the results must be cleared by the caller with PQclear(result); if (result) *result=0; //in the case of errors the results pointer will be null if (sError) *sError=0; ExecStatusType zEST; PGresult *pgResult=0; int ret=0; #ifdef _DEBUG time_t tStart, tEnd; time(&tStart); DEBUGPRINT("sql [%s]", DEBUG_CHECK, sql); #endif //execute into local pointer pgResult = PQexec(m_DB, sql); zEST = PQresultStatus(pgResult); //check status if (zEST == PGRES_TUPLES_OK || zEST == PGRES_COMMAND_OK || zEST == PGRES_NONFATAL_ERROR || zEST == PGRES_EMPTY_QUERY) { DEBUG_RESULT_OK; //SUCCESS! if (result) *result = new PostGresRecordSet(pgResult, manageResults); //caller must free this result else PQclear(pgResult); //caller does not want result so clear it ret = 0; } else { DEBUG_RESULT_FAIL; const char *setError = PQresultErrorMessage(pgResult); //caller may not care about error message if (sError) { *sError = (char *) mallocCheck(strlen(setError)+1); strcpy(*sError, setError); } DEBUGERROR("[PostGresDatabase]: QueryFailed(\n--------------------------\n%s\n--------------------------\n%s)", sql, setError); PQclear(pgResult); //clear result as an error will be returned ret = zEST; //0=PGRES_EMPTY_QUERY throw QueryFailed(sql, sError ? *sError : 0); } #ifdef _DEBUG time(&tEnd); DEBUGPRINT("%f seconds taken", DEBUG_LINE, difftime(tEnd, tStart)); #endif return ret; } int PostGresDatabase::execute(const char *procedure, const int argc, const char *argv[], const bool argt[], RecordSet **result, char **sError, const bool manageResults) { //calculate entire length of statement: //*2 for the potential escaped backslashes //+3 for potential quotes and comma //start at 100 for the "select...", brackets and quotes //include length of the SPROC name bool bQuote; size_t sqlLength; char *sql, *sqlcurrent; const char *arg; //calculate length sqlLength = 100 + strlen(procedure); for (int i = 0; i < argc; i++) { arg = argv[i]; sqlLength += (arg ? strlen(arg) * 2 : 6); //escaping, 6 = null } sql = (char*) mallocCheck(sqlLength); sqlcurrent = sql; //SPROC basics const char *sqlstart = (result ? "select * from \"" : "select \""); strcpy(sqlcurrent, sqlstart); sqlcurrent += strlen(sqlstart); strcpy(sqlcurrent, procedure); sqlcurrent += strlen(procedure); *sqlcurrent++ = '"'; *sqlcurrent++ = '('; //SPROC args if (argc && procedure) { for (int i = 0; i < argc; i++) { arg = argv[i]; bQuote = (arg && (!argt||argt[i])); //if to add quotes if (i) *sqlcurrent++ = ','; if (bQuote) *sqlcurrent++ = '\''; if (arg) PQescapeString(sqlcurrent, arg, strlen(arg)); else strcpy(sqlcurrent, "null"); while (*sqlcurrent) sqlcurrent++; //PQescapeString will 0 terminate the string if (bQuote) *sqlcurrent++ = '\''; } } *sqlcurrent++ = ')'; *sqlcurrent = 0; //terminate const int zEST = execute(sql, result, sError, manageResults); free(sql); return zEST; } //----------------------------------------------- PostGresRecordSet --------------------------------------------------- PostGresRecordSet::~PostGresRecordSet() { if (m_result) PQclear(m_result); } size_t PostGresRecordSet::size() {return PQntuples(m_result);} int PostGresRecordSet::value(char **value, const unsigned int row, const unsigned int column) { //caller frees value int ret=0; if (value) { *value=0; size_t iResultLen=0; const char *string=0; if (string=PQgetvalue(m_result, row, column)) { iResultLen=PQgetlength(m_result, row, column); *value=(char*) mallocCheck(iResultLen+1); //plus trailing zero if (m_manageResults) recordMalloc(*value); strncpy(*value, string, iResultLen); (*value)[iResultLen]=0; } else ret=1; } else ret=1; return ret; } int PostGresRecordSet::length(size_t *length, const unsigned int row, const unsigned int column) { if (*length=PQgetlength(m_result, row, column)) return 0; else return 1; }