kexi

sqlitecursor.cpp

00001 /* This file is part of the KDE project
00002    Copyright (C) 2003-2006 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)
00131     {
00132         int type = sqlite3_column_type(prepared_st_handle, i);
00133         if (type==SQLITE_NULL) {
00134             return QVariant();
00135         }
00136         else if (!f || 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->type()) {
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 SQLiteCursor::SQLiteCursor(Connection* conn, const QString& statement, uint options)
00201     : Cursor( conn, statement, options )
00202     , d( new SQLiteCursorData(conn) )
00203 {
00204     d->data = static_cast<SQLiteConnection*>(conn)->d->data;
00205 }
00206 
00207 SQLiteCursor::SQLiteCursor(Connection* conn, QuerySchema& query, uint options )
00208     : Cursor( conn, query, options )
00209     , d( new SQLiteCursorData(conn) )
00210 {
00211     d->data = static_cast<SQLiteConnection*>(conn)->d->data;
00212 }
00213 
00214 SQLiteCursor::~SQLiteCursor()
00215 {
00216     close();
00217     delete d;
00218 }
00219 
00220 bool SQLiteCursor::drv_open()
00221 {
00222 //  d->st.resize(statement.length()*2);
00223     //TODO: decode
00224 //  d->st = statement.local8Bit();
00225 //  d->st = m_conn->driver()->escapeString( statement.local8Bit() );
00226 
00227     if(! d->data) {
00228         // this may as example be the case if SQLiteConnection::drv_useDatabase()
00229         // wasn't called before. Normaly sqlite_compile/sqlite3_prepare
00230         // should handle it, but it crashes in in sqlite3SafetyOn at util.c:786
00231         kdWarning() << "SQLiteCursor::drv_open(): Database handle undefined." << endl;
00232         return false;
00233     }
00234 
00235 #ifdef SQLITE2
00236     d->st = m_sql.local8Bit();
00237     d->res = sqlite_compile(
00238         d->data,
00239         d->st.data(),
00240         (const char**)&d->utail,
00241         &d->prepared_st_handle,
00242         &d->errmsg_p );
00243 #else //SQLITE3
00244     d->st = m_sql.utf8();
00245     d->res = sqlite3_prepare(
00246         d->data,            /* Database handle */
00247         d->st.data(),       /* SQL statement, UTF-8 encoded */
00248         d->st.length(),             /* Length of zSql in bytes. */
00249         &d->prepared_st_handle,  /* OUT: Statement handle */
00250         0/*const char **pzTail*/     /* OUT: Pointer to unused portion of zSql */
00251     );
00252 #endif
00253     if (d->res!=SQLITE_OK) {
00254         d->storeResult();
00255         return false;
00256     }
00257 //cursor is automatically @ first record
00258 //  m_beforeFirst = true;
00259 
00260     if (isBuffered()) {
00261         d->records.resize(128); //TODO: manage size dynamically
00262     }
00263 
00264     return true;
00265 }
00266 
00267 /*bool SQLiteCursor::drv_getFirstRecord()
00268 {
00269     bool ok = drv_getNextRecord();*/
00270 /*  if ((m_options & Buffered) && ok) { //1st record is there:
00271         //compute parameters for cursor's buffer:
00272         //-size of record's array of pointer to values
00273         d->cols_pointers_mem_size = d->curr_cols * sizeof(char*);
00274         d->records_in_buf = 1;
00275     }*/
00276     /*return ok;
00277 }*/
00278 
00279 bool SQLiteCursor::drv_close()
00280 {
00281 #ifdef SQLITE2
00282     d->res = sqlite_finalize( d->prepared_st_handle, &d->errmsg_p );
00283 #else //SQLITE3
00284     d->res = sqlite3_finalize( d->prepared_st_handle );
00285 #endif
00286     if (d->res!=SQLITE_OK) {
00287         d->storeResult();
00288         return false;
00289     }
00290     return true;
00291 }
00292 
00293 void SQLiteCursor::drv_getNextRecord()
00294 {
00295 #ifdef SQLITE2
00296     static int _fieldCount;
00297     d->res = sqlite_step(
00298      d->prepared_st_handle,
00299      &_fieldCount,
00300      &d->curr_coldata,
00301      &d->curr_colname);
00302 #else //SQLITE3
00303     d->res = sqlite3_step( d->prepared_st_handle );
00304 #endif
00305     if (d->res == SQLITE_ROW) {
00306         m_result = FetchOK;
00307 #ifdef SQLITE2
00308         m_fieldCount = (uint)_fieldCount;
00309 #else
00310         m_fieldCount = sqlite3_data_count(d->prepared_st_handle);
00311 //#else //for SQLITE3 data fetching is delayed. Now we even do not take field count information
00312 //      // -- just set a flag that we've a data not fetched but available
00313 //      d->rowDataReadyToFetch = true;
00314 #endif
00315         //(m_logicalFieldCount introduced) m_fieldCount -= (m_containsROWIDInfo ? 1 : 0);
00316     } else {
00317 //#ifdef SQLITE3
00318 //      d->rowDataReadyToFetch = false;
00319 //#endif
00320         if (d->res==SQLITE_DONE)
00321             m_result = FetchEnd;
00322         else
00323             m_result = FetchError;
00324     }
00325     
00326     //debug
00327 /*
00328     if (m_result == FetchOK && d->curr_coldata) {
00329         for (uint i=0;i<m_fieldCount;i++) {
00330             KexiDBDrvDbg<<"col."<< i<<": "<< d->curr_colname[i]<<" "<< d->curr_colname[m_fieldCount+i]
00331             << " = " << (d->curr_coldata[i] ? QString::fromLocal8Bit(d->curr_coldata[i]) : "(NULL)") <<endl;
00332         }
00333 //      KexiDBDrvDbg << "SQLiteCursor::drv_getNextRecord(): "<<m_fieldCount<<" col(s) fetched"<<endl;
00334     }*/
00335 }
00336 
00337 void SQLiteCursor::drv_appendCurrentRecordToBuffer()
00338 {
00339 //  KexiDBDrvDbg << "SQLiteCursor::drv_appendCurrentRecordToBuffer():" <<endl;
00340     if (!d->cols_pointers_mem_size)
00341         d->cols_pointers_mem_size = m_fieldCount * sizeof(char*);
00342     const char **record = (const char**)malloc(d->cols_pointers_mem_size);
00343     const char **src_col = d->curr_coldata;
00344     const char **dest_col = record;
00345     for (uint i=0; i<m_fieldCount; i++,src_col++,dest_col++) {
00346 //      KexiDBDrvDbg << i <<": '" << *src_col << "'" <<endl;
00347 //      KexiDBDrvDbg << "src_col: " << src_col << endl;
00348         *dest_col = *src_col ? strdup(*src_col) : 0;
00349     }
00350     d->records.insert(m_records_in_buf,record);
00351 //  KexiDBDrvDbg << "SQLiteCursor::drv_appendCurrentRecordToBuffer() ok." <<endl;
00352 }
00353 
00354 void SQLiteCursor::drv_bufferMovePointerNext()
00355 {
00356     d->curr_coldata++; //move to next record in the buffer
00357 }
00358 
00359 void SQLiteCursor::drv_bufferMovePointerPrev()
00360 {
00361     d->curr_coldata--; //move to prev record in the buffer
00362 }
00363 
00364 //compute a place in the buffer that contain next record's data
00365 //and move internal buffer pointer to that place
00366 void SQLiteCursor::drv_bufferMovePointerTo(Q_LLONG at)
00367 {
00368     d->curr_coldata = d->records.at(at);
00369 }
00370 
00371 void SQLiteCursor::drv_clearBuffer()
00372 {
00373     if (d->cols_pointers_mem_size>0) {
00374         const uint records_in_buf = m_records_in_buf;
00375         const char ***r_ptr = d->records.data();
00376         for (uint i=0; i<records_in_buf; i++, r_ptr++) {
00377     //      const char **record = m_records.at(i);
00378             const char **field_data = *r_ptr;
00379     //      for (int col=0; col<d->curr_cols; col++, field_data++) {
00380             for (uint col=0; col<m_fieldCount; col++, field_data++) {
00381                 free((void*)*field_data); //free field memory
00382             }
00383             free(*r_ptr); //free pointers to fields array
00384         }
00385     }
00386 //  d->curr_cols=0;
00387 //  m_fieldCount=0;
00388     m_records_in_buf=0;
00389     d->cols_pointers_mem_size=0;
00390 //  m_at_buffer=false;
00391     d->records.clear();
00392 }
00393 
00394 /*
00395 void SQLiteCursor::drv_storeCurrentRecord()
00396 {
00397 #if 0
00398     assert(!m_data->rec_stored);
00399     m_data->rec_stored = true;
00400     m_data->next_cols = m_data->curr_cols;
00401     for (int i=0;i<m_data->curr_cols;i++) {
00402         KexiDBDrvDbg<<"[COPY] "<<i<<": "<< m_data->curr_coldata[i]<<endl;
00403         if (m_data->curr_coldata[i])
00404             m_data->next_coldata[i] = strdup( m_data->curr_coldata[i] );
00405         else
00406             m_data->next_coldata[i] = 0;
00407     }
00408 #endif
00409 }
00410 */
00411 
00412 /*TODO
00413 const char *** SQLiteCursor::bufferData()
00414 {
00415     if (!isBuffered())
00416         return 0;
00417     return m_records.data();
00418 }*/
00419 
00420 const char ** SQLiteCursor::rowData() const
00421 {
00422     return d->curr_coldata;
00423 }
00424 
00425 void SQLiteCursor::storeCurrentRow(RowData &data) const
00426 {
00427 #ifdef SQLITE2
00428     const char **col = d->curr_coldata;
00429 #endif
00430     //const uint realCount = m_fieldCount + (m_containsROWIDInfo ? 1 : 0);
00431     data.resize(m_fieldCount);
00432     if (!m_fieldsExpanded) {//simple version: without types
00433         for( uint i=0; i<m_fieldCount; i++ ) {
00434 #ifdef SQLITE2
00435             data[i] = QVariant( *col );
00436             col++;
00437 #else //SQLITE3
00438             data[i] = QString::fromUtf8( (const char*)sqlite3_column_text(d->prepared_st_handle, i) );
00439 #endif
00440         }
00441         return;
00442     }
00443 
00444     //const uint fieldsExpandedCount = m_fieldsExpanded->count();
00445     const uint maxCount = QMIN(m_fieldCount, m_fieldsExpanded->count());
00446     // i - visible field's index, j - physical index
00447     for( uint i=0, j=0; i<m_fieldCount; i++, j++ ) {
00448 //      while (j < m_detailedVisibility.count() && !m_detailedVisibility[j]) //!m_query->isColumnVisible(j))
00449 //          j++;
00450         while (j < maxCount && !m_fieldsExpanded->at(j)->visible)
00451             j++;
00452         if (j >= (maxCount /*+(m_containsROWIDInfo ? 1 : 0)*/)) {
00453             //ERR!
00454             break;
00455         }
00456         //(m_logicalFieldCount introduced) Field *f = (m_containsROWIDInfo && i>=m_fieldCount) ? 0 : m_fieldsExpanded->at(j)->field;
00457         Field *f = (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 /*!f means ROWID*/);
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     if (i > (m_fieldCount-1)) //range checking
00512         return QVariant();
00513 //TODO: allow disable range checking! - performance reasons
00514 //  const KexiDB::Field *f = m_query ? m_query->field(i) : 0;
00515     KexiDB::Field *f = (m_fieldsExpanded && i<m_fieldsExpanded->count())
00516         ? m_fieldsExpanded->at(i)->field : 0;
00517 #ifdef SQLITE2
00518     //from most to least frequently used types:
00519 //(m_logicalFieldCount introduced)  if (i==m_fieldCount || f && f->isIntegerType())
00520     if (!f || f->isIntegerType())
00521         return QVariant( QCString(d->curr_coldata[i]).toInt() );
00522     else if (!f || f->isTextType())
00523         return QVariant( d->curr_coldata[i] );
00524     else if (f->isFPNumericType())
00525         return QVariant( QCString(d->curr_coldata[i]).toDouble() );
00526 
00527     return QVariant( d->curr_coldata[i] ); //default
00528 #else
00529     return d->getValue(f, i); //, i==m_logicalFieldCount/*ROWID*/);
00530 #endif
00531 }
00532 
00543 int SQLiteCursor::serverResult()
00544 {
00545     return d->res;
00546 }
00547 
00548 QString SQLiteCursor::serverResultName()
00549 {
00550 #ifdef SQLITE2
00551     return QString::fromLatin1( sqlite_error_string(d->res) );
00552 #else //SQLITE3
00553     return QString::fromLatin1( d->result_name );
00554 #endif
00555 }
00556 
00557 QString SQLiteCursor::serverErrorMsg()
00558 {
00559     return d->errmsg;
00560 }
00561 
00562 void SQLiteCursor::drv_clearServerResult()
00563 {
00564     d->res = SQLITE_OK;
00565     d->errmsg_p = 0;
00566 }
00567 
KDE Home | KDE Accessibility Home | Description of Access Keys