Skip to content

Commit

Permalink
Add support for arrays in PostgresQL
Browse files Browse the repository at this point in the history
Fix parsing of PostgresQL hstore. Had problems when the key or values were
containing comas.
  • Loading branch information
pvalsecc authored and Patrick Valsecchi committed Sep 12, 2016
1 parent 93afbe1 commit abc55f4
Show file tree
Hide file tree
Showing 19 changed files with 418 additions and 69 deletions.
16 changes: 15 additions & 1 deletion python/core/qgsfield.sip
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -24,13 +24,15 @@ class QgsField
* @param prec Field precision. Usually decimal places but may also be * @param prec Field precision. Usually decimal places but may also be
* used in conjunction with other fields types (eg. variable character fields) * used in conjunction with other fields types (eg. variable character fields)
* @param comment Comment for the field * @param comment Comment for the field
* @param subType If the field is a collection, its element's type.
*/ */
QgsField( const QString& name = QString(), QgsField( const QString& name = QString(),
QVariant::Type type = QVariant::Invalid, QVariant::Type type = QVariant::Invalid,
const QString& typeName = QString(), const QString& typeName = QString(),
int len = 0, int len = 0,
int prec = 0, int prec = 0,
const QString& comment = QString() ); const QString& comment = QString(),
QVariant::Type subType = QVariant::Invalid );


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


/**
* If the field is a collection, gets its element's type
* @note added in QGIS 3.0
*/
QVariant::Type subType() const;

/** /**
* Gets the field type. Field types vary depending on the data source. Examples * Gets the field type. Field types vary depending on the data source. Examples
* are char, int, double, blob, geometry, etc. The type is stored exactly as * are char, int, double, blob, geometry, etc. The type is stored exactly as
Expand Down Expand Up @@ -103,6 +111,12 @@ class QgsField
*/ */
void setType( QVariant::Type type ); void setType( QVariant::Type type );


/**
* If the field is a collection, set its element's type.
* @note added in QGIS 3.0
*/
void setSubType( QVariant::Type subType );

