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/postgis/PreparedQuery.cpp
22 
23  \brief A class that implements a prepared query for PostgreSQL data access driver.
24 */
25 
26 // TerraLib
27 #include "../common/StringUtils.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 "Connection.h"
36 #include "DataSet.h"
37 #include "DataSource.h"
38 #include "Exception.h"
39 #include "EWKBWriter.h"
40 #include "PreparedQuery.h"
41 #include "SQLVisitor.h"
42 #include "Transactor.h"
43 #include "Utils.h"
44 
45 // STL
46 #include <cassert>
47 #include <cstring>
48 
49 // Boost
50 #include <boost/cstdint.hpp>
51 #include <boost/format.hpp>
52 #include <boost/lexical_cast.hpp>
53 
54 // libpq
55 #include <libpq-fe.h>
56 
57 namespace te
58 {
59  namespace pgis
60  {
61  inline void BindValue(te::pgis::PreparedQuery* pq, te::da::DataSet* d, std::size_t i, std::size_t propertyPos)
62  {
63  if(d->isNull(propertyPos))
64  return;
65 
66  const int propertyDataType = d->getPropertyDataType(propertyPos);
67 
68  switch(propertyDataType)
69  {
70  case te::dt::CHAR_TYPE :
71  pq->bind(i, d->getChar(propertyPos));
72  break;
73 
74  case te::dt::INT16_TYPE :
75  pq->bind(i, d->getInt16(propertyPos));
76  break;
77 
78  case te::dt::INT32_TYPE :
79  pq->bind(i, d->getInt32(propertyPos));
80  break;
81 
82  case te::dt::INT64_TYPE :
83  pq->bind(i, d->getInt64(propertyPos));
84  break;
85 
87  pq->bind(i, d->getBool(propertyPos));
88  break;
89 
90  case te::dt::FLOAT_TYPE :
91  pq->bind(i, d->getFloat(propertyPos));
92  break;
93 
94  case te::dt::DOUBLE_TYPE :
95  pq->bind(i, d->getDouble(propertyPos));
96  break;
97 
99  pq->bindNumeric(i, d->getNumeric(propertyPos));
100  break;
101 
102  case te::dt::STRING_TYPE :
103  pq->bind(i, d->getString(propertyPos));
104  break;
105 
107  {
108  std::auto_ptr<te::dt::ByteArray> ba(d->getByteArray(propertyPos));
109  pq->bind(i, *ba);
110  }
111  break;
112 
113  case te::dt::GEOMETRY_TYPE :
114  {
115  std::auto_ptr<te::gm::Geometry> geom(d->getGeometry(propertyPos));
116  pq->bind(i, *geom);
117  }
118  break;
119 
120  case te::dt::DATETIME_TYPE :
121  {
122  std::auto_ptr<te::dt::DateTime> dt(d->getDateTime(propertyPos));
123  pq->bind(i, *dt);
124  }
125  break;
126 
127  default :
128  throw Exception(TE_TR("The TerraLib data type is not supported by the PostgreSQL driver!"));
129  }
130  }
131 
132  } // end namespace pgis
133 } // end namespace te
134 
136  : m_t(t),
137  m_conn(0),
138  m_result(0),
139  m_paramValues(0),
140  m_paramLengths(0),
141  m_paramFormats(0),
142  m_nparams(0),
143  m_qname(pqname)
144 {
146 
148 }
149 
151 {
152  try
153  {
154  clear();
155  }
156  catch(...)
157  {
158  }
159 }
160 
162 {
163  return m_qname;
164 }
165 
166 void te::pgis::PreparedQuery::prepare(const te::da::Query& query, const std::vector<te::dt::Property*>& paramTypes)
167 {
168  te::pgis::DataSource* pgds = static_cast<te::pgis::DataSource*>(m_t->getDataSource());
169  assert(m_t && pgds && pgds->getDialect());
170  std::string sql;
171 
172  SQLVisitor visitor(*(pgds->getDialect()), sql, m_t->getConnection()->getConn());
173  query.accept(visitor);
174 
175  prepare(sql, paramTypes);
176 }
177 
178 void te::pgis::PreparedQuery::prepare(const std::string& query, const std::vector<te::dt::Property*>& queryParams)
179 {
180  throw Exception(TE_TR("Not implemented yet!"));
181 }
182 
184 {
185  PQclear(m_result);
186 
187  m_result = PQexecPrepared(m_conn, m_qname.c_str(), m_nparams, m_paramValues, m_paramLengths, m_paramFormats, 1);
188 
189 // release param values data and set it to a null value
190  for(std::size_t i = 0; i < m_nparams; ++i)
191  {
192  delete [] (m_paramValues[i]);
193  m_paramValues[i] = 0;
194  m_paramLengths[i] = 0;
195  }
196 
197 // check result
198  if((PQresultStatus(m_result) != PGRES_COMMAND_OK) &&
199  (PQresultStatus(m_result) != PGRES_TUPLES_OK))
200  {
201  boost::format errmsg(TE_TR("Could not execute the prepared query due to the following error: %1%."));
202 
203  errmsg = errmsg % PQerrorMessage(m_conn);
204 
205  throw Exception(errmsg.str());
206  }
207 }
208 
210  te::common::AccessPolicy /*rwRole*/)
211 {
212  execute();
213 
214  te::pgis::DataSource* ds = static_cast<te::pgis::DataSource*>(m_t->getDataSource());
215 
216  std::vector<int> ptypes;
217  Convert2TerraLib(m_result, ds->getGeomTypeId(), ds->getRasterTypeId(), ptypes);
218 
219  DataSet* dataset = new DataSet(m_result, std::vector<int>(), ds->isTimeAnInteger(), ds->getCharEncoding());
220 
221  m_result = 0;
222 
223  return dataset;
224 }
225 
226 void te::pgis::PreparedQuery::bind(int i, char value)
227 {
228  m_paramLengths[i] = sizeof(char);
229  m_paramFormats[i] = 1;
230 
231  if(m_paramValues[i] == 0)
232  m_paramValues[i] = new char[sizeof(char)];
233 
234  memcpy(m_paramValues[i], &value, sizeof(char));
235 }
236 
237 void te::pgis::PreparedQuery::bind(int i, unsigned char value)
238 {
239  throw Exception(TE_TR("The TerraLib unsigned char data type is not supported by PostgreSQL data access driver!"));
240 }
241 
242 void te::pgis::PreparedQuery::bind(int i, boost::int16_t value)
243 {
244  m_paramLengths[i] = sizeof(boost::int16_t);
245  m_paramFormats[i] = 1;
246 
247  if(m_paramValues[i] == 0)
248  m_paramValues[i] = new char[sizeof(boost::int16_t)];
249 
250  memcpy(m_paramValues[i], &value, sizeof(boost::int16_t));
251 
252 #if TE_MACHINE_BYTE_ORDER == TE_NDR
253  te::common::Swap2Bytes(m_paramValues[i]);
254 #endif
255 }
256 
257 void te::pgis::PreparedQuery::bind(int i, boost::int32_t value)
258 {
259  m_paramLengths[i] = sizeof(boost::int32_t);
260  m_paramFormats[i] = 1;
261 
262  if(m_paramValues[i] == 0)
263  m_paramValues[i] = new char[sizeof(boost::int32_t)];
264 
265  memcpy(m_paramValues[i], &value, sizeof(boost::int32_t));
266 
267 #if TE_MACHINE_BYTE_ORDER == TE_NDR
268  te::common::Swap4Bytes(m_paramValues[i]);
269 #endif
270 }
271 
272 void te::pgis::PreparedQuery::bind(int i, boost::int64_t value)
273 {
274  m_paramLengths[i] = sizeof(boost::int64_t);
275  m_paramFormats[i] = 1;
276 
277  if(m_paramValues[i] == 0)
278  m_paramValues[i] = new char[sizeof(boost::int64_t)];
279 
280  memcpy(m_paramValues[i], &value, sizeof(boost::int64_t));
281 
282 #if TE_MACHINE_BYTE_ORDER == TE_NDR
283  te::common::Swap8Bytes(m_paramValues[i]);
284 #endif
285 }
286 
287 void te::pgis::PreparedQuery::bind(int i, bool value)
288 {
289  m_paramLengths[i] = sizeof(char);
290  m_paramFormats[i] = 1;
291 
292  if(m_paramValues[i] == 0)
293  m_paramValues[i] = new char[sizeof(char)];
294 
295  char bvalue = value ? 1 : 0;
296 
297  memcpy(m_paramValues[i], &bvalue, sizeof(char));
298 }
299 
300 void te::pgis::PreparedQuery::bind(int i, float value)
301 {
302  m_paramLengths[i] = sizeof(float);
303  m_paramFormats[i] = 1;
304 
305  if(m_paramValues[i] == 0)
306  m_paramValues[i] = new char[sizeof(float)];
307 
308  memcpy(m_paramValues[i], &value, sizeof(float));
309 
310 #if TE_MACHINE_BYTE_ORDER == TE_NDR
311  te::common::Swap4Bytes(m_paramValues[i]);
312 #endif
313 }
314 
315 void te::pgis::PreparedQuery::bind(int i, double value)
316 {
317  m_paramLengths[i] = sizeof(double);
318  m_paramFormats[i] = 1;
319 
320  if(m_paramValues[i] == 0)
321  m_paramValues[i] = new char[sizeof(double)];
322 
323  memcpy(m_paramValues[i], &value, sizeof(double));
324 
325 #if TE_MACHINE_BYTE_ORDER == TE_NDR
326  te::common::Swap8Bytes(m_paramValues[i]);
327 #endif
328 }
329 
330 void te::pgis::PreparedQuery::bindNumeric(int i, const std::string& value)
331 {
332  delete [] (m_paramValues[i]);
333 
334  m_paramValues[i] = new char[value.length() + 1];
335 
336  memcpy(m_paramValues[i], value.c_str(), value.length() + 1);
337 
338  //m_paramLengths[i] = static_cast<int>(value.length()); // we don't need to inform the length
339  m_paramFormats[i] = 0;
340 }
341 
342 void te::pgis::PreparedQuery::bind(int i, const std::string& value)
343 {
344  delete [] (m_paramValues[i]);
345 
346  m_paramValues[i] = new char[value.length() + 1];
347 
348  memcpy(m_paramValues[i], value.c_str(), value.length() + 1);
349 
350  //m_paramLengths[i] = static_cast<int>(value.length()); // we don't need to inform the length
351  m_paramFormats[i] = 0;
352 }
353 
355 {
356  delete [] (m_paramValues[i]);
357 
358  m_paramValues[i] = new char[value.bytesUsed()];
359 
360  memcpy(m_paramValues[i], value.getData(), value.bytesUsed());
361 
362  m_paramLengths[i] = value.bytesUsed();
363  m_paramFormats[i] = 1;
364 }
365 
367 {
368  delete [] (m_paramValues[i]);
369 
370  m_paramValues[i] = 0;
371 
372  m_paramFormats[i] = 1;
373 
374  std::size_t ewkbsize = value.getWkbSize() + 4;
375 
376  m_paramValues[i] = new char[ewkbsize];
377 
378  EWKBWriter::write(&value, m_paramValues[i]);
379 
380  m_paramLengths[i] = static_cast<int>(ewkbsize);
381 }
382 
383 void te::pgis::PreparedQuery::bind(int /*i*/, const te::rst::Raster& /*value*/)
384 {
385  throw Exception(TE_TR("Not implemented yet!"));
386 }
387 
389 {
390  //if(dynamic_cast<const te::dt::Date*>(&value) != 0)
391  //{
392  // m_paramTypes[i] = PG_DATE_TYPE;
393  //}
394  //else if(dynamic_cast<const te::dt::TimeDuration*>(&value) != 0)
395  //{
396  // m_paramTypes[i] = PG_TIME_TYPE;
397  //}
398  //else if(dynamic_cast<const te::dt::TimeInstant*>(&value) != 0)
399  //{
400  // m_paramTypes[i] = PG_TIMESTAMP_TYPE;
401  //}
402  //else
403  //{
404  // m_paramTypes[i] = PG_TIMESTAMPTZ_TYPE;
405  //}
406 
407  delete [] (m_paramValues[i]);
408 
409  std::string dvalue = value.toString();
410 
411  m_paramValues[i] = new char[dvalue.length() + 1];
412 
413  memcpy(m_paramValues[i], dvalue.c_str(), dvalue.length() + 1);
414 
415  m_paramLengths[i] = dvalue.length() + 1;
416 }
417 
418 void te::pgis::PreparedQuery::bind(int /*i*/, const te::da::DataSet& /*value*/)
419 {
420  throw Exception(TE_TR("Not implemented yet!"));
421 }
422 
424 {
425  throw Exception(TE_TR("Not implemented yet!"));
426 }
427 
429 {
430  return m_t;
431 }
432 
433 void te::pgis::PreparedQuery::prepare(const std::string& query, const std::vector<int>& paramTypes)
434 {
435 // clear any previous prepared query
436  clear();
437 
438 // create parameters of prepared query
439  m_nparams = paramTypes.size();
440 
441  m_paramValues = new char*[m_nparams];
442 
443  memset(m_paramValues, 0, m_nparams * sizeof(char*));
444 
445  m_paramLengths = new int[m_nparams];
446 
447  memset(m_paramLengths, 0, m_nparams * sizeof(int));
448 
449  m_paramFormats = new int[m_nparams];
450 
451  memset(m_paramFormats, 0, m_nparams * sizeof(int));
452 
453 // make prepared query
454  m_result = PQprepare(m_conn, m_qname.c_str(), query.c_str(), m_nparams, 0);
455 
456 // check result
457  if((PQresultStatus(m_result) != PGRES_COMMAND_OK) &&
458  (PQresultStatus(m_result) != PGRES_TUPLES_OK))
459  {
460  boost::format errmsg(TE_TR("Could not create the prepared query due to the following error: %1%."));
461 
462  errmsg = errmsg % PQerrorMessage(m_conn);
463 
464  throw Exception(errmsg.str());
465  }
466 }
467 
468 void te::pgis::PreparedQuery::bind(const std::vector<std::size_t>& propertiesPos, std::size_t offset, te::da::DataSet* d)
469 {
470  const std::size_t nparams = propertiesPos.size();
471 
472  for(std::size_t i = 0; i < nparams; ++i)
473  BindValue(this, d, i + offset, propertiesPos[i]);
474 }
475 
476 void te::pgis::PreparedQuery::bind(const std::vector<std::size_t>& propertiesPos, te::da::DataSet* d)
477 {
478  const std::size_t nparams = propertiesPos.size();
479 
480  for(std::size_t i = 0; i < nparams; ++i)
481  BindValue(this, d, i, propertiesPos[i]);
482 }
483 
485 {
486  for(std::size_t i = 0; i < m_nparams; ++i)
487  BindValue(this, d, i, i);
488 }
489 
491 {
492  if(m_nparams == 0)
493  return;
494 
495 // release prepared statement
496  m_t->execute("DEALLOCATE PREPARE " + m_qname);
497 
498 // release any pending result
499  PQclear(m_result);
500 
501  m_result = 0;
502 
503 // release param values
504  for(std::size_t i = 0; i < m_nparams; ++i)
505  delete [] (m_paramValues[i]);
506 
507  delete [] m_paramValues;
508 
509  m_paramValues = 0;
510 
511 // release param lengths
512  delete [] m_paramLengths;
513 
514  m_paramLengths = 0;
515 
516 // release param formats
517  delete [] m_paramFormats;
518 
519  m_paramFormats = 0;
520 
521 // don't forget to reset number of params!
522  m_nparams = 0;
523 }
524 
525 
~PreparedQuery()
Virtual destructor.
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).
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
std::string Convert2LCase(const std::string &value)
It converts a string to lower case.
Definition: StringUtils.h:197
virtual char getChar(std::size_t i) const =0
Method for retrieving a signed character attribute value (1 byte long).
Connection * getConnection() const
It returns the underlying connection.
Definition: Transactor.cpp:89
void bindNumeric(int i, const std::string &value)
Binds the i-th parameter of the query to a value.
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).
void write(const te::gm::Geometry *geom)
It serializes the geometry to an EWKB representation into the specified buffer.
Definition: EWKBWriter.cpp:104
void Swap8Bytes(char *v)
It swaps an array of eight bytes in local.
virtual std::auto_ptr< te::dt::ByteArray > getByteArray(std::size_t i) const =0
Method for retrieving a byte array.
unsigned int getRasterTypeId() const
It returns the type id associated to the PostGIS Raster type.
Definition: DataSource.cpp:185
A visitor for building an SQL statement using PostGIS dialect.
Definition: SQLVisitor.h:52
void bind(int i, char value)
Binds the i-th parameter of the query to a value.
virtual std::string toString() const =0
It returns the data value in a string notation.
te::da::DataSourceTransactor * getTransactor() const
It returns a pointer to the underlying data source transactor.
virtual std::string getNumeric(std::size_t i) const =0
Method for retrieving a numeric attribute value.
#define TE_TR(message)
It marks a string in order to get translated.
Definition: Translator.h:347
std::size_t getWkbSize() const
It returns the size required by a WKB representation for this geometric object.
Definition: Geometry.cpp:134
te::da::DataSet * query(te::common::TraverseType travType=te::common::FORWARDONLY, te::common::AccessPolicy rwRole=te::common::RAccess)
virtual double getDouble(std::size_t i) const =0
Method for retrieving a double attribute value.
The PostGIS driver.
Definition: DataSource.h:54
void Swap2Bytes(T &v)
It swaps two bytes in local.
Definition: ByteSwapUtils.h:51
The transactor class for the PostGIS driver.
Definition: Transactor.h:62
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
PreparedQuery()
Constructor.
Definition: PreparedQuery.h:74
An utility class for writing a PostGIS EWKB.
PGconn * getConn() const
It gets the underlying PGconn object.
Definition: Connection.h:97
virtual float getFloat(std::size_t i) const =0
Method for retrieving a float attribute value.
std::string getName() const
It returns the prepared query name.
void Swap4Bytes(T &v)
It swaps four bytes in local.
Definition: ByteSwapUtils.h:82
Implementation of a dataset for the PostGIS driver.
Definition: DataSet.h:60
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
Utility functions for PostgreSQL.
A base class for values that can be retrieved from the data access module.
Definition: AbstractData.h:57
const te::da::SQLDialect * getDialect() const
It returns the data source SQL dialect, if there is one.
Definition: DataSource.cpp:175
A DataSourceTransactor can be viewed as a connection to the data source for reading/writing things in...
Geometry is the root class of the geometries hierarchy, it follows OGC and ISO standards.
Definition: Geometry.h:73
A class that implements a connection to a PostgreSQL database.
virtual std::auto_ptr< te::gm::Geometry > getGeometry(std::size_t i) const =0
Method for retrieving a geometric attribute value.
Implementation of the data source for the PostGIS driver.
A Transactor can be viewed as a connection to the data source for reading/writing things into it...
A dataset is the unit of information manipulated by the data access module of TerraLib.
Definition: DataSet.h:112
An exception class for the PostGIS driver.
A visitor for building an SQL statement using PostGIS dialect.
virtual ReturnType accept(VisitorType &guest) const =0
It call the visit method from the guest object.
te::common::CharEncoding getCharEncoding() const
It returns the datasource char encoding.
Definition: DataSource.cpp:200
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).
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.
Definition: Utils.h:456
virtual std::string getString(std::size_t i) const =0
Method for retrieving a string value attribute.
void BindValue(te::pgis::PreparedQuery *pq, te::da::DataSet *d, std::size_t i, std::size_t propertyPos)
A dataset is the unit of information manipulated by the data access module of TerraLib.
virtual int getPropertyDataType(std::size_t i) const =0
It returns the underlying data type of the property at position pos.
A class that implements a prepared query for PostgreSQL data access driver.
Definition: PreparedQuery.h:68
A Query is independent from the data source language/dialect.
Definition: Query.h:46
A class for representing binary data.
Definition: ByteArray.h:51
unsigned int getGeomTypeId() const
It returns the type id associated to the PostGIS Geometry type.
Definition: DataSource.cpp:180
A class that implements a prepared query for PostgreSQL data access driver.