Friday, March 20, 2009

Postgres with wxWidgets

Ok, let's begin

I'm a mexican programer, my name is Luis Eduardo Cañedo.

I usualy develop web projects with PHP, but I write programs in C++ using wxWidgets very often.
Of course, I have some experience with HTML, XML and JavaScript, And I just start study Java to use it with Tomcat, Websphere and PHP-Java-Bridge.

The first source I want share is a C++ library for Postgres connections. I used this source for some projects with wxWidgets and I still use them when I need write quickly some source that involve Postgresql databases.

If you read the source code, you'll see that you can rewrite it to use it with other libraries different to wxWidgets.

This source was tested in Windows XP SP2, RedHat 4 and Fedora 8, 9 y 10.

For Windows you need include the files:
libpq-fe.h
postgres_ext.h
libpq/libpq-fs.h

And the libraries for link:
libpq.lib
libpqdll.lib

For Linux you need the includes:
libpq-fs.h
libpq-fe.h

And the libraries:
libpq.a
libpq.so

Link with the "-lpq" linker option

Load the library using wx/dynload.h and include the wxPgsLib.h file in your app
and include the file wxPgsDef.h to your app to let it know the methods of wxPgsLib.

Only if you make a static compile of the library libwxPgs.dll, In runtime you'll need the Postgresql libraries that you can download from www.postgres.org:
-libpq.so for Linux, you can install it from the postgres package of your distro
-And for Windows you need: comerr32.dll, libeay32.dll, libintl-2.dll, ssleay32.dll, krb5_32.dll, libiconv-2.dll and libpq.dll, they are in the Postgres frontend installer.
(The sample for windows does not need this files because it was dinamyc compile)

I have all the files for VC and Eclipse projects with a sample of use ready for download at SourceForge

You can compile the library with this four files:


//---------------------------------------------------------------------------

//

// Name: wxPgs.cpp

// Author: eduardo canedo

// Created: 28/05/2007 10:30:00 a.m.

// Description: Exported function for wxPgs dynamic library

//

//---------------------------------------------------------------------------

#include <wx/dynlib.h>

#include "wxPgsLib.h"



WXDLL_ENTRY_FUNCTION();



extern "C" WXEXPORT wxPgs* PgsIni(wxString strTit, wxString strSid, wxString strUsr, wxString strPas)

{

return new wxPgs(strTit, strSid, strUsr, strPas);

}



extern "C" WXEXPORT void PgsFin(wxPgs* PgsObj)

{

PgsObj->~wxPgs();

}



extern "C" WXEXPORT bool PgsExe(wxPgs* PgsObj, wxString strQry)

{

return PgsObj->ExecQry(strQry);

}



extern "C" WXEXPORT bool PgsSel(wxPgs* PgsObj, wxString strQry, std::vector< std::vector<wxString> > *aryDat=NULL, wxGridTableBase *grdDat=NULL)

{

return PgsObj->SelcQry(strQry, aryDat, grdDat);

}



extern "C" WXEXPORT bool PgsArcW(wxPgs* PgsObj, wxString strArc, wxString strLob, wxString strTbl, wxString strCmp, int numCnd)

{

return PgsObj->EscArc(strArc, strLob, strTbl, strCmp, numCnd);

}



extern "C" WXEXPORT bool PgsObjW(wxPgs* PgsObj, wxChar *strArc, size_t size, wxString strLob, wxString strTbl, wxString strCmp, int numCnd)

{

return PgsObj->EscLob(strArc, size, strLob, strTbl, strCmp, numCnd);

}



extern "C" WXEXPORT bool PgsArcR(wxPgs* PgsObj, wxString strArc, wxString strLob, wxString strTbl, wxString strCmp, int numCnd)

{

return PgsObj->LeeArc(strArc, strLob, strTbl, strCmp, numCnd);

}



extern "C" WXEXPORT int PgsObjR(wxPgs* PgsObj, wxChar *strArc, wxString strLob, wxString strTbl, wxString strCmp, int numCnd)

{

return PgsObj->LeeLob(strArc, strLob, strTbl, strCmp, numCnd);

}




//---------------------------------------------------------------------------

//

// Name: wxPgsDef.h

// Author: eduardo canedo

// Created: 28/05/2007 10:30:00 a.m.

// Description: Function headers for wxPgs dynamic library

//

//---------------------------------------------------------------------------

typedef wxPgs* (*PgsIni)(wxString, wxString, wxString, wxString);

