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 // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton, David Courtney
00002 // Distributed under the Boost Software License, Version 1.0.
00003 // (See accompanying file LICENSE_1_0.txt or copy at
00004 // http://www.boost.org/LICENSE_1_0.txt)
00005 
00006 #define SOCI_ODBC_SOURCE
00007 #include "soci-odbc.h"
00008 #include <cctype>
00009 #include <cstdio>
00010 #include <cstring>
00011 #include <ctime>
00012 #include <sstream>
00013 
00014 using namespace soci;
00015 using namespace soci::details;
00016 
00017 void odbc_standard_use_type_backend::prepare_for_bind(
00018     void *&data, SQLLEN &size, SQLSMALLINT &sqlType, SQLSMALLINT &cType)
00019 {
00020     switch (type_)
00021     {
00022     // simple cases
00023     case x_short:
00024         sqlType = SQL_SMALLINT;
00025         cType = SQL_C_SSHORT;
00026         size = sizeof(short);
00027         break;
00028     case x_integer:
00029         sqlType = SQL_INTEGER;
00030         cType = SQL_C_SLONG;
00031         size = sizeof(int);
00032         break;
00033     case x_unsigned_long:
00034         sqlType = SQL_BIGINT;
00035         cType = SQL_C_ULONG;
00036         size = sizeof(unsigned long);
00037         break;
00038     case x_double:
00039         sqlType = SQL_DOUBLE;
00040         cType = SQL_C_DOUBLE;
00041         size = sizeof(double);
00042         break;
00043 
00044     // cases that require adjustments and buffer management
00045     case x_char:
00046         sqlType = SQL_CHAR;
00047         cType = SQL_C_CHAR;
00048         size = sizeof(char)+1;
00049         buf_ = new char[size];
00050         data = buf_;
00051         indHolder_ = SQL_NTS;
00052         break;
00053     case x_stdstring:
00054     {
00055         // TODO: No textual value is assigned here!
00056 
00057         std::string* s = static_cast<std::string*>(data);
00058         sqlType = SQL_VARCHAR;
00059         cType = SQL_C_CHAR;
00060         size = 255; // !FIXME this is not sufficent
00061         buf_ = new char[size];
00062         data = buf_;
00063         indHolder_ = SQL_NTS;
00064     }
00065     break;
00066     case x_stdtm:
00067         sqlType = SQL_TIMESTAMP;
00068         cType = SQL_C_TIMESTAMP;
00069         buf_ = new char[sizeof(TIMESTAMP_STRUCT)];
00070         data = buf_;
00071         size = 19; // This number is not the size in bytes, but the number
00072                    // of characters in the date if it was written out
00073                    // yyyy-mm-dd hh:mm:ss
00074         break;
00075 
00076     case x_blob:
00077     {
00078 //         sqlType = SQL_VARBINARY;
00079 //         cType = SQL_C_BINARY;
00080 
00081 //         BLOB *b = static_cast<BLOB *>(data);
00082 
00083 //         odbc_blob_backend *bbe
00084 //         = static_cast<odbc_blob_backend *>(b->getBackEnd());
00085 
00086 //         size = 0;
00087 //         indHolder_ = size;
00088         //TODO            data = &bbe->lobp_;
00089     }
00090     break;
00091     case x_statement:
00092     case x_rowid:
00093         break;
00094     }
00095 }
00096 
00097 void odbc_standard_use_type_backend::bind_helper(int &position, void *data, exchange_type type)
00098 {
00099     data_ = data; // for future reference
00100     type_ = type; // for future reference
00101 
00102     SQLSMALLINT sqlType;
00103     SQLSMALLINT cType;
00104     SQLLEN size;
00105 
00106     prepare_for_bind(data, size, sqlType, cType);
00107 
00108     SQLRETURN rc = SQLBindParameter(statement_.hstmt_,
00109                                     static_cast<SQLUSMALLINT>(position++),
00110                                     SQL_PARAM_INPUT,
00111                                     cType, sqlType, size, 0, data, 0, &indHolder_);
00112 
00113     if (is_odbc_error(rc))
00114     {
00115         throw odbc_soci_error(SQL_HANDLE_STMT, statement_.hstmt_,
00116                                 "Binding");
00117     }
00118 }
00119 
00120 void odbc_standard_use_type_backend::bind_by_pos(
00121     int &position, void *data, exchange_type type, bool /* readOnly */)
00122 {
00123     if (statement_.boundByName_)
00124     {
00125         throw soci_error(
00126          "Binding for use elements must be either by position or by name.");
00127     }
00128 
00129     bind_helper(position, data, type);
00130 
00131     statement_.boundByPos_ = true;
00132 }
00133 
00134 void odbc_standard_use_type_backend::bind_by_name(
00135     std::string const &name, void *data, exchange_type type, bool /* readOnly */)
00136 {
00137     if (statement_.boundByPos_)
00138     {
00139         throw soci_error(
00140          "Binding for use elements must be either by position or by name.");
00141     }
00142 
00143     int position = -1;
00144     int count = 1;
00145 
00146     for (std::vector<std::string>::iterator it = statement_.names_.begin();
00147          it != statement_.names_.end(); ++it)
00148     {
00149         if (*it == name)
00150         {
00151             position = count;
00152             break;
00153         }
00154         count++;
00155     }
00156 
00157     if (position != -1)
00158     {
00159         bind_helper(position, data, type);
00160     }
00161     else
00162     {
00163         std::ostringstream ss;
00164         ss << "Unable to find name '" << name << "' to bind to";
00165         throw soci_error(ss.str().c_str());
00166     }
00167 
00168     statement_.boundByName_ = true;
00169 }
00170 
00171 void odbc_standard_use_type_backend::pre_use(indicator const *ind)
00172 {
00173     // first deal with data
00174     if (type_ == x_char)
00175     {
00176         char *c = static_cast<char*>(data_);
00177         buf_[0] = *c;
00178         buf_[1] = '\0';
00179     }
00180     else if (type_ == x_stdstring)
00181     {
00182         std::string *s = static_cast<std::string *>(data_);
00183 
00184         std::size_t const bufSize = 4000;
00185         std::size_t const sSize = s->size();
00186         std::size_t const toCopy =
00187             sSize < bufSize -1 ? sSize + 1 : bufSize - 1;
00188         strncpy(buf_, s->c_str(), toCopy);
00189         buf_[toCopy] = '\0';
00190     }
00191     else if (type_ == x_stdtm)
00192     {
00193         std::tm *t = static_cast<std::tm *>(data_);
00194         TIMESTAMP_STRUCT * ts = reinterpret_cast<TIMESTAMP_STRUCT*>(buf_);
00195 
00196         ts->year = static_cast<SQLSMALLINT>(t->tm_year + 1900);
00197         ts->month = static_cast<SQLUSMALLINT>(t->tm_mon + 1);
00198         ts->day = static_cast<SQLUSMALLINT>(t->tm_mday);
00199         ts->hour = static_cast<SQLUSMALLINT>(t->tm_hour);
00200         ts->minute = static_cast<SQLUSMALLINT>(t->tm_min);
00201         ts->second = static_cast<SQLUSMALLINT>(t->tm_sec);
00202         ts->fraction = 0;
00203     }
00204 
00205     // then handle indicators
00206     if (ind != NULL && *ind == i_null)
00207     {
00208         indHolder_ = SQL_NULL_DATA; // null
00209     }
00210 }
00211 
00212 void odbc_standard_use_type_backend::post_use(bool gotData, indicator *ind)
00213 {
00214     // TODO: Is it possible to have the bound element being overwritten
00215     // by the database? (looks like yes)
00216     // If not, then nothing to do here, please remove this comment
00217     //         and most likely the code below is also unnecessary.
00218     // If yes, then use the value of the readOnly parameter:
00219     // - true:  the given object should not be modified and the backend
00220     //          should detect if the modification was performed on the
00221     //          isolated buffer and throw an exception if the buffer was modified
00222     //          (this indicates logic error, because the user used const object
00223     //          and executed a query that attempted to modified it)
00224     // - false: the modification should be propagated to the given object (as below).
00225     //
00226     // From the code below I conclude that ODBC allows the database to modify the bound object
00227     // and the code below correctly deals with readOnly == false.
00228     // The point is that with readOnly == true the propagation of modification should not
00229     // take place and in addition the attempt of modification should be detected and reported.
00230     // ...
00231 
00232     // first, deal with data
00233     if (gotData)
00234     {
00235         if (type_ == x_char)
00236         {
00237             char *c = static_cast<char*>(data_);
00238             *c = buf_[0];
00239         }
00240         else if (type_ == x_stdstring)
00241         {
00242             std::string *s = static_cast<std::string *>(data_);
00243 
00244             *s = buf_;
00245         }
00246         else if (type_ == x_stdtm)
00247         {
00248             std::tm *t = static_cast<std::tm *>(data_);
00249             TIMESTAMP_STRUCT * ts = reinterpret_cast<TIMESTAMP_STRUCT*>(buf_);
00250             t->tm_isdst = -1;
00251             t->tm_year = ts->year - 1900;
00252             t->tm_mon = ts->month - 1;
00253             t->tm_mday = ts->day;
00254             t->tm_hour = ts->hour;
00255             t->tm_min = ts->minute;
00256             t->tm_sec = ts->second;
00257 
00258             // normalize and compute the remaining fields
00259             std::mktime(t);
00260         }
00261     }
00262 
00263     if (ind != NULL)
00264     {
00265         if (gotData)
00266         {
00267             if (indHolder_ == 0)
00268             {
00269                 *ind = i_ok;
00270             }
00271             else if (indHolder_ == SQL_NULL_DATA)
00272             {
00273                 *ind = i_null;
00274             }
00275             else
00276             {
00277                 *ind = i_truncated;
00278             }
00279         }
00280     }
00281 }
00282 
00283 void odbc_standard_use_type_backend::clean_up()
00284 {
00285     if (buf_ != NULL)
00286     {
00287         delete [] buf_;
00288         buf_ = NULL;
00289     }
00290 }
 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