src/QOpenOCCIResult.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002 **
00003 ** Copyright (C) 2008 Andrew White. All rights reserved.
00004 **
00005 ** This file is part of the QOpenOCCI library.
00006 **
00007 ** This file may be used under the terms of the GNU General Public
00008 ** License version 2.0 as published by the Free Software Foundation
00009 ** and appearing in the file LICENSE.GPL included in the 
00010 ** packaging of this file.
00011 **
00012 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00013 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00014 **
00015 ****************************************************************************/
00016 
00017 #include "QOpenOCCI.h"
00018 #include <QString>
00019 
00020 const char* QOpenOCCIResult::EXEC_FAILED             = "QOpenOCCI: Execute Failed";
00021 const char* QOpenOCCIResult::BIND_FAILED             = "QOpenOCCI: Bind Failed";
00022 
00023 template<class C>
00024 QOpenOCCIBindElementI<C>::QOpenOCCIBindElementI(C* data) : mData(data) {};
00025     
00026 template<class C>
00027 QOpenOCCIBindElementI<C>::~QOpenOCCIBindElementI() {};
00028 
00029 template<class C>
00030 void QOpenOCCIBindElementI<C>::free() { delete mData; };
00031 
00032 template<>
00033 void QOpenOCCIBindElementI<OCI_Date>::free() { OCI_DateFree(mData); };
00034 
00035 template<>
00036 void QOpenOCCIBindElementI<OCI_Lob>::free() { OCI_LobFree(mData); };
00037 
00038 template<class C>
00039 void* QOpenOCCIBindElementI<C>::ptrValue() { return (void*) mData; };
00040     
00041 template<class C>
00042 QVariant QOpenOCCIBindElementI<C>::toQVariant() const { return QVariant(*mData); };
00043 
00044 template<>
00045 QVariant QOpenOCCIBindElementI<OCI_Date>::toQVariant() const 
00046 { 
00047     int year, month, day, hour, min, sec;
00048     OCI_DateGetDate(mData, &year, &month, &day);
00049     OCI_DateGetTime(mData, &hour, &min, &sec);
00050 
00051     return QVariant(QDateTime(QDate(year, month, day), QTime(hour, min, sec))); 
00052 } 
00053 
00054 template<>
00055 QVariant QOpenOCCIBindElementI<OCI_Lob>::toQVariant() const 
00056 { 
00057     QByteArray ret;
00058     ret.resize(OCI_LobGetLength(mData));
00059     OCI_LobRead(mData, ret.data(), ret.length());
00060     return QVariant(ret); 
00061 } 
00062 
00063 template<>
00064 QVariant QOpenOCCIBindElementI<char>::toQVariant() const 
00065 { 
00066     return QVariant(QString(mData)); 
00067 }
00068 
00069     
00070 
00071 QOpenOCCIMetadata::QOpenOCCIMetadata(OCI_Resultset* resultSet)
00072 {
00073     for (int i = 1; i <= OCI_GetColumnCount(resultSet); i++) {
00074         OCI_Column* col = OCI_GetColumn(resultSet, i);
00075         
00076         ColumnMetadata cmd;
00077         cmd.name = OCI_GetColumnName(col);
00078         cmd.type = OCI_GetColumnSQLType(col);
00079         cmd.typeCode = OCI_GetColumnType(col);
00080         cmd.size = OCI_GetColumnSize(col);
00081         cmd.precision = OCI_GetColumnPrecision(col);
00082         cmd.scale = OCI_GetColumnScale(col);
00083         cmd.nullable = OCI_GetColumnNullable(col);
00084         
00085         mColMetadata.append(cmd);
00086     }
00087 }
00088 
00089 QOpenOCCIResult::QOpenOCCIResult(
00090     const QSqlDriver* d, OCI_Connection* c,  
00091     unsigned int prefetch_memory, unsigned int prefetch_rows) : 
00092     
00093     QSqlResult( d ),
00094     mConnection( c ),
00095     mStatement( OCI_CreateStatement(c) ),
00096     mResultSet( NULL )
00097 {
00098     OCI_SetPrefetchSize(mStatement, prefetch_rows);
00099     OCI_SetPrefetchMemory(mStatement, prefetch_memory);
00100 }
00101 
00102 QOpenOCCIResult::~QOpenOCCIResult()
00103 {
00104     try {
00105         cleanup();
00106         if (mConnection && mStatement) 
00107             OCI_FreeStatement(mStatement);
00108     }
00109     catch(...) {
00110     }
00111     
00112 }
00113 
00114 void QOpenOCCIResult::rebind(int bound_index, const QVariant& val, QSql::ParamType btype)
00115 {
00116     if (mBindNameIndex.size()) 
00117         QSqlResult::bindValue(boundValueName(bound_index),val, btype);
00118     else 
00119         QSqlResult::bindValue(bound_index, val, btype);
00120 }
00121 
00122 void QOpenOCCIResult::updateBoundResults()
00123 {
00124     for (int i = 0; i < boundValueCount(); i++) {
00125         if (bindValueType(i) == QSql::In || bindValueType(i) == QSql::InOut) {
00126             QString key;
00127             if (bindingSyntax() == QSqlResult::PositionalBinding) {      
00128                 key = QString(':').append(QString::number(i+1));
00129                 bindValue(i, mBindData[key]->toQVariant(), bindValueType(i));
00130             }
00131             else { 
00132                 key = boundValueName(i);
00133                 bindValue(key, mBindData[key]->toQVariant(), bindValueType(i));
00134             }
00135         }
00136     }
00137 }
00138 
00139 bool QOpenOCCIResult::exec()
00140 {
00141     try {
00142         setSelect(FALSE);
00143         setActive(FALSE);
00144         
00145         if (boundValueCount()) {
00146             if (bindingSyntax() == QSqlResult::PositionalBinding)
00147                 OCI_SetBindMode(mStatement, OCI_BIND_BY_POS);
00148             else 
00149                 OCI_SetBindMode(mStatement, OCI_BIND_BY_NAME);
00150         }
00151         
00152         for (int i = 0; i < boundValueCount(); i++) {
00153             if (boundValueCount() && bindingSyntax() == QSqlResult::PositionalBinding)
00154                 bind(QString(':').append(QString::number(i+1)), boundValue(i), bindValueType(i));
00155             else {
00156                 QString key = boundValueName(i);
00157                 bind(key, boundValue(key), bindValueType(key));
00158             }
00159         }
00160         
00161         OCI_Execute(mStatement);
00162  
00163         updateBoundResults();
00164         
00165         switch( OCI_GetStatementType(mStatement) ) 
00166         {
00167             case OCI_CST_SELECT: 
00168             case OCI_CST_BEGIN:
00169             case OCI_CST_DECLARE:
00170                 mResultSet = OCI_GetResultset(mStatement);
00171                 mResultMetadata = QOpenOCCIMetadata(mResultSet);
00172                 setSelect(TRUE);
00173                 setActive(TRUE);
00174                 return TRUE;
00175             case OCI_CST_UPDATE: 
00176             case OCI_CST_DELETE: 
00177             case OCI_CST_INSERT:
00178                 setSelect(FALSE);
00179                 setActive(FALSE);            
00180                 return TRUE;
00181             case OCI_CST_DROP:    
00182             case OCI_CST_CREATE:  
00183             case OCI_CST_ALTER:
00184                 setSelect(FALSE);
00185                 setActive(FALSE);            
00186                 return TRUE;
00187             default:
00188                 throw QOPEN_OCCI_EXCEPTION("Statement failed");
00189         }
00190     }
00191     catch (exception& e) {
00192         setLastError(QSqlError(EXEC_FAILED, e.what(), QSqlError::StatementError));
00193         return FALSE;
00194     }
00195     return FALSE;
00196 }
00197 
00198 bool QOpenOCCIResult::reset ( const QString& query )
00199 {
00200     OCI_Prepare(mStatement, (char*) query.toStdString().c_str());
00201     
00202     cleanup();
00203    
00204     return exec();
00205 }
00206 
00207 int QOpenOCCIResult::numRowsAffected()
00208 {
00209     if (isActive() == TRUE || isSelect() == FALSE) return -1;
00210     return OCI_GetAffectedRows(mStatement);
00211 }
00212 
00213 void QOpenOCCIResult::setQuery ( const QString & query )
00214 {
00215     OCI_Prepare(mStatement, (char*) query.toStdString().c_str());
00216     cleanup();
00217 }
00218 
00219 void QOpenOCCIResult::cleanup() 
00220 {
00221      mResultSet = NULL; //freed by the setSQL statment
00222      mCache.clear();
00223      mBindNameIndex.clear();
00224      boundValues().clear();
00225      QSqlResult::clear();
00226      mBindData.cleanup();
00227 }
00228 
00229 bool QOpenOCCIResult::prepare ( const QString& query )
00230 {
00231     cleanup();
00232     return OCI_Prepare(mStatement, (char*) query.toStdString().c_str());
00233 }
00234 
00235 bool QOpenOCCIResult::savePrepare ( const QString & query )
00236 {
00237     return prepare(query);
00238 }
00239 
00240 
00241 void QOpenOCCIResult::bind(QString name, const QVariant& val, QSql::ParamType paramType )
00242 {
00243     QOpenOCCIBindElement* bindElement;
00244         
00245     try {
00246         switch(val.type()) {
00247             case QVariant::Char:
00248             case QVariant::LongLong:
00249             case QVariant::String:
00250             case QVariant::ULongLong:
00251             case QVariant::UInt:
00252                 if (paramType == QSql::Out)
00253                     OCI_RegisterString(mStatement, name.toAscii().data(), 4000);
00254                 if (paramType == QSql::In || paramType == QSql::InOut) {
00255                     bindElement = new QOpenOCCIBindElementI<char>( 
00256                                       QOpenOCCIBindElement::QStringToChar(val.toString()) ); 
00257                     mBindData.add(name, bindElement);
00258                     OCI_BindString( mStatement, name.toAscii().data(), 
00259                                     static_cast<char*>(bindElement->ptrValue()), 
00260                                     (val.isNull()) ? 4000 : val.toString().size() );
00261                 }
00262                 break;
00263             case QVariant::Date:
00264                 if (paramType == QSql::Out)
00265                     OCI_RegisterDate(mStatement, name.toAscii().data());
00266                 if (paramType == QSql::In || paramType == QSql::InOut) {
00267                     bindElement = new QOpenOCCIBindElementI<OCI_Date>( 
00268                                       QOpenOCCIBindElement::QDateToOCIDate(mConnection, 
00269                                                                            val.toDate()) ); 
00270                     mBindData.add(name, bindElement);
00271                     OCI_BindDate( mStatement, name.toAscii().data(), 
00272                                     static_cast<OCI_Date*>(bindElement->ptrValue()) );
00273                 }
00274                 break;
00275             case QVariant::DateTime:
00276                 if (paramType == QSql::Out)
00277                     OCI_RegisterDate(mStatement, name.toAscii().data());
00278                 if (paramType == QSql::In || paramType == QSql::InOut) {
00279                     bindElement = new QOpenOCCIBindElementI<OCI_Date>( 
00280                                       QOpenOCCIBindElement::QDateToOCIDateTime(mConnection, 
00281                                                                                val.toDateTime()) ); 
00282                     mBindData.add(name, bindElement);
00283                     OCI_BindDate( mStatement, name.toAscii().data(), 
00284                                     static_cast<OCI_Date*>(bindElement->ptrValue()) );
00285                 }
00286                 break;
00287             case QVariant::Time:
00288                 if (paramType == QSql::Out)
00289                     OCI_RegisterDate(mStatement, name.toAscii().data());
00290                 if (paramType == QSql::In || paramType == QSql::InOut) {
00291                     bindElement = new QOpenOCCIBindElementI<OCI_Date>( 
00292                                       QOpenOCCIBindElement::QDateToOCITime(mConnection, 
00293                                                                            val.toTime()) ); 
00294                     mBindData.add(name, bindElement);
00295                     OCI_BindDate( mStatement, name.toAscii().data(), 
00296                                     static_cast<OCI_Date*>(bindElement->ptrValue()) );
00297                 }
00298                 break;        
00299             case QVariant::Double:
00300                 if (paramType == QSql::Out)
00301                     OCI_RegisterInt(mStatement, name.toAscii().data());
00302                 if (paramType == QSql::In || paramType == QSql::InOut) {
00303                     bindElement = new QOpenOCCIBindElementI<double>( new double(val.toDouble()) ); 
00304                     
00305                     mBindData.add(name, bindElement);
00306                     OCI_BindDouble(mStatement, name.toAscii().data(), 
00307                                    static_cast<double*>(bindElement->ptrValue()));
00308                 }
00309                 break;
00310             case QVariant::Int:
00311                 if (paramType == QSql::Out)
00312                     OCI_RegisterInt(mStatement, name.toAscii().data());
00313                 if (paramType == QSql::In || paramType == QSql::InOut) {
00314                     bindElement = new QOpenOCCIBindElementI<int>( new int(val.toInt()) ); 
00315                     
00316                     mBindData.add(name, bindElement);
00317                     OCI_BindInt(mStatement, name.toAscii().data(), 
00318                                 static_cast<int*>(bindElement->ptrValue()));
00319                 }
00320                 break;
00321             case QVariant::ByteArray:
00322                 if (paramType == QSql::Out)
00323                     OCI_RegisterLob(mStatement, name.toAscii().data(), OCI_BLOB);
00324                 if (paramType == QSql::In || paramType == QSql::InOut) {
00325                     bindElement = new QOpenOCCIBindElementI<OCI_Lob>( 
00326                                       QOpenOCCIBindElement::QByteArrayToBLOB( mConnection,
00327                                                                               val.toByteArray() ));
00328                     mBindData.add(name, bindElement);
00329                     OCI_BindLob(mStatement, name.toAscii().data(), 
00330                                 static_cast<OCI_Lob*>(bindElement->ptrValue()));
00331                 }
00332                 break;
00333             default:
00334                 throw QOPEN_OCCI_EXCEPTION("Can not handle this variable type yet!");
00335         }
00336     }
00337     catch (exception& e) {
00338         setLastError(QSqlError(BIND_FAILED, e.what(), QSqlError::StatementError));
00339     }
00340 }
00341 
00342 bool QOpenOCCIResult::fetch( int row_id )
00343 {
00344     if (at() == row_id) return true;
00345     
00346     //Optimize this (tie in cache if possible)!!
00347     if (isForwardOnly()) {
00348         if (at() < row_id) {
00349             // fake a forward seek
00350             for (int x = row_id - at() - 1; x && fetchNext(); x--);
00351             return fetchNext();
00352         } 
00353         else return false;
00354     }
00355     
00356     if (at() < row_id) {
00357         // fake a forward seek
00358         for (int x = row_id - at() - 1; x && fetchNext(); x--);
00359         return fetchNext();    
00360     }
00361     if (at() > row_id) {
00362         // fake a forward seek
00363         for (int x = at() - row_id - 1; x && fetchPrevious(); x--);
00364         return fetchPrevious();     
00365     }
00366     
00367     return FALSE;
00368 }
00369 
00370 QSqlRecord QOpenOCCIResult::record() const
00371 { 
00372     QSqlRecord ret;
00373     const QVector<QOpenOCCIMetadata::ColumnMetadata>& colMD = mResultMetadata.mColMetadata;
00374     
00375     for (int c = 0; c < colMD.size(); c++) {
00376         QVariant::Type datatype = ocilib_to_qvariant_type(colMD[c].typeCode);
00377         QString        name       (colMD[c].name);
00378         QSqlField      field      (name, datatype);
00379         
00380         field.setLength(colMD[c].size);
00381         field.setPrecision(colMD[c].precision);
00382         
00383         ret.append(field);
00384     }
00385     return ret;
00386 }
00387 
00388 bool QOpenOCCIResult::fetchFirst() 
00389 {
00390     if (at() == 0) return true;
00391 
00392     if (isForwardOnly())
00393         return (at() == QSql::BeforeFirstRow) ? fetchNext() : false;
00394     return fetch(0);
00395 }
00396 
00397 bool QOpenOCCIResult::fetchNext()
00398 {
00399     if (mCache.isRowCached(at()+1)) {
00400         setAt(at()+1);
00401         return TRUE;
00402     }
00403     
00404     if (!OCI_FetchNext(mResultSet)) return FALSE;
00405     
00406     addRowToCache();
00407     setAt(at()+1);
00408     return TRUE;
00409 }
00410 
00411 bool QOpenOCCIResult::fetchPrevious() {
00412     if (at() == 0 || at() == QSql::BeforeFirstRow) return false;
00413     
00414     if (at() == QSql::AfterLastRow) {
00415         setAt(mCache.size() - 1);
00416         return TRUE;
00417     }
00418     
00419     setAt(at()-1);
00420     return TRUE;    
00421 }
00422 
00423 bool QOpenOCCIResult::fetchLast() {
00424     if (mCache.size() == 0) return FALSE;
00425     
00426     setAt(mCache.size() - 1);
00427     return TRUE; 
00428 }
00429 
00430 bool QOpenOCCIResult::isNull(int column_id) 
00431 {
00432     return (isForwardOnly()) ? mCache.getLastRow()[column_id].isNull()
00433                              : mCache.getRow(at())[column_id].isNull();
00434 }
00435 
00436 void QOpenOCCIResult::addRowToCache()
00437 {
00438     if (isForwardOnly()) mCache.clear();
00439     
00440     QVector<QVariant>& row = mCache.addRow();
00441 
00442     QVector<QOpenOCCIMetadata::ColumnMetadata>& colMD = mResultMetadata.mColMetadata;
00443 
00444     //String vars
00445     string strData;
00446     
00447     //Date/timestamp vars
00448     int year = 0, mon = 0, day = 0, hour = 0, min = 0, sec = 0, fs = 0;
00449   
00450     //Lob vars
00451     OCI_Lob*       lobPtr  = NULL;
00452     OCI_Date*      datePtr = NULL;
00453     OCI_Timestamp* tsPtr   = NULL;
00454     
00455     QByteArray lobData;
00456         
00457     for (int c = 1; c <= colMD.size(); c++) {
00458         
00459         int typeCode = colMD[c-1].typeCode;
00460         
00461         if (OCI_IsNull(mResultSet, c)) {
00462             row.append(ocilib_to_qvariant_type(typeCode));
00463             continue;
00464         }
00465         
00466         switch (typeCode)
00467         {
00468             case OCI_CDT_TEXT:
00469                 row.append(QString(OCI_GetString(mResultSet, c)));
00470                 break;
00471             case OCI_CDT_INTEGER:
00472                 row.append(OCI_GetInt(mResultSet, c)); 
00473                 break;
00474             case OCI_CDT_DOUBLE:
00475                 row.append(OCI_GetDouble(mResultSet, c)); 
00476                 break;                
00477             case OCI_CDT_LOB:
00478                 lobPtr = OCI_GetLob(mResultSet, c);
00479                 lobData.resize(OCI_LobGetLength(lobPtr));
00480                 OCI_LobRead(lobPtr, lobData.data(), lobData.size());
00481                 row.append(lobData); 
00482                 break;
00483             case OCI_CDT_DATETIME:
00484                 datePtr = OCI_GetDate(mResultSet, c);
00485                 OCI_DateGetDate(datePtr, &year, &mon, &day);
00486                 OCI_DateGetTime(datePtr, &hour, &min, &sec);
00487                 row.append(QDateTime(QDate(year, mon, day), QTime(hour, min, sec)));
00488                 break;
00489             case OCI_CDT_TIMESTAMP:
00490                 tsPtr = OCI_GetTimestamp(mResultSet, c);
00491                 OCI_TimestampGetDate(tsPtr, &year, &mon, &day);
00492                 OCI_TimestampGetTime(tsPtr, &hour, &min, &sec, &fs);
00493                 row.append(QDateTime(QDate(year, mon, day), QTime(hour, min, sec, fs)));
00494                 break;
00495             default:
00496                 row.append( QString(OCI_GetString(mResultSet, c)) );
00497         }
00498     }
00499 }
00500 
00501 QVariant QOpenOCCIResult::data(int column_id)
00502 {
00503     if (column_id  >= mResultMetadata.mColMetadata.size() ||
00504         isActive() == FALSE) {
00505 
00506         return QVariant();
00507     }
00508     
00509     return (isForwardOnly()) ? mCache.getLastRow()[column_id]
00510                              : mCache.getRow(at())[column_id];
00511 }
00512 
00513 QVariant::Type QOpenOCCIResult::ocilib_to_qvariant_type(int ocilib_type)
00514 {
00515     
00516     switch (ocilib_type)
00517     {
00518         case OCI_CDT_TEXT:
00519             return QVariant::String;
00520         case OCI_CDT_INTEGER:
00521             return QVariant::Int;
00522         case OCI_CDT_DOUBLE:
00523             return QVariant::Double;
00524         case OCI_CDT_DATETIME:
00525         case OCI_CDT_TIMESTAMP:
00526             return QVariant::DateTime;
00527         case OCI_CDT_LOB:
00528             return QVariant::ByteArray;
00529         default: 
00530             return QVariant::Invalid;
00531     }    
00532 }

Generated on Tue Mar 18 22:47:08 2008 for QOpenOCCI by  doxygen 1.5.3