All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
DataSourceCatalogLoader.cpp
Go to the documentation of this file.
1 /* Copyright (C) 2009-2013 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/sqlite/DataSourceCatalogLoader.cpp
22 
23  \brief DataSourceCatalogLoader manages metadata information for the TerraLib SQLite Data Access Driver.
24 */
25 
26 // TerraLib
27 #include "../common/Translator.h"
28 #include "../dataaccess/dataset/DataSetType.h"
29 #include "../dataaccess/dataset/ForeignKey.h"
30 #include "../dataaccess/dataset/Index.h"
31 #include "../dataaccess/dataset/PrimaryKey.h"
32 #include "../dataaccess/dataset/UniqueKey.h"
33 #include "../datatype/Property.h"
34 #include "../geometry/Envelope.h"
35 #include "../geometry/Geometry.h"
36 #include "../geometry/GeometryProperty.h"
38 #include "DataSourceTransactor.h"
39 #include "FwDataSet.h"
40 #include "Utils.h"
41 
42 // Boost
43 #include <boost/algorithm/string/case_conv.hpp>
44 #include <boost/format.hpp>
45 
47 {
48  public:
49 
50  Impl(DataSourceTransactor* parent);
51 
53 };
54 
56  : m_parent(parent)
57 {
58 }
59 
61  : m_pImpl(0)
62 {
63  m_pImpl = new Impl(parent);
64 }
65 
67 {
68  delete m_pImpl;
69 }
70 
72 {
73  std::vector<std::string> datasets;
74 
75  std::auto_ptr<te::da::DataSet> tables(getDataSets());
76 
77  while(tables->moveNext())
78  {
79  std::string name = tables->getString(1);
80  datasets.push_back(name);
81  }
82 
83  return datasets;
84 }
85 
86 std::auto_ptr<te::da::DataSet> te::sqlite::DataSourceCatalogLoader::getDataSets()
87 {
88  std::string sql("SELECT rowid, name, tbl_name, type FROM sqlite_master "
89  "WHERE type IN ('table', 'view') "
90  "AND name NOT LIKE 'sqlite_%'"
91  "AND name NOT LIKE 'idx_%'");
92 
93  std::vector<std::string> ommitTables;
94 
95  GetHiddenTables(m_pImpl->m_parent->getDataSource(), ommitTables);
96 
97  sql += " AND name NOT IN ('SpatialIndex'";
98 
99  for(std::size_t i = 0; i < ommitTables.size(); ++i)
100  {
101  sql += ", '";
102  sql += ommitTables[i];
103  sql += "'";
104  }
105 
106  sql += ")";
107 
108  return std::auto_ptr<te::da::DataSet>(m_pImpl->m_parent->query(sql));
109 }
110 
112 {
113  std::auto_ptr<te::da::DataSet> datasets(getDataSets());
114 
115  return datasets->moveNext();
116 }
117 
119 {
120  std::string sql("SELECT rowid FROM sqlite_master WHERE name = '");
121  sql += name;
122  sql += "'";
123 
124  std::auto_ptr<te::da::DataSet> table(m_pImpl->m_parent->query(sql));
125 
126  return table->moveNext();
127 }
128 
130 {
131 
132  std::string sql("SELECT rowid, type FROM sqlite_master WHERE name = '");
133  sql += datasetName;
134  sql += "'";
135 
136  std::auto_ptr<te::da::DataSet> tinfo(m_pImpl->m_parent->query(sql));
137 
138  if(!tinfo->moveNext())
139  throw te::common::Exception(TR_COMMON("Could not find table/view in sqlite_master table!"));
140 
141  unsigned int tid = tinfo->getInt32(0);
142 
143  int tcategory = Convert2TerraLibCategory(tinfo->getString(1));
144 
145 // get attribute list
146  sql = "PRAGMA table_info(";
147  sql += datasetName;
148  sql += ")";
149 
150  std::auto_ptr<te::da::DataSet> attributes(m_pImpl->m_parent->query(sql));
151 
152  std::auto_ptr<te::da::PrimaryKey> pk(new te::da::PrimaryKey(datasetName, 0, 0));
153 
154  std::auto_ptr<te::da::DataSetType> dt(new te::da::DataSetType(datasetName, tid));
155 
156  dt->setTitle(datasetName);
157 
158  dt->setCategory(tcategory);
159 
160  while(attributes->moveNext())
161  {
162  int col = attributes->getInt32(0);
163 
164  std::string colName = attributes->getString(1);
165 
166  std::string colType = attributes->getString(2);
167 
168  bool required = attributes->getInt32(3) != 0;
169 
170  std::string* defaultValue = attributes->isNull(4) ? 0 : new std::string(attributes->getString(4));
171 
172  bool isPK = attributes->getInt32(5) != 0;
173 
174  te::dt::Property* p = Convert2TerraLib(col, colName, colType, required, defaultValue);
175 
176  dt->add(p);
177 
178  if(isPK)
179  pk->add(p);
180 
181  if(p->getType() == te::dt::GEOMETRY_TYPE)
182  {
183  te::gm::GeometryProperty* gp = static_cast<te::gm::GeometryProperty*>(p);
184  getGeometryInfo(datasetName, gp);
185  }
186  }
187 
188 // if we have added a property to the primary we must add the primary key to the dataset type otherwise (if it is empty) just release it!
189  if(!pk->getProperties().empty())
190  dt->setPrimaryKey(pk.release());
191 
192  getIndexes(dt.get());
193  getUniqueKeys(dt.get());
194  //getCheckConstraints(dt.get());
195 
196  return dt.release();
197 }
198 
200 {
201  assert(gp);
202 
203  std::auto_ptr<te::da::DataSet> ftable(0);
204 
205  ftable = getGeometryInfo(datasetName, gp->getName());
206 
207  if(!ftable->moveNext())
208  return;
209 
210  int gtype = ftable->getInt32(0);
211 
212  //int coorddim = ftable->getInt32(1);
213 
214  te::gm::GeomType t = static_cast<te::gm::GeomType>(gtype);
215 
216  gp->setGeometryType(t);
217 
218  int srid = ftable->getInt32(2);
219 
220  gp->setSRID(srid);
221 
222  //bool hasSPIDX = ftable->getInt32(3) != 0;
223 }
224 
225 std::auto_ptr<te::da::DataSet> te::sqlite::DataSourceCatalogLoader::getGeometryInfo(const std::string& tableName, const std::string& geomColName)
226 {
227  std::string sql = "SELECT geometry_type, coord_dimension, srid, spatial_index_enabled "
228  "FROM geometry_columns "
229  "WHERE f_table_name = '";
230  sql += boost::to_lower_copy(tableName);
231 
232  if(!geomColName.empty())
233  {
234  sql += "' AND f_geometry_column = '";
235  sql += boost::to_lower_copy(geomColName);
236  }
237 
238  sql += "'";
239 
240  return m_pImpl->m_parent->query(sql);
241 }
242 
243 boost::ptr_vector<te::dt::Property> te::sqlite::DataSourceCatalogLoader::getProperties(const std::string& datasetName)
244 {
245  boost::ptr_vector<te::dt::Property> pvec;
246 
247  std::string sql = "PRAGMA table_info(";
248  sql += datasetName;
249  sql += ")";
250 
251  std::auto_ptr<te::da::DataSet> attributes(m_pImpl->m_parent->query(sql));
252 
253  while(attributes->moveNext())
254  {
255  int col = attributes->getInt32(0);
256 
257  std::string colName = attributes->getString(1);
258 
259  std::string colType = attributes->getString(2);
260 
261  bool required = attributes->getInt32(3) != 0;
262 
263  std::string* defaultValue = attributes->isNull(4) ? 0 : new std::string(attributes->getString(4));
264 
265  te::dt::Property* p = Convert2TerraLib(col, colName, colType, required, defaultValue);
266 
267  pvec.push_back(p);
268 
269  if(p->getType() == te::dt::GEOMETRY_TYPE)
270  {
271  te::gm::GeometryProperty* gp = static_cast<te::gm::GeometryProperty*>(p);
272  getGeometryInfo(datasetName, gp);
273  }
274  }
275 
276  return pvec;
277 }
278 
280 {
281 // get attribute list
282  std::string sql = "PRAGMA table_info(";
283  sql += dt->getName();
284  sql += ")";
285 
286  std::auto_ptr<te::da::DataSet> attributes(m_pImpl->m_parent->query(sql));
287 
288  std::auto_ptr<te::da::PrimaryKey> pk(new te::da::PrimaryKey(dt->getName(), 0, 0));
289 
290  while(attributes->moveNext())
291  {
292  bool isPK = attributes->getInt32(5) != 0;
293 
294  if(isPK)
295  {
296  int col = attributes->getInt32(0);
297  te::dt::Property* p = dt->getProperty(col);
298  pk->add(p);
299  }
300  }
301 
302 // if we have added a property to the primary we must add the primary key to the dataset type otherwise (if it is empty) just release it!
303  if(pk->getProperties().empty())
304  {
305  dt->setPrimaryKey(0);
306  }
307  else
308  {
309  dt->setPrimaryKey(pk.release());
310  }
311 }
312 
314 {
315  dt->clearUniqueKeys();
316 
317  std::string sql("PRAGMA index_list(");
318  sql += dt->getName();
319  sql += ")";
320 
321  std::auto_ptr<te::da::DataSet> indexes(m_pImpl->m_parent->query(sql));
322 
323  while(indexes->moveNext())
324  {
325  int idxId = indexes->getInt32(0);
326 
327  std::string idxName = indexes->getString(1);
328 
329  bool isUnique = indexes->getInt32(2) != 0;
330 
331  if(isUnique && (idxName.find("sqlite_autoindex_") != std::string::npos))
332  continue;
333 
334  if(isUnique)
335  getUniqueKey(dt, static_cast<unsigned int>(idxId), idxName);
336  }
337 }
338 
340  int idxId,
341  const std::string& idxName)
342 {
343  std::string sql("PRAGMA index_info(");
344  sql += idxName;
345  sql += ")";
346 
347  std::auto_ptr<te::da::DataSet> indexInfo(m_pImpl->m_parent->query(sql));
348 
349  std::auto_ptr<te::da::UniqueKey> uk(new te::da::UniqueKey(dt->getName() + "." + idxName, 0, idxId));
350 
351  while(indexInfo->moveNext())
352  {
353  int col = indexInfo->getInt32(1);
354  te::dt::Property* p = dt->getProperty(col);
355  uk->add(p);
356  }
357 
358 // we need to check if uk is instead a primary key
359  sql = "PRAGMA table_info(";
360  sql += dt->getName();
361  sql += ")";
362 
363  std::auto_ptr<te::da::DataSet> attributes(m_pImpl->m_parent->query(sql));
364 
365  std::size_t nMatchAttributes = 0;
366  bool mayBePK = true;
367 
368  while(mayBePK && attributes->moveNext())
369  {
370  bool isPK = attributes->getInt32(5) != 0;
371 
372  if(!isPK)
373  continue;
374 
375  int col = attributes->getInt32(0);
376  te::dt::Property* p = dt->getProperty(col);
377 
378  if(uk->has(p))
379  ++nMatchAttributes;
380  else
381  mayBePK = false; // we have find a key from pk that is not in uk!
382  }
383 
384  if(mayBePK && (nMatchAttributes == uk->getProperties().size()))
385  return; // ok! it is a pk
386 
387 //// look for an associated index
388 // const std::size_t nidxs = dt->getNumberOfIndexes();
389 //
390 // for(std::size_t i = 0; i < nidxs; ++i)
391 // {
392 // if(dt->getIndex(i)->getName() == uk->getName())
393 // {
394 // uk->setAssociatedIndex(dt->getIndex(i));
395 // break;
396 // }
397 // }
398 
399  dt->add(uk.release());
400 }
401 
403 {
404  dt->clearIndexes();
405 
406  std::string sql("PRAGMA index_list(");
407  sql += dt->getName();
408  sql += ")";
409 
410  std::auto_ptr<te::da::DataSet> indexes(m_pImpl->m_parent->query(sql));
411 
412  while(indexes->moveNext())
413  {
414  int idxId = indexes->getInt32(0);
415 
416  std::string idxName = indexes->getString(1);
417 
418  bool isUnique = indexes->getInt32(2) != 0;
419 
420  if(isUnique && (idxName.find("sqlite_autoindex_") != std::string::npos))
421  continue;
422 
423  getIndex(dt, static_cast<unsigned int>(idxId), idxName, isUnique);
424  }
425 
426  getSpatialIndexes(dt);
427 }
428 
430 {
431  const std::size_t nattrs = dt->size();
432 
433  for(std::size_t i = 0; i < nattrs; ++i)
434  {
435  if(dt->getProperty(i)->getType() != te::dt::GEOMETRY_TYPE)
436  continue;
437 
438  std::string tname = dt->getName();
439  std::string gcol = dt->getProperty(i)->getName();
440 
441  if(dt->getCategory() == te::da::VIEW_TYPE)
442  {
443  std::string sql = "SELECT f_table_name, f_geometry_column "
444  "FROM views_geometry_columns "
445  "WHERE view_name = '";
446  sql += tname;
447  sql += "' AND view_geometry = '";
448  sql += gcol;
449  sql += "'";
450 
451  std::auto_ptr<te::da::DataSet> feature(m_pImpl->m_parent->query(sql));
452 
453  if(!feature->moveNext())
454  return;
455 
456  tname = feature->getString(0);
457  gcol = feature->getString(1);
458  }
459 
460  std::auto_ptr<te::da::DataSet> ftable(getGeometryInfo(tname, gcol));
461 
462  if(!ftable->moveNext())
463  continue;
464 
465  bool hasSPIDX = ftable->getInt32(3) != 0;
466 
467  if(hasSPIDX)
468  {
469  te::da::Index* idx = new te::da::Index(dt->getName() + ".idx_" + tname + "_" + gcol, te::da::R_TREE_TYPE, dt, 0);
470  idx->add(dt->getProperty(i));
471  }
472  }
473 }
474 
476  int idxId,
477  const std::string& idxName,
478  bool isUnique)
479 {
480  std::string sql("PRAGMA index_info(");
481  sql += idxName;
482  sql += ")";
483 
484  std::auto_ptr<te::da::DataSet> indexInfo(m_pImpl->m_parent->query(sql));
485 
486  std::auto_ptr<te::da::Index> idx(new te::da::Index(dt->getName() + "." + idxName, te::da::B_TREE_TYPE, 0, idxId));
487 
488  while(indexInfo->moveNext())
489  {
490  int col = indexInfo->getInt32(1);
491  te::dt::Property* p = dt->getProperty(col);
492  idx->add(p);
493  }
494 
495  if(isUnique)
496  {
497 // look for an associated unique-key
498  const std::size_t nuks = dt->getNumberOfUniqueKeys();
499 
500  for(std::size_t i = 0; i < nuks; ++i)
501  {
502  if(dt->getUniqueKey(i)->getName() == idx->getName())
503  {
504  dt->getUniqueKey(i)->setAssociatedIndex(idx.get());
505  break;
506  }
507  }
508 
509 // look for an associated primary-key
510  if(dt->getPrimaryKey() && (dt->getPrimaryKey()->getName() == idx->getName()))
511  dt->getPrimaryKey()->setAssociatedIndex(idx.get());
512  }
513 
514  dt->add(idx.release());
515 }
516 
517 te::gm::Envelope* te::sqlite::DataSourceCatalogLoader::getExtent(const std::string& tableName, const std::string& geomColName)
518 {
519 // TODO: veificar se a tabela possui um indice espacial
520  std::string sql("SELECT MIN(xmin), MIN(ymin), MAX(xmax), MAX(ymax) ");
521  sql += "FROM idx_";
522  sql += tableName;
523  sql += "_";
524  sql += geomColName;
525 
526  std::auto_ptr<te::da::DataSet> result(m_pImpl->m_parent->query(sql));
527 
528  if(result->moveNext() == false)
529  throw te::common::Exception((boost::format(TR_COMMON("Could not get a MBR for table/view: %1%!")) % tableName).str());
530 
531  double xmin = result->getDouble(0);
532  double ymin = result->getDouble(1);
533  double xmax = result->getDouble(2);
534  double ymax = result->getDouble(3);
535 
536  return new te::gm::Envelope(xmin, ymin, xmax, ymax);
537 }
538 
void setGeometryType(GeomType t)
It sets the geometry subtype.
It describes an index associated to a DataSetType.
Definition: Index.h:54
This class is designed to declare objects to be thrown as exceptions by TerraLib. ...
Definition: Exception.h:58
Property * getProperty(std::size_t i) const
It returns the i-th property.
std::size_t size() const
It returns the number of properties of the CompositeProperty.
An implementation of DataSourceTransactor class for the TerraLib SQLite Data Access Driver...
void getIndex(te::da::DataSetType *dt, int idxId, const std::string &idxName, bool isUnique)
It describes a primary key (pk) constraint.
Definition: PrimaryKey.h:52
const std::string & getName() const
It returns the property name.
Definition: Property.h:126
void add(Constraint *c)
It adds a new constraint.
UniqueKey * getUniqueKey(std::size_t i) const
It returns the i-th unique key.
Definition: DataSetType.h:294
te::da::DataSetType * getDataSetType(const std::string &datasetName)
void clearIndexes()
It removes all indexes from the dataset type.
int Convert2TerraLibCategory(const std::string &category)
Definition: Utils.cpp:522
void setPrimaryKey(PrimaryKey *pk)
It sets the primary key constraint.
std::auto_ptr< te::da::DataSet > getDataSets()
void getUniqueKeys(te::da::DataSetType *dt)
void getPrimaryKey(te::da::DataSetType *dt)
std::vector< std::string > getDataSetNames()
void getGeometryInfo(const std::string &datasetName, te::gm::GeometryProperty *gp)
void getIndexes(te::da::DataSetType *dt)
It describes a unique key (uk) constraint.
Definition: UniqueKey.h:53
GeomType
Each enumerated type is compatible with a Well-known Binary (WKB) type code.
Definition: Enums.h:41
Utility functions for the TerraLib SQLite Data Access driver.
void setAssociatedIndex(Index *idx)
It sets the associated index.
Definition: PrimaryKey.h:130
virtual const std::string & getName() const
It returns the constraint name.
Definition: Constraint.h:119
void add(te::dt::Property *p)
It adds the property to the list of properties of the index.
Definition: Index.h:197
#define TR_COMMON(message)
It marks a string in order to get translated. This is the mark used in the Common module of TerraLib...
Definition: Config.h:173
void clearUniqueKeys()
It removes all unique keys from the dataset type.
int getCategory() const
It returns the dataset category.
Definition: DataSetType.h:177
DataSourceCatalogLoader(DataSourceTransactor *parent)
te::da::DataSetType * Convert2TerraLib(sqlite3_stmt *pStmt)
Definition: Utils.cpp:433
Implementation of a forward-only dataset for the TerraLib SQLite Data Access driver.
A class that models the description of a dataset.
Definition: DataSetType.h:72
void GetHiddenTables(const te::da::DataSource *ds, std::vector< std::string > &tables)
Definition: Utils.cpp:392
void getUniqueKey(te::da::DataSetType *dt, int idxId, const std::string &idxName)
It models a property definition.
Definition: Property.h:59
int getType() const
It returns the property data type.
Definition: Property.h:143
boost::ptr_vector< te::dt::Property > getProperties(const std::string &datasetName)
te::gm::Envelope * getExtent(const std::string &tableName, const std::string &geomColName)
PrimaryKey * getPrimaryKey() const
It returns the primary key associated to the dataset type.
Definition: DataSetType.h:214
void setSRID(int srid)
It sets the spatial reference system identifier associated to this property.
An Envelope defines a 2D rectangular region.
Definition: Envelope.h:51
Geometric property.
std::size_t getNumberOfUniqueKeys() const
It returns the number of unique keys defined for the dataset type.
Definition: DataSetType.h:269
void getSpatialIndexes(te::da::DataSetType *dt)
bool datasetExists(const std::string &name)
DataSourceCatalogLoader manages metadata information for the TerraLib SQLite Data Access Driver...
void setAssociatedIndex(Index *idx)
It sets the associated index.
Definition: UniqueKey.h:138