Skip to content

Commit

Permalink
Merge pull request #5620 from pblottiere/bugfix_gpkg_bool
Browse files Browse the repository at this point in the history
[bugfix]  Fixes #17070 by considering bool fields as OGR integer fields with boolean subtype
  • Loading branch information
pblottiere committed Nov 15, 2017
2 parents f1c3692 + 7663589 commit bc90210
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 5 deletions.
6 changes: 5 additions & 1 deletion src/core/qgsogrutils.cpp
Expand Up @@ -129,7 +129,10 @@ QgsFields QgsOgrUtils::readOgrFields( OGRFeatureH ogrFet, QTextCodec *encoding )
switch ( OGR_Fld_GetType( fldDef ) )
{
case OFTInteger:
varType = QVariant::Int;
if ( OGR_Fld_GetSubType( fldDef ) == OFSTBoolean )
varType = QVariant::Bool;
else
varType = QVariant::Int;
break;
case OFTInteger64:
varType = QVariant::LongLong;
Expand Down Expand Up @@ -193,6 +196,7 @@ QVariant QgsOgrUtils::getOgrFeatureAttribute( OGRFeatureH ogrFet, const QgsField
break;
}
case QVariant::Int:
case QVariant::Bool:
value = QVariant( OGR_F_GetFieldAsInteger( ogrFet, attIndex ) );
break;
case QVariant::LongLong:
Expand Down
18 changes: 18 additions & 0 deletions src/core/qgsvectorfilewriter.cpp
Expand Up @@ -496,6 +496,12 @@ void QgsVectorFileWriter::init( QString vectorFileName,
ogrPrecision = 0;
break;

case QVariant::Bool:
ogrType = OFTInteger;
ogrWidth = 1;
ogrPrecision = 0;
break;

case QVariant::Double:
ogrType = OFTReal;
break;
Expand Down Expand Up @@ -573,6 +579,15 @@ void QgsVectorFileWriter::init( QString vectorFileName,
OGR_Fld_SetPrecision( fld.get(), ogrPrecision );
}

switch ( attrField.type() )
{
case QVariant::Bool:
OGR_Fld_SetSubType( fld.get(), OFSTBoolean );
break;
default:
break;
}

// create the field
QgsDebugMsg( "creating field " + attrField.name() +
" type " + QString( QVariant::typeToName( attrField.type() ) ) +
Expand Down Expand Up @@ -2039,6 +2054,9 @@ gdal::ogr_feature_unique_ptr QgsVectorFileWriter::createFeature( const QgsFeatur
case QVariant::ULongLong:
OGR_F_SetFieldInteger64( poFeature.get(), ogrField, attrValue.toLongLong() );
break;
case QVariant::Bool:
OGR_F_SetFieldInteger( poFeature.get(), ogrField, attrValue.toInt() );
break;
case QVariant::String:
OGR_F_SetFieldString( poFeature.get(), ogrField, mCodec->fromUnicode( attrValue.toString() ).constData() );
break;
Expand Down
41 changes: 37 additions & 4 deletions src/providers/ogr/qgsogrprovider.cpp
Expand Up @@ -108,6 +108,7 @@ QMap< QString, QDateTime > QgsOgrProviderUtils::mapDSNameToLastModifiedDate;
bool QgsOgrProvider::convertField( QgsField &field, const QTextCodec &encoding )
{
OGRFieldType ogrType = OFTString; //default to string
OGRFieldSubType ogrSubType = OFSTNone;
int ogrWidth = field.length();
int ogrPrecision = field.precision();
if ( ogrPrecision > 0 )
Expand All @@ -132,6 +133,13 @@ bool QgsOgrProvider::convertField( QgsField &field, const QTextCodec &encoding )
ogrPrecision = 0;
break;
case QVariant::Bool:
ogrType = OFTInteger;
ogrSubType = OFSTBoolean;
ogrWidth = 1;
ogrPrecision = 0;
break;
case QVariant::Double:
ogrType = OFTReal;
break;
Expand All @@ -152,7 +160,11 @@ bool QgsOgrProvider::convertField( QgsField &field, const QTextCodec &encoding )
return false;
}
field.setTypeName( encoding.toUnicode( OGR_GetFieldTypeName( ogrType ) ) );
if ( ogrSubType != OFSTNone )
field.setTypeName( encoding.toUnicode( OGR_GetFieldSubTypeName( ogrSubType ) ) );
else
field.setTypeName( encoding.toUnicode( OGR_GetFieldTypeName( ogrType ) ) );
field.setLength( ogrWidth );
field.setPrecision( ogrPrecision );
return true;
Expand Down Expand Up @@ -929,11 +941,19 @@ void QgsOgrProvider::loadFields()
{
OGRFieldDefnH fldDef = fdef.GetFieldDefn( i );
OGRFieldType ogrType = OGR_Fld_GetType( fldDef );
OGRFieldSubType ogrSubType = OFSTNone;

QVariant::Type varType;
switch ( ogrType )
{
case OFTInteger:
varType = QVariant::Int;
if ( OGR_Fld_GetSubType( fldDef ) == OFSTBoolean )
{
varType = QVariant::Bool;
ogrSubType = OFSTBoolean;
}
else
varType = QVariant::Int;
break;
case OFTInteger64:
varType = QVariant::LongLong;
Expand Down Expand Up @@ -979,13 +999,17 @@ void QgsOgrProvider::loadFields()
if ( prec > 0 )
width -= 1;

QString typeName = OGR_GetFieldTypeName( ogrType );
if ( ogrSubType != OFSTNone )
typeName = OGR_GetFieldSubTypeName( ogrSubType );

QgsField newField = QgsField(
name,
varType,
#ifdef ANDROID
OGR_GetFieldTypeName( ogrType ),
typeName,
#else
textEncoding()->toUnicode( OGR_GetFieldTypeName( ogrType ) ),
textEncoding()->toUnicode( typeName.toStdString().c_str() ),
#endif
width, prec
);
Expand Down Expand Up @@ -1474,6 +1498,7 @@ bool QgsOgrProvider::addAttributes( const QList<QgsField> &attributes )
switch ( iter->type() )
{
case QVariant::Int:
case QVariant::Bool:
type = OFTInteger;
break;
case QVariant::LongLong:
Expand Down Expand Up @@ -1515,6 +1540,14 @@ bool QgsOgrProvider::addAttributes( const QList<QgsField> &attributes )
OGR_Fld_SetWidth( fielddefn.get(), width );
OGR_Fld_SetPrecision( fielddefn.get(), iter->precision() );

switch ( iter->type() )
{
case QVariant::Bool:
OGR_Fld_SetSubType( fielddefn.get(), OFSTBoolean );
default:
break;
}

if ( mOgrLayer->CreateField( fielddefn.get(), true ) != OGRERR_NONE )
{
pushError( tr( "OGR error creating field %1: %2" ).arg( iter->name(), CPLGetLastErrorMsg() ) );
Expand Down
40 changes: 40 additions & 0 deletions tests/src/python/test_qgsvectorfilewriter.py
Expand Up @@ -93,6 +93,46 @@ def testWrite(self):

writeShape(self.mMemoryLayer, 'writetest.shp')

def testWriteWithBoolField(self):

# init connection string
dbconn = 'dbname=\'qgis_test\''
if 'QGIS_PGTEST_DB' in os.environ:
dbconn = os.environ['QGIS_PGTEST_DB']

# create a vector layer
vl = QgsVectorLayer('{} table="qgis_test"."boolean_table" sql='.format(dbconn), "testbool", "postgres")
self.assertTrue(vl.isValid())

# check that 1 of its fields is a bool
fields = vl.fields()
self.assertEqual(fields.at(fields.indexFromName('fld1')).type(), QVariant.Bool)

# write a gpkg package with a bool field
crs = QgsCoordinateReferenceSystem()
crs.createFromId(4326, QgsCoordinateReferenceSystem.EpsgCrsId)
filename = os.path.join(str(QDir.tempPath()), 'with_bool_field')
rc, errmsg = QgsVectorFileWriter.writeAsVectorFormat(vl,
filename,
'utf-8',
crs,
'GPKG')

self.assertEqual(rc, QgsVectorFileWriter.NoError)

# open the resulting geopackage
vl = QgsVectorLayer(filename + '.gpkg', '', 'ogr')
self.assertTrue(vl.isValid())
fields = vl.fields()

# test type of converted field
idx = fields.indexFromName('fld1')
self.assertEqual(fields.at(idx).type(), QVariant.Bool)

# test values
self.assertEqual(vl.getFeature(1).attributes()[idx], 1)
self.assertEqual(vl.getFeature(2).attributes()[idx], 0)

def testDateTimeWriteShapefile(self):
"""Check writing date and time fields to an ESRI shapefile."""
ml = QgsVectorLayer(
Expand Down

0 comments on commit bc90210

Please sign in to comment.