Skip to content

Commit

Permalink
Fix offline editing with gpkg
Browse files Browse the repository at this point in the history
Up to now, all features were written twice, once with QgsVectorFileWriter, once via addFeature in a subsequent loop. Now it is only done once in a loop, because the loop needs to be done anyway to create the lookup table
  • Loading branch information
m-kuhn committed Sep 14, 2018
1 parent a60324b commit 6584fe7
Showing 1 changed file with 73 additions and 9 deletions.
82 changes: 73 additions & 9 deletions src/core/qgsofflineediting.cpp
Expand Up @@ -45,6 +45,8 @@
#include <QFile>
#include <QMessageBox>

#include <ogr_srs_api.h>

extern "C"
{
#include <sqlite3.h>
Expand Down Expand Up @@ -630,18 +632,80 @@ QgsVectorLayer *QgsOfflineEditing::copyVectorLayer( QgsVectorLayer *layer, sqlit
}
case GPKG:
{
QgsVectorFileWriter::SaveVectorOptions options;
options.driverName = QStringLiteral( "GPKG" );
options.layerName = tableName;
options.actionOnExistingFile = QgsVectorFileWriter::CreateOrOverwriteLayer;
options.onlySelectedFeatures = onlySelected;

QString error;
if ( QgsVectorFileWriter::writeAsVectorFormat( layer, offlineDbPath, options, &error ) != QgsVectorFileWriter::NoError )
// Set options
char **options = nullptr;

options = CSLSetNameValue( options, "OVERWRITE", "YES" );
options = CSLSetNameValue( options, "IDENTIFIER", layer->name().toUtf8().constData() );
options = CSLSetNameValue( options, "DESCRIPTION", layer->dataComment().toUtf8().constData() );
#if 0
options = CSLSetNameValue( options, "FID", featureId.toUtf8().constData() );
#endif

if ( layer->isSpatial() )
{
options = CSLSetNameValue( options, "GEOMETRY_COLUMN", "geom" );
options = CSLSetNameValue( options, "SPATIAL_INDEX", "YES" );
}

OGRSFDriverH hDriver = nullptr;
OGRSpatialReferenceH hSRS = OSRNewSpatialReference( layer->crs().toWkt().toLocal8Bit().data() );
gdal::ogr_datasource_unique_ptr hDS( OGROpen( offlineDbPath.toUtf8().constData(), true, &hDriver ) );
OGRLayerH hLayer = OGR_DS_CreateLayer( hDS.get(), tableName.toUtf8().constData(), hSRS, static_cast<OGRwkbGeometryType>( layer->wkbType() ), options );
CSLDestroy( options );
if ( hSRS )
OSRRelease( hSRS );
if ( !hLayer )
{
showWarning( tr( "Creation of layer failed (OGR error: %1)" ).arg( QString::fromUtf8( CPLGetLastErrorMsg() ) ) );
return nullptr;
}

const QgsFields providerFields = layer->dataProvider()->fields();
for ( const auto &field : providerFields )
{
const QString fieldName( field.name() );
const QVariant::Type type = field.type();
OGRFieldType ogrType( OFTString );
if ( type == QVariant::Int )
ogrType = OFTInteger;
else if ( type == QVariant::LongLong )
ogrType = OFTInteger64;
else if ( type == QVariant::Double )
ogrType = OFTReal;
else if ( type == QVariant::Time )
ogrType = OFTTime;
else if ( type == QVariant::Date )
ogrType = OFTDate;
else if ( type == QVariant::DateTime )
ogrType = OFTDateTime;
else
ogrType = OFTString;

int ogrWidth = field.length();

gdal::ogr_field_def_unique_ptr fld( OGR_Fld_Create( fieldName.toUtf8().constData(), ogrType ) );
OGR_Fld_SetWidth( fld.get(), ogrWidth );

if ( OGR_L_CreateField( hLayer, fld.get(), true ) != OGRERR_NONE )
{
showWarning( tr( "Creation of field %1 failed (OGR error: %2)" )
.arg( fieldName, QString::fromUtf8( CPLGetLastErrorMsg() ) ) );
return nullptr;
}
}

// In GDAL >= 2.0, the driver implements a deferred creation strategy, so
// issue a command that will force table creation
CPLErrorReset();
OGR_L_ResetReading( hLayer );
if ( CPLGetLastErrorType() != CE_None )
{
showWarning( tr( "Packaging layer %1 failed: %2" ).arg( layer->name(), error ) );
QString msg( tr( "Creation of layer failed (OGR error: %1)" ).arg( QString::fromUtf8( CPLGetLastErrorMsg() ) ) );
showWarning( msg );
return nullptr;
}
hDS.reset();

QString uri = QStringLiteral( "%1|layername=%2" ).arg( offlineDbPath, tableName );
newLayer = new QgsVectorLayer( uri, layer->name() + " (offline)", QStringLiteral( "ogr" ) );
Expand Down

0 comments on commit 6584fe7

Please sign in to comment.