src/terralib/postgis/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 "../core/translator/Translator.h"
29 #include "../core/uri/URI.h"
30 #include "../core/uri/Utils.h"
31 #include "../dataaccess/dataset/CheckConstraint.h"
32 #include "../dataaccess/dataset/DataSet.h"
33 #include "../dataaccess/dataset/ForeignKey.h"
34 #include "../dataaccess/dataset/Index.h"
35 #include "../dataaccess/dataset/PrimaryKey.h"
36 #include "../dataaccess/dataset/Sequence.h"
37 #include "../dataaccess/dataset/UniqueKey.h"
38 #include "../dataaccess/datasource/ScopedTransaction.h"
39 #include "../dataaccess/query/Select.h"
40 #include "../dataaccess/query/SQLDialect.h"
41 #include "../dataaccess/utils/Utils.h"
42 #include "../datatype/Array.h"
43 #include "../datatype/Property.h"
44 #include "../datatype/SimpleData.h"
45 #include "../geometry/GeometryProperty.h"
46 #include "../geometry/Utils.h"
47 #include "../raster/Grid.h"
48 #include "../raster/BandProperty.h"
49 #include "../raster/RasterProperty.h"
50 #include "../geometry/Geometry.h"
51 #include "Connection.h"
52 #include "ConnectionPool.h"
53 #include "DataSource.h"
54 #include "DataSet.h"
55 #include "Exception.h"
56 #include "Globals.h"
57 #include "PreparedQuery.h"
58 #include "ScopedConnection.h"
59 #include "SQLVisitor.h"
60 #include "Transactor.h"
61 #include "Utils.h"
62 
63 // STL
64 #include <cassert>
65 #include <memory>
66 
67 // Boost
68 #include <boost/format.hpp>
69 #include <boost/lexical_cast.hpp>
70 
71 // libpq
72 #include <libpq-fe.h>
73 
74 te::pgis::DataSource::DataSource(const std::string& connInfo)
75  : te::da::DataSource(connInfo),
76  m_pool(nullptr),
77  m_geomTypeOid(0),
78  m_rasterTypeOid(0),
79  m_timeIsInteger(true)
80 {
81  m_pool = new ConnectionPool(this);
82 }
83 
85  : te::da::DataSource(uri),
86  m_pool(nullptr),
87  m_geomTypeOid(0),
88  m_rasterTypeOid(0),
89  m_timeIsInteger(true)
90 {
91  m_pool = new ConnectionPool(this);
92 }
93 
95 {
96  delete m_pool;
97 }
98 
99 std::string te::pgis::DataSource::getType() const
100 {
101  return PGIS_DRIVER_IDENTIFIER;
102 }
103 
104 std::unique_ptr<te::da::DataSourceTransactor> te::pgis::DataSource::getTransactor()
105 {
106  ScopedConnection scopedConnetion(m_pool);
107 
108  return std::unique_ptr<te::da::DataSourceTransactor>(new te::pgis::Transactor(this, scopedConnetion->m_id));
109 }
110 
112 {
113  return m_pool->getConnection();
114 }
115 
117 {
118  m_pool->release(conn);
119 }
120 
122 {
123  return m_timeIsInteger;
124 }
125 
127 {
128  m_timeIsInteger = timeIsInteger;
129 }
130 
132 {
133  // Assure we are in a closed state
134  close();
135 
136  m_pool->initialize();
137 
138  std::unique_ptr<te::da::DataSourceTransactor> t = getTransactor();
139  te::pgis::Transactor* pgt = static_cast<te::pgis::Transactor*>(t.get());
140 
141  // Find the PostGIS types
142  m_geomTypeOid = pgt->getGeomTypeId();
144 
145  // Find the PostgreSQL current schema of the connection
147 }
148 
150 {
151  m_pool->finalize();
152 }
153 
155 {
156  return m_pool->isInitialized();
157 }
158 
160 {
161  return m_pool->isValid();
162 }
163 
165 {
167 }
168 
170 {
172 }
173 
175 {
176  return m_geomTypeOid;
177 }
178 
180 {
181  return m_rasterTypeOid;
182 }
183 
184 const std::string& te::pgis::DataSource::getCurrentSchema() const
185 {
186  return m_currentSchema;
187 }
188 
190 {
191  return m_pool;
192 }
193 
194 void te::pgis::DataSource::create(const std::string& connInfo)
195 {
196  // get an auxiliary data source to create the new database
197  std::unique_ptr<DataSource> dsPGIS(new DataSource(connInfo));
198  dsPGIS->open();
199 
200  std::map<std::string, std::string> kvp = te::core::Expand(dsPGIS->getConnectionInfo().query());
201  std::map<std::string, std::string>::const_iterator it = kvp.begin();
202  std::map<std::string, std::string>::const_iterator itend = kvp.end();
203 
204  std::string dbName;
205 
206 // create a database based on the connection information
207  std::string sql = "CREATE DATABASE ";
208 
209  it = kvp.find("PG_NEWDB_NAME");
210  if (it != itend && !it->second.empty())
211  {
212  dbName = it->second;
213  sql += "\"" + it->second + "\"";
214  }
215  else
216  throw Exception(TE_TR("The database could not be created due the missing parameter: PG_NEWDB_NAME!"));
217 
218  it = kvp.find("PG_NEWDB_TEMPLATE");
219  if(it != itend && !it->second.empty())
220  sql += " TEMPLATE = " + it->second;
221 
222  it = kvp.find("PG_NEWDB_OWNER");
223  if (it != itend && !it->second.empty())
224  sql += " OWNER = " + it->second;
225 
227 
228  it = kvp.find("PG_NEWDB_TABLESPACE");
229  if (it != itend && !it->second.empty())
230  sql += " TABLESPACE = " + it->second;
231 
232  it = kvp.find("PG_NEWDB_CONN_LIMIT");
233  if (it != itend && !it->second.empty())
234  sql += " CONNECTION LIMIT = " + it->second;
235 
236  dsPGIS->execute(sql);
237 
238  dsPGIS->close();
239 
240  std::vector<std::string> tokens;
241  te::common::Tokenize(connInfo, tokens, "?");
242 
243  std::string connInfoCheck = tokens[0] + dbName;
244 
245  std::unique_ptr<DataSource> dsPGISCheck(new DataSource(connInfoCheck));
246  dsPGISCheck->open();
247 
248  std::unique_ptr<te::da::DataSet> result(dsPGISCheck->query("SELECT extname, extversion FROM pg_extension WHERE extname = 'postgis'"));
249 
250  if (!result->moveNext())
251  {
252  // no PostGIS extension found, let's try to enable it!
253  dsPGISCheck->execute("CREATE EXTENSION postgis");
254  }
255  dsPGISCheck->close();
256 
257 }
258 
259 void te::pgis::DataSource::drop(const std::string& connInfo)
260 {
261  // Get an auxiliary data source
262  std::unique_ptr<DataSource> ds(new DataSource(connInfo));
263 
264  ds->open();
265 
266  // Drop the database
267  std::string sql = "DROP DATABASE ";
268  std::map<std::string, std::string> kvp = te::core::Expand(ds->getConnectionInfo().query());
269  std::map<std::string, std::string>::const_iterator it = kvp.begin();
270  std::map<std::string, std::string>::const_iterator itend = kvp.end();
271 
272  it = kvp.find("PG_DB_TO_DROP");
273  if (it == itend || it->second.empty())
274  throw Exception(TE_TR("Could not drop the database due the missing parameter: PG_DB_TO_DROP!"));
275 
276  if((it->second == "postgres") || (it->second == "template_postgis"))
277  throw Exception(TE_TR("The database postgres or template_postgis is not allowed to be dropped!"));
278 
279  sql += it->second;
280 
281  ds->execute(sql);
282 
283  ds->close();
284 }
285 
286 bool te::pgis::DataSource::exists(const std::string& connInfo)
287 {
288  // Get an auxiliary data source
289  std::unique_ptr<DataSource> ds(new DataSource(connInfo));
290  ds->open();
291 
292  std::map<std::string, std::string> kvp = te::core::Expand(ds->getConnectionInfo().query());
293  std::map<std::string, std::string>::const_iterator it = kvp.begin();
294  std::map<std::string, std::string>::const_iterator itend = kvp.end();
295 
296  it = kvp.find("PG_CHECK_DB_EXISTENCE");
297 
298  if (it == itend || it->second.empty())
299  throw Exception(TE_TR("Could not check the PostgreSQL database existence due the missing parameter : PG_CHECK_DB_EXISTENCE!"));
300 
301  std::string sql("SELECT * FROM pg_database WHERE datname = '");
302  sql += it->second;
303  sql += "'";
304 
305  std::unique_ptr<te::da::DataSet> database(ds->query(sql));
306 
307  ds->close();
308 
309  return database->moveNext();
310 }
311 
312 std::vector<std::string> te::pgis::DataSource::getDataSourceNames(const std::string& connInfo)
313 {
314  // Get an auxiliary data source
315  std::unique_ptr<DataSource> ds(new DataSource(connInfo));
316  ds->open();
317 
318  std::string sql("SELECT datname FROM pg_database");
319 
320  std::unique_ptr<te::da::DataSet> dataset(ds->query(sql));
321 
322  std::vector<std::string> dataSourceNames;
323 
324  while(dataset->moveNext())
325  dataSourceNames.push_back(dataset->getString(0));
326 
327  ds->close();
328 
329  return dataSourceNames;
330 }
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.
void drop(const std::string &connInfo)
It removes the data source with the connection information from a driver.
ConnectionPool * m_pool
The connection pool.
bool isValid() const
It checks if all the connections in the pool are valid (the communication channel is ok)...
A visitor for building an SQL statement using PostGIS dialect.
A class that control the use of connection to a PostgreSQL database.
std::string getType() const
It returns the data source type name (in UPPER CASE). Ex: POSTGIS, SQLITE, WFS, WMS, or MYSQL.
bool isInitialized() const
It returns true if the connection pool is initialized, otherwise it returns false.
Base exception class for plugin module.
void open()
It opens the connection(s) to the PostgreSQL database server.
static te::da::DataSourceCapabilities * sm_capabilities
The query dialect supported by PostGIS driver.
std::vector< std::string > getDataSourceNames(const std::string &connInfo)
It gets the data source names available in a driver.
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.
const std::string & getCurrentSchema() const
It returns the current schema associated to the database connection, or NULL, if none is set...
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.
static te::dt::Date ds(2010, 01, 01)
A Transactor can be viewed as a connection to the data source for reading/writing things into it...
#define TE_TR(message)
It marks a string in order to get translated.
Definition: Translator.h:242
void setTimeAsInteger(bool timeIsInteger)
static te::da::SQLDialect * sm_queryDialect
The query dialect supported by PostGIS driver.
void release(Connection *conn)
It brings the informed connection back to the pool.
The transactor class for the PostGIS driver.
#define PGIS_DRIVER_IDENTIFIER
The PostGIS driver identifier string.
void Tokenize(const std::string &str, std::vector< std::string > &tokens, const std::string &delimiters=" ")
It tokenizes a given string with a delimiter of your own choice.
Definition: StringUtils.h:221
An exception class for the PostGIS driver.
static std::string getEncodingName(EncodingType et)
Retrive a string from a given character encoding type enum.
unsigned int m_rasterTypeOid
PostGIS Raster type OID.
URI C++ Library.
Definition: Attributes.h:37
void initialize()
It initializes the connections to be managed by the pool.
DataSource(const std::string &connInfo)
te::pgis::Connection * getConnection()
bool isValid() const
It checks if the data source is valid (available for using).
const te::da::SQLDialect * getDialect() const
It returns the data source SQL dialect, if there is one.
void create(const std::string &connInfo)
It creates a new data source.
A class that implements a connection to a PostgreSQL database.
bool isOpened() const
It returns true if the data source is opened, otherwise it returns false.
A class for representing an Uniform Resource Identifier (URI).
Definition: URI.h:49
void close()
It closes the data source and clears all the resources used by its internal communication channel...
A class that control the use of the connection to a PostgreSQL database.
ConnectionPool * getConnPool() const
It returns a pointer to the internal connection pool.
Connection * getConnection(int id=-1)
It returns a connection from the pool.
bool m_timeIsInteger
It indicates if the postgis stores, internally, time and timestamp as an integer. ...
This file contains utility functions used to manipulate data from a URI.
int m_id
The connection Id.
std::string m_currentSchema
The default schema used when no one is provided.
TECOREEXPORT std::map< std::string, std::string > Expand(const std::string &query_str)
Split a query string into its components.
An static class with global definitions.
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...
bool exists(const std::string &connInfo)
Check the existence of a data source in a driver.
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.
A class that implements a prepared query for PostgreSQL data access driver.
Implementation of the data source for the PostGIS driver.
void finalize()
It closes all connections and clears all resources managed by the pool.
unsigned int getGeomTypeId() const
It returns the type id associated to the PostGIS Geometry type.
std::unique_ptr< te::da::DataSourceTransactor > getTransactor()
It returns the set of parameters used to set up the access channel to the underlying repository...
unsigned int m_geomTypeOid
PostGIS Geometry type OID.