/** /**
* Set the field type. * Set the field type.
* @param typeName Field type * @param typeName Field type
Expand Down
16 changes: 16 additions & 0 deletions src/core/qgsexpression.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -5064,6 +5064,22 @@ QString QgsExpression::formatPreviewString( const QVariant& value )
} }
return tr( "<i>&lt;map: %1&gt;</i>" ).arg( mapStr ); return tr( "<i>&lt;map: %1&gt;</i>" ).arg( mapStr );
} }
else if ( value.type() == QVariant::List || value.type() == QVariant::StringList )
{
QString listStr;
const QVariantList list = value.toList();
for ( QVariantList::const_iterator it = list.constBegin(); it != list.constEnd(); ++it )
{
if ( !listStr.isEmpty() ) listStr.append( ", " );
listStr.append( formatPreviewString( *it ) );
if ( listStr.length() > MAX_PREVIEW + 3 )
{
listStr = QString( tr( "%1..." ) ).arg( listStr.left( MAX_PREVIEW ) );
break;
}
}
return tr( "<i>&lt;list: %1&gt;</i>" ).arg( listStr );
}
else else
{ {
return value.toString(); return value.toString();
Expand Down
4 changes: 3 additions & 1 deletion src/core/qgsexpressionfieldbuffer.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ void QgsExpressionFieldBuffer::writeXml( QDomNode& layerNode, QDomDocument& docu
fldElem.setAttribute( "comment", fld.field.comment() ); fldElem.setAttribute( "comment", fld.field.comment() );
fldElem.setAttribute( "length", fld.field.length() ); fldElem.setAttribute( "length", fld.field.length() );
fldElem.setAttribute( "type", fld.field.type() ); fldElem.setAttribute( "type", fld.field.type() );
fldElem.setAttribute( "subType", fld.field.subType() );
fldElem.setAttribute( "typeName", fld.field.typeName() ); fldElem.setAttribute( "typeName", fld.field.typeName() );


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


mExpressions.append( ExpressionField( exp, QgsField( name, type, typeName, length, precision, comment ) ) ); mExpressions.append( ExpressionField( exp, QgsField( name, type, typeName, length, precision, comment, subType ) ) );
} }
} }
} }
Expand Down
21 changes: 17 additions & 4 deletions src/core/qgsfield.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -44,9 +44,10 @@ QgsField::QgsField( QString nam, QString typ, int len, int prec, bool num,
} }
#endif #endif
QgsField::QgsField( const QString& name, QVariant::Type type, QgsField::QgsField( const QString& name, QVariant::Type type,
const QString& typeName, int len, int prec, const QString& comment ) const QString& typeName, int len, int prec, const QString& comment,
QVariant::Type subType )
{ {
d = new QgsFieldPrivate( name, type, typeName, len, prec, comment ); d = new QgsFieldPrivate( name, type, subType, typeName, len, prec, comment );
} }


QgsField::QgsField( const QgsField &other ) QgsField::QgsField( const QgsField &other )
Expand Down Expand Up @@ -99,6 +100,11 @@ QVariant::Type QgsField::type() const
return d->type; return d->type;
} }


QVariant::Type QgsField::subType() const
{
return d->subType;
}

QString QgsField::typeName() const QString QgsField::typeName() const
{ {
return d->typeName; return d->typeName;
Expand Down Expand Up @@ -140,6 +146,11 @@ void QgsField::setType( QVariant::Type type )
d->type = type; d->type = type;
} }


void QgsField::setSubType( QVariant::Type subType )
{
d->subType = subType;
}

void QgsField::setTypeName( const QString& typeName ) void QgsField::setTypeName( const QString& typeName )
{ {
d->typeName = typeName; d->typeName = typeName;
Expand Down Expand Up @@ -292,14 +303,15 @@ QDataStream& operator<<( QDataStream& out, const QgsField& field )
out << field.comment(); out << field.comment();
out << field.alias(); out << field.alias();
out << field.defaultValueExpression(); out << field.defaultValueExpression();
out << static_cast< quint32 >( field.subType() );
return out; return out;
} }


QDataStream& operator>>( QDataStream& in, QgsField& field ) QDataStream& operator>>( QDataStream& in, QgsField& field )
{ {
quint32 type, length, precision; quint32 type, subType, length, precision;
QString name, typeName, comment, alias, defaultValueExpression; QString name, typeName, comment, alias, defaultValueExpression;
in >> name >> type >> typeName >> length >> precision >> comment >> alias >> defaultValueExpression; in >> name >> type >> typeName >> length >> precision >> comment >> alias >> defaultValueExpression >> subType;
field.setName( name ); field.setName( name );
field.setType( static_cast< QVariant::Type >( type ) ); field.setType( static_cast< QVariant::Type >( type ) );
field.setTypeName( typeName ); field.setTypeName( typeName );
Expand All @@ -308,6 +320,7 @@ QDataStream& operator>>( QDataStream& in, QgsField& field )
field.setComment( comment ); field.setComment( comment );
field.setAlias( alias ); field.setAlias( alias );
field.setDefaultValueExpression( defaultValueExpression ); field.setDefaultValueExpression( defaultValueExpression );
field.setSubType( static_cast< QVariant::Type >( subType ) );
return in; return in;
} }


Expand Down
16 changes: 15 additions & 1 deletion src/core/qgsfield.h
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -66,13 +66,15 @@ class CORE_EXPORT QgsField
* @param prec Field precision. Usually decimal places but may also be * @param prec Field precision. Usually decimal places but may also be
* used in conjunction with other fields types (eg. variable character fields) * used in conjunction with other fields types (eg. variable character fields)
* @param comment Comment for the field * @param comment Comment for the field
* @param subType If the field is a collection, its element's type
*/ */
QgsField( const QString& name = QString(), QgsField( const QString& name = QString(),
QVariant::Type type = QVariant::Invalid, QVariant::Type type = QVariant::Invalid,
const QString& typeName = QString(), const QString& typeName = QString(),
int len = 0, int len = 0,
int prec = 0, int prec = 0,
const QString& comment = QString() ); const QString& comment = QString(),
QVariant::Type subType = QVariant::Invalid );


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


/**
* If the field is a collection, gets its element's type
* @note added in QGIS 3.0
*/
QVariant::Type subType() const;

/** /**
* Gets the field type. Field types vary depending on the data source. Examples * Gets the field type. Field types vary depending on the data source. Examples
* are char, int, double, blob, geometry, etc. The type is stored exactly as * are char, int, double, blob, geometry, etc. The type is stored exactly as
Expand Down Expand Up @@ -149,6 +157,12 @@ class CORE_EXPORT QgsField
*/ */
void setType( QVariant::Type type ); void setType( QVariant::Type type );