typedef void* (*PgsFin)(wxPgs*);

typedef bool* (*PgsExe)(wxPgs*, wxString);

typedef bool* (*PgsSel)(wxPgs*, wxString, std::vector< std::vector<wxString> >*, wxGridTableBase*);

typedef int (*PgsArcW)(wxPgs*, wxString, wxString, wxString, wxString, int);

typedef bool* (*PgsObjW)(wxPgs*, wxChar*, size_t, wxString, wxString, wxString, int);

typedef int (*PgsArcR)(wxPgs*, wxString, wxString, wxString, wxString, int);

typedef int (*PgsObjR)(wxPgs*, wxChar*, wxString, wxString, wxString, int);




//---------------------------------------------------------------------------

//

// Name: wxPgsLib.h

// Author: eduardo canedo

// Created: 28/05/2007 10:30:00 a.m.

// Description: wxPgs class declaration

//

//---------------------------------------------------------------------------



#ifdef __BORLANDC__

#pragma hdrstop

#endif



#ifndef WX_PRECOMP

#include <wx/wx.h>

#include <wx/dialog.h>

#else

#include <wx/wxprec.h>

#endif



#include <libpq/libpq-fs.h>

#include <wx/tokenzr.h>

#include <libpq-fe.h>

#include <wx/grid.h>

#include <wx/file.h>

#include <vector>



#define MAXLOBLEN 512000 //MAX VALUE FOR LOB'S



class wxPgs

{

public:

wxPgs(wxString strTit, wxString strSid, wxString strUsr, wxString strPas);

~wxPgs();



bool bolCon;

bool ExecQry(wxString strQry);

bool SelcQry(wxString strQry, std::vector< std::vector<wxString> > *aryDat=NULL, wxGridTableBase *grdDat=NULL);

bool LeeArc(wxString strArc, wxString strLob, wxString strTbl, wxString strCmp, int numCnd);

int LeeLob(wxChar *strArc, wxString strLob, wxString strTbl, wxString strCmp, int numCnd);

bool EscArc(wxString strArc, wxString strLob, wxString strTbl, wxString strCmp, int numCnd);

bool EscLob(wxChar *strArc, size_t size, wxString strLob, wxString strTbl, wxString strCmp, int numCnd);

};



//---------------------------------------------------------------------------

//

// Name: wxPgsLib.cpp

// Author: eduardo canedo

// Created: 28/05/2007 10:30:00 a.m.

// Description: wxPgs class implementation

//

//---------------------------------------------------------------------------



#include "wxPgsLib.h"



PGconn *conn;

PGresult *res;

static wxString msgTit;


//CONSTRUCTOR

wxPgs::wxPgs(wxString strTit, wxString strSid, wxString strUsr, wxString strPas)

{

bolCon = true;

msgTit = strTit;

wxString strPar;

wxArrayString strPars;



//GET THE HOST, BD AND PORT INFO IN THE FIRST STRING SEPATED BY PIPE |

wxStringTokenizer strCmps(strSid, "|");

if (strCmps.CountTokens() == 3)

{

while (strCmps.HasMoreTokens())

strPars.Add(strCmps.GetNextToken());



strPar = wxT("host='"+strPars[0]+"' ");

strPar += wxT("dbname='"+strPars[1]+"' ");

strPar += wxT("port="+strPars[2]+" ");

strPar += wxT("password='"+strPas+"' ");

strPar += wxT("user='"+strUsr+"'");



conn = PQconnectdb(strPar.c_str());



if (PQstatus(conn) == CONNECTION_BAD)

{

bolCon = false;

strPar.Printf("%s", PQerrorMessage(conn));

wxMessageBox(strPar, msgTit, wxOK | wxICON_ERROR);

}

}

else

{

wxMessageBox(wxT("ERROR Connection information incomplete"), msgTit, wxOK | wxICON_ERROR);

bolCon = false;

}

}



//DESCTRUCTOR
wxPgs::~wxPgs()

{

if (PQstatus(conn) == CONNECTION_OK)

PQfinish(conn);

}


//EXECUTES QUERY strQry

bool wxPgs::ExecQry(wxString strQry)

{

wxString strMsg;



res = PQexec(conn, "BEGIN");

if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)

{

strMsg.Printf("%s", PQerrorMessage(conn));

wxMessageBox(strMsg, msgTit, wxOK | wxICON_ERROR);

res = PQexec(conn, "ROLLBACK");

PQclear(res);

return false;

}

PQclear(res);



