Skip to content
Permalink
Browse files

Connections API: add nativeTypes method

  • Loading branch information
elpaso committed Jul 14, 2020
1 parent 5d3201e commit d8a7531dc9ed9a7394194dcde06c9220e4c9df2e
@@ -516,6 +516,20 @@ Raises a QgsProviderConnectionException if any errors are encountered.

.. versionadded:: 3.16

:raises :: py:class:`QgsProviderConnectionException`
%End

virtual QList< QgsVectorDataProvider::NativeType > nativeTypes() const throw( QgsProviderConnectionException );
%Docstring
Returns a list of native types supported by the connection.

.. note::

if the database does not contain any table, a temporary table will
be created, in that case the correct user permissions might be required.

.. versionadded:: 3.16

:raises :: py:class:`QgsProviderConnectionException`
%End

@@ -16,6 +16,7 @@
#include "qgsabstractdatabaseproviderconnection.h"
#include "qgsvectorlayer.h"
#include "qgsexception.h"
#include "qgslogger.h"
#include <QVariant>
#include <QObject>

@@ -226,6 +227,101 @@ QgsAbstractDatabaseProviderConnection::TableProperty QgsAbstractDatabaseProvider
.arg( name, schema ) );
}

QList<QgsVectorDataProvider::NativeType> QgsAbstractDatabaseProviderConnection::nativeTypes() const
{
QList<QgsVectorDataProvider::NativeType> types;
static QAtomicInt tempTableNumber { 0 };
const int temporaryTableNumber = tempTableNumber++;
QString schemaName;
QString tableName;
QString temporarySchemaName;
QString temporaryTableName;
QStringList schemaList;

// Search for schemas
if ( mCapabilities.testFlag( QgsAbstractDatabaseProviderConnection::Capability::Schemas ) )
{
schemaList = schemas();
if ( schemaList.isEmpty() )
{
// Try to create one
temporarySchemaName = QStringLiteral( "qgis_temporary_schema_%1" ).arg( temporaryTableNumber );
try
{
createSchema( temporarySchemaName );
QgsDebugMsgLevel( QStringLiteral( "Temporary schema created: %1" ).arg( temporarySchemaName ), 2 );
schemaList.push_back( temporarySchemaName );
schemaName = temporarySchemaName;
}
catch ( QgsProviderConnectionException &ex )
{
throw QgsProviderConnectionException( QObject::tr( "Could not find an existing schema and could not create temporary schema '%1' for connection: %2" ).arg( schemaName, ex.what() ) );
}
}
}
else
{
schemaList.push_back( QStringLiteral( "dummy_schema" ) );
schemaName = schemaList.first();
}

// Search for tables
for ( const auto &sch : qgis::as_const( schemaList ) )
{
const auto tableList { tables( sch, { QgsAbstractDatabaseProviderConnection::TableFlag::Vector | QgsAbstractDatabaseProviderConnection::TableFlag::Aspatial } ) };
if ( !tableList.isEmpty() )
{
schemaName = sch;
tableName = tableList.first().tableName();
break;
}
}

if ( schemaName.isEmpty() )
{
schemaName = schemaList.first();
}

// Create a temporary table
if ( tableName.isEmpty() )
{
temporaryTableName = QStringLiteral( "qgis_temporary_table_%1" ).arg( temporaryTableNumber );
try
{
createVectorTable( schemaName, temporaryTableName, QgsFields(), QgsWkbTypes::NoGeometry, QgsCoordinateReferenceSystem(), false, {} );
QgsDebugMsgLevel( QStringLiteral( "Temporary table created: %1" ).arg( tableName ), 2 );
tableName = temporaryTableName;
}
catch ( QgsProviderConnectionException &ex )
{
if ( ! temporarySchemaName.isEmpty() )
{
dropSchema( temporarySchemaName, true );
}
throw QgsProviderConnectionException( QObject::tr( "Could not find an existing table and could not create temporary table '%1' for connection: %2" ).arg( temporaryTableName, ex.what() ) );
}
}

QgsVectorLayer::LayerOptions options {false, false };
options.skipCrsValidation = true;
QgsVectorLayer vl { tableUri( schemaName, tableName ), QStringLiteral( "temp_layer" ), providerKey(), options };
if ( vl.isValid() )
{
types = vl.dataProvider()->nativeTypes();
}

// Cleanup
if ( !temporarySchemaName.isEmpty() )
{
dropSchema( temporarySchemaName, true );
}
else if ( ! temporaryTableName.isEmpty() )
{
dropVectorTable( schemaName, tableName );
}
return types;
}

QList<QgsAbstractDatabaseProviderConnection::TableProperty> QgsAbstractDatabaseProviderConnection::tablesInt( const QString &schema, const int flags ) const
{
return tables( schema, static_cast<QgsAbstractDatabaseProviderConnection::TableFlags>( flags ) );
@@ -21,6 +21,7 @@
#include "qgis_core.h"
#include "qgsfields.h"
#include "qgsexception.h"
#include "qgsvectordataprovider.h"

#include <QObject>

@@ -533,6 +534,15 @@ class CORE_EXPORT QgsAbstractDatabaseProviderConnection : public QgsAbstractProv
*/
virtual QgsFields fields( const QString &schema, const QString &table ) const SIP_THROW( QgsProviderConnectionException );

/**
* Returns a list of native types supported by the connection.
* \note if the database does not contain any table, a temporary table will
* be created, in that case the correct user permissions might be required.
* \since QGIS 3.16
* \throws QgsProviderConnectionException
*/
virtual QList< QgsVectorDataProvider::NativeType > nativeTypes() const SIP_THROW( QgsProviderConnectionException );

/**
* Returns the provider key
* \since QGIS 3.16
@@ -401,3 +401,13 @@ def test_connections(self):
self.assertEqual(len(changed_spy), 1)

self._test_operations(md, conn)

def test_native_types(self):
"""Test native types retrieval"""

md = QgsProviderRegistry.instance().providerMetadata(self.providerKey)
conn = md.createConnection(self.uri, {})
native_types = conn.nativeTypes()
names = [nt.mTypeName.lower() for nt in native_types]
self.assertTrue('integer' in names or 'decimal' in names, names)
self.assertTrue('string' in names or 'text' in names, names)

0 comments on commit d8a7531

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