QgsPostgresProvider源码分析(1)之QgsPostgresProviderMetadata

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类进行。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容