Main Page   Class Hierarchy   File List  

openDBPG.cpp

00001 /*
00002 
00003  These classes define a postgreSQL implementation
00004    to the open database interfaces
00005 
00006 */
00007 #include "openDBPG.h"
00008 #include "pgTypeOids.h"
00009 
00010 // initialize the static member variable
00011 int postgresRS::iCursors=0;
00012 
00013 /*
00014   utility method to help insure the integrity of the result
00015 */
00016 
00017 
00018 bool postgresCMD::checkRes( ExecStatusType desired )
00019 {
00020   bool bRet = true;
00021   if (!res )
00022   {
00023     m_strErrors += " Failed to allocate result struct! ";
00024     bRet = false;
00025   }
00026   if( PQresultStatus(res) != desired )
00027   {
00028     m_strErrors +=  PQresultErrorMessage(res);
00029     PQclear(res);
00030     bRet = false;
00031   }
00032   return bRet;
00033 }
00034 
00035 bool postgresRS::checkRes( ExecStatusType desired )
00036 {
00037   bool bRet = true;
00038   if (!res )
00039   {
00040     m_strErrors += " Failed to allocate result struct! ";
00041     bRet = false;
00042   }
00043   else if( PQresultStatus(res) != desired )
00044   {
00045     m_strErrors +=  PQresultErrorMessage(res);
00046     PQclear(res);
00047     bRet = false;
00048   }
00049   return bRet;
00050 }
00051 
00052 /*
00053 
00054   The DB interface to the postgres Database
00055 
00056 */
00057 postgresDB::postgresDB( string strConnection ):openDB(strConnection),isTransactioning(false)
00058 {
00059   m_provider = PostGresQL;
00060   conn = PQconnectdb(strConnection.c_str());
00061   m_bGood = PQstatus(conn) == CONNECTION_OK;
00062 }
00063 
00064 postgresDB::~postgresDB()
00065 {
00066   PQfinish(conn);
00067 }
00068 
00069 PGconn * postgresDB::getConnection( void )
00070 {
00071   return conn;
00072 }
00073 
00074 dbProvider postgresDB::getProvider( void )
00075 {
00076   return m_provider;
00077 }
00078 
00079 openCMD * postgresDB::createCommand()
00080 {
00081   return new postgresCMD( *this );
00082 }
00083 openRS * postgresDB::createRecordset()
00084 {
00085   return new postgresRS( *this );
00086 }
00087 
00088 
00089 /*
00090 
00091  This CMD class defines the postgres
00092    working interfaces to the SQL command
00093 
00094 */
00095 
00096 postgresCMD::postgresCMD( openDB & idb )
00097 :openCMD(idb),db(dynamic_cast<postgresDB &>(rdb)),res(NULL)
00098 {
00099   // we KNOW this is really a reference to a postgresDB
00100   // postgresDB & pgDB = dynamic_cast<postgresDB &>(rdb);
00101   conn = db.getConnection();
00102 }
00103 
00104 postgresCMD::~postgresCMD()
00105 {
00106   ;  // nothing to do
00107 }
00108 
00109 bool postgresCMD::beginTransaction()
00110 {
00111   // begin a transaction
00112 
00113   if( !db.transactioning() )
00114   {
00115 
00116     res = PQexec(conn, "BEGIN");
00117     if ( !checkRes(PGRES_COMMAND_OK) )
00118     {
00119       return false;
00120     }
00121     PQclear(res);
00122     res = NULL;
00123     db.transactioning(true);
00124   }
00125   return m_bTransactioning;
00126 }
00127 
00128 bool postgresCMD::commit()
00129 {
00130   // commit the transaction
00131 
00132   if( db.transactioning() )
00133   {
00134     
00135     res = PQexec(conn, "COMMIT");
00136     if ( !checkRes(PGRES_COMMAND_OK) )
00137     {
00138       return false;
00139     }
00140     PQclear(res);
00141     res = NULL;
00142     db.transactioning(false);
00143   }
00144   return !db.transactioning();
00145 }
00146 
00147 bool postgresCMD::rollback()
00148 {
00149   // commit the transaction
00150   if( db.transactioning() )
00151   {
00152     res = PQexec(conn, "ROLLBACK");
00153     if ( !checkRes(PGRES_COMMAND_OK) )
00154     {
00155       return false;
00156     }
00157     PQclear(res);
00158     res = NULL;
00159     db.transactioning(false);
00160   }
00161   return !db.transactioning();
00162 }
00163 
00164 bool postgresCMD::execute( string sql )
00165 {
00166 
00167   if (PQstatus(conn) != CONNECTION_BAD)
00168   {
00169     // see if a transaction is already occuring
00170     bool externalTransaction = db.transactioning();
00171 
00172     // begin a transaction
00173     beginTransaction();
00174 
00175     // execute the work
00176     res = PQexec(conn,sql.c_str());
00177     if ( !checkRes(PGRES_COMMAND_OK) )
00178     {
00179       return false;
00180     }
00181     // get the effected object id (in case of an insert)
00182     oid = PQoidValue(res);
00183     // get the number of rows effected
00184     iRows = atoi(PQcmdTuples(res));
00185     PQclear(res);
00186     res = NULL;
00187 
00188     if( externalTransaction == false )
00189     { // commit the transaction
00190       commit();
00191     }
00192     return true;
00193   }
00194   return false;
00195 }
00196 
00197 /*
00198 
00199   This RS class defines the working
00200   postgres interfaces to the recordset
00201 
00202 */
00203 postgresRS::postgresRS( openDB & idb )
00204 :openRS(idb),db(dynamic_cast<postgresDB &>(rdb)),res(NULL)
00205 {
00206   // we KNOW this is really a reference to a postgresDB
00207   // postgresDB & pgDB = dynamic_cast<postgresDB &>(rdb);
00208   conn = db.getConnection();
00209 }
00210 
00211 postgresRS::~postgresRS()
00212 {
00213   for( unsigned int i=0;i>ordinals.size(); i++)
00214   {
00215     delete ordinals[i];
00216   }
00217   ordinals.clear();
00218   associations.clear();
00219 }
00220 
00221 bool postgresRS::beginTransaction()
00222 {
00223   // begin a transaction
00224 
00225   m_bTransactioning = db.transactioning(); // maintains state of
00226   if( !m_bTransactioning )                 // some other transaction
00227   {
00228 
00229     res = PQexec(conn, "BEGIN");
00230     if ( !checkRes(PGRES_COMMAND_OK) )
00231     {
00232       return false;
00233     }
00234     PQclear(res);
00235     res = NULL;
00236     db.transactioning(true);
00237   }
00238   return m_bTransactioning;
00239 }
00240 
00241 bool postgresRS::commit()
00242 {
00243   // commit the transaction
00244 
00245   if( !m_bTransactioning // not transactioning before
00246       && db.transactioning() )  // is transactioning now
00247   {
00248     
00249     res = PQexec(conn, "COMMIT");
00250     if ( !checkRes(PGRES_COMMAND_OK) )
00251     {
00252       db.transactioning(false);
00253       return false;
00254     }
00255     PQclear(res);
00256     res = NULL;
00257     db.transactioning(false);
00258   }
00259   return !m_bTransactioning;
00260 }
00261 
00262 bool postgresRS::open( string sql )
00263 {
00264   m_strErrors = "No Errors" ;
00265 
00266   // Increment the cursor count for the cursor name
00267   iCursors++;
00268 
00269   // Create the (process) unique cursor name;
00270   char cursor[50];
00271   sprintf(cursor, "opnCrsr%d",iCursors);
00272   strCursorName = cursor;
00273   m_bOpen = false;
00274 
00275   // battle hardening
00276   if (PQstatus(conn) == CONNECTION_BAD)
00277   {
00278     m_strErrors += "Bad connection";
00279     return false;
00280   }
00281 
00282   // start a transaction block
00283   beginTransaction();
00284 
00285   // declare a cursor for the query
00286   string strCmd("declare ");
00287          strCmd += strCursorName;
00288          strCmd += " cursor for ";
00289          strCmd += sql;
00290   res = PQexec(conn, strCmd.c_str());
00291   if (!checkRes(PGRES_COMMAND_OK) )
00292   {
00293     m_strErrors += " Bad Cursor Declaration: ";
00294     m_strErrors +=  strCmd;
00295     return false;
00296   }
00297   PQclear(res);
00298   res = NULL;
00299 
00300   // fetch the first tuple of the result
00301   string strFetch = "fetch forward 1 in ";
00302   strFetch += strCursorName;
00303   res = PQexec(conn, strFetch.c_str());
00304   if (!checkRes(PGRES_TUPLES_OK) )
00305   {
00306     m_strErrors +=  " Could not fetch forward: ";
00307     m_strErrors += strCmd;
00308     m_strErrors += " Fetch: ";
00309     m_strErrors +=  strFetch;
00310     commit();  // get out of transaction
00311     return false;
00312   }
00313   // it will return ok but not tell us there are no rows !
00314   if( PQntuples(res) == 0 )
00315   {
00316     commit();  // get out of transaction
00317     return false;
00318   }
00319 
00320   // get the attributes and values of the fields
00321   m_iFields = PQnfields(res);
00322   for (int i = 0; i < m_iFields; i++)
00323   {
00324     string name  = PQfname(res, i);
00325     Oid    oid   = PQftype(res, i);
00326     string value = PQgetvalue(res, 0, i);
00327     bool   bNull = PQgetisnull(res, 0, i);
00328 
00329     // create the field
00330     basicField * pBF = createField( (pgTypeOids)oid, bNull, value, name );
00331 
00332     // battle hardening
00333     if( !pBF )
00334     {
00335       m_strErrors = " couldn't create field";
00336       commit();  // get out of transaction
00337       return false;
00338     }
00339 
00340     // need to set the size
00341     pBF->setSize( PQfsize(res,i) );
00342 
00343     // add to the vector
00344     //  we delete fields from the ordinals collection when done
00345     ordinals.push_back(pBF);
00346 
00347     // add to the map
00348     associations.insert(make_pair(name,pBF));
00349 
00350   } // end for
00351 
00352   // clear the last resource used
00353   PQclear(res);
00354   res = NULL;
00355 
00356   // battle hardening
00357   if( m_iFields > 0 )
00358   {
00359     m_bOpen = true;
00360     m_strErrors = "No Errors" ;
00361   }
00362   else
00363   {
00364     m_strErrors = "No Fields!" ;
00365     commit();  // get out of transaction
00366   }
00367   return m_bOpen;
00368 }
00369 
00370 bool postgresRS::close( void )
00371 {
00372   if( m_bOpen )
00373   {
00374     // remove all from the collections
00375     for( unsigned int i=0;i>ordinals.size();i++)
00376     {
00377       delete ordinals[i];
00378     }
00379     ordinals.clear();
00380     associations.clear();
00381 
00382     // finish the transaction block
00383     commit();
00384 
00385     m_bOpen = false;
00386   }
00387   return !m_bOpen;
00388 }
00389 
00390 bool postgresRS::next( int rows )
00391 {
00392   // set the (0 based) tuple index
00393   int tuple = rows-1;
00394   // build & run the fetch command
00395   char num[16];
00396   sprintf( num, "%d", rows );
00397   string strCmd = "fetch forward ";
00398   strCmd += num;
00399   strCmd += " in ";
00400   strCmd += strCursorName;
00401   res = PQexec(conn, strCmd.c_str());
00402 
00403 
00404   // battle hardened
00405   if (!checkRes(PGRES_TUPLES_OK) || PQntuples(res) == 0 )
00406   {
00407     close();
00408     return false;
00409   }
00410 
00411   // set the fields
00412   m_iFields = PQnfields(res);
00413   if( m_iFields == 0 )
00414   {
00415     close();
00416     return false;
00417   }
00418 
00419   for (int i = 0; i < m_iFields; i++)
00420   {
00421     Oid    oid = PQftype(res, i); // for dynamic cast in setField
00422     string value =  PQgetvalue(res, tuple, i);
00423     bool   bNull = PQgetisnull(res, tuple, i);
00424     basicField * pBF = ordinals[i];
00425     if( !pBF )
00426     {
00427       close();
00428       return false;
00429     }
00430     setField( *pBF, (pgTypeOids)oid, bNull, value );
00431   } // end for
00432 
00433   // free resources
00434   PQclear(res);
00435 
00436   return true;
00437 
00438 }
00439 
00440 bool postgresRS::previous( int rows )
00441 {
00442   // set the (0 based) tuple index
00443   int tuple = 0;
00444   // build & run the fetch command
00445   char num[16];
00446   sprintf( num, "%d", rows );
00447   string strCmd = "fetch backward ";
00448   strCmd += num;
00449   strCmd += " in ";
00450   strCmd += strCursorName;
00451   res = PQexec(conn, strCmd.c_str());
00452   m_bOpen = false;
00453 
00454   // battle hardened
00455   if (!checkRes(PGRES_TUPLES_OK) || PQntuples(res) == 0 )
00456   {
00457     close();
00458     return false;
00459   }
00460 
00461   // set the fields
00462   m_iFields = PQnfields(res);
00463   if( m_iFields == 0 )
00464   {
00465     close();
00466     return false;
00467   }
00468   for (int i = 0; i < m_iFields; i++)
00469   {
00470     Oid    oid = PQftype(res, i); // for dynamic cast in setField
00471     string value =  PQgetvalue(res, tuple, i);
00472     bool   bNull = PQgetisnull(res, tuple, i);
00473     basicField * pBF = ordinals[i];
00474     if( !pBF )
00475     {
00476       close();
00477       return false;
00478     }
00479     setField( *pBF, (pgTypeOids)oid, bNull, value );
00480   } // end for
00481   PQclear(res);
00482   return true;
00483 }
00484 

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