Skip to content

Commit a33bf30

Browse files
authoredMar 5, 2019
Merge pull request #9048 from troopa81/fix_20872_postgres_multidim_arrays
Manage postgres multidimensionnal array
2 parents 2046450 + bc166cf commit a33bf30

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
@@ -4217,7 +4217,7 @@ static void jumpSpace( const QString &txt, int &i )
42174217
++i;
42184218
}
42194219

4220-
static QString getNextString( const QString &txt, int &i, const QString &sep )
4220+
QString QgsPostgresProvider::getNextString( const QString &txt, int &i, const QString &sep )
42214221
{
42224222
jumpSpace( txt, i );
42234223
QString cur = txt.mid( i );
@@ -4226,14 +4226,14 @@ static QString getNextString( const QString &txt, int &i, const QString &sep )
42264226
QRegExp stringRe( "^\"((?:\\\\.|[^\"\\\\])*)\".*" );
42274227
if ( !stringRe.exactMatch( cur ) )
42284228
{
4229-
QgsLogger::warning( "Cannot find end of double quoted string: " + txt );
4229+
QgsMessageLog::logMessage( tr( "Cannot find end of double quoted string: %1" ).arg( txt ), tr( "PostGIS" ) );
42304230
return QString();
42314231
}
42324232
i += stringRe.cap( 1 ).length() + 2;
42334233
jumpSpace( txt, i );
42344234
if ( !txt.midRef( i ).startsWith( sep ) && i < txt.length() )
42354235
{
4236-
QgsLogger::warning( "Cannot find separator: " + txt.mid( i ) );
4236+
QgsMessageLog::logMessage( tr( "Cannot find separator: %1" ).arg( txt.mid( i ) ), tr( "PostGIS" ) );
42374237
return QString();
42384238
}
42394239
i += sep.length();
@@ -4252,7 +4252,7 @@ static QString getNextString( const QString &txt, int &i, const QString &sep )
42524252
}
42534253
}
42544254

4255-
static QVariant parseHstore( const QString &txt )
4255+
QVariant QgsPostgresProvider::parseHstore( const QString &txt )
42564256
{
42574257
QVariantMap result;
42584258
int i = 0;
@@ -4262,7 +4262,7 @@ static QVariant parseHstore( const QString &txt )
42624262
QString value = getNextString( txt, i, QStringLiteral( "," ) );
42634263
if ( key.isNull() || value.isNull() )
42644264
{
4265-
QgsLogger::warning( "Error parsing hstore: " + txt );
4265+
QgsMessageLog::logMessage( tr( "Error parsing hstore: %1" ).arg( txt ), tr( "PostGIS" ) );
42664266
break;
42674267
}
42684268
result.insert( key, value );
@@ -4271,7 +4271,7 @@ static QVariant parseHstore( const QString &txt )
42714271
return result;
42724272
}
42734273

4274-
static QVariant parseJson( const QString &txt )
4274+
QVariant QgsPostgresProvider::parseJson( const QString &txt )
42754275
{
42764276
QVariant result;
42774277
QJsonDocument jsonResponse = QJsonDocument::fromJson( txt.toUtf8() );
@@ -4280,7 +4280,7 @@ static QVariant parseJson( const QString &txt )
42804280
return result;
42814281
}
42824282

4283-
static QVariant parseOtherArray( const QString &txt, QVariant::Type subType, const QString &typeName )
4283+
QVariant QgsPostgresProvider::parseOtherArray( const QString &txt, QVariant::Type subType, const QString &typeName )
42844284
{
42854285
int i = 0;
42864286
QVariantList result;
@@ -4289,15 +4289,15 @@ static QVariant parseOtherArray( const QString &txt, QVariant::Type subType, con
42894289
const QString value = getNextString( txt, i, QStringLiteral( "," ) );
42904290
if ( value.isNull() )
42914291
{
4292-
QgsLogger::warning( "Error parsing array: " + txt );
4292+
QgsMessageLog::logMessage( tr( "Error parsing array: %1" ).arg( txt ), tr( "PostGIS" ) );
42934293
break;
42944294
}
42954295
result.append( QgsPostgresProvider::convertValue( subType, QVariant::Invalid, value, typeName ) );
42964296
}
42974297
return result;
42984298
}
42994299

4300-
static QVariant parseStringArray( const QString &txt )
4300+
QVariant QgsPostgresProvider::parseStringArray( const QString &txt )
43014301
{
43024302
int i = 0;
43034303
QStringList result;
@@ -4306,24 +4306,64 @@ static QVariant parseStringArray( const QString &txt )
43064306
const QString value = getNextString( txt, i, QStringLiteral( "," ) );
43074307
if ( value.isNull() )
43084308
{
4309-
QgsLogger::warning( "Error parsing array: " + txt );
4309+
QgsMessageLog::logMessage( tr( "Error parsing array: %1" ).arg( txt ), tr( "PostGIS" ) );
43104310
break;
43114311
}
43124312
result.append( value );
43134313
}
43144314
return result;
43154315
}
43164316

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

‎src/providers/postgres/qgspostgresprovider.h

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

251251
QString geomParam( int offset ) const;
252252

253+
254+
static QString getNextString( const QString &txt, int &i, const QString &sep );
255+
static QVariant parseHstore( const QString &txt );
256+
static QVariant parseJson( const QString &txt );
257+
static QVariant parseOtherArray( const QString &txt, QVariant::Type subType, const QString &typeName );
258+
static QVariant parseStringArray( const QString &txt );
259+
static QVariant parseMultidimensionalArray( const QString &txt );
260+
static QVariant parseArray( const QString &txt, QVariant::Type type, QVariant::Type subType, const QString &typeName );
261+
262+
253263
/**
254264
* Gets parametrized primary key clause
255265
* \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.