Skip to content

Commit 717788f

Browse files
committed
Refactored the class ResultSet to avoid copying the PGresult,
instead, it will reuse during initialization.
1 parent 16d85e5 commit 717788f

File tree

4 files changed

+72
-94
lines changed

4 files changed

+72
-94
lines changed

libs/libconnector/src/connection.cpp

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -431,8 +431,7 @@ QStringList Connection::getNotices()
431431

432432
void Connection::executeDMLCommand(const QString &sql, ResultSet &result)
433433
{
434-
ResultSet *new_res=nullptr;
435-
PGresult *sql_res=nullptr;
434+
PGresult *sql_res = nullptr;
436435

437436
//Raise an error in case the user try to close a not opened connection
438437
if(!connection)
@@ -442,13 +441,11 @@ void Connection::executeDMLCommand(const QString &sql, ResultSet &result)
442441
notices.clear();
443442

444443
//Alocates a new result to receive the resultset returned by the sql command
445-
sql_res=PQexec(connection, sql.toStdString().c_str());
444+
sql_res = PQexec(connection, sql.toStdString().c_str());
446445

447446
//Prints the SQL to stdout when the flag is active
448447
if(print_sql)
449-
{
450-
qDebug().noquote() << "\n---\n" << sql;
451-
}
448+
qDebug().noquote() << "\n---\n" << sql;
452449

453450
//Raise an error in case the command sql execution is not sucessful
454451
if(strlen(PQerrorMessage(connection))>0)
@@ -459,15 +456,8 @@ void Connection::executeDMLCommand(const QString &sql, ResultSet &result)
459456
QString(PQresultErrorField(sql_res, PG_DIAG_SQLSTATE)));
460457
}
461458

462-
//Generates the resultset based on the sql result descriptor
463-
new_res=new ResultSet(sql_res);
464-
465-
//Copy the new resultset to the parameter resultset
466-
result=*(new_res);
467-
468-
//Deallocate the new resultset
469-
delete new_res;
470-
PQclear(sql_res);
459+
// Initializes the result set with the PG result instance.
460+
result.initResultSet(sql_res);
471461
}
472462

473463
void Connection::executeDDLCommand(const QString &sql)

libs/libconnector/src/resultset.cpp

Lines changed: 47 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -18,68 +18,69 @@
1818

1919
#include "resultset.h"
2020
#include "exception.h"
21+
#include <QDebug>
2122

2223
ResultSet::ResultSet()
2324
{
2425
sql_result = nullptr;
2526
empty_result = false;
26-
is_res_copied = false;
2727
current_tuple = -1;
2828
}
2929

30-
ResultSet::ResultSet(PGresult *sql_result)
30+
ResultSet::ResultSet(PGresult *sql_result) : ResultSet()
3131
{
32-
QString str_aux;
33-
int res_state;
34-
35-
if(!sql_result)
36-
throw Exception(ErrorCode::AsgNotAllocatedSQLResult, __PRETTY_FUNCTION__, __FILE__, __LINE__);
37-
38-
this->sql_result=sql_result;
39-
res_state=PQresultStatus(this->sql_result);
40-
41-
//Handling the status of the result
42-
switch(res_state)
43-
{
44-
//Generating an error in case the server returns an incomprehensible response
45-
case PGRES_BAD_RESPONSE:
46-
throw Exception(ErrorCode::IncomprehensibleDBMSResponse, __PRETTY_FUNCTION__, __FILE__, __LINE__);
47-
48-
//Generating an error in case the server returns a fatal error
49-
case PGRES_FATAL_ERROR:
50-
str_aux=Exception::getErrorMessage(ErrorCode::DBMSFatalError)
51-
.arg(PQresultErrorMessage(sql_result));
52-
throw Exception(str_aux,ErrorCode::DBMSFatalError, __PRETTY_FUNCTION__, __FILE__, __LINE__);
53-
54-
//In case of sucess states the result will be created
55-
default:
56-
/* For any other result set status different from PGRES_TUPLES_OK
57-
* we flag the result set as empty since they either return no tuples
58-
* or aren't support at the moment by this class */
59-
empty_result = res_state != PGRES_TUPLES_OK;
60-
current_tuple = -1;
61-
is_res_copied = false;
62-
break;
63-
}
32+
initResultSet(sql_result);
6433
}
6534

