All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
DataSourceCatalogLoader.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/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 
Property * getProperty(std::size_t i) const
It returns the i-th property.
te::da::DataSetType * getDataSetType(const std::string &datasetName)
Geometric property.
GeomType
Each enumerated type is compatible with a Well-known Binary (WKB) type code.
Definition: Enums.h:41
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 class that models the description of a dataset.
Definition: DataSetType.h:72
std::size_t getNumberOfUniqueKeys() const
It returns the number of unique keys defined for the dataset type.
Definition: DataSetType.h:269
DataSourceCatalogLoader manages metadata information for the TerraLib SQLite Data Access Driver...
void GetHiddenTables(const te::da::DataSource *ds, std::vector< std::string > &tables)
Definition: Utils.cpp:392
PrimaryKey * getPrimaryKey() const
It returns the primary key associated to the dataset type.
Definition: DataSetType.h:214
void add(te::dt::Property *p)
It adds the property to the list of properties of the index.
Definition: Index.h:197
boost::ptr_vector< te::dt::Property > getProperties(const std::string &datasetName)
void getGeometryInfo(const std::string &datasetName, te::gm::GeometryProperty *gp)
It models a property definition.
Definition: Property.h:59
void getSpatialIndexes(te::da::DataSetType *dt)
An Envelope defines a 2D rectangular region.
Definition: Envelope.h:51
void getIndex(te::da::DataSetType *dt, int idxId, const std::string &idxName, bool isUnique)
void getIndexes(te::da::DataSetType *dt)
DataSourceCatalogLoader(DataSourceTransactor *parent)
int getCategory() const
It returns the dataset category.
Definition: DataSetType.h:177
It describes a unique key (uk) constraint.
Definition: UniqueKey.h:53
void setAssociatedIndex(Index *idx)
It sets the associated index.
Definition: UniqueKey.h:138
te::gm::Envelope * getExtent(const std::string &tableName, const std::string &geomColName)
std::size_t size() const
It returns the number of properties of the CompositeProperty.
Utility functions for the TerraLib SQLite Data Access driver.
This class is designed to declare objects to be thrown as exceptions by TerraLib. ...
Definition: Exception.h:58
std::auto_ptr< te::da::DataSet > getDataSets()
int getType() const
It returns the property data type.
Definition: Property.h:161
bool datasetExists(const std::string &name)
void add(Constraint *c)
It adds a new constraint.
void setAssociatedIndex(Index *idx)
It sets the associated index.
Definition: PrimaryKey.h:130
void clearUniqueKeys()
It removes all unique keys from the dataset type.
It describes a primary key (pk) constraint.
Definition: PrimaryKey.h:52
std::vector< std::string > getDataSetNames()
void getPrimaryKey(te::da::DataSetType *dt)
An implementation of DataSourceTransactor class for the TerraLib SQLite Data Access Driver...
void clearIndexes()
It removes all indexes from the dataset type.
virtual const std::string & getName() const
It returns the constraint name.
Definition: Constraint.h:119
te::da::DataSetType * Convert2TerraLib(sqlite3_stmt *pStmt)
Definition: Utils.cpp:433
void getUniqueKey(te::da::DataSetType *dt, int idxId, const std::string &idxName)
It describes an index associated to a DataSetType.
Definition: Index.h:54
void setPrimaryKey(PrimaryKey *pk)
It sets the primary key constraint.
UniqueKey * getUniqueKey(std::size_t i) const
It returns the i-th unique key.
Definition: DataSetType.h:294
int Convert2TerraLibCategory(const std::string &category)
Definition: Utils.cpp:522
Implementation of a forward-only dataset for the TerraLib SQLite Data Access driver.
void getUniqueKeys(te::da::DataSetType *dt)
const std::string & getName() const
It returns the property name.
Definition: Property.h:127