I know many will start with ODBC, but slow down ;)
I have searched for ODBC and all I find is UnixODBC. Is this the same as ODBC?
Also how stable it is? I will be happy to know some apps/companies behind it!
I need support for MySQL, PostGreSQL, DB2, Oracle backends.
Thanks and sorry for being little funny!

I've been using ODBC for years. Its the very lowest level Api you can use. I'm pretty sure all other SQL Relational database access technologies are built on top of it. Perhaps ADO isn't; not sure of that.

Its platform independent. If you use it on Unix/Linux to access a database, and you would later want to access SQL Server or MS Access, there wouldn't probably be too much to change. For these reasons I'd highly recommend it. Far as I know Microsoft is still maintaining it; I think they have to.

Most newer folks don't like it because its procedural. No OOP. I've written very thin class wrappers around it that work very well for me. I have to admit I've never used it with anything other than Microsoft Access and SQL Server, plus some incidental use with Microsoft Excel. If you want my class wrapper to start with I'd be happy to post it. Actually, I'd like to see an example of a connection string for some of those databases you listed.

Thanks Fred!
Where do I download headers/libraries plus examples?
Is it the same as UnixODBC or are different?
I would like to see your wrapper!

Edited 6 Years Ago by Stefano Mtangoo: n/a

I'm sure there is an implementation of ODBC for Unix. Its a database standard which applies to all the databases you listed. However, there are various levels of 'conformance' to the standard. That does not mean that some won't work with it, but rather that some optional features might not (most definitely aren't!) be implemented on all databases.

If you have Windows or access to it here is a little program that creates a Microsoft Access database ( a TestData.mdb file ), creates a Table1 in the database, writes a few records to the Table1, then dumps the data. If you have Microsoft Access you can open the database after the program runs. Its named TestData.mdb. It should be in whatever directory you are running the program from. Don't put this code in C:\Program Files or C:\Documents And Setting though. I don't believe it will work. At least not on XP. I'd recommend somewhere right off your C drive such as C:\OdbcDemo or C:\Code\OdbcDemo or something like that. This is a Microsoft thing I can't explain. Oh, one other thing. This program has to link to the two ODBC libraries, which in Visual Studio are ODBC32.lib and ODBCCP32.lib. With CodeBlocks or any of the GNU it will be libODBC32.a and libODBCCP32.a. This is important. It won't compile without static linking to those libs. I'll start posting the code now...

//Main.cpp
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <odbcinst.h>
#include <sql.h>
#include <sqlext.h>
#include "Strings.h"
#include "Sql.h"
#include "SqlProcs.h"
#if defined(MY_DEBUG)
    FILE* fp=NULL;
#endif


int main()
{
 unsigned int iReturn=0,iDatabaseReturn=0;
 TCHAR lpBuffer[512];
 String s1;
 SQL Sql;

 #if defined(MY_DEBUG)
     fp=_tfopen(_T("Output.txt"),_T("w"));
 #endif
 Sql.strDriver=_T("Microsoft Access Driver (*.mdb)");
 iReturn=GetCurrentDirectory(512,lpBuffer);
 Sql.strDBQ=lpBuffer;
 Sql.strDBQ = Sql.strDBQ + _T("\\") + _T("TestData.mdb");
 iDatabaseReturn=iCreateDB(Sql.strDBQ.lpStr());
 Sql.ODBCConnect();
 if(iDatabaseReturn==1)  //Created New Access Database OK
 {
    _tprintf(_T("TestData.mdb Successfully Created!\n"));
    if(blnMakeTable(Sql))
    {
       _tprintf(_T("blnMakeTable() Succeeded!  You Should Have A Table1 In TestData.Mdb!\n"));
       if(blnInsert(Sql))
       {
          _tprintf(_T("\nblnInsert() Succeeded!  You Should Now Have Data In Table1!\n\n"));
          if(blnDumpData(Sql))
          {
             _tprintf(_T("\nKind Of Looks Like Everything Worked!  No?"));
          }
       }
    }
 }
 Sql.ODBCDisconnect();
 #if defined(MY_DEBUG)
     fclose(fp);
 #endif
 getchar();

 return 0;
}

/*
Output

TestData.mdb Successfully Created!
blnMakeTable() Succeeded!  You Should Have A Table1 In TestData.Mdb!
szQuery = INSERT INTO Table1(Id, Float_Point, Date_Field, Text_Field) VALUES(?,?,?,?);

                                                         SQLExecute(hStmt)
iId      Double           Date           String           0=SQL_SUCCESS
========================================================================
1         3.14           11/15/1952    My Birthday              0
2         1.23           6/30/1969     Walk On Moon?            0
3        15.12           1/1/2006      Some String              0
4         0.54           4/1/2006      April Fools Day          0

blnInsert() Succeeded!  You Should Now Have Data In Table1!

iId      Double           Date           String           0=SQL_SUCCESS
========================================================================
1         3.14           11/15/1952    My Birthday              0
2         1.23           6/30/1969     Walk On Moon?            0
3        15.12           1/1/2006      Some String              0
4         0.54           4/1/2006      April Fools Day          0

Kind Of Looks Like Everything Worked!  No?
*/
//Strings.cpp
#include  <windows.h>
#include  <tchar.h>
#include  <stdlib.h>
#include  <stdio.h>
#include  <string.h>
#include  "Strings.h"


String::String()    //Uninitialized Constructor
{
 pStrBuffer=new TCHAR[MINIMUM_ALLOCATION];
 pStrBuffer[0]='\0';
 this->iAllowableCharacterCount=MINIMUM_ALLOCATION-1;
}


String::String(const TCHAR ch)  //Constructor: Initializes with TCHAR
{
 pStrBuffer=new TCHAR[MINIMUM_ALLOCATION];
 pStrBuffer[0]=ch;
 pStrBuffer[1]='\0';
 iAllowableCharacterCount=MINIMUM_ALLOCATION-1;
}


String::String(const TCHAR* pStr)  //Constructor: Initializes with TCHAR*
{
 int iLen,iNewSize;

 iLen=_tcslen(pStr);
 iNewSize=(iLen/16+1)*16;
 pStrBuffer=new TCHAR[iNewSize];
 this->iAllowableCharacterCount=iNewSize-1;
 _tcscpy(pStrBuffer,pStr);
}


String::String(const String& s)  //Constructor Initializes With Another String, i.e., Copy Constructor
{
 int iLen,iNewSize;

 iLen=_tcslen(s.pStrBuffer);
 iNewSize=(iLen/16+1)*16;
 this->pStrBuffer=new TCHAR[iNewSize];
 this->iAllowableCharacterCount=iNewSize-1;
 _tcscpy(this->pStrBuffer,s.pStrBuffer);
}


String::String(const int iSize)  //Constructor Creates String With Custom Sized
{                                //Buffer (rounded up to paragraph boundary)
 int iNewSize;

 iNewSize=(iSize/16+1)*16;
 pStrBuffer=new TCHAR[iNewSize];
 this->iAllowableCharacterCount=iNewSize-1;
 this->pStrBuffer[0]=_T('\0');
}


String::String(const TCHAR ch, int iCount)
{
 int iNewSize;

 iNewSize=(iCount/16+1)*16;
 pStrBuffer=new TCHAR[iNewSize];
 this->iAllowableCharacterCount=iNewSize-1;
 for(int i=0; i<iCount; i++)
     pStrBuffer[i]=ch;
 pStrBuffer[iCount]=_T('\0');
}


String& String::operator=(const TCHAR ch)  //Overloaded operator = for assigning a TCHAR to a String
{
 this->pStrBuffer[0]=ch;
 this->pStrBuffer[1]=_T('\0');

 return *this;
}


String& String::operator=(const TCHAR* pStr)   //Constructor For If Pointer To Asciiz String Parameter
{
 int iLen,iNewSize;

 iLen=_tcslen(pStr);
 if(iLen<this->iAllowableCharacterCount)
    _tcscpy(pStrBuffer,pStr);
 else
 {
    delete [] pStrBuffer;
    iNewSize=(iLen/16+1)*16;
    pStrBuffer=new TCHAR[iNewSize];
    this->iAllowableCharacterCount=iNewSize-1;
    _tcscpy(pStrBuffer,pStr);
 }

 return *this;
}


String& String::operator=(const String& strRight)  //Overloaded operator = for
{                                                  //assigning another String to
 int iRightLen,iNewSize;                           //a String

 if(this==&strRight)
    return *this;
 iRightLen=_tcslen(strRight.pStrBuffer);
 if(iRightLen < this->iAllowableCharacterCount)
    _tcscpy(pStrBuffer,strRight.pStrBuffer);
 else
 {
    iNewSize=(iRightLen/16+1)*16;
    delete [] this->pStrBuffer;
    this->pStrBuffer=new TCHAR[iNewSize];
    this->iAllowableCharacterCount=iNewSize-1;
    _tcscpy(pStrBuffer,strRight.pStrBuffer);
 }

 return *this;
}


bool String::operator==(const String strCompare)
{
 if(_tcscmp(this->pStrBuffer,strCompare.pStrBuffer)==0)  //_tcscmp
    return true;
 else
    return false;
}


String& String::operator+(const TCHAR ch)      //Overloaded operator + (Puts TCHAR in String)
{
 int iLen,iNewSize;
 TCHAR* pNew;

 iLen=_tcslen(this->pStrBuffer);
 if(iLen<this->iAllowableCharacterCount)
 {
    this->pStrBuffer[iLen]=ch;
    this->pStrBuffer[iLen+1]='\0';
 }
 else
 {
    iNewSize=((this->iAllowableCharacterCount*EXPANSION_FACTOR)/16+1)*16;
    pNew=new TCHAR[iNewSize];
    this->iAllowableCharacterCount=iNewSize-1;
    _tcscpy(pNew,this->pStrBuffer);
    delete [] this->pStrBuffer;
    this->pStrBuffer=pNew;
    this->pStrBuffer[iLen]=ch;
    this->pStrBuffer[iLen+1]='\0';
 }

 return *this;
}


String& String::operator+(const TCHAR* pChar) //Overloaded operator + (Adds TCHAR literals
{                                             //or pointers to Asciiz Strings)
 int iLen,iNewSize;
 TCHAR* pNew;

 iLen=_tcslen(this->pStrBuffer)+_tcslen(pChar);
 if(iLen<this->iAllowableCharacterCount)
 {
    if(this->pStrBuffer)
       _tcscat(this->pStrBuffer,pChar);
    else
       _tcscpy(this->pStrBuffer, pChar);
 }
 else
 {
    iNewSize=(iLen*EXPANSION_FACTOR/16+1)*16;
    pNew=new TCHAR[iNewSize];
    this->iAllowableCharacterCount = iNewSize-1;
    if(this->pStrBuffer)
    {
       _tcscpy(pNew,this->pStrBuffer);
       delete [] pStrBuffer;
       _tcscat(pNew,pChar);
    }
    else
       _tcscpy(pNew,pChar);
    this->pStrBuffer=pNew;
 }

 return *this;
}


String& String::operator+(const String& strRight)  //Overloaded operator + Adds
{                                                  //Another String to the left
 int iLen,iNewSize;                                //operand
 TCHAR* pNew;

 iLen=_tcslen(this->pStrBuffer) + _tcslen(strRight.pStrBuffer);
 if(iLen < this->iAllowableCharacterCount)
 {
    if(this->pStrBuffer)
       _tcscat(this->pStrBuffer,strRight.pStrBuffer);
    else
       _tcscpy(this->pStrBuffer,strRight.pStrBuffer);
 }
 else
 {
    iNewSize=(iLen*EXPANSION_FACTOR/16+1)*16;
    pNew=new TCHAR[iNewSize];
    this->iAllowableCharacterCount=iNewSize-1;
    if(this->pStrBuffer)
    {
       _tcscpy(pNew,this->pStrBuffer);
       delete [] pStrBuffer;
       _tcscat(pNew,strRight.pStrBuffer);
    }
    else
       _tcscpy(pNew,strRight.pStrBuffer);
    this->pStrBuffer=pNew;
 }

 return *this;
}


String String::Left(unsigned int iNum)
{
 unsigned int iLen,i,iNewSize;
 String sr;

 iLen=_tcslen(this->pStrBuffer);
 if(iNum<iLen)
 {
    iNewSize=(iNum*EXPANSION_FACTOR/16+1)*16;
    sr.iAllowableCharacterCount=iNewSize-1;
    sr.pStrBuffer=new TCHAR[iNewSize];
    for(i=0;i<iNum;i++)
        sr.pStrBuffer[i]=this->pStrBuffer[i];
    sr.pStrBuffer[iNum]='\0';
    return sr;
 }
 else
 {
    sr=*this;
    return sr;
 }
}


String String::Right(unsigned int iNum)  //Returns Right$(strMain,iNum)
{
 unsigned int iLen,i,j,iNewSize;
 String sr;

 iLen=_tcslen(this->pStrBuffer);
 if(iNum<iLen)
 {
    iNewSize=(iNum*EXPANSION_FACTOR/16+1)*16;
    sr.iAllowableCharacterCount=iNewSize-1;
    sr.pStrBuffer=new TCHAR[iNewSize];
    j=0;
    for(i=iLen-iNum;i<=iLen;i++)
    {
        sr.pStrBuffer[j]=this->pStrBuffer[i];
        j++;
    }
    sr.pStrBuffer[iNum]='\0';
    return sr;
 }
 else
 {
    sr=*this;
    return sr;
 }
}


String String::Mid(unsigned int iStart, unsigned int iCount)
{
 unsigned int iLen,i,j,iNewSize;
 String sr;

 iLen=_tcslen(this->pStrBuffer);
 if(iStart && iStart<=iLen)
 {
    if(iCount && iStart+iCount-1<=iLen)
    {
       iNewSize=(iCount*EXPANSION_FACTOR/16+1)*16;
       sr. iAllowableCharacterCount=iNewSize-1;
       sr.pStrBuffer=new TCHAR[iNewSize];
       j=0;
       sr.pStrBuffer=new TCHAR[iNewSize];
       for(i=iStart-1;i<iStart+iCount-1;i++)
       {
           sr.pStrBuffer[j]=this->pStrBuffer[i];
           j++;
       }
       sr.pStrBuffer[iCount]='\0';
       return sr;
    }
    else
    {
       sr=*this;
       return sr;
    }
 }
 else
 {
    sr=*this;
    return sr;
 }
}


String& String::Make(const TCHAR ch, int iCount)    //Creates (Makes) a String with iCount TCHARs
{
 if(iCount>this->iAllowableCharacterCount)
 {
    delete [] pStrBuffer;
    int iNewSize=(iCount*EXPANSION_FACTOR/16+1)*16;
    this->pStrBuffer=new TCHAR[iNewSize];
    this->iAllowableCharacterCount=iNewSize-1;
 }
 for(int i=0; i<iCount; i++)
     pStrBuffer[i]=ch;
 pStrBuffer[iCount]=_T('\0');

 return *this;
}


String& String::GetModulePath()
{
 TCHAR szFileName[MAX_PATH];
 TCHAR* pChar=NULL;
 DWORD dwRet=0;

 dwRet=GetModuleFileName(NULL,szFileName,MAX_PATH);
 if(dwRet)
 {
    pChar=_tcsrchr(szFileName,(int)_T('\\')); //wcsrchr
    szFileName[pChar-(TCHAR*)szFileName]=_T('\0');
    if(dwRet>(unsigned)this->iAllowableCharacterCount)
    {
       delete [] pStrBuffer;
       int iNewSize=(dwRet*EXPANSION_FACTOR/16+1)*16;
       this->pStrBuffer=new TCHAR[iNewSize];
       this->iAllowableCharacterCount=iNewSize-1;
    }
    _tcscpy(this->pStrBuffer,szFileName);
 }

 return *this;
}


String String::Remove(const TCHAR* pToRemove, bool blnCaseSensitive)
{
 int i,j,iParamLen,iReturn=0;
 bool blnFound=false;

 if(*pToRemove==0)
    return *this;
 iParamLen=_tcslen(pToRemove);
 i=0, j=0;
 do
 {
  if(pStrBuffer[i]==0)
     break;
  if(blnCaseSensitive)
     iReturn=_tcsncmp(pStrBuffer+i,pToRemove,iParamLen);  //_tcsncmp
  else
     iReturn=_tcsnicmp(pStrBuffer+i,pToRemove,iParamLen); //__tcsnicmp
  if(iReturn!=0)
  {
     if(blnFound)
        pStrBuffer[j]=pStrBuffer[i];
     j++, i++;
  }
  else   //made a match
  {
     blnFound=true;
     i=i+iParamLen;
     pStrBuffer[j]=pStrBuffer[i];
     j++, i++;
  }
 }while(1);
 if(blnFound)
    pStrBuffer[i-iParamLen]=_T('\0');
 String sr=pStrBuffer;

 return sr;
}


String String::Remove(TCHAR* pStr)
{
 unsigned int i,j,iStrLen,iParamLen;
 TCHAR *pThis, *pThat, *p;
 bool blnFoundBadChar;

 iStrLen=this->LenStr();             //The length of this
 String sr((int)iStrLen);            //Create new String big enough to contain original String (this)
 iParamLen=_tcslen(pStr);            //Get length of parameter (pStr) which contains chars to be removed
 pThis=this->pStrBuffer;
 p=sr.lpStr();
 for(i=0; i<iStrLen; i++)
 {
     pThat=pStr;
     blnFoundBadChar=false;
     for(j=0; j<iParamLen; j++)
     {
         if(*pThis==*pThat)
         {
            blnFoundBadChar=true;
            break;
         }
         pThat++;
     }
     if(!blnFoundBadChar)
     {
        *p=*pThis;
         p++;
        *p=_T('\0');
     }
     pThis++;
 }

 return sr;
}


String String::Retain(TCHAR* pStr)
{
 unsigned int i,j,iStrLen,iParamLen;
 TCHAR *pThis, *pThat, *p;
 bool blnFoundGoodChar;

 iStrLen=this->LenStr();             //The length of this
 String sr((int)iStrLen);            //Create new String big enough to contain original String (this)
 iParamLen=_tcslen(pStr);            //Get length of parameter (pStr) which contains chars to be retained
 pThis=this->pStrBuffer;             //pThis will point to this String's buffer, and will increment through string.
 p=sr.lpStr();                       //p will start by pointing to new String's buffer and will increment through new string
 for(i=0; i<iStrLen; i++)
 {
     pThat=pStr;
     blnFoundGoodChar=false;
     for(j=0; j<iParamLen; j++)
     {
         if(*pThis==*pThat)
         {
            blnFoundGoodChar=true;
            break;
         }
         pThat++;
     }
     if(blnFoundGoodChar)
     {
        *p=*pThis;
         p++;
        *p=_T('\0');
     }
     pThis++;
 }

 return sr;
}


/*
String& String::Retain(TCHAR* pStr)
{
 unsigned int i,j,blnFoundGoodChar,iStrLen;
 TCHAR *pNewStr,*p,*r,*pOrigNewStr;

 pNewStr=new TCHAR[_tcslen(this->pStrBuffer)+1];
 pOrigNewStr=pNewStr;
 memset(pNewStr,_T('\0'),_tcslen(this->pStrBuffer));
 p=pStrBuffer;
 iStrLen=_tcslen(pStr);
 for(i=0; i<_tcslen(this->pStrBuffer); i++)
 {
     r=pStr;
     blnFoundGoodChar=0;
     for(j=0;j<iStrLen;j++)
     {
         if(*p==*r)
         {
            blnFoundGoodChar=1;
            break;
         }
         r++;
     }
     if(blnFoundGoodChar)
     {
        *pNewStr=*p;
        pNewStr++;
        p++;
        *pNewStr=0;
     }
     else
        p++;
 }
 delete [] pStrBuffer;
 pStrBuffer=pOrigNewStr;

 return *this;
}
*/

int String::InStr(const TCHAR ch)
{
 int iLen,i;

 iLen=_tcslen(this->pStrBuffer);
 for(i=0;i<iLen;i++)
 {
     if(this->pStrBuffer[i]==ch)
        return (i+1);
 }

 return 0;
}


int String::InStr(const TCHAR* pStr, bool blnCaseSensitive)
{
 int i,iParamLen,iRange;

 if(*pStr==0)
    return 0;
 iParamLen=_tcslen(pStr);
 iRange=_tcslen(pStrBuffer)-iParamLen;
 if(iRange>=0)
 {
    for(i=0;i<=iRange;i++)
    {
        if(blnCaseSensitive)
        {
           if(_tcsncmp(pStrBuffer+i,pStr,iParamLen)==0)   //_tcsncmp
              return i+1;
        }
        else
        {
           if(_tcsnicmp(pStrBuffer+i,pStr,iParamLen)==0)  //__tcsnicmp
              return i+1;
        }
    }
 }

 return 0;
}


int String::InStr(const String& s, bool blnCaseSensitive)
{
 int i,iParamLen,iRange,iLen;

 iLen=_tcslen(s.pStrBuffer);
 if(iLen==0)
    return 0;
 iParamLen=iLen;
 iRange=_tcslen(pStrBuffer)-iParamLen;
 if(iRange>=0)
 {
    for(i=0;i<=iRange;i++)
    {
        if(blnCaseSensitive)
        {
           if(_tcsncmp(pStrBuffer+i,s.pStrBuffer,iParamLen)==0)  //_tcsncmp
              return i+1;
        }
        else
        {
           if(_tcsnicmp(pStrBuffer+i,s.pStrBuffer,iParamLen)==0) //__tcsnicmp
              return i+1;
        }
    }
 }

 return 0;
}


void String::LTrim()
{
 unsigned int i,iCt=0,iLenStr;

 iLenStr=this->LenStr();
 for(i=0;i<iLenStr;i++)
 {
     if(pStrBuffer[i]==32||pStrBuffer[i]==9)
        iCt++;
     else
        break;
 }
 if(iCt)
 {
    for(i=iCt;i<=iLenStr;i++)
        pStrBuffer[i-iCt]=pStrBuffer[i];
 }
}


void String::RTrim()
{
 unsigned int iCt=0, iLenStr;

 iLenStr=this->LenStr()-1;
 for(unsigned int i=iLenStr; i>0; i--)
 {
     if(this->pStrBuffer[i]==9||this->pStrBuffer[i]==10||this->pStrBuffer[i]==13||this->pStrBuffer[i]==32)
        iCt++;
     else
        break;
 }
 this->pStrBuffer[this->LenStr()-iCt]=0;
}


void String::Trim()
{
 this->LTrim();
 this->RTrim();
}


unsigned int String::ParseCount(const TCHAR c)  //returns one more than # of
{                                              //delimiters so it accurately
 unsigned int iCtr=0;                          //reflects # of strings delimited
 TCHAR* p;                                      //by delimiter.

 p=this->pStrBuffer;
 while(*p)
 {
  if(*p==c)
     iCtr++;
  p++;
 }

 return ++iCtr;
}


void String::Parse(String* pStr, TCHAR delimiter)
{
 unsigned int i=0;
 TCHAR* pBuffer=0;
 TCHAR* c;
 TCHAR* p;

 pBuffer=new TCHAR[this->LenStr()+1];
 if(pBuffer)
 {
    p=pBuffer;
    c=this->pStrBuffer;
    while(*c)
    {
     if(*c==delimiter)
     {
        pStr[i]=pBuffer;
        //printf("Assigned pStr[%u] In Parse()\n",i);
        //printf("pStr[%u]=%s\n\n",i,pStr[i].lpStr());
        p=pBuffer;
        i++;
     }
     else
     {
        *p=*c;
        p++;
        *p=0;
     }
     c++;
    }
    pStr[i]=pBuffer;
    delete [] pBuffer;
 }
}


int String::iVal()
{
 return _ttoi(this->pStrBuffer);  //_ttoi
}


String String::CStr(const int iNum)
{
 String sr;
 _stprintf(sr.pStrBuffer,_T("%d"),iNum);
 return sr;
}


String String::CStr(const unsigned int iNum)
{
 String sr;
 _stprintf(sr.pStrBuffer,_T("%u"),iNum);
 return sr;
}


String String::CStr(const DWORD dwNum)
{
 String sr;
 _stprintf(sr.pStrBuffer,_T("%u"),(unsigned)dwNum);
 return sr;
}


String String::CStr(const short int iNum)
{
 String sr;
 _stprintf(sr.pStrBuffer,_T("%d"),iNum);
 return sr;
}


String String::CStr(const double dblNum)
{
 String sr(32);
 _stprintf(sr.pStrBuffer,_T("%f"),dblNum);
 return sr;
}


int String::LenStr(void)
{
 return _tcslen(this->pStrBuffer);
}


TCHAR* String::lpStr()
{
 return pStrBuffer;
}


TCHAR String::GetChar(unsigned int iOffset)
{
 return this->pStrBuffer[iOffset-1];
}


void String::SetChar(unsigned int iOneBasedOffset, TCHAR tcChar)
{
 if((int)iOneBasedOffset<=this->iAllowableCharacterCount)
    this->pStrBuffer[iOneBasedOffset-1]=tcChar;
}


void String::Print(bool blnCrLf)
{
 _tprintf(_T("%s"),pStrBuffer);
 if(blnCrLf)
    _tprintf(_T("\n"));
}


String::~String()   //String Destructor
{
 delete [] pStrBuffer;
 pStrBuffer=0;
}
//SqlProcs.cpp
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include  <odbcinst.h>
#include  <sql.h>
#include  <sqlext.h>
#include "Strings.h"
#include "Sql.h"
#include "SqlProcs.h"
extern FILE* fp;


unsigned int iInstallerError()
{
 DWORD pErr;
 TCHAR szErrMsg[512];
 WORD  cbMsgBuffer=512;
 WORD  cbRet;
 WORD  wErrNum=1;

 while(SQLInstallerError(wErrNum,&pErr,szErrMsg,cbMsgBuffer,&cbRet)!=SQL_NO_DATA)
 {
  wErrNum++;
 };

 return (unsigned int)pErr;
}


void MkDate(TIMESTAMP_STRUCT& ts, TCHAR* szBuffer)
{
 TCHAR szMonth[4],szDay[4],szYear[8];

 _stprintf(szMonth,_T("%u"),ts.month);
 _stprintf(szDay,_T("%u"),ts.day);
 _stprintf(szYear,_T("%u"),ts.year);
 _tcscpy(szBuffer,szMonth);
 _tcscat(szBuffer,_T("/"));
 _tcscat(szBuffer,szDay);
 _tcscat(szBuffer,_T("/"));
 _tcscat(szBuffer,szYear);

 return;
}


TIMESTAMP_STRUCT ParseDate(TCHAR* szDate, TCHAR* szFormat, TCHAR* szDelimiter)
{
 UINT i=0,j=0,k=0;
 TIMESTAMP_STRUCT ts;
 TCHAR buf[3][8];             //buf[0] for month, buf[1] for day, buf[2] for year
 TCHAR* p;

 memset(buf,0,sizeof(buf));  //zero out buf[]
 p=szDate;
 for(i=0;i<_tcslen((TCHAR*)szDate);i++)
 {
     if(*p!=*szDelimiter)
     {
        buf[j][k++]=*p;
        buf[j][k+1]=_T('\0');
     }
     else
     {
        j++;
        k=0;
     }
     p++;
 }
 if(!_tcsicmp((TCHAR*)szFormat,_T("MDY")))
 {
    ts.month=(short)_ttoi(buf[0]);
    ts.day=(short)_ttoi(buf[1]);
    ts.year=(short)_ttoi(buf[2]);
 }
 if(!_tcsicmp((TCHAR*)szFormat,_T("DMY")))
 {
    ts.day=(short)_ttoi(buf[0]);
    ts.month=(short)_ttoi(buf[1]);
    ts.year=(short)_ttoi(buf[2]);
 }
 if(!_tcsicmp((TCHAR*)szFormat,_T("YMD")))
 {
    ts.year=(short)_ttoi(buf[0]);
    ts.month=(short)_ttoi(buf[1]);
    ts.day=(short)_ttoi(buf[2]);
 }

 return ts;
}


unsigned int iCreateDB(TCHAR* szDBName)    //To create a Microsoft Access Database from
{                                          //scratch, you use SQLConfigDataSource().  I
 TCHAR szCreate[256];                      //believe if the database already exists at the
                                           //specific location SQLInstallerError() returns
 _tcscpy(szCreate,_T("CREATE_DB="));       //'11'.
 _tcscat(szCreate,szDBName);
 if(SQLConfigDataSource(0,ODBC_ADD_DSN,_T("Microsoft Access Driver (*.mdb)"),szCreate))
    return TRUE;
 else
    return iInstallerError();
}


UINT blnMakeTable(SQL& Sql)          //Uses SQL Create Table statement to add table
{                                    //to database represented by sql->hConn
 TCHAR szQuery[256];
 SQLHSTMT hStmt;

 _tcscpy(szQuery,_T("CREATE TABLE Table1 (Id LONG  NOT NULL PRIMARY KEY, Float_Point DOUBLE, Date_Field DATETIME, Text_Field CHAR(16));"));
 SQLAllocHandle(SQL_HANDLE_STMT,Sql.hConn,&hStmt);
 if(SQLExecDirect(hStmt,(SQLTCHAR*)szQuery,SQL_NTS)==0)
 {
    SQLFreeHandle(SQL_HANDLE_STMT,hStmt);
    return(TRUE);
 }
 else
    return(FALSE);
}


int GetRecordCount(SQL& Sql)
{
 unsigned int iRecCt=0;
 TCHAR szQuery[128];
 SQLHSTMT hStmt;
 long iJnk;

 _tcscpy(szQuery,_T("SELECT Count(*)  As RecordCount From Table1;"));
 SQLAllocHandle(SQL_HANDLE_STMT,Sql.hConn,&hStmt);
 SQLBindCol(hStmt,1,SQL_C_ULONG,&iRecCt,0,&iJnk);
 if(SQLExecDirect(hStmt,(SQLTCHAR*)szQuery,SQL_NTS)!=SQL_SUCCESS)
 {
    SQLGetDiagRec(SQL_HANDLE_STMT,hStmt,1,Sql.szErrCode,&Sql.iNativeErrPtr,Sql.szErrMsg,512,&Sql.iTextLenPtr);
    SQLFreeHandle(SQL_HANDLE_STMT,hStmt);
    return -1;
 }
 else
 {
    SQLFetch(hStmt);
    SQLCloseCursor(hStmt);
    SQLFreeHandle(SQL_HANDLE_STMT,hStmt);
    return iRecCt;
 }
}


UINT blnInsert(SQL& sql)
{
 const TCHAR* szStr[]={_T("My Birthday"),_T("Walk On Moon?"),_T("Some String"),_T("April Fools Day")};
 TCHAR* szDate[]={(TCHAR*)_T("11/15/1952"),(TCHAR*)_T("6/30/1969"),(TCHAR*)_T("1/1/2006"),(TCHAR*)_T("4/1/2006")};
 double dblNum[]={3.14159,1.23456,15.1234,0.54321};
 TCHAR  szQuery[100],szString[32],szBuffer[128];      //Let me give you a hint about something.  If you decide
 SQLINTEGER iNts=SQL_NTS;                             //to use raw ODBC as your database access methodology, the
 UINT i,id,iRet=FALSE;                                //hard part is SQLBindParameter() for inserting prepared
 TIMESTAMP_STRUCT ts;                                 //SQL statements, and SQLBindCol() for selecting data.  These
 SQLINTEGER iJnk;                                     //will inevitably take you some time to learn.  I chose an
 SQLHSTMT hStmt;                                      //integer, a double, a data, and a char string so as to get
 double dbl;                                          //you started on the most common data types.

 #if defined(MY_DEBUG)
     _ftprintf(fp,_T("Entering blnInsert()\n"));
 #endif
 if(SQLAllocHandle(SQL_HANDLE_STMT,sql.hConn,&hStmt)==SQL_SUCCESS)
 {
    _tcscpy((TCHAR*)szQuery,_T("INSERT INTO Table1(Id, Float_Point, Date_Field, Text_Field) VALUES(?,?,?,?);"));
    _tprintf(_T("szQuery = %s\n\n"),szQuery);
    _tprintf(_T("                                                         SQLExecute(hStmt)\n"));
    _tprintf(_T("iId      Double           Date           String           0=SQL_SUCCESS\n"));
    _tprintf(_T("========================================================================\n"));
    if(SQLPrepare(hStmt,(SQLTCHAR*)szQuery,SQL_NTS)==SQL_SUCCESS)
    {
       SQLBindParameter(hStmt,1,SQL_PARAM_INPUT,SQL_C_LONG,SQL_INTEGER,0,0,&id,0,&iJnk);
       SQLBindParameter(hStmt,2,SQL_PARAM_INPUT,SQL_C_DOUBLE,SQL_DOUBLE,0,0,&dbl,0,&iJnk);
       SQLBindParameter(hStmt,3,SQL_PARAM_INPUT,SQL_C_TYPE_DATE,SQL_TYPE_TIMESTAMP,16,0,&ts,0,&iJnk);
       SQLBindParameter(hStmt,4,SQL_PARAM_INPUT,SQL_C_TCHAR,SQL_CHAR,31,0,szString,32,&iNts);
       #if defined(MY_DEBUG)
           _ftprintf(fp,_T("\n                                                         SQLExecute(hStmt)\n"));
           _ftprintf(fp,_T("  iId      Double           Date           String           0=SQL_SUCCESS  \n"));
           _ftprintf(fp,_T("  ========================================================================\n"));
       #endif
       for(i=0;i<4;i++)
       {
           id=i+1;
           dbl=dblNum[i];
           ts=ParseDate(szDate[i],(TCHAR*)_T("mdy"),(TCHAR*)_T("/"));
           _tcscpy(szString,szStr[i]);
           if(SQLExecute(hStmt)==SQL_SUCCESS)
           {
              memset(szBuffer,0,128);
              _stprintf(szBuffer,_T("%-6u%8.2f           %-12.10s  %-20s%6u"),id,dbl,szDate[i],szString,SQL_SUCCESS);
              _tprintf(_T("%s\n"),szBuffer);
              #if defined(MY_DEBUG)
                  _ftprintf(fp,_T("  %u\t%f\t%s\t%s\t\t%u\n"),id,dbl,szDate[i],szString,SQL_SUCCESS);
              #endif
           }
           else
           {
              SQLGetDiagRec(SQL_HANDLE_STMT,hStmt,1,sql.szErrCode,&sql.iNativeErrPtr,sql.szErrMsg,512,&sql.iTextLenPtr);
              #if defined(MY_DEBUG)
                  _ftprintf(fp,_T("  sql.dr.szErrCode = %s\n"),sql.szErrCode);
                  _ftprintf(fp,_T("  sql.dr.szErrMsg  = %s\n"),sql.szErrMsg);
              #endif
              SQLFreeHandle(SQL_HANDLE_STMT,hStmt);
              return FALSE;
           }
       }
       iRet=TRUE;
       #if defined(MY_DEBUG)
           _ftprintf(fp,_T("\n"));
       #endif
    }
    SQLFreeHandle(SQL_HANDLE_STMT,hStmt);
 }
 #if defined(MY_DEBUG)
     _ftprintf(fp,_T("Leaving blnInsert()\n\n"));
 #endif

 return iRet;
}


UINT blnDumpData(SQL& sql)
{
 TCHAR szQuery[100],szBuffer[128],szDate[12];
 SQLTCHAR szString[16];
 TIMESTAMP_STRUCT ts;
 SQLINTEGER iJnk;
 SQLHSTMT hStmt;
 double dblNum;
 UINT iId;

 #if defined(MY_DEBUG)
     _ftprintf(fp,_T("Entering blnDumpData()\n"));
 #endif
 if(SQLAllocHandle(SQL_HANDLE_STMT,sql.hConn,&hStmt)==SQL_SUCCESS)
 {
    _tcscpy(szQuery,_T("SELECT Table1.Id,Table1.Float_Point,Table1.Date_Field,Table1.Text_Field FROM Table1;"));
    SQLBindCol(hStmt,1,SQL_C_ULONG,&iId,0,&iJnk);
    SQLBindCol(hStmt,2,SQL_C_DOUBLE,&dblNum,0,&iJnk);
    SQLBindCol(hStmt,3,SQL_C_TYPE_DATE,&ts,0,&iJnk);
    SQLBindCol(hStmt,4,SQL_C_TCHAR,szString,sizeof(TCHAR)*16,&iJnk);
    if(SQLExecDirect(hStmt,(SQLTCHAR*)szQuery,SQL_NTS)==SQL_SUCCESS)
    {
       _tprintf(_T("iId      Double           Date           String           0=SQL_SUCCESS\n"));
       _tprintf(_T("========================================================================\n"));
       do
       {
          if(SQLFetch(hStmt)==SQL_NO_DATA)
             break;
          memset(szBuffer,0,sizeof(TCHAR)*128);
          MkDate(ts,szDate);
          _stprintf(szBuffer,_T("%-6u%8.2f           %-12.10s  %-16s    %6u"),iId,dblNum,szDate,szString,SQL_SUCCESS);
          _tprintf(_T("%s\n"),szBuffer);
       }  while(TRUE);
    }
    SQLCloseCursor(hStmt);
    SQLFreeHandle(SQL_HANDLE_STMT,hStmt);
    #if defined(MY_DEBUG)
        _ftprintf(fp,_T("Leaving blnDumpData()\n\n"));
    #endif
    return TRUE;
 }
 #if defined(MY_DEBUG)
     _ftprintf(fp,_T("Leaving blnDumpData()\n\n"));
 #endif

 return FALSE;
}
//Sql.cpp
#include  <windows.h>
#include  <tchar.h>
#include  <stdio.h>
#include  <odbcinst.h>
#include  <sql.h>
#include  <sqlext.h>
#include  "Strings.h"
#include  "Sql.h"
#if defined(MY_DEBUG)
    extern FILE* fp;
#endif


SQL::SQL() //Constructor
{
 ZeroMemory(szCnOut, 512);
 ZeroMemory(szErrMsg,512);
 strDBQ=_T("");
}


SQL::~SQL()
{
 //Sql Destructor
}


void SQL::MakeConnectionString(void)
{
 if(strDriver==_T("SQL Server"))
 {
    if(strDBQ==_T(""))
    {
       strConnectionString=_T("DRIVER=");
       strConnectionString=strConnectionString+strDriver+_T(";")+_T("SERVER=")+strServer+_T(";");
    }
    else
    {
       strConnectionString=_T("DRIVER=");
       strConnectionString=strConnectionString+strDriver+_T(";")+_T("SERVER=")+strServer+_T(";")+ \
       _T("DATABASE=") + strDatabase + _T(";") + _T("DBQ=") + strDBQ + _T(";");
    }
 }
 else if(strDriver==_T("Microsoft Access Driver (*.mdb)"))
 {
    strConnectionString=_T("DRIVER=");
    strConnectionString=strConnectionString+strDriver+_T(";")+_T("DBQ=")+strDBQ+_T(";");
 }
 else if(strDriver==_T("Microsoft Excel Driver (*.xls)"))
 {
    strConnectionString=_T("DRIVER=");
    strConnectionString=strConnectionString+strDriver+_T(";")+_T("DBQ=")+strDBQ+_T(";");
 }
}


void SQL::ODBCConnect(void)
{
 TCHAR szCnIn[512];
 UINT iResult;

 MakeConnectionString();
 SQLAllocHandle(SQL_HANDLE_ENV,SQL_NULL_HANDLE,&hEnvr);
 SQLSetEnvAttr(hEnvr,SQL_ATTR_ODBC_VERSION,(SQLPOINTER)SQL_OV_ODBC3,SQL_IS_INTEGER);
 SQLAllocHandle(SQL_HANDLE_DBC,hEnvr,&hConn);
 _tcscpy(szCnIn,strConnectionString.lpStr());
 iResult=SQLDriverConnect(hConn,NULL,(SQLTCHAR*)szCnIn,(SQLSMALLINT)_tcslen(szCnIn),(SQLTCHAR*)szCnOut,512,&swStrLen,SQL_DRIVER_NOPROMPT);
 if(iResult==0 || iResult==1)
    blnConnected=TRUE;
 else
 {
    SQLGetDiagRec(SQL_HANDLE_DBC,hConn,1,szErrCode,&iNativeErrPtr,szErrMsg,512,&iTextLenPtr);
    blnConnected=FALSE;
    SQLDisconnect(hConn);
    SQLFreeHandle(SQL_HANDLE_DBC,hConn);
    SQLFreeHandle(SQL_HANDLE_ENV,hEnvr);
    _tprintf(_T("szErrCode = %s\n"),szErrCode);
    _tprintf(_T("szErrMsg  = %s\n"),szErrMsg);
 }
}


void SQL::ODBCDisconnect(void)
{
 if(blnConnected==TRUE)
 {
    SQLDisconnect(hConn);
    SQLFreeHandle(SQL_HANDLE_DBC,hConn);
    SQLFreeHandle(SQL_HANDLE_ENV,hEnvr);
    blnConnected=FALSE;
 }
}
//Sql.h
#if !defined(SQL_H)
#define SQL_H

class SQL
{
 public:
 SQL();
 ~SQL();
 void MakeConnectionString(void);
 void ODBCConnect(void);
 void ODBCDisconnect(void);

 public:
 String            strConnectionString;
 String            strDatabase;
 String            strDriver;
 String            strServer;
 String            strDBQ;
 TCHAR             szCnOut[512];
 short int         iBytes;
 SWORD             swStrLen;
 SQLHENV           hEnvr;
 SQLHDBC           hConn;
 SQLINTEGER        iNativeErrPtr;
 SQLSMALLINT       iTextLenPtr;
 SQLTCHAR          szErrMsg[512];
 SQLTCHAR          szErrCode[8];
 unsigned int      blnConnected;
};

#endif
//SqlProcs.h

#ifndef SqlProcs_h
#define SqlProcs_h
//#define  MY_DEBUG     //unremark for debug
unsigned int iInstallerError();
void MkDate(TIMESTAMP_STRUCT&, TCHAR*);
TIMESTAMP_STRUCT ParseDate(TCHAR*, TCHAR*, TCHAR*);
unsigned int iCreateDB(TCHAR*);
UINT blnMakeTable(SQL&);
int GetRecordCount(SQL&);
UINT blnInsert(SQL&);
UINT blnDumpData(SQL&);
#endif
//Strings.h
#if !defined(STRINGS_H)
#define STRINGS_H
#define EXPANSION_FACTOR      2
#define MINIMUM_ALLOCATION    8

class __declspec(dllexport) String
{
 public:
 String();                                 //Uninitialized Constructor
 String(const TCHAR);                      //Constructor Initializes String With TCHAR
 String(const TCHAR*);                     //Constructor Initializes String With TCHAR*
 String(const String&);                    //Constructor Initializes String With Another String (Copy Constructor)
 String(const int);                        //Constructor Initializes Buffer To Specific Size
 String(const TCHAR ch, const int iCount); //Constructor initializes String with int # of chars
 String& operator=(const TCHAR);           //Assigns TCHAR To String
 String& operator=(const TCHAR*);          //Assigns TCHAR* To String
 String& operator=(const String&);         //Assigns one String to another (this one)
 String& operator+(const TCHAR);           //For adding TCHAR to String
 bool operator==(const String);            //For comparing Strings
 String& operator+(const TCHAR*);          //For adding null terminated TCHAR array to String
 String& operator+(const String&);         //For adding one String to Another
 String Left(unsigned int);                //Returns String of iNum Left Most TCHARs of this
 String Right(unsigned int);               //Returns String of iNum Right Most TCHARs of this
 String Mid(unsigned int, unsigned int);   //Returns String consisting of number of TCHARs from some offset
 String& Make(const TCHAR ch, int iCount); //Creates (Makes) a String with iCount TCHARs
 String& GetModulePath();                  //Returns reference To String Containing Path of Exe/dll running
 String Remove(const TCHAR*, bool);        //Returns A String With A Specified TCHAR* Removed
 String Remove(TCHAR* pStr);               //Returns A String With All The TCHARs In A TCHAR* Removed (Individual char removal)
 String Retain(TCHAR* pStr);               //Seems to return a String with some characters retained???
 int InStr(const TCHAR);                   //Returns one based offset of a specific TCHAR in a String
 int InStr(const TCHAR*, bool);            //Returns one based offset of a particular TCHAR pStr in a String
 int InStr(const String&, bool);           //Returns one based offset of where a particular String is in another String
 void LTrim();                             //Returns String with leading spaces/tabs removed
 void RTrim();                             //Returns String with spaces/tabs removed from end
 void Trim();                              //Returns String with both leading and trailing whitespace removed
 unsigned int ParseCount(const TCHAR);     //Returns count of Strings delimited by a TCHAR passed as a parameter
 void Parse(String*, TCHAR);               //Returns array of Strings in first parameter as delimited by 2nd TCHAR delimiter
 String CStr(const int);                   //Converts String to integer
 String CStr(const unsigned int);          //Converts String to unsigned int
 String CStr(const DWORD);
 String CStr(const short int);             //Converts String to 16 bit int
 String CStr(const double);                //Converts String to double
 int iVal();                               //Returns int value of a String
 int LenStr(void);                         //Returns length of string
 TCHAR* lpStr();                           //Returns address of pStrBuffer member variable
 TCHAR GetChar(unsigned int);              //Returns TCHAR at one based index
 void SetChar(unsigned int, TCHAR);        //Sets TCHAR at one based index
 void Print(bool);                         //Outputs String to Console with or without CrLf
 ~String();                                //String Destructor

 private:
 TCHAR* pStrBuffer;
 int    iAllowableCharacterCount;
};

#endif

thanks again Freddy. AFAIK, Odbc is not part of C++ standard so it is neither in Mingw or Linux GCC. So where do I download headers/sources to compile? Or even ready .a and .h?
Thanks

AFAIK, Odbc is not part of C++ standard so it is neither in Mingw or Linux GCC. So where do I download headers/sources to compile? Or even ready .a and .h?

In terms of relational databases, what is in the C++ standard? My guess is nothing, but don't rely on me as being knowledeable about the C++ standard because I've never read it.

Having said that I've never used a Windows computer nor a 32 bit programming language where I couldn't easily use ODBC to connect to relational databases, among other things. I use PowerBASIC a lot...

www.powerbasic.com

and they have headers that allow me to use ODBC. Years ago I used to use the GNU / Bloodshed Dev-C++ and the necessary libs and headers were installed as part of the default install. Likewise Visual Studio 6 (circa 1999), and Visual Studio 2008. I now use the new cross platform Code::Blocks a lot too. That code I just posted was written in CodeBlocks.

The most basic Windows installation will install ODBC drivers for most databases; I'm even pretty sure for Oracle. I wouldn't bet my life on that one, but I've seen Oracle Drivers on my systems, and I've never installed any Oracle products.

I have some programming familiarity with Linux, but I've never done any database work on it, so I can't guide you there. If you are only using Linux, why don't you check the /bin and /lib subdirectories for those libs I mentioned and these includes...

#include <odbcinst.h>
#include <sql.h>
#include <sqlext.h>

I can't imagine you have any C++ installation without these files.


#include <odbcinst.h>
#include <sql.h>
#include <sqlext.h>

I can't imagine you have any C++ installation without these files.

They are there On Mingw. I hope there will be too in my GCC in Ubuntu!

Thanks a lot.
Now I have to find ODBC tutorial!

I've posted various tutorial material on the subject in various places. Here is about the same as I posted here but in C instead of C++, but I believe the code is somewhat more heavily commented...

http://www.powerbasic.com/support/pbforums/showthread.php?t=24912&highlight=ODBC+Demo

And here is a rather complex demo that is GUI but shows how to connect to Microsoft SQL Server, Microsoft Access, and Microsoft Excel. Also, it shows how to use SQLDrivers() to dump the ODBC database drivers on your system....

http://www.jose.it-berater.org/smfforum/index.php?board=378.0

As I mentioned, I never tried it on Linux. I have Ubuntu too; just never checked it out. These ODBC functions (the ODBC Api) should work exactly the same on Linux/Unix as on Windows though. If you get it working with My Sql or anything like that I'd appreciate knowing how to change or add to my cnnection string wrappers so as to include it so to speak. The way things are set up now, I have that MakeConnectionString() function...

void SQL::MakeConnectionString(void)
{
 if(strDriver==_T("SQL Server"))
 {
    if(strDBQ==_T(""))
    {
       strConnectionString=_T("DRIVER=");
       strConnectionString=strConnectionString+strDriver+_T(";")+_T("SERVER=")+strServer+_T(";");
    }
    else
    {
       strConnectionString=_T("DRIVER=");
       strConnectionString=strConnectionString+strDriver+_T(";")+_T("SERVER=")+strServer+_T(";")+ \
       _T("DATABASE=") + strDatabase + _T(";") + _T("DBQ=") + strDBQ + _T(";");
    }
 }
 else if(strDriver==_T("Microsoft Access Driver (*.mdb)"))
 {
    strConnectionString=_T("DRIVER=");
    strConnectionString=strConnectionString+strDriver+_T(";")+_T("DBQ=")+strDBQ+_T(";");
 }
 else if(strDriver==_T("Microsoft Excel Driver (*.xls)"))
 {
    strConnectionString=_T("DRIVER=");
    strConnectionString=strConnectionString+strDriver+_T(";")+_T("DBQ=")+strDBQ+_T(";");
 }
}

where you choose SQL Server, Microsoft Access Driver, or Excel Driver, and that function puts together a connection string. That's the function that needs added to to support other databases.

When I first learned ODBC I printed out Microsoft's entire documentation, which comes to 1500 pages or so. Also, I bought a book. It is hard to learn. I want to emphasize though that even though the documentation is from Microsoft, it is fully usable from Linux. The function calls and parameters will be exactly the same. It was designed to be cross platform.

Good Luck.

A general solution is to use a class library such as Qt4 available from http://qt.nokia.com/. Here you'll find general classes for accessing all major RDBMS's (Oracle, MySQl, SQlite etc...). Qt is great...

Specifically for Oracle, a more difficult, but high performance method is the OCI or OCCI API available from oracles website for free.

A general solution is to use a class library such as Qt4 available from http://qt.nokia.com/. Here you'll find general classes for accessing all major RDBMS's (Oracle, MySQl, SQlite etc...). Qt is great...

Specifically for Oracle, a more difficult, but high performance method is the OCI or OCCI API available from oracles website for free.

The problem is, I have learned great deal of wxWidgets and I don't plan to learn QT for now. I have invested a lot of time in learning wx. May be when only alternative is QT ;)

Thanks

I find it hard to believe you are finding it hard to find links on ODBC. Here is a Wikipedial link...

http://en.wikipedia.org/wiki/Open_Database_Connectivity

I imagine wxWidgets must have some class wrappers on ODBC. If not you can use what I provided as a start. All those databases you listed in your first post are supported for sure. The beauty of ODBC is that you can use close to the same code for all. I say 'close to the same' because the standards allow for different levels of support. ODBC contains various functions that query the underlying proprietary database driver for functionalities supported. In that way your code can act appropriately to the context of its present environment.

This question has already been answered. Start a new discussion instead.