00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
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;
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
00347 if (isForwardOnly()) {
00348 if (at() < row_id) {
00349
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
00358 for (int x = row_id - at() - 1; x && fetchNext(); x--);
00359 return fetchNext();
00360 }
00361 if (at() > row_id) {
00362
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
00445 string strData;
00446
00447
00448 int year = 0, mon = 0, day = 0, hour = 0, min = 0, sec = 0, fs = 0;
00449
00450
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 }