Skip to content
Permalink
Browse files

PG raster: fix composite pkeys and extent-less rasters

Fixes composite pkeys and force manual raster envelope
calculation in case metadata have no values for extent
  • Loading branch information
elpaso committed Mar 3, 2020
1 parent e286044 commit aee84a54bed88effa62ee88d746785eb3e587708
@@ -385,7 +385,7 @@ bool QgsPostgresRasterProvider::readBlock( int bandNo, const QgsRectangle &viewE
bandNo,
rasterExtent,
overviewFactor,
quotedIdentifier( pkSql() ),
pkSql(), // already quoted
quotedIdentifier( mRasterColumn ),
tableToQuery,
QString::number( mCrs.postgisSrid() ),
@@ -864,9 +864,22 @@ bool QgsPostgresRasterProvider::init()
const QByteArray hexAscii { result.PQgetvalue( 0, 5 ).toLatin1().mid( 2 ) };
QgsConstWkbPtr ptr { QByteArray::fromHex( hexAscii ) };

if ( ! p.fromWkb( ptr ) )
if ( hexAscii.isEmpty() || ! p.fromWkb( ptr ) )
{
throw QgsPostgresRasterProviderException( tr( "Cannot get extent from raster_columns" ) );
// Try to determine extent from raster
const QString extentSql { QStringLiteral( "SELECT ST_Envelope( %1 ) "
"FROM %2 WHERE %3" )
.arg( quotedValue( mRasterColumn ) )
.arg( mQuery )
.arg( mSqlWhereClause.isEmpty() ? "'t'" : mSqlWhereClause ) };

QgsPostgresResult extentResult( connectionRO()->PQexec( extentSql ) );
const QByteArray extentHexAscii { extentResult.PQgetvalue( 0, 0 ).toLatin1() };
QgsConstWkbPtr extentPtr { QByteArray::fromHex( extentHexAscii ) };
if ( extentHexAscii.isEmpty() || ! p.fromWkb( extentPtr ) )
{
throw QgsPostgresRasterProviderException( tr( "Cannot get extent from raster" ) );
}
}

mExtent = p.boundingBox();
@@ -1344,6 +1357,10 @@ bool QgsPostgresRasterProvider::determinePrimaryKey()
{
pkType = QgsPostgresPrimaryKeyType::PktUint64;
}
else if ( fieldTypeName == QLatin1String( "text" ) )
{
pkType = QgsPostgresPrimaryKeyType::PktFidMap;
}
// Always use PktFidMap for multi-field keys
mPrimaryKeyType = i ? QgsPostgresPrimaryKeyType::PktFidMap : pkType;
mPrimaryKeyAttrs << name;
@@ -1410,9 +1427,14 @@ QString QgsPostgresRasterProvider::pkSql()
Q_ASSERT( ! mPrimaryKeyAttrs.isEmpty() );
if ( mPrimaryKeyAttrs.count( ) > 1 )
{
return mPrimaryKeyAttrs.join( ',' ).prepend( '(' ).append( ')' );
QStringList pkeys;
for ( const auto &k : qgis::as_const( mPrimaryKeyAttrs ) )
{
pkeys.push_back( quotedIdentifier( k ) );
}
return pkeys.join( ',' ).prepend( '(' ).append( ')' );
}
return mPrimaryKeyAttrs.first();
return quotedIdentifier( mPrimaryKeyAttrs.first() );
}


@@ -181,7 +181,7 @@ class QgsPostgresRasterProvider : public QgsRasterDataProvider
void determinePrimaryKeyFromUriKeyColumn();

/**
* Returns the SQL frament to retrieve the PK from the raster table
* Returns the quoted SQL frament to retrieve the PK from the raster table
*/
QString pkSql();

@@ -32,9 +32,10 @@
QgsRasterLayer,
QgsPointXY,
QgsRaster,
QgsProviderRegistry,
)
from qgis.testing import start_app, unittest
from utilities import unitTestDataPath
from utilities import unitTestDataPath, compareWkt

QGISAPP = start_app()
TEST_DATA_DIR = unitTestDataPath()
@@ -140,8 +141,10 @@ def testCompositeKey(self):
rl = QgsRasterLayer(self.dbconn + ' sslmode=disable srid=3035 table="public"."raster_3035_tiled_composite_pk"' +
'sql=', 'test', 'postgresraster')
self.assertTrue(rl.isValid())
data = rl.dataProvider().block(1, rl.extent(), 3, 3)
self.assertEqual(int(data.value(0, 0)), 142)

@unittest.skipIf(os.environ.get('TRAVIS', '') == 'true', 'Performance test is disabled in Travis environment')
@unittest.skip('Performance test is disabled in Travis environment')
def testSpeed(self):
"""Compare speed with GDAL provider, this test was used during development"""

@@ -151,7 +154,7 @@ def testSpeed(self):
speed_db='qgis_test'
)

table = 'eu_dem_tiled'
table = 'basic_map_tiled'
schema = 'public'

def _speed_check(schema, table, width, height):
@@ -195,6 +198,27 @@ def _speed_check(schema, table, width, height):

_speed_check(schema, table, 1000, 1000)

def testOtherSchema(self):
"""Test that a layer in a different schema than public can be loaded
See: GH #34823"""

postgres_conn = "service='qgis_test' sslmode=disable "
md = QgsProviderRegistry.instance().providerMetadata('postgres')
conn = md.createConnection(postgres_conn, {})

if 'idro' not in conn.schemas():
conn.executeSql('CREATE SCHEMA idro')

if 'cosmo_i5_snow' not in [n.tableName() for n in conn.tables('idro')]:
with open(os.path.join(TEST_DATA_DIR, 'provider', 'bug_34823_pg_raster.sql'), 'r') as f:
sql = f.read()
conn.executeSql(sql)
self.assertTrue('cosmo_i5_snow' in [n.tableName() for n in conn.tables('idro')])

rl = QgsRasterLayer(postgres_conn + "table={table} schema={schema}".format(table='cosmo_i5_snow', schema='idro'), 'pg_layer', 'postgresraster')
self.assertTrue(rl.isValid())
self.assertTrue(compareWkt(rl.extent().asWktPolygon(), 'POLYGON((-64.79286766849691048 -77.26689086732433509, -62.18292922825105506 -77.26689086732433509, -62.18292922825105506 -74.83694818157819384, -64.79286766849691048 -74.83694818157819384, -64.79286766849691048 -77.26689086732433509))'))


if __name__ == '__main__':
unittest.main()

0 comments on commit aee84a5

Please sign in to comment.
You can’t perform that action at this time.