/**
* If the field is a collection, set its element's type.
* @note added in QGIS 3.0
*/
void setSubType( QVariant::Type subType );

/** /**
* Set the field type. * Set the field type.
* @param typeName Field type * @param typeName Field type
Expand Down
8 changes: 7 additions & 1 deletion src/core/qgsfield_p.h
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -44,12 +44,14 @@ class QgsFieldPrivate : public QSharedData


QgsFieldPrivate( const QString& name = QString(), QgsFieldPrivate( const QString& name = QString(),
QVariant::Type type = QVariant::Invalid, QVariant::Type type = QVariant::Invalid,
QVariant::Type subType = QVariant::Invalid,
const QString& typeName = QString(), const QString& typeName = QString(),
int len = 0, int len = 0,
int prec = 0, int prec = 0,
const QString& comment = QString() ) const QString& comment = QString() )
: name( name ) : name( name )
, type( type ) , type( type )
, subType( subType )
, typeName( typeName ) , typeName( typeName )
, length( len ) , length( len )
, precision( prec ) , precision( prec )
Expand All @@ -61,6 +63,7 @@ class QgsFieldPrivate : public QSharedData
: QSharedData( other ) : QSharedData( other )
, name( other.name ) , name( other.name )
, type( other.type ) , type( other.type )
, subType( other.subType )
, typeName( other.typeName ) , typeName( other.typeName )
, length( other.length ) , length( other.length )
, precision( other.precision ) , precision( other.precision )
Expand All @@ -74,7 +77,7 @@ class QgsFieldPrivate : public QSharedData


bool operator==( const QgsFieldPrivate& other ) const bool operator==( const QgsFieldPrivate& other ) const
{ {
return (( name == other.name ) && ( type == other.type ) return (( name == other.name ) && ( type == other.type ) && ( subType == other.subType )
&& ( length == other.length ) && ( precision == other.precision ) && ( length == other.length ) && ( precision == other.precision )
&& ( alias == other.alias ) && ( defaultValueExpression == other.defaultValueExpression ) ); && ( alias == other.alias ) && ( defaultValueExpression == other.defaultValueExpression ) );
} }
Expand All @@ -85,6 +88,9 @@ class QgsFieldPrivate : public QSharedData
//! Variant type //! Variant type
QVariant::Type type; QVariant::Type type;


//! If the variant is a collection, its element's type
QVariant::Type subType;

//! Type name from provider //! Type name from provider
QString typeName; QString typeName;


Expand Down
18 changes: 18 additions & 0 deletions src/providers/postgres/qgspostgresconn.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -961,6 +961,20 @@ static QString quotedMap( const QVariantMap& map )
return "E'" + ret + "'::hstore"; return "E'" + ret + "'::hstore";
} }


static QString quotedList( const QVariantList& list )
{
QString ret;
for ( QVariantList::const_iterator i = list.constBegin(); i != list.constEnd(); ++i )
{
if ( !ret.isEmpty() )
{
ret += ",";
}
ret.append( doubleQuotedMapValue( i->toString() ) );
}
return "E'{" + ret + "}'";
}

QString QgsPostgresConn::quotedValue( const QVariant& value ) QString QgsPostgresConn::quotedValue( const QVariant& value )
{ {
if ( value.isNull() ) if ( value.isNull() )
Expand All @@ -979,6 +993,10 @@ QString QgsPostgresConn::quotedValue( const QVariant& value )
case QVariant::Map: case QVariant::Map:
return quotedMap( value.toMap() ); return quotedMap( value.toMap() );


case QVariant::StringList:
case QVariant::List:
return quotedList( value.toList() );

case QVariant::String: case QVariant::String:
default: default:
return quotedString( value.toString() ); return quotedString( value.toString() );
Expand Down
5 changes: 3 additions & 2 deletions src/providers/postgres/qgspostgresfeatureiterator.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -739,7 +739,7 @@ bool QgsPostgresFeatureIterator::getFeature( QgsPostgresResult &queryResult, int
{ {
QgsField fld = mSource->mFields.at( idx ); QgsField fld = mSource->mFields.at( idx );


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


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


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


col++; col++;
Expand Down
Loading

0 comments on commit abc55f4

Please sign in to comment.