QGIS API Documentation  3.19.0-Master (c9e5875a2b)
qgsabstractdatabaseproviderconnection.cpp
Go to the documentation of this file.
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  ***************************************************************************/
17 #include "qgsvectorlayer.h"
18 #include "qgsexception.h"
19 #include "qgslogger.h"
20 #include "qgsfeedback.h"
21 
22 #include <QVariant>
23 #include <QObject>
24 
27 {
28 
29 }
30 
31 QgsAbstractDatabaseProviderConnection::QgsAbstractDatabaseProviderConnection( const QString &uri, const QVariantMap &configuration ):
32  QgsAbstractProviderConnection( uri, configuration )
33 {
34 
35 }
36 QgsAbstractDatabaseProviderConnection::Capabilities QgsAbstractDatabaseProviderConnection::capabilities() const
37 {
38  return mCapabilities;
39 }
40 
41 QgsAbstractDatabaseProviderConnection::GeometryColumnCapabilities QgsAbstractDatabaseProviderConnection::geometryColumnCapabilities()
42 {
44 }
45 
46 QString QgsAbstractDatabaseProviderConnection::tableUri( const QString &schema, const QString &name ) const
47 {
48  Q_UNUSED( schema )
49  Q_UNUSED( name )
50  throw QgsProviderConnectionException( QObject::tr( "Operation 'tableUri' is not supported" ) );
51 }
52 
54 void QgsAbstractDatabaseProviderConnection::checkCapability( QgsAbstractDatabaseProviderConnection::Capability capability ) const
55 {
56  if ( ! mCapabilities.testFlag( capability ) )
57  {
58  static QMetaEnum metaEnum = QMetaEnum::fromType<QgsAbstractDatabaseProviderConnection::Capability>();
59  const QString capName { metaEnum.valueToKey( capability ) };
60  throw QgsProviderConnectionException( QObject::tr( "Operation '%1' is not supported for this connection" ).arg( capName ) );
61  }
62 }
63 
65 {
66  return mProviderKey;
67 }
69 
71  const QString &name,
72  const QgsFields &fields,
73  QgsWkbTypes::Type wkbType,
75  bool overwrite,
76  const QMap<QString, QVariant> *
77  options ) const
78 {
79  Q_UNUSED( schema );
80  Q_UNUSED( name );
81  Q_UNUSED( fields );
82  Q_UNUSED( srs );
83  Q_UNUSED( overwrite );
84  Q_UNUSED( options );
85  Q_UNUSED( wkbType );
86  throw QgsProviderConnectionException( QObject::tr( "Operation 'createVectorTable' is not supported" ) );
87 }
88 
89 void QgsAbstractDatabaseProviderConnection::renameVectorTable( const QString &, const QString &, const QString & ) const
90 {
91  checkCapability( Capability::RenameVectorTable );
92 }
93 
94 void QgsAbstractDatabaseProviderConnection::renameRasterTable( const QString &, const QString &, const QString & ) const
95 {
96  checkCapability( Capability::RenameRasterTable );
97 }
98 
99 void QgsAbstractDatabaseProviderConnection::dropVectorTable( const QString &, const QString & ) const
100 {
101  checkCapability( Capability::DropVectorTable );
102 }
103 
104 bool QgsAbstractDatabaseProviderConnection::tableExists( const QString &schema, const QString &name ) const
105 {
106  checkCapability( Capability::TableExists );
107  const QList<QgsAbstractDatabaseProviderConnection::TableProperty> constTables { tables( schema ) };
108  for ( const auto &t : constTables )
109  {
110  if ( t.tableName() == name )
111  {
112  return true;
113  }
114  }
115  return false;
116 }
117 
118 void QgsAbstractDatabaseProviderConnection::dropRasterTable( const QString &, const QString & ) const
119 {
120  checkCapability( Capability::DropRasterTable );
121 }
122 
124 {
125  checkCapability( Capability::CreateSchema );
126 }
127 
128 void QgsAbstractDatabaseProviderConnection::dropSchema( const QString &, bool ) const
129 {
130  checkCapability( Capability::DropSchema );
131 }
132 
133 void QgsAbstractDatabaseProviderConnection::renameSchema( const QString &, const QString & ) const
134 {
135  checkCapability( Capability::RenameSchema );
136 }
137 
138 QList<QList<QVariant>> QgsAbstractDatabaseProviderConnection::executeSql( const QString &sql, QgsFeedback *feedback ) const
139 {
140  return execSql( sql, feedback ).rows();
141 }
142 
143 
145 {
146  checkCapability( Capability::ExecuteSql );
147  return QueryResult();
148 }
149 
150 
151 void QgsAbstractDatabaseProviderConnection::vacuum( const QString &, const QString & ) const
152 {
153  checkCapability( Capability::Vacuum );
154 }
155 
157 {
158  checkCapability( Capability::CreateSpatialIndex );
159 }
160 
161 void QgsAbstractDatabaseProviderConnection::deleteSpatialIndex( const QString &, const QString &, const QString & ) const
162 {
163  checkCapability( Capability::DeleteSpatialIndex );
164 }
165 
166 bool QgsAbstractDatabaseProviderConnection::spatialIndexExists( const QString &, const QString &, const QString & ) const
167 {
168  checkCapability( Capability::SpatialIndexExists );
169  return false;
170 }
171 
172 void QgsAbstractDatabaseProviderConnection::deleteField( const QString &fieldName, const QString &schema, const QString &tableName, bool ) const
173 {
174  checkCapability( Capability::DeleteField );
175 
176  QgsVectorLayer::LayerOptions options { false, false };
177  options.skipCrsValidation = true;
178  std::unique_ptr<QgsVectorLayer> vl { std::make_unique<QgsVectorLayer>( tableUri( schema, tableName ), QStringLiteral( "temp_layer" ), mProviderKey, options ) };
179  if ( ! vl->isValid() )
180  {
181  throw QgsProviderConnectionException( QObject::tr( "Could not create a vector layer for table '%1' in schema '%2'" )
182  .arg( tableName, schema ) );
183  }
184  if ( vl->fields().lookupField( fieldName ) == -1 )
185  {
186  throw QgsProviderConnectionException( QObject::tr( "Could not find field '%1' in table '%2' in schema '%3'" )
187  .arg( fieldName, tableName, schema ) );
188 
189  }
190  if ( ! vl->dataProvider()->deleteAttributes( { vl->fields().lookupField( fieldName ) } ) )
191  {
192  throw QgsProviderConnectionException( QObject::tr( "Unknown error deleting field '%1' in table '%2' in schema '%3'" )
193  .arg( fieldName, tableName, schema ) );
194  }
195 }
196 
197 void QgsAbstractDatabaseProviderConnection::addField( const QgsField &field, const QString &schema, const QString &tableName ) const
198 {
199  checkCapability( Capability::AddField );
200 
201  QgsVectorLayer::LayerOptions options { false, false };
202  options.skipCrsValidation = true;
203  std::unique_ptr<QgsVectorLayer> vl( std::make_unique<QgsVectorLayer>( tableUri( schema, tableName ), QStringLiteral( "temp_layer" ), mProviderKey, options ) );
204  if ( ! vl->isValid() )
205  {
206  throw QgsProviderConnectionException( QObject::tr( "Could not create a vector layer for table '%1' in schema '%2'" )
207  .arg( tableName, schema ) );
208  }
209  if ( vl->fields().lookupField( field.name() ) != -1 )
210  {
211  throw QgsProviderConnectionException( QObject::tr( "Field '%1' in table '%2' in schema '%3' already exists" )
212  .arg( field.name(), tableName, schema ) );
213 
214  }
215  if ( ! vl->dataProvider()->addAttributes( { field } ) )
216  {
217  throw QgsProviderConnectionException( QObject::tr( "Unknown error adding field '%1' in table '%2' in schema '%3'" )
218  .arg( field.name(), tableName, schema ) );
219  }
220 }
221 
222 QList<QgsAbstractDatabaseProviderConnection::TableProperty> QgsAbstractDatabaseProviderConnection::tables( const QString &, const QgsAbstractDatabaseProviderConnection::TableFlags & ) const
223 {
224  checkCapability( Capability::Tables );
225  return QList<QgsAbstractDatabaseProviderConnection::TableProperty>();
226 }
227 
228 
230 {
231  checkCapability( Capability::Tables );
232  const QList<QgsAbstractDatabaseProviderConnection::TableProperty> constTables { tables( schema ) };
233  for ( const auto &t : constTables )
234  {
235  if ( t.tableName() == name )
236  {
237  return t;
238  }
239  }
240  throw QgsProviderConnectionException( QObject::tr( "Table '%1' was not found in schema '%2'" )
241  .arg( name, schema ) );
242 }
243 
244 QList<QgsAbstractDatabaseProviderConnection::TableProperty> QgsAbstractDatabaseProviderConnection::tablesInt( const QString &schema, const int flags ) const
245 {
246  return tables( schema, static_cast<QgsAbstractDatabaseProviderConnection::TableFlags>( flags ) );
247 }
248 
249 
251 {
252  checkCapability( Capability::Schemas );
253  return QStringList();
254 }
255 
257 {
258  return mTableName;
259 }
260 
262 {
263  mTableName = name;
264 }
265 
267 {
268  // Do not add the type if it's already present
270  for ( const auto &t : std::as_const( mGeometryColumnTypes ) )
271  {
272  if ( t == toAdd )
273  {
274  return;
275  }
276  }
277  mGeometryColumnTypes.push_back( toAdd );
278 }
279 
280 QList<QgsAbstractDatabaseProviderConnection::TableProperty::GeometryColumnType> QgsAbstractDatabaseProviderConnection::TableProperty::geometryColumnTypes() const
281 {
282  return mGeometryColumnTypes;
283 }
284 
285 QgsFields QgsAbstractDatabaseProviderConnection::fields( const QString &schema, const QString &tableName ) const
286 {
287  QgsVectorLayer::LayerOptions options { false, true };
288  options.skipCrsValidation = true;
289  QgsVectorLayer vl { tableUri( schema, tableName ), QStringLiteral( "temp_layer" ), mProviderKey, options };
290  if ( vl.isValid() )
291  {
292  return vl.fields();
293  }
294  else
295  {
296  throw QgsProviderConnectionException( QObject::tr( "Error retrieving fields information for uri: %1" ).arg( vl.publicSource() ) );
297  }
298 }
299 
301 {
302  QString n = mTableName;
303  if ( mGeometryColumnCount > 1 ) n += '.' + mGeometryColumn;
304  return n;
305 }
306 
308 {
309  TableProperty property;
310 
311  Q_ASSERT( index >= 0 && index < mGeometryColumnTypes.size() );
312 
313  property.mGeometryColumnTypes << mGeometryColumnTypes[ index ];
314  property.mSchema = mSchema;
315  property.mTableName = mTableName;
316  property.mGeometryColumn = mGeometryColumn;
317  property.mPkColumns = mPkColumns;
318  property.mGeometryColumnCount = mGeometryColumnCount;
319  property.mFlags = mFlags;
320  property.mComment = mComment;
321  property.mInfo = mInfo;
322  return property;
323 }
324 
326 {
327  mFlags.setFlag( flag );
328 }
329 
331 {
332  int res = 0;
333  for ( const TableProperty::GeometryColumnType &ct : std::as_const( mGeometryColumnTypes ) )
334  {
335  res = std::max( res, QgsWkbTypes::coordDimensions( ct.wkbType ) );
336  }
337  return res;
338 }
339 
341 {
342  return mSchema == other.mSchema &&
343  mTableName == other.mTableName &&
344  mGeometryColumn == other.mGeometryColumn &&
345  mGeometryColumnCount == other.mGeometryColumnCount &&
346  mPkColumns == other.mPkColumns &&
347  mFlags == other.mFlags &&
348  mComment == other.mComment &&
349  mInfo == other.mInfo;
350 }
351 
352 
353 void QgsAbstractDatabaseProviderConnection::TableProperty::setGeometryColumnTypes( const QList<QgsAbstractDatabaseProviderConnection::TableProperty::GeometryColumnType> &columnTypes )
354 {
355  mGeometryColumnTypes = columnTypes;
356 }
357 
358 
360 {
361  return mGeometryColumnCount;
362 }
363 
365 {
366  mGeometryColumnCount = geometryColumnCount;
367 }
368 
370 {
371  return mInfo;
372 }
373 
375 {
376  mInfo = info;
377 }
378 
380 {
381  return mComment;
382 }
383 
385 {
386  mComment = comment;
387 }
388 
389 QgsAbstractDatabaseProviderConnection::TableFlags QgsAbstractDatabaseProviderConnection::TableProperty::flags() const
390 {
391  return mFlags;
392 }
393 
394 void QgsAbstractDatabaseProviderConnection::TableProperty::setFlags( const QgsAbstractDatabaseProviderConnection::TableFlags &flags )
395 {
396  mFlags = flags;
397 }
398 
399 QList<QgsCoordinateReferenceSystem> QgsAbstractDatabaseProviderConnection::TableProperty::crsList() const
400 {
401  QList<QgsCoordinateReferenceSystem> crss;
402  for ( const auto &t : std::as_const( mGeometryColumnTypes ) )
403  {
404  crss.push_back( t.crs );
405  }
406  return crss;
407 }
408 
410 {
411  return mPkColumns;
412 }
413 
415 {
416  mPkColumns = pkColumns;
417 }
418 
420 {
421  return mGeometryColumn;
422 }
423 
425 {
426  mGeometryColumn = geometryColumn;
427 }
428 
430 {
431  return mSchema;
432 }
433 
435 {
436  mSchema = schema;
437 }
438 
439 
441 
443 {
444  return mColumns;
445 }
446 
448 {
449 
450  QList<QList<QVariant> > rows;
451 
452  while ( mResultIterator &&
453  mResultIterator->hasNextRow() &&
454  ( ! feedback || ! feedback->isCanceled() ) )
455  {
456  const QVariantList row( mResultIterator->nextRow() );
457  if ( row.isEmpty() )
458  {
459  break;
460  }
461  else
462  {
463  rows.push_back( row );
464  }
465  }
466  return rows;
467 }
468 
470 {
471  if ( ! mResultIterator )
472  {
473  return QList<QVariant>();
474  }
475  return mResultIterator->nextRow();
476 }
477 
478 
480 {
481  if ( ! mResultIterator )
482  {
483  return 0;
484  }
485  return mResultIterator->fetchedRowCount();
486 }
487 
488 
490 {
491  if ( ! mResultIterator )
492  {
493  return false;
494  }
495  return mResultIterator->hasNextRow();
496 }
497 
498 void QgsAbstractDatabaseProviderConnection::QueryResult::appendColumn( const QString &columnName )
499 {
500  mColumns.push_back( columnName );
501 }
502 
503 
504 QgsAbstractDatabaseProviderConnection::QueryResult::QueryResult( std::shared_ptr<QgsAbstractDatabaseProviderConnection::QueryResult::QueryResultIterator> iterator )
505  : mResultIterator( iterator )
506 {}
507 
508 
509 QVariantList QgsAbstractDatabaseProviderConnection::QueryResult::QueryResultIterator::nextRow()
510 {
511  QMutexLocker lock( &mMutex );
512  const QVariantList row = nextRowPrivate();
513  if ( ! row.isEmpty() )
514  {
515  mFetchedRowCount++;
516  }
517  return row;
518 }
519 
520 bool QgsAbstractDatabaseProviderConnection::QueryResult::QueryResultIterator::hasNextRow() const
521 {
522  QMutexLocker lock( &mMutex );
523  return hasNextRowPrivate();
524 }
525 
526 qlonglong QgsAbstractDatabaseProviderConnection::QueryResult::QueryResultIterator::fetchedRowCount()
527 {
528  QMutexLocker lock( &mMutex );
529  return mFetchedRowCount;
530 }
531 
532 
virtual void vacuum(const QString &schema, const QString &name) const SIP_THROW(QgsProviderConnectionException)
Vacuum the database table with given schema and name (schema is ignored if not supported by the backe...
virtual QueryResult execSql(const QString &sql, QgsFeedback *feedback=nullptr) const SIP_THROW(QgsProviderConnectionException)
Executes raw sql and returns the (possibly empty) query results, optionally feedback can be provided.
QString providerKey() const
Returns the provider key.
virtual bool tableExists(const QString &schema, const QString &name) const SIP_THROW(QgsProviderConnectionException)
Checks whether a table name exists in the given schema.
virtual void createVectorTable(const QString &schema, const QString &name, const QgsFields &fields, QgsWkbTypes::Type wkbType, const QgsCoordinateReferenceSystem &srs, bool overwrite, const QMap< QString, QVariant > *options) const SIP_THROW(QgsProviderConnectionException)
Creates an empty table with name in the given schema (schema is ignored if not supported by the backe...
virtual void deleteSpatialIndex(const QString &schema, const QString &name, const QString &geometryColumn) const SIP_THROW(QgsProviderConnectionException)
Deletes the existing spatial index for the database table with given schema, name and geometryColumn ...
Capability
The Capability enum represents the operations supported by the connection.
virtual void deleteField(const QString &fieldName, const QString &schema, const QString &tableName, bool force=false) const SIP_THROW(QgsProviderConnectionException)
Deletes the field with the specified name.
virtual void createSchema(const QString &name) const SIP_THROW(QgsProviderConnectionException)
Creates a new schema with the specified name.
virtual GeometryColumnCapabilities geometryColumnCapabilities()
Returns connection geomerty column capabilities (Z, M, SinglePart, Curves)
virtual void dropSchema(const QString &name, bool force=false) const SIP_THROW(QgsProviderConnectionException)
Drops an entire schema with the specified name.
virtual void addField(const QgsField &field, const QString &schema, const QString &tableName) const SIP_THROW(QgsProviderConnectionException)
Adds a field Raises a QgsProviderConnectionException if any errors are encountered.
virtual QList< QList< QVariant > > executeSql(const QString &sql, QgsFeedback *feedback=nullptr) const SIP_THROW(QgsProviderConnectionException)
Executes raw sql and returns the (possibly empty) list of results in a multi-dimensional array,...
virtual void renameRasterTable(const QString &schema, const QString &name, const QString &newName) const SIP_THROW(QgsProviderConnectionException)
Renames a raster table with given schema (schema is ignored if not supported by the backend) and name...
QList< QgsAbstractDatabaseProviderConnection::TableProperty > tablesInt(const QString &schema=QString(), const int flags=0) const SIP_THROW(QgsProviderConnectionException)
Returns information on the tables in the given schema.
virtual void renameVectorTable(const QString &schema, const QString &name, const QString &newName) const SIP_THROW(QgsProviderConnectionException)
Renames a vector or aspatial table with given schema (schema is ignored if not supported by the backe...
virtual bool spatialIndexExists(const QString &schema, const QString &name, const QString &geometryColumn) const SIP_THROW(QgsProviderConnectionException)
Determines whether a spatial index exists for the database table with given schema,...
virtual void renameSchema(const QString &name, const QString &newName) const SIP_THROW(QgsProviderConnectionException)
Renames a schema with the specified name.
virtual QgsAbstractDatabaseProviderConnection::TableProperty table(const QString &schema, const QString &table) const SIP_THROW(QgsProviderConnectionException)
Returns information on a table in the given schema.
virtual QStringList schemas() const SIP_THROW(QgsProviderConnectionException)
Returns information about the existing schemas.
virtual QString tableUri(const QString &schema, const QString &name) const SIP_THROW(QgsProviderConnectionException)
Returns the URI string for the given table and schema.
virtual QgsFields fields(const QString &schema, const QString &table) const SIP_THROW(QgsProviderConnectionException)
Returns the fields of a table and schema.
virtual void createSpatialIndex(const QString &schema, const QString &name, const QgsAbstractDatabaseProviderConnection::SpatialIndexOptions &options=QgsAbstractDatabaseProviderConnection::SpatialIndexOptions()) const SIP_THROW(QgsProviderConnectionException)
Creates a spatial index for the database table with given schema and name (schema is ignored if not s...
virtual void dropVectorTable(const QString &schema, const QString &name) const SIP_THROW(QgsProviderConnectionException)
Drops a vector (or aspatial) table with given schema (schema is ignored if not supported by the backe...
QgsAbstractDatabaseProviderConnection(const QString &name)
Creates a new connection with name by reading its configuration from the settings.
virtual void dropRasterTable(const QString &schema, const QString &name) const SIP_THROW(QgsProviderConnectionException)
Drops a raster table with given schema (schema is ignored if not supported by the backend) and name.
virtual QList< QgsAbstractDatabaseProviderConnection::TableProperty > tables(const QString &schema=QString(), const QgsAbstractDatabaseProviderConnection::TableFlags &flags=QgsAbstractDatabaseProviderConnection::TableFlags()) const
Returns information on the tables in the given schema.
Capabilities capabilities() const
Returns connection capabilities.
The QgsAbstractProviderConnection provides an interface for data provider connections.
This class represents a coordinate reference system (CRS).
Base class for feedback objects to be used for cancellation of something running in a worker thread.
Definition: qgsfeedback.h:45
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:54
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:51
QString name
Definition: qgsfield.h:60
Container of fields for a vector layer.
Definition: qgsfields.h:45
Custom exception class for provider connection related exceptions.
Definition: qgsexception.h:101
Represents a vector layer which manages a vector based data sets.
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h:70
static int coordDimensions(Type type) SIP_HOLDGIL
Returns the coordinate dimension of the geometry type as an integer.
Definition: qgswkbtypes.h:925
const QgsField & field
Definition: qgsfield.h:463
const QgsCoordinateReferenceSystem & crs
The QueryResult class represents the result of a query executed by execSql()
QList< QList< QVariant > > rows(QgsFeedback *feedback=nullptr)
Returns the result rows by calling the iterator internally and fetching all the rows,...
bool hasNextRow() const
Returns true if there are more rows to fetch.
qlonglong fetchedRowCount() const
Returns the number of fetched rows.
QList< QVariant > nextRow() const
Returns the next result row or an empty row if there are no rows left.
QStringList columns() const
Returns the column names.
Contains extra options relating to spatial index creation.
The GeometryColumnType struct represents the combination of geometry type and CRS for the table geome...
The TableProperty class represents a database table or view.
void setTableName(const QString &name)
Sets the table name to name.
void addGeometryColumnType(const QgsWkbTypes::Type &type, const QgsCoordinateReferenceSystem &crs)
Appends the geometry column type with the given srid to the geometry column types list.
bool operator==(const QgsAbstractDatabaseProviderConnection::TableProperty &other) const
void setPrimaryKeyColumns(const QStringList &primaryKeyColumns)
Sets the primary key column names to primaryKeyColumns.
QString defaultName() const
Returns the default name for the table entry.
QList< QgsAbstractDatabaseProviderConnection::TableProperty::GeometryColumnType > geometryColumnTypes() const
Returns the list of geometry column types and CRSs.
void setGeometryColumn(const QString &geometryColumn)
Sets the geometry column name to geometryColumn.
TableProperty at(int index) const
Returns the table property corresponding to the geometry type at the given index.
int maxCoordinateDimensions() const
Returns the maximum coordinate dimensions of the geometries of a vector table.
int geometryColumnCount() const
Returns the number of geometry columns in the original table this entry refers to.
QList< QgsCoordinateReferenceSystem > crsList() const
Returns the list of CRSs supported by the geometry column.
QVariantMap info() const
Returns additional information about the table.
void setInfo(const QVariantMap &info)
Sets additional information about the table to info.
QStringList primaryKeyColumns() const
Returns the list of primary key column names.
void setGeometryColumnTypes(const QList< QgsAbstractDatabaseProviderConnection::TableProperty::GeometryColumnType > &geometryColumnTypes)
Sets the geometry column types to geometryColumnTypes.
void setComment(const QString &comment)
Sets the table comment.
QString schema() const
Returns the schema or an empty string for backends that do not support a schema.
void setGeometryColumnCount(int geometryColumnCount)
Sets the geometryColumnCount.
Setting options for loading vector layers.
bool skipCrsValidation
Controls whether the layer is allowed to have an invalid/unknown CRS.