Skip to content

Commit abc55f4

Browse files
pvalseccPatrick Valsecchi
authored and
Patrick Valsecchi
committed
Add support for arrays in PostgresQL
Fix parsing of PostgresQL hstore. Had problems when the key or values were containing comas.
1 parent 93afbe1 commit abc55f4

19 files changed

+418
-69
lines changed

python/core/qgsfield.sip

+15-1
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,15 @@ class QgsField
2424
* @param prec Field precision. Usually decimal places but may also be
2525
* used in conjunction with other fields types (eg. variable character fields)
2626
* @param comment Comment for the field
27+
* @param subType If the field is a collection, its element's type.
2728
*/
2829
QgsField( const QString& name = QString(),
2930
QVariant::Type type = QVariant::Invalid,
3031
const QString& typeName = QString(),
3132
int len = 0,
3233
int prec = 0,
33-
const QString& comment = QString() );
34+
const QString& comment = QString(),
35+
QVariant::Type subType = QVariant::Invalid );
3436

3537
/** Copy constructor
3638
*/
@@ -59,6 +61,12 @@ class QgsField
5961
//! Gets variant type of the field as it will be retrieved from data source
6062
QVariant::Type type() const;
6163

64+
/**
65+
* If the field is a collection, gets its element's type
66+
* @note added in QGIS 3.0
67+
*/
68+
QVariant::Type subType() const;
69+
6270
/**
6371
* Gets the field type. Field types vary depending on the data source. Examples
6472
* are char, int, double, blob, geometry, etc. The type is stored exactly as
@@ -103,6 +111,12 @@ class QgsField
103111
*/
104112
void setType( QVariant::Type type );
105113

