Skip to content

Commit 721c2a7

Browse files
author
mhugent
committed
Applied patch from Juergen that adds a connection pool to the postgres provider
git-svn-id: http://svn.osgeo.org/qgis/trunk@7268 c8812cc2-4d05-0410-92ff-de0c093fc19c
1 parent ca9347d commit 721c2a7

File tree

2 files changed

+108
-50
lines changed

2 files changed

+108
-50
lines changed

src/providers/postgres/qgspostgresprovider.cpp

+96-50
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,6 @@ QgsPostgresProvider::QgsPostgresProvider(QString const & uri)
9797
else
9898
mSchemaTableName = "\"" + mTableName + "\"";
9999

100-
101100
QgsDebugMsg("Table name is " + mTableName);
102101
QgsDebugMsg("SQL is " + sqlWhereClause);
103102
QgsDebugMsg("Connection info is " + mUri.connInfo);
@@ -110,37 +109,18 @@ QgsPostgresProvider::QgsPostgresProvider(QString const & uri)
110109
//pLog.open((const char *)logFile);
111110
//QgsDebugMsg("Opened log file for " + mTableName);
112111

113-
PGconn *pd = PQconnectdb((const char *) mUri.connInfo);
114-
// check the connection status
115-
if (PQstatus(pd) != CONNECTION_OK)
116-
{
117-
QgsDebugMsg("Connection to database failed");
118-
valid = false;
119-
return;
120-
}
121-
122-
// store the connection for future use
123-
connection = pd;
124-
125-
//set client encoding to unicode because QString uses UTF-8 anyway
126-
QgsDebugMsg("setting client encoding to UNICODE");
127-
128-
int errcode=PQsetClientEncoding(connection, "UNICODE");
129-
130-
if(errcode==0) {
131-
QgsDebugMsg("encoding successfully set");
132-
} else if(errcode==-1) {
133-
QgsDebugMsg("error in setting encoding");
134-
} else {
135-
QgsDebugMsg("undefined return value from encoding setting");
112+
connection = connectDb( (const char *)mUri.connInfo );
113+
if( connection==NULL ) {
114+
valid = false;
115+
return;
136116
}
137117

138118
QgsDebugMsg("Checking for select permission on the relation\n");
139119

140120
// Check that we can read from the table (i.e., we have
141121
// select permission).
142122
QString sql = "select * from " + mSchemaTableName + " limit 1";
143-
PGresult* testAccess = PQexec(pd, (const char*)(sql.utf8()));
123+
PGresult* testAccess = PQexec(connection, (const char*)(sql.utf8()));
144124
if (PQresultStatus(testAccess) != PGRES_TUPLES_OK)
145125
{
146126
showMessageBox(tr("Unable to access relation"),
@@ -150,33 +130,19 @@ QgsPostgresProvider::QgsPostgresProvider(QString const & uri)
150130
"SQL: " + sql);
151131
PQclear(testAccess);
152132
valid = false;
153-
PQfinish(connection);
133+
disconnectDb();
154134
return;
155135
}
156136
PQclear(testAccess);
157137

158-
/* Check to see if we have GEOS support and if not, warn the user about
159-
the problems they will see :) */
160-
QgsDebugMsg("Checking for GEOS support");
161-
162-
if(!hasGEOS(pd))
163-
{
164-
showMessageBox(tr("No GEOS Support!"),
165-
tr("Your PostGIS installation has no GEOS support.\n"
166-
"Feature selection and identification will not "
167-
"work properly.\nPlease install PostGIS with "
168-
"GEOS support (http://geos.refractions.net)"));
169-
}
170-
//--std::cout << "Connection to the database was successful\n";
171-
172138
if (!getGeometryDetails()) // gets srid and geometry type
173139
{
174140
// the table is not a geometry table
175141
numberFeatures = 0;
176142
valid = false;
177143

178144
QgsDebugMsg("Invalid Postgres layer");
179-
PQfinish(connection);
145+
disconnectDb();
180146
return;
181147
}
182148

@@ -187,14 +153,14 @@ QgsPostgresProvider::QgsPostgresProvider(QString const & uri)
187153
// Get the relation oid for use in later queries
188154
sql = "SELECT oid FROM pg_class WHERE relname = '" + mTableName + "' AND relnamespace = ("
189155
"SELECT oid FROM pg_namespace WHERE nspname = '" + mSchemaName + "')";
190-
PGresult *tresult= PQexec(pd, (const char *)(sql.utf8()));
156+
PGresult *tresult= PQexec(connection, (const char *)(sql.utf8()));
191157
QString tableoid = PQgetvalue(tresult, 0, 0);
192158
PQclear(tresult);
193159

194160
// Get the table description
195161
sql = "SELECT description FROM pg_description WHERE "
196162
"objoid = " + tableoid + " AND objsubid = 0";
197-
tresult = PQexec(pd, (const char*) sql.utf8());
163+
tresult = PQexec(connection, (const char*) sql.utf8());
198164
if (PQntuples(tresult) > 0)
199165
mDataComment = PQgetvalue(tresult, 0, 0);
200166
PQclear(tresult);
@@ -203,7 +169,7 @@ QgsPostgresProvider::QgsPostgresProvider(QString const & uri)
203169
// field name, type, length, and precision (if numeric)
204170
sql = "select * from " + mSchemaTableName + " limit 0";
205171

206-
PGresult *result = PQexec(pd, (const char *) (sql.utf8()));
172+
PGresult *result = PQexec(connection, (const char *) (sql.utf8()));
207173
//--std::cout << "Field: Name, Type, Size, Modifier:" << std::endl;
208174

209175
// The queries inside this loop could possibly be combined into one
@@ -221,20 +187,20 @@ QgsPostgresProvider::QgsPostgresProvider(QString const & uri)
221187
"oid = (SELECT typelem FROM pg_type WHERE "
222188
"typelem = " + typOid + " AND typlen = -1)";
223189

224-
PGresult* oidResult = PQexec(pd, (const char *) sql);
190+
PGresult* oidResult = PQexec(connection, (const char *) sql);
225191
QString fieldTypeName = PQgetvalue(oidResult, 0, 0);
226192
QString fieldSize = PQgetvalue(oidResult, 0, 1);
227193
PQclear(oidResult);
228194

229195
sql = "SELECT attnum FROM pg_attribute WHERE "
230196
"attrelid = " + tableoid + " AND attname = '" + fieldName + "'";
231-
PGresult *tresult = PQexec(pd, (const char *)(sql.utf8()));
197+
PGresult *tresult = PQexec(connection, (const char *)(sql.utf8()));
232198
QString attnum = PQgetvalue(tresult, 0, 0);
233199
PQclear(tresult);
234200

235201
sql = "SELECT description FROM pg_description WHERE "
236202
"objoid = " + tableoid + " AND objsubid = " + attnum;
237-
tresult = PQexec(pd, (const char*)(sql.utf8()));
203+
tresult = PQexec(connection, (const char*)(sql.utf8()));
238204
if (PQntuples(tresult) > 0)
239205
fieldComment = PQgetvalue(tresult, 0, 0);
240206
PQclear(tresult);
@@ -306,7 +272,7 @@ QgsPostgresProvider::QgsPostgresProvider(QString const & uri)
306272

307273
// Close the database connection if the layer isn't going to be loaded.
308274
if (!valid)
309-
PQfinish(connection);
275+
disconnectDb();
310276
}
311277

