美文网首页
QgsPostgresProvider源码分析(1)之QgsPo

QgsPostgresProvider源码分析(1)之QgsPo

作者: NullUser | 来源:发表于2022-06-22 18:31 被阅读0次

1.QgsPostgresProviderMetadata类

class QgsPostgresProviderMetadata final: public QgsProviderMetadata
{};

(1) createProvider()

QgsDataProvider *QgsPostgresProviderMetadata::createProvider( const QString &uri, const QgsDataProvider::ProviderOptions &options, QgsDataProvider::ReadFlags flags )
{
  return new QgsPostgresProvider( uri, options, flags );
}

createProvder()创建Provider实例,new了一个QgsPostgresProvider后返回。

(2) dataItemProviders()

QList< QgsDataItemProvider * > QgsPostgresProviderMetadata::dataItemProviders() const
{
  QList<QgsDataItemProvider *> providers;
  providers << new QgsPostgresDataItemProvider;
  return providers;
}

dataItemProviders()返回QgsDataItemProvider列表,在创建一个QList后,往QList中加入了一个新new的QgsPostgresDataItemProvider对象,并将该QList返回。QgsPostgresDataItemProvider类与Qgis浏览器面板中PostGIS树节点构建相关。

(3) createEmptyLayer()

Qgis::VectorExportResult QgsPostgresProviderMetadata::createEmptyLayer(
  const QString &uri,
  const QgsFields &fields,
  QgsWkbTypes::Type wkbType,
  const QgsCoordinateReferenceSystem &srs,
  bool overwrite,
  QMap<int, int> &oldToNewAttrIdxMap,
  QString &errorMessage,
  const QMap<QString, QVariant> *options )
{
  return QgsPostgresProvider::createEmptyLayer(
           uri, fields, wkbType, srs, overwrite,
           &oldToNewAttrIdxMap, &errorMessage, options
         );
}

createEmptyLayer()创建空图层,由源码可知该函数只为接口,实际实现为QgsPostgresProvider::createEmptyLayer()。

(4) styleExists()

bool QgsPostgresProviderMetadata::styleExists( const QString &uri, const QString &styleId, QString &errorCause )
{
  ......
    // 1)
    if ( !tableExists( *conn, QStringLiteral( "layer_styles" ) ) )
    {
      return false;
    }
    // 2)
    else if ( !columnExists( *conn, QStringLiteral( "layer_styles" ), QStringLiteral( "type" ) ) )
    {
      return false;
    }
  ......
    // 3)
   const QString wkbTypeString = QgsPostgresConn::quotedValue( QgsWkbTypes::geometryDisplayString( QgsWkbTypes::geometryType( dsUri.wkbType() ) ) );

    const QString checkQuery = QString( "SELECT styleName"
                                      " FROM layer_styles"
                                      " WHERE f_table_catalog=%1"
                                      " AND f_table_schema=%2"
                                      " AND f_table_name=%3"
                                      " AND f_geometry_column=%4"
                                      " AND (type=%5 OR type IS NULL)"
                                      " AND styleName=%6" )
                             .arg( QgsPostgresConn::quotedValue( dsUri.database() ) )
                             .arg( QgsPostgresConn::quotedValue( dsUri.schema() ) )
                             .arg( QgsPostgresConn::quotedValue( dsUri.table() ) )
                             .arg( QgsPostgresConn::quotedValue( dsUri.geometryColumn() ) )
                             .arg( wkbTypeString )
                             .arg( QgsPostgresConn::quotedValue( styleId.isEmpty() ? dsUri.table() : styleId ) );
......
}

styleExists()判断是否有样式表。

  1. 先通过tableExists()查询表是否存在,Sql语句为:SELECT EXISTS ( SELECT oid FROM pg_catalog.pg_class WHERE relname=“layer_styles” )。
  2. 如果layer_styles表存在,再通过columnExists()判断对应列是否存在,Sql语句为:SELECT COUNT(*) FROM information_schema.columns WHERE table_name= layer_styles and column_name= type
  3. 在表和列都存在后,从表中按过滤条件查询,判断是否有style数据,有返回true,否则false。

