Skip to content
Permalink
Browse files

[QgsVectorFileWriter + OGR provider] Create Integer64 fields as Real …

…fields when output driver doesn't support Integer64

Fix #15405
  • Loading branch information
rouault committed Aug 8, 2016
1 parent f17f6ac commit f8ede277dcea55b5789d0ff9c11ff54ef889633f
@@ -45,6 +45,7 @@
#include <ogr_srs_api.h>
#include <cpl_error.h>
#include <cpl_conv.h>
#include <gdal.h>

#if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 1800
#define TO8F(x) (x).toUtf8().constData()
@@ -435,10 +436,16 @@ void QgsVectorFileWriter::init( QString vectorFileName,
break;
#else
case QVariant::LongLong:
ogrType = OFTInteger64;
{
const char* pszDataTypes = GDALGetMetadataItem( poDriver, GDAL_DMD_CREATIONFIELDDATATYPES, NULL );
if ( pszDataTypes && strstr( pszDataTypes, "Integer64" ) )
ogrType = OFTInteger64;
else
ogrType = OFTReal;
ogrWidth = ogrWidth > 0 && ogrWidth <= 20 ? ogrWidth : 20;
ogrPrecision = 0;
break;
}
#endif
case QVariant::String:
ogrType = OFTString;
@@ -1276,6 +1276,8 @@ bool QgsOgrProvider::addAttributes( const QList<QgsField> &attributes )

bool returnvalue = true;

QMap< QString, QVariant::Type > mapFieldTypesToPatch;

for ( QList<QgsField>::const_iterator iter = attributes.begin(); iter != attributes.end(); ++iter )
{
OGRFieldType type;
@@ -1287,8 +1289,17 @@ bool QgsOgrProvider::addAttributes( const QList<QgsField> &attributes )
break;
#if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 2000000
case QVariant::LongLong:
type = OFTInteger64;
{
const char* pszDataTypes = GDALGetMetadataItem( ogrDriver, GDAL_DMD_CREATIONFIELDDATATYPES, NULL );
if ( pszDataTypes && strstr( pszDataTypes, "Integer64" ) )
type = OFTInteger64;
else
{
mapFieldTypesToPatch[ iter->name()] = iter->type();
type = OFTReal;
}
break;
}
#endif
case QVariant::Double:
type = OFTReal;
@@ -1326,6 +1337,16 @@ bool QgsOgrProvider::addAttributes( const QList<QgsField> &attributes )
OGR_Fld_Destroy( fielddefn );
}
loadFields();

// Patch field type in case of Integer64->Real mapping so that QVariant::LongLong
// is still returned to the caller
for ( QMap< QString, QVariant::Type >::const_iterator it = mapFieldTypesToPatch.begin(); it != mapFieldTypesToPatch.end(); ++it )
{
int idx = mAttributeFields.fieldNameIndex( it.key() );
if ( idx >= 0 )
mAttributeFields[ idx ].setType( *it );
}

return returnvalue;
}

@@ -14,8 +14,8 @@

import os
import tempfile
from qgis.core import QgsVectorLayer, QgsFeatureRequest, QgsVectorDataProvider
from qgis.PyQt.QtCore import QDate, QTime, QDateTime, QVariant
from qgis.core import QgsVectorLayer, QgsFeatureRequest, QgsVectorDataProvider, QgsField
from qgis.PyQt.QtCore import QDate, QTime, QDateTime, QVariant, QDir
from qgis.testing import (
start_app,
unittest
@@ -90,6 +90,20 @@ def testUpdateMode(self):
self.assertEquals(vl.dataProvider().property("_debug_open_mode"), "read-only")
self.assertTrue(vl.dataProvider().isValid())

@unittest.expectedFailure(int(osgeo.gdal.VersionInfo()[:1]) < 2)
def testInteger64WriteTabfile(self):
"""Check writing Integer64 fields to an MapInfo tabfile (which does not support that type)."""

base_dest_file_name = os.path.join(str(QDir.tempPath()), 'integer64')
dest_file_name = base_dest_file_name + '.tab'
shutil.copy(os.path.join(TEST_DATA_DIR, 'tab_file.tab'), base_dest_file_name + '.tab')
shutil.copy(os.path.join(TEST_DATA_DIR, 'tab_file.dat'), base_dest_file_name + '.dat')
shutil.copy(os.path.join(TEST_DATA_DIR, 'tab_file.map'), base_dest_file_name + '.map')
shutil.copy(os.path.join(TEST_DATA_DIR, 'tab_file.id'), base_dest_file_name + '.id')
vl = QgsVectorLayer(u'{}|layerid=0'.format(dest_file_name), u'test', u'ogr')
self.assertTrue(vl.isValid())
self.assertTrue(vl.dataProvider().addAttributes([QgsField("int8", QVariant.LongLong, "integer64")]))


if __name__ == '__main__':
unittest.main()
@@ -36,6 +36,10 @@
start_app()


def GDAL_COMPUTE_VERSION(maj, min, rev):
return ((maj) * 1000000 + (min) * 10000 + (rev) * 100)


class TestFieldValueConverter(QgsVectorFileWriter.FieldValueConverter):

def __init__(self, layer):
@@ -416,5 +420,47 @@ def testValueConverter(self):
self.assertEqual(f['nonconv'], 1)
self.assertEqual(f['conv_attr'], 'converted_val')

@unittest.expectedFailure(int(osgeo.gdal.VersionInfo('VERSION_NUM')) < GDAL_COMPUTE_VERSION(2, 0, 0))
def testInteger64WriteTabfile(self):
"""Check writing Integer64 fields to an MapInfo tabfile (which does not support that type)."""
ml = QgsVectorLayer(
('Point?crs=epsg:4326&field=int8:int8'),
'test',
'memory')

self.assertIsNotNone(ml, 'Provider not initialized')
self.assertTrue(ml.isValid(), 'Source layer not valid')
provider = ml.dataProvider()
self.assertIsNotNone(provider)

ft = QgsFeature()
ft.setAttributes([2123456789])
res, features = provider.addFeatures([ft])
self.assertTrue(res)
self.assertTrue(features)

dest_file_name = os.path.join(str(QDir.tempPath()), 'integer64.tab')
crs = QgsCoordinateReferenceSystem()
crs.createFromId(4326, QgsCoordinateReferenceSystem.EpsgCrsId)
write_result = QgsVectorFileWriter.writeAsVectorFormat(
ml,
dest_file_name,
'utf-8',
crs,
'MapInfo File')
self.assertEqual(write_result, QgsVectorFileWriter.NoError)

# Open result and check
created_layer = QgsVectorLayer(u'{}|layerid=0'.format(dest_file_name), u'test', u'ogr')

fields = created_layer.dataProvider().fields()
self.assertEqual(fields.at(fields.indexFromName('int8')).type(), QVariant.Double)

f = next(created_layer.getFeatures(QgsFeatureRequest()))

int8_idx = created_layer.fieldNameIndex('int8')
self.assertEqual(f.attributes()[int8_idx], 2123456789)


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

0 comments on commit f8ede27

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