Skip to content

Commit 2dbaa18

Browse files
troopa81nyalldawson
authored andcommittedMar 11, 2019
fixes #20872 : Manage postgres multidimensionnal array
1 parent 4f9c03d commit 2dbaa18

File tree

5 files changed

+104
-14
lines changed

5 files changed

+104
-14
lines changed
 

‎src/providers/postgres/qgspostgresconn.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1009,7 +1009,16 @@ static QString quotedList( const QVariantList &list )
10091009
{
10101010
ret += QLatin1String( "," );
10111011
}
1012-
ret.append( doubleQuotedMapValue( i->toString() ) );
1012+
1013+
QString inner = i->toString();
1014+
if ( inner.startsWith( '{' ) )
1015+
{
1016+
ret.append( inner );
1017+
}
1018+
else
1019+
{
1020+
ret.append( doubleQuotedMapValue( i->toString() ) );
1021+
}
10131022
}
10141023
return "E'{" + ret + "}'";
10151024
}

‎src/providers/postgres/qgspostgresprovider.cpp

Lines changed: 53 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4214,7 +4214,7 @@ static void jumpSpace( const QString &txt, int &i )
42144214
++i;
42154215
}
42164216

4217-
static QString getNextString( const QString &txt, int &i, const QString &sep )
4217+
QString QgsPostgresProvider::getNextString( const QString &txt, int &i, const QString &sep )
42184218
{
42194219
jumpSpace( txt, i );
42204220
QString cur = txt.mid( i );
@@ -4223,14 +4223,14 @@ static QString getNextString( const QString &txt, int &i, const QString &sep )
42234223
QRegExp stringRe( "^\"((?:\\\\.|[^\"\\\\])*)\".*" );
42244224
if ( !stringRe.exactMatch( cur ) )
42254225
{
4226-
QgsLogger::warning( "Cannot find end of double quoted string: " + txt );
4226+
QgsMessageLog::logMessage( tr( "Cannot find end of double quoted string: %1" ).arg( txt ), tr( "PostGIS" ) );
42274227
return QString();
42284228
}
42294229
i += stringRe.cap( 1 ).length() + 2;
42304230
jumpSpace( txt, i );
42314231
if ( !txt.midRef( i ).startsWith( sep ) && i < txt.length() )
42324232
{
4233-
QgsLogger::warning( "Cannot find separator: " + txt.mid( i ) );
4233+
QgsMessageLog::logMessage( tr( "Cannot find separator: %1" ).arg( txt.mid( i ) ), tr( "PostGIS" ) );
42344234
return QString();
42354235
}
42364236
i += sep.length();
@@ -4249,7 +4249,7 @@ static QString getNextString( const QString &txt, int &i, const QString &sep )
42494249
}
42504250
}
42514251

4252-
static QVariant parseHstore( const QString &txt )
4252+
QVariant QgsPostgresProvider::parseHstore( const QString &txt )
42534253
{
42544254
QVariantMap result;
42554255
int i = 0;
@@ -4259,7 +4259,7 @@ static QVariant parseHstore( const QString &txt )
42594259
QString value = getNextString( txt, i, QStringLiteral( "," ) );
42604260
if ( key.isNull() || value.isNull() )
42614261
{
4262-
QgsLogger::warning( "Error parsing hstore: " + txt );
4262+
QgsMessageLog::logMessage( tr( "Error parsing hstore: %1" ).arg( txt ), tr( "PostGIS" ) );
42634263
break;
42644264
}
42654265
result.insert( key, value );
@@ -4268,7 +4268,7 @@ static QVariant parseHstore( const QString &txt )
42684268
return result;
42694269
}
42704270

4271-
static QVariant parseJson( const QString &txt )
4271+
QVariant QgsPostgresProvider::parseJson( const QString &txt )
42724272
{
42734273
QVariant result;
42744274
QJsonDocument jsonResponse = QJsonDocument::fromJson( txt.toUtf8() );
@@ -4277,7 +4277,7 @@ static QVariant parseJson( const QString &txt )
42774277
return result;
42784278
}
42794279

