Branch data Line data Source code
1 : : /***************************************************************************
2 : : qgsabstractdatabaseproviderconnection.cpp - QgsAbstractDatabaseProviderConnection
3 : :
4 : : ---------------------
5 : : begin : 2.8.2019
6 : : copyright : (C) 2019 by Alessandro Pasotti
7 : : email : elpaso at itopen dot it
8 : : ***************************************************************************
9 : : * *
10 : : * This program is free software; you can redistribute it and/or modify *
11 : : * it under the terms of the GNU General Public License as published by *
12 : : * the Free Software Foundation; either version 2 of the License, or *
13 : : * (at your option) any later version. *
14 : : * *
15 : : ***************************************************************************/
16 : : #include "qgsabstractdatabaseproviderconnection.h"
17 : : #include "qgsvectorlayer.h"
18 : : #include "qgsexception.h"
19 : : #include "qgslogger.h"
20 : : #include "qgsfeedback.h"
21 : :
22 : : #include <QVariant>
23 : : #include <QObject>
24 : :
25 : 0 : QgsAbstractDatabaseProviderConnection::QgsAbstractDatabaseProviderConnection( const QString &name ):
26 : 0 : QgsAbstractProviderConnection( name )
27 : 0 : {
28 : :
29 : 0 : }
30 : :
31 : 0 : QgsAbstractDatabaseProviderConnection::QgsAbstractDatabaseProviderConnection( const QString &uri, const QVariantMap &configuration ):
32 : 0 : QgsAbstractProviderConnection( uri, configuration )
33 : 0 : {
34 : :
35 : 0 : }
36 : 0 : QgsAbstractDatabaseProviderConnection::Capabilities QgsAbstractDatabaseProviderConnection::capabilities() const
37 : : {
38 : 0 : return mCapabilities;
39 : : }
40 : :
41 : 0 : QgsAbstractDatabaseProviderConnection::GeometryColumnCapabilities QgsAbstractDatabaseProviderConnection::geometryColumnCapabilities()
42 : : {
43 : 0 : return mGeometryColumnCapabilities;
44 : : }
45 : :
46 : 0 : QString QgsAbstractDatabaseProviderConnection::tableUri( const QString &schema, const QString &name ) const
47 : : {
48 : 0 : Q_UNUSED( schema )
49 : 0 : Q_UNUSED( name )
50 : 0 : throw QgsProviderConnectionException( QObject::tr( "Operation 'tableUri' is not supported" ) );
51 : 0 : }
52 : :
53 : : ///@cond PRIVATE
54 : 0 : void QgsAbstractDatabaseProviderConnection::checkCapability( QgsAbstractDatabaseProviderConnection::Capability capability ) const
55 : : {
56 : 0 : if ( ! mCapabilities.testFlag( capability ) )
57 : : {
58 : 0 : static QMetaEnum metaEnum = QMetaEnum::fromType<QgsAbstractDatabaseProviderConnection::Capability>();
59 : 0 : const QString capName { metaEnum.valueToKey( capability ) };
60 : 0 : throw QgsProviderConnectionException( QObject::tr( "Operation '%1' is not supported for this connection" ).arg( capName ) );
61 : 0 : }
62 : 0 : }
63 : :
64 : 0 : QString QgsAbstractDatabaseProviderConnection::providerKey() const
65 : : {
66 : 0 : return mProviderKey;
67 : : }
68 : : ///@endcond
69 : :
70 : 0 : void QgsAbstractDatabaseProviderConnection::createVectorTable( const QString &schema,
71 : : const QString &name,
72 : : const QgsFields &fields,
73 : : QgsWkbTypes::Type wkbType,
74 : : const QgsCoordinateReferenceSystem &srs,
75 : : bool overwrite,
76 : : const QMap<QString, QVariant> *
77 : : options ) const
78 : : {
79 : 0 : Q_UNUSED( schema );
80 : 0 : Q_UNUSED( name );
81 : 0 : Q_UNUSED( fields );
82 : 0 : Q_UNUSED( srs );
83 : : Q_UNUSED( overwrite );
84 : : Q_UNUSED( options );
85 : : Q_UNUSED( wkbType );
86 : 0 : throw QgsProviderConnectionException( QObject::tr( "Operation 'createVectorTable' is not supported" ) );
87 : 0 : }
88 : :
89 : 0 : void QgsAbstractDatabaseProviderConnection::renameVectorTable( const QString &, const QString &, const QString & ) const
90 : : {
91 : 0 : checkCapability( Capability::RenameVectorTable );
92 : 0 : }
93 : :
94 : 0 : void QgsAbstractDatabaseProviderConnection::renameRasterTable( const QString &, const QString &, const QString & ) const
95 : : {
96 : 0 : checkCapability( Capability::RenameRasterTable );
97 : 0 : }
98 : :
99 : 0 : void QgsAbstractDatabaseProviderConnection::dropVectorTable( const QString &, const QString & ) const
100 : : {
101 : 0 : checkCapability( Capability::DropVectorTable );
102 : 0 : }
103 : :
104 : 0 : bool QgsAbstractDatabaseProviderConnection::tableExists( const QString &schema, const QString &name ) const
105 : : {
106 : 0 : checkCapability( Capability::TableExists );
107 : 0 : const QList<QgsAbstractDatabaseProviderConnection::TableProperty> constTables { tables( schema ) };
108 : 0 : for ( const auto &t : constTables )
109 : : {
110 : 0 : if ( t.tableName() == name )
111 : : {
112 : 0 : return true;
113 : : }
114 : : }
115 : 0 : return false;
116 : 0 : }
117 : :
118 : 0 : void QgsAbstractDatabaseProviderConnection::dropRasterTable( const QString &, const QString & ) const
119 : : {
120 : 0 : checkCapability( Capability::DropRasterTable );
121 : 0 : }
122 : :
123 : 0 : void QgsAbstractDatabaseProviderConnection::createSchema( const QString & ) const
124 : : {
125 : 0 : checkCapability( Capability::CreateSchema );
126 : 0 : }
127 : :
128 : 0 : void QgsAbstractDatabaseProviderConnection::dropSchema( const QString &, bool ) const
129 : : {
130 : 0 : checkCapability( Capability::DropSchema );
131 : 0 : }
132 : :
133 : 0 : void QgsAbstractDatabaseProviderConnection::renameSchema( const QString &, const QString & ) const
134 : : {
135 : 0 : checkCapability( Capability::RenameSchema );
136 : 0 : }
137 : :
138 : 0 : QList<QList<QVariant>> QgsAbstractDatabaseProviderConnection::executeSql( const QString &sql, QgsFeedback *feedback ) const
139 : : {
140 : 0 : return execSql( sql, feedback ).rows();
141 : 0 : }
142 : :
143 : :
144 : 0 : QgsAbstractDatabaseProviderConnection::QueryResult QgsAbstractDatabaseProviderConnection::execSql( const QString &, QgsFeedback * ) const
145 : : {
146 : 0 : checkCapability( Capability::ExecuteSql );
147 : 0 : return QueryResult();
148 : : }
149 : :
150 : :
151 : 0 : void QgsAbstractDatabaseProviderConnection::vacuum( const QString &, const QString & ) const
152 : : {
153 : 0 : checkCapability( Capability::Vacuum );
154 : 0 : }
155 : :
156 : 0 : void QgsAbstractDatabaseProviderConnection::createSpatialIndex( const QString &, const QString &, const QgsAbstractDatabaseProviderConnection::SpatialIndexOptions & ) const
157 : : {
158 : 0 : checkCapability( Capability::CreateSpatialIndex );
159 : 0 : }
160 : :
161 : 0 : void QgsAbstractDatabaseProviderConnection::deleteSpatialIndex( const QString &, const QString &, const QString & ) const
162 : : {
163 : 0 : checkCapability( Capability::DeleteSpatialIndex );
164 : 0 : }
165 : :
166 : 0 : bool QgsAbstractDatabaseProviderConnection::spatialIndexExists( const QString &, const QString &, const QString & ) const
167 : : {
168 : 0 : checkCapability( Capability::SpatialIndexExists );
169 : 0 : return false;
170 : : }
171 : :
172 : 0 : void QgsAbstractDatabaseProviderConnection::deleteField( const QString &fieldName, const QString &schema, const QString &tableName, bool ) const
173 : : {
174 : 0 : checkCapability( Capability::DeleteField );
175 : :
176 : 0 : QgsVectorLayer::LayerOptions options { false, false };
177 : 0 : options.skipCrsValidation = true;
178 : 0 : std::unique_ptr<QgsVectorLayer> vl { std::make_unique<QgsVectorLayer>( tableUri( schema, tableName ), QStringLiteral( "temp_layer" ), mProviderKey, options ) };
179 : 0 : if ( ! vl->isValid() )
180 : : {
181 : 0 : throw QgsProviderConnectionException( QObject::tr( "Could not create a vector layer for table '%1' in schema '%2'" )
182 : 0 : .arg( tableName, schema ) );
183 : : }
184 : 0 : if ( vl->fields().lookupField( fieldName ) == -1 )
185 : : {
186 : 0 : throw QgsProviderConnectionException( QObject::tr( "Could not find field '%1' in table '%2' in schema '%3'" )
187 : 0 : .arg( fieldName, tableName, schema ) );
188 : :
189 : : }
190 : 0 : if ( ! vl->dataProvider()->deleteAttributes( { vl->fields().lookupField( fieldName ) } ) )
191 : : {
192 : 0 : throw QgsProviderConnectionException( QObject::tr( "Unknown error deleting field '%1' in table '%2' in schema '%3'" )
193 : 0 : .arg( fieldName, tableName, schema ) );
194 : : }
195 : 0 : }
196 : :
197 : 0 : void QgsAbstractDatabaseProviderConnection::addField( const QgsField &field, const QString &schema, const QString &tableName ) const
198 : : {
199 : 0 : checkCapability( Capability::AddField );
200 : :
201 : 0 : QgsVectorLayer::LayerOptions options { false, false };
202 : 0 : options.skipCrsValidation = true;
203 : 0 : std::unique_ptr<QgsVectorLayer> vl( std::make_unique<QgsVectorLayer>( tableUri( schema, tableName ), QStringLiteral( "temp_layer" ), mProviderKey, options ) );
204 : 0 : if ( ! vl->isValid() )
205 : : {
206 : 0 : throw QgsProviderConnectionException( QObject::tr( "Could not create a vector layer for table '%1' in schema '%2'" )
207 : 0 : .arg( tableName, schema ) );
208 : : }
209 : 0 : if ( vl->fields().lookupField( field.name() ) != -1 )
210 : : {
211 : 0 : throw QgsProviderConnectionException( QObject::tr( "Field '%1' in table '%2' in schema '%3' already exists" )
212 : 0 : .arg( field.name(), tableName, schema ) );
213 : :
214 : : }
215 : 0 : if ( ! vl->dataProvider()->addAttributes( { field } ) )
216 : : {
217 : 0 : throw QgsProviderConnectionException( QObject::tr( "Unknown error adding field '%1' in table '%2' in schema '%3'" )
218 : 0 : .arg( field.name(), tableName, schema ) );
219 : : }
220 : 0 : }
221 : :
222 : 0 : QList<QgsAbstractDatabaseProviderConnection::TableProperty> QgsAbstractDatabaseProviderConnection::tables( const QString &, const QgsAbstractDatabaseProviderConnection::TableFlags & ) const
223 : : {
224 : 0 : checkCapability( Capability::Tables );
225 : 0 : return QList<QgsAbstractDatabaseProviderConnection::TableProperty>();
226 : : }
227 : :
228 : :
229 : 0 : QgsAbstractDatabaseProviderConnection::TableProperty QgsAbstractDatabaseProviderConnection::table( const QString &schema, const QString &name ) const
230 : : {
231 : 0 : checkCapability( Capability::Tables );
232 : 0 : const QList<QgsAbstractDatabaseProviderConnection::TableProperty> constTables { tables( schema ) };
233 : 0 : for ( const auto &t : constTables )
234 : : {
235 : 0 : if ( t.tableName() == name )
236 : : {
237 : 0 : return t;
238 : : }
239 : : }
240 : 0 : throw QgsProviderConnectionException( QObject::tr( "Table '%1' was not found in schema '%2'" )
241 : 0 : .arg( name, schema ) );
242 : 0 : }
243 : :
244 : 0 : QList<QgsAbstractDatabaseProviderConnection::TableProperty> QgsAbstractDatabaseProviderConnection::tablesInt( const QString &schema, const int flags ) const
245 : : {
246 : 0 : return tables( schema, static_cast<QgsAbstractDatabaseProviderConnection::TableFlags>( flags ) );
247 : : }
248 : :
249 : :
250 : 0 : QStringList QgsAbstractDatabaseProviderConnection::schemas( ) const
251 : : {
252 : 0 : checkCapability( Capability::Schemas );
253 : 0 : return QStringList();
254 : : }
255 : :
256 : 0 : QString QgsAbstractDatabaseProviderConnection::TableProperty::tableName() const
257 : : {
258 : 0 : return mTableName;
259 : : }
260 : :
261 : 0 : void QgsAbstractDatabaseProviderConnection::TableProperty::setTableName( const QString &name )
262 : : {
263 : 0 : mTableName = name;
264 : 0 : }
265 : :
266 : 0 : void QgsAbstractDatabaseProviderConnection::TableProperty::addGeometryColumnType( const QgsWkbTypes::Type &type, const QgsCoordinateReferenceSystem &crs )
267 : : {
268 : : // Do not add the type if it's already present
269 : 0 : const QgsAbstractDatabaseProviderConnection::TableProperty::GeometryColumnType toAdd { type, crs };
270 : 0 : for ( const auto &t : std::as_const( mGeometryColumnTypes ) )
271 : : {
272 : 0 : if ( t == toAdd )
273 : : {
274 : 0 : return;
275 : : }
276 : : }
277 : 0 : mGeometryColumnTypes.push_back( toAdd );
278 : 0 : }
279 : :
280 : 0 : QList<QgsAbstractDatabaseProviderConnection::TableProperty::GeometryColumnType> QgsAbstractDatabaseProviderConnection::TableProperty::geometryColumnTypes() const
281 : : {
282 : 0 : return mGeometryColumnTypes;
283 : : }
284 : :
285 : 0 : QgsFields QgsAbstractDatabaseProviderConnection::fields( const QString &schema, const QString &tableName ) const
286 : : {
287 : 0 : QgsVectorLayer::LayerOptions options { false, true };
288 : 0 : options.skipCrsValidation = true;
289 : 0 : QgsVectorLayer vl { tableUri( schema, tableName ), QStringLiteral( "temp_layer" ), mProviderKey, options };
290 : 0 : if ( vl.isValid() )
291 : : {
292 : 0 : return vl.fields();
293 : : }
294 : : else
295 : : {
296 : 0 : throw QgsProviderConnectionException( QObject::tr( "Error retrieving fields information for uri: %1" ).arg( vl.publicSource() ) );
297 : : }
298 : 0 : }
299 : :
300 : 0 : QString QgsAbstractDatabaseProviderConnection::TableProperty::defaultName() const
301 : : {
302 : 0 : QString n = mTableName;
303 : 0 : if ( mGeometryColumnCount > 1 ) n += '.' + mGeometryColumn;
304 : 0 : return n;
305 : 0 : }
306 : :
307 : 0 : QgsAbstractDatabaseProviderConnection::TableProperty QgsAbstractDatabaseProviderConnection::TableProperty::at( int index ) const
308 : : {
309 : 0 : TableProperty property;
310 : :
311 : : Q_ASSERT( index >= 0 && index < mGeometryColumnTypes.size() );
312 : :
313 : 0 : property.mGeometryColumnTypes << mGeometryColumnTypes[ index ];
314 : 0 : property.mSchema = mSchema;
315 : 0 : property.mTableName = mTableName;
316 : 0 : property.mGeometryColumn = mGeometryColumn;
317 : 0 : property.mPkColumns = mPkColumns;
318 : 0 : property.mGeometryColumnCount = mGeometryColumnCount;
319 : 0 : property.mFlags = mFlags;
320 : 0 : property.mComment = mComment;
321 : 0 : property.mInfo = mInfo;
322 : 0 : return property;
323 : 0 : }
324 : :
325 : 0 : void QgsAbstractDatabaseProviderConnection::TableProperty::setFlag( const QgsAbstractDatabaseProviderConnection::TableFlag &flag )
326 : : {
327 : 0 : mFlags.setFlag( flag );
328 : 0 : }
329 : :
330 : 0 : int QgsAbstractDatabaseProviderConnection::TableProperty::maxCoordinateDimensions() const
331 : : {
332 : 0 : int res = 0;
333 : 0 : for ( const TableProperty::GeometryColumnType &ct : std::as_const( mGeometryColumnTypes ) )
334 : : {
335 : 0 : res = std::max( res, QgsWkbTypes::coordDimensions( ct.wkbType ) );
336 : : }
337 : 0 : return res;
338 : : }
339 : :
340 : 0 : bool QgsAbstractDatabaseProviderConnection::TableProperty::operator==( const QgsAbstractDatabaseProviderConnection::TableProperty &other ) const
341 : : {
342 : 0 : return mSchema == other.mSchema &&
343 : 0 : mTableName == other.mTableName &&
344 : 0 : mGeometryColumn == other.mGeometryColumn &&
345 : 0 : mGeometryColumnCount == other.mGeometryColumnCount &&
346 : 0 : mPkColumns == other.mPkColumns &&
347 : 0 : mFlags == other.mFlags &&
348 : 0 : mComment == other.mComment &&
349 : 0 : mInfo == other.mInfo;
350 : : }
351 : :
352 : :
353 : 0 : void QgsAbstractDatabaseProviderConnection::TableProperty::setGeometryColumnTypes( const QList<QgsAbstractDatabaseProviderConnection::TableProperty::GeometryColumnType> &columnTypes )
354 : : {
355 : 0 : mGeometryColumnTypes = columnTypes;
356 : 0 : }
357 : :
358 : :
359 : 0 : int QgsAbstractDatabaseProviderConnection::TableProperty::geometryColumnCount() const
360 : : {
361 : 0 : return mGeometryColumnCount;
362 : : }
363 : :
364 : 0 : void QgsAbstractDatabaseProviderConnection::TableProperty::setGeometryColumnCount( int geometryColumnCount )
365 : : {
366 : 0 : mGeometryColumnCount = geometryColumnCount;
367 : 0 : }
368 : :
369 : 0 : QVariantMap QgsAbstractDatabaseProviderConnection::TableProperty::info() const
370 : : {
371 : 0 : return mInfo;
372 : : }
373 : :
374 : 0 : void QgsAbstractDatabaseProviderConnection::TableProperty::setInfo( const QVariantMap &info )
375 : : {
376 : 0 : mInfo = info;
377 : 0 : }
378 : :
379 : 0 : QString QgsAbstractDatabaseProviderConnection::TableProperty::comment() const
380 : : {
381 : 0 : return mComment;
382 : : }
383 : :
384 : 0 : void QgsAbstractDatabaseProviderConnection::TableProperty::setComment( const QString &comment )
385 : : {
386 : 0 : mComment = comment;
387 : 0 : }
388 : :
389 : 0 : QgsAbstractDatabaseProviderConnection::TableFlags QgsAbstractDatabaseProviderConnection::TableProperty::flags() const
390 : : {
391 : 0 : return mFlags;
392 : : }
393 : :
394 : 0 : void QgsAbstractDatabaseProviderConnection::TableProperty::setFlags( const QgsAbstractDatabaseProviderConnection::TableFlags &flags )
395 : : {
396 : 0 : mFlags = flags;
397 : 0 : }
398 : :
399 : 0 : QList<QgsCoordinateReferenceSystem> QgsAbstractDatabaseProviderConnection::TableProperty::crsList() const
400 : : {
401 : 0 : QList<QgsCoordinateReferenceSystem> crss;
402 : 0 : for ( const auto &t : std::as_const( mGeometryColumnTypes ) )
403 : : {
404 : 0 : crss.push_back( t.crs );
405 : : }
406 : 0 : return crss;
407 : 0 : }
408 : :
409 : 0 : QStringList QgsAbstractDatabaseProviderConnection::TableProperty::primaryKeyColumns() const
410 : : {
411 : 0 : return mPkColumns;
412 : : }
413 : :
414 : 0 : void QgsAbstractDatabaseProviderConnection::TableProperty::setPrimaryKeyColumns( const QStringList &pkColumns )
415 : : {
416 : 0 : mPkColumns = pkColumns;
417 : 0 : }
418 : :
419 : 0 : QString QgsAbstractDatabaseProviderConnection::TableProperty::geometryColumn() const
420 : : {
421 : 0 : return mGeometryColumn;
422 : : }
423 : :
424 : 0 : void QgsAbstractDatabaseProviderConnection::TableProperty::setGeometryColumn( const QString &geometryColumn )
425 : : {
426 : 0 : mGeometryColumn = geometryColumn;
427 : 0 : }
428 : :
429 : 0 : QString QgsAbstractDatabaseProviderConnection::TableProperty::schema() const
430 : : {
431 : 0 : return mSchema;
432 : : }
433 : :
434 : 0 : void QgsAbstractDatabaseProviderConnection::TableProperty::setSchema( const QString &schema )
435 : : {
436 : 0 : mSchema = schema;
437 : 0 : }
438 : :
439 : :
440 : : ///@cond PRIVATE
441 : :
442 : 0 : QStringList QgsAbstractDatabaseProviderConnection::QueryResult::columns() const
443 : : {
444 : 0 : return mColumns;
445 : : }
446 : :
447 : 0 : QList<QList<QVariant> > QgsAbstractDatabaseProviderConnection::QueryResult::rows( QgsFeedback *feedback )
448 : : {
449 : :
450 : 0 : QList<QList<QVariant> > rows;
451 : :
452 : 0 : while ( mResultIterator &&
453 : 0 : mResultIterator->hasNextRow() &&
454 : 0 : ( ! feedback || ! feedback->isCanceled() ) )
455 : : {
456 : 0 : const QVariantList row( mResultIterator->nextRow() );
457 : 0 : if ( row.isEmpty() )
458 : : {
459 : 0 : break;
460 : : }
461 : : else
462 : : {
463 : 0 : rows.push_back( row );
464 : : }
465 : 0 : }
466 : 0 : return rows;
467 : 0 : }
468 : :
469 : 0 : QList<QVariant> QgsAbstractDatabaseProviderConnection::QueryResult::nextRow() const
470 : : {
471 : 0 : if ( ! mResultIterator )
472 : : {
473 : 0 : return QList<QVariant>();
474 : : }
475 : 0 : return mResultIterator->nextRow();
476 : 0 : }
477 : :
478 : :
479 : 0 : qlonglong QgsAbstractDatabaseProviderConnection::QueryResult::fetchedRowCount() const
480 : : {
481 : 0 : if ( ! mResultIterator )
482 : : {
483 : 0 : return 0;
484 : : }
485 : 0 : return mResultIterator->fetchedRowCount();
486 : 0 : }
487 : :
488 : :
489 : 0 : bool QgsAbstractDatabaseProviderConnection::QueryResult::hasNextRow() const
490 : : {
491 : 0 : if ( ! mResultIterator )
492 : : {
493 : 0 : return false;
494 : : }
495 : 0 : return mResultIterator->hasNextRow();
496 : 0 : }
497 : :
498 : 0 : void QgsAbstractDatabaseProviderConnection::QueryResult::appendColumn( const QString &columnName )
499 : : {
500 : 0 : mColumns.push_back( columnName );
501 : 0 : }
502 : :
503 : :
504 : 0 : QgsAbstractDatabaseProviderConnection::QueryResult::QueryResult( std::shared_ptr<QgsAbstractDatabaseProviderConnection::QueryResult::QueryResultIterator> iterator )
505 : 0 : : mResultIterator( iterator )
506 : 0 : {}
507 : :
508 : :
509 : 0 : QVariantList QgsAbstractDatabaseProviderConnection::QueryResult::QueryResultIterator::nextRow()
510 : : {
511 : 0 : QMutexLocker lock( &mMutex );
512 : 0 : const QVariantList row = nextRowPrivate();
513 : 0 : if ( ! row.isEmpty() )
514 : : {
515 : 0 : mFetchedRowCount++;
516 : 0 : }
517 : 0 : return row;
518 : 0 : }
519 : :
520 : 0 : bool QgsAbstractDatabaseProviderConnection::QueryResult::QueryResultIterator::hasNextRow() const
521 : : {
522 : 0 : QMutexLocker lock( &mMutex );
523 : 0 : return hasNextRowPrivate();
524 : 0 : }
525 : :
526 : 0 : qlonglong QgsAbstractDatabaseProviderConnection::QueryResult::QueryResultIterator::fetchedRowCount()
527 : : {
528 : 0 : QMutexLocker lock( &mMutex );
529 : 0 : return mFetchedRowCount;
530 : 0 : }
531 : :
532 : :
533 : : ///@endcond private
|