Skip to content

Commit 6584fe7

Browse files
committed
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
1 parent a60324b commit 6584fe7

File tree

1 file changed

+73
-9
lines changed

1 file changed

+73
-9
lines changed

src/core/qgsofflineediting.cpp

Lines changed: 73 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@
4545
#include <QFile>
4646
#include <QMessageBox>
4747

48+
#include <ogr_srs_api.h>
49+
4850
extern "C"
4951
{
5052
#include <sqlite3.h>
@@ -630,18 +632,80 @@ QgsVectorLayer *QgsOfflineEditing::copyVectorLayer( QgsVectorLayer *layer, sqlit
630632
}
631633
case GPKG:
632634
{
633-
QgsVectorFileWriter::SaveVectorOptions options;
634-
options.driverName = QStringLiteral( "GPKG" );
635-
options.layerName = tableName;
636-
options.actionOnExistingFile = QgsVectorFileWriter::CreateOrOverwriteLayer;
637-
options.onlySelectedFeatures = onlySelected;
638-
639-
QString error;
640-
if ( QgsVectorFileWriter::writeAsVectorFormat( layer, offlineDbPath, options, &error ) != QgsVectorFileWriter::NoError )
635+
// Set options
636+
char **options = nullptr;
637+
638+
options = CSLSetNameValue( options, "OVERWRITE", "YES" );
639+
options = CSLSetNameValue( options, "IDENTIFIER", layer->name().toUtf8().constData() );
640+
options = CSLSetNameValue( options, "DESCRIPTION", layer->dataComment().toUtf8().constData() );
641+
#if 0
642+
options = CSLSetNameValue( options, "FID", featureId.toUtf8().constData() );
643+
#endif
644+
645+
if ( layer->isSpatial() )
646+
{
647+
options = CSLSetNameValue( options, "GEOMETRY_COLUMN", "geom" );
648+
options = CSLSetNameValue( options, "SPATIAL_INDEX", "YES" );
649+
}
650+
651+
OGRSFDriverH hDriver = nullptr;
652+
OGRSpatialReferenceH hSRS = OSRNewSpatialReference( layer->crs().toWkt().toLocal8Bit().data() );
653+
gdal::ogr_datasource_unique_ptr hDS( OGROpen( offlineDbPath.toUtf8().constData(), true, &hDriver ) );
654+
OGRLayerH hLayer = OGR_DS_CreateLayer( hDS.get(), tableName.toUtf8().constData(), hSRS, static_cast<OGRwkbGeometryType>( layer->wkbType() ), options );
655+
CSLDestroy( options );
656+
if ( hSRS )
657+
OSRRelease( hSRS );
658+
if ( !hLayer )
659+
{
660+
showWarning( tr( "Creation of layer failed (OGR error: %1)" ).arg( QString::fromUtf8( CPLGetLastErrorMsg() ) ) );
661+
return nullptr;
662+
}
663+
664+
const QgsFields providerFields = layer->dataProvider()->fields();
665+
for ( const auto &field : providerFields )
666+
{
667+
const QString fieldName( field.name() );
668+
const QVariant::Type type = field.type();
669+
OGRFieldType ogrType( OFTString );
670+
if ( type == QVariant::Int )
671+
ogrType = OFTInteger;
672+
else if ( type == QVariant::LongLong )
673+
ogrType = OFTInteger64;
674+
else if ( type == QVariant::Double )
675+
ogrType = OFTReal;
676+
else if ( type == QVariant::Time )
677+
ogrType = OFTTime;
678+
else if ( type == QVariant::Date )
679+
ogrType = OFTDate;
680+
else if ( type == QVariant::DateTime )
681+
ogrType = OFTDateTime;
682+
else
683+
ogrType = OFTString;
684+
685+
int ogrWidth = field.length();
686+
687+
gdal::ogr_field_def_unique_ptr fld( OGR_Fld_Create( fieldName.toUtf8().constData(), ogrType ) );
688+
OGR_Fld_SetWidth( fld.get(), ogrWidth );
689+
690+
if ( OGR_L_CreateField( hLayer, fld.get(), true ) != OGRERR_NONE )
691+
{
692+
showWarning( tr( "Creation of field %1 failed (OGR error: %2)" )
693+
.arg( fieldName, QString::fromUtf8( CPLGetLastErrorMsg() ) ) );
694+
return nullptr;
695+
}
696+
}
697+
698+
// In GDAL >= 2.0, the driver implements a deferred creation strategy, so
699+
// issue a command that will force table creation
700+
CPLErrorReset();
701+
OGR_L_ResetReading( hLayer );
702+
if ( CPLGetLastErrorType() != CE_None )
641703
{
642-
showWarning( tr( "Packaging layer %1 failed: %2" ).arg( layer->name(), error ) );
704+
QString msg( tr( "Creation of layer failed (OGR error: %1)" ).arg( QString::fromUtf8( CPLGetLastErrorMsg() ) ) );
705+
showWarning( msg );
643706
return nullptr;
644707
}
708+
hDS.reset();
645709

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

0 commit comments

Comments
 (0)