SOCI Logo Get SOCI at SourceForge.net. Fast, secure and Free Open Source software downloads

standard-use-type.cpp

Go to the documentation of this file.
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
SourceForge Logo

Generated on Sun Oct 3 2010 17:42:16 for EXTRAS-SOCI by Doxygen 1.7.1