oracle/standard-use-type.cpp
Go to the documentation of this file.
1 //
2 // Copyright (C) 2004-2007 Maciej Sobczak, Stephen Hutton
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_ORACLE_SOURCE
9 #include "soci-oracle.h"
10 #include "blob.h"
11 #include "error.h"
12 #include "rowid.h"
13 #include "statement.h"
14 #include <soci-platform.h>
15 #include <cctype>
16 #include <cstdio>
17 #include <cstring>
18 #include <cstdlib>
19 #include <ctime>
20 #include <sstream>
21 
22 #ifdef _MSC_VER
23 #pragma warning(disable:4355)
24 #define snprintf _snprintf
25 #endif
26 
27 using namespace soci;
28 using namespace soci::details;
29 using namespace soci::details::oracle;
30 
32  void *&data, sb4 &size, ub2 &oracleType, bool readOnly)
33 {
34  readOnly_ = readOnly;
35 
36  switch (type_)
37  {
38  // simple cases
39  case x_char:
40  oracleType = SQLT_AFC;
41  size = sizeof(char);
42  if (readOnly)
43  {
44  buf_ = new char[size];
45  data = buf_;
46  }
47  break;
48  case x_short:
49  oracleType = SQLT_INT;
50  size = sizeof(short);
51  if (readOnly)
52  {
53  buf_ = new char[size];
54  data = buf_;
55  }
56  break;
57  case x_integer:
58  oracleType = SQLT_INT;
59  size = sizeof(int);
60  if (readOnly)
61  {
62  buf_ = new char[size];
63  data = buf_;
64  }
65  break;
66  case x_double:
67  oracleType = SQLT_FLT;
68  size = sizeof(double);
69  if (readOnly)
70  {
71  buf_ = new char[size];
72  data = buf_;
73  }
74  break;
75 
76  // cases that require adjustments and buffer management
77  case x_long_long:
79  oracleType = SQLT_STR;
80  size = 100; // arbitrary buffer length
81  buf_ = new char[size];
82  data = buf_;
83  break;
84  case x_stdstring:
85  oracleType = SQLT_STR;
86  // 4000 is Oracle max VARCHAR2 size; 32768 is max LONG size
87  size = 32769;
88  buf_ = new char[size];
89  data = buf_;
90  break;
91  case x_stdtm:
92  oracleType = SQLT_DAT;
93  size = 7 * sizeof(ub1);
94  buf_ = new char[size];
95  data = buf_;
96  break;
97 
98  // cases that require special handling
99  case x_statement:
100  {
101  oracleType = SQLT_RSET;
102 
103  statement *st = static_cast<statement *>(data);
104  st->alloc();
105 
107  = static_cast<oracle_statement_backend *>(st->get_backend());
108  size = 0;
109  data = &stbe->stmtp_;
110  }
111  break;
112  case x_rowid:
113  {
114  oracleType = SQLT_RDD;
115 
116  rowid *rid = static_cast<rowid *>(data);
117 
119  = static_cast<oracle_rowid_backend *>(rid->get_backend());
120 
121  size = 0;
122  data = &rbe->rowidp_;
123  }
124  break;
125  case x_blob:
126  {
127  oracleType = SQLT_BLOB;
128 
129  blob *b = static_cast<blob *>(data);
130 
132  = static_cast<oracle_blob_backend *>(b->get_backend());
133 
134  size = 0;
135  data = &bbe->lobp_;
136  }
137  break;
138  }
139 }
140 
142  int &position, void *data, exchange_type type, bool readOnly)
143 {
144  if (statement_.boundByName_)
145  {
146  throw soci_error(
147  "Binding for use elements must be either by position or by name.");
148  }
149 
150  data_ = data; // for future reference
151  type_ = type; // for future reference
152 
153  ub2 oracleType;
154  sb4 size;
155 
156  prepare_for_bind(data, size, oracleType, readOnly);
157 
158  sword res = OCIBindByPos(statement_.stmtp_, &bindp_,
159  statement_.session_.errhp_,
160  position++, data, size, oracleType,
161  &indOCIHolder_, 0, 0, 0, 0, OCI_DEFAULT);
162  if (res != OCI_SUCCESS)
163  {
164  throw_oracle_soci_error(res, statement_.session_.errhp_);
165  }
166 
167  statement_.boundByPos_ = true;
168 }
169 
171  std::string const &name, void *data, exchange_type type, bool readOnly)
172 {
173  if (statement_.boundByPos_)
174  {
175  throw soci_error(
176  "Binding for use elements must be either by position or by name.");
177  }
178 
179  data_ = data; // for future reference
180  type_ = type; // for future reference
181 
182  ub2 oracleType;
183  sb4 size;
184 
185  prepare_for_bind(data, size, oracleType, readOnly);
186 
187  sword res = OCIBindByName(statement_.stmtp_, &bindp_,
188  statement_.session_.errhp_,
189  reinterpret_cast<text*>(const_cast<char*>(name.c_str())),
190  static_cast<sb4>(name.size()),
191  data, size, oracleType,
192  &indOCIHolder_, 0, 0, 0, 0, OCI_DEFAULT);
193  if (res != OCI_SUCCESS)
194  {
195  throw_oracle_soci_error(res, statement_.session_.errhp_);
196  }
197 
198  statement_.boundByName_ = true;
199 }
200 
202 {
203  // first deal with data
204  switch (type_)
205  {
206  case x_char:
207  if (readOnly_)
208  {
209  buf_[0] = *static_cast<char *>(data_);
210  }
211  break;
212  case x_short:
213  if (readOnly_)
214  {
215  *static_cast<short *>(static_cast<void *>(buf_)) = *static_cast<short *>(data_);
216  }
217  break;
218  case x_integer:
219  if (readOnly_)
220  {
221  *static_cast<int *>(static_cast<void *>(buf_)) = *static_cast<int *>(data_);
222  }
223  break;
224  case x_long_long:
225  {
226  size_t const size = 100; // arbitrary, but consistent with prepare_for_bind
227  snprintf(buf_, size, "%" LL_FMT_FLAGS "d", *static_cast<long long *>(data_));
228  }
229  break;
231  {
232  size_t const size = 100; // arbitrary, but consistent with prepare_for_bind
233  snprintf(buf_, size, "%" LL_FMT_FLAGS "u", *static_cast<unsigned long long *>(data_));
234  }
235  break;
236  case x_double:
237  if (readOnly_)
238  {
239  *static_cast<double *>(static_cast<void *>(buf_)) = *static_cast<double *>(data_);
240  }
241  break;
242  case x_stdstring:
243  {
244  std::string *s = static_cast<std::string *>(data_);
245 
246  // 4000 is Oracle max VARCHAR2 size; 32768 is max LONG size
247  std::size_t const bufSize = 32769;
248  std::size_t const sSize = s->size();
249  std::size_t const toCopy =
250  sSize < bufSize -1 ? sSize + 1 : bufSize - 1;
251  strncpy(buf_, s->c_str(), toCopy);
252  buf_[toCopy] = '\0';
253  }
254  break;
255  case x_stdtm:
256  {
257  std::tm *t = static_cast<std::tm *>(data_);
258  ub1* pos = reinterpret_cast<ub1*>(buf_);
259 
260  *pos++ = static_cast<ub1>(100 + (1900 + t->tm_year) / 100);
261  *pos++ = static_cast<ub1>(100 + t->tm_year % 100);
262  *pos++ = static_cast<ub1>(t->tm_mon + 1);
263  *pos++ = static_cast<ub1>(t->tm_mday);
264  *pos++ = static_cast<ub1>(t->tm_hour + 1);
265  *pos++ = static_cast<ub1>(t->tm_min + 1);
266  *pos = static_cast<ub1>(t->tm_sec + 1);
267  }
268  break;
269  case x_statement:
270  {
271  statement *s = static_cast<statement *>(data_);
272 
273  s->undefine_and_bind();
274  }
275  break;
276  case x_rowid:
277  case x_blob:
278  // nothing to do
279  break;
280  }
281 
282  // then handle indicators
283  if (ind != NULL && *ind == i_null)
284  {
285  indOCIHolder_ = -1; // null
286  }
287  else
288  {
289  indOCIHolder_ = 0; // value is OK
290  }
291 }
292 
294 {
295  // It is possible to have the bound element being overwritten
296  // by the database.
297  //
298  // With readOnly_ == true the propagation of modification should *not*
299  // take place and in addition the attempt of modification should be detected and reported.
300 
301  // first, deal with data
302  if (gotData)
303  {
304  switch (type_)
305  {
306  case x_char:
307  if (readOnly_)
308  {
309  const char original = *static_cast<char *>(data_);
310  const char bound = buf_[0];
311 
312  if (original != bound)
313  {
314  throw soci_error("Attempted modification of const use element");
315  }
316  }
317  break;
318  case x_short:
319  if (readOnly_)
320  {
321  const short original = *static_cast<short *>(data_);
322  const short bound = *static_cast<short *>(static_cast<void *>(buf_));
323 
324  if (original != bound)
325  {
326  throw soci_error("Attempted modification of const use element");
327  }
328  }
329  break;
330  case x_integer:
331  if (readOnly_)
332  {
333  const int original = *static_cast<int *>(data_);
334  const int bound = *static_cast<int *>(static_cast<void *>(buf_));
335 
336  if (original != bound)
337  {
338  throw soci_error("Attempted modification of const use element");
339  }
340  }
341  break;
342  case x_long_long:
343  if (readOnly_)
344  {
345  long long const original = *static_cast<long long *>(data_);
346  long long const bound = std::strtoll(buf_, NULL, 10);
347 
348  if (original != bound)
349  {
350  throw soci_error("Attempted modification of const use element");
351  }
352  }
353  break;
355  if (readOnly_)
356  {
357  unsigned long long const original = *static_cast<unsigned long long *>(data_);
358  unsigned long long const bound = std::strtoull(buf_, NULL, 10);
359 
360  if (original != bound)
361  {
362  throw soci_error("Attempted modification of const use element");
363  }
364  }
365  break;
366  case x_double:
367  if (readOnly_)
368  {
369  const double original = *static_cast<double *>(data_);
370  const double bound = *static_cast<double *>(static_cast<void *>(buf_));
371 
372  if (original != bound)
373  {
374  throw soci_error("Attempted modification of const use element");
375  }
376  }
377  break;
378  case x_stdstring:
379  {
380  std::string & original = *static_cast<std::string *>(data_);
381  if (original != buf_)
382  {
383  if (readOnly_)
384  {
385  throw soci_error("Attempted modification of const use element");
386  }
387  else
388  {
389  original = buf_;
390  }
391  }
392  }
393  break;
394  case x_stdtm:
395  {
396  std::tm & original = *static_cast<std::tm *>(data_);
397 
398  std::tm bound;
399  ub1 *pos = reinterpret_cast<ub1*>(buf_);
400  bound.tm_isdst = -1;
401  bound.tm_year = (*pos++ - 100) * 100;
402  bound.tm_year += *pos++ - 2000;
403  bound.tm_mon = *pos++ - 1;
404  bound.tm_mday = *pos++;
405  bound.tm_hour = *pos++ - 1;
406  bound.tm_min = *pos++ - 1;
407  bound.tm_sec = *pos++ - 1;
408 
409  if (original.tm_year != bound.tm_year ||
410  original.tm_mon != bound.tm_mon ||
411  original.tm_mday != bound.tm_mday ||
412  original.tm_hour != bound.tm_hour ||
413  original.tm_min != bound.tm_min ||
414  original.tm_sec != bound.tm_sec)
415  {
416  if (readOnly_)
417  {
418  throw soci_error("Attempted modification of const use element");
419  }
420  else
421  {
422  original = bound;
423 
424  // normalize and compute the remaining fields
425  std::mktime(&original);
426  }
427  }
428  }
429  break;
430  case x_statement:
431  {
432  statement *s = static_cast<statement *>(data_);
433  s->define_and_bind();
434  }
435  break;
436  case x_rowid:
437  case x_blob:
438  // nothing to do here
439  break;
440  }
441  }
442 
443  if (ind != NULL)
444  {
445  if (gotData)
446  {
447  if (indOCIHolder_ == 0)
448  {
449  *ind = i_ok;
450  }
451  else if (indOCIHolder_ == -1)
452  {
453  *ind = i_null;
454  }
455  else
456  {
457  *ind = i_truncated;
458  }
459  }
460  }
461 }
462 
464 {
465  if (bindp_ != NULL)
466  {
467  OCIHandleFree(bindp_, OCI_HTYPE_DEFINE);
468  bindp_ = NULL;
469  }
470 
471  if (buf_ != NULL)
472  {
473  delete [] buf_;
474  buf_ = NULL;
475  }
476 }
virtual void bind_by_name(std::string const &name, void *data, details::exchange_type type, bool readOnly)
details::statement_backend * get_backend()
Definition: statement.h:243
details::rowid_backend * get_backend()
Definition: rowid.h:33
void undefine_and_bind()
Definition: statement.h:207
void throw_oracle_soci_error(sword res, OCIError *errhp)
virtual void post_use(bool gotData, indicator *ind)
void prepare_for_bind(void *&data, sb4 &size, ub2 &oracleType, bool readOnly)
void define_and_bind()
Definition: statement.h:206
details::blob_backend * get_backend()
Definition: blob.h:39
virtual void bind_by_pos(int &position, void *data, details::exchange_type type, bool readOnly)
OCILobLocator * lobp_
Definition: soci-oracle.h:240
#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