1 /***************************************************************************
2       qgsdatasourceuri.h  -  Structure to contain the component parts
3                              of a data source URI
4                              -------------------
5     begin                : Dec 5, 2004
6     copyright            : (C) 2004 by Gary E.Sherman
7     email                : sherman at mrcc.com
8  ***************************************************************************/
9 
10 /***************************************************************************
11  *                                                                         *
12  *   This program is free software; you can redistribute it and/or modify  *
13  *   it under the terms of the GNU General Public License as published by  *
14  *   the Free Software Foundation; either version 2 of the License, or     *
15  *   (at your option) any later version.                                   *
16  *                                                                         *
17  ***************************************************************************/
18 
19 #include "qgsdatasourceuri.h"
20 #include "qgsauthmanager.h"
21 #include "qgslogger.h"
22 #include "qgswkbtypes.h"
23 #include "qgsapplication.h"
24 
25 #include <QStringList>
26 #include <QRegularExpression>
27 #include <QUrl>
28 #include <QUrlQuery>
29 
QgsDataSourceUri()30 QgsDataSourceUri::QgsDataSourceUri()
31 {
32   // do nothing
33 }
34 
QgsDataSourceUri(const QString & u)35 QgsDataSourceUri::QgsDataSourceUri( const QString &u )
36 {
37   QString uri = u;
38   int i = 0;
39   while ( i < uri.length() )
40   {
41     skipBlanks( uri, i );
42 
43     if ( uri[i] == '=' )
44     {
45       QgsDebugMsg( QStringLiteral( "parameter name expected before =" ) );
46       i++;
47       continue;
48     }
49 
50     int start = i;
51 
52     while ( i < uri.length() && uri[i] != '=' && !uri[i].isSpace() )
53       i++;
54 
55     const QString pname = uri.mid( start, i - start );
56 
57     skipBlanks( uri, i );
58 
59     if ( i == uri.length() || uri[i] != '=' )
60     {
61       // no "=", so likely not a parameter name
62       continue;
63     }
64 
65     i++;
66 
67     if ( pname == QLatin1String( "sql" ) )
68     {
69       // rest of line is a sql where clause
70       skipBlanks( uri, i );
71       mSql = uri.mid( i );
72       break;
73     }
74     else
75     {
76       const QString pval = getValue( uri, i );
77 
78       if ( pname == QLatin1String( "table" ) )
79       {
80         if ( i < uri.length() && uri[i] == '.' )
81         {
82           i++;
83 
84           mSchema = pval;
85           mTable = getValue( uri, i );
86         }
87         else
88         {
89           mTable = pval;
90         }
91 
92         if ( i < uri.length() && uri[i] == '(' )
93         {
94           i++;
95 
96           start = i;
97           while ( i < uri.length() && uri[i] != ')' )
98           {
99             if ( uri[i] == '\\' )
100               i++;
101             i++;
102           }
103 
104           if ( i == uri.length() )
105           {
106             QgsDebugMsg( QStringLiteral( "closing parenthesis missing" ) );
107           }
108 
109           mGeometryColumn = uri.mid( start, i - start );
110           mGeometryColumn.replace( QLatin1String( "\\)" ), QLatin1String( ")" ) );
111           mGeometryColumn.replace( QLatin1String( "\\\\" ), QLatin1String( "\\" ) );
112 
113           i++;
114         }
115         else
116         {
117           mGeometryColumn = QString();
118         }
119       }
120       else if ( pname == QLatin1String( "schema" ) )
121       {
122         mSchema = pval;
123       }
124       else if ( pname == QLatin1String( "key" ) )
125       {
126         mKeyColumn = pval;
127       }
128       else if ( pname == QLatin1String( "estimatedmetadata" ) )
129       {
130         mUseEstimatedMetadata = pval == QLatin1String( "true" );
131       }
132       else if ( pname == QLatin1String( "srid" ) )
133       {
134         mSrid = pval;
135       }
136       else if ( pname == QLatin1String( "type" ) )
137       {
138         mWkbType = QgsWkbTypes::parseType( pval );
139       }
140       else if ( pname == QLatin1String( "selectatid" ) )
141       {
142         mSelectAtIdDisabled = pval == QLatin1String( "false" );
143       }
144       else if ( pname == QLatin1String( "service" ) )
145       {
146         mService = pval;
147       }
148       else if ( pname == QLatin1String( "authcfg" ) )
149       {
150         mAuthConfigId = pval;
151       }
152       else if ( pname == QLatin1String( "user" ) || pname == QLatin1String( "username" ) ) // Also accepts new WFS provider naming
153       {
154         mUsername = pval;
155       }
156       else if ( pname == QLatin1String( "password" ) )
157       {
158         mPassword = pval;
159       }
160       else if ( pname == QLatin1String( "connect_timeout" ) )
161       {
162         QgsDebugMsgLevel( QStringLiteral( "connection timeout ignored" ), 3 );
163       }
164       else if ( pname == QLatin1String( "dbname" ) )
165       {
166         mDatabase = pval;
167       }
168       else if ( pname == QLatin1String( "host" ) )
169       {
170         mHost = pval;
171       }
172       else if ( pname == QLatin1String( "hostaddr" ) )
173       {
174         QgsDebugMsg( QStringLiteral( "database host ip address ignored" ) );
175       }
176       else if ( pname == QLatin1String( "port" ) )
177       {
178         mPort = pval;
179       }
180       else if ( pname == QLatin1String( "driver" ) )
181       {
182         mDriver = pval;
183       }
184       else if ( pname == QLatin1String( "tty" ) )
185       {
186         QgsDebugMsg( QStringLiteral( "backend debug tty ignored" ) );
187       }
188       else if ( pname == QLatin1String( "options" ) )
189       {
190         QgsDebugMsg( QStringLiteral( "backend debug options ignored" ) );
191       }
192       else if ( pname == QLatin1String( "sslmode" ) )
193       {
194         mSSLmode = decodeSslMode( pval );
195       }
196       else if ( pname == QLatin1String( "requiressl" ) )
197       {
198         if ( pval == QLatin1String( "0" ) )
199           mSSLmode = SslDisable;
200         else
201           mSSLmode = SslPrefer;
202       }
203       else if ( pname == QLatin1String( "krbsrvname" ) )
204       {
205         QgsDebugMsg( QStringLiteral( "kerberos server name ignored" ) );
206       }
207       else if ( pname == QLatin1String( "gsslib" ) )
208       {
209         QgsDebugMsg( QStringLiteral( "gsslib ignored" ) );
210       }
211       else
212       {
213         QgsDebugMsgLevel( "parameter \"" + pname + "\":\"" + pval + "\" added", 4 );
214         setParam( pname, pval );
215       }
216     }
217   }
218 }
219 
removePassword(const QString & aUri)220 QString QgsDataSourceUri::removePassword( const QString &aUri )
221 {
222   QRegularExpression regexp;
223   regexp.setPatternOptions( QRegularExpression::InvertedGreedinessOption );
224   QString safeName( aUri );
225   if ( aUri.contains( QLatin1String( " password=" ) ) )
226   {
227     regexp.setPattern( QStringLiteral( " password=.* " ) );
228     safeName.replace( regexp, QStringLiteral( " " ) );
229   }
230   else if ( aUri.contains( QLatin1String( ",password=" ) ) )
231   {
232     regexp.setPattern( QStringLiteral( ",password=.*," ) );
233     safeName.replace( regexp, QStringLiteral( "," ) );
234   }
235   else if ( aUri.contains( QLatin1String( "IDB:" ) ) )
236   {
237     regexp.setPattern( QStringLiteral( " pass=.* " ) );
238     safeName.replace( regexp, QStringLiteral( " " ) );
239   }
240   else if ( ( aUri.contains( QLatin1String( "OCI:" ) ) )
241             || ( aUri.contains( QLatin1String( "ODBC:" ) ) ) )
242   {
243     regexp.setPattern( QStringLiteral( "/.*@" ) );
244     safeName.replace( regexp, QStringLiteral( "/@" ) );
245   }
246   else if ( aUri.contains( QLatin1String( "SDE:" ) ) )
247   {
248     QStringList strlist = aUri.split( ',' );
249     safeName = strlist[0] + ',' + strlist[1] + ',' + strlist[2] + ',' + strlist[3];
250   }
251   return safeName;
252 }
253 
authConfigId() const254 QString QgsDataSourceUri::authConfigId() const
255 {
256   return mAuthConfigId;
257 }
258 
username() const259 QString QgsDataSourceUri::username() const
260 {
261   return mUsername;
262 }
263 
setUsername(const QString & username)264 void QgsDataSourceUri::setUsername( const QString &username )
265 {
266   mUsername = username;
267 }
268 
service() const269 QString QgsDataSourceUri::service() const
270 {
271   return mService;
272 }
273 
host() const274 QString QgsDataSourceUri::host() const
275 {
276   return mHost;
277 }
278 
database() const279 QString QgsDataSourceUri::database() const
280 {
281   return mDatabase;
282 }
283 
password() const284 QString QgsDataSourceUri::password() const
285 {
286   return mPassword;
287 }
288 
setPassword(const QString & password)289 void QgsDataSourceUri::setPassword( const QString &password )
290 {
291   mPassword = password;
292 }
293 
port() const294 QString QgsDataSourceUri::port() const
295 {
296   return mPort;
297 }
298 
driver() const299 QString QgsDataSourceUri::driver() const
300 {
301   return mDriver;
302 }
303 
sslMode() const304 QgsDataSourceUri::SslMode QgsDataSourceUri::sslMode() const
305 {
306   return mSSLmode;
307 }
308 
schema() const309 QString QgsDataSourceUri::schema() const
310 {
311   return mSchema;
312 }
313 
table() const314 QString QgsDataSourceUri::table() const
315 {
316   return mTable;
317 }
318 
sql() const319 QString QgsDataSourceUri::sql() const
320 {
321   return mSql;
322 }
323 
geometryColumn() const324 QString QgsDataSourceUri::geometryColumn() const
325 {
326   return mGeometryColumn;
327 }
328 
keyColumn() const329 QString QgsDataSourceUri::keyColumn() const
330 {
331   return mKeyColumn;
332 }
333 
334 
setDriver(const QString & driver)335 void QgsDataSourceUri::setDriver( const QString &driver )
336 {
337   mDriver = driver;
338 }
339 
340 
setKeyColumn(const QString & column)341 void QgsDataSourceUri::setKeyColumn( const QString &column )
342 {
343   mKeyColumn = column;
344 }
345 
346 
setUseEstimatedMetadata(bool flag)347 void QgsDataSourceUri::setUseEstimatedMetadata( bool flag )
348 {
349   mUseEstimatedMetadata = flag;
350 }
351 
useEstimatedMetadata() const352 bool QgsDataSourceUri::useEstimatedMetadata() const
353 {
354   return mUseEstimatedMetadata;
355 }
356 
disableSelectAtId(bool flag)357 void QgsDataSourceUri::disableSelectAtId( bool flag )
358 {
359   mSelectAtIdDisabled = flag;
360 }
361 
selectAtIdDisabled() const362 bool QgsDataSourceUri::selectAtIdDisabled() const
363 {
364   return mSelectAtIdDisabled;
365 }
366 
setSql(const QString & sql)367 void QgsDataSourceUri::setSql( const QString &sql )
368 {
369   mSql = sql;
370 }
371 
clearSchema()372 void QgsDataSourceUri::clearSchema()
373 {
374   mSchema.clear();
375 }
376 
setSchema(const QString & schema)377 void QgsDataSourceUri::setSchema( const QString &schema )
378 {
379   mSchema = schema;
380 }
381 
escape(const QString & val,QChar delim='\\'') const382 QString QgsDataSourceUri::escape( const QString &val, QChar delim = '\'' ) const
383 {
384   QString escaped = val;
385 
386   escaped.replace( '\\', QLatin1String( "\\\\" ) );
387   escaped.replace( delim, QStringLiteral( "\\%1" ).arg( delim ) );
388 
389   return escaped;
390 }
391 
setGeometryColumn(const QString & geometryColumn)392 void QgsDataSourceUri::setGeometryColumn( const QString &geometryColumn )
393 {
394   mGeometryColumn = geometryColumn;
395 }
396 
setTable(const QString & table)397 void QgsDataSourceUri::setTable( const QString &table )
398 {
399   mTable = table;
400 }
401 
skipBlanks(const QString & uri,int & i)402 void QgsDataSourceUri::skipBlanks( const QString &uri, int &i )
403 {
404   // skip space before value
405   while ( i < uri.length() && uri[i].isSpace() )
406     i++;
407 }
408 
getValue(const QString & uri,int & i)409 QString QgsDataSourceUri::getValue( const QString &uri, int &i )
410 {
411   skipBlanks( uri, i );
412 
413   // Get the parameter value
414   QString pval;
415   if ( i < uri.length() && ( uri[i] == '\'' || uri[i] == '"' ) )
416   {
417     const QChar delim = uri[i];
418 
419     i++;
420 
421     // value is quoted
422     for ( ;; )
423     {
424       if ( i == uri.length() )
425       {
426         QgsDebugMsg( QStringLiteral( "unterminated quoted string in connection info string" ) );
427         return pval;
428       }
429 
430       if ( uri[i] == '\\' )
431       {
432         i++;
433         if ( i == uri.length() )
434           continue;
435         if ( uri[i] != delim && uri[i] != '\\' )
436           i--;
437       }
438       else if ( uri[i] == delim )
439       {
440         i++;
441         break;
442       }
443 
444       pval += uri[i++];
445     }
446   }
447   else
448   {
449     // value is not quoted
450     while ( i < uri.length() )
451     {
452       if ( uri[i].isSpace() )
453       {
454         // end of value
455         break;
456       }
457 
458       if ( uri[i] == '\\' )
459       {
460         i++;
461         if ( i == uri.length() )
462           break;
463         if ( uri[i] != '\\' && uri[i] != '\'' )
464           i--;
465       }
466 
467       pval += uri[i++];
468     }
469   }
470 
471   skipBlanks( uri, i );
472 
473   return pval;
474 }
475 
connectionInfo(bool expandAuthConfig) const476 QString QgsDataSourceUri::connectionInfo( bool expandAuthConfig ) const
477 {
478   QStringList connectionItems;
479 
480   if ( !mDatabase.isEmpty() )
481   {
482     connectionItems << "dbname='" + escape( mDatabase ) + '\'';
483   }
484 
485   if ( !mService.isEmpty() )
486   {
487     connectionItems << "service='" + escape( mService ) + '\'';
488   }
489   else if ( !mHost.isEmpty() )
490   {
491     connectionItems << "host=" + mHost;
492   }
493 
494   if ( mService.isEmpty() )
495   {
496     if ( !mPort.isEmpty() )
497       connectionItems << "port=" + mPort;
498   }
499 
500   if ( !mDriver.isEmpty() )
501   {
502     connectionItems << "driver='" + escape( mDriver ) + '\'';
503   }
504 
505   if ( !mUsername.isEmpty() )
506   {
507     connectionItems << "user='" + escape( mUsername ) + '\'';
508 
509     if ( !mPassword.isEmpty() )
510     {
511       connectionItems << "password='" + escape( mPassword ) + '\'';
512     }
513   }
514 
515   if ( mSSLmode != SslPrefer )  // no need to output the default
516   {
517     connectionItems << QStringLiteral( "sslmode=" ) + encodeSslMode( mSSLmode );
518   }
519 
520   if ( !mAuthConfigId.isEmpty() )
521   {
522     if ( expandAuthConfig )
523     {
524       if ( !QgsApplication::authManager()->updateDataSourceUriItems( connectionItems, mAuthConfigId ) )
525       {
526         QgsDebugMsg( QStringLiteral( "Data source URI FAILED to update via loading configuration ID '%1'" ).arg( mAuthConfigId ) );
527       }
528     }
529     else
530     {
531       connectionItems << "authcfg=" + mAuthConfigId;
532     }
533   }
534 
535   return connectionItems.join( QLatin1Char( ' ' ) );
536 }
537 
uri(bool expandAuthConfig) const538 QString QgsDataSourceUri::uri( bool expandAuthConfig ) const
539 {
540   QString uri = connectionInfo( expandAuthConfig );
541 
542   if ( !mKeyColumn.isEmpty() )
543   {
544     uri += QStringLiteral( " key='%1'" ).arg( escape( mKeyColumn ) );
545   }
546 
547   if ( mUseEstimatedMetadata )
548   {
549     uri += QLatin1String( " estimatedmetadata=true" );
550   }
551 
552   if ( !mSrid.isEmpty() )
553   {
554     uri += QStringLiteral( " srid=%1" ).arg( mSrid );
555   }
556 
557   if ( mWkbType != QgsWkbTypes::Unknown && mWkbType != QgsWkbTypes::NoGeometry )
558   {
559     uri += QLatin1String( " type=" );
560     uri += QgsWkbTypes::displayString( mWkbType );
561   }
562 
563   if ( mSelectAtIdDisabled )
564   {
565     uri += QLatin1String( " selectatid=false" );
566   }
567 
568   for ( auto it = mParams.constBegin(); it != mParams.constEnd(); ++it )
569   {
570     if ( it.key().contains( '=' ) || it.key().contains( ' ' ) )
571     {
572       QgsDebugMsg( QStringLiteral( "invalid uri parameter %1 skipped" ).arg( it.key() ) );
573       continue;
574     }
575 
576     uri += ' ' + it.key() + "='" + escape( it.value() ) + '\'';
577   }
578 
579   QString columnName( mGeometryColumn );
580   columnName.replace( '\\', QLatin1String( "\\\\" ) );
581   columnName.replace( ')', QLatin1String( "\\)" ) );
582 
583   if ( !mTable.isEmpty() )
584   {
585     uri += QStringLiteral( " table=%1%2" )
586            .arg( quotedTablename(),
587                  mGeometryColumn.isEmpty() ? QString() : QStringLiteral( " (%1)" ).arg( columnName ) );
588   }
589   else if ( !mSchema.isEmpty() )
590   {
591     uri += QStringLiteral( " schema='%1'" ).arg( escape( mSchema ) );
592   }
593 
594   if ( !mSql.isEmpty() )
595   {
596     uri += QStringLiteral( " sql=" ) + mSql;
597   }
598 
599   return uri;
600 }
601 
602 // from qurl.h
toLatin1_helper(const QString & string)603 QByteArray toLatin1_helper( const QString &string )
604 {
605   if ( string.isEmpty() )
606     return string.isNull() ? QByteArray() : QByteArray( "" );
607   return string.toLatin1();
608 }
609 
encodedUri() const610 QByteArray QgsDataSourceUri::encodedUri() const
611 {
612   QUrlQuery url;
613   for ( auto it = mParams.constBegin(); it != mParams.constEnd(); ++it )
614   {
615     url.addQueryItem( it.key(), it.value() );
616   }
617 
618   if ( !mUsername.isEmpty() )
619     url.addQueryItem( QStringLiteral( "username" ), mUsername );
620 
621   if ( !mPassword.isEmpty() )
622     url.addQueryItem( QStringLiteral( "password" ), mPassword );
623 
624   if ( !mAuthConfigId.isEmpty() )
625     url.addQueryItem( QStringLiteral( "authcfg" ), mAuthConfigId );
626 
627   return toLatin1_helper( url.toString( QUrl::FullyEncoded ) );
628 }
629 
setEncodedUri(const QByteArray & uri)630 void QgsDataSourceUri::setEncodedUri( const QByteArray &uri )
631 {
632   mParams.clear();
633   mUsername.clear();
634   mPassword.clear();
635   mAuthConfigId.clear();
636 
637   QUrl url;
638   url.setQuery( QString::fromLatin1( uri ) );
639   const QUrlQuery query( url );
640 
641   const auto constQueryItems = query.queryItems( QUrl::ComponentFormattingOption::FullyDecoded );
642   for ( const QPair<QString, QString> &item : constQueryItems )
643   {
644     if ( item.first == QLatin1String( "username" ) )
645       mUsername = item.second;
646     else if ( item.first == QLatin1String( "password" ) )
647       mPassword = item.second;
648     else if ( item.first == QLatin1String( "authcfg" ) )
649       mAuthConfigId = item.second;
650     else
651       mParams.insert( item.first, item.second );
652   }
653 }
654 
setEncodedUri(const QString & uri)655 void QgsDataSourceUri::setEncodedUri( const QString &uri )
656 {
657   setEncodedUri( uri.toLatin1() );
658 }
659 
quotedTablename() const660 QString QgsDataSourceUri::quotedTablename() const
661 {
662   if ( !mSchema.isEmpty() )
663     return QStringLiteral( "\"%1\".\"%2\"" )
664            .arg( escape( mSchema, '"' ),
665                  escape( mTable, '"' ) );
666   else
667     return QStringLiteral( "\"%1\"" )
668            .arg( escape( mTable, '"' ) );
669 }
670 
setConnection(const QString & host,const QString & port,const QString & database,const QString & username,const QString & password,SslMode sslmode,const QString & authConfigId)671 void QgsDataSourceUri::setConnection( const QString &host,
672                                       const QString &port,
673                                       const QString &database,
674                                       const QString &username,
675                                       const QString &password,
676                                       SslMode sslmode,
677                                       const QString &authConfigId )
678 {
679   mHost = host;
680   mDatabase = database;
681   mPort = port;
682   mUsername = username;
683   mPassword = password;
684   mSSLmode = sslmode;
685   mAuthConfigId = authConfigId;
686 }
687 
setConnection(const QString & service,const QString & database,const QString & username,const QString & password,SslMode sslmode,const QString & authConfigId)688 void QgsDataSourceUri::setConnection( const QString &service,
689                                       const QString &database,
690                                       const QString &username,
691                                       const QString &password,
692                                       SslMode sslmode,
693                                       const QString &authConfigId )
694 {
695   mService = service;
696   mDatabase = database;
697   mUsername = username;
698   mPassword = password;
699   mSSLmode = sslmode;
700   mAuthConfigId = authConfigId;
701 }
702 
setDataSource(const QString & schema,const QString & table,const QString & geometryColumn,const QString & sql,const QString & keyColumn)703 void QgsDataSourceUri::setDataSource( const QString &schema,
704                                       const QString &table,
705                                       const QString &geometryColumn,
706                                       const QString &sql,
707                                       const QString &keyColumn )
708 {
709   mSchema = schema;
710   mTable = table;
711   mGeometryColumn = geometryColumn;
712   mSql = sql;
713   mKeyColumn = keyColumn;
714 }
715 
setAuthConfigId(const QString & authcfg)716 void QgsDataSourceUri::setAuthConfigId( const QString &authcfg )
717 {
718   mAuthConfigId = authcfg;
719 }
720 
setDatabase(const QString & database)721 void QgsDataSourceUri::setDatabase( const QString &database )
722 {
723   mDatabase = database;
724 }
725 
wkbType() const726 QgsWkbTypes::Type QgsDataSourceUri::wkbType() const
727 {
728   return mWkbType;
729 }
730 
setWkbType(QgsWkbTypes::Type wkbType)731 void QgsDataSourceUri::setWkbType( QgsWkbTypes::Type wkbType )
732 {
733   mWkbType = wkbType;
734 }
735 
srid() const736 QString QgsDataSourceUri::srid() const
737 {
738   return mSrid;
739 }
740 
setSrid(const QString & srid)741 void QgsDataSourceUri::setSrid( const QString &srid )
742 {
743   mSrid = srid;
744 }
745 
decodeSslMode(const QString & sslMode)746 QgsDataSourceUri::SslMode QgsDataSourceUri::decodeSslMode( const QString &sslMode )
747 {
748   if ( sslMode == QLatin1String( "prefer" ) )
749     return SslPrefer;
750   else if ( sslMode == QLatin1String( "disable" ) )
751     return SslDisable;
752   else if ( sslMode == QLatin1String( "allow" ) )
753     return SslAllow;
754   else if ( sslMode == QLatin1String( "require" ) )
755     return SslRequire;
756   else if ( sslMode == QLatin1String( "verify-ca" ) )
757     return SslVerifyCa;
758   else if ( sslMode == QLatin1String( "verify-full" ) )
759     return SslVerifyFull;
760   else
761     return SslPrefer;  // default
762 }
763 
encodeSslMode(QgsDataSourceUri::SslMode sslMode)764 QString QgsDataSourceUri::encodeSslMode( QgsDataSourceUri::SslMode sslMode )
765 {
766   switch ( sslMode )
767   {
768     case SslPrefer: return QStringLiteral( "prefer" );
769     case SslDisable: return QStringLiteral( "disable" );
770     case SslAllow: return QStringLiteral( "allow" );
771     case SslRequire: return QStringLiteral( "require" );
772     case SslVerifyCa: return QStringLiteral( "verify-ca" );
773     case SslVerifyFull: return QStringLiteral( "verify-full" );
774   }
775   return QString();
776 }
777 
setParam(const QString & key,const QString & value)778 void QgsDataSourceUri::setParam( const QString &key, const QString &value )
779 {
780   // maintain old API
781   if ( key == QLatin1String( "username" ) )
782     mUsername = value;
783   else if ( key == QLatin1String( "password" ) )
784     mPassword = value;
785   else if ( key == QLatin1String( "authcfg" ) )
786     mAuthConfigId = value;
787   else
788   {
789     // may be multiple
790     mParams.insert( key, value );
791   }
792 }
793 
setParam(const QString & key,const QStringList & value)794 void QgsDataSourceUri::setParam( const QString &key, const QStringList &value )
795 {
796   for ( const QString &val : value )
797   {
798     setParam( key, val );
799   }
800 }
801 
removeParam(const QString & key)802 int QgsDataSourceUri::removeParam( const QString &key )
803 {
804   if ( key == QLatin1String( "username" ) && !mUsername.isEmpty() )
805   {
806     mUsername.clear();
807     return 1;
808   }
809   else if ( key == QLatin1String( "password" ) && !mPassword.isEmpty() )
810   {
811     mPassword.clear();
812     return 1;
813   }
814   else if ( key == QLatin1String( "authcfg" ) && !mAuthConfigId.isEmpty() )
815   {
816     mAuthConfigId.clear();
817     return 1;
818   }
819 
820   return mParams.remove( key );
821 }
822 
param(const QString & key) const823 QString QgsDataSourceUri::param( const QString &key ) const
824 {
825   // maintain old api
826   if ( key == QLatin1String( "username" ) && !mUsername.isEmpty() )
827     return mUsername;
828   else if ( key == QLatin1String( "password" ) && !mPassword.isEmpty() )
829     return mPassword;
830   else if ( key == QLatin1String( "authcfg" ) && !mAuthConfigId.isEmpty() )
831     return mAuthConfigId;
832 
833   return mParams.value( key );
834 }
835 
params(const QString & key) const836 QStringList QgsDataSourceUri::params( const QString &key ) const
837 {
838   // maintain old api
839   if ( key == QLatin1String( "username" ) && !mUsername.isEmpty() )
840     return QStringList() << mUsername;
841   else if ( key == QLatin1String( "password" ) && !mPassword.isEmpty() )
842     return QStringList() << mPassword;
843   else if ( key == QLatin1String( "authcfg" ) && !mAuthConfigId.isEmpty() )
844     return QStringList() << mAuthConfigId;
845 
846   return mParams.values( key );
847 }
848 
hasParam(const QString & key) const849 bool QgsDataSourceUri::hasParam( const QString &key ) const
850 {
851   // maintain old api
852   if ( key == QLatin1String( "username" ) && !mUsername.isEmpty() )
853     return true;
854   else if ( key == QLatin1String( "password" ) && !mPassword.isEmpty() )
855     return true;
856   else if ( key == QLatin1String( "authcfg" ) && !mAuthConfigId.isEmpty() )
857     return true;
858 
859   return mParams.contains( key );
860 }
861