31 changes: 16 additions & 15 deletions src/providers/postgres/qgspostgresconn.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ bool QgsPostgresConn::getTableInfo( bool searchGeometryColumnsOnly, bool searchP
"f_table_schema,"
"%2,"
"upper(type),"
"coalesce(srid,-1),"
"srid,"
"pg_class.relkind"
" FROM "
"%1,pg_class,pg_namespace"
Expand Down Expand Up @@ -377,7 +377,7 @@ bool QgsPostgresConn::getTableInfo( bool searchGeometryColumnsOnly, bool searchP
layerProperty.tableName = tableName;
layerProperty.geometryColName = column;
layerProperty.pkCols = relkind == "v" ? pkCandidates( schemaName, tableName ) : QStringList();
layerProperty.srid = srid.toInt();
layerProperty.srid = srid;
layerProperty.sql = "";
layerProperty.isGeography = i == 1;

Expand Down Expand Up @@ -464,7 +464,7 @@ bool QgsPostgresConn::getTableInfo( bool searchGeometryColumnsOnly, bool searchP
QString column = result.PQgetvalue( i, 2 ); // attname
QString relkind = result.PQgetvalue( i, 3 ); // relation kind

QgsDebugMsg( QString( "%1.%2.%3: %4 %5" ).arg( schema ).arg( table ).arg( column ).arg( relkind ) );
QgsDebugMsg( QString( "%1.%2.%3: %4" ).arg( schema ).arg( table ).arg( column ).arg( relkind ) );

layerProperty.type = QString::null;
layerProperty.schemaName = schema;
Expand Down Expand Up @@ -505,7 +505,7 @@ bool QgsPostgresConn::getTableInfo( bool searchGeometryColumnsOnly, bool searchP

if ( result.PQresultStatus() != PGRES_TUPLES_OK )
{
QgsMessageLog::logMessage( tr( "Database connection was successful, but the accessible tables could not be determined.\nThe error message from the database was:\n%1\n" )
QgsMessageLog::logMessage( tr( "Database connection was successful, but the accessible tables could not be determined.\nThe error message from the database was:\n%1" )
.arg( result.PQresultErrorMessage() ),
tr( "PostGIS" ) );
if ( nColumns == 0 )
Expand All @@ -526,7 +526,7 @@ bool QgsPostgresConn::getTableInfo( bool searchGeometryColumnsOnly, bool searchP
layerProperty.tableName = table;
layerProperty.geometryColName = QString::null;
layerProperty.pkCols = relkind == "v" ? pkCandidates( schema, table ) : QStringList();
layerProperty.srid = -1;
layerProperty.srid = "";
layerProperty.sql = "";
layerProperty.isGeography = false;

Expand All @@ -544,11 +544,7 @@ bool QgsPostgresConn::getTableInfo( bool searchGeometryColumnsOnly, bool searchP
return nColumns > 0;
}

bool QgsPostgresConn::supportedLayers(
QVector<QgsPostgresLayerProperty> &layers,
bool searchGeometryColumnsOnly,
bool searchPublicOnly,
bool allowGeometrylessTables )
bool QgsPostgresConn::supportedLayers( QVector<QgsPostgresLayerProperty> &layers, bool searchGeometryColumnsOnly, bool searchPublicOnly, bool allowGeometrylessTables )
{
// Get the list of supported tables
if ( !getTableInfo( searchGeometryColumnsOnly, searchPublicOnly, allowGeometrylessTables ) )
Expand Down Expand Up @@ -1045,7 +1041,7 @@ void QgsPostgresConn::retrieveLayerTypes( QgsPostgresLayerProperty &layerPropert
" WHEN %2 THEN 'LINESTRING'"
" WHEN %3 THEN 'POLYGON'"
" END,"
" coalesce(%4(%5),-1)"
" %4(%5)"
" FROM %6" )
.arg( postgisTypeFilter( layerProperty.geometryColName, QGis::Point, layerProperty.isGeography ) )
.arg( postgisTypeFilter( layerProperty.geometryColName, QGis::Line, layerProperty.isGeography ) )
Expand All @@ -1059,20 +1055,25 @@ void QgsPostgresConn::retrieveLayerTypes( QgsPostgresLayerProperty &layerPropert
QgsPostgresResult gresult = PQexec( query );

QString type;
int srid = -1;
QString srid;
if ( gresult.PQresultStatus() == PGRES_TUPLES_OK )
{
QStringList types;
QStringList srids;

for ( int i = 0; i < gresult.PQntuples(); i++ )
{
QString type = gresult.PQgetvalue( i, 0 );
if ( !type.isEmpty() )
types << type;
srid = gresult.PQgetvalue( i, 1 ).toInt();
QString srid = gresult.PQgetvalue( i, 1 );
if ( type.isEmpty() )
continue;

types << type;
srids << srid;
}

type = types.join( "," );
srid = srids.join( "," );
}

QgsDebugMsg( QString( "type:%1 srid:%2" ).arg( type ).arg( srid ) );
Expand Down
2 changes: 1 addition & 1 deletion src/providers/postgres/qgspostgresconn.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ struct QgsPostgresLayerProperty
QString tableName;
QString geometryColName;
QStringList pkCols;
int srid;
QString srid;
bool isGeography;
QString sql;
};
Expand Down
16 changes: 11 additions & 5 deletions src/providers/postgres/qgspostgresdataitems.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,15 +86,21 @@ void QgsPGConnectionItem::setLayerType( QgsPostgresLayerProperty layerProperty )
return;
}

foreach( QString type, layerProperty.type.split( ",", QString::SkipEmptyParts ) )
QStringList typeList = layerProperty.type.split( ",", QString::SkipEmptyParts );
QStringList sridList = layerProperty.srid.split( ",", QString::SkipEmptyParts );
Q_ASSERT( typeList.size() == sridList.size() );

for ( int i = 0 ; i < typeList.size(); i++ )
{
QGis::GeometryType geomType = QgsPostgresConn::geomTypeFromPostgis( type );
QGis::GeometryType geomType = QgsPostgresConn::geomTypeFromPostgis( typeList[i] );
if ( geomType == QGis::UnknownGeometry )
{
QgsDebugMsg( QString( "unsupported geometry type:%1" ).arg( type ) );
QgsDebugMsg( QString( "unsupported geometry type:%1" ).arg( typeList[i] ) );
continue;
}

layerProperty.type = typeList[i];
layerProperty.srid = sridList[i];
schemaItem->addLayer( layerProperty );
}
}
Expand Down Expand Up @@ -171,7 +177,7 @@ QString QgsPGLayerItem::createUri()

QgsDataSourceURI uri( connItem->connection()->connInfo() );
uri.setDataSource( mLayerProperty.schemaName, mLayerProperty.tableName, mLayerProperty.geometryColName, mLayerProperty.sql, pkColName );
uri.setSrid( QString::number( mLayerProperty.srid ) );
uri.setSrid( mLayerProperty.srid );
uri.setGeometryType( QgsPostgresConn::geomTypeFromPostgis( mLayerProperty.type ) );
QgsDebugMsg( QString( "layer uri: %1" ).arg( uri.uri() ) );
return uri.uri();
Expand All @@ -197,7 +203,7 @@ QgsPGSchemaItem::~QgsPGSchemaItem()
void QgsPGSchemaItem::addLayer( QgsPostgresLayerProperty layerProperty )
{
QGis::GeometryType geomType = QgsPostgresConn::geomTypeFromPostgis( layerProperty.type );
QString tip = tr( "%1 as %2" ).arg( layerProperty.geometryColName ).arg( QgsPostgresConn::displayStringForGeomType( geomType ) );
QString tip = tr( "%1 as %2 in %3" ).arg( layerProperty.geometryColName ).arg( QgsPostgresConn::displayStringForGeomType( geomType ) ).arg( layerProperty.srid );

QgsLayerItem::LayerType layerType;
switch ( geomType )
Expand Down
170 changes: 90 additions & 80 deletions src/providers/postgres/qgspostgresprovider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@
const QString POSTGRES_KEY = "postgres";
const QString POSTGRES_DESCRIPTION = "PostgreSQL/PostGIS data provider";

// code this parameter is duplicated there.
int QgsPostgresProvider::sProviderIds = 0;
const int QgsPostgresProvider::sFeatureQueueSize = 2000;

Expand Down Expand Up @@ -209,8 +208,6 @@ QgsPostgresProvider::~QgsPostgresProvider()
disconnectDb();

QgsDebugMsg( "deconstructing." );

//pLog.flush();
}

void QgsPostgresProvider::disconnectDb()
Expand Down Expand Up @@ -538,7 +535,7 @@ void QgsPostgresProvider::select( QgsAttributeList fetchAttributes, QgsRectangle
{
qBox = QString( "setsrid('BOX3D(%1)'::box3d,%2)" )
.arg( rect.asWktCoordinates() )
.arg( mRequestedSrid );
.arg( mRequestedSrid.isEmpty() ? mDetectedSrid : mRequestedSrid );
}
else
{
Expand All @@ -547,7 +544,7 @@ void QgsPostgresProvider::select( QgsAttributeList fetchAttributes, QgsRectangle
.arg( rect.yMinimum() )
.arg( rect.xMaximum() )
.arg( rect.yMaximum() )
.arg( mRequestedSrid );
.arg( mRequestedSrid.isEmpty() ? mDetectedSrid : mRequestedSrid );
}

whereClause = QString( "%1 && %2" )
Expand Down Expand Up @@ -1816,7 +1813,7 @@ bool QgsPostgresProvider::addFeatures( QgsFeatureList &flist )
.arg( mConnectionRO->majorVersion() < 2 ? "geomfromwkb" : "st_geomfromwkb" )
.arg( offset++ )
.arg( mConnectionRW->useWkbHex() ? "" : "::bytea" )
.arg( mRequestedSrid );
.arg( mRequestedSrid.isEmpty() ? mDetectedSrid : mRequestedSrid );
delim = ",";
}

Expand Down Expand Up @@ -2322,7 +2319,7 @@ bool QgsPostgresProvider::changeGeometryValues( QgsGeometryMap & geometry_map )
.arg( quotedIdentifier( mGeometryColumn ) )
.arg( mConnectionRW->majorVersion() < 2 ? "geomfromwkb" : "st_geomfromwkb" )
.arg( mConnectionRW->useWkbHex() ? "" : "::bytea" )
.arg( mRequestedSrid )
.arg( mRequestedSrid.isEmpty() ? mDetectedSrid : mRequestedSrid )
.arg( pkParamWhereClause( 2 ) );

QgsDebugMsg( "updating: " + update );
Expand Down Expand Up @@ -2593,9 +2590,6 @@ bool QgsPostgresProvider::getGeometryDetails()
QString tableName = mTableName;
QString geomCol = mGeometryColumn;

QString type;
QString srid;

if ( mIsQuery )
{
sql = QString( "SELECT %1 FROM %2 LIMIT 0" ).arg( quotedIdentifier( mGeometryColumn ) ).arg( mQuery );
Expand Down Expand Up @@ -2635,6 +2629,9 @@ bool QgsPostgresProvider::getGeometryDetails()
}
}

QString detectedType;
QString detectedSrid;

// check geometry columns
sql = QString( "SELECT upper(type),srid FROM geometry_columns WHERE f_table_name=%1 AND f_geometry_column=%2 AND f_table_schema=%3" )
.arg( quotedValue( tableName ) )
Expand All @@ -2647,11 +2644,11 @@ bool QgsPostgresProvider::getGeometryDetails()

if ( result.PQntuples() == 1 )
{
type = result.PQgetvalue( 0, 0 );
srid = result.PQgetvalue( 0, 1 );
detectedType = result.PQgetvalue( 0, 0 );
detectedSrid = result.PQgetvalue( 0, 1 );
}

if ( srid.isEmpty() || type.isEmpty() )
if ( !detectedType.isEmpty() )
{
// check geometry columns
sql = QString( "SELECT upper(type),srid FROM geography_columns WHERE f_table_name=%1 AND f_geography_column=%2 AND f_table_schema=%3" )
Expand All @@ -2663,16 +2660,22 @@ bool QgsPostgresProvider::getGeometryDetails()
result = mConnectionRO->PQexec( sql );
QgsDebugMsg( "Geography column query returned " + QString::number( result.PQntuples() ) );

if ( result.PQntuples() == 1 )
if ( result.PQresultStatus() == PGRES_TUPLES_OK )
{
type = result.PQgetvalue( 0, 0 );
srid = result.PQgetvalue( 0, 1 );

mIsGeography = true;
if ( result.PQntuples() == 1 )
{
detectedType = result.PQgetvalue( 0, 0 );
detectedSrid = result.PQgetvalue( 0, 1 );
mIsGeography = true;
}
}
else
{
mConnectionRO->PQexecNR( "ROLLBACK" );
}
}

if ( srid.isEmpty() || type.isEmpty() || type == "GEOMETRY" )
if ( QgsPostgresConn::geomTypeFromPostgis( detectedType ) == QGis::UnknownGeometry )
{
QgsPostgresLayerProperty layerProperty;
layerProperty.schemaName = mSchemaName;
Expand All @@ -2688,83 +2691,90 @@ bool QgsPostgresProvider::getGeometryDetails()
delim = " AND ";
}

if ( mRequestedGeomType != QGis::UnknownGeometry )
{
layerProperty.sql += delim + QgsPostgresConn::postgisTypeFilter( mGeometryColumn, mRequestedGeomType, mIsGeography );
delim = " AND ";
}

if ( !mRequestedSrid.isEmpty() )
{
layerProperty.sql += QString( "%1%2(%3)=%4" )
.arg( delim )
.arg( mConnectionRO->majorVersion() < 2 ? "srid" : "st_srid" )
.arg( quotedIdentifier( mGeometryColumn, mIsGeography ) )
.arg( mRequestedSrid );
delim = " AND ";
}

mConnectionRO->retrieveLayerTypes( layerProperty, mUseEstimatedMetadata );

if ( srid.isEmpty() )
QStringList typeList = layerProperty.type.split( ",", QString::SkipEmptyParts );
QStringList sridList = layerProperty.srid.split( ",", QString::SkipEmptyParts );
Q_ASSERT( typeList.size() == sridList.size() );

if ( typeList.size() == 0 )
{
srid = QString::number( layerProperty.srid );
}
// no data - so take what's requested
if ( mRequestedGeomType == QGis::UnknownGeometry || mRequestedSrid.isEmpty() )
{
QgsMessageLog::logMessage( tr( "Geometry type and srid for empty column %1 of %2 undefined." ).arg( mGeometryColumn ).arg( mQuery ) );
}

if ( !type.isEmpty() && !type.contains( "," ) )
detectedType = "";
detectedSrid = "";
}
else
{
type = layerProperty.type;
int i;
for ( i = 0; i < typeList.size(); i++ )
{
QGis::GeometryType geomType = QgsPostgresConn::geomTypeFromPostgis( typeList.at( i ) );

if (( geomType != QGis::UnknownGeometry && ( mRequestedGeomType == QGis::UnknownGeometry || mRequestedGeomType == geomType ) ) &&
( mRequestedSrid.isEmpty() || sridList.at( i ) == mRequestedSrid ) )
break;
}

// requested type && srid is available
if ( i < typeList.size() )
{
if ( typeList.size() == 1 )
{
// only what we requested is available
detectedType = typeList.at( 0 );
detectedSrid = sridList.at( 0 );
}
else
{
// we need to filter
detectedType = "";
detectedSrid = "";
}
}
else
{
// geometry type undetermined or not unrequested
QgsMessageLog::logMessage( tr( "Feature type or srid for %1 of %2 could not be determined or was not requested." ).arg( mGeometryColumn ).arg( mQuery ) );
detectedType = "";
detectedSrid = "";
}
}
}

if ( !type.isEmpty() && !srid.isEmpty() )
{
mDetectedGeomType = QgsPostgresConn::geomTypeFromPostgis( type );
mDetectedSrid = srid;
mDetectedGeomType = QgsPostgresConn::geomTypeFromPostgis( detectedType );
mDetectedSrid = detectedSrid;

if ( mRequestedSrid.isEmpty() )
{
mRequestedSrid = srid;
}
QgsDebugMsg( "Detected SRID is " + mDetectedSrid );
QgsDebugMsg( "Requested SRID is " + mRequestedSrid );
QgsDebugMsg( "Detected type is " + QString::number( mDetectedGeomType ) );
QgsDebugMsg( "Requested type is " + QString::number( mRequestedGeomType ) );

mValid = mDetectedGeomType != QGis::UnknownGeometry || mRequestedGeomType != QGis::UnknownGeometry;
mValid = ( mDetectedGeomType != QGis::UnknownGeometry || mRequestedGeomType != QGis::UnknownGeometry )
&& ( !mDetectedSrid.isEmpty() || !mRequestedSrid.isEmpty() );

if ( !mValid )
{
QgsMessageLog::logMessage( tr( "Column %1 in %2 has a geometry type of %3, which Quantum GIS does not currently support." )
.arg( mGeometryColumn ).arg( mQuery ).arg( type ), tr( "PostGIS" ) );
}
}
else
{
QgsMessageLog::logMessage( tr( "Unable to get feature type or srid for %1 of %2" ).arg( mGeometryColumn ).arg( mQuery ) );
}
if ( !mValid )
return false;

if ( mValid )
{
// store whether the geometry includes measure value
if ( type == "POINTM" || type == "MULTIPOINTM" ||
type == "LINESTRINGM" || type == "MULTILINESTRINGM" ||
type == "POLYGONM" || type == "MULTIPOLYGONM" )
{
// explicitly disable adding new features and editing of geometries
// as this would lead to corruption of measures
QgsMessageLog::logMessage( tr( "Editing and adding disabled for 2D+ layer (%1; %2)" ).arg( mGeometryColumn ).arg( mQuery ) );
mEnabledCapabilities &= ~( QgsVectorDataProvider::ChangeGeometries | QgsVectorDataProvider::AddFeatures );
}

QgsDebugMsg( "Detected SRID is " + mDetectedSrid );
QgsDebugMsg( "Requested SRID is " + mRequestedSrid );
QgsDebugMsg( "Detected type is " + QString::number( mDetectedGeomType ) );
QgsDebugMsg( "Requested type is " + QString::number( mRequestedGeomType ) );
QgsDebugMsg( "Feature type name is " + QString( QGis::qgisFeatureTypes[ geometryType()] ) );
QgsDebugMsg( "Geometry is geography " + mIsGeography );
}
else
// store whether the geometry includes measure value
if ( detectedType == "POINTM" || detectedType == "MULTIPOINTM" ||
detectedType == "LINESTRINGM" || detectedType == "MULTILINESTRINGM" ||
detectedType == "POLYGONM" || detectedType == "MULTIPOLYGONM" )
{
QgsMessageLog::logMessage( tr( "Failed to get geometry details for PostGIS column %1.%2." ).arg( tableName ).arg( mGeometryColumn ), tr( "PostGIS" ) );
// explicitly disable adding new features and editing of geometries
// as this would lead to corruption of measures
QgsMessageLog::logMessage( tr( "Editing and adding disabled for 2D+ layer (%1; %2)" ).arg( mGeometryColumn ).arg( mQuery ) );
mEnabledCapabilities &= ~( QgsVectorDataProvider::ChangeGeometries | QgsVectorDataProvider::AddFeatures );
}

QgsDebugMsg( "Feature type name is " + QString( QGis::qgisFeatureTypes[ geometryType()] ) );
QgsDebugMsg( "Geometry is geography " + mIsGeography );

return mValid;
}

Expand Down