Skip to content
Permalink
Browse files

Fix offline editing with gpkg

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 6584fe7d580d7fe213f266d005aa7e0d827873fa
Showing with 73 additions and 9 deletions.
  1. +73 −9 src/core/qgsofflineediting.cpp
@@ -45,6 +45,8 @@
#include <QFile>
#include <QMessageBox>

#include <ogr_srs_api.h>

extern "C"
{
#include <sqlite3.h>
@@ -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" ) );

0 comments on commit 6584fe7

Please sign in to comment.
You can’t perform that action at this time.