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 #define SOCI_ODBC_SOURCE 00009 #include "soci-odbc.h" 00010 #include <cctype> 00011 #include <cstdio> 00012 #include <cstring> 00013 #include <ctime> 00014 #include <sstream> 00015 00016 #ifdef _MSC_VER 00017 // disables the warning about converting int to void*. This is a 64 bit compatibility 00018 // warning, but odbc requires the value to be converted on this line 00019 // SQLSetStmtAttr(statement_.hstmt_, SQL_ATTR_PARAMSET_SIZE, (SQLPOINTER)arraySize, 0); 00020 #pragma warning(disable:4312) 00021 #endif 00022 00023 00024 using namespace soci; 00025 using namespace soci::details; 00026 00027 void odbc_vector_use_type_backend::prepare_indicators(std::size_t size) 00028 { 00029 if (size == 0) 00030 { 00031 throw soci_error("Vectors of size 0 are not allowed."); 00032 } 00033 00034 indHolderVec_.resize(size); 00035 indHolders_ = &indHolderVec_[0]; 00036 } 00037 00038 void odbc_vector_use_type_backend::prepare_for_bind(void *&data, SQLUINTEGER &size, 00039 SQLSMALLINT &sqlType, SQLSMALLINT &cType) 00040 { 00041 switch (type_) 00042 { // simple cases 00043 case x_short: 00044 { 00045 sqlType = SQL_SMALLINT; 00046 cType = SQL_C_SSHORT; 00047 size = sizeof(short); 00048 std::vector<short> *vp = static_cast<std::vector<short> *>(data); 00049 std::vector<short> &v(*vp); 00050 prepare_indicators(v.size()); 00051 data = &v[0]; 00052 } 00053 break; 00054 case x_integer: 00055 { 00056 sqlType = SQL_INTEGER; 00057 cType = SQL_C_SLONG; 00058 size = sizeof(int); 00059 std::vector<int> *vp = static_cast<std::vector<int> *>(data); 00060 std::vector<int> &v(*vp); 00061 prepare_indicators(v.size()); 00062 data = &v[0]; 00063 } 00064 break; 00065 case x_unsigned_long: 00066 { 00067 sqlType = SQL_BIGINT; 00068 cType = SQL_C_ULONG; 00069 size = sizeof(unsigned long); 00070 std::vector<unsigned long> *vp 00071 = static_cast<std::vector<unsigned long> *>(data); 00072 std::vector<unsigned long> &v(*vp); 00073 prepare_indicators(v.size()); 00074 data = &v[0]; 00075 } 00076 break; 00077 case x_double: 00078 { 00079 sqlType = SQL_DOUBLE; 00080 cType = SQL_C_DOUBLE; 00081 size = sizeof(double); 00082 std::vector<double> *vp = static_cast<std::vector<double> *>(data); 00083 std::vector<double> &v(*vp); 00084 prepare_indicators(v.size()); 00085 data = &v[0]; 00086 } 00087 break; 00088 00089 // cases that require adjustments and buffer management 00090 case x_char: 00091 { 00092 std::vector<char> *vp 00093 = static_cast<std::vector<char> *>(data); 00094 std::size_t const vsize = vp->size(); 00095 00096 prepare_indicators(vsize); 00097 00098 size = sizeof(char) * 2; 00099 buf_ = new char[size * vsize]; 00100 00101 char *pos = buf_; 00102 00103 for (std::size_t i = 0; i != vsize; ++i) 00104 { 00105 *pos++ = (*vp)[i]; 00106 *pos++ = 0; 00107 } 00108 00109 sqlType = SQL_CHAR; 00110 cType = SQL_C_CHAR; 00111 data = buf_; 00112 } 00113 break; 00114 case x_stdstring: 00115 { 00116 sqlType = SQL_CHAR; 00117 cType = SQL_C_CHAR; 00118 00119 std::vector<std::string> *vp 00120 = static_cast<std::vector<std::string> *>(data); 00121 std::vector<std::string> &v(*vp); 00122 00123 std::size_t maxSize = 0; 00124 std::size_t const vecSize = v.size(); 00125 prepare_indicators(vecSize); 00126 for (std::size_t i = 0; i != vecSize; ++i) 00127 { 00128 std::size_t sz = v[i].length() + 1; // add one for null 00129 indHolderVec_[i] = static_cast<long>(sz); 00130 maxSize = sz > maxSize ? sz : maxSize; 00131 } 00132 00133 buf_ = new char[maxSize * vecSize]; 00134 memset(buf_, 0, maxSize * vecSize); 00135 00136 char *pos = buf_; 00137 for (std::size_t i = 0; i != vecSize; ++i) 00138 { 00139 strncpy(pos, v[i].c_str(), v[i].length()); 00140 pos += maxSize; 00141 } 00142 00143 data = buf_; 00144 size = static_cast<SQLINTEGER>(maxSize); 00145 } 00146 break; 00147 case x_stdtm: 00148 { 00149 std::vector<std::tm> *vp 00150 = static_cast<std::vector<std::tm> *>(data); 00151 00152 prepare_indicators(vp->size()); 00153 00154 buf_ = new char[sizeof(TIMESTAMP_STRUCT) * vp->size()]; 00155 00156 sqlType = SQL_TYPE_TIMESTAMP; 00157 cType = SQL_C_TYPE_TIMESTAMP; 00158 data = buf_; 00159 size = 19; // This number is not the size in bytes, but the number 00160 // of characters in the date if it was written out 00161 // yyyy-mm-dd hh:mm:ss 00162 } 00163 break; 00164 00165 case x_statement: break; // not supported 00166 case x_rowid: break; // not supported 00167 case x_blob: break; // not supported 00168 } 00169 00170 colSize_ = size; 00171 } 00172 00173 void odbc_vector_use_type_backend::bind_helper(int &position, void *data, exchange_type type) 00174 { 00175 data_ = data; // for future reference 00176 type_ = type; // for future reference 00177 00178 SQLSMALLINT sqlType; 00179 SQLSMALLINT cType; 00180 SQLUINTEGER size; 00181 00182 prepare_for_bind(data, size, sqlType, cType); 00183 00184 SQLINTEGER arraySize = (SQLINTEGER)indHolderVec_.size(); 00185 SQLSetStmtAttr(statement_.hstmt_, SQL_ATTR_PARAMSET_SIZE, (SQLPOINTER)arraySize, 0); 00186 00187 SQLRETURN rc = SQLBindParameter(statement_.hstmt_, static_cast<SQLUSMALLINT>(position++), 00188 SQL_PARAM_INPUT, cType, sqlType, size, 0, 00189 static_cast<SQLPOINTER>(data), size, indHolders_); 00190 00191 if (is_odbc_error(rc)) 00192 { 00193 throw odbc_soci_error(SQL_HANDLE_STMT, statement_.hstmt_, 00194 "Error while binding value to column"); 00195 } 00196 } 00197 00198 void odbc_vector_use_type_backend::bind_by_pos(int &position, 00199 void *data, exchange_type type) 00200 { 00201 if (statement_.boundByName_) 00202 { 00203 throw soci_error( 00204 "Binding for use elements must be either by position or by name."); 00205 } 00206 00207 bind_helper(position, data, type); 00208 00209 statement_.boundByPos_ = true; 00210 } 00211 00212 void odbc_vector_use_type_backend::bind_by_name( 00213 std::string const &name, void *data, exchange_type type) 00214 { 00215 if (statement_.boundByPos_) 00216 { 00217 throw soci_error( 00218 "Binding for use elements must be either by position or by name."); 00219 } 00220 00221 int position = -1; 00222 int count = 1; 00223 00224 for (std::vector<std::string>::iterator it = statement_.names_.begin(); 00225 it != statement_.names_.end(); ++it) 00226 { 00227 if (*it == name) 00228 { 00229 position = count; 00230 break; 00231 } 00232 count++; 00233 } 00234 00235 if (position != -1) 00236 { 00237 bind_helper(position, data, type); 00238 } 00239 else 00240 { 00241 std::ostringstream ss; 00242 ss << "Unable to find name '" << name << "' to bind to"; 00243 throw soci_error(ss.str().c_str()); 00244 } 00245 00246 statement_.boundByName_ = true; 00247 } 00248 00249 void odbc_vector_use_type_backend::pre_use(indicator const *ind) 00250 { 00251 // first deal with data 00252 if (type_ == x_stdtm) 00253 { 00254 std::vector<std::tm> *vp 00255 = static_cast<std::vector<std::tm> *>(data_); 00256 00257 std::vector<std::tm> &v(*vp); 00258 00259 char *pos = buf_; 00260 std::size_t const vsize = v.size(); 00261 for (std::size_t i = 0; i != vsize; ++i) 00262 { 00263 std::tm t = v[i]; 00264 TIMESTAMP_STRUCT * ts = reinterpret_cast<TIMESTAMP_STRUCT*>(pos); 00265 00266 ts->year = static_cast<SQLSMALLINT>(t.tm_year + 1900); 00267 ts->month = static_cast<SQLUSMALLINT>(t.tm_mon + 1); 00268 ts->day = static_cast<SQLUSMALLINT>(t.tm_mday); 00269 ts->hour = static_cast<SQLUSMALLINT>(t.tm_hour); 00270 ts->minute = static_cast<SQLUSMALLINT>(t.tm_min); 00271 ts->second = static_cast<SQLUSMALLINT>(t.tm_sec); 00272 ts->fraction = 0; 00273 pos += sizeof(TIMESTAMP_STRUCT); 00274 } 00275 } 00276 00277 // then handle indicators 00278 if (ind != NULL) 00279 { 00280 std::size_t const vsize = size(); 00281 for (std::size_t i = 0; i != vsize; ++i, ++ind) 00282 { 00283 if (*ind == i_null) 00284 { 00285 indHolderVec_[i] = SQL_NULL_DATA; // null 00286 } 00287 else 00288 { 00289 // for strings we have already set the values 00290 if (type_ != x_stdstring) 00291 { 00292 indHolderVec_[i] = SQL_NTS; // value is OK 00293 } 00294 } 00295 } 00296 } 00297 else 00298 { 00299 // no indicators - treat all fields as OK 00300 std::size_t const vsize = size(); 00301 for (std::size_t i = 0; i != vsize; ++i, ++ind) 00302 { 00303 // for strings we have already set the values 00304 if (type_ != x_stdstring) 00305 { 00306 indHolderVec_[i] = SQL_NTS; // value is OK 00307 } 00308 } 00309 } 00310 } 00311 00312 std::size_t odbc_vector_use_type_backend::size() 00313 { 00314 std::size_t sz = 0; // dummy initialization to please the compiler 00315 switch (type_) 00316 { 00317 // simple cases 00318 case x_char: 00319 { 00320 std::vector<char> *vp = static_cast<std::vector<char> *>(data_); 00321 sz = vp->size(); 00322 } 00323 break; 00324 case x_short: 00325 { 00326 std::vector<short> *vp = static_cast<std::vector<short> *>(data_); 00327 sz = vp->size(); 00328 } 00329 break; 00330 case x_integer: 00331 { 00332 std::vector<int> *vp = static_cast<std::vector<int> *>(data_); 00333 sz = vp->size(); 00334 } 00335 break; 00336 case x_unsigned_long: 00337 { 00338 std::vector<unsigned long> *vp 00339 = static_cast<std::vector<unsigned long> *>(data_); 00340 sz = vp->size(); 00341 } 00342 break; 00343 case x_double: 00344 { 00345 std::vector<double> *vp 00346 = static_cast<std::vector<double> *>(data_); 00347 sz = vp->size(); 00348 } 00349 break; 00350 case x_stdstring: 00351 { 00352 std::vector<std::string> *vp 00353 = static_cast<std::vector<std::string> *>(data_); 00354 sz = vp->size(); 00355 } 00356 break; 00357 case x_stdtm: 00358 { 00359 std::vector<std::tm> *vp 00360 = static_cast<std::vector<std::tm> *>(data_); 00361 sz = vp->size(); 00362 } 00363 break; 00364 00365 case x_statement: break; // not supported 00366 case x_rowid: break; // not supported 00367 case x_blob: break; // not supported 00368 } 00369 00370 return sz; 00371 } 00372 00373 void odbc_vector_use_type_backend::clean_up() 00374 { 00375 if (buf_ != NULL) 00376 { 00377 delete [] buf_; 00378 buf_ = NULL; 00379 } 00380 }
Generated on Sun Oct 3 2010 17:42:16 for EXTRAS-SOCI by Doxygen 1.7.1