114+
/**
115+
* If the field is a collection, set its element's type.
116+
* @note added in QGIS 3.0
117+
*/
118+
void setSubType( QVariant::Type subType );
119+
106120
/**
107121
* Set the field type.
108122
* @param typeName Field type

src/core/qgsexpression.cpp

+16
Original file line numberDiff line numberDiff line change
@@ -5064,6 +5064,22 @@ QString QgsExpression::formatPreviewString( const QVariant& value )
50645064
}
50655065
return tr( "<i>&lt;map: %1&gt;</i>" ).arg( mapStr );
50665066
}
5067+
else if ( value.type() == QVariant::List || value.type() == QVariant::StringList )
5068+
{
5069+
QString listStr;
5070+
const QVariantList list = value.toList();
5071+
for ( QVariantList::const_iterator it = list.constBegin(); it != list.constEnd(); ++it )
5072+
{
5073+
if ( !listStr.isEmpty() ) listStr.append( ", " );
5074+
listStr.append( formatPreviewString( *it ) );
5075+
if ( listStr.length() > MAX_PREVIEW + 3 )
5076+
{
5077+
listStr = QString( tr( "%1..." ) ).arg( listStr.left( MAX_PREVIEW ) );
5078+
break;
5079+
}
5080+
}
5081+
return tr( "<i>&lt;list: %1&gt;</i>" ).arg( listStr );
5082+
}
50675083
else
50685084
{
50695085
return value.toString();

src/core/qgsexpressionfieldbuffer.cpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ void QgsExpressionFieldBuffer::writeXml( QDomNode& layerNode, QDomDocument& docu
5454
fldElem.setAttribute( "comment", fld.field.comment() );
5555
fldElem.setAttribute( "length", fld.field.length() );
5656
fldElem.setAttribute( "type", fld.field.type() );
57+
fldElem.setAttribute( "subType", fld.field.subType() );
5758
fldElem.setAttribute( "typeName", fld.field.typeName() );
5859

5960
expressionFieldsElem.appendChild( fldElem );
@@ -79,9 +80,10 @@ void QgsExpressionFieldBuffer::readXml( const QDomNode& layerNode )
7980
int precision = field.attribute( "precision" ).toInt();
8081
int length = field.attribute( "length" ).toInt();
8182
QVariant::Type type = static_cast< QVariant::Type >( field.attribute( "type" ).toInt() );
83+
QVariant::Type subType = static_cast< QVariant::Type >( field.attribute( "subType", 0 ).toInt() );
8284
QString typeName = field.attribute( "typeName" );
8385

84-
mExpressions.append( ExpressionField( exp, QgsField( name, type, typeName, length, precision, comment ) ) );
86+
mExpressions.append( ExpressionField( exp, QgsField( name, type, typeName, length, precision, comment, subType ) ) );
8587
}
8688
}
8789
}

src/core/qgsfield.cpp

+17-4
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,10 @@ QgsField::QgsField( QString nam, QString typ, int len, int prec, bool num,
4444
}
4545
#endif
4646
QgsField::QgsField( const QString& name, QVariant::Type type,
47-
const QString& typeName, int len, int prec, const QString& comment )
47+
const QString& typeName, int len, int prec, const QString& comment,
48+
QVariant::Type subType )
4849
{
49-
d = new QgsFieldPrivate( name, type, typeName, len, prec, comment );
50+
d = new QgsFieldPrivate( name, type, subType, typeName, len, prec, comment );
5051
}
5152

5253
QgsField::QgsField( const QgsField &other )
@@ -99,6 +100,11 @@ QVariant::Type QgsField::type() const
99100
return d->type;
100101
}
101102

103+
QVariant::Type QgsField::subType() const
104+
{
105+
return d->subType;
106+
}
107+
102108
QString QgsField::typeName() const
103109
{
104110
return d->typeName;
@@ -140,6 +146,11 @@ void QgsField::setType( QVariant::Type type )
140146
d->type = type;
141147
}
142148

149+
void QgsField::setSubType( QVariant::Type subType )
150+
{
151+
d->subType = subType;
152+
}
153+
143154
void QgsField::setTypeName( const QString& typeName )
144155
{
145156
d->typeName = typeName;
@@ -292,14 +303,15 @@ QDataStream& operator<<( QDataStream& out, const QgsField& field )
292303
out << field.comment();
293304
out << field.alias();
294305
out << field.defaultValueExpression();
306+
out << static_cast< quint32 >( field.subType() );
295307
return out;
296308
}
297309

298310
QDataStream& operator>>( QDataStream& in, QgsField& field )
299311
{
300-
quint32 type, length, precision;
312+
quint32 type, subType, length, precision;
301313
QString name, typeName, comment, alias, defaultValueExpression;
302-
in >> name >> type >> typeName >> length >> precision >> comment >> alias >> defaultValueExpression;
314+
in >> name >> type >> typeName >> length >> precision >> comment >> alias >> defaultValueExpression >> subType;
303315
field.setName( name );
304316
field.setType( static_cast< QVariant::Type >( type ) );
305317
field.setTypeName( typeName );
@@ -308,6 +320,7 @@ QDataStream& operator>>( QDataStream& in, QgsField& field )
308320
field.setComment( comment );
309321
field.setAlias( alias );
310322
field.setDefaultValueExpression( defaultValueExpression );
323+
field.setSubType( static_cast< QVariant::Type >( subType ) );
311324
return in;
312325
}
313326

src/core/qgsfield.h

+15-1
Original file line numberDiff line numberDiff line change
@@ -66,13 +66,15 @@ class CORE_EXPORT QgsField
6666
* @param prec Field precision. Usually decimal places but may also be
6767
* used in conjunction with other fields types (eg. variable character fields)
6868
* @param comment Comment for the field
69+
* @param subType If the field is a collection, its element's type
6970
*/
7071
QgsField( const QString& name = QString(),
7172
QVariant::Type type = QVariant::Invalid,
7273
const QString& typeName = QString(),
7374
int len = 0,
7475
int prec = 0,
75-
const QString& comment = QString() );
76+
const QString& comment = QString(),
77+
QVariant::Type subType = QVariant::Invalid );
7678

7779
/** Copy constructor
7880
*/
@@ -105,6 +107,12 @@ class CORE_EXPORT QgsField
105107
//! Gets variant type of the field as it will be retrieved from data source
106108
QVariant::Type type() const;
107109

110+
/**
111+
* If the field is a collection, gets its element's type
112+
* @note added in QGIS 3.0
113+
*/
114+
QVariant::Type subType() const;
115+
108116
/**
109117
* Gets the field type. Field types vary depending on the data source. Examples
110118
* are char, int, double, blob, geometry, etc. The type is stored exactly as
@@ -149,6 +157,12 @@ class CORE_EXPORT QgsField
149157
*/
150158
void setType( QVariant::Type type );
151159