6635
ResultSet::~ResultSet()
6736
{
6837
clearResultSet();
6938
}
7039

40+
void ResultSet::initResultSet(PGresult *sql_res)
41+
{
42+
if(!sql_res)
43+
throw Exception(ErrorCode::AsgNotAllocatedSQLResult, __PRETTY_FUNCTION__, __FILE__, __LINE__);
44+
45+
int res_state = -1;
46+
47+
clearResultSet();
48+
this->sql_result = sql_res;
49+
res_state = PQresultStatus(sql_res);
50+
51+
//Handling the status of the result
52+
switch(res_state)
53+
{
54+
//Generating an error in case the server returns an incomprehensible response
55+
case PGRES_BAD_RESPONSE:
56+
throw Exception(ErrorCode::IncomprehensibleDBMSResponse, __PRETTY_FUNCTION__, __FILE__, __LINE__);
57+
58+
//Generating an error in case the server returns a fatal error
59+
case PGRES_FATAL_ERROR:
60+
throw Exception(Exception::getErrorMessage(ErrorCode::DBMSFatalError)
61+
.arg(PQresultErrorMessage(sql_res)),
62+
ErrorCode::DBMSFatalError, __PRETTY_FUNCTION__, __FILE__, __LINE__);
63+
64+
//In case of sucess states the result will be created
65+
default:
66+
/* For any other result set status different from PGRES_TUPLES_OK
67+
* we flag the result set as empty since they either return no tuples
68+
* or aren't support at the moment by this class */
69+
empty_result = res_state != PGRES_TUPLES_OK;
70+
current_tuple = -1;
71+
break;
72+
}
73+
}
74+
7175
void ResultSet::clearResultSet()
7276
{
73-
/* Destroy the resultset of the object if it was not copied
74-
to another class instance (see 'operator =') */
75-
if(sql_result && !is_res_copied)
76-
PQclear(sql_result);
77+
if(sql_result)
78+
PQclear(sql_result);
7779

7880
//Reset the other attributes
79-
sql_result=nullptr;
80-
empty_result=false;
81-
is_res_copied=false;
82-
current_tuple=-1;
81+
sql_result = nullptr;
82+
empty_result = false;
83+
current_tuple = -1;
8384
}
8485

8586
QString ResultSet::getColumnName(int column_idx)
@@ -89,7 +90,10 @@ QString ResultSet::getColumnName(int column_idx)
8990
throw Exception(ErrorCode::RefTupleColumnInvalidIndex, __PRETTY_FUNCTION__, __FILE__, __LINE__);
9091

9192
//Returns the column name on the specified index
92-
return QString(PQfname(sql_result, column_idx));
93+
//QString col_name { PQfname(sql_result, column_idx) };
94+
//return col_name;
95+
96+
return { PQfname(sql_result, column_idx) };
9397
}
9498

9599
QStringList ResultSet::getColumnNames()
@@ -332,20 +336,3 @@ bool ResultSet::isValid()
332336
return (sql_result != nullptr);
333337
}
334338

335-
void ResultSet::operator = (ResultSet &res)
336-
{
337-
/* Mark the result parameter as copied, avoiding
338-
the sql_result attribute to be deallocated */
339-
res.is_res_copied=true;
340-
341-
/* If the resultset 'this' is allocated,
342-
it will be deallocated to avoid memory leaks */
343-
clearResultSet();
344-
345-
//Copy the parameter restulset attributes to 'this' resultset
346-
this->current_tuple=res.current_tuple;
347-
this->empty_result=res.empty_result;
348-
this->sql_result=PQcopyResult(res.sql_result, PG_COPYRES_TUPLES | PG_COPYRES_ATTRS | PG_COPYRES_EVENTS);
349-
this->is_res_copied=false;
350-
}
351-

