美文网首页
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