kexi

sqlitecursor.cpp

00001 /* This file is part of the KDE project
00002    Copyright (C) 2003-2005 Jaroslaw Staniek <js@iidea.pl>
00003 
00004    This program is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    License as published by the Free Software Foundation; either
00007    version 2 of the License, or (at your option) any later version.
00008 
00009    This program is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Library General Public License for more details.
00013 
00014    You should have received a copy of the GNU Library General Public License
00015    along with this program; see the file COPYING.  If not, write to
00016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017  * Boston, MA 02110-1301, USA.
00018 */
00019 
00020 #include "sqlitecursor.h"
00021 
00022 #include "sqliteconnection.h"
00023 #include "sqliteconnection_p.h"
00024 
00025 #include <kexidb/error.h>
00026 #include <kexidb/driver.h>
00027 #include <kexiutils/utils.h>
00028 
00029 #include <assert.h>
00030 #include <string.h>
00031 #include <stdlib.h>
00032 
00033 #include <kdebug.h>
00034 #include <klocale.h>
00035 
00036 #include <qptrvector.h>
00037 #include <qdatetime.h>
00038 
00039 using namespace KexiDB;
00040 
00042 static bool sqliteStringToBool(const QString& s)
00043 {
00044     return s.lower()=="yes" || (s.lower()!="no" && s!="0");
00045 }
00046 
00047 //----------------------------------------------------
00048 
00049 class KexiDB::SQLiteCursorData : public SQLiteConnectionInternal
00050 {
00051     public:
00052         SQLiteCursorData(Connection* conn)
00053             :
00054             SQLiteConnectionInternal(conn)
00055 //          : curr_cols(0)
00056 //          errmsg_p(0)
00057 //          , res(SQLITE_OK)
00058             , curr_coldata(0)
00059             , curr_colname(0)
00060             , cols_pointers_mem_size(0)
00061 //          , rec_stored(false)
00062 /* MOVED TO Cursor:
00063             , cols_pointers_mem_size(0)
00064             , records_in_buf(0)
00065             , buffering_completed(false)
00066             , at_buffer(false)*/
00067 //#ifdef SQLITE3
00068 //          , rowDataReadyToFetch(false)
00069 //#endif
00070         {
00071             data_owned = false;
00072         }
00073 
00074 /*#ifdef SQLITE3
00075         void fetchRowDataIfNeeded()
00076         {
00077             if (!rowDataReadyToFetch)
00078                 return true;
00079             rowDataReadyToFetch = false;
00080             m_fieldCount = sqlite3_data_count(data);
00081             for (int i=0; i<m_fieldCount; i++) {
00082                 
00083             }
00084         }
00085 #endif*/
00086 
00087         QCString st;
00088         //for sqlite:
00089 //      sqlite_struct *data; //! taken from SQLiteConnection
00090 #ifdef SQLITE2
00091         sqlite_vm *prepared_st_handle; //vm
00092 #else //SQLITE3
00093         sqlite3_stmt *prepared_st_handle;
00094 #endif
00095         
00096         char *utail;
00097         
00098 //      QString errmsg; //<! server-specific message of last operation
00099 //      char *errmsg_p; //<! temporary: server-specific message of last operation
00100 //      int res; //<! result code of last operation on server
00101 
00102 //      int curr_cols;
00103         const char **curr_coldata;
00104         const char **curr_colname;
00105 
00106         int next_cols;
00107 //      const char **next_coldata;
00108 //      const char **next_colname;
00109 //      bool rec_stored : 1; //! true, current record is stored in next_coldata
00110 
00111 /* MOVED TO Cursor:
00112         uint cols_pointers_mem_size; //! size of record's array of pointers to values
00113         int records_in_buf; //! number of records currently stored in the buffer
00114         bool buffering_completed; //! true if we have already all records stored in the buffer
00115         QPtrVector<const char*> records; //buffer data
00116         bool at_buffer; //! true if we already point to the buffer with curr_coldata
00117 */
00118 
00119 /*      int prev_cols;
00120         const char **prev_coldata;
00121         const char **prev_colname;*/
00122         
00123         uint cols_pointers_mem_size; 
00124         QPtrVector<const char*> records;
00125 //#ifdef SQLITE3
00126 //      bool rowDataReadyToFetch : 1;
00127 //#endif
00128 
00129 #ifdef SQLITE3
00130     inline QVariant getValue(Field *f, int i, bool ROWID)
00131     {
00132         int type = sqlite3_column_type(prepared_st_handle, i);
00133         if (type==SQLITE_NULL) {
00134             return QVariant();
00135         }
00136         else if ((!f && !ROWID) || type==SQLITE_TEXT) {
00137 //TODO: support for UTF-16
00138 #define GET_sqlite3_column_text QString::fromUtf8( (const char*)sqlite3_column_text(prepared_st_handle, i) )
00139             if (!f || f->isTextType())
00140                 return GET_sqlite3_column_text;
00141             else {
00142                 switch (f->type()) {
00143                 case Field::Date:
00144                     return QDate::fromString( GET_sqlite3_column_text, Qt::ISODate );
00145                 case Field::Time:
00146                     //QDateTime - a hack needed because QVariant(QTime) has broken isNull()
00147                     return KexiUtils::stringToHackedQTime(GET_sqlite3_column_text);
00148                 case Field::DateTime: {
00149                     QString tmp( GET_sqlite3_column_text );
00150                     tmp[10] = 'T'; //for ISODate compatibility
00151                     return QDateTime::fromString( tmp, Qt::ISODate );
00152                 }
00153                 case Field::Boolean:
00154                     return QVariant(sqliteStringToBool(GET_sqlite3_column_text), 1);
00155                 default:
00156                     return QVariant(); //TODO
00157                 }
00158             }
00159         }
00160         else if (type==SQLITE_INTEGER) {
00161             switch (f ? f->type() : Field::Integer /*ROWID*/) {
00162             case Field::Byte:
00163             case Field::ShortInteger:
00164             case Field::Integer:
00165                 return QVariant( sqlite3_column_int(prepared_st_handle, i) );
00166             case Field::BigInteger:
00167                 return QVariant( (Q_LLONG)sqlite3_column_int64(prepared_st_handle, i) );
00168             case Field::Boolean:
00169                 return QVariant( sqlite3_column_int(prepared_st_handle, i)!=0, 1 );
00170             default:;
00171             }
00172             if (f->isFPNumericType()) //WEIRD, YEAH?
00173                 return QVariant( (double)sqlite3_column_int(prepared_st_handle, i) );
00174             else
00175                 return QVariant(); //TODO
00176         }
00177         else if (type==SQLITE_FLOAT) {
00178             if (f && f->isFPNumericType())
00179                 return QVariant( sqlite3_column_double(prepared_st_handle, i) );
00180             else if (!f || f->isIntegerType())
00181                 return QVariant( (double)sqlite3_column_double(prepared_st_handle, i) );
00182             else
00183                 return QVariant(); //TODO
00184         }
00185         else if (type==SQLITE_BLOB) {
00186             if (f && f->type()==Field::BLOB) {
00187                 QByteArray ba;
00189                 ba.duplicate((const char*)sqlite3_column_blob(prepared_st_handle, i),
00190                     sqlite3_column_bytes(prepared_st_handle, i));
00191                 return ba;
00192             } else
00193                 return QVariant(); //TODO
00194         }
00195         return QVariant();
00196     }
00197 #endif //SQLITE3
00198 };
00199 
00200 
00201 
00202 SQLiteCursor::SQLiteCursor(Connection* conn, const QString& statement, uint options)
00203     : Cursor( conn, statement, options )
00204     , d( new SQLiteCursorData(conn) )
00205 {
00206     d->data = static_cast<SQLiteConnection*>(conn)->d->data;
00207 }
00208 
00209 SQLiteCursor::SQLiteCursor(Connection* conn, QuerySchema& query, uint options )
00210     : Cursor( conn, query, options )
00211     , d( new SQLiteCursorData(conn) )
00212 {
00213     d->data = static_cast<SQLiteConnection*>(conn)->d->data;
00214 }
00215 
00216 SQLiteCursor::~SQLiteCursor()
00217 {
00218     close();
00219     delete d;
00220 }
00221 
00222 bool SQLiteCursor::drv_open()
00223 {
00224 //  d->st.resize(statement.length()*2);
00225     //TODO: decode
00226 //  d->st = statement.local8Bit();
00227 //  d->st = m_conn->driver()->escapeString( statement.local8Bit() );
00228 
00229     if(! d->data) {
00230         // this may as example be the case if SQLiteConnection::drv_useDatabase()
00231         // wasn't called before. Normaly sqlite_compile/sqlite3_prepare
00232         // should handle it, but it crashes in in sqlite3SafetyOn at util.c:786
00233         kdWarning() << "SQLiteCursor::drv_open(): Database handle undefined." << endl;
00234         return false;
00235     }
00236 
00237 #ifdef SQLITE2
00238     d->st = m_sql.local8Bit();
00239     d->res = sqlite_compile(
00240         d->data,
00241         d->st.data(),
00242         (const char**)&d->utail,
00243         &d->prepared_st_handle,
00244         &d->errmsg_p );
00245 #else //SQLITE3
00246     d->st = m_sql.utf8();
00247     d->res = sqlite3_prepare(
00248         d->data,            /* Database handle */
00249         d->st.data(),       /* SQL statement, UTF-8 encoded */
00250         d->st.length(),             /* Length of zSql in bytes. */
00251         &d->prepared_st_handle,  /* OUT: Statement handle */
00252         0/*const char **pzTail*/     /* OUT: Pointer to unused portion of zSql */
00253     );
00254 #endif
00255     if (d->res!=SQLITE_OK) {
00256         d->storeResult();
00257         return false;
00258     }
00259 //cursor is automatically @ first record
00260 //  m_beforeFirst = true;
00261 
00262     if (isBuffered()) {
00263         d->records.resize(128); //TODO: manage size dynamically
00264     }
00265 
00266     return true;
00267 }
00268 
00269 /*bool SQLiteCursor::drv_getFirstRecord()
00270 {
00271     bool ok = drv_getNextRecord();*/
00272 /*  if ((m_options & Buffered) && ok) { //1st record is there:
00273         //compute parameters for cursor's buffer:
00274         //-size of record's array of pointer to values
00275         d->cols_pointers_mem_size = d->curr_cols * sizeof(char*);
00276         d->records_in_buf = 1;
00277     }*/
00278     /*return ok;
00279 }*/
00280 
00281 bool SQLiteCursor::drv_close()
00282 {
00283 #ifdef SQLITE2
00284     d->res = sqlite_finalize( d->prepared_st_handle, &d->errmsg_p );
00285 #else //SQLITE3
00286     d->res = sqlite3_finalize( d->prepared_st_handle );
00287 #endif
00288     if (d->res!=SQLITE_OK) {
00289         d->storeResult();
00290         return false;
00291     }
00292     return true;
00293 }
00294 
00295 void SQLiteCursor::drv_getNextRecord()
00296 {
00297 #ifdef SQLITE2
00298     static int _fieldCount;
00299     d->res = sqlite_step(
00300      d->prepared_st_handle,
00301      &_fieldCount,
00302      &d->curr_coldata,
00303      &d->curr_colname);
00304 #else //SQLITE3
00305     d->res = sqlite3_step( d->prepared_st_handle );
00306 #endif
00307     if (d->res == SQLITE_ROW) {
00308         m_result = FetchOK;
00309 #ifdef SQLITE2
00310         m_fieldCount = (uint)_fieldCount;
00311 #else
00312         m_fieldCount = sqlite3_data_count(d->prepared_st_handle);
00313 //#else //for SQLITE3 data fetching is delayed. Now we even do not take field count information
00314 //      // -- just set a flag that we've a data not fetched but available
00315 //      d->rowDataReadyToFetch = true;
00316 #endif
00317         m_fieldCount -= (m_containsROWIDInfo ? 1 : 0);
00318     } else {
00319 //#ifdef SQLITE3
00320 //      d->rowDataReadyToFetch = false;
00321 //#endif
00322         if (d->res==SQLITE_DONE)
00323             m_result = FetchEnd;
00324         else
00325             m_result = FetchError;
00326     }
00327     
00328     //debug
00329 /*
00330     if (m_result == FetchOK && d->curr_coldata) {
00331         for (uint i=0;i<m_fieldCount;i++) {
00332             KexiDBDrvDbg<<"col."<< i<<": "<< d->curr_colname[i]<<" "<< d->curr_colname[m_fieldCount+i]
00333             << " = " << (d->curr_coldata[i] ? QString::fromLocal8Bit(d->curr_coldata[i]) : "(NULL)") <<endl;
00334         }
00335 //      KexiDBDrvDbg << "SQLiteCursor::drv_getNextRecord(): "<<m_fieldCount<<" col(s) fetched"<<endl;
00336     }*/
00337 }
00338 
00339 void SQLiteCursor::drv_appendCurrentRecordToBuffer()
00340 {
00341 //  KexiDBDrvDbg << "SQLiteCursor::drv_appendCurrentRecordToBuffer():" <<endl;
00342     if (!d->cols_pointers_mem_size)
00343         d->cols_pointers_mem_size = m_fieldCount * sizeof(char*);
00344     const char **record = (const char**)malloc(d->cols_pointers_mem_size);
00345     const char **src_col = d->curr_coldata;
00346     const char **dest_col = record;
00347     for (uint i=0; i<m_fieldCount; i++,src_col++,dest_col++) {
00348 //      KexiDBDrvDbg << i <<": '" << *src_col << "'" <<endl;
00349 //      KexiDBDrvDbg << "src_col: " << src_col << endl;
00350         *dest_col = *src_col ? strdup(*src_col) : 0;
00351     }
00352     d->records.insert(m_records_in_buf,record);
00353 //  KexiDBDrvDbg << "SQLiteCursor::drv_appendCurrentRecordToBuffer() ok." <<endl;
00354 }
00355 
00356 void SQLiteCursor::drv_bufferMovePointerNext()
00357 {
00358     d->curr_coldata++; //move to next record in the buffer
00359 }
00360 
00361 void SQLiteCursor::drv_bufferMovePointerPrev()
00362 {
00363     d->curr_coldata--; //move to prev record in the buffer
00364 }
00365 
00366 //compute a place in the buffer that contain next record's data
00367 //and move internal buffer pointer to that place
00368 void SQLiteCursor::drv_bufferMovePointerTo(Q_LLONG at)
00369 {
00370     d->curr_coldata = d->records.at(at);
00371 }
00372 
00373 void SQLiteCursor::drv_clearBuffer()
00374 {
00375     if (d->cols_pointers_mem_size>0) {
00376         const uint records_in_buf = m_records_in_buf;
00377         const char ***r_ptr = d->records.data();
00378         for (uint i=0; i<records_in_buf; i++, r_ptr++) {
00379     //      const char **record = m_records.at(i);
00380             const char **field_data = *r_ptr;
00381     //      for (int col=0; col<d->curr_cols; col++, field_data++) {
00382             for (uint col=0; col<m_fieldCount; col++, field_data++) {
00383                 free((void*)*field_data); //free field memory
00384             }
00385             free(*r_ptr); //free pointers to fields array
00386         }
00387     }
00388 //  d->curr_cols=0;
00389 //  m_fieldCount=0;
00390     m_records_in_buf=0;
00391     d->cols_pointers_mem_size=0;
00392 //  m_at_buffer=false;
00393     d->records.clear();
00394 }
00395 
00396 /*
00397 void SQLiteCursor::drv_storeCurrentRecord()
00398 {
00399 #if 0
00400     assert(!m_data->rec_stored);
00401     m_data->rec_stored = true;
00402     m_data->next_cols = m_data->curr_cols;
00403     for (int i=0;i<m_data->curr_cols;i++) {
00404         KexiDBDrvDbg<<"[COPY] "<<i<<": "<< m_data->curr_coldata[i]<<endl;
00405         if (m_data->curr_coldata[i])
00406             m_data->next_coldata[i] = strdup( m_data->curr_coldata[i] );
00407         else
00408             m_data->next_coldata[i] = 0;
00409     }
00410 #endif
00411 }
00412 */
00413 
00414 /*TODO
00415 const char *** SQLiteCursor::bufferData()
00416 {
00417     if (!isBuffered())
00418         return 0;
00419     return m_records.data();
00420 }*/
00421 
00422 const char ** SQLiteCursor::rowData() const
00423 {
00424     return d->curr_coldata;
00425 }
00426 
00427 void SQLiteCursor::storeCurrentRow(RowData &data) const
00428 {
00429 #ifdef SQLITE2
00430     const char **col = d->curr_coldata;
00431 #endif
00432     const uint realCount = m_fieldCount + (m_containsROWIDInfo ? 1 : 0);
00433     data.resize(realCount);
00434     if (!m_fieldsExpanded) {//simple version: without types
00435         for( uint i=0; i<realCount; i++ ) {
00436 #ifdef SQLITE2
00437             data[i] = QVariant( *col );
00438             col++;
00439 #else //SQLITE3
00440             data[i] = QString::fromUtf8( (const char*)sqlite3_column_text(d->prepared_st_handle, i) );
00441 #endif
00442         }
00443         return;
00444     }
00445 
00446     const uint fieldsExpandedCount = m_fieldsExpanded->count();
00447     for( uint i=0, j=0; i<realCount; i++, j++ ) {
00448 //      while (j < m_detailedVisibility.count() && !m_detailedVisibility[j]) //!m_query->isColumnVisible(j))
00449 //          j++;
00450         while (j < fieldsExpandedCount && !m_fieldsExpanded->at(j)->visible)
00451             j++;
00452         if (j >= (fieldsExpandedCount+(m_containsROWIDInfo ? 1 : 0))) {
00453             //ERR!
00454             break;
00455         }
00456 //      Field *f = m_fieldsExpanded->at(j);
00457         Field *f = (m_containsROWIDInfo && i>=m_fieldCount) ? 0 : m_fieldsExpanded->at(j)->field;
00458 //      KexiDBDrvDbg << "SQLiteCursor::storeCurrentRow(): col=" << (col ? *col : 0) << endl;
00459 
00460 #ifdef SQLITE2
00461         if (!*col)
00462             data[i] = QVariant();
00463         else if (f && f->isTextType())
00464 # ifdef SQLITE_UTF8
00465             data[i] = QString::fromUtf8( *col );
00466 # else
00467             data[i] = QVariant( *col ); //only latin1
00468 # endif
00469         else if (f && f->isFPNumericType())
00470             data[i] = QVariant( QCString(*col).toDouble() );
00471         else {
00472             switch (f ? f->type() : Field::Integer/*ROWINFO*/) {
00473 //todo: use short, etc.
00474             case Field::Byte:
00475             case Field::ShortInteger:
00476             case Field::Integer:
00477                 data[i] = QVariant( QCString(*col).toInt() );
00478             case Field::BigInteger:
00479                 data[i] = QVariant( QString::fromLatin1(*col).toLongLong() );
00480             case Field::Boolean:
00481                 data[i] = QVariant( sqliteStringToBool(QString::fromLatin1(*col)), 1 );
00482                 break;
00483             case Field::Date:
00484                 data[i] = QDate::fromString( QString::fromLatin1(*col), Qt::ISODate );
00485                 break;
00486             case Field::Time:
00487                 //QDateTime - a hack needed because QVariant(QTime) has broken isNull()
00488                 data[i] = KexiUtils::stringToHackedQTime(QString::fromLatin1(*col));
00489                 break;
00490             case Field::DateTime: {
00491                 QString tmp( QString::fromLatin1(*col) );
00492                 tmp[10] = 'T';
00493                 data[i] = QDateTime::fromString( tmp, Qt::ISODate );
00494                 break;
00495             }
00496             default:
00497                 data[i] = QVariant( *col );
00498             }
00499         }
00500 
00501         col++;
00502 #else //SQLITE3
00503         data[i] = d->getValue(f, i, !f );
00504 #endif
00505     }
00506 }
00507 
00508 QVariant SQLiteCursor::value(uint i)
00509 {
00510     if (i > (m_fieldCount-1+(m_containsROWIDInfo?1:0))) //range checking
00511         return QVariant();
00512 //TODO: allow disable range checking! - performance reasons
00513 //  const KexiDB::Field *f = m_query ? m_query->field(i) : 0;
00514     KexiDB::Field *f = (m_fieldsExpanded && i<m_fieldsExpanded->count())
00515         ? m_fieldsExpanded->at(i)->field : 0;
00516 #ifdef SQLITE2
00517     //from most to least frequently used types:
00518     if (i==m_fieldCount || f && f->isIntegerType())
00519         return QVariant( QCString(d->curr_coldata[i]).toInt() );
00520     if (!f || f->isTextType())
00521         return QVariant( d->curr_coldata[i] );
00522     else if (f->isFPNumericType())
00523         return QVariant( QCString(d->curr_coldata[i]).toDouble() );
00524 
00525     return QVariant( d->curr_coldata[i] ); //default
00526 #else
00527     return d->getValue(f, i, i==m_fieldCount/*ROWID*/);
00528 #endif
00529 }
00530 
00541 int SQLiteCursor::serverResult()
00542 {
00543     return d->res;
00544 }
00545 
00546 QString SQLiteCursor::serverResultName()
00547 {
00548 #ifdef SQLITE2
00549     return QString::fromLatin1( sqlite_error_string(d->res) );
00550 #else //SQLITE3
00551     return QString::fromLatin1( d->result_name );
00552 #endif
00553 }
00554 
00555 QString SQLiteCursor::serverErrorMsg()
00556 {
00557     return d->errmsg;
00558 }
00559 
00560 void SQLiteCursor::drv_clearServerResult()
00561 {
00562     d->res = SQLITE_OK;
00563     d->errmsg_p = 0;
00564 }
00565 
KDE Home | KDE Accessibility Home | Description of Access Keys