4280-
static QVariant parseOtherArray( const QString &txt, QVariant::Type subType, const QString &typeName )
4280+
QVariant QgsPostgresProvider::parseOtherArray( const QString &txt, QVariant::Type subType, const QString &typeName )
42814281
{
42824282
int i = 0;
42834283
QVariantList result;
@@ -4286,15 +4286,15 @@ static QVariant parseOtherArray( const QString &txt, QVariant::Type subType, con
42864286
const QString value = getNextString( txt, i, QStringLiteral( "," ) );
42874287
if ( value.isNull() )
42884288
{
4289-
QgsLogger::warning( "Error parsing array: " + txt );
4289+
QgsMessageLog::logMessage( tr( "Error parsing array: %1" ).arg( txt ), tr( "PostGIS" ) );
42904290
break;
42914291
}
42924292
result.append( QgsPostgresProvider::convertValue( subType, QVariant::Invalid, value, typeName ) );
42934293
}
42944294
return result;
42954295
}
42964296

4297-
static QVariant parseStringArray( const QString &txt )
4297+
QVariant QgsPostgresProvider::parseStringArray( const QString &txt )
42984298
{
42994299
int i = 0;
43004300
QStringList result;
@@ -4303,24 +4303,64 @@ static QVariant parseStringArray( const QString &txt )
43034303
const QString value = getNextString( txt, i, QStringLiteral( "," ) );
43044304
if ( value.isNull() )
43054305
{
4306-
QgsLogger::warning( "Error parsing array: " + txt );
4306+
QgsMessageLog::logMessage( tr( "Error parsing array: %1" ).arg( txt ), tr( "PostGIS" ) );
43074307
break;
43084308
}
43094309
result.append( value );
43104310
}
43114311
return result;
43124312
}
43134313

