Skip to content
Permalink
Browse files
Fix GPKG/SQLITE comments in query layers
Fix #45754
  • Loading branch information
elpaso authored and nyalldawson committed Nov 5, 2021
1 parent e5a8915 commit 9e3b3ec792b38600c3099d3b086e46a939535c2f
Showing with 59 additions and 3 deletions.
  1. +27 −3 src/core/providers/ogr/qgsogrproviderutils.cpp
  2. +32 −0 tests/src/python/test_provider_ogr_gpkg.py
@@ -1300,6 +1300,30 @@ QString QgsOgrProviderUtils::quotedValue( const QVariant &value )

OGRLayerH QgsOgrProviderUtils::setSubsetString( OGRLayerH layer, GDALDatasetH ds, QTextCodec *encoding, const QString &subsetString )
{
// Remove any comments
QStringList lines {subsetString.split( QChar( '\n' ) )};
lines.erase( std::remove_if( lines.begin(), lines.end(), []( const QString & line )
{
return line.startsWith( QStringLiteral( "--" ) );
} ), lines.end() );
for ( auto &line : lines )
{
bool inLiteral {false};
for ( int i = 0; i < line.length(); ++i )
{
if ( line[i] == QChar( '\'' ) && ( i == 0 || line[i - 1] != QChar( '\\' ) ) )
{
inLiteral = !inLiteral;
}
if ( !inLiteral && line.midRef( i ).startsWith( QStringLiteral( "--" ) ) )
{
line = line.left( i );
break;
}
}
}
const QString cleanedSubsetString {lines.join( QChar( ' ' ) ).trimmed() };

QByteArray layerName = OGR_FD_GetName( OGR_L_GetLayerDefn( layer ) );
GDALDriverH driver = GDALGetDatasetDriver( ds );
QString driverName = GDALGetDriverShortName( driver );
@@ -1315,16 +1339,16 @@ OGRLayerH QgsOgrProviderUtils::setSubsetString( OGRLayerH layer, GDALDatasetH ds
}
}
OGRLayerH subsetLayer = nullptr;
if ( subsetString.startsWith( QLatin1String( "SELECT " ), Qt::CaseInsensitive ) )
if ( cleanedSubsetString.startsWith( QLatin1String( "SELECT " ), Qt::CaseInsensitive ) )
{
QByteArray sql = encoding->fromUnicode( subsetString );
QByteArray sql = encoding->fromUnicode( cleanedSubsetString );

QgsDebugMsgLevel( QStringLiteral( "SQL: %1" ).arg( encoding->toUnicode( sql ) ), 2 );
subsetLayer = GDALDatasetExecuteSQL( ds, sql.constData(), nullptr, nullptr );
}
else
{
if ( OGR_L_SetAttributeFilter( layer, encoding->fromUnicode( subsetString ).constData() ) != OGRERR_NONE )
if ( OGR_L_SetAttributeFilter( layer, encoding->fromUnicode( cleanedSubsetString ).constData() ) != OGRERR_NONE )
{
return nullptr;
}
@@ -2338,6 +2338,38 @@ def testRejectedGeometryUpdate(self):
g = [f.geometry() for f in vl.getFeatures()][0]
self.assertEqual(g.asWkt(), 'Polygon ((0 0, 0 1, 1 1, 1 0, 0 0))')

def testSubsetComments(self):
"""Test issue GH #45754"""

tmp_dir = QTemporaryDir()
tmpfile = os.path.join(tmp_dir.path(), 'testSubsetComments.gpkg')
ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile)
lyr = ds.CreateLayer('my--test', geom_type=ogr.wkbPoint)
lyr.CreateField(ogr.FieldDefn('text_field', ogr.OFTString))
lyr.CreateField(ogr.FieldDefn('my--thing\'s', ogr.OFTString))
f = ogr.Feature(lyr.GetLayerDefn())
f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(0 0)'))
f['text_field'] = 'one'
f['my--thing\'s'] = 'one'
lyr.CreateFeature(f)
f = ogr.Feature(lyr.GetLayerDefn())
f['text_field'] = 'two'
f['my--thing\'s'] = 'my "things -- all'
f.SetGeometry(ogr.CreateGeometryFromWkt('POINT(1 1)'))
lyr.CreateFeature(f)
del (lyr)

def _test(subset_string):
vl1 = QgsVectorLayer(f'{tmpfile}|subset={subset_string}'.format(tmpfile, subset_string), 'test', 'ogr')
self.assertTrue(vl1.isValid())
self.assertEqual(vl1.featureCount(), 1)

_test('-- comment\n SELECT * --comment\nFROM "my--test" WHERE text_field=\'one\'')
_test('\n SELECT * --comment\nFROM "my--test" WHERE\n-- comment \ntext_field=\'one\'')
_test(' SELECT * --comment\nFROM "my--test" WHERE\ntext_field=\'one\' AND \ntext_field != \'--embedded comment\'')
_test('SELECT * FROM "my--test" WHERE text_field=\'one\' AND text_field != \' \\\'--embedded comment\'')
_test('select "my--thing\'s" from "my--test" where "my--thing\'s" = \'my "things -- all\'')

def testIsSqlQuery(self):
"""Test that isQuery returns what it should in case of simple filters"""

0 comments on commit 9e3b3ec

Please sign in to comment.