kexi

pqxxcursor.cpp

00001 /* This file is part of the KDE project
00002    Copyright (C) 2003 Adam Pigg <adam@piggz.co.uk>
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 "pqxxcursor.h"
00021 #include "pqxxconnection.h"
00022 #include "pqxxconnection_p.h"
00023 
00024 #include <kexidb/error.h>
00025 #include <kexidb/global.h>
00026 
00027 #include <klocale.h>
00028 #include <kdebug.h>
00029 
00030 using namespace KexiDB;
00031 
00032 
00033 unsigned int pqxxSqlCursor_trans_num=0; 
00034 
00035 static QByteArray pgsqlByteaToByteArray(const pqxx::result::field& r)
00036 {
00037     return KexiDB::pgsqlByteaToByteArray(r.c_str(), r.size());
00038 }
00039 
00040 //==================================================================================
00041 //Constructor based on query statement
00042 pqxxSqlCursor::pqxxSqlCursor(KexiDB::Connection* conn, const QString& statement, uint options):
00043     Cursor(conn,statement, options)
00044 {
00045 //  KexiDBDrvDbg << "PQXXSQLCURSOR: constructor for query statement" << endl;
00046     my_conn = static_cast<pqxxSqlConnection*>(conn)->d->pqxxsql;
00047     m_options = Buffered;
00048     m_res = 0;
00049 //  m_tran = 0;
00050     m_implicityStarted = false;
00051 }
00052 
00053 //==================================================================================
00054 //Constructor base on query object
00055 pqxxSqlCursor::pqxxSqlCursor(Connection* conn, QuerySchema& query, uint options )
00056     : Cursor( conn, query, options )
00057 {
00058 //  KexiDBDrvDbg << "PQXXSQLCURSOR: constructor for query schema" << endl;
00059     my_conn = static_cast<pqxxSqlConnection*>(conn)->d->pqxxsql;
00060     m_options = Buffered;
00061     m_res = 0;
00062 //  m_tran = 0;
00063     m_implicityStarted = false;
00064 }
00065 
00066 //==================================================================================
00067 //Destructor
00068 pqxxSqlCursor::~pqxxSqlCursor()
00069 {
00070     close();
00071 }
00072 
00073 //==================================================================================
00074 //Create a cursor result set 
00075 bool pqxxSqlCursor::drv_open()
00076 {
00077 //  KexiDBDrvDbg << "pqxxSqlCursor::drv_open:" << m_sql << endl;
00078 
00079     if (!my_conn->is_open())
00080     {
00082         //should never happen, but who knows
00083         setError(ERR_NO_CONNECTION,i18n("No connection for cursor open operation specified"));
00084         return false;
00085     }
00086         
00087     QCString cur_name;
00088     //Set up a transaction
00089     try
00090     {
00091         //m_tran = new pqxx::work(*my_conn, "cursor_open");
00092         cur_name.sprintf("cursor_transaction%d", pqxxSqlCursor_trans_num++);
00093         
00094 //      m_tran = new pqxx::nontransaction(*my_conn, (const char*)cur_name);
00095         if (!((pqxxSqlConnection*)connection())->m_trans) {
00096 //          my_conn->drv_beginTransaction();
00097 //      if (implicityStarted)
00098             (void)new pqxxTransactionData((pqxxSqlConnection*)connection(), true);
00099             m_implicityStarted = true;
00100         }
00101 
00102         m_res = new pqxx::result(((pqxxSqlConnection*)connection())->m_trans->data->exec(m_sql.utf8()));
00103         ((pqxxSqlConnection*)connection())
00104             ->drv_commitTransaction(((pqxxSqlConnection*)connection())->m_trans);
00105 //      my_conn->m_trans->commit();
00106 //      KexiDBDrvDbg << "pqxxSqlCursor::drv_open: trans. committed: " << cur_name <<endl;
00107 
00108         //We should now be placed before the first row, if any
00109         m_fieldCount = m_res->columns() - (m_containsROWIDInfo ? 1 : 0);
00110 //js        m_opened=true;
00111         m_afterLast=false;
00112         m_records_in_buf = m_res->size();
00113         m_buffering_completed = true;
00114         return true;
00115     }
00116     catch (const std::exception &e)
00117     {
00118         setError(ERR_DB_SPECIFIC, QString::fromUtf8( e.what()) );
00119         KexiDBDrvWarn << "pqxxSqlCursor::drv_open:exception - " << QString::fromUtf8( e.what() ) << endl;
00120     }
00121     catch(...)
00122     {
00123         setError();
00124     }
00125 //  delete m_tran;
00126 //  m_tran = 0;
00127     if (m_implicityStarted) {
00128         delete ((pqxxSqlConnection*)connection())->m_trans;
00129         m_implicityStarted = false;
00130     }
00131 //  KexiDBDrvDbg << "pqxxSqlCursor::drv_open: trans. rolled back! - " << cur_name <<endl;
00132     return false;
00133 }
00134 
00135 //==================================================================================
00136 //Delete objects
00137 bool pqxxSqlCursor::drv_close()
00138 {
00139 //js    m_opened=false;
00140 
00141     delete m_res;
00142     m_res = 0;
00143 
00144 //  if (m_implicityStarted) {
00145 //      delete m_tran;
00146 //      m_tran = 0;
00147 //      m_implicityStarted = false;
00148 //  }
00149 
00150     return true;
00151 }
00152 
00153 //==================================================================================
00154 //Gets the next record...does not need to do much, just return fetchend if at end of result set
00155 void pqxxSqlCursor::drv_getNextRecord()
00156 {
00157 //  KexiDBDrvDbg << "pqxxSqlCursor::drv_getNextRecord, size is " <<m_res->size() << " Current Position is " << (long)at() << endl;
00158     if(at() < m_res->size() && at() >=0)
00159     {   
00160         m_result = FetchOK;
00161     }
00162     else if (at() >= m_res->size())
00163     {
00164         m_result = FetchEnd;
00165     }
00166     else
00167     {
00168         m_result = FetchError;
00169     }
00170 }
00171 
00172 //==================================================================================
00173 //Check the current position is within boundaries
00174 void pqxxSqlCursor::drv_getPrevRecord()
00175 {
00176 //  KexiDBDrvDbg << "pqxxSqlCursor::drv_getPrevRecord" << endl;
00177 
00178     if(at() < m_res->size() && at() >=0)
00179     {   
00180         m_result = FetchOK;
00181     }
00182     else if (at() >= m_res->size())
00183     {
00184         m_result = FetchEnd;
00185     }
00186     else
00187     {
00188         m_result = FetchError;
00189     }
00190 }
00191 
00192 //==================================================================================
00193 //Return the value for a given column for the current record
00194 QVariant pqxxSqlCursor::value(uint pos)
00195 {
00196     if (pos < m_fieldCount)
00197         return pValue(pos);
00198     else
00199         return QVariant();
00200 }
00201 
00202 //==================================================================================
00203 //Return the value for a given column for the current record - Private const version
00204 QVariant pqxxSqlCursor::pValue(uint pos)const
00205 {   
00206     if (m_res->size() <= 0)
00207     {
00208         KexiDBDrvWarn << "pqxxSqlCursor::value - ERROR: result size not greater than 0" << endl;
00209         return QVariant();
00210     }
00211 
00212     if (pos>=(m_fieldCount+(m_containsROWIDInfo ? 1 : 0)))
00213     {
00214 //      KexiDBDrvWarn << "pqxxSqlCursor::value - ERROR: requested position is greater than the number of fields" << endl;
00215         return QVariant();
00216     }
00217 
00218     KexiDB::Field *f = (m_fieldsExpanded && pos<QMIN(m_fieldsExpanded->count(), m_fieldCount)) 
00219         ? m_fieldsExpanded->at(pos)->field : 0;
00220 
00221 //  KexiDBDrvDbg << "pqxxSqlCursor::value(" << pos << ")" << endl;
00222 
00223     //from most to least frequently used types:
00224     if (f) //We probably have a schema type query so can use kexi to determin the row type
00225     {
00226         if ((f->isIntegerType()) || (/*ROWID*/!f && m_containsROWIDInfo && pos==m_fieldCount))
00227         {
00228             return (*m_res)[at()][pos].as(int());
00229         }
00230         else if (f->isTextType())
00231         {
00232             return QString::fromUtf8((*m_res)[at()][pos].c_str()); //utf8?
00233         }
00234         else if (f->isFPNumericType())
00235         {
00236             return (*m_res)[at()][pos].as(double());
00237         }
00238         else if (f->typeGroup() == Field::BLOBGroup)
00239         {
00240 //          pqxx::result::field r = (*m_res)[at()][pos];
00241 //          kdDebug() << r.name() << ", " << r.c_str() << ", " << r.type() << ", " << r.size() << endl;
00242             return ::pgsqlByteaToByteArray((*m_res)[at()][pos]);
00243         }
00244     }
00245     else // We probably have a raw type query so use pqxx to determin the column type
00246     {
00247         return pgsqlCStrToVariant((*m_res)[at()][pos]);
00248     }
00249 
00250     return QString::fromUtf8((*m_res)[at()][pos].c_str(), (*m_res)[at()][pos].size()); //utf8?
00251 }
00252 
00253 //==================================================================================
00254 //Return the current record as a char**
00255 //who'd have thought we'd be using char** in this day and age :o)
00256 const char** pqxxSqlCursor::rowData() const
00257 {
00258 //  KexiDBDrvDbg << "pqxxSqlCursor::recordData" << endl;
00259     
00260     const char** row;
00261     
00262     row = (const char**)malloc(m_res->columns()+1);
00263     row[m_res->columns()] = NULL;
00264     if (at() >= 0 && at() < m_res->size())
00265     {
00266         for(int i = 0; i < (int)m_res->columns(); i++)
00267         {
00268             row[i] = (char*)malloc(strlen((*m_res)[at()][i].c_str())+1);
00269             strcpy((char*)(*m_res)[at()][i].c_str(), row[i]);
00270 //          KexiDBDrvDbg << row[i] << endl;
00271         }
00272     }
00273     else
00274     {
00275         KexiDBDrvWarn << "pqxxSqlCursor::recordData: m_at is invalid" << endl;
00276     }
00277     return row;
00278 }
00279 
00280 //==================================================================================
00281 //Store the current record in [data]
00282 void pqxxSqlCursor::storeCurrentRow(RowData &data) const
00283 {
00284 //  KexiDBDrvDbg << "pqxxSqlCursor::storeCurrentRow: POSITION IS " << (long)m_at<< endl;
00285 
00286     if (m_res->size()<=0)
00287         return;
00288 
00289     const uint realCount = m_fieldCount + (m_containsROWIDInfo ? 1 : 0);
00290     data.resize(realCount);
00291 
00292     for( uint i=0; i<realCount; i++)
00293     {
00294         data[i] = pValue(i);
00295     }
00296 }
00297 
00298 //==================================================================================
00299 //
00300 void pqxxSqlCursor::drv_clearServerResult()
00301 {
00303 }
00304 
00305 //==================================================================================
00306 //Add the current record to the internal buffer
00307 //Implementation required but no need in this driver
00308 //Result set is a buffer so do not need another
00309 void pqxxSqlCursor::drv_appendCurrentRecordToBuffer()
00310 {
00311 
00312 }
00313 
00314 //==================================================================================
00315 //Move internal pointer to internal buffer +1
00316 //Implementation required but no need in this driver
00317 void pqxxSqlCursor::drv_bufferMovePointerNext()
00318 {
00319 
00320 }
00321 
00322 //==================================================================================
00323 //Move internal pointer to internal buffer -1
00324 //Implementation required but no need in this driver
00325 void pqxxSqlCursor::drv_bufferMovePointerPrev()
00326 {
00327 
00328 }
00329 
00330 //==================================================================================
00331 //Move internal pointer to internal buffer to N
00332 //Implementation required but no need in this driver
00333 void pqxxSqlCursor::drv_bufferMovePointerTo(Q_LLONG to)
00334 {
00335     Q_UNUSED(to);
00336 }
00337 
KDE Home | KDE Accessibility Home | Description of Access Keys