Main Page   Class Hierarchy   File List  

openODBC.cpp

00001 /*
00002    These classes define a
00003    ODBC implementation
00004    to the open database interfaces.
00005    ================================
00006 */
00007 
00008 #include "openODBC.h"
00009 #include "ocString.h"
00010 
00011 
00012 /*
00013   utility method to help insure the integrity of the result
00014 */
00015 
00016 bool odbcDB::error( SQLHSTMT hstmt )
00017 {
00018   UCHAR sqlstate[10];
00019   UCHAR errmsg[SQL_MAX_MESSAGE_LENGTH];
00020   SDWORD nativeerr;
00021   SWORD actualmsglen;
00022   RETCODE rc;
00023   bool bRet = true;
00024   m_bGood = false;
00025   do
00026   {
00027     rc = SQLError( henv, hdbc, hstmt,
00028                    sqlstate, &nativeerr,
00029                    errmsg,
00030                    SQL_MAX_MESSAGE_LENGTH - 1, // for the null
00031                    &actualmsglen );
00032 
00033     if (rc == SQL_ERROR)
00034     {
00035       m_strErrors += "SQLError failed!\n";
00036       bRet = false;
00037     }
00038     else if( rc != SQL_NO_DATA_FOUND )
00039     {
00040       // append a null to the end of the errmsg buffer
00041       errmsg[actualmsglen] = '\0';
00042       m_strErrors += "SQLSTATE = ";
00043       m_strErrors += (char *)sqlstate;
00044       m_strErrors += "\nNATIVE ERROR = ";
00045       m_strErrors += nativeerr;
00046       m_strErrors += "\nMSG = ";
00047       m_strErrors += (char *)errmsg;
00048       m_strErrors += "\n\n";
00049     }
00050   } while ( rc != SQL_NO_DATA_FOUND && rc != SQL_ERROR );
00051   if(hstmt != SQL_NULL_HSTMT)
00052   {
00053     SQLFreeStmt(hstmt, SQL_CLOSE) ;
00054   }
00055   return bRet;
00056 }
00057 
00058 
00059 /*
00060 
00061   The DB interface to the odbc Database
00062 
00063 */
00064 odbcDB::odbcDB( string strConnection ):openDB(strConnection)
00065 {
00066   // hdbc; henv;  rc;
00067   // expect these for the dsn
00068   // dsn=mssql1;
00069   // pwd=webuser;
00070   // uid=webuser
00071   m_strErrors = "";
00072   m_provider = ODBC;
00073 
00074   rc = SQLAllocEnv(&henv);
00075   if ( (rc == SQL_SUCCESS) || (rc == SQL_SUCCESS_WITH_INFO))
00076   {
00077     rc = SQLAllocConnect( henv, &hdbc);
00078     if( parseConnection( strConnection ) )
00079     {
00080       for ( int retries = 1; retries <= 3; retries++ )
00081       {
00082 
00083         rc = SQLConnect( hdbc,
00084                         (SQLCHAR*)dsn.c_str(), SQL_NTS,
00085                         (SQLCHAR*)uid.c_str(), SQL_NTS,
00086                         (SQLCHAR*)pwd.c_str(), SQL_NTS );
00087 
00088         if( ( rc == SQL_SUCCESS) || (rc == SQL_SUCCESS_WITH_INFO) )
00089         {
00090           m_bGood = true;
00091           m_strErrors = "Connection OK\n";
00092           break;
00093         }
00094         else
00095         {
00096           error(SQL_NULL_HSTMT);
00097         }
00098       }
00099     }
00100   }
00101 
00102   // cout << "End of odbcDB Constructor: " << m_strErrors << endl;
00103 }
00104 
00105 bool odbcDB::parseConnection( string & strConnection )
00106 {
00107   bool bRet=false;
00108   dsn = uid = pwd = "";
00109   // expect these for the dsn
00110   // dsn=mssql1;pwd=webuser;uid=webuser
00111   ocString connStr = strConnection;
00112   connStr.parseInit();
00113   for( string element=connStr.parse(";");
00114        !(element.length()==0 && connStr.endOfParse() );
00115        element=connStr.parse(";") )
00116   {
00117     ocString apair(element);
00118     string name = apair.parse("=");
00119     string value = apair.parse("=");
00120     transform(name.begin(),name.end(),name.begin(),(int(*)(int)) toupper );
00121     if( name == "DSN" )
00122     {
00123       dsn = value;
00124     }
00125     else if ( name == "UID" )
00126     {
00127       uid = value;
00128     }
00129     else if( name == "PWD" )
00130     {
00131       pwd = value;
00132     }
00133   }
00134   if( dsn.length() && uid.length() && pwd.length() )
00135   {
00136     bRet = true;
00137   }
00138 
00139   return bRet;
00140 }
00141 dbProvider odbcDB::getProvider( void )
00142 {
00143   return m_provider;
00144 }
00145 odbcDB::~odbcDB()
00146 {
00147   SQLDisconnect(hdbc);
00148   SQLFreeConnect(hdbc);
00149   SQLFreeEnv(henv);
00150 }
00151 
00152 
00153 openCMD * odbcDB::createCommand()
00154 {
00155   return new odbcCMD( *this );
00156 }
00157 
00158 openRS * odbcDB::createRecordset()
00159 {
00160   return new odbcRS( *this );
00161 }
00162 
00163 
00164 /*
00165 
00166  This CMD class defines the odbc
00167    working interfaces to the SQL command
00168 
00169 */
00170 
00171 odbcCMD::odbcCMD( openDB & idb ):openCMD(idb)
00172 {
00173   // we KNOW this is really a reference to an odbcDB
00174   poDB = & dynamic_cast<odbcDB &>(rdb);
00175 }
00176 
00177 odbcCMD::~odbcCMD()
00178 {
00179   ;  // nothing to do
00180 }
00181 
00182 bool odbcCMD::beginTransaction()
00183 {
00184   // begin a transaction
00185   if( !m_bTransactioning )
00186   {
00187 
00188     m_bTransactioning = true;
00189   }
00190   return m_bTransactioning;
00191 }
00192 
00193 bool odbcCMD::commit()
00194 {
00195   // commit the transaction
00196   if( m_bTransactioning )
00197   {
00198 
00199     m_bTransactioning = false;
00200   }
00201   return !m_bTransactioning;
00202 }
00203 
00204 bool odbcCMD::rollback()
00205 {
00206   // commit the transaction
00207   if( m_bTransactioning )
00208   {
00209 
00210     m_bTransactioning = false;
00211   }
00212   return !m_bTransactioning;
00213 }
00214 
00215 bool odbcCMD::execute( string sql )
00216 {
00217   bool bRet = false;
00218   rc = SQLAllocStmt( poDB->getDbConnHandle(), &hstmt );
00219   if ( (rc != SQL_SUCCESS) &&
00220        (rc != SQL_SUCCESS_WITH_INFO) )
00221   {
00222     poDB->error(SQL_NULL_HSTMT);
00223   }
00224   else
00225   {
00226     // get the data
00227     rc = SQLExecDirect (hstmt, (SQLCHAR*)sql.c_str(), SQL_NTS);
00228     if( (rc != SQL_SUCCESS) &&
00229         (rc != SQL_SUCCESS_WITH_INFO) )
00230     {
00231       poDB->error(hstmt);
00232     }
00233     else
00234     {
00235       bRet = true;
00236     }
00237     SQLFreeStmt ((SQLHSTMT)hstmt, SQL_CLOSE) ;
00238   }
00239   return bRet;
00240 }
00241 
00242 /*
00243 
00244   This RS class defines the working
00245   odbc interfaces to the recordset
00246 
00247 */
00248 odbcRS::odbcRS( openDB & idb )
00249 :openRS(idb),hstmt(0),rc(0),numCols(0)
00250 {
00251   // we KNOW this is really a reference to a odbcDB
00252   poDB = dynamic_cast<odbcDB *>(&idb);
00253 }
00254 
00255 odbcRS::~odbcRS()
00256 {
00257   for( unsigned int i=0;i>ordinals.size();i++)
00258   {
00259     delete ordinals[i];
00260   }
00261   ordinals.clear();
00262   associations.clear();
00263 }
00264 
00265 bool odbcRS::open( string sql )
00266 {
00267   rc = SQLAllocStmt( poDB->getDbConnHandle(), &hstmt );
00268   if ( (rc != SQL_SUCCESS) &&
00269        (rc != SQL_SUCCESS_WITH_INFO) )
00270   {
00271     poDB->error(SQL_NULL_HSTMT);
00272   }
00273   else
00274   {
00275     // get the data
00276     rc = SQLExecDirect (hstmt, (SQLCHAR*)sql.c_str(), SQL_NTS);
00277     if( (rc != SQL_SUCCESS) &&
00278         (rc != SQL_SUCCESS_WITH_INFO) )
00279     {
00280       poDB->error(hstmt);
00281     }
00282     else
00283     {
00284       // debug cout << "Query OK!" << endl;
00285       // all is good, get column count
00286       numCols = 0 ;
00287       rc = SQLNumResultCols( hstmt, &numCols );
00288       if( (rc != SQL_SUCCESS) &&
00289           (rc != SQL_SUCCESS_WITH_INFO) )
00290       {
00291         poDB->error(hstmt);
00292       }
00293       else if (numCols == 0)
00294       {
00295         // no cols means not a select statement
00296         m_bOpen = false;
00297       }
00298       else
00299       {
00300         // set the base class field count
00301         m_iFields = (int) numCols;
00302 
00303         // debug cout << numCols << " Columns!" << endl;
00304         UWORD icol;
00305         // describe, allocate and bind the columns
00306 
00307         for( icol = 0 ; icol < numCols ; icol ++ )
00308         {
00309           odbcColInfo * pInfo = new odbcColInfo;
00310           rc = SQLDescribeCol( hstmt,
00311                                icol + (UWORD)1,
00312                                pInfo->szColName,
00313                                cOL_nAMe_Len,
00314                                &pInfo->cbColName,
00315                                &pInfo->fSqlType,
00316                                &pInfo->cbColDef,
00317                                &pInfo->ibScale,
00318                                &pInfo->fNullable) ;
00319           if ((rc != SQL_SUCCESS) &&
00320             (rc != SQL_SUCCESS_WITH_INFO))
00321           {
00322             delete pInfo;
00323             poDB->error(hstmt);
00324             break ;
00325           }
00326           else
00327           {
00328             // cout << " ColName=" << pInfo->szColName << endl;
00329             // Add the column info. to the back of the vector
00330             colInfo.push_back(pInfo);
00331             // get the map item based on sql type
00332             mapItem * pItem = colMap.data[pInfo->fSqlType];
00333             // debug cout << " MapItem Allocated: "  << pItem << endl;
00334             if( pItem )
00335             {
00336               // create the right kind of field
00337               basicField * pField =  pItem->createField( pInfo );
00338               if( pField )
00339               {
00340                 /*
00341                 cout << " ColName: " << pInfo->szColName
00342                      << " has field "  << pField
00343                      << " and type " << pInfo->fSqlType
00344                      << " and length " << pInfo->cbColDef
00345                      << endl;
00346                 */
00347                 // add to the vector
00348                 ordinals.push_back(pField);
00349                 // add to the map
00350                 associations.insert(make_pair((char*)pInfo->szColName,pField));
00351                 // cout << " get data storage " << endl;
00352                 void * pVoid = pItem->thingToBind( pInfo , pField );
00353                 // cout << " bind " << endl;
00354                 // bind results to the data storage
00355                 rc = SQLBindCol( hstmt,
00356                                  icol + (UWORD)1,
00357                                  pItem->cType,
00358                                  pVoid,
00359                                  pInfo->cbColDef+1,
00360                                  &pInfo->length );
00361                 if((rc != SQL_SUCCESS) &&
00362                    (rc != SQL_SUCCESS_WITH_INFO))
00363                 {
00364                   poDB->error(hstmt);
00365                   break;
00366                 }
00367               }
00368             }
00369             else
00370             {
00371               poDB->errorString() += "\r\nUnable to find type in map\r\n";
00372             }
00373           }
00374         }// end for all cols
00375 
00376         // now fetch the first row
00377         m_bOpen = next();
00378       }
00379     }
00380   }
00381   // cout << poDB->errorString();
00382   return m_bOpen;
00383 }
00384 bool odbcRS::beginTransaction()
00385 {
00386   // begin a transaction
00387   if( !m_bTransactioning )
00388   {
00389 
00390     m_bTransactioning = true;
00391   }
00392   return m_bTransactioning;
00393 }
00394 
00395 bool odbcRS::commit()
00396 {
00397   // commit the transaction
00398   if( m_bTransactioning )
00399   {
00400 
00401     m_bTransactioning = false;
00402   }
00403   return !m_bTransactioning;
00404 }
00405 bool odbcRS::close( void )
00406 {
00407 
00408   return !m_bOpen;
00409 }
00410 
00411 bool odbcRS::next( int )
00412 {
00413 
00414   rc = SQLFetch(hstmt);
00415   if((rc != SQL_SUCCESS) &&
00416     (rc != SQL_SUCCESS_WITH_INFO))
00417   {
00418     poDB->error(hstmt);
00419     return false;
00420   }
00421   UWORD icol;
00422   // now do post fetch fixips   numCols
00423   for( icol = 0 ; icol < numCols; icol ++ )
00424   {
00425     odbcColInfo * pInfo = colInfo[icol];
00426     if( pInfo )
00427     {
00428       mapItem * pItem = colMap.data[pInfo->fSqlType];
00429       if( pItem )
00430       {
00431         basicField * pField = ordinals[icol];
00432         if( pField)
00433         {
00434           pItem->postFetchFixup(pInfo,pField);
00435         }
00436       }
00437     }
00438   }
00439 
00440   return true;
00441 }
00442 
00443 bool odbcRS::previous( int )
00444 {
00445 
00446   return true;
00447 }

Generated on Tue Jan 20 09:06:56 2004 for OpenTools by doxygen1.2.18