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

0001 /* This file is part of the KDE project
0002    Copyright (C) 2003 Joseph Wenninger<jowenn@kde.org>
0003    Copyright (C) 2005-2016 Jarosław Staniek <staniek@kde.org>
0004 
0005    This program is free software; you can redistribute it and/or
0006    modify it under the terms of the GNU Library General Public
0007    License as published by the Free Software Foundation; either
0008    version 2 of the License, or (at your option) any later version.
0009 
0010    This program is distributed in the hope that it will be useful,
0011    but WITHOUT ANY WARRANTY; without even the implied warranty of
0012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0013    Library General Public License for more details.
0014 
0015    You should have received a copy of the GNU Library General Public License
0016    along with this program; see the file COPYING.  If not, write to
0017    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0018  * Boston, MA 02110-1301, USA.
0019 */
0020 
0021 #include "MysqlCursor.h"
0022 #include "MysqlConnection.h"
0023 #include "MysqlConnection_p.h"
0024 #include "KDbError.h"
0025 #include "KDb.h"
0026 #include "KDbRecordData.h"
0027 
0028 #include <limits.h>
0029 
0030 #define BOOL bool
0031 
0032 MysqlCursor::MysqlCursor(KDbConnection* conn, const KDbEscapedString& sql,
0033                          KDbCursor::Options options)
0034         : KDbCursor(conn, sql, options | KDbCursor::Option::Buffered)
0035         , d(new MysqlCursorData(conn))
0036 {
0037 }
0038 
0039 MysqlCursor::MysqlCursor(KDbConnection* conn, KDbQuerySchema* query, KDbCursor::Options options)
0040         : KDbCursor(conn, query, options | KDbCursor::Option::Buffered)
0041         , d(new MysqlCursorData(conn))
0042 {
0043 }
0044 
0045 MysqlCursor::~MysqlCursor()
0046 {
0047     close();
0048     delete d;
0049 }
0050 
0051 bool MysqlCursor::drv_open(const KDbEscapedString& sql)
0052 {
0053     if (mysql_real_query(d->mysql, sql.constData(), sql.length()) == 0) {
0054         if (mysql_errno(d->mysql) == 0) {
0055             //! @todo Add option somewhere so we can use more optimal mysql_num_rows().
0056             //!       In this case mysql_num_rows() does not work however.
0057             d->mysqlres = mysql_store_result(d->mysql);
0058             m_fieldCount = mysql_num_fields(d->mysqlres);
0059             m_fieldsToStoreInRecord = m_fieldCount;
0060             d->numRows = mysql_num_rows(d->mysqlres);
0061 
0062             m_records_in_buf = d->numRows;
0063             m_buffering_completed = true;
0064             return true;
0065         }
0066     }
0067 
0068     storeResult();
0069     return false;
0070 }
0071 
0072 bool MysqlCursor::drv_close()
0073 {
0074     mysql_free_result(d->mysqlres);
0075     d->mysqlres = nullptr;
0076     d->mysqlrow = nullptr;
0077     d->lengths = nullptr;
0078     d->numRows = 0;
0079     return true;
0080 }
0081 
0082 void MysqlCursor::drv_getNextRecord()
0083 {
0084     if (at() >= d->numRows) {
0085         m_fetchResult = FetchResult::End;
0086     }
0087     else if (at() < 0) {
0088         // control will reach here only when at() < 0 ( which is usually -1 )
0089         // -1 is same as "1 beyond the End"
0090         m_fetchResult = FetchResult::End;
0091     }
0092     else {  // 0 <= at() < d->numRows
0093         d->lengths = mysql_fetch_lengths(d->mysqlres);
0094         m_fetchResult = FetchResult::Ok;
0095     }
0096 }
0097 
0098 // This isn't going to work right now as it uses d->mysqlrow
0099 QVariant MysqlCursor::value(int pos)
0100 {
0101     if (!d->mysqlrow || pos >= m_fieldCount || d->mysqlrow[pos] == nullptr)
0102         return QVariant();
0103 
0104     KDbField *f = (m_visibleFieldsExpanded && pos < m_visibleFieldsExpanded->count())
0105                        ? m_visibleFieldsExpanded->at(pos)->field() : nullptr;
0106 
0107 //! @todo js: use MYSQL_FIELD::type here!
0108 
0109     bool ok;
0110     return KDb::cstringToVariant(d->mysqlrow[pos], f ? f->type() : KDbField::Text,
0111                                             &ok, d->lengths[pos]);
0112 }
0113 
0114 /* As with sqlite, the DB library returns all values (including numbers) as
0115    strings. So just put that string in a QVariant and let KDb deal with it.
0116  */
0117 bool MysqlCursor::drv_storeCurrentRecord(KDbRecordData* data) const
0118 {
0119 // mysqlDebug() << "position is " << (long)m_at;
0120     if (d->numRows == 0)
0121         return false;
0122 
0123     if (!m_visibleFieldsExpanded) {//simple version: without types
0124         for (int i = 0; i < m_fieldCount; ++i) {
0125             (*data)[i] = QString::fromUtf8(d->mysqlrow[i], d->lengths[i]);
0126         }
0127         return true;
0128     }
0129     for (int i = 0; i < m_fieldCount; ++i) {
0130         KDbField *f = m_visibleFieldsExpanded->at(i)->field();
0131         bool ok;
0132         (*data)[i] = KDb::cstringToVariant(d->mysqlrow[i], f ? f->type() : KDbField::Text,
0133                                            &ok, d->lengths[i]);
0134         if (!ok) {
0135             return false;
0136         }
0137     }
0138     return true;
0139 }
0140 
0141 void MysqlCursor::drv_appendCurrentRecordToBuffer()
0142 {
0143 }
0144 
0145 
0146 void MysqlCursor::drv_bufferMovePointerNext()
0147 {
0148     d->mysqlrow = mysql_fetch_row(d->mysqlres);
0149     d->lengths = mysql_fetch_lengths(d->mysqlres);
0150 }
0151 
0152 void MysqlCursor::drv_bufferMovePointerPrev()
0153 {
0154     mysql_data_seek(d->mysqlres, m_at - 1);
0155     d->mysqlrow = mysql_fetch_row(d->mysqlres);
0156     d->lengths = mysql_fetch_lengths(d->mysqlres);
0157 }
0158 
0159 
0160 void MysqlCursor::drv_bufferMovePointerTo(qint64 to)
0161 {
0162     mysql_data_seek(d->mysqlres, to);
0163     d->mysqlrow = mysql_fetch_row(d->mysqlres);
0164     d->lengths = mysql_fetch_lengths(d->mysqlres);
0165 }
0166 
0167 const char** MysqlCursor::recordData() const
0168 {
0169     //! @todo
0170     return nullptr;
0171 }
0172 
0173 QString MysqlCursor::serverResultName() const
0174 {
0175     return MysqlConnectionInternal::serverResultName(d->mysql);
0176 }
0177 
0178 void MysqlCursor::storeResult()
0179 {
0180     d->storeResult(&m_result);
0181 }