4314-
static QVariant parseArray( const QString &txt, QVariant::Type type, QVariant::Type subType, const QString &typeName )
4314+
QVariant QgsPostgresProvider::parseMultidimensionalArray( const QString &txt )
4315+
{
4316+
QStringList result;
4317+
if ( !txt.startsWith( '{' ) || !txt.endsWith( '}' ) )
4318+
{
4319+
QgsMessageLog::logMessage( tr( "Error parsing array, missing curly braces: %1" ).arg( txt ), tr( "PostGIS" ) );
4320+
return result;
4321+
}
4322+
4323+
QStringList values;
4324+
QString text = txt;
4325+
while ( !text.isEmpty() )
4326+
{
4327+
bool escaped = false;
4328+
int openedBrackets = 1;
4329+
int i = 0;
4330+
while ( i < text.length() && openedBrackets > 0 )
4331+
{
4332+
++i;
4333+
4334+
if ( text.at( i ) == '}' && !escaped ) openedBrackets--;
4335+
else if ( text.at( i ) == '{' && !escaped ) openedBrackets++;
4336+
4337+
escaped = !escaped ? text.at( i ) == '\\' : false;
4338+
}
4339+
4340+
values.append( text.left( ++i ) );
4341+
i = text.indexOf( ',', i );
4342+
i = i > 0 ? text.indexOf( '{', i ) : -1;
4343+
if ( i == -1 )
4344+
break;
4345+
4346+
text = text.mid( i );
4347+
}
4348+
return values;
4349+
4350+
}
4351+
4352+
QVariant QgsPostgresProvider::parseArray( const QString &txt, QVariant::Type type, QVariant::Type subType, const QString &typeName )
43154353
{
43164354
if ( !txt.startsWith( '{' ) || !txt.endsWith( '}' ) )
43174355
{
43184356
if ( !txt.isEmpty() )
4319-
QgsLogger::warning( "Error parsing array, missing curly braces: " + txt );
4357+
QgsMessageLog::logMessage( tr( "Error parsing array, missing curly braces: %1" ).arg( txt ), tr( "PostGIS" ) );
43204358
return QVariant( type );
43214359
}
43224360
QString inner = txt.mid( 1, txt.length() - 2 );
4323-
if ( type == QVariant::StringList )
4361+
if ( ( type == QVariant::StringList || type == QVariant::List ) && inner.startsWith( "{" ) )
4362+
return parseMultidimensionalArray( inner );
4363+
else if ( type == QVariant::StringList )
43244364
return parseStringArray( inner );
43254365
else
43264366
return parseOtherArray( inner, subType, typeName );

‎src/providers/postgres/qgspostgresprovider.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,16 @@ class QgsPostgresProvider : public QgsVectorDataProvider
264264

265265
QString geomParam( int offset ) const;
266266

267+
268+
static QString getNextString( const QString &txt, int &i, const QString &sep );
269+
static QVariant parseHstore( const QString &txt );
270+
static QVariant parseJson( const QString &txt );
271+
static QVariant parseOtherArray( const QString &txt, QVariant::Type subType, const QString &typeName );
272+
static QVariant parseStringArray( const QString &txt );
273+
static QVariant parseMultidimensionalArray( const QString &txt );
274+
static QVariant parseArray( const QString &txt, QVariant::Type type, QVariant::Type subType, const QString &typeName );
275+
276+
267277
/**
268278
* Gets parametrized primary key clause
269279
* \param offset specifies offset to use for the pk value parameter

‎tests/src/providers/testqgspostgresconn.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,14 @@ class TestQgsPostgresConn: public QObject
5454
QCOMPARE( actual, QString( "E'{\"1\",\"-5\"}'" ) );
5555
}
5656

57+
void quotedValue2DimArray()
58+
{
59+
QStringList list;
60+
list << QStringLiteral( "{\"hello foo\",b}" ) << QStringLiteral( "{c,\"hello bar\"}" );
61+
const QString actual = QgsPostgresConn::quotedValue( list );
62+
QCOMPARE( actual, QString( "E'{{\"hello foo\",b},{c,\"hello bar\"}}'" ) );
63+
}
64+
5765
};
5866

5967
QGSTEST_MAIN( TestQgsPostgresConn )

‎tests/src/providers/testqgspostgresprovider.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,29 @@ class TestQgsPostgresProvider: public QObject
7878
qDebug() << "actual: " << decoded;
7979
QCOMPARE( decoded.toList(), expected );
8080
}
81+
82+
void decode2DimensionArray()
83+
{
84+
const QVariant decoded = QgsPostgresProvider::convertValue( QVariant::StringList, QVariant::String, QStringLiteral( "{{foo,\"escape bracket \\}\"},{\"escape bracket and backslash \\\\\\}\",\"hello bar\"}}" ), QStringLiteral( "_text" ) );
85+
QCOMPARE( decoded.type(), QVariant::StringList );
86+
87+
QVariantList expected;
88+
expected << QVariant( "{foo,\"escape bracket \\}\"}" ) << QVariant( "{\"escape bracket and backslash \\\\\\}\",\"hello bar\"}" );
89+
qDebug() << "actual: " << decoded;
90+
QCOMPARE( decoded.toList(), expected );
91+
}
92+
93+
void decode3DimensionArray()
94+
{
95+
const QVariant decoded = QgsPostgresProvider::convertValue( QVariant::StringList, QVariant::String, QStringLiteral( "{{{0,1},{1,2}},{{3,4},{5,6}}}" ), QStringLiteral( "_integer" ) );
96+
QCOMPARE( decoded.type(), QVariant::StringList );
97+
98+
QVariantList expected;
99+
expected << QVariant( "{{0,1},{1,2}}" ) << QVariant( "{{3,4},{5,6}}" );
100+
qDebug() << "actual: " << decoded;
101+
QCOMPARE( decoded.toList(), expected );
102+
}
103+
81104
void decodeJsonList()
82105
{
83106
const QVariant decoded = QgsPostgresProvider::convertValue( QVariant::Map, QVariant::String, QStringLiteral( "[1,2,3]" ), QStringLiteral( "json" ) );

0 commit comments

Comments
 (0)
Please sign in to comment.