All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
DataSource.cpp
Go to the documentation of this file.
1 /* Copyright (C) 2008 National Institute For Space Research (INPE) - Brazil.
2 
3  This file is part of the TerraLib - a Framework for building GIS enabled applications.
4 
5  TerraLib is free software: you can redistribute it and/or modify
6  it under the terms of the GNU Lesser General Public License as published byF
7  the Free Software Foundation, either version 3 of the License,
8  or (at your option) any later version.
9 
10  TerraLib is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU Lesser General Public License for more details.
14 
15  You should have received a copy of the GNU Lesser General Public License
16  along with TerraLib. See COPYING. If not, write to
17  TerraLib Team at <terralib-team@terralib.org>.
18  */
19 
20 /*!
21  \file terralib/postgis/DataSource.cpp
22 
23  \brief Implementation of the data source for the PostGIS driver.
24 */
25 
26 // TerraLib
27 #include "../common/StringUtils.h"
28 #include "../common/Translator.h"
29 #include "../dataaccess/dataset/CheckConstraint.h"
30 #include "../dataaccess/dataset/DataSet.h"
31 #include "../dataaccess/dataset/ForeignKey.h"
32 #include "../dataaccess/dataset/Index.h"
33 #include "../dataaccess/dataset/PrimaryKey.h"
34 #include "../dataaccess/dataset/Sequence.h"
35 #include "../dataaccess/dataset/UniqueKey.h"
36 #include "../dataaccess/datasource/ScopedTransaction.h"
37 #include "../dataaccess/query/Select.h"
38 #include "../dataaccess/query/SQLDialect.h"
39 #include "../dataaccess/utils/Utils.h"
40 #include "../datatype/Array.h"
41 #include "../datatype/Property.h"
42 #include "../datatype/SimpleData.h"
43 #include "../geometry/GeometryProperty.h"
44 #include "../geometry/Utils.h"
45 #include "../raster/Grid.h"
46 #include "../raster/BandProperty.h"
47 #include "../raster/RasterProperty.h"
48 #include "../geometry/Geometry.h"
49 #include "Connection.h"
50 #include "ConnectionPool.h"
51 #include "DataSource.h"
52 #include "DataSet.h"
53 #include "Exception.h"
54 #include "Globals.h"
55 #include "PreparedQuery.h"
56 #include "SQLVisitor.h"
57 #include "Transactor.h"
58 #include "Utils.h"
59 
60 // STL
61 #include <cassert>
62 //#include <cstring>
63 #include <memory>
64 
65 // Boost
66 //#include <boost/algorithm/string/case_conv.hpp>
67 #include <boost/format.hpp>
68 //#include <boost/lexical_cast.hpp>
69 //#include <boost/thread.hpp>
70 
71 // libpq
72 #include <libpq-fe.h>
73 
75  : m_pool(0),
76  m_geomTypeOid(0),
77  m_rasterTypeOid(0),
78  m_timeIsInteger(true)
79 {
80  m_pool = new ConnectionPool(this);
81 }
82 
84 {
85  delete m_pool;
86 }
87 
88 std::string te::pgis::DataSource::getType() const
89 {
91 }
92 
93 const std::map<std::string, std::string>& te::pgis::DataSource::getConnectionInfo() const
94 {
95  return m_connInfo;
96 }
97 
98 void te::pgis::DataSource::setConnectionInfo(const std::map<std::string, std::string>& connInfo)
99 {
100  m_connInfo = connInfo;
101 }
102 
103 std::auto_ptr<te::da::DataSourceTransactor> te::pgis::DataSource::getTransactor()
104 {
105  Connection* conn = m_pool->getConnection();
106 
107  return std::auto_ptr<te::da::DataSourceTransactor>(new te::pgis::Transactor(this, conn));
108 }
109 
111 {
112  return m_pool->getConnection();
113 }
114 
116 {
117  m_pool->release(conn);
118 }
119 
121 {
122  return m_timeIsInteger;
123 }
124 
126 {
127  m_timeIsInteger = timeIsInteger;
128 }
129 
131 {
132  // Assure we are in a closed state
133  close();
134 
135  // Retrieve the char encoding
136  std::map<std::string, std::string>::const_iterator it = m_connInfo.find("PG_CLIENT_ENCODING");
137  if(it != m_connInfo.end())
138  m_encoding = te::common::CharEncodingConv::getCharEncodingType(it->second);
139  else
141 
142  m_pool->initialize();
143 
144  std::auto_ptr<te::da::DataSourceTransactor> t = getTransactor();
145  te::pgis::Transactor* pgt = static_cast<te::pgis::Transactor*>(t.get());
146 
147  // Find the PostGIS types
148  m_geomTypeOid = pgt->getGeomTypeId();
149  m_rasterTypeOid = pgt->getRasterTypeId();
150 
151  // Find the PostgreSQL current schema of the connection
152  pgt->getDatabaseInfo(m_currentSchema);
153 }
154 
156 {
157  m_pool->finalize();
158 }
159 
161 {
162  return m_pool->isInitialized();
163 }
164 
166 {
167  return m_pool->isValid();
168 }
169 
171 {
173 }
174 
176 {
178 }
179 
181 {
182  return m_geomTypeOid;
183 }
184 
186 {
187  return m_rasterTypeOid;
188 }
189 
190 const std::string& te::pgis::DataSource::getCurrentSchema() const
191 {
192  return m_currentSchema;
193 }
194 
196 {
197  return m_pool;
198 }
199 
201 {
202  return m_encoding;
203 }
204 
205 void te::pgis::DataSource::create(const std::map<std::string, std::string>& dsInfo)
206 {
207  // Get an auxiliary data source
208  std::auto_ptr<DataSource> ds(new DataSource());
209 
210  ds->setConnectionInfo(dsInfo);
211 
212  ds->open();
213 
214  // Create a database based on the connection information
215  std::string sql = "CREATE DATABASE ";
216 
217  std::map<std::string, std::string>::const_iterator it = dsInfo.find("PG_NEWDB_NAME");
218  std::map<std::string, std::string>::const_iterator it_end = dsInfo.end();
219 
220  if(it != it_end)
221  sql += "\"" + it->second + "\"";
222  else
223  throw Exception(TE_TR("The database could not be created due the missing parameter: PG_NEWDB_NAME!"));
224 
225  it = dsInfo.find("PG_NEWDB_TEMPLATE");
226 
227  if(it != it_end)
228  sql += " TEMPLATE = " + it->second;
229 
230  it = dsInfo.find("PG_NEWDB_OWNER");
231 
232  if(it != it_end)
233  sql += " OWNER = " + it->second;
234 
235  it = dsInfo.find("PG_NEWDB_ENCODING");
236 
237  if(it != it_end)
238  sql += " ENCODING = " + it->second;
239 
240  it = dsInfo.find("PG_NEWDB_TABLESPACE");
241 
242  if(it != it_end)
243  sql += " TABLESPACE = " + it->second;
244 
245  it = dsInfo.find("PG_NEWDB_CONN_LIMIT");
246 
247  if(it != it_end)
248  sql += " CONNECTION LIMIT = " + it->second;
249 
250  ds->execute(sql);
251 
252  ds->close();
253 
254  // Copy the database connection parameters to this new data source object.
255  it = dsInfo.find("PG_NEWDB_HOST");
256 
257  if(it == it_end)
258  it = dsInfo.find("PG_HOST");
259 
260  if(it != it_end)
261  m_connInfo["PG_HOST"] = it->second;
262 
263  it = dsInfo.find("PG_NEWDB_HOSTADDR");
264 
265  if(it == it_end)
266  it = dsInfo.find("PG_HOST_ADDR");
267 
268  if(it != it_end)
269  m_connInfo["PG_HOST_ADDR"] = it->second;
270 
271  it = dsInfo.find("PG_NEWDB_PORT");
272 
273  if(it == it_end)
274  it = dsInfo.find("PG_PORT");
275 
276  if(it != it_end)
277  m_connInfo["PG_PORT"] = it->second;
278 
279  it = dsInfo.find("PG_NEWDB_NAME");
280 
281  if(it != it_end)
282  m_connInfo["PG_DB_NAME"] = it->second;
283 
284  it = dsInfo.find("PG_NEWDB_USER");
285 
286  if(it == it_end)
287  it = dsInfo.find("PG_USER");
288 
289  if(it != it_end)
290  m_connInfo["PG_USER"] = it->second;
291 
292  it = dsInfo.find("PG_NEWDB_PASSWORD");
293 
294  if(it == it_end)
295  it = dsInfo.find("PG_PASSWORD");
296 
297  if(it != it_end)
298  m_connInfo["PG_PASSWORD"] = it->second;
299 
300  it = dsInfo.find("PG_NEWDB_CONNECT_TIMEOUT");
301 
302  if(it == it_end)
303  it = dsInfo.find("PG_CONNECT_TIMEOUT");
304 
305  if(it != it_end)
306  m_connInfo["PG_CONNECT_TIMEOUT"] = it->second;
307 
308  it = dsInfo.find("PG_NEWDB_OPTIONS");
309 
310  if(it == it_end)
311  it = dsInfo.find("PG_OPTIONS");
312 
313  if(it != it_end)
314  m_connInfo["PG_OPTIONS"] = it->second;
315 
316  it = dsInfo.find("PG_NEWDB_SSL_MODE");
317 
318  if(it == it_end)
319  it = dsInfo.find("PG_SSL_MODE");
320 
321  if(it != it_end)
322  m_connInfo["PG_SSL_MODE"] = it->second;
323 
324  it = dsInfo.find("PG_NEWDB_KRBSRVNAME");
325 
326  if(it == it_end)
327  it = dsInfo.find("PG_KRBSRVNAME");
328 
329  if(it != it_end)
330  m_connInfo["PG_KRBSRVNAME"] = it->second;
331 
332  it = dsInfo.find("PG_NEWDB_GSSLIB");
333 
334  if(it == it_end)
335  it = dsInfo.find("PG_GSSLIB");
336 
337  if(it != it_end)
338  m_connInfo["PG_GSSLIB"] = it->second;
339 
340  it = dsInfo.find("PG_NEWDB_INITIAL_POOL_SIZE");
341 
342  if(it == it_end)
343  it = dsInfo.find("PG_INITIAL_POOL_SIZE");
344 
345  if(it != it_end)
346  m_connInfo["PG_INITIAL_POOL_SIZE"] = it->second;
347 
348  it = dsInfo.find("PG_NEWDB_MIN_POOL_SIZE");
349 
350  if(it == it_end)
351  it = dsInfo.find("PG_MIN_POOL_SIZE");
352 
353  if(it != it_end)
354  m_connInfo["PG_MIN_POOL_SIZE"] = it->second;
355 
356  it = dsInfo.find("PG_NEW_DB_MAX_POOL_SIZE");
357 
358  if(it == it_end)
359  it = dsInfo.find("PG_MAX_POOL_SIZE");
360 
361  if(it != it_end)
362  m_connInfo["PG_MAX_POOL_SIZE"] = it->second;
363 
364  it = dsInfo.find("PG_NEWDB_MAX_IDLE_TIME");
365 
366  if(it == it_end)
367  it = dsInfo.find("PG_MAX_IDLE_TIME");
368 
369  if(it != it_end)
370  m_connInfo["PG_MAX_IDLE_TIME"] = it->second;
371 
372  it = dsInfo.find("PG_NEWDB_CLIENT_ENCODING");
373 
374  if(it == it_end)
375  it = dsInfo.find("PG_CLIENT_ENCODING");
376 
377  if(it != it_end)
378  m_connInfo["PG_CLIENT_ENCODING"] = it->second;
379 }
380 
381 void te::pgis::DataSource::drop(const std::map<std::string, std::string>& dsInfo)
382 {
383  // Get an auxiliary data source
384  std::auto_ptr<DataSource> ds(new DataSource());
385 
386  ds->setConnectionInfo(dsInfo);
387 
388  ds->open();
389 
390  // Drop the database
391  std::string sql = "DROP DATABASE ";
392 
393  std::map<std::string, std::string>::const_iterator it = dsInfo.find("PG_DB_TO_DROP");
394 
395  if(it == dsInfo.end())
396  throw Exception(TE_TR("Could not drop the database due the missing parameter: PG_DB_TO_DROP!"));
397 
398  if((it->second == "postgres") || (it->second == "template_postgis"))
399  throw Exception(TE_TR("The database postgres or template_postgis is not allowed to be dropped!"));
400 
401  sql += it->second;
402 
403  ds->execute(sql);
404 
405  ds->close();
406 }
407 
408 bool te::pgis::DataSource::exists(const std::map<std::string, std::string>& dsInfo)
409 {
410  if(dsInfo.count("PG_CHECK_DB_EXISTENCE") == 0)
411  throw Exception(TE_TR("Could not check the PostgreSQL database existence due the missing parameter: PG_CHECK_DB_EXISTENCE!"));
412 
413  const std::string& dbName = dsInfo.find("PG_CHECK_DB_EXISTENCE")->second;
414 
415  // Get an auxiliary data source
416  std::auto_ptr<DataSource> ds(new DataSource());
417 
418  ds->setConnectionInfo(dsInfo);
419 
420  ds->open();
421 
422  std::string sql("SELECT * FROM pg_database WHERE datname = '");
423  sql += dbName;
424  sql += "'";
425 
426  std::auto_ptr<te::da::DataSet> database(ds->query(sql));
427 
428  ds->close();
429 
430  return database->moveNext();
431 }
432 
433 std::vector<std::string> te::pgis::DataSource::getDataSourceNames(const std::map<std::string, std::string>& dsInfo)
434 {
435  // Get an auxiliary data source
436  std::auto_ptr<DataSource> ds(new DataSource());
437 
438  ds->setConnectionInfo(dsInfo);
439 
440  ds->open();
441 
442  std::string sql("SELECT datname FROM pg_database");
443 
444  std::auto_ptr<te::da::DataSet> dataset(ds->query(sql));
445 
446  std::vector<std::string> dataSourceNames;
447 
448  while(dataset->moveNext())
449  dataSourceNames.push_back(dataset->getString(0));
450 
451  ds->close();
452 
453  return dataSourceNames;
454 }
455 
456 
457 std::vector<te::common::CharEncoding> te::pgis::DataSource::getEncodings(const std::map<std::string, std::string>& dsInfo)
458 {
459  std::vector<te::common::CharEncoding> encodings;
460 
461  encodings.push_back(te::common::UTF8); // UTF8
462  encodings.push_back(te::common::CP1250); // WIN1250
463  encodings.push_back(te::common::CP1251); // WIN1251
464  encodings.push_back(te::common::CP1252); // WIN1252
465  encodings.push_back(te::common::CP1253); // WIN1253
466  encodings.push_back(te::common::CP1254); // WIN1254
467  encodings.push_back(te::common::CP1257); // WIN1257
468  encodings.push_back(te::common::LATIN1); // LATIN1
469 
470  //std::auto_ptr<DataSource> ds(new DataSource());
471 
472  //ds->setConnectionInfo(dsInfo);
473 
474  //ds->open();
475 
476  //std::string sql("SELECT DISTINCT pg_catalog.pg_encoding_to_char(conforencoding) FROM pg_catalog.pg_conversion ORDER BY pg_catalog.pg_encoding_to_char(conforencoding)");
477 
478  //std::auto_ptr<te::da::DataSet> encs(ds->query(sql));
479 
480  //while(encs->moveNext())
481  // encodings.push_back(encs->getString(0));
482 
483  //ds->close();
484 
485  return encodings;
486 }
void getDatabaseInfo(std::string &currentSchema)
It retrieves some information about the database such as the default schema used when no one is provi...
const te::da::DataSourceCapabilities & getCapabilities() const
It returns the known capabilities of the data source.
Definition: DataSource.cpp:170
ConnectionPool * m_pool
The connection pool.
Definition: DataSource.h:172
Utility functions for the data access module.
void setConnectionInfo(const std::map< std::string, std::string > &connInfo)
It sets the connection information to be used when connecting to the data source. ...
Definition: DataSource.cpp:98
CharEncoding
Supported charsets (character encoding).
std::string getType() const
It returns the data source type name (in UPPER CASE). Ex: POSTGIS, SQLITE, WFS, WMS, or MYSQL.
Definition: DataSource.cpp:88
~DataSource()
Virtual destructor.
Definition: DataSource.cpp:83
void open()
It opens the connection(s) to the PostgreSQL database server.
Definition: DataSource.cpp:130
static te::da::DataSourceCapabilities * sm_capabilities
The query dialect supported by PostGIS driver.
Definition: Globals.h:95
An static class with global definitions.
It represents the SQL query dialect accepted by a given data source.
Definition: SQLDialect.h:55
unsigned int getRasterTypeId() const
It returns the type id associated to the PostGIS Raster type.
Definition: DataSource.cpp:185
const std::string & getCurrentSchema() const
It returns the current schema associated to the database connection, or NULL, if none is set...
Definition: DataSource.cpp:190
A class that represents the known capabilities of a specific data source, i.e. this class informs all...
A class that implements a connection to a PostgreSQL database.
Definition: Connection.h:68
#define TE_TR(message)
It marks a string in order to get translated.
Definition: Translator.h:347
void closeConnection(Connection *conn)
Definition: DataSource.cpp:115
void create(const std::map< std::string, std::string > &dsInfo)
It creates a new data source.
Definition: DataSource.cpp:205
void setTimeAsInteger(bool timeIsInteger)
Definition: DataSource.cpp:125
The PostGIS driver.
Definition: DataSource.h:54
static te::da::SQLDialect * sm_queryDialect
The query dialect supported by PostGIS driver.
Definition: Globals.h:94
The transactor class for the PostGIS driver.
Definition: Transactor.h:62
const std::map< std::string, std::string > & getConnectionInfo() const
It returns the set of parameters used to set up the access channel to the underlying repository...
Definition: DataSource.cpp:93
void drop(const std::map< std::string, std::string > &dsInfo)
It removes the data source with the connection information from a driver.
Definition: DataSource.cpp:381
static CharEncoding getCharEncodingType(const std::string &name)
It returns the charset type of the given charset name.
te::pgis::Connection * getConnection()
Definition: DataSource.cpp:110
bool isValid() const
It checks if the data source is valid (available for using).
Definition: DataSource.cpp:165
const te::da::SQLDialect * getDialect() const
It returns the data source SQL dialect, if there is one.
Definition: DataSource.cpp:175
std::auto_ptr< te::da::DataSourceTransactor > getTransactor()
It returns an object that can execute transactions in the context of a data source.
Definition: DataSource.cpp:103
A class that implements a connection to a PostgreSQL database.
bool exists(const std::map< std::string, std::string > &dsInfo)
Check the existence of a data source in a driver.
Definition: DataSource.cpp:408
bool isOpened() const
It returns true if the data source is opened, otherwise it returns false.
Definition: DataSource.cpp:160
Implementation of the data source for the PostGIS driver.
A Transactor can be viewed as a connection to the data source for reading/writing things into it...
void close()
It closes the data source and clears all the resources used by its internal communication channel...
Definition: DataSource.cpp:155
ConnectionPool * getConnPool() const
It returns a pointer to the internal connection pool.
Definition: DataSource.cpp:195
An exception class for the PostGIS driver.
A visitor for building an SQL statement using PostGIS dialect.
te::common::CharEncoding getCharEncoding() const
It returns the datasource char encoding.
Definition: DataSource.cpp:200
std::vector< std::string > getDataSourceNames(const std::map< std::string, std::string > &dsInfo)
It gets the data source names available in a driver.
Definition: DataSource.cpp:433
This class implements a connection pool for the PostGIS driver.
unsigned int getGeomTypeId()
It will check in the database catalog the number that identifies the PostGIS Geometry type...
unsigned int getRasterTypeId()
It will check in the database catalog the number that identifies the PostGIS Raster type...
A dataset is the unit of information manipulated by the data access module of TerraLib.
A class that implements a connection pool for PostGIS.
#define PGIS_DRIVER_IDENTIFIER
The PostGIS driver identifier string.
Definition: Config.h:90
std::vector< te::common::CharEncoding > getEncodings(const std::map< std::string, std::string > &dsInfo)
It gets the encodings for the data source.
Definition: DataSource.cpp:457
unsigned int getGeomTypeId() const
It returns the type id associated to the PostGIS Geometry type.
Definition: DataSource.cpp:180
A class that implements a prepared query for PostgreSQL data access driver.