00001 // 00002 // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton, David Courtney 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 00009 #include "soci-sqlite3.h" 00010 // 00011 #if defined(SOCI_HEADERS_BURIED) 00012 # include <soci/core/rowid.h> 00013 # include <soci/core/blob.h> 00014 #else 00015 # include <rowid.h> 00016 # include <blob.h> 00017 #endif 00018 // 00019 // STL 00020 #include <cstring> 00021 #include <ctime> 00022 #include <limits> 00023 #include <cstdio> 00024 #include <sstream> 00025 #include <string> 00026 00027 #ifdef _MSC_VER 00028 #pragma warning(disable:4355 4996) 00029 #define snprintf _snprintf 00030 #endif 00031 00032 using namespace soci; 00033 using namespace soci::details; 00034 00035 void sqlite3_standard_use_type_backend::bind_by_pos(int & position, void * data, 00036 exchange_type type, bool readOnly) 00037 { 00038 if (statement_.boundByName_) 00039 { 00040 throw soci_error( 00041 "Binding for use elements must be either by position or by name."); 00042 } 00043 00044 data_ = data; 00045 type_ = type; 00046 position_ = position++; 00047 00048 statement_.boundByPos_ = true; 00049 } 00050 00051 void sqlite3_standard_use_type_backend::bind_by_name(std::string const & name, 00052 void * data, exchange_type type, bool readOnly) 00053 { 00054 if (statement_.boundByPos_) 00055 { 00056 throw soci_error( 00057 "Binding for use elements must be either by position or by name."); 00058 } 00059 00060 data_ = data; 00061 type_ = type; 00062 name_ = ":" + name; 00063 00064 statement_.resetIfNeeded(); 00065 position_ = sqlite3_bind_parameter_index(statement_.stmt_, name_.c_str()); 00066 00067 if (0 == position_) 00068 { 00069 std::ostringstream ss; 00070 ss << "Cannot bind to (by name) " << name_; 00071 throw soci_error(ss.str()); 00072 } 00073 statement_.boundByName_ = true; 00074 } 00075 00076 void sqlite3_standard_use_type_backend::pre_use(indicator const * ind) 00077 { 00078 statement_.useData_.resize(1); 00079 int pos = position_ - 1; 00080 00081 if (statement_.useData_[0].size() < static_cast<std::size_t>(position_)) 00082 { 00083 statement_.useData_[0].resize(position_); 00084 } 00085 00086 if (ind != NULL && *ind == i_null) 00087 { 00088 statement_.useData_[0][pos].isNull_ = true; 00089 statement_.useData_[0][pos].data_ = ""; 00090 statement_.useData_[0][pos].blobBuf_ = 0; 00091 statement_.useData_[0][pos].blobSize_ = 0; 00092 } 00093 else 00094 { 00095 // allocate and fill the buffer with text-formatted client data 00096 switch (type_) 00097 { 00098 case x_char: 00099 { 00100 buf_ = new char[2]; 00101 buf_[0] = *static_cast<char*>(data_); 00102 buf_[1] = '\0'; 00103 } 00104 break; 00105 case x_stdstring: 00106 { 00107 std::string *s = static_cast<std::string *>(data_); 00108 buf_ = new char[s->size() + 1]; 00109 std::strcpy(buf_, s->c_str()); 00110 } 00111 break; 00112 case x_short: 00113 { 00114 std::size_t const bufSize 00115 = std::numeric_limits<short>::digits10 + 3; 00116 buf_ = new char[bufSize]; 00117 snprintf(buf_, bufSize, "%d", 00118 static_cast<int>(*static_cast<short*>(data_))); 00119 } 00120 break; 00121 case x_integer: 00122 { 00123 std::size_t const bufSize 00124 = std::numeric_limits<int>::digits10 + 3; 00125 buf_ = new char[bufSize]; 00126 snprintf(buf_, bufSize, "%d", 00127 *static_cast<int*>(data_)); 00128 } 00129 break; 00130 case x_unsigned_long: 00131 { 00132 std::size_t const bufSize 00133 = std::numeric_limits<unsigned long>::digits10 + 2; 00134 buf_ = new char[bufSize]; 00135 snprintf(buf_, bufSize, "%lu", 00136 *static_cast<unsigned long*>(data_)); 00137 } 00138 break; 00139 case x_long_long: 00140 { 00141 std::size_t const bufSize 00142 = std::numeric_limits<long long>::digits10 + 3; 00143 buf_ = new char[bufSize]; 00144 snprintf(buf_, bufSize, "%lld", 00145 *static_cast<long long *>(data_)); 00146 } 00147 break; 00148 case x_double: 00149 { 00150 // no need to overengineer it (KISS)... 00151 00152 std::size_t const bufSize = 100; 00153 buf_ = new char[bufSize]; 00154 00155 snprintf(buf_, bufSize, "%.20g", 00156 *static_cast<double*>(data_)); 00157 } 00158 break; 00159 case x_stdtm: 00160 { 00161 std::size_t const bufSize = 20; 00162 buf_ = new char[bufSize]; 00163 00164 std::tm *t = static_cast<std::tm *>(data_); 00165 snprintf(buf_, bufSize, "%d-%02d-%02d %02d:%02d:%02d", 00166 t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, 00167 t->tm_hour, t->tm_min, t->tm_sec); 00168 } 00169 break; 00170 case x_rowid: 00171 { 00172 // RowID is internally identical to unsigned long 00173 00174 rowid *rid = static_cast<rowid *>(data_); 00175 sqlite3_rowid_backend *rbe = static_cast<sqlite3_rowid_backend *>(rid->get_backend()); 00176 00177 std::size_t const bufSize 00178 = std::numeric_limits<unsigned long>::digits10 + 2; 00179 buf_ = new char[bufSize]; 00180 00181 snprintf(buf_, bufSize, "%lu", rbe->value_); 00182 } 00183 break; 00184 case x_blob: 00185 { 00186 blob *b = static_cast<blob *>(data_); 00187 sqlite3_blob_backend *bbe = 00188 static_cast<sqlite3_blob_backend *>(b->get_backend()); 00189 00190 std::size_t len = bbe->get_len(); 00191 buf_ = new char[len]; 00192 bbe->read(0, buf_, len); 00193 statement_.useData_[0][pos].blobBuf_ = buf_; 00194 statement_.useData_[0][pos].blobSize_ = len; 00195 } 00196 break; 00197 00198 default: 00199 throw soci_error("Use element used with non-supported type."); 00200 } 00201 00202 statement_.useData_[0][pos].isNull_ = false; 00203 if (type_ != x_blob) 00204 { 00205 statement_.useData_[0][pos].blobBuf_ = 0; 00206 statement_.useData_[0][pos].blobSize_ = 0; 00207 statement_.useData_[0][pos].data_ = buf_; 00208 } 00209 } 00210 } 00211 00212 void sqlite3_standard_use_type_backend::post_use( 00213 bool /* gotData */, indicator * /* ind */) 00214 { 00215 // TODO: Is it possible to have the bound element being overwritten 00216 // by the database? 00217 // If not, then nothing to do here, please remove this comment. 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. 00225 // ... 00226 00227 // clean up the working buffer, it might be allocated anew in 00228 // the next run of preUse 00229 clean_up(); 00230 } 00231 00232 void sqlite3_standard_use_type_backend::clean_up() 00233 { 00234 if (buf_ != NULL) 00235 { 00236 delete [] buf_; 00237 buf_ = NULL; 00238 } 00239 }
Generated on Sun Oct 3 2010 17:42:16 for EXTRAS-SOCI by Doxygen 1.7.1