312278
QgsPostgresProvider::~QgsPostgresProvider()
@@ -329,13 +295,93 @@ QgsPostgresProvider::~QgsPostgresProvider()
329295
QApplication::sendPostedEvents(this, QGis::ProviderExtentCalcEvent);
330296
QApplication::sendPostedEvents(this, QGis::ProviderCountCalcEvent);
331297
#endif
332-
PQfinish(connection);
298+
299+
disconnectDb();
333300

334301
QgsDebugMsg("deconstructing.");
335302

336303
//pLog.flush();
337304
}
338305

306+
PGconn *QgsPostgresProvider::connectDb(const char *conninfo)
307+
{
308+
if( connections.contains(conninfo) )
309+
{
310+
QgsDebugMsg(QString("Using cached connection for ") + conninfo);
311+
connections[conninfo]->ref++;
312+
return connections[conninfo]->conn;
313+
}
314+
315+
QgsDebugMsg(QString("New postgres connection for ") + conninfo);
316+
317+
PGconn *pd = PQconnectdb(conninfo);
318+
// check the connection status
319+
if (PQstatus(pd) != CONNECTION_OK)
320+
{
321+
QgsDebugMsg("Connection to database failed");
322+
return NULL;
323+
}
324+
325+
//set client encoding to unicode because QString uses UTF-8 anyway
326+
QgsDebugMsg("setting client encoding to UNICODE");
327+
328+
int errcode=PQsetClientEncoding(pd, "UNICODE");
329+
330+
if(errcode==0)
331+
{
332+
QgsDebugMsg("encoding successfully set");
333+
}
334+
else if(errcode==-1)
335+
{
336+
QgsDebugMsg("error in setting encoding");
337+
}
338+
else
339+
{
340+
QgsDebugMsg("undefined return value from encoding setting");
341+
}
342+
343+
/* Check to see if we have GEOS support and if not, warn the user about
344+
the problems they will see :) */
345+
QgsDebugMsg("Checking for GEOS support");
346+
347+
if(!hasGEOS(pd))
348+
{
349+
showMessageBox(tr("No GEOS Support!"),
350+
tr("Your PostGIS installation has no GEOS support.\n"
351+
"Feature selection and identification will not "
352+
"work properly.\nPlease install PostGIS with "
353+
"GEOS support (http://geos.refractions.net)"));
354+
}
355+
//--std::cout << "Connection to the database was successful\n";
356+
357+
Conn *conn = new Conn(pd);
358+
connections.insert( conninfo, conn );
359+
360+
return pd;
361+
}
362+
363+
void QgsPostgresProvider::disconnectDb()
364+
{
365+
QMapIterator <QString, Conn *> i(connections);
366+
while( i.hasNext() )
367+
{
368+
i.next();
369+
370+
if( i.value()->conn == connection )
371+
break;
372+
}
373+
374+
assert( i.value()->conn==connection );
375+
assert( i.value()->ref>0 );
376+
377+
if( --i.value()->ref==0 )
378+
{
379+
PQfinish( i.value()->conn );
380+
delete (i.value());
381+
connections.remove( i.key() );
382+
}
383+
}
384+
339385
QString QgsPostgresProvider::storageType()
340386
{
341387
return "PostgreSQL database with PostGIS extension";
@@ -434,7 +480,6 @@ bool QgsPostgresProvider::getNextFeature(QgsFeature& feature)
434480
} // if new queue is required
435481

436482
// Now return the next feature from the queue
437-
438483
feature = mFeatureQueue.front();
439484
mFeatureQueue.pop();
440485

@@ -2609,3 +2654,4 @@ QGISEXTERN bool isProvider(){
26092654
return true;
26102655
}
26112656

2657+
QMap<QString, QgsPostgresProvider::Conn *> QgsPostgresProvider::connections;

src/providers/postgres/qgspostgresprovider.h

+12
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,18 @@ class QgsPostgresProvider:public QgsVectorDataProvider
546546
*/
547547
void customEvent ( QCustomEvent * e );
548548

549+
private:
550+
struct Conn {
551+
Conn(PGconn *connection) : ref(1), conn(connection) {}
552+
553+
int ref;
554+
PGconn *conn;
555+
};
556+
557+
PGconn *connectDb(const char *conninfo);
558+
void disconnectDb();
559+
560+
static QMap<QString, Conn *> connections;
549561
};
550562

551563
#endif

0 commit comments

Comments
 (0)