00001 // 00002 // Copyright (C) 2004-2007 Maciej Sobczak, Stephen Hutton 00003 // Distributed under the Boost Software License, Version 1.0. 00004 // (See accompanying file LICENSE_1_0.txt or copy at 00005 // http://www.boost.org/LICENSE_1_0.txt) 00006 // 00007 00008 #define soci_ORACLE_SOURCE 00009 #include "soci-oracle.h" 00010 #include "error.h" 00011 // 00012 #if defined(SOCI_HEADERS_BURIED) 00013 # include <soci/core/blob.h> 00014 # include <soci/core/rowid.h> 00015 # include <soci/core/statement.h> 00016 #else 00017 # include <blob.h> 00018 # include <rowid.h> 00019 # include <statement.h> 00020 #endif 00021 // 00022 #include <cctype> 00023 #include <cstdio> 00024 #include <cstring> 00025 #include <cstdlib> 00026 #include <ctime> 00027 #include <sstream> 00028 00029 #ifdef _MSC_VER 00030 #pragma warning(disable:4355) 00031 #endif 00032 00033 using namespace soci; 00034 using namespace soci::details; 00035 using namespace soci::details::oracle; 00036 00037 void oracle_standard_use_type_backend::prepare_for_bind( 00038 void *&data, sb4 &size, ub2 &oracleType, bool readOnly) 00039 { 00040 readOnly_ = readOnly; 00041 00042 switch (type_) 00043 { 00044 // simple cases 00045 case x_char: 00046 oracleType = SQLT_AFC; 00047 size = sizeof(char); 00048 if (readOnly) 00049 { 00050 buf_ = new char[size]; 00051 data = buf_; 00052 } 00053 break; 00054 case x_short: 00055 oracleType = SQLT_INT; 00056 size = sizeof(short); 00057 if (readOnly) 00058 { 00059 buf_ = new char[size]; 00060 data = buf_; 00061 } 00062 break; 00063 case x_integer: 00064 oracleType = SQLT_INT; 00065 size = sizeof(int); 00066 if (readOnly) 00067 { 00068 buf_ = new char[size]; 00069 data = buf_; 00070 } 00071 break; 00072 case x_unsigned_long: 00073 oracleType = SQLT_UIN; 00074 size = sizeof(unsigned long); 00075 if (readOnly) 00076 { 00077 buf_ = new char[size]; 00078 data = buf_; 00079 } 00080 break; 00081 case x_double: 00082 oracleType = SQLT_FLT; 00083 size = sizeof(double); 00084 if (readOnly) 00085 { 00086 buf_ = new char[size]; 00087 data = buf_; 00088 } 00089 break; 00090 00091 // cases that require adjustments and buffer management 00092 case x_long_long: 00093 oracleType = SQLT_STR; 00094 size = 100; // arbitrary buffer length 00095 buf_ = new char[size]; 00096 data = buf_; 00097 break; 00098 case x_stdstring: 00099 oracleType = SQLT_STR; 00100 // 4000 is Oracle max VARCHAR2 size; 32768 is max LONG size 00101 size = 32769; 00102 buf_ = new char[size]; 00103 data = buf_; 00104 break; 00105 case x_stdtm: 00106 oracleType = SQLT_DAT; 00107 size = 7 * sizeof(ub1); 00108 buf_ = new char[size]; 00109 data = buf_; 00110 break; 00111 00112 // cases that require special handling 00113 case x_statement: 00114 { 00115 oracleType = SQLT_RSET; 00116 00117 statement *st = static_cast<statement *>(data); 00118 st->alloc(); 00119 00120 oracle_statement_backend *stbe 00121 = static_cast<oracle_statement_backend *>(st->get_backend()); 00122 size = 0; 00123 data = &stbe->stmtp_; 00124 } 00125 break; 00126 case x_rowid: 00127 { 00128 oracleType = SQLT_RDD; 00129 00130 rowid *rid = static_cast<rowid *>(data); 00131 00132 oracle_rowid_backend *rbe 00133 = static_cast<oracle_rowid_backend *>(rid->get_backend()); 00134 00135 size = 0; 00136 data = &rbe->rowidp_; 00137 } 00138 break; 00139 case x_blob: 00140 { 00141 oracleType = SQLT_BLOB; 00142 00143 blob *b = static_cast<blob *>(data); 00144 00145 oracle_blob_backend *bbe 00146 = static_cast<oracle_blob_backend *>(b->get_backend()); 00147 00148 size = 0; 00149 data = &bbe->lobp_; 00150 } 00151 break; 00152 } 00153 } 00154 00155 void oracle_standard_use_type_backend::bind_by_pos( 00156 int &position, void *data, exchange_type type, bool readOnly) 00157 { 00158 if (statement_.boundByName_) 00159 { 00160 throw soci_error( 00161 "Binding for use elements must be either by position or by name."); 00162 } 00163 00164 data_ = data; // for future reference 00165 type_ = type; // for future reference 00166 00167 ub2 oracleType; 00168 sb4 size; 00169 00170 prepare_for_bind(data, size, oracleType, readOnly); 00171 00172 sword res = OCIBindByPos(statement_.stmtp_, &bindp_, 00173 statement_.session_.errhp_, 00174 position++, data, size, oracleType, 00175 &indOCIHolder_, 0, 0, 0, 0, OCI_DEFAULT); 00176 if (res != OCI_SUCCESS) 00177 { 00178 throw_oracle_soci_error(res, statement_.session_.errhp_); 00179 } 00180 00181 statement_.boundByPos_ = true; 00182 } 00183 00184 void oracle_standard_use_type_backend::bind_by_name( 00185 std::string const &name, void *data, exchange_type type, bool readOnly) 00186 { 00187 if (statement_.boundByPos_) 00188 { 00189 throw soci_error( 00190 "Binding for use elements must be either by position or by name."); 00191 } 00192 00193 data_ = data; // for future reference 00194 type_ = type; // for future reference 00195 00196 ub2 oracleType; 00197 sb4 size; 00198 00199 prepare_for_bind(data, size, oracleType, readOnly); 00200 00201 sword res = OCIBindByName(statement_.stmtp_, &bindp_, 00202 statement_.session_.errhp_, 00203 reinterpret_cast<text*>(const_cast<char*>(name.c_str())), 00204 static_cast<sb4>(name.size()), 00205 data, size, oracleType, 00206 &indOCIHolder_, 0, 0, 0, 0, OCI_DEFAULT); 00207 if (res != OCI_SUCCESS) 00208 { 00209 throw_oracle_soci_error(res, statement_.session_.errhp_); 00210 } 00211 00212 statement_.boundByName_ = true; 00213 } 00214 00215 void oracle_standard_use_type_backend::pre_use(indicator const *ind) 00216 { 00217 // first deal with data 00218 switch (type_) 00219 { 00220 case x_char: 00221 if (readOnly_) 00222 { 00223 buf_[0] = *static_cast<char *>(data_); 00224 } 00225 break; 00226 case x_short: 00227 if (readOnly_) 00228 { 00229 *static_cast<short *>(static_cast<void *>(buf_)) = *static_cast<short *>(data_); 00230 } 00231 break; 00232 case x_integer: 00233 if (readOnly_) 00234 { 00235 *static_cast<int *>(static_cast<void *>(buf_)) = *static_cast<int *>(data_); 00236 } 00237 break; 00238 case x_unsigned_long: 00239 if (readOnly_) 00240 { 00241 *static_cast<unsigned long *>(static_cast<void *>(buf_)) 00242 = *static_cast<unsigned long *>(data_); 00243 } 00244 break; 00245 case x_long_long: 00246 { 00247 size_t const size = 100; // arbitrary, but consistent with prepare_for_bind 00248 snprintf(buf_, size, "%lld", *static_cast<long long *>(data_)); 00249 } 00250 break; 00251 case x_double: 00252 if (readOnly_) 00253 { 00254 *static_cast<double *>(static_cast<void *>(buf_)) = *static_cast<double *>(data_); 00255 } 00256 break; 00257 case x_stdstring: 00258 { 00259 std::string *s = static_cast<std::string *>(data_); 00260 00261 // 4000 is Oracle max VARCHAR2 size; 32768 is max LONG size 00262 std::size_t const bufSize = 32769; 00263 std::size_t const sSize = s->size(); 00264 std::size_t const toCopy = 00265 sSize < bufSize -1 ? sSize + 1 : bufSize - 1; 00266 strncpy(buf_, s->c_str(), toCopy); 00267 buf_[toCopy] = '\0'; 00268 } 00269 break; 00270 case x_stdtm: 00271 { 00272 std::tm *t = static_cast<std::tm *>(data_); 00273 ub1* pos = reinterpret_cast<ub1*>(buf_); 00274 00275 *pos++ = static_cast<ub1>(100 + (1900 + t->tm_year) / 100); 00276 *pos++ = static_cast<ub1>(100 + t->tm_year % 100); 00277 *pos++ = static_cast<ub1>(t->tm_mon + 1); 00278 *pos++ = static_cast<ub1>(t->tm_mday); 00279 *pos++ = static_cast<ub1>(t->tm_hour + 1); 00280 *pos++ = static_cast<ub1>(t->tm_min + 1); 00281 *pos = static_cast<ub1>(t->tm_sec + 1); 00282 } 00283 break; 00284 case x_statement: 00285 { 00286 statement *s = static_cast<statement *>(data_); 00287 00288 s->undefine_and_bind(); 00289 } 00290 break; 00291 case x_rowid: 00292 case x_blob: 00293 // nothing to do 00294 break; 00295 } 00296 00297 // then handle indicators 00298 if (ind != NULL && *ind == i_null) 00299 { 00300 indOCIHolder_ = -1; // null 00301 } 00302 else 00303 { 00304 indOCIHolder_ = 0; // value is OK 00305 } 00306 } 00307 00308 void oracle_standard_use_type_backend::post_use(bool gotData, indicator *ind) 00309 { 00310 // It is possible to have the bound element being overwritten 00311 // by the database. 00312 // 00313 // With readOnly_ == true the propagation of modification should *not* 00314 // take place and in addition the attempt of modification should be detected and reported. 00315 00316 // first, deal with data 00317 if (gotData) 00318 { 00319 switch (type_) 00320 { 00321 case x_char: 00322 if (readOnly_) 00323 { 00324 const char original = *static_cast<char *>(data_); 00325 const char bound = buf_[0]; 00326 00327 if (original != bound) 00328 { 00329 throw soci_error("Attempted modification of const use element"); 00330 } 00331 } 00332 break; 00333 case x_short: 00334 if (readOnly_) 00335 { 00336 const short original = *static_cast<short *>(data_); 00337 const short bound = *static_cast<short *>(static_cast<void *>(buf_)); 00338 00339 if (original != bound) 00340 { 00341 throw soci_error("Attempted modification of const use element"); 00342 } 00343 } 00344 break; 00345 case x_integer: 00346 if (readOnly_) 00347 { 00348 const int original = *static_cast<int *>(data_); 00349 const int bound = *static_cast<int *>(static_cast<void *>(buf_)); 00350 00351 if (original != bound) 00352 { 00353 throw soci_error("Attempted modification of const use element"); 00354 } 00355 } 00356 break; 00357 case x_unsigned_long: 00358 if (readOnly_) 00359 { 00360 const unsigned long original = *static_cast<unsigned long *>(data_); 00361 const unsigned long bound 00362 = *static_cast<unsigned long *>(static_cast<void *>(buf_)); 00363 00364 if (original != bound) 00365 { 00366 throw soci_error("Attempted modification of const use element"); 00367 } 00368 } 00369 break; 00370 case x_long_long: 00371 if (readOnly_) 00372 { 00373 long long const original = *static_cast<long long *>(data_); 00374 long long const bound = strtoll(buf_, NULL, 10); 00375 00376 if (original != bound) 00377 { 00378 throw soci_error("Attempted modification of const use element"); 00379 } 00380 } 00381 break; 00382 case x_double: 00383 if (readOnly_) 00384 { 00385 const double original = *static_cast<double *>(data_); 00386 const double bound = *static_cast<double *>(static_cast<void *>(buf_)); 00387 00388 if (original != bound) 00389 { 00390 throw soci_error("Attempted modification of const use element"); 00391 } 00392 } 00393 break; 00394 case x_stdstring: 00395 { 00396 std::string & original = *static_cast<std::string *>(data_); 00397 if (original != buf_) 00398 { 00399 if (readOnly_) 00400 { 00401 throw soci_error("Attempted modification of const use element"); 00402 } 00403 else 00404 { 00405 original = buf_; 00406 } 00407 } 00408 } 00409 break; 00410 case x_stdtm: 00411 { 00412 std::tm & original = *static_cast<std::tm *>(data_); 00413 00414 std::tm bound; 00415 ub1 *pos = reinterpret_cast<ub1*>(buf_); 00416 bound.tm_isdst = -1; 00417 bound.tm_year = (*pos++ - 100) * 100; 00418 bound.tm_year += *pos++ - 2000; 00419 bound.tm_mon = *pos++ - 1; 00420 bound.tm_mday = *pos++; 00421 bound.tm_hour = *pos++ - 1; 00422 bound.tm_min = *pos++ - 1; 00423 bound.tm_sec = *pos++ - 1; 00424 00425 if (original.tm_year != bound.tm_year || 00426 original.tm_mon != bound.tm_mon || 00427 original.tm_mday != bound.tm_mday || 00428 original.tm_hour != bound.tm_hour || 00429 original.tm_min != bound.tm_min || 00430 original.tm_sec != bound.tm_sec) 00431 { 00432 if (readOnly_) 00433 { 00434 throw soci_error("Attempted modification of const use element"); 00435 } 00436 else 00437 { 00438 original = bound; 00439 00440 // normalize and compute the remaining fields 00441 std::mktime(&original); 00442 } 00443 } 00444 } 00445 break; 00446 case x_statement: 00447 { 00448 statement *s = static_cast<statement *>(data_); 00449 s->define_and_bind(); 00450 } 00451 break; 00452 case x_rowid: 00453 case x_blob: 00454 // nothing to do here 00455 break; 00456 } 00457 } 00458 00459 if (ind != NULL) 00460 { 00461 if (gotData) 00462 { 00463 if (indOCIHolder_ == 0) 00464 { 00465 *ind = i_ok; 00466 } 00467 else if (indOCIHolder_ == -1) 00468 { 00469 *ind = i_null; 00470 } 00471 else 00472 { 00473 *ind = i_truncated; 00474 } 00475 } 00476 } 00477 } 00478 00479 void oracle_standard_use_type_backend::clean_up() 00480 { 00481 if (bindp_ != NULL) 00482 { 00483 OCIHandleFree(bindp_, OCI_HTYPE_DEFINE); 00484 bindp_ = NULL; 00485 } 00486 00487 if (buf_ != NULL) 00488 { 00489 delete [] buf_; 00490 buf_ = NULL; 00491 } 00492 }
Generated on Sun Oct 3 2010 17:42:16 for EXTRAS-SOCI by Doxygen 1.7.1