src/terralib/postgis/Transactor.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 by
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/dataaccess/postgis/Transactor.cpp
22 
23  \brief A Transactor can be viewed as a gateway for reading/writing things into the data source.
24 */
25 
26 // TerraLib
27 #include "../common/progress/TaskProgress.h"
28 #include "../common/StringUtils.h"
29 #include "../core/translator/Translator.h"
30 #include "../dataaccess/dataset/CheckConstraint.h"
31 #include "../dataaccess/dataset/DataSet.h"
32 #include "../dataaccess/dataset/ForeignKey.h"
33 #include "../dataaccess/dataset/Index.h"
34 #include "../dataaccess/dataset/ObjectIdSet.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/In.h"
40 #include "../dataaccess/query/Select.h"
41 #include "../dataaccess/query/SQLDialect.h"
42 #include "../dataaccess/utils/Utils.h"
43 #include "../datatype/Array.h"
44 #include "../datatype/Enums.h"
45 #include "../datatype/Property.h"
46 #include "../datatype/SimpleData.h"
47 #include "../geometry/GeometryProperty.h"
48 #include "../geometry/Utils.h"
49 #include "../raster/Grid.h"
50 #include "../raster/BandProperty.h"
51 #include "../raster/RasterProperty.h"
52 #include "../geometry/Geometry.h"
53 #include "ConnectedDataSet.h"
54 #include "Connection.h"
55 #include "ConnectionPool.h"
56 #include "DataSource.h"
57 #include "DataSet.h"
58 #include "Exception.h"
59 #include "Globals.h"
60 #include "PreparedQuery.h"
61 #include "ScopedConnection.h"
62 #include "SQLVisitor.h"
63 #include "Transactor.h"
64 #include "Utils.h"
65 
66 // STL
67 #include <cassert>
68 #include <memory>
69 
70 // Boost
71 #include <boost/algorithm/algorithm.hpp>
72 #include <boost/format.hpp>
73 #include <boost/uuid/random_generator.hpp>
74 #include <boost/uuid/uuid_io.hpp>
75 
76 // libpq
77 #include <libpq-fe.h>
78 
79 //tests
80 #include "../datatype/Utils.h"
81 #include "../dataaccess/dataset/ObjectId.h"
82 
83 //#include "../memory/DataSet.h"
84 //#include "../memory/DataSetItem.h"
85 //
86 //#include "../memory.h"
87 
88 //-----------------------------------------------------------------------
89 
90 
92  : m_ds(ds),
93  m_connectionId(connectionId),
94  m_fetchSize(5000),
95  m_isInTransaction(false),
96  m_getConstraints(true)
97 {
98 }
99 
101 
103 {
104  return m_ds;
105 }
106 
108 {
109  return m_ds->getConnPool()->getConnection(id);
110 }
111 
113 {
114  return m_connectionId;
115 }
116 
118 {
119  execute("BEGIN");
120  m_isInTransaction = true;
121 }
122 
124 {
125  m_isInTransaction = false;
126  execute("COMMIT");
127 }
128 
130 {
131  m_isInTransaction = false;
132  execute("ROLLBACK");
133 }
134 
136 {
137  return m_isInTransaction;
138 }
139 
140 std::unique_ptr<te::da::DataSet> te::pgis::Transactor::getDataSet(
141  const std::string& name, te::common::TraverseType /*travType*/,
142  bool isConnected, const te::common::AccessPolicy)
143 {
144  if(isConnected)
145  {
146  //connectDataSet will have its own connection
147  ScopedConnection scopedConnection(m_ds->getConnPool(), m_connectionId);
148 
149  /********************
150  * SIZE OF ALL LAYER *
151  *********************/
152  std::string sizeQuery("SELECT COUNT(*) FROM ");
153  sizeQuery += name;
154 
155  PGresult* sizeResult = scopedConnection->query(sizeQuery);
156 
157  long long int size = *((long long int*)(PQgetvalue(sizeResult, 0, 0)));
158 
159  #if TE_MACHINE_BYTE_ORDER == TE_NDR
160  te::common::SwapBytes(size);
161  #endif
162 
163 
164  /***************************
165  * A NEW CURSOR DECLARATION *
166  ****************************/
167  std::string cursor = "DECLARE ";
168 
169  boost::uuids::basic_random_generator<boost::mt19937> gen;
170  boost::uuids::uuid u = gen();
171 
172  std::string id_cursor = boost::uuids::to_string(u);
173  boost::erase_all(id_cursor, "-");
174 
175  id_cursor = "c_" + id_cursor;
176  cursor += id_cursor;
177  cursor += " CURSOR WITH HOLD FOR ";
178 
179  std::string sql("SELECT * FROM ");
180  sql += name;
181 
182  cursor += sql;
183 
184  scopedConnection->execute(cursor);
185 
186  /*************************
187  * FETCH FIRST N ELEMENTS *
188  **************************/
189  std::string fetch("FETCH FORWARD ");
190  fetch += boost::lexical_cast<std::string>(m_fetchSize);
191  fetch += " FROM ";
192  fetch += id_cursor;
193 
194  PGresult* result = scopedConnection->query(fetch);
195 
196  std::vector<int> ptypes;
197  Convert2TerraLib(result, m_ds->getGeomTypeId(), m_ds->getRasterTypeId(), ptypes);
198 
199  return std::unique_ptr<te::da::DataSet>(new ConnectedDataSet(
200  result, m_ds, m_connectionId, id_cursor, static_cast<int>(size), ptypes, m_ds->isTimeAnInteger()));
201  }
202  else
203  {
204  ScopedConnection scopedConnection(m_ds->getConnPool(), m_connectionId);
205 
206  std::unique_ptr<std::string> sql(new std::string("SELECT * FROM "));
207  *sql += name;
208 
209  PGresult* result = scopedConnection->query(*sql);
210 
211  std::vector<int> ptypes;
212  Convert2TerraLib(result, m_ds->getGeomTypeId(), m_ds->getRasterTypeId(), ptypes);
213 
214  return std::unique_ptr<te::da::DataSet>(new DataSet(result, ptypes, m_ds->isTimeAnInteger()));;
215  }
216 }
217 
218 std::unique_ptr<te::da::DataSet> te::pgis::Transactor::getDataSet(
219  const std::string& name, const std::string& propertyName,
221  te::common::TraverseType /*travType*/, bool isConnected,
223 {
224  if(e == nullptr)
225  throw Exception(TE_TR("The envelope is missing!"));
226 
227  std::unique_ptr<te::dt::Property> p = getProperty(name, propertyName);
228 
229  const te::gm::GeometryProperty* gp = static_cast<const te::gm::GeometryProperty*>(p.get());
230 
231  std::string rel = GetBoxSpatialRelation(r);
232 
233  if(isConnected)
234  {
235 
236  //connectDataSet will have its own connection
237  ScopedConnection scopedConnection(m_ds->getConnPool(), m_connectionId);
238 
239  /********************
240  * SIZE OF ALL LAYER *
241  *********************/
242  std::string sizeQuery("SELECT COUNT(*) FROM ");
243  sizeQuery += name;
244  sizeQuery += " WHERE ";
245  sizeQuery += propertyName;
246  sizeQuery += rel;
247 
248  Convert2PostGIS(e, gp->getSRID(), sizeQuery);
249 
250  PGresult* sizeResult = scopedConnection->query(sizeQuery);
251  long long int size = *((long long int*)(PQgetvalue(sizeResult, 0, 0)));
252 
253  #if TE_MACHINE_BYTE_ORDER == TE_NDR
254  te::common::SwapBytes(size);
255  #endif
256 
257 
258  /***************************
259  * A NEW CURSOR DECLARATION *
260  ****************************/
261  std::string cursor = "DECLARE ";
262 
263  boost::uuids::basic_random_generator<boost::mt19937> gen;
264  boost::uuids::uuid u = gen();
265 
266  std::string id_cursor = boost::uuids::to_string(u);
267  boost::erase_all(id_cursor, "-");
268 
269  id_cursor = "c_" + id_cursor;
270  cursor += id_cursor;
271  cursor += " CURSOR WITH HOLD FOR ";
272 
273  std::string sql("SELECT * FROM ");
274  sql += name;
275  sql += " WHERE ";
276  sql += propertyName;
277  sql += rel;
278 
279  Convert2PostGIS(e, gp->getSRID(), sql);
280 
281  cursor += sql;
282 
283  scopedConnection->execute(cursor);
284 
285  /*************************
286  * FETCH FIRST N ELEMENTS *
287  **************************/
288  std::string fetch("FETCH FORWARD ");
289  fetch += boost::lexical_cast<std::string>(m_fetchSize);
290  fetch += " FROM ";
291  fetch += id_cursor;
292 
293  PGresult* result = scopedConnection->query(fetch);
294 
295  std::vector<int> ptypes;
296  Convert2TerraLib(result, m_ds->getGeomTypeId(), m_ds->getRasterTypeId(), ptypes);
297 
298  return std::unique_ptr<te::da::DataSet>(new ConnectedDataSet(
299  result, m_ds, m_connectionId, id_cursor, static_cast<int>(size), ptypes, m_ds->isTimeAnInteger()));
300  }
301  else
302  {
303  ScopedConnection scopedConnection(m_ds->getConnPool(), m_connectionId);
304 
305  std::string sql("SELECT * FROM ");
306  sql += name;
307  sql += " WHERE ";
308  sql += propertyName;
309  sql += rel;
310 
311  Convert2PostGIS(e, gp->getSRID(), sql);
312 
313  PGresult* result = scopedConnection->query(sql);
314 
315  std::vector<int> ptypes;
316  Convert2TerraLib(result, m_ds->getGeomTypeId(), m_ds->getRasterTypeId(), ptypes);
317 
318  return std::unique_ptr<te::da::DataSet>(
319  new DataSet(result, ptypes, m_ds->isTimeAnInteger()));
320  }
321 }
322 
323 std::unique_ptr<te::da::DataSet> te::pgis::Transactor::getDataSet(
324  const std::string& name, const std::string& propertyName,
326  te::common::TraverseType /*travType*/, bool isConnected,
328 {
329  if(g == nullptr)
330  throw Exception(TE_TR("The geometry is missing!"));
331 
332  std::string rel = GetSpatialRelation(r);
333 
334  if(isConnected)
335  {
336  //connectDataSet will have its own connection
337  ScopedConnection scopedConnection(m_ds->getConnPool(), m_connectionId);
338 
339  /********************
340  * SIZE OF ALL LAYER *
341  *********************/
342  std::string sizeQuery("SELECT COUNT(*) FROM ");
343  sizeQuery += name;
344  sizeQuery += "WHERE";
345  sizeQuery += rel;
346  sizeQuery += "(";
347 
348  Convert2PostGIS(scopedConnection->m_pgconn, g, sizeQuery);
349 
350  sizeQuery += ",";
351  sizeQuery += propertyName;
352  sizeQuery += ")";
353 
354  PGresult* sizeResult = scopedConnection->query(sizeQuery);
355  long long int size = *((long long int*)(PQgetvalue(sizeResult, 0, 0)));
356 
357  #if TE_MACHINE_BYTE_ORDER == TE_NDR
358  te::common::SwapBytes(size);
359  #endif
360 
361 
362  /***************************
363  * A NEW CURSOR DECLARATION *
364  ****************************/
365  std::string cursor = "DECLARE ";
366 
367  boost::uuids::basic_random_generator<boost::mt19937> gen;
368  boost::uuids::uuid u = gen();
369 
370  std::string id_cursor = boost::uuids::to_string(u);
371  boost::erase_all(id_cursor, "-");
372 
373  id_cursor = "c_" + id_cursor;
374  cursor += id_cursor;
375  cursor += " CURSOR WITH HOLD FOR ";
376 
377  std::string sql("SELECT * FROM ");
378  sql += name;
379  sql += " WHERE ";
380  sql += rel;
381  sql += "(";
382 
383  Convert2PostGIS(scopedConnection->m_pgconn, g, sql);
384 
385  sql += ",";
386  sql += propertyName;
387  sql += ")";
388 
389  cursor += sql;
390 
391  scopedConnection->execute(cursor);
392 
393  /*************************
394  * FETCH FIRST N ELEMENTS *
395  **************************/
396  std::string fetch("FETCH FORWARD ");
397  fetch += boost::lexical_cast<std::string>(m_fetchSize);
398  fetch += " FROM ";
399  fetch += id_cursor;
400 
401  PGresult* result = scopedConnection->query(fetch);
402 
403  std::vector<int> ptypes;
404  Convert2TerraLib(result, m_ds->getGeomTypeId(), m_ds->getRasterTypeId(), ptypes);
405 
406  return std::unique_ptr<te::da::DataSet>(new ConnectedDataSet(
407  result, m_ds, m_connectionId, id_cursor, static_cast<int>(size), ptypes, m_ds->isTimeAnInteger()));
408  }
409  else
410  {
411  ScopedConnection scopedConnection(m_ds->getConnPool(), m_connectionId);
412 
413  std::string sql("SELECT * FROM ");
414  sql += name;
415  sql += " WHERE ";
416  sql += rel;
417  sql += "(";
418 
419  Convert2PostGIS(scopedConnection->m_pgconn, g, sql);
420 
421  PGresult* result = scopedConnection->query(sql);
422 
423  std::vector<int> ptypes;
424  Convert2TerraLib(result, m_ds->getGeomTypeId(), m_ds->getRasterTypeId(), ptypes);
425 
426  return std::unique_ptr<te::da::DataSet>(
427  new DataSet(result, ptypes, m_ds->isTimeAnInteger()));
428  }
429 }
430 
431 std::unique_ptr<te::da::DataSet> te::pgis::Transactor::query(const te::da::Select& q,
432  te::common::TraverseType travType,
433  bool isConnected,
434  const te::common::AccessPolicy accessPolicy)
435 {
436  ScopedConnection scopedConnection(m_ds->getConnPool(), m_connectionId);
437 
438  std::string sql;
439 
440  SQLVisitor visitor(*(m_ds->getDialect()), sql, scopedConnection->getConn());
441  q.accept(visitor);
442 
443  scopedConnection.release();
444 
445  return query(sql, travType, isConnected,accessPolicy);
446 }
447 
448 std::unique_ptr<te::da::DataSet> te::pgis::Transactor::query(
449  const std::string& query, te::common::TraverseType /*travType*/,
450  bool isConnected, const te::common::AccessPolicy)
451 {
452  if(isConnected)
453  {
454  //connectDataSet will have its own connection
455  ScopedConnection scopedConnection(m_ds->getConnPool(), m_connectionId);
456 
457  /********************
458  * SIZE OF ALL LAYER *
459  *********************/
460  std::string sizeQuery("SELECT COUNT(*) FROM ");
461  sizeQuery += "("+ query +") AS InputQuery";
462  PGresult* sizeResult = scopedConnection->query(sizeQuery);
463  long long int size = *((long long int*)(PQgetvalue(sizeResult, 0, 0)));
464 
465  #if TE_MACHINE_BYTE_ORDER == TE_NDR
466  te::common::SwapBytes(size);
467  #endif
468 
469  /***************************
470  * A NEW CURSOR DECLARATION *
471  ****************************/
472  std::string cursor = "DECLARE ";
473 
474  boost::uuids::basic_random_generator<boost::mt19937> gen;
475  boost::uuids::uuid u = gen();
476 
477  std::string id_cursor = boost::uuids::to_string(u);
478  boost::erase_all(id_cursor, "-");
479 
480  id_cursor = "c_" + id_cursor;
481  cursor += id_cursor;
482  cursor += " CURSOR WITH HOLD FOR ";
483 
484  cursor += query;
485 
486  scopedConnection->execute(cursor);
487 
488  /*************************
489  * FETCH FIRST N ELEMENTS *
490  **************************/
491  std::string fetch("FETCH FORWARD ");
492  fetch += boost::lexical_cast<std::string>(m_fetchSize);
493  fetch += " FROM ";
494  fetch += id_cursor;
495 
496  PGresult* result = scopedConnection->query(fetch);
497 
498  std::vector<int> ptypes;
499  Convert2TerraLib(result, m_ds->getGeomTypeId(), m_ds->getRasterTypeId(), ptypes);
500 
501  return std::unique_ptr<te::da::DataSet>(new ConnectedDataSet(
502  result, m_ds, m_connectionId, id_cursor, static_cast<int>(size), ptypes, m_ds->isTimeAnInteger()));
503  }
504  else
505  {
506  ScopedConnection scopedConnection(m_ds->getConnPool(), m_connectionId);
507 
508  PGresult* result = scopedConnection->query(query);
509 
510  std::vector<int> ptypes;
511  Convert2TerraLib(result, m_ds->getGeomTypeId(), m_ds->getRasterTypeId(), ptypes);
512 
513  return std::unique_ptr<te::da::DataSet>(new DataSet(result, ptypes, m_ds->isTimeAnInteger()));
514  }
515 }
516 
518 {
519  ScopedConnection scopedConnection(m_ds->getConnPool(), m_connectionId);
520 
521  std::string sql;
522 
523  SQLVisitor visitor(*(m_ds->getDialect()), sql, scopedConnection->getConn());
524  command.accept(visitor);
525 
526  execute(sql);
527 }
528 
529 void te::pgis::Transactor::execute(const std::string& command)
530 {
531  ScopedConnection scopedConnection(m_ds->getConnPool(), m_connectionId);
532  scopedConnection->execute(command);
533 }
534 
535 std::unique_ptr<te::da::PreparedQuery> te::pgis::Transactor::getPrepared(const std::string& qName)
536 {
537  return std::unique_ptr<te::da::PreparedQuery>(new PreparedQuery(this, qName));
538 }
539 
540 std::unique_ptr<te::da::BatchExecutor> te::pgis::Transactor::getBatchExecutor()
541 {
542  return std::unique_ptr<te::da::BatchExecutor>(nullptr);
543 }
544 
546 {
547 }
548 
550 {
551  std::string sql("SELECT lastval()");
552 
553  std::unique_ptr<te::da::DataSet> dataset = query(sql);
554 
555  if (dataset->size() != 1)
556  throw Exception(TE_TR("Error getting last generated id."));
557 
558  dataset->moveFirst();
559 
560  boost::int64_t value = dataset->getInt64(0);
561 
562  return value;
563 }
564 
565 std::string te::pgis::Transactor::escape(const std::string& value)
566 {
567  return value;
568 }
569 
570 std::vector<std::string> te::pgis::Transactor::getDataSetNames()
571 {
572  std::vector<std::string> datasetNames;
573 
574  std::string sql("SELECT pg_class.oid, pg_namespace.nspname, pg_class.relname, pg_class.relkind "
575  "FROM pg_class, pg_namespace "
576  "WHERE pg_class.relname !~ '^pg_' "
577  "AND pg_class.relname NOT IN ('spatial_ref_sys', 'geometry_columns', 'geography_columns', 'raster_columns', 'raster_overviews') "
578  "AND pg_class.relkind in ('r','v') "
579  "AND pg_class.relnamespace = pg_namespace.oid "
580  "AND pg_namespace.nspname NOT IN ('information_schema', 'pg_toast', 'pg_temp_1', 'pg_catalog', 'topology') "
581  "ORDER BY pg_class.relname"
582  );
583 
584  std::unique_ptr<te::da::DataSet> datasetInfo = query(sql);
585 
586  while(datasetInfo->moveNext())
587  {
588  std::string datasetName = std::string(datasetInfo->getString(1) + "." + datasetInfo->getString(2));
589  datasetNames.push_back(datasetName);
590  }
591 
592  return datasetNames;
593 }
594 
596 {
597  return getDataSetNames().size();
598 }
599 
600 std::unique_ptr<te::da::DataSetType> te::pgis::Transactor::getDataSetType(const std::string& name)
601 {
602  std::string datasetName = getFullName(name);
603 
604  // Find the dataset id
605  unsigned int dtid = getDataSetId(datasetName);
606 
607  // Create the dataset type
608  te::da::DataSetType* dt = new te::da::DataSetType(datasetName, dtid);
609  dt->setTitle(datasetName);
610 
611  // Get the properties of the dataset and add them to its schema
612  boost::ptr_vector<te::dt::Property> properties = getProperties(datasetName);
613  for(std::size_t i = 0; i < properties.size(); ++i)
614  {
615  te::dt::Property* p = properties[i].clone();
616  dt->add(p);
617  }
618 
619  // Get all the constraints of the dataset and load them to its schema
620  if (m_getConstraints)
621  getConstraints(dt);
622 
623  // Get the indexes of the dataset and add them to its schema
624  getIndexes(dt);
625 
626  return std::unique_ptr<te::da::DataSetType>(dt);
627 }
628 
629 boost::ptr_vector<te::dt::Property> te::pgis::Transactor::getProperties(const std::string& datasetName)
630 {
631  std::string fullDatasetName = getFullName(datasetName);
632 
633  boost::ptr_vector<te::dt::Property> properties;
634 
635  std::unique_ptr<te::da::DataSet> pInfo = getPropertiesInfo(fullDatasetName);
636 
637  while(pInfo->moveNext())
638  {
639  unsigned int attNum = pInfo->getInt16(0);
640  std::string attName = pInfo->getString(1);
641  unsigned int attType = pInfo->getInt32(2);
642  bool attNotNull = pInfo->getBool(3);
643  std::string fmt = pInfo->getString(4);
644  bool attHasDefault = pInfo->getBool(5);
645  std::string attDefValue = pInfo->getString(6);
646  int ndims = pInfo->getInt32(7);
647 
648  te::dt::Property* p = Convert2TerraLib(attNum, attName.c_str(), attType, attNotNull,
649  fmt.c_str(), attHasDefault, attDefValue.c_str(),
650  ndims, m_ds->getGeomTypeId(), m_ds->getRasterTypeId());
651 
652  properties.push_back(p);
653 
654  if(p->getType() == te::dt::GEOMETRY_TYPE)
655  {
656  getGeometryInfo(datasetName, static_cast<te::gm::GeometryProperty*>(p));
657  }
658  else if(p->getType() == te::dt::RASTER_TYPE)
659  {
660  getRasterInfo(datasetName, static_cast<te::rst::RasterProperty*>(p));
661  }
662  }
663 
664  return properties;
665 }
666 
667 std::unique_ptr<te::dt::Property> te::pgis::Transactor::getProperty(const std::string& datasetName, const std::string& name)
668 {
669  std::string fullDatasetName = getFullName(datasetName);
670 
671  te::dt::Property* p = nullptr;
672 
673  std::string pName = name;
674 
675  // If the property name contains also the dataset name, strip it from the name.
676  std::size_t pos = pName.find_last_of(".");
677  if(pos != std::string::npos)
678  pName = pName.substr(++pos);
679 
680  std::unique_ptr<te::da::DataSet> pInfo = getPropertiesInfo(fullDatasetName);
681  while(pInfo->moveNext())
682  {
683  std::string attName = pInfo->getString(1);
684  if(attName != pName)
685  continue;
686 
687  unsigned int attNum = pInfo->getInt16(0);
688  unsigned int attType = pInfo->getInt32(2);
689  bool attNotNull = pInfo->getBool(3);
690  std::string fmt = pInfo->getString(4);
691  bool attHasDefault = pInfo->getBool(5);
692  std::string attDefValue = pInfo->getString(6);
693  int ndims = pInfo->getInt32(7);
694 
695  p = Convert2TerraLib(attNum, attName.c_str(), attType, attNotNull,
696  fmt.c_str(), attHasDefault, attDefValue.c_str(),
697  ndims, m_ds->getGeomTypeId(), m_ds->getRasterTypeId());
698 
699  if(p->getType() == te::dt::GEOMETRY_TYPE)
700  {
701  getGeometryInfo(datasetName, static_cast<te::gm::GeometryProperty*>(p));
702  }
703  else if(p->getType() == te::dt::RASTER_TYPE)
704  {
705  getRasterInfo(datasetName, static_cast<te::rst::RasterProperty*>(p));
706  }
707  }
708 
709  return std::unique_ptr<te::dt::Property>(p);
710 }
711 
712 std::unique_ptr<te::dt::Property> te::pgis::Transactor::getProperty(const std::string& datasetName, std::size_t propertyPos)
713 {
714  std::string fullDatasetName = getFullName(datasetName);
715 
716  boost::ptr_vector<te::dt::Property> properties = getProperties(fullDatasetName);
717 
718  assert(propertyPos < properties.size());
719 
720  return std::unique_ptr<te::dt::Property>(properties[propertyPos].clone());
721 }
722 
723 std::vector<std::string> te::pgis::Transactor::getPropertyNames(const std::string& datasetName)
724 {
725  std::string fullDatasetName = getFullName(datasetName);
726 
727  boost::ptr_vector<te::dt::Property> properties = getProperties(fullDatasetName);
728 
729  std::size_t numProperties = properties.size();
730 
731  std::vector<std::string> pNames(numProperties);
732 
733  for(std::size_t i = 0; i < numProperties; ++i)
734  pNames[i] = properties[i].getName();
735 
736  return pNames;
737 }
738 
739 std::size_t te::pgis::Transactor::getNumberOfProperties(const std::string& datasetName)
740 {
741  std::string fullDatasetName = getFullName(datasetName);
742  return getProperties(fullDatasetName).size();
743 }
744 
745 bool te::pgis::Transactor::propertyExists(const std::string& datasetName, const std::string& name)
746 {
747  std::string fullDatasetName = getFullName(datasetName);
748 
749  std::vector<std::string> pNames = getPropertyNames(fullDatasetName);
750 
751  if(std::find(pNames.begin(), pNames.end(), name) != pNames.end())
752  return true;
753 
754  return false;
755 }
756 
757 void te::pgis::Transactor::addProperty(const std::string& datasetName, te::dt::Property* p)
758 {
759  std::string fullDatasetName = getFullName(datasetName);
760 
761  std::string pName = p->getName();
762 
763  // Persist the property in the database
764  std::string sql;
765 
766  if(p->getType() == te::dt::GEOMETRY_TYPE)
767  {
769 
770  sql = "SELECT AddGeometryColumn('";
771 
772  // split schema-name.table-name
773  std::size_t pos = fullDatasetName.find(".");
774 
775  if(pos == std::string::npos)
776  {
777  sql += te::common::Convert2LCase(fullDatasetName);
778  sql += "', '";
779  }
780  else
781  {
782  sql += te::common::Convert2LCase(fullDatasetName.substr(0, pos));
783  sql += "', '";
784  sql += te::common::Convert2LCase(fullDatasetName.substr(pos + 1));
785  sql += "', '";
786  }
787 
788  sql += te::common::Convert2LCase(gp->getName());
789  sql += "', ";
790 
791  int srid = gp->getSRID();
792  if(srid <= TE_UNKNOWN_SRS)
793  srid = PGIS_UNKNOWN_SRS;
794 
795  sql += te::common::Convert2String(srid);
796 
797  sql += ", '";
799  sql += "', ";
801  sql += ")";
802  }
803  else
804  {
805  sql = "ALTER TABLE ";
806  sql += fullDatasetName;
807  sql += " ADD COLUMN ";
808  sql += pName;
809  sql += " ";
810 
811  SetColumnDef(sql, p);
812  }
813 
814  execute(sql);
815 }
816 
817 void te::pgis::Transactor::dropProperty(const std::string& datasetName, const std::string& name)
818 {
819  std::string fullDatasetName = getFullName(datasetName);
820 
821  std::unique_ptr<te::dt::Property> p = getProperty(fullDatasetName, name);
822 
823  std::string sql;
824 
825  if(p->getType() == te::dt::GEOMETRY_TYPE)
826  {
827  sql = "SELECT DropGeometryColumn('";
828 
829  // Split schema-name.table-name, if needed
830  std::size_t pos = fullDatasetName.find(".");
831 
832  if(pos == std::string::npos)
833  {
834  sql += m_ds->getCurrentSchema();
835  sql += "', '";
836  sql += te::common::Convert2LCase(fullDatasetName);
837  }
838  else
839  {
840  sql += te::common::Convert2LCase(fullDatasetName.substr(0, pos));
841  sql += "', '";
842  sql += te::common::Convert2LCase(fullDatasetName.substr(pos + 1));
843  }
844 
845  sql += "', '";
846  sql += te::common::Convert2LCase(name) + "'";
847  sql += ")";
848  }
849  else
850  {
851  sql = " ALTER TABLE ";
852  sql += fullDatasetName;
853  sql += " DROP COLUMN ";
854  sql += name;
855  }
856 
857  execute(sql);
858 }
859 
860 void te::pgis::Transactor::renameProperty(const std::string& datasetName,
861  const std::string& name,
862  const std::string& newName)
863 {
864  std::string fullDatasetName = getFullName(datasetName);
865 
866  std::unique_ptr<te::dt::Property> p = getProperty(fullDatasetName, name);
867 
868  std::string sql("ALTER TABLE ");
869  sql += fullDatasetName;
870  sql += " RENAME COLUMN ";
871  sql += name + " TO ";
872  sql += newName;
873 
874  execute(sql);
875 
876  if(p->getType() == te::dt::GEOMETRY_TYPE)
877  {
878  sql = "UPDATE geometry_columns SET f_geometry_column = '" + newName + "'";
879  sql += " WHERE f_table_name = '" ;
880 
881  // Split schema-name.table-name
882  std::size_t pos = fullDatasetName.find(".");
883 
884  if(pos == std::string::npos)
885  {
886  sql += fullDatasetName;
887  sql += "' AND f_table_schema ='";
888  sql += m_ds->getCurrentSchema();
889  sql += "'";
890  }
891  else
892  {
893  sql += fullDatasetName.substr(pos + 1);
894  sql += "' AND f_table_schema ='";
895  sql += fullDatasetName.substr(0, pos);
896  sql += "'";
897  }
898 
899  sql += " AND f_geometry_column = '" + name + "'";
900 
901  execute(sql);
902  }
903 }
904 
905 void te::pgis::Transactor::changePropertyDefinition(const std::string& datasetName, const std::string& propName, te::dt::Property* newProp)
906 {
907  std::unique_ptr<te::dt::Property> prp(newProp);
908  std::string type;
909 
910  if(prp->getType() == te::dt::DOUBLE_TYPE)
911  type = "NUMERIC USING " + propName+ "::numeric";
912 
913  if(type.empty())
914  SetColumnDef(type, prp.get());
915 
916  std::string sql("ALTER TABLE ");
917  sql += datasetName + " ALTER COLUMN " + propName + " TYPE " + type;
918 
919  execute(sql);
920 }
921 
923 {
924  return te::pgis::GetGeometryName(type);
925 }
926 
927 
928 std::unique_ptr<te::da::PrimaryKey> te::pgis::Transactor::getPrimaryKey(const std::string& datasetName)
929 {
930  std::string fullDatasetName = getFullName(datasetName);
931 
932  te::da::PrimaryKey* pk = nullptr;
933 
934  std::unique_ptr<te::da::DataSet> pkInfo = getConstraints(fullDatasetName, 'p');
935 
936  while(pkInfo->moveNext())
937  {
938  unsigned int pkId = pkInfo->getInt32(0);
939  std::string pkName = pkInfo->getString(2);
940 
941  pk = new te::da::PrimaryKey(pkName, nullptr, pkId);
942 
943  std::unique_ptr<te::dt::Array> pkCols(pkInfo->getArray(8));
944  std::size_t size = pkCols->getDimensionSize(0);
945 
946  std::vector<std::size_t> pos;
947  pos.push_back(0);
948  for(std::size_t i = 0; i < size; ++i)
949  {
950  pos[0] = i;
951 
952  te::dt::AbstractData* pkCol = pkCols->getData(pos);
953 
954  std::unique_ptr<te::dt::Property> p = getProperty(static_cast<te::dt::Int16*>(pkCol)->getValue(), fullDatasetName);
955  pk->add(p.release());
956  }
957  }
958 
959  // Try to link the pk to an index
960  std::vector<std::string> idxNames = getIndexNames(fullDatasetName);
961 
962  for(std::size_t i = 0; i < idxNames.size(); ++i)
963  {
964  if(pk && pk->getName() == idxNames[i])
965  {
966  pk->setAssociatedIndex(getIndex(fullDatasetName, idxNames[i]).get());
967  break;
968  }
969  }
970 
971  return std::unique_ptr<te::da::PrimaryKey>(pk);
972 }
973 
974 bool te::pgis::Transactor::primaryKeyExists(const std::string& datasetName, const std::string& name)
975 {
976  std::string fullDatasetName = getFullName(datasetName);
977 
978  std::unique_ptr<te::da::PrimaryKey> pk = getPrimaryKey(fullDatasetName);
979 
980  if(pk->getName() == name)
981  return true;
982 
983  return false;
984 }
985 
986 void te::pgis::Transactor::addPrimaryKey(const std::string& datasetName, te::da::PrimaryKey* pk)
987 {
988  std::string fullDatasetName = getFullName(datasetName);
989 
990  // Check if there is a primary key in the dataset
991  // If true, drop it from the dataset
992  if(getPrimaryKey(fullDatasetName).get() != nullptr)
993  dropPrimaryKey(fullDatasetName);
994 
995  std::string pkName;
996 
997  if(pk->getName().empty())
998  {
999  pkName = fullDatasetName + "_pk";
1000 
1001  boost::replace_all(pkName, ".", "_");
1002 
1003  pk->setName(pkName);
1004  }
1005 
1006  pkName = pk->getName();
1007 
1008  std::string sql("ALTER TABLE ");
1009  sql += fullDatasetName;
1010  sql += " ADD CONSTRAINT ";
1011  sql += pkName;
1012  sql += " PRIMARY KEY (";
1013 
1014  const std::vector<te::dt::Property*>& properties = pk->getProperties();
1015 
1016  std::size_t size = properties.size();
1017 
1018  for(std::size_t i = 0; i < size; ++i)
1019  {
1020  if(i != 0)
1021  sql += ", ";
1022 
1023  sql += properties[i]->getName();
1024  }
1025 
1026  sql += ")";
1027 
1028  execute(sql);
1029 }
1030 
1031 void te::pgis::Transactor::dropPrimaryKey(const std::string& datasetName)
1032 {
1033  std::string fullDatasetName = getFullName(datasetName);
1034 
1035  std::unique_ptr<te::da::PrimaryKey> pk = getPrimaryKey(fullDatasetName);
1036 
1037  std::string pkName = pk->getName();
1038 
1039  std::string sql("ALTER TABLE ");
1040  sql += fullDatasetName;
1041  sql += " DROP CONSTRAINT " + pkName;
1042 
1043  execute(sql);
1044 }
1045 
1046 std::unique_ptr<te::da::ForeignKey> te::pgis::Transactor::getForeignKey(const std::string& datasetName, const std::string& name)
1047 {
1048  std::string fullDatasetName = getFullName(datasetName);
1049 
1050  te::da::ForeignKey* fk = nullptr;
1051 
1052  std::unique_ptr<te::da::DataSet> fkInfo = getConstraints(fullDatasetName, 'f');
1053 
1054  while(fkInfo->moveNext())
1055  {
1056  std::string fkName = fkInfo->getString(2);
1057 
1058  if(fkName != name)
1059  continue;
1060 
1061  unsigned int fkId = fkInfo->getInt32(0);
1062  unsigned int refDatasetId = fkInfo->getInt32(4);
1063  char onUpdate = fkInfo->getChar(5);
1064  char onDeletion = fkInfo->getChar(6);
1065 
1066  std::unique_ptr<te::dt::Array> fkCols(fkInfo->getArray(8));
1067  std::unique_ptr<te::dt::Array> fkRefCols(fkInfo->getArray(9));
1068 
1069  assert(fkCols->getDimension() == 1);
1070  assert(fkCols->getDimension() == fkRefCols->getDimension());
1071  assert(fkCols->getDimensionSize(0) == fkRefCols->getDimensionSize(0));
1072 
1073  std::string refName = getDataSetName(refDatasetId);
1074  std::unique_ptr<te::da::DataSetType> refdt = getDataSetType(refName);
1075 
1076  fk = new te::da::ForeignKey(fkName, fkId);
1077  fk->setOnUpdateAction(GetAction(onUpdate));
1078  fk->setOnDeleteAction(GetAction(onDeletion));
1079  fk->setReferencedDataSetType(refdt.get());
1080 
1081  std::size_t size = fkCols->getDimensionSize(0);
1082 
1083  std::vector<std::size_t> pos;
1084  pos.push_back(0);
1085 
1086  for(std::size_t i = 0; i < size; ++i)
1087  {
1088  pos[0] = i;
1089 
1090  te::dt::AbstractData* fkRefCol = fkRefCols->getData(pos);
1091  fk->addRefProperty(refdt->getPropertyById(static_cast<te::dt::Int16*>(fkRefCol)->getValue()));
1092 
1093  te::dt::AbstractData* fkCol = fkCols->getData(pos);
1094  fk->add(getProperty(static_cast<te::dt::Int16*>(fkCol)->getValue(), datasetName).release());
1095  }
1096  }
1097 
1098  return std::unique_ptr<te::da::ForeignKey>(fk);
1099 }
1100 
1101 std::vector<std::string> te::pgis::Transactor::getForeignKeyNames(const std::string& datasetName)
1102 {
1103  std::string fullDatasetName = getFullName(datasetName);
1104 
1105  std::vector<std::string> fkNames;
1106 
1107  std::unique_ptr<te::da::DataSet> fkInfo = getConstraints(fullDatasetName, 'f');
1108 
1109  while(fkInfo->moveNext())
1110  {
1111  std::string fkName = fkInfo->getString(2);
1112  fkNames.push_back(fkName);
1113  }
1114 
1115  return fkNames;
1116 }
1117 
1118 bool te::pgis::Transactor::foreignKeyExists(const std::string& datasetName, const std::string& name)
1119 {
1120  std::string fullDatasetName = getFullName(datasetName);
1121 
1122  std::vector<std::string> fkNames = getForeignKeyNames(fullDatasetName);
1123  if(std::find(fkNames.begin(), fkNames.end(), name) != fkNames.end())
1124  return true;
1125 
1126  return false;
1127 }
1128 
1129 void te::pgis::Transactor::addForeignKey(const std::string& datasetName, te::da::ForeignKey* fk)
1130 {
1131  std::string fullDatasetName = getFullName(datasetName);
1132 
1133  std::string fkName = fk->getName();
1134 
1135  std::string sql("ALTER TABLE ");
1136  sql += fullDatasetName;
1137  sql += " ADD CONSTRAINT ";
1138  sql += fkName;
1139  sql += " FOREIGN KEY (";
1140 
1141  std::size_t size = fk->getProperties().size();
1142 
1143  for(std::size_t i = 0; i < size; ++i)
1144  {
1145  if(i != 0)
1146  sql += ", ";
1147 
1148  sql += fk->getProperties()[i]->getName();
1149  }
1150 
1151  sql += ") REFERENCES " + fk->getReferencedDataSetType()->getName() + " (";
1152 
1153  size = fk->getReferencedProperties().size();
1154 
1155  for(size_t i = 0; i < size; ++i)
1156  {
1157  if(i != 0)
1158  sql += ", ";
1159 
1160  sql += fk->getReferencedProperties()[i]->getName();
1161  }
1162 
1163  sql += ") ON DELETE ";
1164 
1165  switch(fk->getOnDeleteAction())
1166  {
1167  case te::da::NO_ACTION:
1168  sql += " NO ACTION ";
1169  break;
1170 
1171  case te::da::RESTRICT:
1172  sql += " RESTRICT ";
1173  break;
1174 
1175  case te::da::CASCADE:
1176  sql += " CASCADE ";
1177  break;
1178 
1179  case te::da::SET_NULL:
1180  sql += "SET NULL ";
1181  break;
1182 
1183  case te::da::SET_DEFAULT:
1184  default:
1185  sql += "SET DEFAULT ";
1186  break;
1187  }
1188 
1189  sql += " ON UPDATE ";
1190 
1191  switch(fk->getOnUpdateAction())
1192  {
1193  case te::da::NO_ACTION:
1194  sql += " NO ACTION ";
1195  break;
1196 
1197  case te::da::RESTRICT:
1198  sql += " RESTRICT ";
1199  break;
1200 
1201  case te::da::CASCADE:
1202  sql += " CASCADE ";
1203  break;
1204 
1205  case te::da::SET_NULL:
1206  sql += "SET NULL ";
1207  break;
1208 
1209  case te::da::SET_DEFAULT:
1210  default:
1211  sql += "SET DEFAULT ";
1212  break;
1213  }
1214 
1215  execute(sql);
1216 }
1217 
1218 void te::pgis::Transactor::dropForeignKey(const std::string& datasetName, const std::string& name)
1219 {
1220  std::string fullDatasetName = getFullName(datasetName);
1221 
1222  std::string sql("ALTER TABLE ");
1223  sql += fullDatasetName;
1224  sql += " DROP CONSTRAINT ";
1225  sql += name;
1226 
1227  execute(sql);
1228 }
1229 
1230 std::unique_ptr<te::da::UniqueKey> te::pgis::Transactor::getUniqueKey(const std::string& datasetName, const std::string& name)
1231 {
1232  std::string fullDatasetName = getFullName(datasetName);
1233 
1234  te::da::UniqueKey* uk = nullptr;
1235 
1236  std::unique_ptr<te::da::DataSet> ukInfo = getConstraints(fullDatasetName, 'u');
1237 
1238  while(ukInfo->moveNext())
1239  {
1240  std::string ukName = ukInfo->getString(2);
1241 
1242  if(ukName != name)
1243  continue;
1244 
1245  unsigned int ukId = ukInfo->getInt32(0);
1246 
1247  std::unique_ptr<te::dt::Array> ukCols(ukInfo->getArray(8));
1248 
1249  uk = new te::da::UniqueKey(ukName, nullptr, ukId);
1250 
1251  std::size_t size = ukCols->getDimensionSize(0);
1252 
1253  std::vector<std::size_t> pos;
1254  pos.push_back(0);
1255 
1256  for(std::size_t i = 0; i < size; ++i)
1257  {
1258  pos[0] = i;
1259 
1260  te::dt::AbstractData* ukCol = ukCols->getData(pos);
1261 
1262  std::unique_ptr<te::dt::Property> p = getProperty(static_cast<te::dt::Int16*>(ukCol)->getValue(), fullDatasetName);
1263 
1264  uk->add(p.release());
1265  }
1266  }
1267 
1268  // Try to link the uk to an index
1269  std::vector<std::string> idxNames = getIndexNames(fullDatasetName);
1270 
1271  for(std::size_t i = 0; i < idxNames.size(); ++i)
1272  {
1273  if(uk->getName() == idxNames[i])
1274  {
1275  uk->setAssociatedIndex(getIndex(fullDatasetName, idxNames[i]).get());
1276  break;
1277  }
1278  }
1279 
1280  return std::unique_ptr<te::da::UniqueKey>(uk);
1281 }
1282 
1283 std::vector<std::string> te::pgis::Transactor::getUniqueKeyNames(const std::string& datasetName)
1284 {
1285  std::string fullDatasetName = getFullName(datasetName);
1286 
1287  std::vector<std::string> ukNames;
1288 
1289  std::unique_ptr<te::da::DataSet> ukInfo = getConstraints(fullDatasetName, 'u');
1290 
1291  while(ukInfo->moveNext())
1292  {
1293  std::string ukName = ukInfo->getString(2);
1294  ukNames.push_back(ukName);
1295  }
1296 
1297  return ukNames;
1298 }
1299 
1300 bool te::pgis::Transactor::uniqueKeyExists(const std::string& datasetName, const std::string& name)
1301 {
1302  std::string fullDatasetName = getFullName(datasetName);
1303 
1304  std::vector<std::string> ukNames = getUniqueKeyNames(fullDatasetName);
1305 
1306  if(std::find(ukNames.begin(), ukNames.end(), name) != ukNames.end())
1307  return true;
1308 
1309  return false;
1310 }
1311 
1312 void te::pgis::Transactor::addUniqueKey(const std::string& datasetName, te::da::UniqueKey* uk)
1313 {
1314  std::string fullDatasetName = getFullName(datasetName);
1315 
1316  std::string ukName = uk->getName();
1317 
1318  std::string sql("ALTER TABLE ");
1319  sql += fullDatasetName;
1320  sql += " ADD CONSTRAINT ";
1321  sql += ukName;
1322  sql += " UNIQUE (";
1323 
1324  const std::vector<te::dt::Property*>& properties = uk->getProperties();
1325 
1326  std::size_t size = properties.size();
1327 
1328  for(std::size_t i = 0; i < size; ++i)
1329  {
1330  if(i != 0)
1331  sql += ", ";
1332 
1333  sql += properties[i]->getName();
1334  }
1335 
1336  sql += ")";
1337 
1338  execute(sql);
1339 }
1340 
1341 void te::pgis::Transactor::dropUniqueKey(const std::string& datasetName, const std::string& name)
1342 {
1343  std::string fullDatasetName = getFullName(datasetName);
1344 
1345  std::string sql("ALTER TABLE ");
1346  sql += fullDatasetName;
1347  sql += " DROP CONSTRAINT ";
1348  sql += name;
1349 
1350  execute(sql);
1351 
1352  // Remove the index associated to the unique key
1353  if(indexExists(fullDatasetName, name))
1354  dropIndex(fullDatasetName, name);
1355 }
1356 
1357 std::unique_ptr<te::da::CheckConstraint> te::pgis::Transactor::getCheckConstraint(const std::string& datasetName, const std::string& name)
1358 {
1359  std::string fullDatasetName = getFullName(datasetName);
1360 
1361  te::da::CheckConstraint* cc = nullptr;
1362 
1363  std::unique_ptr<te::da::DataSet> ccInfo = getConstraints(datasetName, 'c');
1364 
1365  while(ccInfo->moveNext())
1366  {
1367  std::string ccName = ccInfo->getString(2);
1368 
1369  if(ccName != name)
1370  continue;
1371 
1372  unsigned int ccId = ccInfo->getInt32(0);
1373 
1374  cc = new te::da::CheckConstraint(ccName);
1375  cc->setId(ccId);
1376  cc->setExpression(ccInfo->getString(10));
1377  }
1378 
1379  return std::unique_ptr<te::da::CheckConstraint>(cc);
1380 }
1381 
1382 std::vector<std::string> te::pgis::Transactor::getCheckConstraintNames(const std::string& datasetName)
1383 {
1384  std::string fullDatasetName = getFullName(datasetName);
1385 
1386  std::vector<std::string> ccNames;
1387 
1388  std::unique_ptr<te::da::DataSet> ccInfo = getConstraints(fullDatasetName, 'c');
1389 
1390  while(ccInfo->moveNext())
1391  {
1392  std::string ccName = ccInfo->getString(2);
1393 
1394  ccNames.push_back(ccName);
1395  }
1396 
1397  return ccNames;
1398 }
1399 
1400 bool te::pgis::Transactor::checkConstraintExists(const std::string& datasetName, const std::string& name)
1401 {
1402  std::string fullDatasetName = getFullName(datasetName);
1403 
1404  std::vector<std::string> ccNames = getCheckConstraintNames(fullDatasetName);
1405 
1406  if(std::find(ccNames.begin(), ccNames.end(), name) != ccNames.end())
1407  return true;
1408 
1409  return false;
1410 }
1411 
1413 {
1414  std::string fullDatasetName = getFullName(datasetName);
1415 
1416  std::string ccName = cc->getName();
1417 
1418  std::string sql("ALTER TABLE ");
1419  sql += fullDatasetName;
1420  sql += " ADD CONSTRAINT ";
1421  sql += ccName;
1422  sql += " CHECK(";
1423  sql += cc->getExpression();
1424  sql += ")";
1425 
1426  execute(sql);
1427 }
1428 
1429 void te::pgis::Transactor::dropCheckConstraint(const std::string& datasetName, const std::string& name)
1430 {
1431  std::string fullDatasetName = getFullName(datasetName);
1432 
1433  std::string sql("ALTER TABLE ");
1434  sql += fullDatasetName;
1435  sql += " DROP CONSTRAINT ";
1436  sql += name;
1437 
1438  execute(sql);
1439 }
1440 
1441 std::unique_ptr<te::da::Index> te::pgis::Transactor::getIndex(const std::string& datasetName, const std::string& name)
1442 {
1443  std::string fullDatasetName = getFullName(datasetName);
1444 
1445  te::da::Index* idx = nullptr;
1446 
1447  unsigned int dtid = getDataSetId(fullDatasetName);
1448 
1449  std::string sql("SELECT idx_table.oid, s.nspname, idx_table.relname, pg_index.indkey, pg_am.amname, pg_index.indisunique, pg_index.indisprimary "
1450  "FROM pg_index, pg_class idx_table, pg_am, pg_namespace s "
1451  "WHERE s.oid = idx_table.relnamespace "
1452  "AND pg_index.indexrelid = idx_table.oid "
1453  "AND idx_table.relam = pg_am.oid "
1454  "AND pg_index.indrelid = ");
1455  sql += te::common::Convert2String(dtid);
1456 
1457  std::unique_ptr<te::da::DataSet> idxInfo = query(sql);
1458 
1459  while(idxInfo->moveNext())
1460  {
1461  std::string idxName = idxInfo->getString(2);
1462 
1463  if(idxName != name)
1464  continue;
1465 
1466  unsigned int idxId = idxInfo->getInt32(0);
1467 
1468  std::unique_ptr<te::dt::Array> idxCols(idxInfo->getArray(3));
1469 
1470  std::string idxType = idxInfo->getString(4);
1471 
1472  idx = new te::da::Index(idxName, GetIndexType(idxType.c_str()), nullptr, idxId);
1473 
1474  std::size_t size = idxCols->getDimensionSize(0);
1475 
1476  std::vector<std::size_t> pos;
1477  pos.push_back(0);
1478 
1479  for(std::size_t i = 0; i < size; ++i)
1480  {
1481  pos[0] = i;
1482  te::dt::AbstractData* idxCol = idxCols->getData(pos);
1483 
1484  std::unique_ptr<te::dt::Property> p = getProperty(static_cast<te::dt::Int16*>(idxCol)->getValue(), fullDatasetName);
1485 
1486  idx->add(p.release());
1487  }
1488  }
1489 
1490  return std::unique_ptr<te::da::Index>(idx);
1491 }
1492 
1493 std::vector<std::string> te::pgis::Transactor::getIndexNames(const std::string& datasetName)
1494 {
1495  std::string fullDatasetName = getFullName(datasetName);
1496 
1497  std::vector<std::string> idxNames;
1498 
1499  unsigned int dtid = getDataSetId(fullDatasetName);
1500 
1501  std::string sql("SELECT idx_table.oid, s.nspname, idx_table.relname, pg_index.indkey, pg_am.amname, pg_index.indisunique, pg_index.indisprimary "
1502  "FROM pg_index, pg_class idx_table, pg_am, pg_namespace s "
1503  "WHERE s.oid = idx_table.relnamespace "
1504  "AND pg_index.indexrelid = idx_table.oid "
1505  "AND idx_table.relam = pg_am.oid "
1506  "AND pg_index.indrelid = ");
1507  sql += te::common::Convert2String(dtid);
1508 
1509  std::unique_ptr<te::da::DataSet> idxInfo = query(sql);
1510 
1511  while(idxInfo->moveNext())
1512  {
1513  std::string idxName = idxInfo->getString(2);
1514 
1515  idxNames.push_back(idxName);
1516  }
1517 
1518  return idxNames;
1519 }
1520 
1521 bool te::pgis::Transactor::indexExists(const std::string& datasetName, const std::string& name)
1522 {
1523  std::string fullDatasetName = getFullName(datasetName);
1524 
1525  std::vector<std::string> idxNames = getIndexNames(fullDatasetName);
1526 
1527  if(std::find(idxNames.begin(), idxNames.end(), name) != idxNames.end())
1528  return true;
1529 
1530  return false;
1531 }
1532 
1534  const std::string& datasetName, te::da::Index* idx,
1535  const std::map<std::string, std::string>& /*options*/)
1536 {
1537  std::string fullDatasetName = getFullName(datasetName);
1538 
1539  std::string idxName = idx->getName();
1540 
1541  // Check if the index is associated to a UK or PK
1542  std::unique_ptr<te::da::PrimaryKey> pk = getPrimaryKey(fullDatasetName);
1543 
1544  if(pk.get() && (pk->getAssociatedIndex() == idx))
1545  return;
1546 
1547  std::vector<std::string> ukNames = getUniqueKeyNames(datasetName);
1548 
1549  for(std::size_t i = 0; i < ukNames.size(); ++i)
1550  if(getUniqueKey(datasetName, ukNames[i])->getAssociatedIndex() == idx)
1551  return;
1552 
1553  // If there is not a uk or pk associated, let's create the index!
1554  std::string sql("CREATE INDEX ");
1555  sql += idxName;
1556  sql += " ON ";
1557  sql += fullDatasetName;
1558 
1559  if(idx->getIndexType() == te::da::HASH_TYPE)
1560  sql += " USING HASH (";
1561  else if(idx->getIndexType() == te::da::R_TREE_TYPE)
1562  sql += " USING GIST (";
1563  else if(idx->getIndexType() == te::da::B_TREE_TYPE)
1564  sql += " USING BTREE (";
1565  else
1566  throw Exception(TE_TR("The index type is not supported!"));
1567 
1568  std::size_t numProperties = idx->getProperties().size();
1569 
1570  for(size_t i = 0; i < numProperties; ++i)
1571  {
1572  if(i != 0)
1573  sql += ", ";
1574 
1575  sql += idx->getProperties()[i]->getName();
1576  }
1577 
1578  sql += ")";
1579 
1580  execute(sql);
1581 }
1582 
1583 void te::pgis::Transactor::dropIndex(const std::string& datasetName, const std::string& name)
1584 {
1585  std::string fullDatasetName = getFullName(datasetName);
1586 
1587  std::string sql("DROP INDEX ");
1588  sql += name;
1589 
1590  execute(sql);
1591 }
1592 
1593 std::unique_ptr<te::da::Sequence> te::pgis::Transactor::getSequence(const std::string& name)
1594 {
1595  te::da::Sequence* seq = nullptr;
1596 
1597  // Query the data source for the sequences
1598  std::vector<std::string> seqNames;
1599 
1600  std::string sql("SELECT c.oid, n.nspname, c.relname, c.relkind "
1601  "FROM pg_class c, pg_namespace n "
1602  "WHERE c.relname !~ '^pg_' "
1603  "AND c.relkind = 'S' "
1604  "AND c.relnamespace = n.oid "
1605  "AND n.nspname NOT IN ('information_schema', 'pg_toast', 'pg_temp_1', 'pg_catalog')");
1606 
1607  std::unique_ptr<te::da::DataSet> seqNamesInfo = query(sql);
1608 
1609  while(seqNamesInfo->moveNext())
1610  {
1611  std::string seqName(seqNamesInfo->getString(2));
1612 
1613  if(seqName != name)
1614  continue;
1615 
1616  std::string sql("SELECT * FROM ");
1617  sql += seqName;
1618 
1619  std::unique_ptr<te::da::DataSet> result(query(sql));
1620 
1621  if(result->moveNext())
1622  {
1623  unsigned int seqId = getDataSetId(seqName);
1624 
1625  seq = new te::da::Sequence(seqName, 0, 0, nullptr, seqId);
1626 
1627  // Check if the sequence is cycled
1628  if(result->getBool(8))
1629  seq->setAsCycle();
1630  else
1631  seq->setAsNoCycle();
1632 
1633  seq->setCachedValues(result->getInt64(6)); // "cache_value"
1634  seq->setIncrement(result->getInt64(3)); // "increment_by";
1635  seq->setMaxValue(result->getInt64(4)); // "max_value";
1636  seq->setMinValue(result->getInt64(5)); // "min_value";
1637  }
1638  }
1639 
1640  return std::unique_ptr<te::da::Sequence>(seq);
1641 }
1642 
1643 std::vector<std::string> te::pgis::Transactor::getSequenceNames()
1644 {
1645  std::vector<std::string> seqNames;
1646 
1647  std::string sql("SELECT c.oid, n.nspname, c.relname, c.relkind "
1648  "FROM pg_class c, pg_namespace n "
1649  "WHERE c.relname !~ '^pg_' "
1650  "AND c.relkind = 'S' "
1651  "AND c.relnamespace = n.oid "
1652  "AND n.nspname NOT IN ('information_schema', 'pg_toast', 'pg_temp_1', 'pg_catalog')");
1653 
1654  std::unique_ptr<te::da::DataSet> seqNamesInfo = query(sql);
1655 
1656  while(seqNamesInfo->moveNext())
1657  {
1658  std::string seqName(seqNamesInfo->getString(2));
1659  seqNames.push_back(seqName);
1660  }
1661 
1662  return seqNames;
1663 }
1664 
1665 bool te::pgis::Transactor::sequenceExists(const std::string& name)
1666 {
1667  std::vector<std::string> seqNames = getSequenceNames();
1668 
1669  if(std::find(seqNames.begin(), seqNames.end(), name) != seqNames.end())
1670  return true;
1671 
1672  return false;
1673 }
1674 
1676 {
1677  std::string seqName = sequence->getName();
1678 
1679  std::string sql("CREATE SEQUENCE ");
1680  sql += seqName;
1681  sql += " INCREMENT BY ";
1682  sql += te::common::Convert2String(sequence->getIncrement());
1683  sql += " MINVALUE ";
1684  sql += te::common::Convert2String(sequence->getMinValue());
1685  sql += " MAXVALUE ";
1686  sql += te::common::Convert2String(sequence->getMaxValue());
1687  sql += " START WITH ";
1688  sql += te::common::Convert2String(sequence->getStartValue());
1689  sql += " CACHE ";
1690  sql += te::common::Convert2String(sequence->getCachedValues());
1691 
1692  if(sequence->isCycled() == false)
1693  sql += " NO";
1694 
1695  sql += " CYCLE ";
1696 
1697  if(sequence->getOwner())
1698  {
1699  sql += " OWNED BY ";
1700  sql += sequence->getOwner()->getParent()->getName();
1701  sql += ".";
1702  sql += sequence->getOwner()->getName();
1703  }
1704 
1705  execute(sql);
1706 
1707  unsigned int seqId = getDataSetId(seqName);
1708 
1709  sequence->setId(seqId);
1710 }
1711 
1712 void te::pgis::Transactor::dropSequence(const std::string& name)
1713 {
1714  std::unique_ptr<te::da::Sequence> seq = getSequence(name);
1715 
1716  std::string sql("DROP SEQUENCE ");
1717  sql += name;
1718 
1719  execute(sql);
1720 }
1721 
1722 std::unique_ptr<te::gm::Envelope> te::pgis::Transactor::getExtent(const std::string& datasetName, const std::string& propertyName)
1723 {
1724  ScopedConnection scopedConnection(m_ds->getConnPool(), m_connectionId);
1725 
1726  std::string sql("SELECT ST_Extent(");
1727  sql += propertyName;
1728  sql += ") FROM ";
1729  sql += datasetName;
1730 
1731  PGresult* result = PQexec(scopedConnection->getConn(), sql.c_str());
1732 
1733  if(PQresultStatus(result) != PGRES_TUPLES_OK)
1734  {
1735  std::string errmsg(TE_TR("Could not find the envelope for the given geometry property due to the following error: "));
1736  errmsg += PQerrorMessage(scopedConnection->getConn());
1737 
1738  PQclear(result);
1739 
1740  throw Exception(errmsg);
1741  }
1742 
1743  const char* boxStr = PQgetvalue(result, 0, 0);
1744 
1745  te::gm::Envelope* mbr = nullptr;
1746 
1747  if(*boxStr != '\0')
1748  mbr = GetEnvelope(boxStr);
1749 
1750  PQclear(result);
1751  return std::unique_ptr<te::gm::Envelope>(mbr);
1752 }
1753 
1754 std::unique_ptr<te::gm::Envelope> te::pgis::Transactor::getExtent(const std::string& datasetName, std::size_t propertyPos)
1755 {
1756  ScopedConnection scopedConnection(m_ds->getConnPool(), m_connectionId);
1757 
1758  std::unique_ptr<te::dt::Property> p = getProperty(datasetName, propertyPos);
1759 
1760  std::string sql("SELECT ST_Extent(");
1761  sql += p->getName();
1762  sql += ") FROM ";
1763  sql += datasetName;
1764 
1765  PGresult* result = PQexec(scopedConnection->getConn(), sql.c_str());
1766 
1767  if(PQresultStatus(result) != PGRES_TUPLES_OK)
1768  {
1769  std::string errmsg(TE_TR("Could not find the envelope for the given geometry property due to the following error: "));
1770  errmsg += PQerrorMessage(scopedConnection->getConn());
1771 
1772  PQclear(result);
1773 
1774  throw Exception(errmsg);
1775  }
1776 
1777  const char* boxStr = PQgetvalue(result, 0, 0);
1778 
1779  te::gm::Envelope* mbr = nullptr;
1780 
1781  if(*boxStr != '\0')
1782  mbr = GetEnvelope(boxStr);
1783 
1784  PQclear(result);
1785  return std::unique_ptr<te::gm::Envelope>(mbr);
1786 }
1787 
1788 std::size_t te::pgis::Transactor::getNumberOfItems(const std::string& datasetName)
1789 {
1790  std::unique_ptr<te::da::DataSet> result = getDataSet(datasetName);
1791  return result->size();
1792 }
1793 
1795 {
1796  std::vector<std::string> datasetNames = getDataSetNames();
1797 
1798  if(datasetNames.empty())
1799  return false;
1800 
1801  return true;
1802 }
1803 
1804 bool te::pgis::Transactor::dataSetExists(const std::string& name)
1805 {
1806  std::string datasetName = getFullName(name);
1807 
1808  std::vector<std::string> datasetNames = getDataSetNames();
1809 
1810  if(std::find(datasetNames.begin(), datasetNames.end(), datasetName) != datasetNames.end())
1811  return true;
1812 
1813  return false;
1814 }
1815 
1816 void te::pgis::Transactor::createDataSet(te::da::DataSetType* dt, const std::map<std::string, std::string>& options)
1817 {
1818  std::string datasetName = dt->getName();
1819  datasetName = getFullName(datasetName);
1820 
1821  std::string sql = "CREATE TABLE ";
1822  sql += datasetName;
1823  sql += "()";
1824 
1825  execute(sql);
1826 
1827  // Find the table id
1828  unsigned int dtid = getDataSetId(datasetName);
1829 
1830  dt->setId(dtid);
1831 
1832  // Add the properties
1833  std::size_t nCols = dt->size();
1834  for(std::size_t i = 0; i < nCols; ++i)
1835  addProperty(datasetName, dt->getProperty(i));
1836 
1837  // Add the primary key
1838  if(dt->getPrimaryKey())
1839  addPrimaryKey(datasetName, dt->getPrimaryKey());
1840 
1841  // Add the unique keys
1842  std::size_t nUKs = dt->getNumberOfUniqueKeys();
1843  for(std::size_t i = 0; i < nUKs; ++i)
1844  addUniqueKey(datasetName, dt->getUniqueKey(i));
1845 
1846  // Add the indexes, just if no primary key or unique key with the same name exists!
1847  std::size_t nIdxs = dt->getNumberOfIndexes();
1848  for(std::size_t i = 0; i < nIdxs; ++i)
1849  addIndex(datasetName, dt->getIndex(i), options);
1850 
1851  // Add the foreign keys
1852  std::size_t nFKs = dt->getNumberOfForeignKeys();
1853  for(std::size_t i = 0; i < nFKs; ++i)
1854  addForeignKey(datasetName, dt->getForeignKey(i));
1855 
1856  // Add the the check constraints
1857  std::size_t nCCs = dt->getNumberOfCheckConstraints();
1858 
1859  for(std::size_t i = 0; i < nCCs; ++i)
1860  addCheckConstraint(datasetName, dt->getCheckConstraint(i));
1861 
1862  // Try to link the primary key to an index
1863  std::vector<std::string> indexNames = getIndexNames(datasetName);
1864 
1865  te::da::PrimaryKey* pk = dt->getPrimaryKey();
1866  if(pk)
1867  {
1868  for(std::size_t i = 0; i < indexNames.size(); ++i)
1869  {
1870  if(pk->getName() == indexNames[i])
1871  {
1872  pk->setAssociatedIndex(dt->getIndex(indexNames[i]));
1873  break;
1874  }
1875  }
1876  }
1877 
1878  // Try to link the unique keys to an index
1879  std::size_t numUKs = dt->getNumberOfUniqueKeys();
1880 
1881  for(std::size_t i = 0; i < numUKs; ++i)
1882  {
1883  te::da::UniqueKey* uk = dt->getUniqueKey(i);
1884 
1885  for(std::size_t j = 0; j < indexNames.size(); ++j)
1886  {
1887  if(uk->getName() == indexNames[j])
1888  {
1889  uk->setAssociatedIndex(dt->getIndex(indexNames[j]));
1890  break;
1891  }
1892  }
1893  }
1894 }
1895 
1896 void te::pgis::Transactor::cloneDataSet(const std::string& /*name*/,
1897  const std::string& /*cloneName*/,
1898  const std::map<std::string, std::string>& /*options*/)
1899 {
1900  throw Exception(TE_TR("Not implemented yet!"));
1901 }
1902 
1903 void te::pgis::Transactor::dropDataSet(const std::string& name)
1904 {
1905  std::unique_ptr<te::da::DataSetType> dt = getDataSetType(name);
1906 
1907  std::string sql;
1908 
1909  if(dt->hasGeom())
1910  {
1911  std::string tSchema, tName;
1912  SplitTableName(dt->getName(), &(m_ds->getCurrentSchema()), tSchema, tName);
1913 
1914  sql = "SELECT DropGeometryTable('";
1915  sql += te::common::Convert2LCase(tSchema);
1916  sql += "', '";
1917  sql += te::common::Convert2LCase(tName);
1918  sql += "')";
1919  }
1920  else
1921  {
1922  sql += "DROP TABLE ";
1923  sql += dt->getName();
1924  }
1925 
1926  execute(sql);
1927 }
1928 
1929 void te::pgis::Transactor::renameDataSet(const std::string& name, const std::string& newName)
1930 {
1931  std::string newTableName, newTableSchema, oldTableName, oldTableSchema;
1932 
1933  std::string sql("ALTER TABLE ");
1934  sql += name;
1935  sql += " RENAME TO ";
1936 
1937  SplitTableName(newName, &(m_ds->getCurrentSchema()), newTableSchema, newTableName);
1938 
1939  sql += newTableName;
1940 
1941  execute(sql);
1942 
1943  // If the table has a geometry column, we need to propagate changes to the geometry columns table
1944  std::unique_ptr<te::da::DataSetType> dt = getDataSetType(newName);
1945 
1946  if(dt->hasGeom())
1947  {
1948  SplitTableName(name, &(m_ds->getCurrentSchema()), oldTableSchema, oldTableName);
1949 
1950  sql = "UPDATE geometry_columns SET f_table_name = '";
1951  sql += newTableName;
1952  sql += "' WHERE f_table_name = '";
1953  sql += oldTableName;
1954  sql += "' AND f_table_schema ='";
1955  sql += oldTableSchema;
1956  sql += "'";
1957 
1958  execute(sql);
1959  }
1960 }
1961 
1963  const std::string& datasetName, te::da::DataSet* d,
1964  const std::map<std::string, std::string>& /*options*/, std::size_t limit,
1965  bool /*enableProgress*/)
1966 {
1967  if(limit == 0)
1968  limit = std::string::npos;
1969 
1970 // create a prepared statement
1971  std::string sql = "INSERT INTO ";
1972  sql += datasetName;
1973  sql += te::da::GetSQLValueNames(d);
1974  sql += " VALUES";
1975  sql += GetSQLBindValues(d->getNumProperties());
1976 
1977  std::unique_ptr<PreparedQuery> pq(new PreparedQuery(this, "a" + boost::lexical_cast<std::string>((intptr_t)(this))));
1978 
1979  te::da::ScopedTransaction st(*this);
1980 
1981  std::vector<int> paramTypes = te::da::GetPropertyDataTypes(d);
1982 
1983  std::size_t nProcessedRows = 0;
1984 
1985  pq->prepare(sql, paramTypes);
1986 
1987  te::common::TaskProgress task("Saving...");
1988  task.setTotalSteps((int)d->size());
1989  task.useTimer(true);
1990 
1991  while(d->moveNext() && (nProcessedRows != limit))
1992  {
1993  pq->bind(d);
1994  pq->execute();
1995 
1996  ++nProcessedRows;
1997 
1998  task.pulse();
1999 
2000  if(task.isActive() == false)
2001  {
2002  rollBack();
2003  throw Exception(TE_TR("Save canceled!"));
2004  }
2005  }
2006 
2007  st.commit();
2008 }
2009 
2010 void te::pgis::Transactor::remove(const std::string& datasetName, const te::da::ObjectIdSet* oids)
2011 {
2012  std::unique_ptr<te::da::DataSetType> dt = getDataSetType(datasetName);
2013 
2014  if(!dt->getPrimaryKey())
2015  {
2016  throw Exception(TE_TR("Can not remove dataset items because dataset doesn't have a primary key or unique key!"));
2017  }
2018 
2019  // create a prepared statement
2020  std::string sql = "DELETE FROM ";
2021  sql += datasetName;
2022 
2023  if (oids)
2024  {
2025  te::da::Expression* oidsExpression = oids->getExpressionByInClause();
2026  te::da::In* oidsInClause = dynamic_cast<te::da::In*>(oidsExpression);
2027 
2028  std::string oidsInClauseStr;
2029  te::da::SQLVisitor v(*(m_ds->getDialect()), oidsInClauseStr);
2030  v.visit(*oidsInClause);
2031 
2032  sql += " WHERE ";
2033  sql += oidsInClauseStr;
2034  }
2035 
2036  execute(sql);
2037 }
2038 
2039 void te::pgis::Transactor::update(const std::string& /*datasetName*/,
2040  te::da::DataSet* /*dataset*/,
2041  const std::vector<std::size_t>& /*properties*/,
2042  const te::da::ObjectIdSet* /*oids*/,
2043  const std::map<std::string, std::string>& /*options*/,
2044  std::size_t /*limit*/)
2045 {
2046  throw Exception(TE_TR("Not implemented yet!"));
2047 
2048 // const std::vector<te::dt::Property*>* keyProperties = 0;
2049 //
2050 // if(dt->getPrimaryKey())
2051 // {
2052 // keyProperties = &(dt->getPrimaryKey()->getProperties());
2053 // }
2054 // else if(dt->getNumberOfUniqueKeys() > 0)
2055 // {
2056 // keyProperties = &(dt->getUniqueKey(0)->getProperties());
2057 // }
2058 // else
2059 // {
2060 // throw Exception(TE_TR("Can not update dataset item(s) because dataset doesn't have a primary key or unique key!"));
2061 // }
2062 //
2063 //// create a prepared statement
2064 // std::string sql = "UPDATE ";
2065 // sql += dt->getName();
2066 // sql += " SET ";
2067 // sql += GetBindableUpdateSQL(properties);
2068 // sql += " WHERE ";
2069 // sql += GetBindableWhereSQL(*keyProperties, properties.size());
2070 //
2071 // std::vector<std::size_t> propertiesPos;
2072 //
2073 // te::dt::GetPropertiesPosition(properties, dt, propertiesPos);
2074 //
2075 // te::dt::GetPropertiesPosition(*keyProperties, dt, propertiesPos);
2076 //
2077 // std::unique_ptr<PreparedQuery> pq(m_t->getPGPrepared("a" + boost::lexical_cast<std::string>((boost::int64_t)(this))));
2078 //
2079 // std::vector<te::dt::Property*> allprops(properties);
2080 //
2081 // std::copy(keyProperties->begin(), keyProperties->end(), allprops.end());
2082 //
2083 // te::da::ScopedTransaction st(*m_t);
2084 //
2085 // pq->prepare(sql, allprops);
2086 //
2087 // do
2088 // {
2089 // pq->bind(propertiesPos, dt, dataset);
2090 // pq->execute();
2091 //
2092 // }while(dataset->moveNext());
2093 //
2094 // st.commit();
2095 }
2096 
2097 void te::pgis::Transactor::update(const std::string& datasetName,
2098  te::da::DataSet* dataset,
2099  const std::vector< std::set<int> >& properties,
2100  const std::vector<size_t>& ids)
2101 {
2102  dataset->moveFirst();
2103 
2104  std::unique_ptr<PreparedQuery> pq(new PreparedQuery(this, "a" + boost::lexical_cast<std::string>((intptr_t)(this))));
2105 
2106  te::da::ScopedTransaction st(*this);
2107 
2108  std::vector<int> paramTypes;
2109 
2110  std::size_t nProcessedRows = 0;
2111 
2112  do
2113  {
2114  const std::set<int>& setProperties = properties[nProcessedRows];
2115 
2116  std::vector<size_t> vecPropertiesPos;
2117  std::vector<te::dt::Property*> vecProperties;
2118  std::set<int>::iterator itProperties = setProperties.begin();
2119 
2120  while (itProperties != setProperties.end())
2121  {
2122  std::string propertyName = dataset->getPropertyName(*itProperties);
2123  int dataType = dataset->getPropertyDataType(*itProperties);
2124  te::dt::Property* property = new te::dt::SimpleProperty(propertyName, dataType);
2125  vecProperties.push_back(property);
2126  vecPropertiesPos.push_back(*itProperties);
2127 
2128  paramTypes.push_back(dataType);
2129 
2130  ++itProperties;
2131  }
2132 
2133  std::string id;
2134  for (size_t j = 0; j<ids.size(); ++j)
2135  {
2136  if (j>0)
2137  id += " AND ";
2138 
2139  id += dataset->getPropertyName(ids[j]) += "=";
2140 
2141  if (dataset->getPropertyDataType(ids[j]) == te::dt::STRING_TYPE)
2142  id += "\'" + dataset->getAsString(ids[j]) + "\'";
2143  else
2144  id += dataset->getAsString(ids[j]);
2145  }
2146 
2147  // create a prepared statement
2148  std::string sql = "UPDATE ";
2149  sql += datasetName;
2150  sql += " SET ";
2151  sql += GetBindableUpdateSQL(vecProperties);
2152  sql += " WHERE " + id;
2153 
2154  pq->prepare(sql, paramTypes);
2155 
2156  pq->bind(vecPropertiesPos, dataset);
2157  pq->execute();
2158 
2159  ++nProcessedRows;
2160 
2161  for (size_t i = 0; i < vecProperties.size(); ++i)
2162  {
2163  delete vecProperties[i];
2164  }
2165 
2166  paramTypes.clear();
2167 
2168  } while (dataset->moveNext());
2169 
2170  st.commit();
2171 
2172 }
2173 
2174 void te::pgis::Transactor::optimize(const std::map<std::string, std::string>& /*opInfo*/)
2175 {
2176  throw Exception(TE_TR("Not implemented yet!"));
2177 }
2178 
2180 {
2181  std::string sql("SELECT oid FROM pg_type WHERE typname = 'geometry'");
2182 
2183  std::unique_ptr<te::da::DataSet> result(query(sql));
2184 
2185  unsigned int id = 0;
2186 
2187  if(result->moveNext())
2188  id = result->getInt32(0);
2189 
2190  return id;
2191 }
2192 
2194 {
2195  std::string sql("SELECT oid FROM pg_type WHERE typname = 'raster'");
2196 
2197  std::unique_ptr<te::da::DataSet> result(query(sql));
2198 
2199  unsigned int id = 0;
2200 
2201  if(result->moveNext())
2202  id = result->getInt32(0);
2203 
2204  return id;
2205 }
2206 
2207 void te::pgis::Transactor::getDatabaseInfo(std::string& currentSchema)
2208 {
2209  std::string sql("SELECT current_schema()");
2210 
2211  std::unique_ptr<te::da::DataSet> result(query(sql));
2212 
2213  if(!result->moveNext())
2214  Exception(TE_TR("Could not get information about PostgreSQL database backend!"));
2215 
2216  currentSchema = result->getString(0);
2217 }
2218 
2219 void te::pgis::Transactor::getGeometryInfo(const std::string& datasetName, te::gm::GeometryProperty* gp)
2220 {
2221  std::string sql = "SELECT g.coord_dimension, g.srid, g.type "
2222  "FROM geometry_columns g "
2223  "WHERE lower(g.f_table_name) = '";
2224 
2225  std::string tname, sname;
2226 
2227  SplitTableName(datasetName, &(m_ds->getCurrentSchema()), sname, tname);
2228 
2229  sql += te::common::Convert2LCase(tname);
2230  sql += "' AND g.f_table_schema = '";
2231  sql += sname;
2232  sql += "' AND f_geometry_column = '";
2233  sql += gp->getName();
2234  sql += "'";
2235 
2236  std::unique_ptr<te::da::DataSet> result(query(sql));
2237 
2238  if(result->moveNext())
2239  {
2240  //int cdim = result->getInt(0);
2241  int srid = result->getInt32(1);
2242  te::gm::GeomType t = te::gm::Geometry::getGeomTypeId(result->getString(2));
2243  //gp->setCoordDimension(cdim);
2244 
2245  if(srid == PGIS_UNKNOWN_SRS)
2246  srid = TE_UNKNOWN_SRS;
2247 
2248  gp->setSRID(srid);
2249  gp->setGeometryType(t);
2250  }
2251  else
2252  {
2253 // Don't throw: someone can create a geometry column without using AddGeometryColumn function!!
2254  gp->setSRID(TE_UNKNOWN_SRS);
2256  }
2257 }
2258 
2259 void te::pgis::Transactor::getRasterInfo(const std::string& datasetName, te::rst::RasterProperty* rp)
2260 {
2261  std::string sql = "SELECT * FROM raster_columns as r WHERE r.r_table_name = '";
2262 
2263  std::string tname, sname;
2264 
2265  SplitTableName(datasetName, &(m_ds->getCurrentSchema()), sname, tname);
2266 
2267  sql += tname;
2268  sql += "' AND r.r_table_schema = '";
2269  sql += sname;
2270  sql += "' AND r_raster_column = '";
2271  sql += rp->getName();
2272  sql += "'";
2273 
2274  std::unique_ptr<te::da::DataSet> result(query(sql));
2275 
2276  if(result->moveNext())
2277  {
2278  int srid = result->getInt32("srid");
2279 
2280  if(srid == PGIS_UNKNOWN_SRS)
2281  srid = TE_UNKNOWN_SRS;
2282 
2283  double scale_x = result->getDouble("scale_x");
2284 
2285  double scale_y = result->getDouble("scale_y");
2286 
2287  int blocksize_x = result->getInt32("blocksize_x");
2288 
2289  int blocksize_y = result->getInt32("blocksize_y");
2290 
2291  //bool regular_blocking = result->getBool("regular_blocking");
2292 
2293  int nbands = result->getInt32("num_bands");
2294 
2295  std::unique_ptr<te::dt::Array> pixel_types(result->getArray("pixel_types"));
2296 
2297  std::unique_ptr<te::dt::Array> nodata_values(result->getArray("nodata_values"));
2298 
2299  std::unique_ptr<te::gm::Geometry> g(result->getGeometry("extent"));
2300 
2301  const te::gm::Envelope* e = g->getMBR();
2302 
2303  std::unique_ptr<te::rst::Grid> grid(new te::rst::Grid(scale_x, scale_y, new te::gm::Envelope(*e), srid));
2304 
2305  rp->set(grid.release());
2306 
2307  for(int i = 0; i != nbands; ++i)
2308  {
2309  std::vector<std::size_t> pos(1, i);
2310 
2311  std::string st = pixel_types->getData(pos)->toString();
2312 
2313  int t = te::dt::UNKNOWN_TYPE;
2314 
2315  if(st == "8BI")
2316  t = te::dt::CHAR_TYPE;
2317  else if(st == "8BUI")
2318  t = te::dt::UCHAR_TYPE;
2319  else if(st == "16BI")
2320  t = te::dt::INT16_TYPE;
2321  else if(st == "16BUI")
2322  t = te::dt::UINT16_TYPE;
2323  else if(st == "32BI")
2324  t = te::dt::INT32_TYPE;
2325  else if(st == "32BUI")
2326  t = te::dt::UINT32_TYPE;
2327  else if(st == "32BF")
2328  t = te::dt::FLOAT_TYPE;
2329  else if(st == "64BF")
2330  t = te::dt::DOUBLE_TYPE;
2331  else
2332  throw Exception(TE_TR("Band data type not supported by PostGIS driver!"));
2333 
2335 
2336  bp->m_blkh = blocksize_y;
2337 
2338  bp->m_blkw = blocksize_x;
2339 
2340  te::dt::AbstractData* ab = nodata_values->getData(pos);
2341 
2342  if(ab)
2343  bp->m_noDataValue = static_cast<te::dt::Double*>(ab)->getValue();
2344 
2345  rp->add(bp);
2346  }
2347  }
2348  else
2349  {
2350  //throw Exception(TE_TR("We must add support for rasters that don't have constraints!"));
2351  }
2352 }
2353 
2354 std::string te::pgis::Transactor::getFullName(const std::string& name)
2355 {
2356  std::string fullName = name;
2357 
2358  if(fullName.find(".") == std::string::npos)
2359  fullName = m_ds->getCurrentSchema() + "." + name;
2360 
2361  return fullName;
2362 }
2363 
2364 /////////// Protected methods
2365 
2366 unsigned int te::pgis::Transactor::getDataSetId(const std::string& tableName)
2367 {
2368  std::string tname, sname;
2369 
2370  SplitTableName(tableName, &(m_ds->getCurrentSchema()), sname, tname);
2371 
2372  std::string sql("SELECT pg_class.oid "
2373  "FROM pg_class, pg_namespace "
2374  "WHERE pg_class.relnamespace = pg_namespace.oid "
2375  "AND lower(pg_class.relname) = '");
2376 
2377  sql += te::common::Convert2LCase(tname);
2378  sql += "' AND lower(pg_namespace.nspname) = '";
2379  sql += te::common::Convert2LCase(sname);
2380  sql += "'";
2381 
2382  std::unique_ptr<te::da::DataSet> result(query(sql));
2383 
2384  if(result->moveNext() == false)
2385  throw Exception(TE_TR("Could not find the table oid!"));
2386 
2387  unsigned int tableid = result->getInt32(0);
2388 
2389  return tableid;
2390 }
2391 
2392 std::string te::pgis::Transactor::getDataSetName(unsigned int id)
2393 {
2394  std::string sql("SELECT pg_namespace.nspname, pg_class.relname "
2395  "FROM pg_class, pg_namespace "
2396  "WHERE pg_class.relnamespace = pg_namespace.oid "
2397  "AND pg_class.oid = ");
2398 
2399  sql += te::common::Convert2String(id);
2400 
2401  std::unique_ptr<te::da::DataSet> result(query(sql));
2402 
2403  if(result->moveNext() == false)
2404  throw Exception(TE_TR("Could not find the dataset name!"));
2405 
2406  std::string tname = result->getString(0);
2407  tname += ".";
2408  tname += result->getString(1);
2409 
2410  return tname;
2411 }
2412 
2413 std::unique_ptr<te::da::DataSet> te::pgis::Transactor::getPropertiesInfo(const std::string& datasetName)
2414 {
2415  std::string fullDatasetName = getFullName(datasetName);
2416 
2417  unsigned int dtid = getDataSetId(fullDatasetName);
2418 
2419  std::string sql("SELECT a.attnum, a.attname, t.oid, a.attnotnull, format_type(a.atttypid, a.atttypmod), a.atthasdef, pg_get_expr(d.adbin, d.adrelid), a.attndims "
2420  "FROM pg_attribute AS a INNER JOIN pg_type AS t ON (a.atttypid = t.oid) LEFT JOIN pg_attrdef AS d ON (a.attrelid = d.adrelid AND a.attnum = d.adnum) "
2421  "WHERE a.attrelid = ");
2422  sql += te::common::Convert2String(dtid);
2423  sql += " AND a.attisdropped = false"
2424  " AND a.attnum > 0"
2425  " ORDER BY a.attnum";
2426 
2427  return query(sql);
2428 }
2429 
2431 {
2432  if((p->getParent()==nullptr) || (p->getParent()->getType() != te::dt::DATASET_TYPE))
2433  throw Exception(TE_TR("The informed property is not valid!"));
2434 
2435  std::string sql("SELECT attnum "
2436  "FROM pg_attribute WHERE attrelid = ");
2437  sql += te::common::Convert2String(p->getParent()->getId());
2438  sql += " AND attisdropped = false "
2439  "AND attname = '";
2440  sql += te::common::Convert2LCase(p->getName());
2441  sql += "' ";
2442 
2443  std::unique_ptr<te::da::DataSet> result(query(sql));
2444 
2445  if(result->moveNext() == false)
2446  throw Exception(TE_TR("Could not find the property ID!"));
2447 
2448  unsigned int id = result->getInt32(0);
2449  p->setId(id);
2450 }
2451 
2452 std::unique_ptr<te::dt::Property> te::pgis::Transactor::getProperty(unsigned int pid, const std::string& datasetName)
2453 {
2454  unsigned int dtid = getDataSetId(datasetName);
2455 
2456  std::string sql("SELECT a.attnum, a.attname, t.oid, a.attnotnull, format_type(a.atttypid, a.atttypmod), a.atthasdef, pg_get_expr(d.adbin, d.adrelid), a.attndims "
2457  "FROM pg_attribute AS a INNER JOIN pg_type AS t ON (a.atttypid = t.oid) LEFT JOIN pg_attrdef AS d ON (a.attrelid = d.adrelid AND a.attnum = d.adnum) "
2458  "WHERE a.attrelid = ");
2459  sql += te::common::Convert2String(dtid);
2460  sql += " AND a.attnum = ";
2461  sql += te::common::Convert2String(pid);
2462  sql += " AND a.attisdropped = false"
2463  " AND a.attnum > 0";
2464 
2465  std::unique_ptr<te::da::DataSet> result(query(sql));
2466 
2467  std::unique_ptr<te::dt::Property> p;
2468 
2469  if(result->moveNext())
2470  {
2471  unsigned int attNum = result->getInt16(0);
2472  std::string attName = result->getString(1);
2473  unsigned int attType = result->getInt32(2);
2474  bool attNotNull = result->getBool(3);
2475  std::string fmt = result->getString(4);
2476  bool attHasDefault = result->getBool(5);
2477  std::string attDefValue = result->getString(6);
2478  int ndims = result->getInt32(7);
2479 
2480  p.reset(Convert2TerraLib(attNum, attName.c_str(), attType, attNotNull, fmt.c_str(), attHasDefault,
2481  attDefValue.c_str(),ndims, m_ds->getGeomTypeId(), m_ds->getRasterTypeId()));
2482 
2483  if(p->getType() == te::dt::GEOMETRY_TYPE)
2484  getGeometryInfo(datasetName, static_cast<te::gm::GeometryProperty*>(p.get()));
2485  }
2486 
2487  return p;
2488 }
2489 
2490 std::unique_ptr<te::da::DataSet> te::pgis::Transactor::getConstraints(const std::string& datasetName, char conType)
2491 {
2492  unsigned int dtid = getDataSetId(datasetName);
2493 
2494  std::string sql("SELECT c.oid, n.nspname, c.conname, c.contype, c.confrelid, c.confupdtype, c.confdeltype, c.confmatchtype, c.conkey, c.confkey, pg_get_constraintdef(c.oid) "
2495  "FROM pg_constraint c, pg_namespace n "
2496  "WHERE c.connamespace = n.oid "
2497  "AND c.conrelid = ");
2498  sql += te::common::Convert2String(dtid);
2499 
2500  if(conType != '\0')
2501  {
2502  sql += " AND c.contype = '";
2503  sql += conType;
2504  sql += "'";
2505  }
2506 
2507  return query(sql);
2508 }
2509 
2511 {
2512  std::string datasetName = dt->getName();
2513  unsigned int dtid = dt->getId();
2514 
2515  std::string sql("SELECT c.oid, n.nspname, c.conname, c.contype, c.confrelid, c.confupdtype, c.confdeltype, c.confmatchtype, c.conkey, c.confkey, pg_get_constraintdef(c.oid) "
2516  "FROM pg_constraint c, pg_namespace n "
2517  "WHERE c.connamespace = n.oid "
2518  "AND c.conrelid = ");
2519  sql += te::common::Convert2String(dtid);
2520 
2521  std::unique_ptr<te::da::DataSet> cInfo = query(sql);
2522 
2523  while(cInfo->moveNext())
2524  {
2525  char cType = cInfo->getChar(3);
2526  if(cType == 'p')
2527  {
2528  // begin of the dataset primary key
2529  unsigned int pkId = cInfo->getInt32(0);
2530  std::string pkName = cInfo->getString(2);
2531 
2532  te::da::PrimaryKey* pk = new te::da::PrimaryKey(pkName, nullptr, pkId);
2533 
2534  std::unique_ptr<te::dt::Array> pkCols(cInfo->getArray(8));
2535  std::size_t size = pkCols->getDimensionSize(0);
2536 
2537  std::vector<std::size_t> pos;
2538  pos.push_back(0);
2539  for(std::size_t i = 0; i < size; ++i)
2540  {
2541  pos[0] = i;
2542 
2543  te::dt::AbstractData* pkCol = pkCols->getData(pos);
2544 
2545  te::dt::Property* p = dt->getPropertyById(static_cast<te::dt::Int16*>(pkCol)->getValue());
2546  pk->add(p);
2547  }
2548 
2549  // Try to link the pk to an index
2550  std::vector<std::string> idxNames = getIndexNames(datasetName);
2551 
2552  for(std::size_t i = 0; i < idxNames.size(); ++i)
2553  {
2554  if(pk->getName() == idxNames[i])
2555  {
2556  pk->setAssociatedIndex(getIndex(datasetName, idxNames[i]).get());
2557  break;
2558  }
2559  }
2560 
2561  // Add the primary key to the schema
2562  dt->add(pk);
2563 
2564  } // end of the dataset primary key
2565  else if (cType == 'f')
2566  {
2567  // begin of foreign key constraint
2568  unsigned int fkId = cInfo->getInt32(0);
2569  unsigned int refDatasetId = cInfo->getInt32(4);
2570  char onUpdate = cInfo->getChar(5);
2571  char onDeletion = cInfo->getChar(6);
2572 
2573  std::unique_ptr<te::dt::Array> fkCols(cInfo->getArray(8));
2574  std::unique_ptr<te::dt::Array> fkRefCols(cInfo->getArray(9));
2575 
2576  assert(fkCols->getDimension() == 1);
2577  assert(fkCols->getDimension() == fkRefCols->getDimension());
2578  assert(fkCols->getDimensionSize(0) == fkRefCols->getDimensionSize(0));
2579 
2580  std::string refName = getDataSetName(refDatasetId);
2581 
2582  m_getConstraints = false;
2583  std::unique_ptr<te::da::DataSetType> refDatasetType = getDataSetType(refName);
2584  m_getConstraints = true;
2585 
2586  std::string fkName = cInfo->getString(2);
2587 
2588  te::da::ForeignKey* fk = new te::da::ForeignKey(fkName, fkId);
2589  fk->setOnUpdateAction(GetAction(onUpdate));
2590  fk->setOnDeleteAction(GetAction(onDeletion));
2591  fk->setReferencedDataSetType(refDatasetType.get());
2592 
2593  std::size_t size = fkCols->getDimensionSize(0);
2594 
2595  std::vector<std::size_t> pos;
2596  pos.push_back(0);
2597 
2598  for(std::size_t i = 0; i < size; ++i)
2599  {
2600  pos[0] = i;
2601 
2602  te::dt::AbstractData* fkRefCol = fkRefCols->getData(pos);
2603  fk->addRefProperty(refDatasetType->getPropertyById(static_cast<te::dt::Int16*>(fkRefCol)->getValue()));
2604 
2605  te::dt::AbstractData* fkCol = fkCols->getData(pos);
2606  fk->add(getProperty(static_cast<te::dt::Int16*>(fkCol)->getValue(), datasetName).release());
2607  }
2608 
2609  // Add the foreign key to the schema
2610  dt->add(fk);
2611 
2612  } // end of foreign key constraint
2613  else if(cType == 'u')
2614  {
2615  // begin of unique key constraint
2616  unsigned int ukId = cInfo->getInt32(0);
2617  std::string ukName = cInfo->getString(2);
2618 
2619  std::unique_ptr<te::dt::Array> ukCols(cInfo->getArray(8));
2620 
2621  te::da::UniqueKey* uk = new te::da::UniqueKey(ukName, nullptr, ukId);
2622 
2623  std::size_t size = ukCols->getDimensionSize(0);
2624 
2625  std::vector<std::size_t> pos;
2626  pos.push_back(0);
2627 
2628  for(std::size_t i = 0; i < size; ++i)
2629  {
2630  pos[0] = i;
2631 
2632  te::dt::AbstractData* ukCol = ukCols->getData(pos);
2633 
2634  std::unique_ptr<te::dt::Property> p = getProperty(static_cast<te::dt::Int16*>(ukCol)->getValue(), datasetName);
2635  uk->add(p.release());
2636  }
2637 
2638  // Try to link the uk to an index
2639  std::vector<std::string> idxNames = getIndexNames(datasetName);
2640 
2641  for(std::size_t i = 0; i < idxNames.size(); ++i)
2642  {
2643  if(uk->getName() == idxNames[i])
2644  {
2645  uk->setAssociatedIndex(getIndex(datasetName, idxNames[i]).get());
2646  break;
2647  }
2648  }
2649 
2650  // Add the unique key to the schema
2651  dt->add(uk);
2652 
2653  } // end of the unique key constraint
2654  else if(cType == 'c')
2655  {
2656  // begin of check constraint
2657  std::string ccName = cInfo->getString(2);
2658 
2659  unsigned int ccId = cInfo->getInt32(0);
2660 
2662  cc->setId(ccId);
2663  cc->setExpression(cInfo->getString(10));
2664 
2665  // Add the check constraint to the schema
2666  dt->add(cc);
2667 
2668  } // end of check constraint
2669  } // end of moveNext
2670 }
2671 
2673 {
2674  std::string datasetName = dt->getName();
2675  unsigned int dtid = dt->getId();
2676 
2677  std::string sql("SELECT idx_table.oid, s.nspname, idx_table.relname, pg_index.indkey, pg_am.amname, pg_index.indisunique, pg_index.indisprimary "
2678  "FROM pg_index, pg_class idx_table, pg_am, pg_namespace s "
2679  "WHERE s.oid = idx_table.relnamespace "
2680  "AND pg_index.indexrelid = idx_table.oid "
2681  "AND idx_table.relam = pg_am.oid "
2682  "AND pg_index.indrelid = ");
2683  sql += te::common::Convert2String(dtid);
2684 
2685  std::unique_ptr<te::da::DataSet> idxInfo = query(sql);
2686 
2687  while(idxInfo->moveNext())
2688  {
2689  unsigned int idxId = idxInfo->getInt32(0);
2690  std::string idxName = idxInfo->getString(2);
2691 
2692  std::unique_ptr<te::dt::Array> idxCols(idxInfo->getArray(3));
2693 
2694  std::string idxType = idxInfo->getString(4);
2695  bool isUK = idxInfo->getBool(5);
2696  bool isPK = idxInfo->getBool(6);
2697 
2698  te::da::Index* idx = new te::da::Index(idxName, GetIndexType(idxType.c_str()), dt, idxId);
2699 
2700  std::size_t size = idxCols->getDimensionSize(0);
2701 
2702  std::vector<std::size_t> pos;
2703  pos.push_back(0);
2704 
2705  for(std::size_t i = 0; i < size; ++i)
2706  {
2707  pos[0] = i;
2708  te::dt::AbstractData* idxCol = idxCols->getData(pos);
2709 
2710  idx->add(dt->getPropertyById(static_cast<te::dt::Int16*>(idxCol)->getValue()));
2711  }
2712 
2713  // Look if there is an association with a pk and uk
2714  idxName = idxInfo->getString(2);
2715  if(isPK && dt->getPrimaryKey() && (dt->getPrimaryKey()->getName() == idxName))
2716  {
2717  dt->getPrimaryKey()->setAssociatedIndex(idx);
2718  }
2719  else if(isUK)
2720  {
2721  te::da::UniqueKey* uk = dt->getUniqueKey(idxName);
2722 
2723  if(uk)
2724  uk->setAssociatedIndex(idx);
2725  }
2726  }
2727 }
2728 
2729 std::vector<te::da::Sequence*> te::pgis::Transactor::getSequences()
2730 {
2731  std::vector<te::da::Sequence*> seqs;
2732 
2733  // Query the data source for the sequences
2734  std::vector<std::string> seqNames;
2735 
2736  std::string sql("SELECT c.oid, n.nspname, c.relname, c.relkind "
2737  "FROM pg_class c, pg_namespace n "
2738  "WHERE c.relname !~ '^pg_' "
2739  "AND c.relkind = 'S' "
2740  "AND c.relnamespace = n.oid "
2741  "AND n.nspname NOT IN ('information_schema', 'pg_toast', 'pg_temp_1', 'pg_catalog')");
2742 
2743  std::unique_ptr<te::da::DataSet> seqNamesInfo = query(sql);
2744 
2745  while(seqNamesInfo->moveNext())
2746  {
2747  std::string seqName(seqNamesInfo->getString(2));
2748  seqNames.push_back(seqName);
2749  }
2750 
2751  for(std::size_t i = 0; i < seqNames.size(); ++i)
2752  {
2753  std::string seqName = seqNames[i];
2754 
2755  std::string sql("SELECT * FROM ");
2756  sql += seqName;
2757 
2758  std::unique_ptr<te::da::DataSet> result(query(sql));
2759 
2760  if(result->moveNext() == false)
2761  throw Exception((boost::format(TE_TR("There is no information about the sequence \"%1%\"!")) % seqName).str());
2762 
2763  unsigned int seqId = getDataSetId(seqName);
2764 
2765  te::da::Sequence* seq = new te::da::Sequence(seqName, 0, 0, nullptr, seqId);
2766 
2767  // Check if the sequence is cycled
2768  if(result->getBool(8))
2769  seq->setAsCycle();
2770  else
2771  seq->setAsNoCycle();
2772 
2773  seq->setCachedValues(result->getInt64(6)); // "cache_value"
2774  seq->setIncrement(result->getInt64(3)); // "increment_by";
2775  seq->setMaxValue(result->getInt64(4)); // "max_value";
2776  seq->setMinValue(result->getInt64(5)); // "min_value";
2777 
2778  seqs.push_back(seq);
2779  }
2780 
2781  return seqs;
2782 }
virtual void setName(const std::string &name)
It sets the constraint name.
Definition: Constraint.h:126
std::unique_ptr< te::da::DataSetType > getDataSetType(const std::string &name)
It gets information about the given dataset.
void setTitle(const std::string &title)
It sets a human descriptive title for the DataSetType.
Definition: DataSetType.h:137
Property * getProperty(std::size_t i) const
It returns the i-th property.
void getDatabaseInfo(std::string &currentSchema)
It retrieves some information about the database such as the default schema used when no one is provi...
boost::int64_t getMinValue() const
It returns the minimum value that the sequence can generate.
void getIndexes(te::da::DataSetType *dt)
It gets all the indexes of the given dataset and adds them to the dummy schema.
Geometric property.
void set(te::rst::Grid *grid)
Sets the definition of the raster grid support.
bool isInTransaction() const
It returns true if a transaction is in progress, otherwise, it returns false.
void update(const std::string &datasetName, te::da::DataSet *dataset, const std::vector< std::size_t > &properties, const te::da::ObjectIdSet *oids, const std::map< std::string, std::string > &options, std::size_t limit=0)
It updates the contents of a dataset for the set of data items.
void add(te::dt::Property *p)
It adds a property to the list of properties of the primary key.
Definition: PrimaryKey.h:123
GeomType
Each enumerated type is compatible with a Well-known Binary (WKB) type code.
boost::ptr_vector< te::dt::Property > getProperties(const std::string &datasetName)
It retrieves the properties of the dataset.
void SplitTableName(const std::string &fullName, const std::string *defaultSchema, std::string &schemaName, std::string &tableName)
void setMaxValue(boost::int64_t value)
It sets the maximum value that the sequence can generate.
void setSRID(int srid)
It sets the spatial reference system identifier associated to this property.
void setGeometryType(GeomType t)
It sets the geometry subtype.
A visitor for building an SQL statement using PostGIS dialect.
An atomic property like an integer or double.
std::unique_ptr< te::da::ForeignKey > getForeignKey(const std::string &datasetName, const std::string &name)
It retrieves the foreign key from the given dataset.
std::string GetBindableUpdateSQL(const std::vector< te::dt::Property * > &properties)
Given a list of properties it constructs a string with bindable parameters that can be used inside an...
void getRasterInfo(const std::string &datasetName, te::rst::RasterProperty *rp)
It loads information about a given raster column.
te::dt::Property * getOwner() const
It returns the property type associated to the sequence.
A class that control the use of connection to a PostgreSQL database.
std::vector< std::string > getDataSetNames()
It It gets the dataset names available in the data source.
bool uniqueKeyExists(const std::string &datasetName, const std::string &name)
It checks if a unique key with the given name exists in the dataset.
std::string Convert2LCase(const std::string &value)
It converts a string to lower case.
Definition: StringUtils.h:202
void setAsNoCycle()
It sets the sequence as not cycled (it can&#39;t wrap).
#define TE_UNKNOWN_SRS
A numeric value to represent a unknown SRS identification in TerraLib.
boost::int64_t getMaxValue() const
It returns the maximum value that the sequence can generate.
void addForeignKey(const std::string &datasetName, te::da::ForeignKey *fk)
It adds a foreign key constraint to a dataset.
A raster band description.
Definition: BandProperty.h:61
Base exception class for plugin module.
A class that models the description of a dataset.
Definition: DataSetType.h:72
std::vector< std::string > getUniqueKeyNames(const std::string &datasetName)
It gets the unique key names of the given dataset.
void addPrimaryKey(const std::string &datasetName, te::da::PrimaryKey *pk)
It adds a primary key constraint to the dataset schema.
std::size_t getNumberOfUniqueKeys() const
It returns the number of unique keys defined for the dataset type.
Definition: DataSetType.h:269
void useTimer(bool flag)
Used to define if task use progress timer information.
const std::string & GetGeometryName(te::gm::GeomType t)
It returns the geometry names as usual for PostGIS.
CheckConstraint * getCheckConstraint(std::size_t i) const
It returns the i-th check-constraint associated to the dataset type.
Definition: DataSetType.h:354
GeomType getGeomTypeId() const _NOEXCEPT_OP(true)
It returns the geometry subclass type identifier.
struct pg_result PGresult
void addUniqueKey(const std::string &datasetName, te::da::UniqueKey *uk)
It adds a unique key constraint to the dataset.
This class can be used to inform the progress of a task.
Definition: TaskProgress.h:53
std::string getDataSetName(unsigned int id)
It looks for a dataset name with the given id in the PostgreSQL.
unsigned int getRasterTypeId() const
It returns the type id associated to the PostGIS Raster type.
A visitor for building an SQL statement using PostGIS dialect.
bool checkConstraintExists(const std::string &datasetName, const std::string &name)
It checks if a check-constraint with the given name exists in the data source.
const std::string & getCurrentSchema() const
It returns the current schema associated to the database connection, or NULL, if none is set...
PrimaryKey * getPrimaryKey() const
It returns the primary key associated to the dataset type.
Definition: DataSetType.h:214
virtual void setId(unsigned int id)
It sets the constraint identifier.
Definition: Constraint.h:112
An utility class to coordinate transactions.
Implementation of a connected dataset for the PostGIS driver.
boost::int64_t getCachedValues() const
It returns how many sequence numbers are preallocated.
SpatialRelation
Spatial relations between geometric objects.
void dropForeignKey(const std::string &datasetName, const std::string &fkName)
It removes the foreign key constraint from the dataset schema.
It describes a sequence (a number generator).
void add(te::dt::Property *p)
It adds the property to the list of properties of the index.
virtual ReturnType accept(VisitorType &guest) const =0
It call the visit method from the guest object.
te::gm::Envelope * GetEnvelope(const char *str)
It converts the pgType to a valid TerraLib data type.
A class that implements a connection to a PostgreSQL database.
TEDATAACCESSEXPORT std::string GetSQLValueNames(const DataSetType *dt)
static te::dt::Date ds(2010, 01, 01)
Implementation of a connected dataset for the PostGIS driver.
A class that describes a check constraint.
void commit()
It commits the transaction.
An abstract class for data providers like a DBMS, Web Services or a regular file. ...
double m_noDataValue
Value to indicate elements where there is no data, default is std::numeric_limits<double>::max().
Definition: BandProperty.h:136
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
int m_connectionId
The connection id used by this transactor.
bool m_getConstraints
Flag that defines if the method getConstraints must be called.
std::unique_ptr< te::da::DataSet > getConstraints(const std::string &datasetName, char conType= '\0')
It gets the dataset containing information about one of the constraints(primary, foreign or unique ke...
int GetCoordDimension(GeomType t)
It returns the number of measurements or axes needed to describe a position in a coordinate system...
void execute(const std::string &command)
It executes the given SQL command and throws away the result.
std::unique_ptr< te::dt::Property > getProperty(const std::string &datasetName, const std::string &name)
It retrieves the property with the given name from the dataset.
It models a property definition.
Definition: Property.h:59
bool isActive() const
Verify if the task is active.
Raster property.
Transactor(DataSource *ds, const int &connectionId=-1)
Constructor.
void remove(const std::string &datasetName, const te::da::ObjectIdSet *oids=0)
It removes all the informed items from the dataset.
std::vector< te::da::Sequence * > getSequences()
It gets information about all the sequences in the datasource.
This is an abstract class that models a query expression.
const std::vector< te::dt::Property * > & getProperties() const
It returns the properties that take part of the primary key.
Definition: PrimaryKey.h:109
void dropCheckConstraint(const std::string &datasetName, const std::string &name)
It removes the check constraint from the dataset.
void commit()
It commits the transaction.
void renameDataSet(const std::string &name, const std::string &newName)
It renames a dataset.
Index * getIndex(std::size_t i) const
It returns the i-th index associated to the dataset type.
Definition: DataSetType.h:428
void setTotalSteps(int value)
Set the task total stepes.
void setId(unsigned int id)
It sets the property identifier.
Definition: Property.h:118
void changePropertyDefinition(const std::string &datasetName, const std::string &propName, te::dt::Property *newProp)
virtual te::dt::AbstractData * clone() const
It clones the linestring.
void optimize(const std::map< std::string, std::string > &opInfo)
For some data access drivers, this method will perform some operations to optimize the data storage...
bool dataSetExists(const std::string &name)
It checks if a dataset with the given name exists in the data source.
void setIncrement(boost::int64_t n)
It sets the increment value.
virtual std::size_t size() const =0
It returns the collection size, if it is known.
te::da::DataSource * getDataSource() const
It returns the parent data source of the transactor.
virtual bool moveNext()=0
It moves the internal pointer to the next item of the collection.
unsigned int unsigned int nCols
AccessPolicy
Supported data access policies (can be used as bitfield).
TraverseType
A dataset can be traversed in two ways:
void dropDataSet(const std::string &name)
It removes the dataset schema from the data source.
An exception class for the PostGIS driver.
~Transactor()
The destructor will automatically release the connection to the pool.
std::size_t getNumberOfForeignKeys() const
It returns the number of foreign keys defined for the dataset type.
Definition: DataSetType.h:467
void getGeometryInfo(const std::string &datasetName, te::gm::GeometryProperty *gp)
It loads information about a given geometry column.
void add(te::rst::BandProperty *b)
It adds a new band information to the property.
const std::string & getExpression() const
It returns the check constraint expression.
void setOnDeleteAction(FKActionType a)
It sets the action to be performed when a referenced element value in the referenced DataSetType is b...
Definition: ForeignKey.h:174
void setCachedValues(boost::int64_t value)
It sets how many sequence numbers are to be preallocated.
int getSRID() const
It returns the spatial reference system identifier associated to this property.
virtual int getPropertyDataType(std::size_t i) const =0
It returns the underlying data type of the property at position pos.
std::size_t getNumberOfItems(const std::string &datasetName)
It retrieves the number of items of the given dataset.
An Envelope defines a 2D rectangular region.
std::unique_ptr< te::da::PrimaryKey > getPrimaryKey(const std::string &datasetName)
It retrieves the primary key of the dataset.
void add(te::dt::Property *p)
It adds a property to the foreign key constraint.
Definition: ForeignKey.h:112
This class represents a set of unique ids created in the same context. i.e. from the same data set...
Definition: ObjectIdSet.h:55
virtual void visit(const Expression &visited)
std::unique_ptr< te::da::Index > getIndex(const std::string &datasetName, const std::string &name)
It gets the index with the given name from the dataset.
void dropPrimaryKey(const std::string &datasetName)
It removes the primary key constraint from the dataset schema.
void Convert2PostGIS(const te::gm::Envelope *e, int srid, std::string &output)
It converts the envelope into a PostGIS BOX3D.
std::string escape(const std::string &value)
It escapes a string for using in commands and queries.
Property * getPropertyById(unsigned int id) const
It searches for a property with the given ID.
int m_blkw
Block width (pixels).
Definition: BandProperty.h:143
void DataSet()
static te::dt::DateTime d(2010, 8, 9, 15, 58, 39)
GeomType getGeometryType() const
It returns the geometry subtype allowed for the property.
static te::dt::TimeDuration dt(20, 30, 50, 11)
std::size_t getNumberOfProperties(const std::string &datasetName)
It gets the number of properties of the given dataset.
void createDataSet(te::da::DataSetType *dt, const std::map< std::string, std::string > &options)
It creates the dataset schema definition in the target data source.
std::size_t getNumberOfIndexes() const
It returns the number of indexes defined for the dataset type.
Definition: DataSetType.h:391
DataSetType * getReferencedDataSetType() const
It returns the referenced DataSetType of this foreign key constraint.
Definition: ForeignKey.h:153
std::size_t getNumberOfDataSets()
It retrieves the number of data sets available in the data source.
std::unique_ptr< te::da::UniqueKey > getUniqueKey(const std::string &datasetName, const std::string &name)
It gets the unique key in the dataset with the given name.
te::gm::Polygon * p
It models a foreign key constraint for a DataSetType.
Definition: ForeignKey.h:50
void pulse()
Calls setCurrentStep() function using getCurrentStep() + 1.
virtual std::string getAsString(std::size_t i, int precision=0) const
Method for retrieving a data value as a string plain representation.
A base class for values that can be retrieved from the data access module.
Definition: AbstractData.h:57
void addRefProperty(te::dt::Property *p)
It adds a reference property (on the referenced DataSetType) of this foreign key constraint.
Definition: ForeignKey.h:137
const te::da::SQLDialect * getDialect() const
It returns the data source SQL dialect, if there is one.
It describes a unique key (uk) constraint.
Definition: UniqueKey.h:53
void setAssociatedIndex(Index *idx)
It sets the associated index.
Definition: UniqueKey.h:138
Property * getParent() const
It returns the parent of this property, or NULL, if it doesn&#39;t have one.
Definition: Property.h:168
std::size_t size() const
It returns the number of properties of the CompositeProperty.
TEDATAACCESSEXPORT std::vector< int > GetPropertyDataTypes(const te::da::DataSet *dataset)
Utility functions for the data access module.
void addIndex(const std::string &datasetName, te::da::Index *idx, const std::map< std::string, std::string > &options)
It adds an index to the dataset.
Geometry is the root class of the geometries hierarchy, it follows OGC and ISO standards.
A class that implements a connection to a PostgreSQL database.
void getPropertyId(te::dt::Property *p)
It sets the property id from the PostgreSQL system.
A Select models a query to be used when retrieving data from a DataSource.
Definition: Select.h:65
std::unique_ptr< te::da::DataSet > query(const te::da::Select &q, te::common::TraverseType travType=te::common::FORWARDONLY, bool connected=false, const te::common::AccessPolicy accessPolicy=te::common::RAccess)
It executes a query that may return some data using a generic query. A dataset can be connected or di...
std::string getGeometryTypeName(te::gm::GeomType type)
It gets the datasource geometry type name equivalent to terralib.
void add(const std::string &datasetName, te::da::DataSet *d, const std::map< std::string, std::string > &options, std::size_t limit=0, bool enableProgress=true)
It adds data items to the dataset in the data source.
bool isCycled() const
It returns true if the sequence can wrap, otherwise it returns false.
int getType() const
It returns the property data type.
Definition: Property.h:161
void add(Constraint *c)
It adds a new constraint.
void rollBack()
It aborts the transaction. Any changes will be rolled-back.
A dataset is the unit of information manipulated by the data access module of TerraLib.
void addProperty(const std::string &datasetName, te::dt::Property *p)
It adds a new property to the dataset schema.
const std::vector< te::dt::Property * > & getProperties() const
It returns the properties that form the unique key.
Definition: UniqueKey.h:110
Connection * getConnection(const int &id=-1) const
It returns the underlying connection.
bool m_isInTransaction
Tells if there is a transaction in progress.
bool sequenceExists(const std::string &name)
It checks if a sequence with the given name exists in the data source.
void cloneDataSet(const std::string &name, const std::string &cloneName, const std::map< std::string, std::string > &options)
It clones the dataset in the data source.
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.
void setAssociatedIndex(Index *idx)
It sets the associated index.
Definition: PrimaryKey.h:130
Connection * getConnection(int id=-1)
It returns a connection from the pool.
ForeignKey * getForeignKey(std::size_t i) const
It returns the i-th foreign key associated to the dataset type.
Definition: DataSetType.h:480
void setOnUpdateAction(FKActionType a)
It sets the action to be performed when a referenced element value in the referenced DataSetType is b...
Definition: ForeignKey.h:188
std::string GetSpatialRelation(te::gm::SpatialRelation rel)
It converts the spatial relationship to PostGIS dialect.
std::unique_ptr< te::da::PreparedQuery > getPrepared(const std::string &qName=std::string(""))
It creates a prepared query object that may be used for query commands (select, insert, update and delete) that are used repeatedly.
const std::vector< te::dt::Property * > & getProperties() const
It returns the properties that take part of the index.
std::size_t getNumberOfCheckConstraints() const
It returns the number of check-constraints defined over the dataset type.
Definition: DataSetType.h:331
std::vector< std::string > getIndexNames(const std::string &datasetName)
It gets the index names of the given dataset.
bool indexExists(const std::string &datasetName, const std::string &name)
It checks if an index with the given name exists in the dataset.
It describes a primary key (pk) constraint.
Definition: PrimaryKey.h:52
int getConnectionID() const
It returns the underlying connection ID.
void renameProperty(const std::string &datasetName, const std::string &propertyName, const std::string &newPropertyName)
It renames a property of the given dataset.
void setExpression(const std::string &e)
It sets the check constraint expression.
std::unique_ptr< te::gm::Envelope > getExtent(const std::string &datasetName, const std::string &propertyName)
It retrieves the bounding rectangle of the spatial property for the given dataset.
std::string getFullName(const std::string &name)
It gets the full name of the given name including the schema name.
An static class with global definitions.
te::dt::Property * Convert2TerraLib(unsigned int attNum, const char *attName, unsigned int attType, bool attNotNull, const char *fmt, bool attHasDefault, const char *attDefValue, unsigned int pgisGeomTypeOid, unsigned int pgisRasterTypeOid)
It creates a PropertyType from a PostgreSQL attribute description.
void execute(const te::da::Query &command)
It executes the specified command using a generic query representation.
unsigned int getGeomTypeId()
It will check in the database catalog the number that identifies the PostGIS Geometry type...
std::vector< std::string > getSequenceNames()
It gets the sequence names available in the data source.
std::unique_ptr< te::da::Sequence > getSequence(const std::string &name)
It gets the sequence with the given name in the data source.
boost::int64_t getIncrement() const
It returns the increment value.
void dropSequence(const std::string &name)
It removes the sequence from the data source.
boost::int64_t getStartValue() const
It returns the initial value of the sequence.
bool propertyExists(const std::string &datasetName, const std::string &name)
It checks if a property with the given name exists in the dataset.
Expression * getExpressionByInClause(const std::string source="") const
A visitor for building an SQL statement from a given Query hierarchy.
FKActionType getOnUpdateAction() const
It returns the action performed when a referenced element value in the referenced DataSetType is bein...
Definition: ForeignKey.h:181
void dropProperty(const std::string &datasetName, const std::string &name)
It removes a property from the given dataset.
unsigned int getRasterTypeId()
It will check in the database catalog the number that identifies the PostGIS Raster type...
std::vector< std::string > getPropertyNames(const std::string &datasetName)
It gets the property names of the given dataset.
A class that represents the IN operator.
Definition: In.h:52
void addCheckConstraint(const std::string &datasetName, te::da::CheckConstraint *cc)
It adds a check constraint to the dataset.
void setAsCycle()
It sets the sequence as cycled (it can wrap).
te::da::IndexType GetIndexType(const char *t)
It converts the PostgreSQL index string to a TerraLib index type.
std::string GetBoxSpatialRelation(te::gm::SpatialRelation rel)
It converts the spatial relationship to PostGIS dialect.
void setReferencedDataSetType(DataSetType *refDt)
It sets the referenced DataSetType of this foreign key constraint.
Definition: ForeignKey.h:160
std::vector< std::string > getForeignKeyNames(const std::string &datasetName)
It gets the foreign key names of the given dataset.
te::da::FKActionType GetAction(char a)
It converts the PostgreSQL foreign key modifier to a TerraLib data type.
void dropIndex(const std::string &datasetName, const std::string &idxName)
It removes the index from the dataset schema.
A template for atomic data types (integers, floats, strings and others).
Definition: SimpleData.h:59
std::string Convert2String(boost::int16_t value)
It converts a short integer value to a string.
Definition: StringUtils.h:56
int m_blkh
Block height (pixels).
Definition: BandProperty.h:144
A dataset is the unit of information manipulated by the data access module of TerraLib.
virtual const std::string & getName() const
It returns the constraint name.
Definition: Constraint.h:119
virtual std::size_t getNumProperties() const =0
It returns the number of properties that composes an item of the dataset.
virtual std::string getPropertyName(std::size_t i) const =0
It returns the property name at position pos.
PGresult * query(const std::string &query)
It queries the database.
A class that implements a connection pool for PostGIS.
const std::string & getName() const
It returns the sequence name.
std::vector< std::string > getCheckConstraintNames(const std::string &datasetName)
It gets the check constraint names of the given dataset.
A rectified grid is the spatial support for raster data.
Definition: raster/Grid.h:68
IndexType getIndexType() const
It gets the index type.
A class that implements a prepared query for PostgreSQL data access driver.
bool foreignKeyExists(const std::string &datasetName, const std::string &name)
It checks if a foreign key with the given name exists in the data source.
const std::vector< te::dt::Property * > & getProperties() const
It returns the properties that take part of the foreign key constraint.
Definition: ForeignKey.h:103
std::unique_ptr< te::da::CheckConstraint > getCheckConstraint(const std::string &datasetName, const std::string &name)
It gets the check constraint of the dataset with the given name.
void addSequence(te::da::Sequence *sequence)
It creates a new sequence in the data source.
void begin()
It starts a new transaction.
virtual bool moveFirst()=0
It moves the internal pointer to the first item in the collection.
const std::vector< te::dt::Property * > & getReferencedProperties() const
It returns the referenced properties (on the referenced DataSetType) of this foreign key constraint...
Definition: ForeignKey.h:128
std::unique_ptr< te::da::DataSet > getPropertiesInfo(const std::string &datasetName)
It gets the information about the given dataset.
Implementation of the data source for the PostGIS driver.
boost::int64_t getLastGeneratedId()
It returns the last id generated by an insertion command.
A class that implements a prepared query for PostgreSQL data access driver.
void cancel()
It requests that the data source stop the processing of the current command.
void setId(unsigned int id)
It sets the sequence identifier.
#define PGIS_UNKNOWN_SRS
A numeric value to represent a unknown SRS identification in PostGIS.
const int m_fetchSize
The size of cursor fetch.
A Query is independent from the data source language/dialect.
Definition: Query.h:46
It describes an index associated to a DataSetType.
bool hasDataSets()
It checks if the data source has any dataset.
bool primaryKeyExists(const std::string &datasetName, const std::string &name)
It checks if a primary key exists in the dataset.
void SwapBytes(T &v)
It swaps the bytes in local.
unsigned int getId() const
It returns the property identifier.
Definition: Property.h:109
DataSource * m_ds
The PostGIS data source associated to this transactor.
std::string GetSQLBindValues(std::size_t nproperties)
UniqueKey * getUniqueKey(std::size_t i) const
It returns the i-th unique key.
Definition: DataSetType.h:294
void setMinValue(boost::int64_t value)
It sets the minimum value that the sequence can generate.
bool SetColumnDef(std::string &s, const std::string &tname, const te::dt::SimpleProperty *p, bool justDataType=false)
unsigned int getDataSetId(const std::string &datasetName)
It looks for the dataset id in the PostgreSQL system.
std::unique_ptr< te::da::DataSet > getDataSet(const std::string &name, te::common::TraverseType travType=te::common::FORWARDONLY, bool isConnected=false, const te::common::AccessPolicy accessPolicy=te::common::RAccess)
It gets the dataset identified by the given name. A dataset can be connected or disconnected. A connected dataset, after its creation through the data source transactor, continues to depend on the connection given by its associated data source. Differently, a disconnected dataset, after its creation, no more depends of the connection given by the data source, and it continues to live after the connection has been released to the data source.
std::unique_ptr< te::da::BatchExecutor > getBatchExecutor()
It creates a batch command executor.
unsigned int getGeomTypeId() const
It returns the type id associated to the PostGIS Geometry type.
void dropUniqueKey(const std::string &datasetName, const std::string &name)
It removes the unique key constraint from the dataset.
FKActionType getOnDeleteAction() const
It returns the action performed when a referenced element value in the referenced DataSetType is bein...
Definition: ForeignKey.h:167
const std::string & getName() const
It returns the property name.
Definition: Property.h:127
const std::string & getName() const
It returns the index name.