res = PQexec(conn, strQry.c_str());

if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)

{

strMsg.Printf("%s", PQerrorMessage(conn));

wxMessageBox(strMsg, msgTit, wxOK | wxICON_ERROR);

res = PQexec(conn, "ROLLBACK");

PQclear(res);

return false;

}



res = PQexec(conn, "COMMIT");

PQclear(res);

return true;

}


//SELECT QUERY INTO AN ARRAY OR INTO AN WXGRID

bool wxPgs::SelcQry(wxString strQry, std::vector< std::vector<wxString> > *aryDat, wxGridTableBase *grdDat)

{

wxString strTmp;



if (aryDat==NULL && grdDat==NULL)

{

wxMessageBox(wxT("ERROR Data container required"), msgTit, wxOK | wxICON_ERROR);

return false;

}

else if (aryDat!=NULL && grdDat!=NULL)

{

wxMessageBox(wxT("ERROR Only one data container is required"), msgTit, wxOK | wxICON_ERROR);

return false;

}



res = PQexec(conn, strQry.c_str());

if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)

{

strTmp.Printf("%s", PQerrorMessage(conn));

wxMessageBox(strTmp, msgTit, wxOK | wxICON_ERROR);

PQclear(res);

return false;

}



short numCols = PQnfields(res);



if (grdDat!=NULL)

{

grdDat->DeleteCols(0, grdDat->GetNumberCols());

grdDat->DeleteRows(0, grdDat->GetNumberRows());

grdDat->AppendCols(numCols);

}

else

{

aryDat->clear();

}



for (int i=0;i<PQntuples(res);i++)

{

if (grdDat!=NULL)

{

grdDat->AppendRows(1);

for (int j=0;j<numCols;j++)

{

strTmp.Printf("%s", PQgetvalue(res, i, j));

grdDat->SetValue(grdDat->GetNumberRows()-1, j, strTmp);

}

}

else

{

std::vector<wxString> aryTmp;

for (int j=0;j<numCols;j++)

{

strTmp.Printf("%s", PQgetvalue(res, i, j));

aryTmp.push_back(strTmp);

}

aryDat->push_back(aryTmp);

}

}



PQclear(res);

return true;

}


//WRITE FILE INTO THE DB

bool wxPgs::EscArc(wxString strArc, wxString strLob, wxString strTbl, wxString strCmp, int numCnd)

{

wxFile file(strArc);

if (file.IsOpened())

{

long iSize = (long)file.Length();

//wxChar strBuf[iSize];

wxChar* strBuf=(wxChar*) malloc(sizeof(wxChar) * iSize);



if (iSize < 1)

{

wxMessageBox(wxT("ERROR Of file size"), msgTit, wxOK | wxICON_ERROR);

return false;

}

else if (iSize > MAXLOBLEN)

{

wxMessageBox(wxT("ERROR The file size is biger than expected"), msgTit, wxOK | wxICON_ERROR);

return false;

}

else

{

memset(strBuf, 0, (size_t)iSize);

size_t iRead = file.Read(strBuf, (size_t)iSize);

if (iRead < (size_t)iSize)

{

wxMessageBox(wxT("ERROR Betwen content and file size"), msgTit, wxOK | wxICON_ERROR);

memset((void *)strBuf, '\0', (size_t)iSize);

return false;

}

else if (!EscLob(strBuf, iRead, strLob, strTbl, strCmp, numCnd))

{

memset((void *)strBuf, '\0', (size_t)iSize);

return false;

}

}

file.Close();

}

else

{

wxMessageBox(wxT("ERROR Can't Open file"), msgTit, wxOK | wxICON_ERROR);

return false;

}



return true;

}


//WRITE BLOB INTO THE DB

bool wxPgs::EscLob(wxChar *strArc, size_t size, wxString strLob, wxString strTbl, wxString strCmp, int numCnd)

{

Oid lobId;

int lobObj;

int numByt;



res = PQexec(conn, "BEGIN");

PQclear(res);



wxString strQry;

strQry.Printf("SELECT %s FROM %s WHERE %s=%d", strLob.c_str(), strTbl.c_str(), strCmp.c_str(), numCnd);



res = PQexec(conn, strQry.c_str());

if (PQresultStatus(res) == PGRES_TUPLES_OK)

{

long resOid;

strQry.Printf("%s", PQgetvalue(res, 0, 0));

strQry.ToLong(&resOid);

lobId = (Oid)resOid;



if (lobId > 0)

{

strQry.Printf("DELETE FROM %s WHERE %s=%d", strTbl.c_str(), strCmp.c_str(), numCnd);

res = PQexec(conn, strQry.c_str());

if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)

{

strQry.Printf("%s", PQerrorMessage(conn));

wxMessageBox(strQry, msgTit, wxOK | wxICON_ERROR);

res = PQexec(conn, "ROLLBACK");

PQclear(res);

return false;

}

lo_unlink(conn, lobId);

}

}



