kexi

pqxxcursor.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2003 Adam Pigg <adam@piggz.co.uk>
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this program; see the file COPYING. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18*/
19
20#include "pqxxcursor.h"
21#include "pqxxconnection.h"
22#include "pqxxconnection_p.h"
23
24#include <kexidb/error.h>
25#include <kexidb/global.h>
26
27#include <tdelocale.h>
28#include <kdebug.h>
29
30#include <cstdlib>
31
32using namespace KexiDB;
33
34
35unsigned int pqxxSqlCursor_trans_num=0;
36
37static TQByteArray pgsqlByteaToByteArray(const PQXX_FIELD_CLASS& r)
38{
39 return KexiDB::pgsqlByteaToByteArray(r.c_str(), r.size());
40}
41
42//==================================================================================
43//Constructor based on query statement
44pqxxSqlCursor::pqxxSqlCursor(KexiDB::Connection* conn, const TQString& statement, uint options):
45 Cursor(conn,statement, options)
46{
47// KexiDBDrvDbg << "PQXXSQLCURSOR: constructor for query statement" << endl;
48 my_conn = static_cast<pqxxSqlConnection*>(conn)->d->pqxxsql;
49 m_options = Buffered;
50 m_res = 0;
51// m_tran = 0;
52 m_implicityStarted = false;
53}
54
55//==================================================================================
56//Constructor base on query object
57pqxxSqlCursor::pqxxSqlCursor(Connection* conn, QuerySchema& query, uint options )
58 : Cursor( conn, query, options )
59{
60// KexiDBDrvDbg << "PQXXSQLCURSOR: constructor for query schema" << endl;
61 my_conn = static_cast<pqxxSqlConnection*>(conn)->d->pqxxsql;
62 m_options = Buffered;
63 m_res = 0;
64// m_tran = 0;
65 m_implicityStarted = false;
66}
67
68//==================================================================================
69//Destructor
70pqxxSqlCursor::~pqxxSqlCursor()
71{
72 close();
73}
74
75//==================================================================================
76//Create a cursor result set
77bool pqxxSqlCursor::drv_open()
78{
79// KexiDBDrvDbg << "pqxxSqlCursor::drv_open:" << m_sql << endl;
80
81 if (!my_conn->is_open())
82 {
84 //should never happen, but who knows
85 setError(ERR_NO_CONNECTION,i18n("No connection for cursor open operation specified"));
86 return false;
87 }
88
89 TQCString cur_name;
90 //Set up a transaction
91 try
92 {
93 //m_tran = new pqxx::work(*my_conn, "cursor_open");
94 cur_name.sprintf("cursor_transaction%d", pqxxSqlCursor_trans_num++);
95
96// m_tran = new pqxx::nontransaction(*my_conn, (const char*)cur_name);
97 if (!((pqxxSqlConnection*)connection())->m_trans) {
98// my_conn->drv_beginTransaction();
99// if (implicityStarted)
100 (void)new pqxxTransactionData((pqxxSqlConnection*)connection(), true);
101 m_implicityStarted = true;
102 }
103
104 m_res = new pqxx::result(((pqxxSqlConnection*)connection())->m_trans->data->exec(std::string(m_sql.utf8())));
105 ((pqxxSqlConnection*)connection())
106 ->drv_commitTransaction(((pqxxSqlConnection*)connection())->m_trans);
107// my_conn->m_trans->commit();
108// KexiDBDrvDbg << "pqxxSqlCursor::drv_open: trans. committed: " << cur_name <<endl;
109
110 //We should now be placed before the first row, if any
111 m_fieldCount = m_res->columns() - (m_containsROWIDInfo ? 1 : 0);
112//js m_opened=true;
113 m_afterLast=false;
114 m_records_in_buf = m_res->size();
116 return true;
117 }
118 catch (const std::exception &e)
119 {
120 setError(ERR_DB_SPECIFIC, TQString::fromUtf8( e.what()) );
121 KexiDBDrvWarn << "pqxxSqlCursor::drv_open:exception - " << TQString::fromUtf8( e.what() ) << endl;
122 }
123 catch(...)
124 {
125 setError();
126 }
127// delete m_tran;
128// m_tran = 0;
129 if (m_implicityStarted) {
130 delete ((pqxxSqlConnection*)connection())->m_trans;
131 m_implicityStarted = false;
132 }
133// KexiDBDrvDbg << "pqxxSqlCursor::drv_open: trans. rolled back! - " << cur_name <<endl;
134 return false;
135}
136
137//==================================================================================
138//Delete objects
139bool pqxxSqlCursor::drv_close()
140{
141//js m_opened=false;
142
143 delete m_res;
144 m_res = 0;
145
146// if (m_implicityStarted) {
147// delete m_tran;
148// m_tran = 0;
149// m_implicityStarted = false;
150// }
151
152 return true;
153}
154
155//==================================================================================
156//Gets the next record...does not need to do much, just return fetchend if at end of result set
157void pqxxSqlCursor::drv_getNextRecord()
158{
159// KexiDBDrvDbg << "pqxxSqlCursor::drv_getNextRecord, size is " <<m_res->size() << " Current Position is " << (long)at() << endl;
160 if(at() < m_res->size() && at() >=0)
161 {
162 m_result = FetchOK;
163 }
164 else if (at() >= m_res->size())
165 {
166 m_result = FetchEnd;
167 }
168 else
169 {
170 m_result = FetchError;
171 }
172}
173
174//==================================================================================
175//Check the current position is within boundaries
176void pqxxSqlCursor::drv_getPrevRecord()
177{
178// KexiDBDrvDbg << "pqxxSqlCursor::drv_getPrevRecord" << endl;
179
180 if(at() < m_res->size() && at() >=0)
181 {
182 m_result = FetchOK;
183 }
184 else if (at() >= m_res->size())
185 {
186 m_result = FetchEnd;
187 }
188 else
189 {
190 m_result = FetchError;
191 }
192}
193
194//==================================================================================
195//Return the value for a given column for the current record
196TQVariant pqxxSqlCursor::value(uint pos)
197{
198 if (pos < m_fieldCount)
199 return pValue(pos);
200 else
201 return TQVariant();
202}
203
204//==================================================================================
205//Return the value for a given column for the current record - Private const version
206TQVariant pqxxSqlCursor::pValue(uint pos)const
207{
208 if (m_res->size() <= 0)
209 {
210 KexiDBDrvWarn << "pqxxSqlCursor::value - ERROR: result size not greater than 0" << endl;
211 return TQVariant();
212 }
213
214 if (pos>=(m_fieldCount+(m_containsROWIDInfo ? 1 : 0)))
215 {
216// KexiDBDrvWarn << "pqxxSqlCursor::value - ERROR: requested position is greater than the number of fields" << endl;
217 return TQVariant();
218 }
219
220 KexiDB::Field *f = (m_fieldsExpanded && pos<TQMIN(m_fieldsExpanded->count(), m_fieldCount))
221 ? m_fieldsExpanded->at(pos)->field : 0;
222
223// KexiDBDrvDbg << "pqxxSqlCursor::value(" << pos << ")" << endl;
224
225 //from most to least frequently used types:
226 if (f) //We probably have a schema type query so can use kexi to determin the row type
227 {
228 if ((f->isIntegerType()) || (/*ROWID*/!f && m_containsROWIDInfo && pos==m_fieldCount))
229 {
230 return (*m_res)[at()][pos].as(int());
231 }
232 else if (f->isTextType())
233 {
234 return TQString::fromUtf8((*m_res)[at()][pos].c_str()); //utf8?
235 }
236 else if (f->isFPNumericType())
237 {
238 return (*m_res)[at()][pos].as(double());
239 }
240 else if (f->type() == Field::Boolean )
241 {
242 return TQString((*m_res)[at()][pos].c_str()).lower() == "t" ? TQVariant(true) : TQVariant(false);
243 }
244 else if (f->typeGroup() == Field::BLOBGroup)
245 {
246// PQXX_FIELD_CLASS r = (*m_res)[at()][pos];
247// kdDebug() << r.name() << ", " << r.c_str() << ", " << r.type() << ", " << r.size() << endl;
248 return ::pgsqlByteaToByteArray((*m_res)[at()][pos]);
249 }
250 else
251 {
252 return pgsqlCStrToVariant((*m_res)[at()][pos]);
253 }
254 }
255 else // We probably have a raw type query so use pqxx to determin the column type
256 {
257 return pgsqlCStrToVariant((*m_res)[at()][pos]);
258 }
259
260 return TQString::fromUtf8((*m_res)[at()][pos].c_str(), (*m_res)[at()][pos].size()); //utf8?
261}
262
263//==================================================================================
264//Return the current record as a char**
265//who'd have thought we'd be using char** in this day and age :o)
266const char** pqxxSqlCursor::rowData() const
267{
268// KexiDBDrvDbg << "pqxxSqlCursor::recordData" << endl;
269
270 const char** row;
271
272 row = (const char**)malloc(m_res->columns()+1);
273 row[m_res->columns()] = NULL;
274 if (at() >= 0 && at() < m_res->size())
275 {
276 for(int i = 0; i < (int)m_res->columns(); i++)
277 {
278 row[i] = strdup((*m_res)[at()][i].c_str());
279// KexiDBDrvDbg << row[i] << endl;
280 }
281 }
282 else
283 {
284 KexiDBDrvWarn << "pqxxSqlCursor::recordData: m_at is invalid" << endl;
285 }
286 return row;
287}
288
289//==================================================================================
290//Store the current record in [data]
291void pqxxSqlCursor::storeCurrentRow(RowData &data) const
292{
293// KexiDBDrvDbg << "pqxxSqlCursor::storeCurrentRow: POSITION IS " << (long)m_at<< endl;
294
295 if (m_res->size()<=0)
296 return;
297
298 const uint realCount = m_fieldCount + (m_containsROWIDInfo ? 1 : 0);
299 data.resize(realCount);
300
301 for( uint i=0; i<realCount; i++)
302 {
303 data[i] = pValue(i);
304 }
305}
306
307//==================================================================================
308//
310{
312}
313
314//==================================================================================
315//Add the current record to the internal buffer
316//Implementation required but no need in this driver
317//Result set is a buffer so do not need another
319{
320
321}
322
323//==================================================================================
324//Move internal pointer to internal buffer +1
325//Implementation required but no need in this driver
327{
328
329}
330
331//==================================================================================
332//Move internal pointer to internal buffer -1
333//Implementation required but no need in this driver
335{
336
337}
338
339//==================================================================================
340//Move internal pointer to internal buffer to N
341//Implementation required but no need in this driver
342void pqxxSqlCursor::drv_bufferMovePointerTo(TQ_LLONG to)
343{
344 Q_UNUSED(to);
345}
346
Provides database connection, allowing queries and data modification.
Definition connection.h:62
Provides database cursor functionality.
Definition cursor.h:67
int m_records_in_buf
number of records currently stored in the buffer
Definition cursor.h:340
char m_result
result of a row fetching
Definition cursor.h:337
TQ_LLONG at() const
Definition cursor.cpp:349
virtual bool close()
Definition cursor.cpp:178
QueryColumnInfo::Vector * m_fieldsExpanded
Useful e.g. for value(int) method when we need access to schema def.
Definition cursor.h:345
virtual void drv_appendCurrentRecordToBuffer()=0
uint m_fieldCount
cached field count information
Definition cursor.h:334
Connection * connection() const
Definition cursor.h:81
virtual void drv_bufferMovePointerNext()=0
virtual void drv_bufferMovePointerPrev()=0
virtual const char ** rowData() const =0
bool m_buffering_completed
true if we already have all records stored in the buffer
Definition cursor.h:341
virtual void drv_clearServerResult()=0
Type type() const
Definition field.cpp:134
bool isFPNumericType() const
Definition field.h:266
bool isIntegerType() const
Definition field.h:259
bool isTextType() const
Definition field.h:280
static TypeGroup typeGroup(uint type)
Definition field.cpp:281
TQString m_sql
used to store of actually executed SQL statement
Definition object.h:161
virtual void setError(int code=ERR_OTHER, const TQString &msg=TQString())
Definition object.cpp:53
KexiDB::QuerySchema provides information about database query.
High-level database connectivity library with database backend drivers.
TQValueVector< TQVariant > RowData
structure for storing single record with type information
Definition connection.h:47
KEXI_DB_EXPORT TQByteArray pgsqlByteaToByteArray(const char *data, int length)