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