Skip to content

Commit

Permalink
[ogr] Add support for integer, real and integer64 list data types
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Apr 3, 2021
1 parent 3a6f643 commit e142884
Show file tree
Hide file tree
Showing 6 changed files with 838 additions and 50 deletions.
182 changes: 174 additions & 8 deletions src/core/providers/ogr/qgsogrprovider.cpp
Expand Up @@ -170,14 +170,32 @@ bool QgsOgrProvider::convertField( QgsField &field, const QTextCodec &encoding )
ogrType = OFTDateTime;
break;

case QVariant::StringList:
{
ogrType = OFTStringList;
break;
}

case QVariant::List:
if ( field.subType() == QVariant::String )
{
ogrType = OFTStringList;
}
else if ( field.subType() == QVariant::Int )
{
ogrType = OFTIntegerList;
}
else if ( field.subType() == QVariant::LongLong )
{
ogrType = OFTInteger64List;
}
else if ( field.subType() == QVariant::Double )
{
ogrType = OFTRealList;
}
else
{
// only string lists are supported at this moment
// other lists are supported at this moment
return false;
}
break;
Expand Down Expand Up @@ -1224,10 +1242,25 @@ void QgsOgrProvider::loadFields()
break;

case OFTStringList:
varType = QVariant::List;
varType = QVariant::StringList;
varSubType = QVariant::String;
break;

case OFTIntegerList:
varType = QVariant::List;
varSubType = QVariant::Int;
break;

case OFTRealList:
varType = QVariant::List;
varSubType = QVariant::Double;
break;

case OFTInteger64List:
varType = QVariant::List;
varSubType = QVariant::LongLong;
break;

