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
Expand Up @@ -24,13 +24,15 @@ class QgsField
* @param prec Field precision. Usually decimal places but may also be
* used in conjunction with other fields types (eg. variable character fields)
* @param comment Comment for the field
* @param subType If the field is a collection, its element's type.
*/
QgsField( const QString& name = QString(),
QVariant::Type type = QVariant::Invalid,
const QString& typeName = QString(),
int len = 0,
int prec = 0,
const QString& comment = QString() );
const QString& comment = QString(),
QVariant::Type subType = QVariant::Invalid );

/** 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
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
* 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 );

/**
* 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.
* @param typeName Field type
Expand Down
16 changes: 16 additions & 0 deletions src/core/qgsexpression.cpp
Expand Up @@ -5064,6 +5064,22 @@ QString QgsExpression::formatPreviewString( const QVariant& value )
}
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
{
return value.toString();
Expand Down
4 changes: 3 additions & 1 deletion src/core/qgsexpressionfieldbuffer.cpp
Expand Up @@ -54,6 +54,7 @@ void QgsExpressionFieldBuffer::writeXml( QDomNode& layerNode, QDomDocument& docu
fldElem.setAttribute( "comment", fld.field.comment() );
fldElem.setAttribute( "length", fld.field.length() );
fldElem.setAttribute( "type", fld.field.type() );
fldElem.setAttribute( "subType", fld.field.subType() );
fldElem.setAttribute( "typeName", fld.field.typeName() );

expressionFieldsElem.appendChild( fldElem );
Expand All @@ -79,9 +80,10 @@ void QgsExpressionFieldBuffer::readXml( const QDomNode& layerNode )
int precision = field.attribute( "precision" ).toInt();
int length = field.attribute( "length" ).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" );

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
Expand Up @@ -44,9 +44,10 @@ QgsField::QgsField( QString nam, QString typ, int len, int prec, bool num,
}
#endif
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 )
Expand Down Expand Up @@ -99,6 +100,11 @@ QVariant::Type QgsField::type() const
return d->type;
}

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

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

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

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

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

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

/** 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
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
* 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 );

/**
* 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.
* @param typeName Field type
Expand Down
8 changes: 7 additions & 1 deletion src/core/qgsfield_p.h
Expand Up @@ -44,12 +44,14 @@ class QgsFieldPrivate : public QSharedData

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

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 )
&& ( alias == other.alias ) && ( defaultValueExpression == other.defaultValueExpression ) );
}
Expand All @@ -85,6 +88,9 @@ class QgsFieldPrivate : public QSharedData
//! Variant type
QVariant::Type type;

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

//! Type name from provider
QString typeName;

Expand Down
18 changes: 18 additions & 0 deletions src/providers/postgres/qgspostgresconn.cpp
Expand Up @@ -961,6 +961,20 @@ static QString quotedMap( const QVariantMap& map )
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 )
{
if ( value.isNull() )
Expand All @@ -979,6 +993,10 @@ QString QgsPostgresConn::quotedValue( const QVariant& value )
case QVariant::Map:
return quotedMap( value.toMap() );

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

case QVariant::String:
default:
return quotedString( value.toString() );
Expand Down
5 changes: 3 additions & 2 deletions src/providers/postgres/qgspostgresfeatureiterator.cpp
Expand Up @@ -739,7 +739,7 @@ bool QgsPostgresFeatureIterator::getFeature( QgsPostgresResult &queryResult, int
{
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;

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

col++;
Expand Down

0 comments on commit abc55f4

Please sign in to comment.