odbc/vector-use-type.cpp
Go to the documentation of this file.
1 //
2 // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton, David Courtney
3 // Distributed under the Boost Software License, Version 1.0.
4 // (See accompanying file LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
6 //
7 
8 #define SOCI_ODBC_SOURCE
9 #include "soci-odbc.h"
10 #include <soci-platform.h>
11 #include <cassert>
12 #include <cctype>
13 #include <cstdio>
14 #include <cstring>
15 #include <ctime>
16 #include <sstream>
17 
18 #ifdef _MSC_VER
19 // disables the warning about converting int to void*. This is a 64 bit compatibility
20 // warning, but odbc requires the value to be converted on this line
21 // SQLSetStmtAttr(statement_.hstmt_, SQL_ATTR_PARAMSET_SIZE, (SQLPOINTER)arraySize, 0);
22 #pragma warning(disable:4312)
23 #endif
24 
25 using namespace soci;
26 using namespace soci::details;
27 
29 {
30  if (size == 0)
31  {
32  throw soci_error("Vectors of size 0 are not allowed.");
33  }
34 
35  indHolderVec_.resize(size);
36  indHolders_ = &indHolderVec_[0];
37 }
38 
39 void odbc_vector_use_type_backend::prepare_for_bind(void *&data, SQLUINTEGER &size,
40  SQLSMALLINT &sqlType, SQLSMALLINT &cType)
41 {
42  switch (type_)
43  { // simple cases
44  case x_short:
45  {
46  sqlType = SQL_SMALLINT;
47  cType = SQL_C_SSHORT;
48  size = sizeof(short);
49  std::vector<short> *vp = static_cast<std::vector<short> *>(data);
50  std::vector<short> &v(*vp);
51  prepare_indicators(v.size());
52  data = &v[0];
53  }
54  break;
55  case x_integer:
56  {
57  sqlType = SQL_INTEGER;
58  cType = SQL_C_SLONG;
59  size = sizeof(SQLINTEGER);
60  assert(sizeof(SQLINTEGER) == sizeof(int));
61  std::vector<int> *vp = static_cast<std::vector<int> *>(data);
62  std::vector<int> &v(*vp);
63  prepare_indicators(v.size());
64  data = &v[0];
65  }
66  break;
67  case x_long_long:
68  {
69  std::vector<long long> *vp =
70  static_cast<std::vector<long long> *>(data);
71  std::vector<long long> &v(*vp);
72  std::size_t const vsize = v.size();
73  prepare_indicators(vsize);
74 
75  if (use_string_for_bigint())
76  {
77  sqlType = SQL_NUMERIC;
78  cType = SQL_C_CHAR;
79  size = max_bigint_length;
80  buf_ = new char[size * vsize];
81  data = buf_;
82  }
83  else // Normal case, use ODBC support.
84  {
85  sqlType = SQL_BIGINT;
86  cType = SQL_C_SBIGINT;
87  size = sizeof(long long);
88  data = &v[0];
89  }
90  }
91  break;
93  {
94  std::vector<unsigned long long> *vp =
95  static_cast<std::vector<unsigned long long> *>(data);
96  std::vector<unsigned long long> &v(*vp);
97  std::size_t const vsize = v.size();
98  prepare_indicators(vsize);
99 
100  if (use_string_for_bigint())
101  {
102  sqlType = SQL_NUMERIC;
103  cType = SQL_C_CHAR;
104  size = max_bigint_length;
105  buf_ = new char[size * vsize];
106  data = buf_;
107  }
108  else // Normal case, use ODBC support.
109  {
110  sqlType = SQL_BIGINT;
111  cType = SQL_C_SBIGINT;
112  size = sizeof(unsigned long long);
113  data = &v[0];
114  }
115  }
116  break;
117  case x_double:
118  {
119  sqlType = SQL_DOUBLE;
120  cType = SQL_C_DOUBLE;
121  size = sizeof(double);
122  std::vector<double> *vp = static_cast<std::vector<double> *>(data);
123  std::vector<double> &v(*vp);
124  prepare_indicators(v.size());
125  data = &v[0];
126  }
127  break;
128 
129  // cases that require adjustments and buffer management
130  case x_char:
131  {
132  std::vector<char> *vp
133  = static_cast<std::vector<char> *>(data);
134  std::size_t const vsize = vp->size();
135 
136  prepare_indicators(vsize);
137 
138  size = sizeof(char) * 2;
139  buf_ = new char[size * vsize];
140 
141  char *pos = buf_;
142 
143  for (std::size_t i = 0; i != vsize; ++i)
144  {
145  *pos++ = (*vp)[i];
146  *pos++ = 0;
147  }
148 
149  sqlType = SQL_CHAR;
150  cType = SQL_C_CHAR;
151  data = buf_;
152  }
153  break;
154  case x_stdstring:
155  {
156  sqlType = SQL_CHAR;
157  cType = SQL_C_CHAR;
158 
159  std::vector<std::string> *vp
160  = static_cast<std::vector<std::string> *>(data);
161  std::vector<std::string> &v(*vp);
162 
163  std::size_t maxSize = 0;
164  std::size_t const vecSize = v.size();
165  prepare_indicators(vecSize);
166  for (std::size_t i = 0; i != vecSize; ++i)
167  {
168  std::size_t sz = v[i].length() + 1; // add one for null
169  indHolderVec_[i] = static_cast<long>(sz);
170  maxSize = sz > maxSize ? sz : maxSize;
171  }
172 
173  buf_ = new char[maxSize * vecSize];
174  memset(buf_, 0, maxSize * vecSize);
175 
176  char *pos = buf_;
177  for (std::size_t i = 0; i != vecSize; ++i)
178  {
179  strncpy(pos, v[i].c_str(), v[i].length());
180  pos += maxSize;
181  }
182 
183  data = buf_;
184  size = static_cast<SQLINTEGER>(maxSize);
185  }
186  break;
187  case x_stdtm:
188  {
189  std::vector<std::tm> *vp
190  = static_cast<std::vector<std::tm> *>(data);
191 
192  prepare_indicators(vp->size());
193 
194  buf_ = new char[sizeof(TIMESTAMP_STRUCT) * vp->size()];
195 
196  sqlType = SQL_TYPE_TIMESTAMP;
197  cType = SQL_C_TYPE_TIMESTAMP;
198  data = buf_;
199  size = 19; // This number is not the size in bytes, but the number
200  // of characters in the date if it was written out
201  // yyyy-mm-dd hh:mm:ss
202  }
203  break;
204 
205  case x_statement: break; // not supported
206  case x_rowid: break; // not supported
207  case x_blob: break; // not supported
208  }
209 
210  colSize_ = size;
211 }
212 
213 void odbc_vector_use_type_backend::bind_helper(int &position, void *data, exchange_type type)
214 {
215  data_ = data; // for future reference
216  type_ = type; // for future reference
217 
218  SQLSMALLINT sqlType;
219  SQLSMALLINT cType;
220  SQLUINTEGER size;
221 
222  prepare_for_bind(data, size, sqlType, cType);
223 
224  SQLULEN const arraySize = static_cast<SQLULEN>(indHolderVec_.size());
225  SQLSetStmtAttr(statement_.hstmt_, SQL_ATTR_PARAMSET_SIZE, (SQLPOINTER)arraySize, 0);
226 
227  SQLRETURN rc = SQLBindParameter(statement_.hstmt_, static_cast<SQLUSMALLINT>(position++),
228  SQL_PARAM_INPUT, cType, sqlType, size, 0,
229  static_cast<SQLPOINTER>(data), size, indHolders_);
230 
231  if (is_odbc_error(rc))
232  {
233  throw odbc_soci_error(SQL_HANDLE_STMT, statement_.hstmt_,
234  "Error while binding value to column");
235  }
236 }
237 
239  void *data, exchange_type type)
240 {
241  if (statement_.boundByName_)
242  {
243  throw soci_error(
244  "Binding for use elements must be either by position or by name.");
245  }
246 
247  bind_helper(position, data, type);
248 
249  statement_.boundByPos_ = true;
250 }
251 
253  std::string const &name, void *data, exchange_type type)
254 {
255  if (statement_.boundByPos_)
256  {
257  throw soci_error(
258  "Binding for use elements must be either by position or by name.");
259  }
260 
261  int position = -1;
262  int count = 1;
263 
264  for (std::vector<std::string>::iterator it = statement_.names_.begin();
265  it != statement_.names_.end(); ++it)
266  {
267  if (*it == name)
268  {
269  position = count;
270  break;
271  }
272  count++;
273  }
274 
275  if (position != -1)
276  {
277  bind_helper(position, data, type);
278  }
279  else
280  {
281  std::ostringstream ss;
282  ss << "Unable to find name '" << name << "' to bind to";
283  throw soci_error(ss.str().c_str());
284  }
285 
286  statement_.boundByName_ = true;
287 }
288 
290 {
291  // first deal with data
292  if (type_ == x_stdtm)
293  {
294  std::vector<std::tm> *vp
295  = static_cast<std::vector<std::tm> *>(data_);
296 
297  std::vector<std::tm> &v(*vp);
298 
299  char *pos = buf_;
300  std::size_t const vsize = v.size();
301  for (std::size_t i = 0; i != vsize; ++i)
302  {
303  std::tm t = v[i];
304  TIMESTAMP_STRUCT * ts = reinterpret_cast<TIMESTAMP_STRUCT*>(pos);
305 
306  ts->year = static_cast<SQLSMALLINT>(t.tm_year + 1900);
307  ts->month = static_cast<SQLUSMALLINT>(t.tm_mon + 1);
308  ts->day = static_cast<SQLUSMALLINT>(t.tm_mday);
309  ts->hour = static_cast<SQLUSMALLINT>(t.tm_hour);
310  ts->minute = static_cast<SQLUSMALLINT>(t.tm_min);
311  ts->second = static_cast<SQLUSMALLINT>(t.tm_sec);
312  ts->fraction = 0;
313  pos += sizeof(TIMESTAMP_STRUCT);
314  }
315  }
316  else if (type_ == x_long_long && use_string_for_bigint())
317  {
318  std::vector<long long> *vp
319  = static_cast<std::vector<long long> *>(data_);
320  std::vector<long long> &v(*vp);
321 
322  char *pos = buf_;
323  std::size_t const vsize = v.size();
324  for (std::size_t i = 0; i != vsize; ++i)
325  {
326  snprintf(pos, max_bigint_length, "%" LL_FMT_FLAGS "d", v[i]);
327  pos += max_bigint_length;
328  }
329  }
330  else if (type_ == x_unsigned_long_long && use_string_for_bigint())
331  {
332  std::vector<unsigned long long> *vp
333  = static_cast<std::vector<unsigned long long> *>(data_);
334  std::vector<unsigned long long> &v(*vp);
335 
336  char *pos = buf_;
337  std::size_t const vsize = v.size();
338  for (std::size_t i = 0; i != vsize; ++i)
339  {
340  snprintf(pos, max_bigint_length, "%" LL_FMT_FLAGS "u", v[i]);
341  pos += max_bigint_length;
342  }
343  }
344 
345  // then handle indicators
346  if (ind != NULL)
347  {
348  std::size_t const vsize = size();
349  for (std::size_t i = 0; i != vsize; ++i, ++ind)
350  {
351  if (*ind == i_null)
352  {
353  indHolderVec_[i] = SQL_NULL_DATA; // null
354  }
355  else
356  {
357  // for strings we have already set the values
358  if (type_ != x_stdstring)
359  {
360  indHolderVec_[i] = SQL_NTS; // value is OK
361  }
362  }
363  }
364  }
365  else
366  {
367  // no indicators - treat all fields as OK
368  std::size_t const vsize = size();
369  for (std::size_t i = 0; i != vsize; ++i, ++ind)
370  {
371  // for strings we have already set the values
372  if (type_ != x_stdstring)
373  {
374  indHolderVec_[i] = SQL_NTS; // value is OK
375  }
376  }
377  }
378 }
379 
381 {
382  std::size_t sz = 0; // dummy initialization to please the compiler
383  switch (type_)
384  {
385  // simple cases
386  case x_char:
387  {
388  std::vector<char> *vp = static_cast<std::vector<char> *>(data_);
389  sz = vp->size();
390  }
391  break;
392  case x_short:
393  {
394  std::vector<short> *vp = static_cast<std::vector<short> *>(data_);
395  sz = vp->size();
396  }
397  break;
398  case x_integer:
399  {
400  std::vector<int> *vp = static_cast<std::vector<int> *>(data_);
401  sz = vp->size();
402  }
403  break;
404  case x_long_long:
405  {
406  std::vector<long long> *vp =
407  static_cast<std::vector<long long> *>(data_);
408  sz = vp->size();
409  }
410  break;
412  {
413  std::vector<unsigned long long> *vp =
414  static_cast<std::vector<unsigned long long> *>(data_);
415  sz = vp->size();
416  }
417  break;
418  case x_double:
419  {
420  std::vector<double> *vp
421  = static_cast<std::vector<double> *>(data_);
422  sz = vp->size();
423  }
424  break;
425  case x_stdstring:
426  {
427  std::vector<std::string> *vp
428  = static_cast<std::vector<std::string> *>(data_);
429  sz = vp->size();
430  }
431  break;
432  case x_stdtm:
433  {
434  std::vector<std::tm> *vp
435  = static_cast<std::vector<std::tm> *>(data_);
436  sz = vp->size();
437  }
438  break;
439 
440  case x_statement: break; // not supported
441  case x_rowid: break; // not supported
442  case x_blob: break; // not supported
443  }
444 
445  return sz;
446 }
447 
449 {
450  if (buf_ != NULL)
451  {
452  delete [] buf_;
453  buf_ = NULL;
454  }
455 }
virtual void bind_by_name(std::string const &name, void *data, details::exchange_type type)
bool is_odbc_error(SQLRETURN rc)
Definition: soci-odbc.h:399
virtual void bind_by_pos(int &position, void *data, details::exchange_type type)
void prepare_for_bind(void *&data, SQLUINTEGER &size, SQLSMALLINT &sqlType, SQLSMALLINT &cType)
void bind_helper(int &position, void *data, details::exchange_type type)
#define LL_FMT_FLAGS
Definition: soci-platform.h:14
virtual void pre_use(indicator const *ind)


asr_lib_ism
Author(s): Hanselmann Fabian, Heller Florian, Heizmann Heinrich, Kübler Marcel, Mehlhaus Jonas, Meißner Pascal, Qattan Mohamad, Reckling Reno, Stroh Daniel
autogenerated on Wed Jan 8 2020 04:02:41