00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #ifndef QOPENOCCI_H
00019 #define QOPENOCCI_H
00020
00021 #include <QtSql/QtSql>
00022
00023 #include <iostream>
00024 #include <memory>
00025 #include "ocilib/ocilib.h"
00026
00031 using namespace std;
00032
00033
00034 #define DEFAULT_MEMORY_PREFETCH 1048576
00035 #define DEFAULT_ROWS_PREFETCH 100
00036
00037 class QOpenOCCIResult;
00038 class QOpenOCCIDriver;
00039
00040 #define QOPEN_OCCI_EXCEPTION(str) (QOpenOCCIException("Error %s[%d]: %s", __FILE__, __LINE__, str))
00041 #define MAX_ERROR_LEN 1024
00042
00043 class QOpenOCCIException : public std::exception {
00044 public:
00045 QOpenOCCIException(char * format, ...) : std::exception() {
00046 va_list args;
00047 va_start(args, format);
00048 vsnprintf(error_msg, MAX_ERROR_LEN, format, args);
00049 va_end(args);
00050 }
00051
00052 virtual const char * what() const throw() {return error_msg;}
00053 virtual ~QOpenOCCIException() throw() {};
00054 private:
00055 char error_msg[MAX_ERROR_LEN];
00056 };
00057
00058
00059 class QOpenOCCICache
00060 {
00061 public:
00062 QOpenOCCICache(){};
00063
00064 bool isRowCached(int row_id) { return row_id < mCache.size(); }
00065 void clear() { mCache.clear(); }
00066
00067 unsigned int size() { return mCache.size(); }
00068
00069 QVector<QVariant>& getLastRow() { return mCache.back(); }
00070 QVector<QVariant>& getRow(unsigned int row_id) { return mCache[row_id]; }
00071 QVector<QVariant>& addRow() {
00072 mCache.append(QVector<QVariant>());
00073 return mCache.back();
00074 }
00075
00076 private:
00077 QVector< QVector< QVariant > > mCache;
00078 };
00079
00080 class QOpenOCCIBindElement {
00081 public:
00082 virtual void free() = 0;
00083 virtual void* ptrValue() = 0;
00084 virtual QVariant toQVariant() const = 0;
00085 virtual ~QOpenOCCIBindElement() {};
00086
00087 static char* QStringToChar(const QString& str) {
00088 int size = (str.isNull()) ? 4000
00089 : str.size()+1;
00090 char * ret = new char[size];
00091 memcpy(ret, str.toAscii().constData(), str.size()+1);
00092 return ret;
00093 }
00094 static OCI_Date* QDateToOCIDate( OCI_Connection* c, const QDate& date ){
00095 OCI_Date* ret = OCI_DateCreate(c);
00096 OCI_DateSetDate(ret, date.year(), date.month(), date.day());
00097 return ret;
00098 }
00099
00100 static OCI_Date* QDateToOCIDateTime( OCI_Connection* c, const QDateTime& date ){
00101 OCI_Date* ret = OCI_DateCreate(c);
00102 OCI_DateSetDate(ret, date.date().year(), date.date().month(), date.date().day());
00103 OCI_DateSetTime(ret, date.time().hour(), date.time().minute(), date.time().second());
00104 return ret;
00105 }
00106
00107 static OCI_Date* QDateToOCITime( OCI_Connection* c, const QTime& time ){
00108 OCI_Date* ret = OCI_DateCreate(c);
00109 OCI_DateSetTime(ret, time.hour(), time.minute(), time.second());
00110 return ret;
00111 }
00112
00113 static OCI_Lob* QByteArrayToBLOB( OCI_Connection* c, const QByteArray& buf ) {
00114 OCI_Lob* ret = OCI_LobCreate(c, OCI_BLOB);
00115 OCI_LobWrite(ret, (void*)buf.data(), buf.size());
00116 return ret;
00117 }
00118 };
00119
00120 template <class C>
00121 class QOpenOCCIBindElementI : public QOpenOCCIBindElement{
00122 public:
00123 QOpenOCCIBindElementI(C* data);
00124 ~QOpenOCCIBindElementI();
00125
00126 void free();
00127 void* ptrValue();
00128 QVariant toQVariant() const;
00129
00130 private:
00131 C* mData;
00132 };
00133
00134 class QOpenOCCIBindData {
00135 public:
00136 void add(const QString& key, QOpenOCCIBindElement* val) {
00137 if (mMap.contains(key)) mMap[key]->free();
00138 mMap[key] = val;
00139 }
00140
00141 void cleanup() {
00142 QMapIterator<QString, QOpenOCCIBindElement*> i(mMap);
00143 while (i.hasNext()) {
00144 i.next();
00145 i.value()->free();
00146 delete i.value();
00147 }
00148 mMap.clear();
00149 }
00150
00151 QOpenOCCIBindElement* operator[](const QString& key) { return mMap[key]; }
00152 private:
00153 QMap<QString, QOpenOCCIBindElement*> mMap;
00154 };
00155
00156
00157
00158 class QOpenOCCIMetadata {
00159 public:
00160 QOpenOCCIMetadata(){};
00161 QOpenOCCIMetadata(OCI_Resultset* resultSet);
00162
00163 struct ColumnMetadata {
00164 QString name;
00165 QString type;
00166 int typeCode;
00167 int size;
00168 int precision;
00169 int scale;
00170 bool nullable;
00171 };
00172
00173 QVector< ColumnMetadata > mColMetadata;
00174 };
00175
00176 class QOpenOCCIResult : public QSqlResult
00177 {
00178 public:
00179 QOpenOCCIResult(
00180 const QSqlDriver* d = NULL,
00181 OCI_Connection* c = NULL,
00182 unsigned int prefetch_memory = DEFAULT_MEMORY_PREFETCH,
00183 unsigned int prefetch_rows = DEFAULT_ROWS_PREFETCH
00184 );
00185
00186 ~QOpenOCCIResult();
00187
00188 protected:
00189 QVariant data( int );
00190 bool exec();
00191 bool isNull( int );
00192 bool reset ( const QString& );
00193 bool fetch( int );
00194 bool fetchFirst();
00195 bool fetchNext();
00196 bool fetchPrevious();
00197 bool fetchLast();
00198 QSqlRecord record() const;
00199 int size() { return -1; }
00200 int numRowsAffected();
00201 bool prepare ( const QString & query );
00202 bool savePrepare ( const QString & query );
00203 void setQuery ( const QString & query );
00204
00205 static const char* EXEC_FAILED;
00206 static const char* BIND_FAILED;
00207 private:
00208 void addRowToCache();
00209 void bind(QString name, const QVariant& val, QSql::ParamType paramType);
00210 void updateBoundResults();
00211 void cleanup();
00212 void rebind(int bound_index, const QVariant & val, QSql::ParamType paramType);
00213
00214 static QVariant::Type ocilib_to_qvariant_type(int occi_type);
00215
00216 OCI_Connection * mConnection;
00217 OCI_Statement * mStatement;
00218 OCI_Resultset * mResultSet;
00219
00220 QOpenOCCIMetadata mResultMetadata;
00221 QOpenOCCIBindData mBindData;
00222
00223 map<QString, int> mBindNameIndex;
00224
00225 QOpenOCCICache mCache;
00226
00227 };
00228
00230 class QOpenOCCIDriver : public QSqlDriver
00231 {
00232 public:
00234 QOpenOCCIDriver();
00236 ~QOpenOCCIDriver();
00237
00242 bool hasFeature( DriverFeature ) const;
00243
00257 bool open( const QString& db,
00258 const QString& user,
00259 const QString& password,
00260 const QString& host,
00261 int port = 1521,
00262 const QString& options = "");
00263 void close() {}
00264 QSqlQuery createQuery() const;
00265 QSqlResult* createResult() const;
00266
00267 bool beginTransaction ();
00268 bool commitTransaction ();
00269 bool rollbackTransaction();
00270
00271 static const char* CONNECTION_FAILED;
00272 static const char* CONNECTION_ALREADY_OPEN;
00273 static const char* COMMIT_FAILED;
00274 static const char* ROLLBACK_FAILED;
00275 static const char* PREFETCH_MEM_KEY;
00276 static const char* PREFETCH_ROWS_KEY;
00277 static const char* RESULT_FAILED;
00278 private:
00279 static void ErrHandle(OCI_Error *err);
00280 void closeConnection();
00281
00282 static int driverCount;
00283
00284 OCI_Connection * mConnection;
00285
00286 QMap<QString, QString> mOptionMap;
00287 };
00288 #endif