File indexing completed on 2024-04-28 15:58:54

0001 /* This file is part of the KDE project
0002    Copyright (C) 2003-2016 Jarosław Staniek <staniek@kde.org>
0003 
0004    This program is free software; you can redistribute it and/or
0005    modify it under the terms of the GNU Library General Public
0006    License as published by the Free Software Foundation; either
0007    version 2 of the License, or (at your option) any later version.
0008 
0009    This program is distributed in the hope that it will be useful,
0010    but WITHOUT ANY WARRANTY; without even the implied warranty of
0011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0012    Library General Public License for more details.
0013 
0014    You should have received a copy of the GNU Library General Public License
0015    along with this program; see the file COPYING.  If not, write to
0016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0017  * Boston, MA 02110-1301, USA.
0018 */
0019 
0020 #include "SqliteCursor.h"
0021 
0022 #include "SqliteConnection.h"
0023 #include "SqliteConnection_p.h"
0024 #include "sqlite_debug.h"
0025 
0026 #include "KDbDriver.h"
0027 #include "KDbError.h"
0028 #include "KDbRecordData.h"
0029 #include "KDbUtils.h"
0030 
0031 #include <QVector>
0032 #include <QDateTime>
0033 #include <QByteArray>
0034 
0035 //! safer interpretations of boolean values for SQLite
0036 static bool sqliteStringToBool(const QString& s)
0037 {
0038     return 0 == s.compare(QLatin1String("yes"), Qt::CaseInsensitive)
0039         || (0 != s.compare(QLatin1String("no"), Qt::CaseInsensitive) && s != QLatin1String("0"));
0040 }
0041 
0042 //----------------------------------------------------
0043 
0044 class SqliteCursorData : public SqliteConnectionInternal
0045 {
0046 public:
0047     explicit SqliteCursorData(SqliteConnection* conn)
0048             : SqliteConnectionInternal(conn)
0049             , prepared_st_handle(nullptr)
0050             , utail(nullptr)
0051             , curr_coldata(nullptr)
0052             , curr_colname(nullptr)
0053             , cols_pointers_mem_size(0)
0054     {
0055         data_owned = false;
0056     }
0057 
0058     /*
0059         void fetchRowDataIfNeeded()
0060         {
0061           if (!rowDataReadyToFetch)
0062             return true;
0063           rowDataReadyToFetch = false;
0064           m_fieldCount = sqlite3_data_count(data);
0065           for (int i=0; i<m_fieldCount; i++) {
0066 
0067           }
0068         }
0069     */
0070 
0071     sqlite3_stmt *prepared_st_handle;
0072 
0073     char *utail;
0074     const char **curr_coldata;
0075     const char **curr_colname;
0076     int cols_pointers_mem_size; //!< size of record's array of pointers to values
0077     QVector<const char**> records; //!< buffer data
0078 
0079     inline QVariant getValue(KDbField *f, int i) {
0080         int type = sqlite3_column_type(prepared_st_handle, i);
0081         if (type == SQLITE_NULL) {
0082             return QVariant();
0083         } else if (!f || type == SQLITE_TEXT) {
0084 //! @todo support for UTF-16
0085             QString text(QString::fromUtf8(
0086                 (const char*)sqlite3_column_text(prepared_st_handle, i),
0087                  sqlite3_column_bytes(prepared_st_handle, i)));
0088             if (!f) {
0089                 return text;
0090             }
0091             const KDbField::Type t = f->type(); // cache: evaluating type of expressions can be expensive
0092             if (KDbField::isTextType(t)) {
0093                 return text;
0094             } else if (t == KDbField::Date) {
0095                 return QDate::fromString(text, Qt::ISODate);
0096             } else if (t == KDbField::Time) {
0097                 //QDateTime - a hack needed because QVariant(QTime) has broken isNull()
0098                 return KDbUtils::stringToHackedQTime(text);
0099             } else if (t == KDbField::DateTime) {
0100                 if (text.length() > 10) {
0101                     text[10] = QLatin1Char('T'); //for ISODate compatibility
0102                 }
0103                 return KDbUtils::dateTimeFromISODateStringWithMs(text);
0104             } else if (t == KDbField::Boolean) {
0105                 return sqliteStringToBool(text);
0106             } else {
0107                 return QVariant(); //!< @todo
0108             }
0109         } else if (type == SQLITE_INTEGER) {
0110             const KDbField::Type t = f->type();  // cache: evaluating type of expressions can be expensive
0111             if (t == KDbField::BigInteger) {
0112                 return QVariant(qint64(sqlite3_column_int64(prepared_st_handle, i)));
0113             } else if (KDbField::isIntegerType(t)) {
0114                 const int intVal = sqlite3_column_int(prepared_st_handle, i);
0115                 return f->isUnsigned() ? QVariant(static_cast<uint>(intVal)) : QVariant(intVal);
0116             } else if (t == KDbField::Boolean) {
0117                 return sqlite3_column_int(prepared_st_handle, i) != 0;
0118             } else if (KDbField::isFPNumericType(t)) { //WEIRD, YEAH?
0119                 return QVariant(double(sqlite3_column_int(prepared_st_handle, i)));
0120             } else {
0121                 return QVariant(); //!< @todo
0122             }
0123         } else if (type == SQLITE_FLOAT) {
0124             const KDbField::Type t = f->type(); // cache: evaluating type of expressions can be expensive
0125             if (KDbField::isFPNumericType(t)) {
0126                 return QVariant(sqlite3_column_double(prepared_st_handle, i));
0127             } else if (t == KDbField::BigInteger) {
0128                 return QVariant(qint64(sqlite3_column_int64(prepared_st_handle, i)));
0129             } else if (KDbField::isIntegerType(t)) {
0130                 const double doubleVal = sqlite3_column_double(prepared_st_handle, i);
0131                 return f->isUnsigned() ? QVariant(static_cast<uint>(doubleVal)) : QVariant(static_cast<int>(doubleVal));
0132             } else {
0133                 return QVariant(); //!< @todo
0134             }
0135         } else if (type == SQLITE_BLOB) {
0136             if (f && f->type() == KDbField::BLOB) {
0137 //! @todo efficient enough?
0138                 return QByteArray((const char*)sqlite3_column_blob(prepared_st_handle, i),
0139                                   sqlite3_column_bytes(prepared_st_handle, i));
0140             } else
0141                 return QVariant(); //!< @todo
0142         }
0143         return QVariant();
0144     }
0145     Q_DISABLE_COPY(SqliteCursorData)
0146 };
0147 
0148 SqliteCursor::SqliteCursor(SqliteConnection* conn, const KDbEscapedString& sql,
0149                            Options options)
0150         : KDbCursor(conn, sql, options)
0151         , d(new SqliteCursorData(conn))
0152 {
0153     d->data = static_cast<SqliteConnection*>(conn)->d->data;
0154 }
0155 
0156 SqliteCursor::SqliteCursor(SqliteConnection* conn, KDbQuerySchema* query, Options options)
0157         : KDbCursor(conn, query, options)
0158         , d(new SqliteCursorData(conn))
0159 {
0160     d->data = static_cast<SqliteConnection*>(conn)->d->data;
0161 }
0162 
0163 SqliteCursor::~SqliteCursor()
0164 {
0165     close();
0166     delete d;
0167 }
0168 
0169 bool SqliteCursor::drv_open(const KDbEscapedString& sql)
0170 {
0171     //! @todo decode
0172     if (! d->data) {
0173         // this may as example be the case if SqliteConnection::drv_useDatabase()
0174         // wasn't called before. Normaly sqlite_compile/sqlite3_prepare
0175         // should handle it, but it crashes in in sqlite3SafetyOn at util.c:786
0176         sqliteWarning() << "Missing database handle";
0177         return false;
0178     }
0179 
0180     int res = sqlite3_prepare(
0181                  d->data,            /* Database handle */
0182                  sql.constData(),       /* SQL statement, UTF-8 encoded */
0183                  sql.length(),             /* Length of zSql in bytes. */
0184                  &d->prepared_st_handle,  /* OUT: Statement handle */
0185                  nullptr/*const char **pzTail*/     /* OUT: Pointer to unused portion of zSql */
0186              );
0187     if (res != SQLITE_OK) {
0188         m_result.setServerErrorCode(res);
0189         storeResult();
0190         return false;
0191     }
0192     if (isBuffered()) {
0193 //! @todo manage size dynamically
0194         d->records.resize(128);
0195     }
0196 
0197     return true;
0198 }
0199 
0200 bool SqliteCursor::drv_close()
0201 {
0202     int res = sqlite3_finalize(d->prepared_st_handle);
0203     if (res != SQLITE_OK) {
0204         m_result.setServerErrorCode(res);
0205         storeResult();
0206         return false;
0207     }
0208     return true;
0209 }
0210 
0211 void SqliteCursor::drv_getNextRecord()
0212 {
0213     int res = sqlite3_step(d->prepared_st_handle);
0214     if (res == SQLITE_ROW) {
0215         m_fetchResult = FetchResult::Ok;
0216         m_fieldCount = sqlite3_data_count(d->prepared_st_handle);
0217 //#else //for SQLITE3 data fetching is delayed. Now we even do not take field count information
0218 //      // -- just set a flag that we've a data not fetched but available
0219         m_fieldsToStoreInRecord = m_fieldCount;
0220     }
0221     else {
0222         if (res == SQLITE_DONE) {
0223             m_fetchResult = FetchResult::End;
0224         } else {
0225             m_result.setServerErrorCode(res);
0226             m_fetchResult = FetchResult::Error;
0227         }
0228     }
0229 
0230     //debug
0231     /*
0232       if ((int)m_result == (int)FetchResult::Ok && d->curr_coldata) {
0233         for (int i=0;i<m_fieldCount;i++) {
0234           sqliteDebug()<<"col."<< i<<": "<< d->curr_colname[i]<<" "<< d->curr_colname[m_fieldCount+i]
0235           << " = " << (d->curr_coldata[i] ? QString::fromLocal8Bit(d->curr_coldata[i]) : "(NULL)");
0236         }
0237     //  sqliteDebug() << m_fieldCount << "col(s) fetched";
0238       }*/
0239 }
0240 
0241 void SqliteCursor::drv_appendCurrentRecordToBuffer()
0242 {
0243 // sqliteDebug();
0244     if (!d->curr_coldata)
0245         return;
0246     if (!d->cols_pointers_mem_size)
0247         d->cols_pointers_mem_size = m_fieldCount * sizeof(char*);
0248     const char **record = (const char**)malloc(d->cols_pointers_mem_size);
0249     const char **src_col = d->curr_coldata;
0250     const char **dest_col = record;
0251     for (int i = 0; i < m_fieldCount; i++, src_col++, dest_col++) {
0252 //  sqliteDebug() << i <<": '" << *src_col << "'";
0253 //  sqliteDebug() << "src_col: " << src_col;
0254         *dest_col = *src_col ? strdup(*src_col) : nullptr;
0255     }
0256     d->records[m_records_in_buf] = record;
0257 // sqliteDebug() << "ok.";
0258 }
0259 
0260 void SqliteCursor::drv_bufferMovePointerNext()
0261 {
0262     d->curr_coldata++; //move to next record in the buffer
0263 }
0264 
0265 void SqliteCursor::drv_bufferMovePointerPrev()
0266 {
0267     d->curr_coldata--; //move to prev record in the buffer
0268 }
0269 
0270 //compute a place in the buffer that contain next record's data
0271 //and move internal buffer pointer to that place
0272 void SqliteCursor::drv_bufferMovePointerTo(qint64 at)
0273 {
0274     d->curr_coldata = d->records.at(at);
0275 }
0276 
0277 void SqliteCursor::drv_clearBuffer()
0278 {
0279     if (d->cols_pointers_mem_size > 0) {
0280         const int records_in_buf = m_records_in_buf;
0281         const char ***r_ptr = d->records.data();
0282         for (int i = 0; i < records_in_buf; i++, r_ptr++) {
0283             const char **field_data = *r_ptr;
0284             for (int col = 0; col < m_fieldCount; col++, field_data++) {
0285                 free((void*)*field_data); //free field memory
0286             }
0287             free(*r_ptr); //free pointers to fields array
0288         }
0289     }
0290     m_records_in_buf = 0;
0291     d->cols_pointers_mem_size = 0;
0292     d->records.clear();
0293 }
0294 
0295 //! @todo
0296 /*
0297 const char *** SqliteCursor::bufferData()
0298 {
0299   if (!isBuffered())
0300     return 0;
0301   return m_records.data();
0302 }*/
0303 
0304 const char ** SqliteCursor::recordData() const
0305 {
0306     return d->curr_coldata;
0307 }
0308 
0309 bool SqliteCursor::drv_storeCurrentRecord(KDbRecordData* data) const
0310 {
0311     if (!m_visibleFieldsExpanded) {//simple version: without types
0312         for (int i = 0; i < m_fieldCount; i++) {
0313             (*data)[i] = QString::fromUtf8(
0314                             (const char*)sqlite3_column_text(d->prepared_st_handle, i),
0315                             sqlite3_column_bytes(d->prepared_st_handle, i));
0316         }
0317         return true;
0318     }
0319     for (int i = 0; i < m_fieldCount; ++i) {
0320         KDbField *f = m_visibleFieldsExpanded->at(i)->field();
0321 //  sqliteDebug() << "col=" << (col ? *col : 0);
0322         (*data)[i] = d->getValue(f, i);
0323     }
0324     return true;
0325 }
0326 
0327 QVariant SqliteCursor::value(int i)
0328 {
0329     if (i < 0 || i > (m_fieldCount - 1)) //range checking
0330         return QVariant();
0331 //! @todo allow disable range checking! - performance reasons
0332     KDbField *f = (m_visibleFieldsExpanded && i < m_visibleFieldsExpanded->count())
0333                   ? m_visibleFieldsExpanded->at(i)->field() : nullptr;
0334     return d->getValue(f, i); //, i==m_logicalFieldCount/*ROWID*/);
0335 }
0336 
0337 QString SqliteCursor::serverResultName() const
0338 {
0339     return SqliteConnectionInternal::serverResultName(m_result.serverErrorCode());
0340 }
0341 
0342 void SqliteCursor::storeResult()
0343 {
0344     d->storeResult(&m_result);
0345 }