(5) saveStyle()

bool QgsPostgresProviderMetadata::saveStyle( const QString &uri, const QString &qmlStyleIn, const QString &sldStyleIn,
    const QString &styleName, const QString &styleDescription,
    const QString &uiFileContent, bool useAsDefault, QString &errCause )
{
......
  // 1)
  if ( !tableExists( *conn, QStringLiteral( "layer_styles" ) ) )
  {
    QgsPostgresResult res( conn->PQexec( "CREATE TABLE layer_styles("
......
  // 2)
    if ( !columnExists( *conn, QStringLiteral( "layer_styles" ), QStringLiteral( "type" ) ) )
    {
      QgsPostgresResult res( conn->PQexec( "ALTER TABLE layer_styles ADD COLUMN type varchar NULL" ) );
......
  // 3)
  QString sql = QString( "INSERT INTO layer_styles("
......
  // 4)
  QString checkQuery = QString( "SELECT styleName"
                                " FROM layer_styles"......
  QgsPostgresResult res( conn->PQexec( checkQuery ) );
  if ( res.PQntuples() > 0 )
  {
    sql = QString( "UPDATE layer_styles"......
}

saveStyle()保存style。

  1. saveStyle首先通过tableExists()判断layer_styles表是否存在,如果不存在则创建。
  2. 然后通过columnExists()判断layer_styles表是否存在type列,如果不存在则ALERT TABLE添加该列。
  3. 构建INSERT语句,往layer_styles表添加一行数据。(构建sql语句并不执行)
  4. 通过SELECT语句判断是否已有该行数据,如果有则更改INSERT语句为UPDATE语句更新数据。

(6) loadStyle()

QString QgsPostgresProviderMetadata::loadStyle( const QString &uri, QString &errCause )
{
......
    selectQmlQuery = QString( "SELECT styleQML"
                              " FROM layer_styles"......
......
}

loadStyle()从layer_styles表获取数据。

(7) listStyles()

int QgsPostgresProviderMetadata::listStyles( const QString &uri, QStringList &ids, QStringList &names,
    QStringList &descriptions, QString &errCause )
{
......
  QString selectRelatedQuery = QString( "SELECT id,styleName,description"
                                        " FROM layer_styles"
                                        " WHERE f_table_catalog=%1"
                                        " AND f_table_schema=%2"
                                        " AND f_table_name=%3"
                                        " AND %4"
                                        " AND (type=%5 OR type IS NULL)"
                                        " ORDER BY useasdefault DESC, update_time DESC" )
                               .arg( QgsPostgresConn::quotedValue( dsUri.database() ) )
                               .arg( QgsPostgresConn::quotedValue( dsUri.schema() ) )
                               .arg( QgsPostgresConn::quotedValue( dsUri.table() ) )
                               .arg( dsUri.geometryColumn().isEmpty() ? "f_geometry_column is NULL" :
                                     QString( "f_geometry_column=%1" ).arg( QgsPostgresConn::quotedValue( dsUri.geometryColumn() ) ) )
                               .arg( wkbTypeString );
......
  QString selectOthersQuery = QString( "SELECT id,styleName,description"
                                       " FROM layer_styles"
                                       " WHERE NOT (f_table_catalog=%1 AND f_table_schema=%2 AND f_table_name=%3 AND f_geometry_column=%4 AND type=%5)"
                                       " ORDER BY update_time DESC" )
                              .arg( QgsPostgresConn::quotedValue( dsUri.database() ) )
                              .arg( QgsPostgresConn::quotedValue( dsUri.schema() ) )
                              .arg( QgsPostgresConn::quotedValue( dsUri.table() ) )
                              .arg( QgsPostgresConn::quotedValue( dsUri.geometryColumn() ) )
                              .arg( wkbTypeString );
......
}

listStyles()列出layer_styles表的所有数据并将每行数据追加的形参ids, names, descriptions中。

(8) deleteStyleById()

bool QgsPostgresProviderMetadata::deleteStyleById( const QString &uri, const QString &styleId, QString &errCause )
{}

deleteStyleById()删除style行,Sql:DELETE FROM layer_styles WHERE id=%1

(9) getStyleById()

QString QgsPostgresProviderMetadata::getStyleById( const QString &uri, const QString &styleId, QString &errCause )
{}

getStyleById()根据id获取style,Sql:SELECT styleQml FROM layer_styles WHERE id=%1"

(10) createTransaction()

QgsTransaction *QgsPostgresProviderMetadata::createTransaction( const QString &connString )
{
  return new QgsPostgresTransaction( connString );
}

createTransaction()返回new的QgsPostgresTransaction对象。QgsPostgresTransaction代表了一个事务去执行sql。

(11) connections()

QMap<QString, QgsAbstractProviderConnection *> QgsPostgresProviderMetadata::connections( bool cached )
{
  return connectionsProtected<QgsPostgresProviderConnection, QgsPostgresConn>( cached );
}

connections()返回QgsProviderMetadata::connectionsProtected()的结果,connectionsProtected()是QgsProviderMetadata的内联函数,提供连接管理的统一功能。其返回的是QgsProviderMetadata的成员变量mProviderConnections

(12) createConnection()

QgsAbstractProviderConnection *QgsPostgresProviderMetadata::createConnection( const QString &uri, const QVariantMap &configuration )
{
  return new QgsPostgresProviderConnection( uri, configuration );
}

createConnection()返回new的QgsPostgresProviderConnection对象。QgsPostgresProviderConnection提供数据库连接的一些接口。

(13) initProvider(

void QgsPostgresProviderMetadata::initProvider()
{
  Q_ASSERT( !gPgProjectStorage );
  gPgProjectStorage = new QgsPostgresProjectStorage;
  QgsApplication::projectStorageRegistry()->registerProjectStorage( gPgProjectStorage );  // takes ownership
}

initProvider()可以做一些初始化工作,这里创建了一个QgsPostgresProjectStorage对象,并通过QgsApplication::projectStorageRegistry()进行注册,QgsPostgresProjectStorage将工程的一些数据储存在pg表中。

(14) cleanupProvider()

void QgsPostgresProviderMetadata::cleanupProvider()
{
  QgsApplication::projectStorageRegistry()->unregisterProjectStorage( gPgProjectStorage );  // destroys the object
  gPgProjectStorage = nullptr;

  QgsPostgresConnPool::cleanupInstance();
}

cleanupProvider()同initProvider()相反,做一些回收工作。

(15) decodeUri()

QVariantMap QgsPostgresProviderMetadata::decodeUri( const QString &uri ) const
{
  const QgsDataSourceUri dsUri { uri };
  QVariantMap uriParts;

  if ( ! dsUri.database().isEmpty() )
    uriParts[ QStringLiteral( "dbname" ) ] = dsUri.database();
  if ( ! dsUri.host().isEmpty() )
    uriParts[ QStringLiteral( "host" ) ] = dsUri.host();
......
  return uriParts;
}

decodeUri()解析uri字符串,可以自定义,这里使用了QgsDataSourceUri类进行解析,因为QgsPostgresProvider使用了QgsDataSourceUri的标准uri格式,参考uri: dbname='sdetest' host=127.0.0.1 port=5432 user='sde' password='123' table="sde"."testlayer" (shape)。

(16) encodeUri()

QString QgsPostgresProviderMetadata::encodeUri( const QVariantMap &parts ) const
{
  QgsDataSourceUri dsUri;
  if ( parts.contains( QStringLiteral( "dbname" ) ) )
    dsUri.setDatabase( parts.value( QStringLiteral( "dbname" ) ).toString() );
  if ( parts.contains( QStringLiteral( "port" ) ) )
    dsUri.setParam( QStringLiteral( "port" ), parts.value( QStringLiteral( "port" ) ).toString() );
......
  return dsUri.uri(false);
 }

encodeUri()将数据编码成uri字符串,同样使用QgsDataSourceUri类进行。

相关文章

网友评论

      本文标题:QgsPostgresProvider源码分析(1)之QgsPo

      本文链接:https://www.haomeiwen.com/subject/jbhuvrtx.html