QGIS API Documentation  3.8.0-Zanzibar (11aff65)
qgsdatasourceuri.cpp
Go to the documentation of this file.
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 <QRegExp>
27 #include <QUrl>
28 
30 {
31  // do nothing
32 }
33 
35 {
36  QString uri = u;
37  int i = 0;
38  while ( i < uri.length() )
39  {
40  skipBlanks( uri, i );
41 
42  if ( uri[i] == '=' )
43  {
44  QgsDebugMsg( QStringLiteral( "parameter name expected before =" ) );
45  i++;
46  continue;
47  }
48 
49  int start = i;
50 
51  while ( i < uri.length() && uri[i] != '=' && !uri[i].isSpace() )
52  i++;
53 
54  QString pname = uri.mid( start, i - start );
55 
56  skipBlanks( uri, i );
57 
58  if ( i == uri.length() || uri[i] != '=' )
59  {
60  QgsDebugMsg( QStringLiteral( "= expected after parameter name, skipping text '%1'" ).arg( pname ) );
61  continue;
62  }
63 
64  i++;
65 
66  if ( pname == QLatin1String( "sql" ) )
67  {
68  // rest of line is a sql where clause
69  skipBlanks( uri, i );
70  mSql = uri.mid( i );
71  break;
72  }
73  else
74  {
75  QString pval = getValue( uri, i );
76 
77  if ( pname == QLatin1String( "table" ) )
78  {
79  if ( uri[i] == '.' )
80  {
81  i++;
82 
83  mSchema = pval;
84  mTable = getValue( uri, i );
85  }
86  else
87  {
88  mSchema.clear();
89  mTable = pval;
90  }
91 
92  if ( uri[i] == '(' )
93  {
94  i++;
95 
96  int 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( "key" ) )
121  {
122  mKeyColumn = pval;
123  }
124  else if ( pname == QLatin1String( "estimatedmetadata" ) )
125  {
126  mUseEstimatedMetadata = pval == QLatin1String( "true" );
127  }
128  else if ( pname == QLatin1String( "srid" ) )
129  {
130  mSrid = pval;
131  }
132  else if ( pname == QLatin1String( "type" ) )
133  {
134  mWkbType = QgsWkbTypes::parseType( pval );
135  }
136  else if ( pname == QLatin1String( "selectatid" ) )
137  {
138  mSelectAtIdDisabled = pval == QLatin1String( "false" );
139  }
140  else if ( pname == QLatin1String( "service" ) )
141  {
142  mService = pval;
143  }
144  else if ( pname == QLatin1String( "authcfg" ) )
145  {
146  mAuthConfigId = pval;
147  }
148  else if ( pname == QLatin1String( "user" ) || pname == QLatin1String( "username" ) ) // Also accepts new WFS provider naming
149  {
150  mUsername = pval;
151  }
152  else if ( pname == QLatin1String( "password" ) )
153  {
154  mPassword = pval;
155  }
156  else if ( pname == QLatin1String( "connect_timeout" ) )
157  {
158  QgsDebugMsg( QStringLiteral( "connection timeout ignored" ) );
159  }
160  else if ( pname == QLatin1String( "dbname" ) )
161  {
162  mDatabase = pval;
163  }
164  else if ( pname == QLatin1String( "host" ) )
165  {
166  mHost = pval;
167  }
168  else if ( pname == QLatin1String( "hostaddr" ) )
169  {
170  QgsDebugMsg( QStringLiteral( "database host ip address ignored" ) );
171  }
172  else if ( pname == QLatin1String( "port" ) )
173  {
174  mPort = pval;
175  }
176  else if ( pname == QLatin1String( "driver" ) )
177  {
178  mDriver = pval;
179  }
180  else if ( pname == QLatin1String( "tty" ) )
181  {
182  QgsDebugMsg( QStringLiteral( "backend debug tty ignored" ) );
183  }
184  else if ( pname == QLatin1String( "options" ) )
185  {
186  QgsDebugMsg( QStringLiteral( "backend debug options ignored" ) );
187  }
188  else if ( pname == QLatin1String( "sslmode" ) )
189  {
190  mSSLmode = decodeSslMode( pval );
191  }
192  else if ( pname == QLatin1String( "requiressl" ) )
193  {
194  if ( pval == QLatin1String( "0" ) )
195  mSSLmode = SslDisable;
196  else
197  mSSLmode = SslPrefer;
198  }
199  else if ( pname == QLatin1String( "krbsrvname" ) )
200  {
201  QgsDebugMsg( QStringLiteral( "kerberos server name ignored" ) );
202  }
203  else if ( pname == QLatin1String( "gsslib" ) )
204  {
205  QgsDebugMsg( QStringLiteral( "gsslib ignored" ) );
206  }
207  else
208  {
209  QgsDebugMsgLevel( "parameter \"" + pname + "\":\"" + pval + "\" added", 4 );
210  setParam( pname, pval );
211  }
212  }
213  }
214 }
215 
216 QString QgsDataSourceUri::removePassword( const QString &aUri )
217 {
218  QRegExp regexp;
219  regexp.setMinimal( true );
220  QString safeName( aUri );
221  if ( aUri.contains( QLatin1String( " password=" ) ) )
222  {
223  regexp.setPattern( QStringLiteral( " password=.* " ) );
224  safeName.replace( regexp, QStringLiteral( " " ) );
225  }
226  else if ( aUri.contains( QLatin1String( ",password=" ) ) )
227  {
228  regexp.setPattern( QStringLiteral( ",password=.*," ) );
229  safeName.replace( regexp, QStringLiteral( "," ) );
230  }
231  else if ( aUri.contains( QLatin1String( "IDB:" ) ) )
232  {
233  regexp.setPattern( QStringLiteral( " pass=.* " ) );
234  safeName.replace( regexp, QStringLiteral( " " ) );
235  }
236  else if ( ( aUri.contains( QLatin1String( "OCI:" ) ) )
237  || ( aUri.contains( QLatin1String( "ODBC:" ) ) ) )
238  {
239  regexp.setPattern( QStringLiteral( "/.*@" ) );
240  safeName.replace( regexp, QStringLiteral( "/@" ) );
241  }
242  else if ( aUri.contains( QLatin1String( "SDE:" ) ) )
243  {
244  QStringList strlist = aUri.split( ',' );
245  safeName = strlist[0] + ',' + strlist[1] + ',' + strlist[2] + ',' + strlist[3];
246  }
247  return safeName;
248 }
249 
251 {
252  return mAuthConfigId;
253 }
254 
256 {
257  return mUsername;
258 }
259 
261 {
262  mUsername = username;
263 }
264 
266 {
267  return mService;
268 }
269 
270 QString QgsDataSourceUri::host() const
271 {
272  return mHost;
273 }
274 
276 {
277  return mDatabase;
278 }
279 
281 {
282  return mPassword;
283 }
284 
286 {
287  mPassword = password;
288 }
289 
290 QString QgsDataSourceUri::port() const
291 {
292  return mPort;
293 }
294 
296 {
297  return mDriver;
298 }
299 
301 {
302  return mSSLmode;
303 }
304 
306 {
307  return mSchema;
308 }
309 
310 QString QgsDataSourceUri::table() const
311 {
312  return mTable;
313 }
314 
315 QString QgsDataSourceUri::sql() const
316 {
317  return mSql;
318 }
319 
321 {
322  return mGeometryColumn;
323 }
324 
326 {
327  return mKeyColumn;
328 }
329 
330 
331 void QgsDataSourceUri::setDriver( const QString &driver )
332 {
333  mDriver = driver;
334 }
335 
336 
337 void QgsDataSourceUri::setKeyColumn( const QString &column )
338 {
339  mKeyColumn = column;
340 }
341 
342 
344 {
345  mUseEstimatedMetadata = flag;
346 }
347 
349 {
350  return mUseEstimatedMetadata;
351 }
352 
354 {
355  mSelectAtIdDisabled = flag;
356 }
357 
359 {
360  return mSelectAtIdDisabled;
361 }
362 
363 void QgsDataSourceUri::setSql( const QString &sql )
364 {
365  mSql = sql;
366 }
367 
369 {
370  mSchema.clear();
371 }
372 
373 void QgsDataSourceUri::setSchema( const QString &schema )
374 {
375  mSchema = schema;
376 }
377 
378 QString QgsDataSourceUri::escape( const QString &val, QChar delim = '\'' ) const
379 {
380  QString escaped = val;
381 
382  escaped.replace( '\\', QLatin1String( "\\\\" ) );
383  escaped.replace( delim, QStringLiteral( "\\%1" ).arg( delim ) );
384 
385  return escaped;
386 }
387 
388 void QgsDataSourceUri::skipBlanks( const QString &uri, int &i )
389 {
390  // skip space before value
391  while ( i < uri.length() && uri[i].isSpace() )
392  i++;
393 }
394 
395 QString QgsDataSourceUri::getValue( const QString &uri, int &i )
396 {
397  skipBlanks( uri, i );
398 
399  // Get the parameter value
400  QString pval;
401  if ( i < uri.length() && ( uri[i] == '\'' || uri[i] == '"' ) )
402  {
403  QChar delim = uri[i];
404 
405  i++;
406 
407  // value is quoted
408  for ( ;; )
409  {
410  if ( i == uri.length() )
411  {
412  QgsDebugMsg( QStringLiteral( "unterminated quoted string in connection info string" ) );
413  return pval;
414  }
415 
416  if ( uri[i] == '\\' )
417  {
418  i++;
419  if ( i == uri.length() )
420  continue;
421  if ( uri[i] != delim && uri[i] != '\\' )
422  i--;
423  }
424  else if ( uri[i] == delim )
425  {
426  i++;
427  break;
428  }
429 
430  pval += uri[i++];
431  }
432  }
433  else
434  {
435  // value is not quoted
436  while ( i < uri.length() )
437  {
438  if ( uri[i].isSpace() )
439  {
440  // end of value
441  break;
442  }
443 
444  if ( uri[i] == '\\' )
445  {
446  i++;
447  if ( i == uri.length() )
448  break;
449  if ( uri[i] != '\\' && uri[i] != '\'' )
450  i--;
451  }
452 
453  pval += uri[i++];
454  }
455  }
456 
457  skipBlanks( uri, i );
458 
459  return pval;
460 }
461 
462 QString QgsDataSourceUri::connectionInfo( bool expandAuthConfig ) const
463 {
464  QStringList connectionItems;
465 
466  if ( !mDatabase.isEmpty() )
467  {
468  connectionItems << "dbname='" + escape( mDatabase ) + '\'';
469  }
470 
471  if ( !mService.isEmpty() )
472  {
473  connectionItems << "service='" + escape( mService ) + '\'';
474  }
475  else if ( !mHost.isEmpty() )
476  {
477  connectionItems << "host=" + mHost;
478  }
479 
480  if ( mService.isEmpty() )
481  {
482  if ( !mPort.isEmpty() )
483  connectionItems << "port=" + mPort;
484  }
485 
486  if ( !mDriver.isEmpty() )
487  {
488  connectionItems << "driver='" + escape( mDriver ) + '\'';
489  }
490 
491  if ( !mUsername.isEmpty() )
492  {
493  connectionItems << "user='" + escape( mUsername ) + '\'';
494 
495  if ( !mPassword.isEmpty() )
496  {
497  connectionItems << "password='" + escape( mPassword ) + '\'';
498  }
499  }
500 
501  if ( mSSLmode != SslPrefer ) // no need to output the default
502  {
503  connectionItems << QStringLiteral( "sslmode=" ) + encodeSslMode( mSSLmode );
504  }
505 
506  if ( !mAuthConfigId.isEmpty() )
507  {
508  if ( expandAuthConfig )
509  {
510  if ( !QgsApplication::authManager()->updateDataSourceUriItems( connectionItems, mAuthConfigId ) )
511  {
512  QgsDebugMsg( QStringLiteral( "Data source URI FAILED to update via loading configuration ID '%1'" ).arg( mAuthConfigId ) );
513  }
514  }
515  else
516  {
517  connectionItems << "authcfg=" + mAuthConfigId;
518  }
519  }
520 
521  return connectionItems.join( QStringLiteral( " " ) );
522 }
523 
524 QString QgsDataSourceUri::uri( bool expandAuthConfig ) const
525 {
526  QString uri = connectionInfo( expandAuthConfig );
527 
528  if ( !mKeyColumn.isEmpty() )
529  {
530  uri += QStringLiteral( " key='%1'" ).arg( escape( mKeyColumn ) );
531  }
532 
533  if ( mUseEstimatedMetadata )
534  {
535  uri += QStringLiteral( " estimatedmetadata=true" );
536  }
537 
538  if ( !mSrid.isEmpty() )
539  {
540  uri += QStringLiteral( " srid=%1" ).arg( mSrid );
541  }
542 
543  if ( mWkbType != QgsWkbTypes::Unknown && mWkbType != QgsWkbTypes::NoGeometry )
544  {
545  uri += QLatin1String( " type=" );
546  uri += QgsWkbTypes::displayString( mWkbType );
547  }
548 
549  if ( mSelectAtIdDisabled )
550  {
551  uri += QStringLiteral( " selectatid=false" );
552  }
553 
554  for ( QMap<QString, QString>::const_iterator it = mParams.begin(); it != mParams.end(); ++it )
555  {
556  if ( it.key().contains( '=' ) || it.key().contains( ' ' ) )
557  {
558  QgsDebugMsg( QStringLiteral( "invalid uri parameter %1 skipped" ).arg( it.key() ) );
559  continue;
560  }
561 
562  uri += ' ' + it.key() + "='" + escape( it.value() ) + '\'';
563  }
564 
565  QString columnName( mGeometryColumn );
566  columnName.replace( '\\', QLatin1String( "\\\\" ) );
567  columnName.replace( ')', QLatin1String( "\\)" ) );
568 
569  uri += QStringLiteral( " table=%1%2 sql=%3" )
570  .arg( quotedTablename(),
571  mGeometryColumn.isNull() ? QString() : QStringLiteral( " (%1)" ).arg( columnName ),
572  mSql );
573 
574  return uri;
575 }
576 
578 {
579  QUrl url;
580  for ( auto it = mParams.constBegin(); it != mParams.constEnd(); ++it )
581  {
582  url.addQueryItem( it.key(), it.value() );
583  }
584  return url.encodedQuery();
585 }
586 
587 void QgsDataSourceUri::setEncodedUri( const QByteArray &uri )
588 {
589  mParams.clear();
590  QUrl url;
591  url.setEncodedQuery( uri );
592 
593  const auto constQueryItems = url.queryItems();
594  for ( const QPair<QString, QString> &item : constQueryItems )
595  {
596  mParams.insertMulti( item.first, item.second );
597  }
598 }
599 
600 void QgsDataSourceUri::setEncodedUri( const QString &uri )
601 {
602  setEncodedUri( uri.toLatin1() );
603 }
604 
606 {
607  if ( !mSchema.isEmpty() )
608  return QStringLiteral( "\"%1\".\"%2\"" )
609  .arg( escape( mSchema, '"' ),
610  escape( mTable, '"' ) );
611  else
612  return QStringLiteral( "\"%1\"" )
613  .arg( escape( mTable, '"' ) );
614 }
615 
617  const QString &port,
618  const QString &database,
619  const QString &username,
620  const QString &password,
621  SslMode sslmode,
622  const QString &authConfigId )
623 {
624  mHost = host;
625  mDatabase = database;
626  mPort = port;
627  mUsername = username;
628  mPassword = password;
629  mSSLmode = sslmode;
630  mAuthConfigId = authConfigId;
631 }
632 
634  const QString &database,
635  const QString &username,
636  const QString &password,
637  SslMode sslmode,
638  const QString &authConfigId )
639 {
640  mService = service;
641  mDatabase = database;
642  mUsername = username;
643  mPassword = password;
644  mSSLmode = sslmode;
645  mAuthConfigId = authConfigId;
646 }
647 
649  const QString &table,
650  const QString &geometryColumn,
651  const QString &sql,
652  const QString &keyColumn )
653 {
654  mSchema = schema;
655  mTable = table;
656  mGeometryColumn = geometryColumn;
657  mSql = sql;
658  mKeyColumn = keyColumn;
659 }
660 
661 void QgsDataSourceUri::setAuthConfigId( const QString &authcfg )
662 {
663  mAuthConfigId = authcfg;
664 }
665 
667 {
668  mDatabase = database;
669 }
670 
672 {
673  return mWkbType;
674 }
675 
677 {
678  mWkbType = wkbType;
679 }
680 
681 QString QgsDataSourceUri::srid() const
682 {
683  return mSrid;
684 }
685 
686 void QgsDataSourceUri::setSrid( const QString &srid )
687 {
688  mSrid = srid;
689 }
690 
692 {
693  if ( sslMode == QLatin1String( "prefer" ) )
694  return SslPrefer;
695  else if ( sslMode == QLatin1String( "disable" ) )
696  return SslDisable;
697  else if ( sslMode == QLatin1String( "allow" ) )
698  return SslAllow;
699  else if ( sslMode == QLatin1String( "require" ) )
700  return SslRequire;
701  else if ( sslMode == QLatin1String( "verify-ca" ) )
702  return SslVerifyCa;
703  else if ( sslMode == QLatin1String( "verify-full" ) )
704  return SslVerifyFull;
705  else
706  return SslPrefer; // default
707 }
708 
710 {
711  switch ( sslMode )
712  {
713  case SslPrefer: return QStringLiteral( "prefer" );
714  case SslDisable: return QStringLiteral( "disable" );
715  case SslAllow: return QStringLiteral( "allow" );
716  case SslRequire: return QStringLiteral( "require" );
717  case SslVerifyCa: return QStringLiteral( "verify-ca" );
718  case SslVerifyFull: return QStringLiteral( "verify-full" );
719  }
720  return QString();
721 }
722 
723 void QgsDataSourceUri::setParam( const QString &key, const QString &value )
724 {
725  // may be multiple
726  mParams.insertMulti( key, value );
727 }
728 
729 void QgsDataSourceUri::setParam( const QString &key, const QStringList &value )
730 {
731  const auto constValue = value;
732  for ( const QString &val : constValue )
733  {
734  mParams.insertMulti( key, val );
735  }
736 }
737 
738 int QgsDataSourceUri::removeParam( const QString &key )
739 {
740  return mParams.remove( key );
741 }
742 
743 QString QgsDataSourceUri::param( const QString &key ) const
744 {
745  return mParams.value( key );
746 }
747 
748 QStringList QgsDataSourceUri::params( const QString &key ) const
749 {
750  return mParams.values( key );
751 }
752 
753 bool QgsDataSourceUri::hasParam( const QString &key ) const
754 {
755  return mParams.contains( key );
756 }
QString param(const QString &key) const
Returns a generic parameter value corresponding to the specified key.
QgsWkbTypes::Type wkbType() const
Returns the WKB type associated with the URI.
QString table() const
Returns the table name stored in the URI.
bool useEstimatedMetadata() const
Returns true if estimated metadata should be used for the connection.
void setUsername(const QString &username)
Sets the username for the URI.
bool hasParam(const QString &key) const
Returns true if a parameter with the specified key exists.
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
void clearSchema()
Clears the schema stored in the URI.
static SslMode decodeSslMode(const QString &sslMode)
Decodes SSL mode string into enum value.
QString authConfigId() const
Returns any associated authentication configuration ID stored in the URI.
SslMode sslMode() const
Returns the SSL mode associated with the URI.
static Type parseType(const QString &wktStr)
Attempts to extract the WKB type from a WKT string.
QString keyColumn() const
Returns the name of the (primary) key column for the referenced table.
void setConnection(const QString &aHost, const QString &aPort, const QString &aDatabase, const QString &aUsername, const QString &aPassword, SslMode sslmode=SslPrefer, const QString &authConfigId=QString())
Sets all connection related members at once.
QString connectionInfo(bool expandAuthConfig=true) const
Returns the connection part of the URI.
QString username() const
Returns the username stored in the URI.
SslMode
Available SSQL connection modes.
QString host() const
Returns the host name stored in the URI.
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h:68
QStringList params(const QString &key) const
Returns multiple generic parameter values corresponding to the specified key.
void setDriver(const QString &driver)
Sets the driver name stored in the URI.
int removeParam(const QString &key)
Removes a generic parameter by key.
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
QString geometryColumn() const
Returns the name of the geometry column stored in the URI, if set.
void setKeyColumn(const QString &column)
Sets the name of the (primary) key column.
bool selectAtIdDisabled() const
Returns whether the selection by feature ID is disabled.
bool updateDataSourceUriItems(QStringList &connectionItems, const QString &authcfg, const QString &dataprovider=QString())
Provider call to update a QgsDataSourceUri with an authentication config.
void setEncodedUri(const QByteArray &uri)
Sets the complete encoded uri.
QString quotedTablename() const
Returns the URI&#39;s table name, escaped and quoted.
static QString encodeSslMode(SslMode sslMode)
Encodes SSL mode enum value into a string.
void setParam(const QString &key, const QString &value)
Sets a generic parameter value on the URI.
QString port() const
Returns the port stored in the URI.
void setAuthConfigId(const QString &authcfg)
Sets the authentication configuration ID for the URI.
void setSrid(const QString &srid)
Sets the spatial reference ID associated with the URI.
void setWkbType(QgsWkbTypes::Type type)
Sets the WKB type associated with the URI.
QString uri(bool expandAuthConfig=true) const
Returns the complete URI as a string.
static QgsAuthManager * authManager()
Returns the application&#39;s authentication manager instance.
void disableSelectAtId(bool flag)
Set to true to disable selection by feature ID.
QString driver() const
Returns the driver name stored in the URI.
void setDataSource(const QString &aSchema, const QString &aTable, const QString &aGeometryColumn, const QString &aSql=QString(), const QString &aKeyColumn=QString())
Sets all data source related members at once.
void setSql(const QString &sql)
Sets the SQL query for the URI.
void setPassword(const QString &password)
Sets the password for the URI.
QByteArray encodedUri() const
Returns the complete encoded URI as a byte array.
QString sql() const
Returns the SQL query stored in the URI, if set.
QString service() const
Returns the service name associated with the URI.
static QString displayString(Type type)
Returns a display string type for a WKB type, e.g., the geometry name used in WKT geometry representa...
QString password() const
Returns the password stored in the URI.
void setSchema(const QString &schema)
Sets the scheme for the URI.
QString schema() const
Returns the schema stored in the URI.
void setUseEstimatedMetadata(bool flag)
Sets whether estimated metadata should be used for the connection.
QString database() const
Returns the database name stored in the URI.
void setDatabase(const QString &database)
Sets the URI database name.
QString srid() const
Returns the spatial reference ID associated with the URI.
static QString removePassword(const QString &aUri)
Removes the password element from a URI.