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