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