libs/libconnector/src/resultset.h

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -38,19 +38,15 @@ It the resultset contains data the user must call ResultSet::accessTuple() to ac
3838

3939
class __libconnector ResultSet {
4040
private:
41-
/*! \brief Indicates whether the result was copied, this flag is used
42-
to avoid segmentation faults when calling the destructor.
43-
As the pointer 'sql_result' is copied
44-
to other elements if it is destroyed can cause
45-
reference fails. Thus, such a pointer is only deleted
46-
when this flag is marked as false */
47-
bool is_res_copied;
48-
4941
void validateColumnIndex(int column_idx);
5042

5143
int validateColumnName(const QString &column_name);
5244

53-
protected:
45+
void initResultSet(PGresult *sql_res);
46+
47+
void clearResultSet();
48+
49+
protected:
5450
//! \brief Stores the current tuple index, just for navigation
5551
int current_tuple;
5652

@@ -61,8 +57,12 @@ class __libconnector ResultSet {
6157
//! \brief Stores the result object of a SQL command
6258
PGresult *sql_result;
6359

64-
/*! \brief This class may be constructed from a
65-
result of SQL command generated in DBConnection class */
60+
/*! \brief This class may be constructed from a
61+
* result of SQL command generated in Connection class.
62+
* The ResultSet takes the ownership of the provided sql_result,
63+
* so there's no need to call PQclear() over it after instantiate
64+
* an object of this class. When destroyed, the instance will
65+
* free the PGresult. (see clearResultSet) */
6666
ResultSet(PGresult *sql_result);
6767

6868
public:
@@ -75,6 +75,9 @@ class __libconnector ResultSet {
7575
};
7676

7777
ResultSet();
78+
79+
/*! \brief Destroys the result set using clearResultSet.
80+
* The internal PostgreSQL result set (sql_result) is automatically freed */
7881
~ResultSet();
7982

8083
//! \brief Returns the value of a column (searching by name or index)
@@ -88,9 +91,9 @@ class __libconnector ResultSet {
8891
//! \brief Returns all the column names / values for the current tuple.
8992
attribs_map getTupleValues();
9093

91-
/*! \brief Returns the number of rows affected by the command that generated
92-
the result if it is an INSERT, DELETE, UPDATE or the number of
93-
tuples returned if the command was a SELECT */
94+
/*! \brief Returns the number of rows affected by the command that generated
95+
* the result if it is an INSERT, DELETE, UPDATE or the number of
96+
* tuples returned if the command was a SELECT */
9497
int getTupleCount();
9598

9699
//! \brief Returns the column count present in one tuple
@@ -128,10 +131,8 @@ class __libconnector ResultSet {
128131
//! \brief Returns if the result set is valid (created from a valid result set)
129132
bool isValid();
130133

131-
void clearResultSet();
132-
133-
//! \brief Make a copy between two resultsets
134-
void operator = (ResultSet &res);
134+
ResultSet &operator = (const PGresult *) = delete;
135+
ResultSet &operator = (const ResultSet &) = delete;
135136

136137
friend class Connection;
137138
};

pgmodeler.pri

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ windows {
271271
!defined(PGSQL_LIB, var): PGSQL_LIB = C:/msys64/mingw64/bin/libpq.dll
272272
!defined(PGSQL_INC, var): PGSQL_INC = C:/msys64/mingw64/include
273273
!defined(XML_INC, var): XML_INC = C:/msys64/mingw64/include/libxml2
274-
!defined(XML_LIB, var): XML_LIB = C:/msys64/mingw64/bin/libxml2-2.dll
274+
!defined(XML_LIB, var): XML_LIB = C:/msys64/mingw64/bin/libxml2-16.dll
275275
INCLUDEPATH += "$$PGSQL_INC" "$$XML_INC"
276276
}
277277

0 commit comments

Comments
 (0)