Skip to content

Commit

Permalink
Add support for binary fields to QgsVectorFileWriter
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Nov 12, 2018
1 parent f3f1214 commit 608d03c
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 1 deletion.
12 changes: 12 additions & 0 deletions src/core/qgsvectorfilewriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,10 @@ void QgsVectorFileWriter::init( QString vectorFileName,
}
break;

case QVariant::ByteArray:
ogrType = OFTBinary;
break;

default:
//assert(0 && "invalid variant type!");
mErrorMessage = QObject::tr( "Unsupported type for field %1" )
Expand Down Expand Up @@ -2207,6 +2211,14 @@ gdal::ogr_feature_unique_ptr QgsVectorFileWriter::createFeature( const QgsFeatur
0 );
}
break;

case QVariant::ByteArray:
{
const QByteArray ba = attrValue.toByteArray();
OGR_F_SetFieldBinary( poFeature.get(), ogrField, ba.size(), const_cast< GByte * >( reinterpret_cast< const GByte * >( ba.data() ) ) );
break;
}

case QVariant::Invalid:
break;
default:
Expand Down
63 changes: 62 additions & 1 deletion tests/src/python/test_qgsvectorfilewriter.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
QgsRectangle,
QgsCoordinateTransform
)
from qgis.PyQt.QtCore import QDate, QTime, QDateTime, QVariant, QDir
from qgis.PyQt.QtCore import QDate, QTime, QDateTime, QVariant, QDir, QByteArray
import os
import tempfile
import osgeo.gdal # NOQA
Expand Down Expand Up @@ -1044,6 +1044,67 @@ def testDropZ(self):
f = next(created_layer.getFeatures(QgsFeatureRequest()))
self.assertEqual(f.geometry().asWkt(), 'Point (10 10)')

def testWriteWithBinaryField(self):
"""
Test writing with a binary field
:return:
"""
basetestpath = tempfile.mkdtemp()

tmpfile = os.path.join(basetestpath, 'binaryfield.sqlite')
ds = ogr.GetDriverByName('SQLite').CreateDataSource(tmpfile)
lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint, options=['FID=fid'])
lyr.CreateField(ogr.FieldDefn('strfield', ogr.OFTString))
lyr.CreateField(ogr.FieldDefn('intfield', ogr.OFTInteger))
lyr.CreateField(ogr.FieldDefn('binfield', ogr.OFTBinary))
lyr.CreateField(ogr.FieldDefn('binfield2', ogr.OFTBinary))
f = None
ds = None

vl = QgsVectorLayer(tmpfile)
self.assertTrue(vl.isValid())

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

dp = vl.dataProvider()
f = QgsFeature(fields)
bin_1 = b'xxx'
bin_2 = b'yyy'
bin_val1 = QByteArray(bin_1)
bin_val2 = QByteArray(bin_2)
f.setAttributes([1, 'str', 100, bin_val1, bin_val2])
self.assertTrue(dp.addFeature(f))

# write a gpkg package with a binary field
filename = os.path.join(str(QDir.tempPath()), 'with_bin_field')
rc, errmsg = QgsVectorFileWriter.writeAsVectorFormat(vl,
filename,
'utf-8',
vl.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('binfield')
self.assertEqual(fields.at(idx).type(), QVariant.ByteArray)
idx2 = fields.indexFromName('binfield2')
self.assertEqual(fields.at(idx2).type(), QVariant.ByteArray)

# test values
self.assertEqual(vl.getFeature(1).attributes()[idx], bin_val1)
self.assertEqual(vl.getFeature(1).attributes()[idx2], bin_val2)

del vl
os.unlink(filename + '.gpkg')


if __name__ == '__main__':
unittest.main()

0 comments on commit 608d03c

Please sign in to comment.