00001 // 00002 // Copyright (C) 2004-2008 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_POSTGRESQL_SOURCE 00009 #include "soci-postgresql.h" 00010 // 00011 #if defined(SOCI_HEADERS_BURIED) 00012 # include <soci/core/blob.h> 00013 # include <soci/core/rowid.h> 00014 #else 00015 # include <blob.h> 00016 # include <rowid.h> 00017 #endif 00018 // 00019 #include <libpq/libpq-fs.h> // libpq (PostGreSQL client) 00020 #include <cctype> 00021 #include <cstdio> 00022 #include <cstring> 00023 #include <ctime> 00024 #include <limits> 00025 #include <sstream> 00026 00027 #ifdef SOCI_PGSQL_NOPARAMS 00028 #define SOCI_PGSQL_NOBINDBYNAME 00029 #endif // SOCI_PGSQL_NOPARAMS 00030 00031 #ifdef _MSC_VER 00032 #pragma warning(disable:4355 4996) 00033 #define snprintf _snprintf 00034 #endif 00035 00036 using namespace soci; 00037 using namespace soci::details; 00038 00039 00040 void postgresql_standard_use_type_backend::bind_by_pos( 00041 int & position, void * data, exchange_type type, bool /* readOnly */) 00042 { 00043 // readOnly is ignored, because PostgreSQL does not support 00044 // any data to be written back to used (bound) objects. 00045 00046 data_ = data; 00047 type_ = type; 00048 position_ = position++; 00049 } 00050 00051 void postgresql_standard_use_type_backend::bind_by_name( 00052 std::string const & name, void * data, exchange_type type, bool /* readOnly */) 00053 { 00054 // readOnly is ignored, because PostgreSQL does not support 00055 // any data to be written back to used (bound) objects. 00056 00057 data_ = data; 00058 type_ = type; 00059 name_ = name; 00060 } 00061 00062 void postgresql_standard_use_type_backend::pre_use(indicator const * ind) 00063 { 00064 if (ind != NULL && *ind == i_null) 00065 { 00066 // leave the working buffer as NULL 00067 } 00068 else 00069 { 00070 // allocate and fill the buffer with text-formatted client data 00071 switch (type_) 00072 { 00073 case x_char: 00074 { 00075 buf_ = new char[2]; 00076 buf_[0] = *static_cast<char *>(data_); 00077 buf_[1] = '\0'; 00078 } 00079 break; 00080 case x_stdstring: 00081 { 00082 std::string * s = static_cast<std::string *>(data_); 00083 buf_ = new char[s->size() + 1]; 00084 std::strcpy(buf_, s->c_str()); 00085 } 00086 break; 00087 case x_short: 00088 { 00089 std::size_t const bufSize 00090 = std::numeric_limits<short>::digits10 + 3; 00091 buf_ = new char[bufSize]; 00092 snprintf(buf_, bufSize, "%d", 00093 static_cast<int>(*static_cast<short *>(data_))); 00094 } 00095 break; 00096 case x_integer: 00097 { 00098 std::size_t const bufSize 00099 = std::numeric_limits<int>::digits10 + 3; 00100 buf_ = new char[bufSize]; 00101 snprintf(buf_, bufSize, "%d", 00102 *static_cast<int *>(data_)); 00103 } 00104 break; 00105 case x_unsigned_long: 00106 { 00107 std::size_t const bufSize 00108 = std::numeric_limits<unsigned long>::digits10 + 2; 00109 buf_ = new char[bufSize]; 00110 snprintf(buf_, bufSize, "%lu", 00111 *static_cast<unsigned long *>(data_)); 00112 } 00113 break; 00114 case x_long_long: 00115 { 00116 std::size_t const bufSize 00117 = std::numeric_limits<long long>::digits10 + 3; 00118 buf_ = new char[bufSize]; 00119 snprintf(buf_, bufSize, "%lld", 00120 *static_cast<long long *>(data_)); 00121 } 00122 break; 00123 case x_double: 00124 { 00125 // no need to overengineer it (KISS)... 00126 00127 std::size_t const bufSize = 100; 00128 buf_ = new char[bufSize]; 00129 00130 snprintf(buf_, bufSize, "%.20g", 00131 *static_cast<double *>(data_)); 00132 } 00133 break; 00134 case x_stdtm: 00135 { 00136 std::size_t const bufSize = 20; 00137 buf_ = new char[bufSize]; 00138 00139 std::tm * t = static_cast<std::tm *>(data_); 00140 snprintf(buf_, bufSize, "%d-%02d-%02d %02d:%02d:%02d", 00141 t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, 00142 t->tm_hour, t->tm_min, t->tm_sec); 00143 } 00144 break; 00145 case x_rowid: 00146 { 00147 // RowID is internally identical to unsigned long 00148 00149 rowid * rid = static_cast<rowid *>(data_); 00150 postgresql_rowid_backend * rbe 00151 = static_cast<postgresql_rowid_backend *>( 00152 rid->get_backend()); 00153 00154 std::size_t const bufSize 00155 = std::numeric_limits<unsigned long>::digits10 + 2; 00156 buf_ = new char[bufSize]; 00157 00158 snprintf(buf_, bufSize, "%lu", rbe->value_); 00159 } 00160 break; 00161 case x_blob: 00162 { 00163 blob * b = static_cast<blob *>(data_); 00164 postgresql_blob_backend * bbe = 00165 static_cast<postgresql_blob_backend *>(b->get_backend()); 00166 00167 std::size_t const bufSize 00168 = std::numeric_limits<unsigned long>::digits10 + 2; 00169 buf_ = new char[bufSize]; 00170 snprintf(buf_, bufSize, "%lu", bbe->oid_); 00171 } 00172 break; 00173 00174 default: 00175 throw soci_error("Use element used with non-supported type."); 00176 } 00177 } 00178 00179 if (position_ > 0) 00180 { 00181 // binding by position 00182 statement_.useByPosBuffers_[position_] = &buf_; 00183 } 00184 else 00185 { 00186 // binding by name 00187 statement_.useByNameBuffers_[name_] = &buf_; 00188 } 00189 } 00190 00191 void postgresql_standard_use_type_backend::post_use( 00192 bool /* gotData */, indicator * /* ind */) 00193 { 00194 // PostgreSQL does not support any data moving back the same channel, 00195 // so there is nothing to do here. 00196 // In particular, there is nothing to protect, because both const and non-const 00197 // objects will never be modified. 00198 00199 // clean up the working buffer, it might be allocated anew in 00200 // the next run of preUse 00201 clean_up(); 00202 } 00203 00204 void postgresql_standard_use_type_backend::clean_up() 00205 { 00206 if (buf_ != NULL) 00207 { 00208 delete [] buf_; 00209 buf_ = NULL; 00210 } 00211 }
Generated on Sun Oct 3 2010 17:42:16 for EXTRAS-SOCI by Doxygen 1.7.1