Merge pull request #8630 from elpaso/bugfix-20674-db-manager-sqlite-aliased-queries

sqlite accept aliased queries from db manager
This commit is contained in:
Alessandro Pasotti 2018-12-10 08:39:44 +01:00 committed by GitHub
commit cf0442dac6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 32 additions and 8 deletions

View File

@ -147,13 +147,13 @@ class DlgSqlLayerWindow(QWidget, Ui_Dialog):
# Update from layer
# First the SQL from QgsDataSourceUri table
sql = uri.table()
sql = uri.table().replace('\n', ' ').strip()
if uri.keyColumn() == '_uid_':
match = re.search(r'^\(SELECT .+ AS _uid_,\* FROM \((.*)\) AS _subq_.+_\s*\)$', sql, re.S | re.X)
match = re.search(r'^\(SELECT .+ AS _uid_,\* FROM \((.*)\) AS _subq_.+_\s*\)$', sql, re.S | re.X | re.IGNORECASE)
if match:
sql = match.group(1)
else:
match = re.search(r'^\((SELECT .+ FROM .+)\)$', sql, re.S | re.X)
match = re.search(r'^\((SELECT .+ FROM .+)\)$', sql, re.S | re.X | re.IGNORECASE)
if match:
sql = match.group(1)
# Need to check on table() since the parentheses were removed by the regexp

View File

@ -602,7 +602,7 @@ class DlgSqlWindow(QWidget, Ui_Dialog):
def _getSqlQuery(self):
sql = self.editSql.selectedText()
if len(sql) == 0:
sql = self.editSql.text()
sql = self.editSql.text().replace('\n', ' ').strip()
return sql
def uniqueChanged(self):

View File

@ -4603,9 +4603,21 @@ bool QgsSpatiaLiteProvider::checkLayerType()
// 3. check if ROWID injection works
if ( ! queryGeomTableName.isEmpty() )
{
// Check if the whole sql is aliased (I couldn't find a sqlite API call to get this information)
QRegularExpression re { R"re(\s+AS\s+(\w+)\n?\)?$)re" };
re.setPatternOptions( QRegularExpression::PatternOption::MultilineOption |
QRegularExpression::PatternOption::CaseInsensitiveOption );
QRegularExpressionMatch match { re.match( mTableName ) };
regex.setPattern( QStringLiteral( R"re(\s+AS\s+(\w+)\n?\)?$)re" ) );
QString tableAlias;
if ( match.hasMatch() )
{
tableAlias = match.captured( 1 );
}
QString newSql( mQuery.replace( QStringLiteral( "SELECT " ),
QStringLiteral( "SELECT %1.%2, " )
.arg( quotedIdentifier( queryGeomTableName ), QStringLiteral( "ROWID" ) ),
.arg( quotedIdentifier( tableAlias.isEmpty() ? queryGeomTableName : tableAlias ),
QStringLiteral( "ROWID" ) ),
Qt::CaseInsensitive ) );
sql = QStringLiteral( "SELECT ROWID FROM %1 WHERE ROWID IS NOT NULL LIMIT 1" ).arg( newSql );
ret = sqlite3_get_table( mSqliteHandle, sql.toUtf8().constData(), &results, &rows, &columns, &errMsg );

View File

@ -654,14 +654,14 @@ class TestQgsSpatialiteProvider(unittest.TestCase, ProviderTestCase):
f = QgsVectorLayerUtils.createFeature(vl)
self.assertEqual(f.attributes(), [None, "qgis 'is good", 5, 5.7, None])
# check that provider default literals take precedence over passed attribute values
# check that provider default literals do not take precedence over passed attribute values
f = QgsVectorLayerUtils.createFeature(vl, attributes={1: 'qgis is great', 0: 3})
self.assertEqual(f.attributes(), [3, "qgis 'is good", 5, 5.7, None])
self.assertEqual(f.attributes(), [3, "qgis is great", 5, 5.7, None])
# test that vector layer default value expression overrides provider default literal
vl.setDefaultValueDefinition(3, QgsDefaultValue("4*3"))
f = QgsVectorLayerUtils.createFeature(vl, attributes={1: 'qgis is great', 0: 3})
self.assertEqual(f.attributes(), [3, "qgis 'is good", 5, 12, None])
self.assertEqual(f.attributes(), [3, "qgis is great", 5, 12, None])
def testCreateAttributeIndex(self):
vl = QgsVectorLayer("dbname=%s table='test_defaults' key='id'" % self.dbname, "test_defaults", "spatialite")
@ -848,6 +848,18 @@ class TestQgsSpatialiteProvider(unittest.TestCase, ProviderTestCase):
self.assertTrue(vl_no_pk.isValid())
_check_features(vl_no_pk, 10)
def testAliasedQueries(self):
"""Test regression when sending queries with aliased tables from DB manager"""
def _test(sql):
vl = QgsVectorLayer('dbname=\'{}/provider/spatialite.db\' table="{}" (geom) sql='.format(TEST_DATA_DIR, sql), 'test', 'spatialite')
self.assertTrue(vl.isValid())
_test("(SELECT * FROM somedata as my_alias\n)")
_test("(SELECT * FROM somedata as my_alias)")
_test("(SELECT * FROM somedata AS my_alias)")
_test('(SELECT * FROM \\"somedata\\" as my_alias\n)')
if __name__ == '__main__':
unittest.main()