160+
/**
161+
* If the field is a collection, set its element's type.
162+
* @note added in QGIS 3.0
163+
*/
164+
void setSubType( QVariant::Type subType );
165+
152166
/**
153167
* Set the field type.
154168
* @param typeName Field type

src/core/qgsfield_p.h

+7-1
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,14 @@ class QgsFieldPrivate : public QSharedData
4444

4545
QgsFieldPrivate( const QString& name = QString(),
4646
QVariant::Type type = QVariant::Invalid,
47+
QVariant::Type subType = QVariant::Invalid,
4748
const QString& typeName = QString(),
4849
int len = 0,
4950
int prec = 0,
5051
const QString& comment = QString() )
5152
: name( name )
5253
, type( type )
54+
, subType( subType )
5355
, typeName( typeName )
5456
, length( len )
5557
, precision( prec )
@@ -61,6 +63,7 @@ class QgsFieldPrivate : public QSharedData
6163
: QSharedData( other )
6264
, name( other.name )
6365
, type( other.type )
66+
, subType( other.subType )
6467
, typeName( other.typeName )
6568
, length( other.length )
6669
, precision( other.precision )
@@ -74,7 +77,7 @@ class QgsFieldPrivate : public QSharedData
7477

7578
bool operator==( const QgsFieldPrivate& other ) const
7679
{
77-
return (( name == other.name ) && ( type == other.type )
80+
return (( name == other.name ) && ( type == other.type ) && ( subType == other.subType )
7881
&& ( length == other.length ) && ( precision == other.precision )
7982
&& ( alias == other.alias ) && ( defaultValueExpression == other.defaultValueExpression ) );
8083
}
@@ -85,6 +88,9 @@ class QgsFieldPrivate : public QSharedData
8588
//! Variant type
8689
QVariant::Type type;
8790

91+
//! If the variant is a collection, its element's type
92+
QVariant::Type subType;
93+
8894
//! Type name from provider
8995
QString typeName;
9096

src/providers/postgres/qgspostgresconn.cpp

+18
Original file line numberDiff line numberDiff line change
@@ -961,6 +961,20 @@ static QString quotedMap( const QVariantMap& map )
961961
return "E'" + ret + "'::hstore";
962962
}
963963

964+
static QString quotedList( const QVariantList& list )
965+
{
966+
QString ret;
967+
for ( QVariantList::const_iterator i = list.constBegin(); i != list.constEnd(); ++i )
968+
{
969+
if ( !ret.isEmpty() )
970+
{
971+
ret += ",";
972+
}
973+
ret.append( doubleQuotedMapValue( i->toString() ) );
974+
}
975+
return "E'{" + ret + "}'";
976+
}
977+
964978
QString QgsPostgresConn::quotedValue( const QVariant& value )
965979
{
966980
if ( value.isNull() )
@@ -979,6 +993,10 @@ QString QgsPostgresConn::quotedValue( const QVariant& value )
979993
case QVariant::Map:
980994
return quotedMap( value.toMap() );
981995

996+
case QVariant::StringList:
997+
case QVariant::List:
998+
return quotedList( value.toList() );
999+
9821000
case QVariant::String:
9831001
default:
9841002
return quotedString( value.toString() );

src/providers/postgres/qgspostgresfeatureiterator.cpp

+3-2
Original file line numberDiff line numberDiff line change
@@ -739,7 +739,7 @@ bool QgsPostgresFeatureIterator::getFeature( QgsPostgresResult &queryResult, int
739739
{
740740
QgsField fld = mSource->mFields.at( idx );
741741

742-
QVariant v = QgsPostgresProvider::convertValue( fld.type(), queryResult.PQgetvalue( row, col ) );
742+
QVariant v = QgsPostgresProvider::convertValue( fld.type(), fld.subType(), queryResult.PQgetvalue( row, col ) );
743743
primaryKeyVals << v;
744744

745745
if ( !subsetOfAttributes || fetchAttributes.contains( idx ) )
@@ -781,7 +781,8 @@ void QgsPostgresFeatureIterator::getFeatureAttribute( int idx, QgsPostgresResult
781781
if ( mSource->mPrimaryKeyAttrs.contains( idx ) )
782782
return;
783783

784-
QVariant v = QgsPostgresProvider::convertValue( mSource->mFields.at( idx ).type(), queryResult.PQgetvalue( row, col ) );
784+
const QgsField fld = mSource->mFields.at( idx );
785+
QVariant v = QgsPostgresProvider::convertValue( fld.type(), fld.subType(), queryResult.PQgetvalue( row, col ) );
785786
feature.setAttribute( idx, v );
786787

787788
col++;

0 commit comments

Comments
 (0)