lobId = lo_creat(conn, INV_READ | INV_WRITE);

if (lobId == 0)

{

wxMessageBox(wxT("ERROR The object can't be created"), msgTit, wxOK | wxICON_ERROR);

res = PQexec(conn, "ROLLBACK");

PQclear(res);

return false;

}



lobObj = lo_open(conn, lobId, INV_READ | INV_WRITE);

numByt = lo_write(conn, lobObj, strArc, size);

if (numByt < (int)size)

{

wxMessageBox(wxT("ERROR The object can't be inserted"), msgTit, wxOK | wxICON_ERROR);

res = PQexec(conn, "ROLLBACK");

PQclear(res);

return false;

}



strQry.Printf("INSERT INTO %s(%s, %s) VALUES(%d, %d)", strTbl.c_str(), strCmp.c_str(), strLob.c_str(), numCnd, lobId);

res = PQexec(conn, strQry.c_str());

if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)

{

strQry.Printf("%s", PQerrorMessage(conn));

wxMessageBox(strQry, msgTit, wxOK | wxICON_ERROR);

res = PQexec(conn, "ROLLBACK");

PQclear(res);

return false;

}



lo_close(conn, lobObj);

res = PQexec(conn, "COMMIT");

PQclear(res);

return true;

}


//READ FILE FROM DB

bool wxPgs::LeeArc(wxString strArc, wxString strLob, wxString strTbl, wxString strCmp, int numCnd)

{

int numLen;

wxChar strBuf[MAXLOBLEN];

numLen = LeeLob(strBuf, strLob, strTbl, strCmp, numCnd);

if (numLen > 0)

{

wxFile file;

if (!file.Open(strArc, wxFile::write))

{

wxMessageBox(wxT("ERROR Can't open file"), msgTit, wxOK | wxICON_ERROR);

memset((void *)strBuf, '\0', (size_t) numLen);

return false;

}

file.Write(strBuf, (size_t) numLen);

file.Close();

}

else

{

wxMessageBox(wxT("ERROR Can't read file"), msgTit, wxOK | wxICON_ERROR);

memset((void *)strBuf, '\0', (size_t) numLen);

return false;

}

return true;

}


//READ BLOB FROM DB

int wxPgs::LeeLob(wxChar *strArc, wxString strLob, wxString strTbl, wxString strCmp, int numCnd)

{

Oid lobId;

int lobObj;

int numByt;

long resOid;

int numRet = 0;

wxString strRes;



res = PQexec(conn, "BEGIN");

PQclear(res);



wxString strQry;

strQry.Printf("SELECT %s FROM %s WHERE %s=%d", strLob.c_str(), strTbl.c_str(), strCmp.c_str(), numCnd);



res = PQexec(conn, strQry.c_str());

if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)

{

strQry.Printf("%s", PQerrorMessage(conn));

wxMessageBox(strQry, msgTit, wxOK | wxICON_ERROR);

res = PQexec(conn, "ROLLBACK");

PQclear(res);

return numRet;

}



strRes.Printf("%s", PQgetvalue(res, 0, 0));

strRes.ToLong(&resOid);

lobId = (Oid)resOid;



lobObj = lo_open(conn, lobId, INV_READ | INV_WRITE);



if (lobObj < 0)

{

wxMessageBox(wxT("ERROR Can't read the file from the db"), msgTit, wxOK | wxICON_ERROR);

res = PQexec(conn, "ROLLBACK");

PQclear(res);

return numRet;

}



while (MAXLOBLEN - numRet > 0)

{

numByt = lo_read(conn, lobObj, strArc, MAXLOBLEN - numRet);

numRet += numByt;

if (numByt <= 0) break;

}



lo_close(conn, lobObj);

res = PQexec(conn, "COMMIT");

PQclear(res);

return numRet;

}

2 comments:

  1. Replies
    1. Hi Andika:

      I have not tried, but should work , you must have installed headers and libraries for Mac .
      This might help: http://www.postgresql.org/download/macosx/

      Delete