QGIS API Documentation 3.99.0-Master (21b3aa880ba)
Loading...
Searching...
No Matches
qgsalgorithmexporttospatialite.cpp
Go to the documentation of this file.
1
2/***************************************************************************
3 qgsalgorithmexporttospatialite.cpp
4 ---------------------
5 begin : April 2025
6 copyright : (C) 2025 by Alexander Bruy
7 email : alexander dot bruy at gmail dot com
8 ***************************************************************************/
9
10/***************************************************************************
11 * *
12 * This program is free software; you can redistribute it and/or modify *
13 * it under the terms of the GNU General Public License as published by *
14 * the Free Software Foundation; either version 2 of the License, or *
15 * (at your option) any later version. *
16 * *
17 ***************************************************************************/
18
20
22#include "qgsprovidermetadata.h"
23#include "qgsproviderregistry.h"
25
27
28QString QgsExportToSpatialiteAlgorithm::name() const
29{
30 return QStringLiteral( "importintospatialite" );
31}
32
33QString QgsExportToSpatialiteAlgorithm::displayName() const
34{
35 return QObject::tr( "Export to SpatiaLite" );
36}
37
38QStringList QgsExportToSpatialiteAlgorithm::tags() const
39{
40 return QObject::tr( "export,import,spatialite,table,layer,into,copy" ).split( ',' );
41}
42
43QString QgsExportToSpatialiteAlgorithm::group() const
44{
45 return QObject::tr( "Database" );
46}
47
48QString QgsExportToSpatialiteAlgorithm::groupId() const
49{
50 return QStringLiteral( "database" );
51}
52
53QString QgsExportToSpatialiteAlgorithm::shortHelpString() const
54{
55 return QObject::tr( "This algorithm exports a vector layer to a SpatiaLite database, creating a new table." );
56}
57
58QString QgsExportToSpatialiteAlgorithm::shortDescription() const
59{
60 return QObject::tr( "Exports a vector layer to a SpatiaLite database, creating a new table." );
61}
62
63QgsExportToSpatialiteAlgorithm *QgsExportToSpatialiteAlgorithm::createInstance() const
64{
65 return new QgsExportToSpatialiteAlgorithm();
66}
67
68void QgsExportToSpatialiteAlgorithm::initAlgorithm( const QVariantMap & )
69{
70 addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Layer to export" ), QList<int>() << static_cast<int>( Qgis::ProcessingSourceType::Vector ) ) );
71 addParameter( new QgsProcessingParameterVectorLayer( QStringLiteral( "DATABASE" ), QObject::tr( "Database layer (or file)" ), QList<int>() << static_cast<int>( Qgis::ProcessingSourceType::Vector ) ) );
72 addParameter( new QgsProcessingParameterString( QStringLiteral( "TABLENAME" ), QObject::tr( "Table to export to (leave blank to use layer name)" ), QVariant(), false, true ) );
73 addParameter( new QgsProcessingParameterField( QStringLiteral( "PRIMARY_KEY" ), QObject::tr( "Primary key field" ), QVariant(), QStringLiteral( "INPUT" ), Qgis::ProcessingFieldParameterDataType::Any, false, true ) );
74 addParameter( new QgsProcessingParameterString( QStringLiteral( "GEOMETRY_COLUMN" ), QObject::tr( "Geometry column" ), QStringLiteral( "geom" ) ) );
75 addParameter( new QgsProcessingParameterString( QStringLiteral( "ENCODING" ), QObject::tr( "Encoding" ), QStringLiteral( "UTF-8" ), false, true ) );
76 addParameter( new QgsProcessingParameterBoolean( QStringLiteral( "OVERWRITE" ), QObject::tr( "Overwrite" ), true ) );
77 addParameter( new QgsProcessingParameterBoolean( QStringLiteral( "CREATEINDEX" ), QObject::tr( "Create spatial index" ), true ) );
78 addParameter( new QgsProcessingParameterBoolean( QStringLiteral( "LOWERCASE_NAMES" ), QObject::tr( "Convert field names to lowercase" ), true ) );
79 addParameter( new QgsProcessingParameterBoolean( QStringLiteral( "DROP_STRING_LENGTH" ), QObject::tr( "Drop length constraints on character fields" ), false ) );
80 addParameter( new QgsProcessingParameterBoolean( QStringLiteral( "FORCE_SINGLEPART" ), QObject::tr( "Create single-part geometries instead of multipart" ), false ) );
81}
82
83bool QgsExportToSpatialiteAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback * )
84{
85 QgsVectorLayer *layer = parameterAsVectorLayer( parameters, QStringLiteral( "DATABASE" ), context );
86 mProviderType = layer->providerType();
87 mDatabaseUri = layer->dataProvider()->dataSourceUri();
88 return true;
89}
90
91QVariantMap QgsExportToSpatialiteAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
92{
93 std::unique_ptr<QgsProcessingFeatureSource> source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
94 if ( !source )
95 throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT" ) ) );
96
97 QgsDataSourceUri uri( mDatabaseUri );
98 if ( uri.database().isEmpty() )
99 {
101 const QVariantMap parts = md->decodeUri( mDatabaseUri );
102 mDatabaseUri = parts.value( QStringLiteral( "path" ) ).toString();
103 uri = QgsDataSourceUri( QStringLiteral( "dbname='%1'" ).arg( mDatabaseUri ) );
104 }
105
106 std::unique_ptr<QgsAbstractDatabaseProviderConnection> conn;
107 try
108 {
109 QgsProviderMetadata *md = QgsProviderRegistry::instance()->providerMetadata( QStringLiteral( "spatialite" ) );
110 conn.reset( static_cast<QgsAbstractDatabaseProviderConnection *>( md->createConnection( uri.uri(), QVariantMap() ) ) );
111 }
113 {
114 throw QgsProcessingException( QObject::tr( "Could not connect to %1" ).arg( uri.uri() ) );
115 }
116
117 const QString primaryKeyField = parameterAsString( parameters, QStringLiteral( "PRIMARY_KEY" ), context );
118 const QString encoding = parameterAsString( parameters, QStringLiteral( "ENCODING" ), context );
119 const bool overwrite = parameterAsBoolean( parameters, QStringLiteral( "OVERWRITE" ), context );
120
121 QString tableName = parameterAsDatabaseTableName( parameters, QStringLiteral( "TABLENAME" ), context ).trimmed();
122 if ( tableName.isEmpty() )
123 {
124 tableName = source->sourceName();
125 tableName = tableName.replace( '.', '_' );
126 }
127 tableName = tableName.replace( ' ', QString() ).right( 63 );
128
129 QString geometryColumn = parameterAsString( parameters, QStringLiteral( "GEOMETRY_COLUMN" ), context );
130 if ( geometryColumn.isEmpty() )
131 {
132 geometryColumn = QStringLiteral( "geom" );
133 }
134 if ( source->wkbType() == Qgis::WkbType::NoGeometry )
135 {
136 geometryColumn.clear();
137 }
138
139 const bool createSpatialIndex = parameterAsBoolean( parameters, QStringLiteral( "CREATEINDEX" ), context );
140
141 QMap<QString, QVariant> options;
142 if ( overwrite )
143 {
144 options[QStringLiteral( "overwrite" )] = true;
145 }
146 if ( parameterAsBoolean( parameters, QStringLiteral( "LOWERCASE_NAMES" ), context ) )
147 {
148 options[QStringLiteral( "lowercaseFieldNames" )] = true;
149 geometryColumn = geometryColumn.toLower();
150 }
151 if ( parameterAsBoolean( parameters, QStringLiteral( "DROP_STRING_LENGTH" ), context ) )
152 {
153 options[QStringLiteral( "dropStringConstraints" )] = true;
154 }
155 if ( parameterAsBoolean( parameters, QStringLiteral( "FORCE_SINGLEPART" ), context ) )
156 {
157 options[QStringLiteral( "forceSinglePartGeometryType" )] = true;
158 }
159 if ( !encoding.isEmpty() )
160 {
161 options[QStringLiteral( "fileEncoding" )] = encoding;
162 }
163
164 uri = QgsDataSourceUri( conn->uri() );
165 uri.setTable( tableName );
166 uri.setKeyColumn( primaryKeyField );
167 uri.setGeometryColumn( geometryColumn );
168
169 auto exporter = std::make_unique<QgsVectorLayerExporter>( uri.uri(), QStringLiteral( "spatialite" ), source->fields(), source->wkbType(), source->sourceCrs(), overwrite, options );
170
171 if ( exporter->errorCode() != Qgis::VectorExportResult::Success )
172 throw QgsProcessingException( QObject::tr( "Error exporting to SpatiaLite\n%1" ).arg( exporter->errorMessage() ) );
173
174 QgsFeatureIterator featureIterator = source->getFeatures();
175
176 const double step = source->featureCount() > 0 ? 100.0 / source->featureCount() : 0.0;
177
178 long long i = 0;
179 QgsFeature f;
180 while ( featureIterator.nextFeature( f ) )
181 {
182 if ( feedback->isCanceled() )
183 {
184 break;
185 }
186
187 if ( !exporter->addFeature( f, QgsFeatureSink::FastInsert ) )
188 {
189 feedback->reportError( exporter->errorMessage() );
190 }
191
192 feedback->setProgress( i * step );
193 i++;
194 }
195 exporter->flushBuffer();
196
197 if ( exporter->errorCode() != Qgis::VectorExportResult::Success )
198 throw QgsProcessingException( QObject::tr( "Error exporting to SpatiaLite\n%1" ).arg( exporter->errorMessage() ) );
199
200 exporter.reset();
201
202 if ( !geometryColumn.isEmpty() && createSpatialIndex )
203 {
204 try
205 {
207 opt.geometryColumnName = geometryColumn;
208 conn->createSpatialIndex( "", tableName, opt );
209 }
211 {
212 throw QgsProcessingException( QObject::tr( "Error creating spatial index:\n%1" ).arg( e.what() ) );
213 }
214 }
215
216 try
217 {
218 conn->vacuum( "", tableName );
219 }
221 {
222 feedback->reportError( QObject::tr( "Error vacuuming table:\n%1" ).arg( e.what() ) );
223 }
224
225 QVariantMap outputs;
226 return outputs;
227}
228
@ Vector
Tables (i.e. vector layers with or without geometry). When used for a sink this indicates the sink ha...
Definition qgis.h:3539
@ Success
No errors were encountered.
Definition qgis.h:1053
@ NoGeometry
No geometry.
Definition qgis.h:294
Provides common functionality for database based connections.
virtual QString dataSourceUri(bool expandAuthConfig=false) const
Gets the data source specification.
Stores the component parts of a data source URI (e.g.
QString what() const
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
Fetch next feature and stores in f, returns true on success.
@ FastInsert
Use faster inserts, at the cost of updating the passed features to reflect changes made at the provid...
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition qgsfeature.h:58
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition qgsfeedback.h:53
void setProgress(double progress)
Sets the current progress for the feedback object.
Definition qgsfeedback.h:61
QString providerType() const
Returns the provider type (provider key) for this layer.
Contains information about the context in which a processing algorithm is executed.
Custom exception class for processing related exceptions.
Base class for providing feedback from a processing algorithm.
virtual void reportError(const QString &error, bool fatalError=false)
Reports that the algorithm encountered an error while executing.
A boolean parameter for processing algorithms.
An input feature source (such as vector layers) parameter for processing algorithms.
A vector layer or feature source field parameter for processing algorithms.
A string parameter for processing algorithms.
A vector layer (with or without geometry) parameter for processing algorithms.
Custom exception class for provider connection related exceptions.
Holds data provider key, description, and associated shared library file or function pointer informat...
virtual QgsAbstractProviderConnection * createConnection(const QString &uri, const QVariantMap &configuration)
Creates a new connection from uri and configuration, the newly created connection is not automaticall...
virtual QVariantMap decodeUri(const QString &uri) const
Breaks a provider data source URI into its component paths (e.g.
static QgsProviderRegistry * instance(const QString &pluginPath=QString())
Means of accessing canonical single instance.
QgsProviderMetadata * providerMetadata(const QString &providerKey) const
Returns metadata of the provider or nullptr if not found.
Represents a vector layer which manages a vector based dataset.
QgsVectorDataProvider * dataProvider() final
Returns the layer's data provider, it may be nullptr.
The SpatialIndexOptions contains extra options relating to spatial index creation.
QString geometryColumnName
Specifies the name of the geometry column to create the index for.