Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[Oracle] Fix create layer with lowercase and large field names
  • Loading branch information
troopa81 authored and nyalldawson committed Feb 19, 2021
1 parent b1067af commit 1ffbb78
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 1 deletion.
7 changes: 7 additions & 0 deletions src/core/qgsvectorlayerexporter.cpp
Expand Up @@ -139,6 +139,13 @@ QgsVectorLayerExporter::QgsVectorLayerExporter( const QString &uri,
}
}

// Oracle specific HACK: we cannot guess the geometry type when there is no rows, so we need
// to force it in the uri
if ( providerKey == QLatin1String( "oracle" ) )
{
uriUpdated += QStringLiteral( " type=%1" ).arg( QgsWkbTypes::displayString( geometryType ) );
}

QgsDataProvider::ProviderOptions providerOptions;
QgsVectorDataProvider *vectorProvider = qobject_cast< QgsVectorDataProvider * >( pReg->createProvider( providerKey, uriUpdated, providerOptions ) );
if ( !vectorProvider || !vectorProvider->isValid() || ( vectorProvider->capabilities() & QgsVectorDataProvider::AddFeatures ) == 0 )
Expand Down
9 changes: 8 additions & 1 deletion src/providers/oracle/qgsoracleprovider.cpp
Expand Up @@ -3091,6 +3091,9 @@ QgsVectorLayerExporter::ExportError QgsOracleProvider::createEmptyLayer(
// use the provider to edit the table1
dsUri.setDataSource( ownerName, tableName, geometryColumn, QString(), primaryKey );

// provider cannot guess the type when there is no feature, so force the wkbtype in the uri
dsUri.setWkbType( wkbType );

QgsDataProvider::ProviderOptions providerOptions;
std::unique_ptr<QgsOracleProvider> provider( new QgsOracleProvider( dsUri.uri( false ), providerOptions ) );
if ( !provider->isValid() )
Expand All @@ -3114,7 +3117,7 @@ QgsVectorLayerExporter::ExportError QgsOracleProvider::createEmptyLayer(
{
QgsField fld = fields.at( i );

QString name = fld.name().left( 30 ).toUpper();
QString name = fld.name();

if ( names.contains( name ) )
{
Expand Down Expand Up @@ -3268,6 +3271,10 @@ void QgsOracleProvider::insertGeomMetadata( QgsOracleConn *conn, const QString &
}
}

if ( tableName.toUpper() != tableName || geometryColumn.toUpper() != geometryColumn )
throw OracleException( tr( "Cannot insert geometry metadata for table '%1' and geometry column '%2'. Both needs to be uppercase" ).arg(
tableName, geometryColumn ), qry );

if ( !exec( qry, QStringLiteral( "INSERT INTO mdsys.user_sdo_geom_metadata(table_name,column_name,srid,diminfo) VALUES (?,?,?,%1)" ).arg( diminfo ),
QVariantList() << tableName.toUpper() << geometryColumn.toUpper() << srid ) )
{
Expand Down
63 changes: 63 additions & 0 deletions tests/src/python/test_provider_oracle.py
Expand Up @@ -951,6 +951,69 @@ def countFeature(table_name):
self.assertTrue(vl.dataProvider().addFeatures([feature])[0])
self.assertEqual(countFeature('EMPTYFEATURE_NOGEOM_LAYER'), 1)

def testCreateLayerLongFieldNames(self):
"""
Test to create an empty layer with long field names
"""

# cleanup (it seems overwrite option doesn't clean the sdo_geom_metadata table)
self.execSQLCommand('DROP TABLE "QGIS"."LONGFIELD_LAYER"', ignore_errors=True)

long_name = "this_is_a_very_long_field_name_more_than_30_characters"

fields = QgsFields()
fields.append(QgsField(long_name, QVariant.Int))

uri = self.dbconn + "table=\"LONGFIELD_LAYER\""
exporter = QgsVectorLayerExporter(uri=uri, provider='oracle', fields=fields, geometryType=QgsWkbTypes.Point, crs=QgsCoordinateReferenceSystem("EPSG:4326"), overwrite=True)
self.assertEqual(exporter.errorCount(), 0)
self.assertEqual(exporter.errorCode(), 0)

self.execSQLCommand('SELECT count(*) FROM "QGIS"."LONGFIELD_LAYER"')
vl = QgsVectorLayer(self.dbconn + ' sslmode=disable table="QGIS"."LONGFIELD_LAYER" sql=', 'test', 'oracle')
self.assertTrue(vl.isValid())

self.assertEqual(vl.fields().names(), [long_name])

def testCreateGeomLowercase(self):
"""
Test to create an empty layer with either table or geometry column in lower case. It has to fail
"""

# table is lower case -> fails
self.execSQLCommand('DROP TABLE "QGIS"."lowercase_layer"', ignore_errors=True)

fields = QgsFields()
fields.append(QgsField("test", QVariant.Int))

uri = self.dbconn + "table=\"lowercase_layer\" (GEOM)"
exporter = QgsVectorLayerExporter(uri=uri, provider='oracle', fields=fields, geometryType=QgsWkbTypes.Point, crs=QgsCoordinateReferenceSystem("EPSG:4326"), overwrite=True)
self.assertEqual(exporter.errorCode(), 2)

# geom column is lower case -> fails
self.execSQLCommand('DROP TABLE "QGIS"."LOWERCASEGEOM_LAYER"', ignore_errors=True)

fields = QgsFields()
fields.append(QgsField("test", QVariant.Int))

uri = self.dbconn + "table=\"LOWERCASEGEOM\" (geom)"
exporter = QgsVectorLayerExporter(uri=uri, provider='oracle', fields=fields, geometryType=QgsWkbTypes.Point, crs=QgsCoordinateReferenceSystem("EPSG:4326"), overwrite=True)
self.assertEqual(exporter.errorCode(), 2)

# table and geom column are uppercase -> success
self.execSQLCommand('DROP TABLE "QGIS"."UPPERCASEGEOM_LAYER"', ignore_errors=True)
self.execSQLCommand("""DELETE FROM user_sdo_geom_metadata where TABLE_NAME = 'UPPERCASEGEOM_LAYER'""")

fields = QgsFields()
fields.append(QgsField("test", QVariant.Int))

uri = self.dbconn + "table=\"UPPERCASEGEOM_LAYER\" (GEOM)"

exporter = QgsVectorLayerExporter(uri=uri, provider='oracle', fields=fields, geometryType=QgsWkbTypes.Point, crs=QgsCoordinateReferenceSystem("EPSG:4326"), overwrite=True)
print(exporter.errorMessage())
self.assertEqual(exporter.errorCount(), 0)
self.assertEqual(exporter.errorCode(), 0)


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

0 comments on commit 1ffbb78

Please sign in to comment.