default:
varType = QVariant::String; // other unsupported, leave it as a string
}
Expand Down Expand Up @@ -1764,7 +1797,7 @@ bool QgsOgrProvider::addFeaturePrivate( QgsFeature &f, Flags flags, QgsFeatureId
{
OGR_F_UnsetField( feature.get(), ogrAttributeId );
}
else if ( attrVal.isNull() || ( type != OFTString && attrVal.toString().isEmpty() ) )
else if ( attrVal.isNull() || ( type != OFTString && ( ( attrVal.type() != QVariant::List && attrVal.toString().isEmpty() ) || ( attrVal.type() == QVariant::List && attrVal.toList().empty() ) ) ) )
{
// Starting with GDAL 2.2, there are 2 concepts: unset fields and null fields
// whereas previously there was only unset fields. For a GeoJSON output,
Expand Down Expand Up @@ -1857,7 +1890,7 @@ bool QgsOgrProvider::addFeaturePrivate( QgsFeature &f, Flags flags, QgsFeatureId
if ( count > 0 )
{
int pos = 0;
for ( QString string : list )
for ( const QString &string : list )
{
lst[pos] = textEncoding()->fromUnicode( string ).data();
pos++;
Expand All @@ -1868,6 +1901,63 @@ bool QgsOgrProvider::addFeaturePrivate( QgsFeature &f, Flags flags, QgsFeatureId
break;
}

case OFTIntegerList:
{
const QVariantList list = attrVal.toList();
const int count = list.count();
int *lst = new int[count];
if ( count > 0 )
{
int pos = 0;
for ( const QVariant &value : list )
{
lst[pos] = value.toInt();
pos++;
}
}
OGR_F_SetFieldIntegerList( feature.get(), ogrAttributeId, count, lst );
delete [] lst;
break;
}

case OFTRealList:
{
const QVariantList list = attrVal.toList();
const int count = list.count();
double *lst = new double[count];
if ( count > 0 )
{
int pos = 0;
for ( const QVariant &value : list )
{
lst[pos] = value.toDouble();
pos++;
}
}
OGR_F_SetFieldDoubleList( feature.get(), ogrAttributeId, count, lst );
delete [] lst;
break;
}

case OFTInteger64List:
{
const QVariantList list = attrVal.toList();
const int count = list.count();
long long *lst = new long long[count];
if ( count > 0 )
{
int pos = 0;
for ( const QVariant &value : list )
{
lst[pos] = value.toLongLong();
pos++;
}
}
OGR_F_SetFieldInteger64List( feature.get(), ogrAttributeId, count, lst );
delete [] lst;
break;
}

default:
QgsMessageLog::logMessage( tr( "type %1 for attribute %2 not found" ).arg( type ).arg( qgisAttributeId ), tr( "OGR" ) );
break;
Expand Down Expand Up @@ -2026,13 +2116,32 @@ bool QgsOgrProvider::addAttributeOGRLevel( const QgsField &field, bool &ignoreEr
case QVariant::Map:
type = OFTString;
break;
case QVariant::StringList:
type = OFTStringList;
break;
case QVariant::List:
// only string list supported at the moment, fall through to default for other types
if ( field.subType() == QVariant::String )
{
type = OFTStringList;
break;
}
else if ( field.subType() == QVariant::Int )
{
type = OFTIntegerList;
break;
}
else if ( field.subType() == QVariant::LongLong )
{
type = OFTInteger64List;
break;
}
else if ( field.subType() == QVariant::Double )
{
type = OFTRealList;
break;
}
// other lists are supported at this moment, fall through to default for other types

//intentional fall-through
FALLTHROUGH

Expand All @@ -2044,7 +2153,7 @@ bool QgsOgrProvider::addAttributeOGRLevel( const QgsField &field, bool &ignoreEr

gdal::ogr_field_def_unique_ptr fielddefn( OGR_Fld_Create( textEncoding()->fromUnicode( field.name() ).constData(), type ) );
int width = field.length();
// Increase width by 1 for OFTReal to make room for the decimal point
// Increase width by 1 for OFTReal to make room for the decimal point
if ( type == OFTReal && field.precision() )
width += 1;
OGR_Fld_SetWidth( fielddefn.get(), width );
Expand Down Expand Up @@ -2487,7 +2596,7 @@ bool QgsOgrProvider::changeAttributeValues( const QgsChangedAttributesMap &attr_

OGRFieldType type = OGR_Fld_GetType( fd );

if ( it2->isNull() || ( type != OFTString && it2->toString().isEmpty() ) )
if ( it2->isNull() || ( type != OFTString && ( ( it2->type() != QVariant::List && it2->toString().isEmpty() ) || ( it2->type() == QVariant::List && it2->toList().empty() ) ) ) )
{
// Starting with GDAL 2.2, there are 2 concepts: unset fields and null fields
// whereas previously there was only unset fields. For a GeoJSON output,
Expand Down Expand Up @@ -2568,7 +2677,7 @@ bool QgsOgrProvider::changeAttributeValues( const QgsChangedAttributesMap &attr_
if ( count > 0 )
{
int pos = 0;
for ( QString string : list )
for ( const QString &string : list )
{
lst[pos] = textEncoding()->fromUnicode( string ).data();
pos++;
Expand All @@ -2579,6 +2688,63 @@ bool QgsOgrProvider::changeAttributeValues( const QgsChangedAttributesMap &attr_
break;
}

case OFTIntegerList:
{
const QVariantList list = it2->toList();
const int count = list.count();
int *lst = new int[count];
if ( count > 0 )
{
int pos = 0;
for ( const QVariant &value : list )
{
lst[pos] = value.toInt();
pos++;
}
}
OGR_F_SetFieldIntegerList( of.get(), f, count, lst );
delete [] lst;
break;
}

case OFTRealList:
{
const QVariantList list = it2->toList();
const int count = list.count();
double *lst = new double[count];
if ( count > 0 )
{
int pos = 0;
for ( const QVariant &value : list )
{
lst[pos] = value.toDouble();
pos++;
}
}
OGR_F_SetFieldDoubleList( of.get(), f, count, lst );
delete [] lst;
break;
}

case OFTInteger64List:
{
const QVariantList list = it2->toList();
const int count = list.count();
long long *lst = new long long[count];
if ( count > 0 )
{
int pos = 0;
for ( const QVariant &value : list )
{
lst[pos] = value.toLongLong();
pos++;
}
}
OGR_F_SetFieldInteger64List( of.get(), f, count, lst );
delete [] lst;
break;
}

default:
pushError( tr( "Type %1 of attribute %2 of feature %3 unknown." ).arg( type ).arg( fid ).arg( f ) );
break;
Expand Down
112 changes: 95 additions & 17 deletions src/core/qgsogrutils.cpp
Expand Up @@ -280,30 +280,108 @@ QVariant QgsOgrUtils::getOgrFeatureAttribute( OGRFeatureH ogrFet, const QgsField
break;
}

case QVariant::StringList:
{
QStringList list;
char **lst = OGR_F_GetFieldAsStringList( ogrFet, attIndex );
const int count = CSLCount( lst );
if ( count > 0 )
{
list.reserve( count );
for ( int i = 0; i < count; i++ )
{
if ( encoding )
list << encoding->toUnicode( lst[i] );
else
list << QString::fromUtf8( lst[i] );
}
}
value = list;
break;
}

case QVariant::List:
{
if ( field.subType() == QVariant::String )
switch ( field.subType() )
{
QStringList list;
char **lst = OGR_F_GetFieldAsStringList( ogrFet, attIndex );
const int count = CSLCount( lst );
if ( count > 0 )
case QVariant::String:
{
for ( int i = 0; i < count; i++ )
QStringList list;
char **lst = OGR_F_GetFieldAsStringList( ogrFet, attIndex );
const int count = CSLCount( lst );
if ( count > 0 )
{
if ( encoding )
list << encoding->toUnicode( lst[i] );
else
list << QString::fromUtf8( lst[i] );
list.reserve( count );
for ( int i = 0; i < count; i++ )
{
if ( encoding )
list << encoding->toUnicode( lst[i] );
else
list << QString::fromUtf8( lst[i] );
}
}
value = list;
break;
}

case QVariant::Int:
{
QVariantList list;
int count = 0;
const int *lst = OGR_F_GetFieldAsIntegerList( ogrFet, attIndex, &count );
if ( count > 0 )
{
list.reserve( count );
for ( int i = 0; i < count; i++ )
{
list << lst[i];
}
}
value = list;
break;
}

case QVariant::Double:
{
QVariantList list;
int count = 0;
const double *lst = OGR_F_GetFieldAsDoubleList( ogrFet, attIndex, &count );
if ( count > 0 )
{
list.reserve( count );
for ( int i = 0; i < count; i++ )
{
list << lst[i];
}
}
value = list;
break;
}

case QVariant::LongLong:
{
QVariantList list;
int count = 0;
const long long *lst = OGR_F_GetFieldAsInteger64List( ogrFet, attIndex, &count );
if ( count > 0 )
{
list.reserve( count );
for ( int i = 0; i < count; i++ )
{
list << lst[i];
}
}
value = list;
break;
}

default:
{
Q_ASSERT_X( false, "QgsOgrUtils::getOgrFeatureAttribute", "unsupported field type" );
if ( ok )
*ok = false;
break;
}
value = list;
}
else
{
Q_ASSERT_X( false, "QgsOgrUtils::getOgrFeatureAttribute", "unsupported field type" );
if ( ok )
*ok = false;
}
break;
}
Expand Down

0 comments on commit e142884

Please sign in to comment.