QgsVirtualLayerDefinition QgsVirtualLayerDefinitionUtils::fromJoinedLayer( QgsVectorLayer *layer ) { QgsVirtualLayerDefinition def; QStringList leftJoins; QStringList columns; // add the geometry column if the layer is spatial if ( layer->isSpatial() ) columns << "t.geometry"; // look for the uid QgsFields fields = layer->dataProvider()->fields(); { QgsAttributeList pk = layer->dataProvider()->pkAttributeIndexes(); if ( pk.size() == 1 ) { def.setUid( fields.field( pk[0] ).name() ); } else { // find an uid name QString uid = QStringLiteral( "uid" ); while ( fields.lookupField( uid ) != -1 ) uid += QLatin1String( "_" ); // add "_" each time this name already exists // add a column columns << "t.rowid AS " + uid; def.setUid( uid ); } } const QgsFields providerFields = layer->dataProvider()->fields(); for ( const auto &f : providerFields ) { columns << "t.\"" + f.name() + "\""; } int joinIdx = 0; Q_FOREACH ( const QgsVectorLayerJoinInfo &join, layer->vectorJoins() ) { QString joinName = QStringLiteral( "j%1" ).arg( ++joinIdx ); QgsVectorLayer *joinedLayer = join.joinLayer(); if ( !joinedLayer ) continue; QString prefix = join.prefix().isEmpty() ? joinedLayer->name() + "_" : join.prefix(); leftJoins << QStringLiteral( "LEFT JOIN \"%1\" AS %2 ON t.\"%5\"=%2.\"%3\"" ).arg( joinedLayer->id(), joinName, join.joinFieldName(), join.targetFieldName() ); if ( join.joinFieldNamesSubset() ) { Q_FOREACH ( const QString &f, *join.joinFieldNamesSubset() ) { columns << joinName + ".\"" + f + "\" AS \"" + prefix + f + "\""; } } else {
QGISEXTERN QgsVirtualLayerSourceSelect *createWidget( QWidget *parent, Qt::WindowFlags fl, const QList<QPair<QString, QString> >& parameters ) { QgsVirtualLayerSourceSelect *w = new QgsVirtualLayerSourceSelect( parent, fl ); QString name, source, encoding; foreach ( const auto& p, parameters ) { if ((p.first == "fromUrl") || (p.first == "fromFile")) { QgsVirtualLayerDefinition def; if (p.first == "fromUrl") { QUrl url( QUrl::fromEncoded( p.second.toLocal8Bit() ) ); def.fromUrl( url ); } else { def = virtualLayerDefinitionFromSqlite( p.second ); } w->setQuery( def.query() ); w->setUid( def.uid() ); w->setGeometryColumn( def.geometryField() ); foreach ( const auto& l, def.sourceLayers() ) { w->addSource( l.name(), l.source(), l.provider(), l.encoding() ); } w->setFilename( def.uri() ); break; } else if (p.first == "layer") {
QgsVirtualLayerDefinition QgsVirtualLayerDefinition::fromUrl( const QUrl& url ) { QgsVirtualLayerDefinition def; def.setFilePath( url.path() ); // regexp for column name const QString columnNameRx( "[a-zA-Z_\x80-\xFF][a-zA-Z0-9_\x80-\xFF]*" ); QgsFields fields; int layerIdx = 0; QList<QPair<QString, QString> > items = url.queryItems(); for ( int i = 0; i < items.size(); i++ ) { QString key = items.at( i ).first; QString value = items.at( i ).second; if ( key == "layer_ref" ) { layerIdx++; // layer id, with optional layer_name int pos = value.indexOf( ':' ); QString layerId, vlayerName; if ( pos == -1 ) { layerId = value; vlayerName = QString( "vtab%1" ).arg( layerIdx ); } else { layerId = value.left( pos ); vlayerName = QUrl::fromPercentEncoding( value.mid( pos + 1 ).toUtf8() ); } // add the layer to the list def.addSource( vlayerName, layerId ); } else if ( key == "layer" ) { layerIdx++; // syntax: layer=provider:url_encoded_source_URI(:name(:encoding)?)? int pos = value.indexOf( ':' ); if ( pos != -1 ) { QString providerKey, source, vlayerName, encoding = "UTF-8"; providerKey = value.left( pos ); int pos2 = value.indexOf( ':', pos + 1 ); if ( pos2 != -1 ) { source = QUrl::fromPercentEncoding( value.mid( pos + 1, pos2 - pos - 1 ).toUtf8() ); int pos3 = value.indexOf( ':', pos2 + 1 ); if ( pos3 != -1 ) { vlayerName = QUrl::fromPercentEncoding( value.mid( pos2 + 1, pos3 - pos2 - 1 ).toUtf8() ); encoding = value.mid( pos3 + 1 ); } else { vlayerName = QUrl::fromPercentEncoding( value.mid( pos2 + 1 ).toUtf8() ); } } else { source = QUrl::fromPercentEncoding( value.mid( pos + 1 ).toUtf8() ); vlayerName = QString( "vtab%1" ).arg( layerIdx ); } def.addSource( vlayerName, source, providerKey, encoding ); } } else if ( key == "geometry" ) { // geometry field definition, optional // geometry_column(:wkb_type:srid)? QRegExp reGeom( "(" + columnNameRx + ")(?::([a-zA-Z0-9]+):(\\d+))?" ); int pos = reGeom.indexIn( value ); if ( pos >= 0 ) { def.setGeometryField( reGeom.cap( 1 ) ); if ( reGeom.captureCount() > 1 ) { // not used by the spatialite provider for now ... QgsWKBTypes::Type wkbType = QgsWKBTypes::parseType( reGeom.cap( 2 ) ); if ( wkbType == QgsWKBTypes::Unknown ) { wkbType = static_cast<QgsWKBTypes::Type>( reGeom.cap( 2 ).toLong() ); } def.setGeometryWkbType( wkbType ); def.setGeometrySrid( reGeom.cap( 3 ).toLong() ); } } } else if ( key == "nogeometry" ) { def.setGeometryWkbType( QgsWKBTypes::NoGeometry ); } else if ( key == "uid" ) { def.setUid( value ); } else if ( key == "query" ) { // url encoded query def.setQuery( value ); } else if ( key == "field" ) { // field_name:type (int, real, text) QRegExp reField( "(" + columnNameRx + "):(int|real|text)" ); int pos = reField.indexIn( value ); if ( pos >= 0 ) { QString fieldName( reField.cap( 1 ) ); QString fieldType( reField.cap( 2 ) ); if ( fieldType == "int" ) { fields.append( QgsField( fieldName, QVariant::Int, fieldType ) ); } else if ( fieldType == "real" ) { fields.append( QgsField( fieldName, QVariant::Double, fieldType ) ); } if ( fieldType == "text" ) { fields.append( QgsField( fieldName, QVariant::String, fieldType ) ); } } } } def.setFields( fields ); return def; }