[QGIS Commit] r8273 - trunk/qgis/src/providers/postgres
svn_qgis at osgeo.org
svn_qgis at osgeo.org
Tue Mar 25 17:24:56 EDT 2008
Author: jef
Date: 2008-03-25 17:24:56 -0400 (Tue, 25 Mar 2008)
New Revision: 8273
Modified:
trunk/qgis/src/providers/postgres/qgspostgresprovider.cpp
trunk/qgis/src/providers/postgres/qgspostgresprovider.h
Log:
reintroduce connection pooling, but use cursors independantly of transactions
by declaring them "WITH HOLD" and "CLOSE" them when done.
Modified: trunk/qgis/src/providers/postgres/qgspostgresprovider.cpp
===================================================================
--- trunk/qgis/src/providers/postgres/qgspostgresprovider.cpp 2008-03-25 20:19:53 UTC (rev 8272)
+++ trunk/qgis/src/providers/postgres/qgspostgresprovider.cpp 2008-03-25 21:24:56 UTC (rev 8273)
@@ -58,6 +58,9 @@
const QString POSTGRES_KEY = "postgres";
const QString POSTGRES_DESCRIPTION = "PostgreSQL/PostGIS data provider";
+QMap<QString, QgsPostgresProvider::Conn *> QgsPostgresProvider::connections;
+int QgsPostgresProvider::providerIds=0;
+
QgsPostgresProvider::QgsPostgresProvider(QString const & uri)
: QgsVectorDataProvider(uri),
geomType(QGis::WKBUnknown),
@@ -67,10 +70,7 @@
// assume this is a valid layer until we determine otherwise
valid = true;
- // Make connection to the data source
- // For postgres, the connection information is passed as a space delimited
- // string:
- // host=192.168.1.5 dbname=test port=5342 user=gsherman password=xxx table=tablename
+ providerId=providerIds++;
QgsDebugMsg("Postgresql Layer Creation");
QgsDebugMsg("URI: " + uri);
@@ -234,8 +234,6 @@
QgsDebugMsg("Main thread just dispatched mCountThread");
#endif
- ready = false; // not ready to read yet cuz the cursor hasn't been created
-
//fill type names into sets
mSupportedNativeTypes.insert("double precision");
mSupportedNativeTypes.insert("int4");
@@ -283,6 +281,13 @@
PGconn *QgsPostgresProvider::connectDb(const QString & conninfo)
{
+ if( connections.contains(conninfo) )
+ {
+ QgsDebugMsg( QString("Using cached connection for %1").arg(conninfo) );
+ connections[conninfo]->ref++;
+ return connections[conninfo]->conn;
+ }
+
QgsDebugMsg(QString("New postgres connection for ") + conninfo);
PGconn *pd = PQconnectdb(conninfo.toLocal8Bit()); // use what is set based on locale; after connecting, use Utf8
@@ -323,14 +328,36 @@
"work properly.\nPlease install PostGIS with "
"GEOS support (http://geos.refractions.net)"));
}
- //--std::cout << "Connection to the database was successful\n";
+
+ QgsDebugMsg("Connection to the database was successful");
+
+ Conn *conn = new Conn(pd);
+ connections.insert( conninfo, conn );
return pd;
}
void QgsPostgresProvider::disconnectDb()
{
- PQfinish( connection );
+ if(mFetching)
+ {
+ PQexecNR(connection, QString("CLOSE qgisf%1").arg(providerId).toUtf8() );
+ mFetching=false;
+ }
+
+ QMap<QString, Conn *>::iterator i;
+ for(i=connections.begin(); i!=connections.end() && i.value()->conn!=connection; i++)
+ ;
+
+ assert( i.value()->conn==connection );
+ assert( i.value()->ref>0 );
+
+ if( --i.value()->ref==0 ) {
+ PQfinish( connection );
+ delete i.value();
+ connections.remove( i.key() );
+ }
+
connection = 0;
}
@@ -341,14 +368,17 @@
bool QgsPostgresProvider::getNextFeature(QgsFeature& feature)
{
+ assert(mFetching);
+
if (valid)
{
// Top up our queue if it is empty
if (mFeatureQueue.empty())
{
- QString fetch = QString("fetch forward %1 from qgisf")
- .arg(mFeatureQueueSize);
+ QString fetch = QString("fetch forward %1 from qgisf%2")
+ .arg(mFeatureQueueSize)
+ .arg(providerId);
if(mFirstFetch)
{
@@ -368,9 +398,7 @@
QgsDebugMsg("End of features");
PQclear(queryResult);
- if (ready)
- PQexecNR(connection, QString("end work").toUtf8());
- ready = false;
+
return false;
}
@@ -499,7 +527,7 @@
QgsFieldMap attributeMap = fields();
QgsFieldMap::const_iterator fieldIt;
for(QgsAttributeList::const_iterator it = mAttributesToFetch.constBegin();
- it != mAttributesToFetch.constEnd(); ++it)
+ it != mAttributesToFetch.constEnd(); ++it)
{
fieldIt = attributeMap.find(*it);
if(fieldIt != attributeMap.end())
@@ -508,14 +536,22 @@
}
}
- QString declare = "declare qgisf binary cursor for select " + quotedIdentifier(primaryKey);
+ if(mFetching)
+ {
+ PQexecNR(connection, QString("CLOSE qgisf%1").arg(providerId).toUtf8() );
+ mFetching=false;
+ }
+ QString declare = QString("declare qgisf%1 binary cursor with hold for select %2")
+ .arg(providerId).arg(quotedIdentifier(primaryKey));
+
if(fetchGeometry)
{
declare += QString(",asbinary(%1,'%2') as qgs_feature_geometry")
- .arg( quotedIdentifier(geometryColumn) )
- .arg( endianString() );
+ .arg( quotedIdentifier(geometryColumn) )
+ .arg( endianString() );
}
+
for(std::list<QString>::const_iterator it = mFetchAttributeNames.begin(); it != mFetchAttributeNames.end(); ++it)
{
if( (*it) != primaryKey) //no need to fetch primary key again
@@ -570,18 +606,14 @@
QgsDebugMsg("Selecting features using: " + declare);
- // set up the cursor
- if(ready){
- PQexecNR(connection, QString("end work").toUtf8());
+ PQexecNR(connection, declare.toUtf8());
+
+ while(!mFeatureQueue.empty())
+ {
+ mFeatureQueue.pop();
}
- PQexecNR(connection,QString("begin work").toUtf8());
- ready = true;
- PQexecNR(connection, declare.toUtf8());
- while(!mFeatureQueue.empty())
- {
- mFeatureQueue.pop();
- }
+ mFetching = true;
mFirstFetch = true;
}
@@ -605,40 +637,41 @@
}
}
- QString sql = "declare qgisfid binary cursor for select " + quotedIdentifier(primaryKey);
+ QString declare = QString("declare qgisfid%1 binary cursor with hold for select %2")
+ .arg(providerId).arg(quotedIdentifier(primaryKey));
if(fetchGeometry)
{
- sql += QString(",asbinary(%1,'%2') as qgs_feature_geometry")
- .arg( quotedIdentifier(geometryColumn) )
- .arg( endianString() );
+ declare += QString(",asbinary(%1,'%2') as qgs_feature_geometry")
+ .arg( quotedIdentifier(geometryColumn) )
+ .arg( endianString() );
}
+
for(namesIt = attributeNames.begin(); namesIt != attributeNames.end(); ++namesIt)
{
if( (*namesIt) != primaryKey) //no need to fetch primary key again
{
- sql += "," + quotedIdentifier(*namesIt) + "::text";
+ declare += "," + quotedIdentifier(*namesIt) + "::text";
}
}
- sql += " " + QString("from %1").arg(mSchemaTableName);
+ declare += QString(" from %1 where %2=%3")
+ .arg(mSchemaTableName)
+ .arg(quotedIdentifier(primaryKey))
+ .arg(featureId);
- sql += " where " + quotedIdentifier(primaryKey) + "=" + QString::number(featureId);
+ QgsDebugMsg("Selecting feature using: " + declare);
- QgsDebugMsg("Selecting feature using: " + sql);
-
- PQexecNR(connection,QString("begin work").toUtf8());
-
// execute query
- PQexecNR(connection, sql.toUtf8());
+ PQexecNR(connection, declare.toUtf8());
- PGresult *res = PQexec(connection, QString("fetch forward 1 from qgisfid").toUtf8());
+ PGresult *res = PQexec(connection, QString("fetch forward 1 from qgisfid%1").arg(providerId).toUtf8());
int rows = PQntuples(res);
if (rows == 0)
{
PQclear(res);
- PQexecNR(connection, QString("end work").toUtf8());
+ PQexecNR(connection, QString("CLOSE qgisfid%1").arg(providerId).toUtf8());
QgsDebugMsg("feature " + QString::number(featureId) + " not found");
return FALSE;
}
@@ -710,7 +743,7 @@
}
PQclear(res);
- PQexecNR(connection, QString("end work").toUtf8());
+ PQexecNR(connection, QString("CLOSE qgisfid%1").arg(providerId).toUtf8());
return TRUE;
}
@@ -770,8 +803,11 @@
void QgsPostgresProvider::reset()
{
- QString move = "move 0 in qgisf"; //move cursor to first record
- PQexecNR(connection, move.toUtf8());
+ if(mFetching)
+ {
+ //move cursor to first record
+ PQexecNR(connection, QString("move 0 in qgisf%1").arg(providerId).toUtf8());
+ }
mFeatureQueue.empty();
loadFields();
}
@@ -852,9 +888,6 @@
fieldComment = QString::fromUtf8(PQgetvalue(tresult, 0, 0));
PQclear(tresult);
- QgsDebugMsg("Field: " + attnum + " maps to " + QString::number(i) + " " + fieldName + ", "
- + fieldTypeName + " (" + QString::number(fldtyp) + "), " + fieldSize + ", " + QString::number(fieldModifier));
-
if(fieldName!=geometryColumn)
{
QVariant::Type fieldType;
@@ -1906,10 +1939,8 @@
appendGeomString( features->geometry(), geomParam);
QList<QByteArray> qparam;
-
qparam.append( geomParam.toUtf8() );
qparam.append( QString("%1").arg( ++primaryKeyHighWater ).toUtf8() );
-
param[0] = qparam[0];
param[1] = qparam[1];
@@ -2446,8 +2477,7 @@
// get the same value using a binary cursor
- PQexecNR(connection,QString("begin work").toUtf8());
- QString oidDeclare = "declare oidcursor binary cursor for select regclass('" + mSchemaTableName + "')::oid";
+ QString oidDeclare = "declare oidcursor binary cursor with hold for select regclass('" + mSchemaTableName + "')::oid";
// set up the cursor
PQexecNR(connection, oidDeclare.toUtf8());
QString fetch = "fetch forward 1 from oidcursor";
@@ -2455,7 +2485,6 @@
QgsDebugMsg("Fetching a record and attempting to get check endian-ness");
PGresult *fResult = PQexec(connection, fetch.toUtf8());
- PQexecNR(connection, QString("end work").toUtf8());
swapEndian = true;
if(PQntuples(fResult) > 0){
// get the oid value from the binary cursor
@@ -2469,6 +2498,7 @@
PQclear(fResult);
}
+ PQexecNR(connection, QString("close oidcursor").toUtf8());
return swapEndian;
}
@@ -2643,16 +2673,15 @@
PGresult *res = PQexec(conn, query);
if(res)
{
- QgsDebugMsg( QString("Query: %1 returned %2 [%3]")
- .arg(query)
- .arg(PQresStatus(PQresultStatus(res)))
- .arg(PQresultErrorMessage(res))
- );
+ QgsDebugMsgLevel( QString("Query: %1 returned %2 [%3]")
+ .arg(query)
+ .arg(PQresStatus(PQresultStatus(res)))
+ .arg(PQresultErrorMessage(res)), 3 );
PQclear(res);
}
else
{
- QgsDebugMsg( QString("Query: %1 returned no result buffer").arg(query) );
+ QgsDebugMsgLevel( QString("Query: %1 returned no result buffer").arg(query), 3 );
}
}
Modified: trunk/qgis/src/providers/postgres/qgspostgresprovider.h
===================================================================
--- trunk/qgis/src/providers/postgres/qgspostgresprovider.h 2008-03-25 20:19:53 UTC (rev 8272)
+++ trunk/qgis/src/providers/postgres/qgspostgresprovider.h 2008-03-25 21:24:56 UTC (rev 8273)
@@ -290,7 +290,6 @@
*/
QString name() const;
-
/** return description
Return a terse string describing what the provider is.
@@ -304,12 +303,7 @@
*/
QString description() const;
-
-
-
-
-
- signals:
+ signals:
/**
* This is emitted whenever the worker thread has fully calculated the
* PostGIS extents for this layer, and its event has been received by this
@@ -330,6 +324,7 @@
void repaintRequested();
private:
+ int providerId; // id to append to provider specific identified (like cursors)
/** Double quote a PostgreSQL identifier for placement in a SQL string.
*/
@@ -343,7 +338,8 @@
*/
void loadFields();
- bool mFirstFetch; //true if fetch forward is called the first time after select
+ bool mFetching; // true if a cursor was declared
+ bool mFirstFetch; // true if fetch forward is called the first time after select
std::vector < QgsFeature > features;
QgsFieldMap attributeFields;
QString mDataComment;
@@ -547,9 +543,6 @@
int SRCFromViewColumn(const QString& ns, const QString& relname, const QString& attname_table,
const QString& attname_view, const QString& viewDefinition, SRC& result) const;
- bool ready;
- std::ofstream pLog;
-
//! PostGIS version string
QString postgisVersionInfo;
@@ -601,6 +594,16 @@
// run a query and free result buffer
static void PQexecNR(PGconn *conn, const char *query);
+
+ struct Conn
+ {
+ Conn(PGconn *connection) : ref(1), conn(connection) {}
+
+ int ref;
+ PGconn *conn;
+ };
+ static QMap<QString, Conn *> connections;
+ static int providerIds;
};
#endif
More information about the QGIS-commit
mailing list