All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
PreparedQuery.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/PreparedQuery.cpp
22 
23  \brief A class that implements a prepared query for the TerraLib SQLite Data Access Driver.
24 */
25 
26 // TerraLib
27 #include "../common/Globals.h"
28 #include "../common/Translator.h"
29 #include "../dataaccess/dataset/DataSet.h"
30 #include "../dataaccess/dataset/DataSetType.h"
31 #include "../dataaccess/query/Query.h"
32 #include "../datatype/ByteArray.h"
33 #include "../datatype/DateTime.h"
34 #include "../geometry/Geometry.h"
35 #include "../memory/DataSet.h"
36 #include "DataSource.h"
37 #include "DataSourceTransactor.h"
38 #include "EWKBSize.h"
39 #include "EWKBWriter.h"
40 #include "FwDataSet.h"
41 #include "PreparedQuery.h"
42 #include "SQLVisitor.h"
43 
44 // STL
45 #include <memory>
46 
47 // Boost
48 #include <boost/date_time.hpp>
49 #include <boost/format.hpp>
50 
51 // SQLite
52 #include <sqlite3.h>
53 
54 namespace te
55 {
56  namespace sqlite
57  {
58 
59  inline void BindValue(sqlite3_stmt* stmt, te::da::DataSet* d, std::size_t i, std::size_t propertyPos)
60  {
61  int retval = SQLITE_OK;
62 
63  const int propertyDataType = d->getPropertyDataType(propertyPos);
64 
65  if(d->isNull(propertyPos))
66  {
67  retval = sqlite3_bind_null(stmt, i + 1);
68 
69  if(retval != SQLITE_OK)
70  throw te::common::Exception(TR_COMMON("SQLite driver couldn't bind a NULL value!"));
71 
72  return;
73  }
74 
75  switch(propertyDataType)
76  {
77  case te::dt::CHAR_TYPE :
78  retval = sqlite3_bind_int(stmt, i + 1, d->getChar(propertyPos));
79  break;
80 
81  case te::dt::UCHAR_TYPE :
82  retval = sqlite3_bind_int(stmt, i + 1, d->getUChar(propertyPos));
83  break;
84 
85  case te::dt::INT16_TYPE :
86  retval = sqlite3_bind_int(stmt, i + 1, d->getInt16(propertyPos));
87  break;
88 
89  case te::dt::INT32_TYPE :
90  retval = sqlite3_bind_int(stmt, i + 1, d->getInt32(propertyPos));
91  break;
92 
93  case te::dt::INT64_TYPE :
94  retval = sqlite3_bind_int64(stmt, i + 1, d->getInt64(propertyPos));
95  break;
96 
98  retval = sqlite3_bind_int(stmt, i + 1, d->getBool(propertyPos) ? TE_SQLITE_BOOL_TRUE : TE_SQLITE_BOOL_FALSE);
99  break;
100 
101  case te::dt::FLOAT_TYPE :
102  retval = sqlite3_bind_double(stmt, i + 1, static_cast<double>(d->getFloat(propertyPos)));
103  break;
104 
105  case te::dt::DOUBLE_TYPE :
106  retval = sqlite3_bind_double(stmt, i + 1, d->getDouble(propertyPos));
107  break;
108 
109  case te::dt::NUMERIC_TYPE :
110  {
111  std::string value = d->getNumeric(propertyPos);
112  retval = sqlite3_bind_text(stmt, i + 1, value.c_str(), value.size(), SQLITE_TRANSIENT);
113  }
114  break;
115 
116  case te::dt::STRING_TYPE :
117  {
118  std::string value = d->getString(propertyPos);
119  retval = sqlite3_bind_text(stmt, i + 1, value.c_str(), value.size(), SQLITE_TRANSIENT);
120  }
121  break;
122 
123  //case te::dt::BYTE_ARRAY_TYPE :
124  // {
125  // std::auto_ptr<te::dt::ByteArray> b(d->getByteArray(propertyPos));
126 
127  // retval = sqlite3_bind_blob(stmt, i + 1, b->getData(), b->bytesUsed(), SQLITE_TRANSIENT);
128  // }
129  //break;
130 
131  case te::dt::GEOMETRY_TYPE :
132  {
133  std::auto_ptr<te::gm::Geometry> g(d->getGeometry(propertyPos));
134 
135  std::size_t ewkbSize = EWKBSize::getEWKBSize(g.get());
136 
137  unsigned char* ewkb = new unsigned char[ewkbSize];
138 
139  EWKBWriter::write(g.get(), ewkb, te::common::Globals::sm_machineByteOrder);
140 
141  retval = sqlite3_bind_blob(stmt, i + 1, ewkb, ewkbSize, SQLITE_TRANSIENT);
142 
143  delete [] ewkb;
144  }
145  break;
146 
147  case te::dt::DATETIME_TYPE :
148  {
149  std::auto_ptr<te::dt::DateTime> dt(d->getDateTime(propertyPos));
150 
151  std::string sdate = dt->toString();
152 
153  retval = sqlite3_bind_text(stmt, i + 1, sdate.c_str(), sdate.size(), SQLITE_TRANSIENT);
154 
155  //const te::dt::DateTimeProperty* dtp = static_cast<const te::dt::DateTimeProperty*>(p);
156 
157  //if(dtp->getSubType() == te::dt::DateTimeProperty::TIME_INSTANT)
158  //{
159  //
160  //}
161  //else //if(dtp->getSubType() == te::dt::DateTimeProperty::DATE)
162  //{
163  //
164  //}
165  }
166  break;
167 
168  default:
169  throw te::common::Exception(TR_COMMON("There is a TerraLib data type that can not be mapped to SQLite type system!"));
170  }
171 
172  if(retval != SQLITE_OK)
173  throw te::common::Exception(TR_COMMON("Could not bind a value!"));
174  }
175 
176  } // end namespace sqlite
177 } // end namespace te
178 
180  : m_t(parent),
181  m_stmt(0),
182  m_db(db)
183 {
184 }
185 
187 {
188  sqlite3_finalize(m_stmt);
189 }
190 
192 {
193  return "UNAMED";
194 }
195 
196 void te::sqlite::PreparedQuery::prepare(const te::da::Query& query, const std::vector<te::dt::Property*>& /*paramTypes*/)
197 {
198  assert(m_t && m_t->getDataSource() && m_t->getDataSource()->getDialect());
199  std::string sql;
200 
201  SQLVisitor visitor(*(m_t->getDataSource()->getDialect()), sql);
202  query.accept(visitor);
203 
204  prepare(sql);
205 }
206 
207 void te::sqlite::PreparedQuery::prepare(const std::string& query, const std::vector<te::dt::Property*>& /*paramTypes*/)
208 {
209  sqlite3_finalize(m_stmt);
210 
211  m_stmt = 0;
212 
213  int ret = sqlite3_prepare_v2(m_db, query.c_str(), -1, &m_stmt, 0);
214 
215  if(ret != SQLITE_OK)
216  {
217  if(m_stmt)
218  sqlite3_finalize(m_stmt);
219 
220  m_stmt = 0;
221 
222  throw te::common::Exception((boost::format(TR_COMMON("Could not excute the given query due to the following error: %1%.")) % sqlite3_errmsg(m_db)).str());
223  }
224 }
225 
227 {
228  int retval = sqlite3_step(m_stmt);
229 
230  if(retval != SQLITE_DONE)
231  {
232  boost::format errmsg(TR_COMMON("Could not execute prepared query due to the following error: %1%."));
233 
234  const char* litemsg = sqlite3_errmsg(m_db);
235 
236  if(litemsg != 0)
237  errmsg = errmsg % litemsg;
238 
239  throw te::common::Exception(errmsg.str());
240  }
241 
242  retval = sqlite3_reset(m_stmt);
243 
244  if(retval != SQLITE_OK)
245  {
246  boost::format errmsg(TR_COMMON("Could not reset the prepared query to its initial state due to the following error: %1%."));
247 
248  const char* litemsg = sqlite3_errmsg(m_db);
249 
250  if(litemsg)
251  errmsg = errmsg % litemsg;
252 
253  throw te::common::Exception(errmsg.str());
254  }
255 }
256 
258  te::common::AccessPolicy /*rwRole*/)
259 {
260  //int retval = sqlite3_step(m_stmt);
261 
262  te::mem::DataSet* dataset = 0;
263 
264  //if(retval == SQLITE_ROW)
265  //{
266  // FwDataSet fwdataset(m_stmt, m_t, false);
267 
268  // dataset = new te::mem::DataSet(fwdataset);
269  //}
270  //else if(retval != SQLITE_DONE)
271  //{
272  // boost::format errmsg(TR_COMMON("Could not excute prepared query due to the following error: %1%."));
273 
274  // const char* litemsg = sqlite3_errmsg(m_t->getLiteDataSource()->getDB());
275 
276  // if(litemsg)
277  // errmsg = errmsg % litemsg;
278 
279  // throw te::common::Exception(errmsg.str());
280  //}
281  //else
282  //{
283  // dataset = new te::mem::DataSet(0);
284  //}
285 
286  //retval = sqlite3_reset(m_stmt);
287  //
288  //if(retval != SQLITE_OK)
289  //{
290  // boost::format errmsg(TR_COMMON("Could not reset the prepared query to its initial state due to the following error: %1%."));
291 
292  // const char* litemsg = sqlite3_errmsg(m_t->getLiteDataSource()->getDB());
293 
294  // if(litemsg)
295  // errmsg = errmsg % litemsg;
296 
297  // throw te::common::Exception(errmsg.str());
298  //}
299 
300  return dataset;
301 }
302 
303 void te::sqlite::PreparedQuery::bind(int i, char value)
304 {
305  int retval = sqlite3_bind_int(m_stmt, i + 1, value);
306 
307  if(retval != SQLITE_OK)
308  throw te::common::Exception(TR_COMMON("Could not bind a char value!"));
309 }
310 
311 void te::sqlite::PreparedQuery::bind(int i, unsigned char value)
312 {
313  int retval = sqlite3_bind_int(m_stmt, i + 1, value);
314 
315  if(retval != SQLITE_OK)
316  throw te::common::Exception(TR_COMMON("Could not bind a unsigned char value!"));
317 }
318 
319 void te::sqlite::PreparedQuery::bind(int i, boost::int16_t value)
320 {
321  int retval = sqlite3_bind_int(m_stmt, i + 1, value);
322 
323  if(retval != SQLITE_OK)
324  throw te::common::Exception(TR_COMMON("Could not bind a 16-bit integer value!"));
325 }
326 
327 void te::sqlite::PreparedQuery::bind(int i, boost::int32_t value)
328 {
329  int retval = sqlite3_bind_int(m_stmt, i + 1, value);
330 
331  if(retval != SQLITE_OK)
332  throw te::common::Exception(TR_COMMON("Could not bind a 32-bit integer value!"));
333 }
334 
335 void te::sqlite::PreparedQuery::bind(int i, boost::int64_t value)
336 {
337  int retval = sqlite3_bind_int64(m_stmt, i + 1, value);
338 
339  if(retval != SQLITE_OK)
340  throw te::common::Exception(TR_COMMON("Could not bind a 64-bit integer value!"));
341 }
342 
343 void te::sqlite::PreparedQuery::bind(int i, bool value)
344 {
345  int retval = sqlite3_bind_int(m_stmt, i + 1, value ? TE_SQLITE_BOOL_TRUE : TE_SQLITE_BOOL_FALSE);
346 
347  if(retval != SQLITE_OK)
348  throw te::common::Exception(TR_COMMON("Could not bind a boolean value!"));
349 }
350 
351 void te::sqlite::PreparedQuery::bind(int i, float value)
352 {
353  int retval = sqlite3_bind_double(m_stmt, i + 1, static_cast<double>(value));
354 
355  if(retval != SQLITE_OK)
356  throw te::common::Exception(TR_COMMON("Could not bind a float value!"));
357 }
358 
359 void te::sqlite::PreparedQuery::bind(int i, double value)
360 {
361  int retval = sqlite3_bind_double(m_stmt, i + 1, value);
362 
363  if(retval != SQLITE_OK)
364  throw te::common::Exception(TR_COMMON("Could not bind a double value!"));
365 }
366 
367 void te::sqlite::PreparedQuery::bindNumeric(int i, const std::string& value)
368 {
369  int retval = sqlite3_bind_text(m_stmt, i + 1, value.c_str(), value.size(), SQLITE_TRANSIENT);
370 
371  if(retval != SQLITE_OK)
372  throw te::common::Exception(TR_COMMON("Could not bind a numeric value!"));
373 }
374 
375 void te::sqlite::PreparedQuery::bind(int i, const std::string& value)
376 {
377  int retval = sqlite3_bind_text(m_stmt, i + 1, value.c_str(), value.size(), SQLITE_TRANSIENT);
378 
379  if(retval != SQLITE_OK)
380  throw te::common::Exception(TR_COMMON("Could not bind a string value!"));
381 }
382 
384 {
385  int retval = sqlite3_bind_blob(m_stmt, i + 1, value.getData(), value.bytesUsed(), SQLITE_TRANSIENT);
386 
387  if(retval != SQLITE_OK)
388  throw te::common::Exception(TR_COMMON("Could not bind a byte array value!"));
389 }
390 
392 {
393  std::size_t ewkbSize = EWKBSize::getEWKBSize(&value);
394 
395  unsigned char* ewkb = new unsigned char[ewkbSize];
396 
397  EWKBWriter::write(&value, ewkb, te::common::Globals::sm_machineByteOrder);
398 
399  int retval = sqlite3_bind_blob(m_stmt, i + 1, ewkb, ewkbSize, SQLITE_TRANSIENT);
400 
401  delete [] ewkb;
402 
403  if(retval != SQLITE_OK)
404  throw te::common::Exception(TR_COMMON("Could not bind a geometry value!"));
405 }
406 
407 void te::sqlite::PreparedQuery::bind(int /*i*/, const te::rst::Raster& /*value*/)
408 {
409  throw te::common::Exception(TR_COMMON("Not implemented yet!"));
410 }
411 
413 {
414  std::string sdate = value.toString();
415 
416  int retval = sqlite3_bind_text(m_stmt, i + 1, sdate.c_str(), sdate.size(), SQLITE_TRANSIENT);
417 
418  if(retval != SQLITE_OK)
419  throw te::common::Exception(TR_COMMON("Could not bind a date-time value!"));
420 }
421 
422 void te::sqlite::PreparedQuery::bind(int /*i*/, const te::da::DataSet& /*value*/)
423 {
424  throw te::common::Exception(TR_COMMON("Not implemented yet!"));
425 }
426 
428 {
429  throw te::common::Exception(TR_COMMON("Not implemented yet!"));
430 }
431 
433 {
434  return m_t;
435 }
436 
437 // SQLite specific
438 void te::sqlite::PreparedQuery::prepare(const std::string& query)
439 {
440  sqlite3_finalize(m_stmt);
441 
442  m_stmt = 0;
443 
444  sqlite3_finalize(m_stmt);
445 
446  m_stmt = 0;
447 
448  int ret = sqlite3_prepare_v2(m_db, query.c_str(), -1, &m_stmt, 0);
449 
450  if(ret != SQLITE_OK)
451  {
452  if(m_stmt)
453  sqlite3_finalize(m_stmt);
454 
455  m_stmt = 0;
456 
457  throw te::common::Exception((boost::format(TR_COMMON("Could not excute the given query due to the following error: %1%.")) % sqlite3_errmsg(m_db)).str());
458  }
459 }
460 
461 void te::sqlite::PreparedQuery::bind(const std::vector<std::size_t>& propertiesPos,
462  std::size_t offset,
463  te::da::DataSet* d)
464 {
465  const std::size_t nparams = propertiesPos.size();
466 
467  for(std::size_t i = 0; i != nparams; ++i)
468  BindValue(m_stmt, d, i + offset, propertiesPos[i]);
469 }
470 
471 void te::sqlite::PreparedQuery::bind(const std::vector<std::size_t>& propertiesPos,
472  te::da::DataSet* d)
473 {
474  const std::size_t nparams = propertiesPos.size();
475 
476  for(std::size_t i = 0; i != nparams; ++i)
477  BindValue(m_stmt, d, i, propertiesPos[i]);
478 }
479 
481 {
482  const std::size_t nparams = d->getNumProperties();
483 
484  for(std::size_t i = 0; i != nparams; ++i)
485  BindValue(m_stmt, d, i, i);
486 }
487 
488 
489 
490 
491 
virtual std::auto_ptr< te::dt::DateTime > getDateTime(std::size_t i) const =0
Method for retrieving a date and time attribute value.
virtual boost::int16_t getInt16(std::size_t i) const =0
Method for retrieving a 16-bit integer attribute value (2 bytes long).
void BindValue(sqlite3_stmt *stmt, te::da::DataSet *d, std::size_t i, std::size_t propertyPos)
A visitor for building an SQL statement using SQLite dialect.
#define TE_SQLITE_BOOL_FALSE
A flag that indicates a false value (boolean).
Definition: Config.h:39
struct sqlite3 sqlite3
virtual boost::int32_t getInt32(std::size_t i) const =0
Method for retrieving a 32-bit integer attribute value (4 bytes long).
std::size_t bytesUsed() const
It returns the number of used bytes in the internal buffer.
Definition: ByteArray.cpp:169
void prepare(const te::da::Query &query, const std::vector< te::dt::Property * > &paramTypes)
It prepares the query that may be used for commands that are used mutiple times (select, insert, update and delete).
virtual char getChar(std::size_t i) const =0
Method for retrieving a signed character attribute value (1 byte long).
virtual bool getBool(std::size_t i) const =0
Method for retrieving a boolean attribute value.
virtual boost::int64_t getInt64(std::size_t i) const =0
Method for retrieving a 64-bit integer attribute value (8 bytes long).
te::da::DataSet * query(te::common::TraverseType travType=te::common::FORWARDONLY, te::common::AccessPolicy rwRole=te::common::RAccess)
static const MachineByteOrder sm_machineByteOrder
A flag that indicates the machine byte order (Big Endian or Little Endian).
Definition: Globals.h:54
virtual std::string toString() const =0
It returns the data value in a string notation.
virtual std::string getNumeric(std::size_t i) const =0
Method for retrieving a numeric attribute value.
A class that implements a prepared query for the TerraLib SQLite Data Access Driver.
virtual double getDouble(std::size_t i) const =0
Method for retrieving a double attribute value.
AccessPolicy
Supported data access policies (can be used as bitfield).
Definition: Enums.h:40
TraverseType
A dataset can be traversed in two ways:
Definition: Enums.h:53
Implementation of a random-access dataset class for the TerraLib In-Memory Data Access driver...
Definition: DataSet.h:65
PreparedQuery()
Constructor.
Definition: PreparedQuery.h:74
virtual float getFloat(std::size_t i) const =0
Method for retrieving a float attribute value.
An abstract class for raster data strucutures.
Definition: Raster.h:71
virtual bool isNull(std::size_t i) const =0
It checks if the attribute value is NULL.
char * getData() const
It returns the data array.
Definition: ByteArray.cpp:105
A class that helps to determine the size of a SpatiaLite geometry.
std::string getName() const
It returns the prepared query name.
A base class for values that can be retrieved from the data access module.
Definition: AbstractData.h:57
void bind(int i, char value)
Binds the i-th parameter of the query to a value.
A DataSourceTransactor can be viewed as a connection to the data source for reading/writing things in...
virtual std::size_t getNumProperties() const =0
It returns the number of properties that composes an item of the dataset.
This class is designed to declare objects to be thrown as exceptions by TerraLib. ...
Definition: Exception.h:58
Geometry is the root class of the geometries hierarchy, it follows OGC and ISO standards.
Definition: Geometry.h:73
virtual std::auto_ptr< te::gm::Geometry > getGeometry(std::size_t i) const =0
Method for retrieving a geometric attribute value.
A class that serializes a geometry to the SpatiaLite EWKB format.
A visitor for building an SQL statement using SQLite dialect.
Definition: SQLVisitor.h:44
A dataset is the unit of information manipulated by the data access module of TerraLib.
Definition: DataSet.h:112
~PreparedQuery()
Virtual destructor.
virtual ReturnType accept(VisitorType &guest) const =0
It call the visit method from the guest object.
void bindNumeric(int i, const std::string &value)
Binds the i-th parameter of the query to a value.
Implements the DataSource class for the SQLite Data Access Driver.
struct sqlite3_stmt sqlite3_stmt
Definition: FwDataSet.h:35
An implementation of DataSourceTransactor class for the TerraLib SQLite Data Access Driver...
virtual std::string getString(std::size_t i) const =0
Method for retrieving a string value attribute.
virtual unsigned char getUChar(std::size_t i) const =0
Method for retrieving an unsigned character attribute value (1 byte long).
virtual int getPropertyDataType(std::size_t i) const =0
It returns the underlying data type of the property at position pos.
static std::size_t getEWKBSize(const te::gm::Geometry *g)
Definition: EWKBSize.cpp:49
te::da::DataSourceTransactor * getTransactor() const
It returns a pointer to the underlying data source transactor.
#define TE_SQLITE_BOOL_TRUE
A flag that indicates a false value (boolean).
Definition: Config.h:42
A Query is independent from the data source language/dialect.
Definition: Query.h:46
Implementation of a forward-only dataset for the TerraLib SQLite Data Access driver.
A class for representing binary data.
Definition: ByteArray.h:51