QGIS API Documentation  2.9.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
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 "qgslogger.h"
21 #include "qgswkbtypes.h"
22 
23 #include <QStringList>
24 #include <QRegExp>
25 #include <QUrl>
26 
28  : mSSLmode( SSLprefer )
29  , mKeyColumn( "" )
30  , mUseEstimatedMetadata( false )
31  , mSelectAtIdDisabled( false )
32  , mWkbType( QGis::WKBUnknown )
33 {
34  // do nothing
35 }
36 
38  : mSSLmode( SSLprefer )
39  , mKeyColumn( "" )
40  , mUseEstimatedMetadata( false )
41  , mSelectAtIdDisabled( false )
42  , mWkbType( QGis::WKBUnknown )
43 {
44  int i = 0;
45  while ( i < uri.length() )
46  {
47  skipBlanks( uri, i );
48 
49  if ( uri[i] == '=' )
50  {
51  QgsDebugMsg( "parameter name expected before =" );
52  i++;
53  continue;
54  }
55 
56  int start = i;
57 
58  while ( i < uri.length() && uri[i] != '=' && !uri[i].isSpace() )
59  i++;
60 
61  QString pname = uri.mid( start, i - start );
62 
63  skipBlanks( uri, i );
64 
65  if ( i == uri.length() || uri[i] != '=' )
66  {
67  QgsDebugMsg( "= expected after parameter name" );
68  return;
69  }
70 
71  i++;
72 
73  if ( pname == "sql" )
74  {
75  // rest of line is a sql where clause
76  skipBlanks( uri, i );
77  mSql = uri.mid( i );
78  break;
79  }
80  else
81  {
82  QString pval = getValue( uri, i );
83 
84  if ( pname == "table" )
85  {
86  if ( uri[i] == '.' )
87  {
88  i++;
89 
90  mSchema = pval;
91  mTable = getValue( uri, i );
92  }
93  else
94  {
95  mSchema = "";
96  mTable = pval;
97  }
98 
99  if ( uri[i] == '(' )
100  {
101  i++;
102 
103  int start = i;
104  QString col;
105  while ( i < uri.length() && uri[i] != ')' )
106  {
107  if ( uri[i] == '\\' )
108  i++;
109  i++;
110  }
111 
112  if ( i == uri.length() )
113  {
114  QgsDebugMsg( "closing parenthesis missing" );
115  }
116 
117  mGeometryColumn = uri.mid( start, i - start );
118  mGeometryColumn.replace( "\\)", ")" );
119  mGeometryColumn.replace( "\\\\", "\\" );
120 
121  i++;
122  }
123  else
124  {
125  mGeometryColumn = QString::null;
126  }
127  }
128  else if ( pname == "key" )
129  {
130  mKeyColumn = pval;
131  }
132  else if ( pname == "estimatedmetadata" )
133  {
134  mUseEstimatedMetadata = pval == "true";
135  }
136  else if ( pname == "srid" )
137  {
138  mSrid = pval;
139  }
140  else if ( pname == "type" )
141  {
142  QString geomTypeUpper = pval.toUpper();
143  if ( geomTypeUpper == "POINT" )
144  {
145  mWkbType = QGis::WKBPoint;
146  }
147  else if ( geomTypeUpper == "LINESTRING" || geomTypeUpper == "LINE" )
148  {
149  mWkbType = QGis::WKBLineString;
150  }
151  else if ( geomTypeUpper == "POLYGON" )
152  {
153  mWkbType = QGis::WKBPolygon;
154  }
155  else if ( geomTypeUpper == "MULTIPOINT" )
156  {
157  mWkbType = QGis::WKBMultiPoint;
158  }
159  else if ( geomTypeUpper == "MULTILINESTRING" )
160  {
161  mWkbType = QGis::WKBMultiLineString;
162  }
163  else if ( geomTypeUpper == "MULTIPOLYGON" )
164  {
165  mWkbType = QGis::WKBMultiPolygon;
166  }
167  else
168  {
169  mWkbType = QGis::WKBUnknown;
170  }
171  }
172  else if ( pname == "selectatid" )
173  {
174  mSelectAtIdDisabled = pval == "false";
175  }
176  else if ( pname == "service" )
177  {
178  mService = pval;
179  }
180  else if ( pname == "user" )
181  {
182  mUsername = pval;
183  }
184  else if ( pname == "password" )
185  {
186  mPassword = pval;
187  }
188  else if ( pname == "connect_timeout" )
189  {
190  QgsDebugMsg( "connection timeout ignored" );
191  }
192  else if ( pname == "dbname" )
193  {
194  mDatabase = pval;
195  }
196  else if ( pname == "host" )
197  {
198  mHost = pval;
199  }
200  else if ( pname == "hostaddr" )
201  {
202  QgsDebugMsg( "database host ip address ignored" );
203  }
204  else if ( pname == "port" )
205  {
206  mPort = pval;
207  }
208  else if ( pname == "tty" )
209  {
210  QgsDebugMsg( "backend debug tty ignored" );
211  }
212  else if ( pname == "options" )
213  {
214  QgsDebugMsg( "backend debug options ignored" );
215  }
216  else if ( pname == "sslmode" )
217  {
218  if ( pval == "disable" )
219  mSSLmode = SSLdisable;
220  else if ( pval == "allow" )
221  mSSLmode = SSLallow;
222  else if ( pval == "prefer" )
223  mSSLmode = SSLprefer;
224  else if ( pval == "require" )
225  mSSLmode = SSLrequire;
226  }
227  else if ( pname == "requiressl" )
228  {
229  if ( pval == "0" )
230  mSSLmode = SSLdisable;
231  else
232  mSSLmode = SSLprefer;
233  }
234  else if ( pname == "krbsrvname" )
235  {
236  QgsDebugMsg( "kerberos server name ignored" );
237  }
238  else if ( pname == "gsslib" )
239  {
240  QgsDebugMsg( "gsslib ignored" );
241  }
242  else
243  {
244  QgsDebugMsg( "parameter \"" + pname + "\":\"" + pval + "\" added" );
245  setParam( pname, pval );
246  }
247  }
248  }
249 }
250 
251 QString QgsDataSourceURI::removePassword( const QString& aUri )
252 {
253  QRegExp regexp;
254  regexp.setMinimal( true );
255  QString safeName( aUri );
256  if ( aUri.contains( " password=" ) )
257  {
258  regexp.setPattern( " password=.* " );
259  safeName.replace( regexp, " " );
260  }
261  else if ( aUri.contains( ",password=" ) )
262  {
263  regexp.setPattern( ",password=.*," );
264  safeName.replace( regexp, "," );
265  }
266  else if ( aUri.contains( "IDB:" ) )
267  {
268  regexp.setPattern( " pass=.* " );
269  safeName.replace( regexp, " " );
270  }
271  else if (( aUri.contains( "OCI:" ) )
272  || ( aUri.contains( "ODBC:" ) ) )
273  {
274  regexp.setPattern( "/.*@" );
275  safeName.replace( regexp, "/@" );
276  }
277  else if ( aUri.contains( "SDE:" ) )
278  {
279  QStringList strlist = aUri.split( "," );
280  safeName = strlist[0] + "," + strlist[1] + "," + strlist[2] + "," + strlist[3];
281  }
282  return safeName;
283 }
284 
286 {
287  return mUsername;
288 }
289 
290 void QgsDataSourceURI::setUsername( QString username )
291 {
292  mUsername = username;
293 }
294 
296 {
297  return mService;
298 }
299 
300 QString QgsDataSourceURI::host() const
301 {
302  return mHost;
303 }
304 
306 {
307  return mDatabase;
308 }
309 
311 {
312  return mPassword;
313 }
314 
315 void QgsDataSourceURI::setPassword( QString password )
316 {
317  mPassword = password;
318 }
319 
320 QString QgsDataSourceURI::port() const
321 {
322  return mPort;
323 }
324 
326 {
327  return mSSLmode;
328 }
329 
331 {
332  return mSchema;
333 }
334 
335 QString QgsDataSourceURI::table() const
336 {
337  return mTable;
338 }
339 
340 QString QgsDataSourceURI::sql() const
341 {
342  return mSql;
343 }
344 
346 {
347  return mGeometryColumn;
348 }
349 
351 {
352  return mKeyColumn;
353 }
354 
355 void QgsDataSourceURI::setKeyColumn( QString column )
356 {
357  mKeyColumn = column;
358 }
359 
360 
362 {
363  mUseEstimatedMetadata = theFlag;
364 }
365 
367 {
368  return mUseEstimatedMetadata;
369 }
370 
372 {
373  mSelectAtIdDisabled = theFlag;
374 }
375 
377 {
378  return mSelectAtIdDisabled;
379 }
380 
381 void QgsDataSourceURI::setSql( QString sql )
382 {
383  mSql = sql;
384 }
385 
387 {
388  mSchema = "";
389 }
390 
391 QString QgsDataSourceURI::escape( const QString &theVal, QChar delim = '\'' ) const
392 {
393  QString val = theVal;
394 
395  val.replace( "\\", "\\\\" );
396  val.replace( delim, QString( "\\%1" ).arg( delim ) );
397 
398  return val;
399 }
400 
401 void QgsDataSourceURI::skipBlanks( const QString &uri, int &i )
402 {
403  // skip space before value
404  while ( i < uri.length() && uri[i].isSpace() )
405  i++;
406 }
407 
408 QString QgsDataSourceURI::getValue( const QString &uri, int &i )
409 {
410  skipBlanks( uri, i );
411 
412  // Get the parameter value
413  QString pval;
414  if ( i < uri.length() && ( uri[i] == '\'' || uri[i] == '"' ) )
415  {
416  QChar delim = uri[i];
417 
418  i++;
419 
420  // value is quoted
421  for ( ;; )
422  {
423  if ( i == uri.length() )
424  {
425  QgsDebugMsg( "unterminated quoted string in connection info string" );
426  return pval;
427  }
428 
429  if ( uri[i] == '\\' )
430  {
431  i++;
432  if ( i == uri.length() )
433  continue;
434  if ( uri[i] != delim && uri[i] != '\\' )
435  i--;
436  }
437  else if ( uri[i] == delim )
438  {
439  i++;
440  break;
441  }
442 
443  pval += uri[i++];
444  }
445  }
446  else
447  {
448  // value is not quoted
449  while ( i < uri.length() )
450  {
451  if ( uri[i].isSpace() )
452  {
453  // end of value
454  break;
455  }
456 
457  if ( uri[i] == '\\' )
458  {
459  i++;
460  if ( i == uri.length() )
461  break;
462  if ( uri[i] != '\\' && uri[i] != '\'' )
463  i--;
464  }
465 
466  pval += uri[i++];
467  }
468  }
469 
470  skipBlanks( uri, i );
471 
472  return pval;
473 }
474 
476 {
477  QStringList connectionItems;
478 
479  if ( mDatabase != "" )
480  {
481  connectionItems << "dbname='" + escape( mDatabase ) + "'";
482  }
483 
484  if ( mService != "" )
485  {
486  connectionItems << "service='" + escape( mService ) + "'";
487  }
488  else if ( mHost != "" )
489  {
490  connectionItems << "host=" + mHost;
491  }
492 
493  if ( mService.isEmpty() )
494  {
495  if ( mPort != "" )
496  connectionItems << "port=" + mPort;
497  }
498 
499  if ( mUsername != "" )
500  {
501  connectionItems << "user='" + escape( mUsername ) + "'";
502 
503  if ( mPassword != "" )
504  {
505  connectionItems << "password='" + escape( mPassword ) + "'";
506  }
507  }
508 
509  if ( mSSLmode == SSLdisable )
510  connectionItems << "sslmode=disable";
511  else if ( mSSLmode == SSLallow )
512  connectionItems << "sslmode=allow";
513  else if ( mSSLmode == SSLrequire )
514  connectionItems << "sslmode=require";
515 #if 0
516  else if ( mSSLmode == SSLprefer )
517  connectionItems << "sslmode=prefer";
518 #endif
519 
520  return connectionItems.join( " " );
521 }
522 
523 QString QgsDataSourceURI::uri() const
524 {
525  QString theUri = connectionInfo();
526 
527  if ( !mKeyColumn.isEmpty() )
528  {
529  theUri += QString( " key='%1'" ).arg( escape( mKeyColumn ) );
530  }
531 
532  if ( mUseEstimatedMetadata )
533  {
534  theUri += QString( " estimatedmetadata=true" );
535  }
536 
537  if ( !mSrid.isEmpty() )
538  {
539  theUri += QString( " srid=%1" ).arg( mSrid );
540  }
541 
542  if ( mWkbType != QGis::WKBUnknown && mWkbType != QGis::WKBNoGeometry )
543  {
544  theUri += " type=";
545  theUri += QgsWKBTypes::displayString( QgsWKBTypes::flatType(( QgsWKBTypes::Type( mWkbType ) ) ) );
546  }
547 
548  if ( mSelectAtIdDisabled )
549  {
550  theUri += QString( " selectatid=false" );
551  }
552 
553  for ( QMap<QString, QString>::const_iterator it = mParams.begin(); it != mParams.end(); ++it )
554  {
555  if ( it.key().contains( "=" ) || it.key().contains( " " ) )
556  {
557  QgsDebugMsg( QString( "invalid uri parameter %1 skipped" ).arg( it.key() ) );
558  continue;
559  }
560 
561  theUri += " " + it.key() + "='" + escape( it.value() ) + "'";
562  }
563 
564  QString columnName( mGeometryColumn );
565  columnName.replace( "\\", "\\\\" );
566  columnName.replace( ")", "\\)" );
567 
568  theUri += QString( " table=%1%2 sql=%3" )
569  .arg( quotedTablename() )
570  .arg( mGeometryColumn.isNull() ? QString() : QString( " (%1)" ).arg( columnName ) )
571  .arg( mSql );
572 
573  return theUri;
574 }
575 
577 {
578  QUrl url;
579  foreach ( QString key, mParams.uniqueKeys() )
580  {
581  foreach ( QString value, mParams.values( key ) )
582  {
583  url.addQueryItem( key, value );
584  }
585  }
586  return url.encodedQuery();
587 }
588 
589 void QgsDataSourceURI::setEncodedUri( const QByteArray & uri )
590 {
591  mParams.clear();
592  QUrl url;
593  url.setEncodedQuery( uri );
594  QPair<QString, QString> item;
595  foreach ( item, url.queryItems() )
596  {
597  mParams.insertMulti( item.first, item.second );
598  }
599 }
600 
601 void QgsDataSourceURI::setEncodedUri( const QString & uri )
602 {
603  setEncodedUri( uri.toAscii() );
604 }
605 
607 {
608  if ( !mSchema.isEmpty() )
609  return QString( "\"%1\".\"%2\"" )
610  .arg( escape( mSchema, '"' ) )
611  .arg( escape( mTable, '"' ) );
612  else
613  return QString( "\"%1\"" )
614  .arg( escape( mTable, '"' ) );
615 }
616 
617 void QgsDataSourceURI::setConnection( const QString &host,
618  const QString &port,
619  const QString &database,
620  const QString &username,
621  const QString &password,
622  SSLmode sslmode )
623 {
624  mHost = host;
625  mDatabase = database;
626  mPort = port;
627  mUsername = username;
628  mPassword = password;
629  mSSLmode = sslmode;
630 }
631 
632 void QgsDataSourceURI::setConnection( const QString &service,
633  const QString &database,
634  const QString &username,
635  const QString &password,
636  SSLmode sslmode )
637 {
638  mService = service;
639  mDatabase = database;
640  mUsername = username;
641  mPassword = password;
642  mSSLmode = sslmode;
643 }
644 
645 void QgsDataSourceURI::setDataSource( const QString &schema,
646  const QString &table,
647  const QString &geometryColumn,
648  const QString &sql,
649  const QString &keyColumn )
650 {
651  mSchema = schema;
652  mTable = table;
653  mGeometryColumn = geometryColumn;
654  mSql = sql;
655  mKeyColumn = keyColumn;
656 }
657 
658 void QgsDataSourceURI::setDatabase( const QString &database )
659 {
660  mDatabase = database;
661 }
662 
664 {
665  return mWkbType;
666 }
667 
669 {
670  mWkbType = wkbType;
671 }
672 
673 QString QgsDataSourceURI::srid() const
674 {
675  return mSrid;
676 }
677 
678 void QgsDataSourceURI::setSrid( QString srid )
679 {
680  mSrid = srid;
681 }
682 
683 void QgsDataSourceURI::setParam( const QString &key, const QString &value )
684 {
685  // may be multiple
686  mParams.insertMulti( key, value );
687 }
688 
689 void QgsDataSourceURI::setParam( const QString &key, const QStringList &value )
690 {
691  foreach ( QString val, value )
692  {
693  mParams.insertMulti( key, val );
694  }
695 }
696 
697 int QgsDataSourceURI::removeParam( const QString &key )
698 {
699  return mParams.remove( key );
700 }
701 
702 QString QgsDataSourceURI::param( const QString &key ) const
703 {
704  return mParams.value( key );
705 }
706 
707 QStringList QgsDataSourceURI::params( const QString &key ) const
708 {
709  return mParams.values( key );
710 }
711 
712 bool QgsDataSourceURI::hasParam( const QString &key ) const
713 {
714  return mParams.contains( key );
715 }