File indexing completed on 2025-02-23 05:15:11
0001 // 0002 // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton, Rafal Bobrowski 0003 // Distributed under the Boost Software License, Version 1.0. 0004 // (See accompanying file LICENSE_1_0.txt or copy at 0005 // http://www.boost.org/LICENSE_1_0.txt) 0006 // 0007 0008 #ifndef SOCI_FIREBIRD_COMMON_H_INCLUDED 0009 #define SOCI_FIREBIRD_COMMON_H_INCLUDED 0010 0011 #include "soci/firebird/soci-firebird.h" 0012 #include "soci-compiler.h" 0013 #include <cstdlib> 0014 #include <cstring> 0015 #include <ctime> 0016 #include <limits> 0017 #include <sstream> 0018 #include <iomanip> 0019 #include <string> 0020 #include <vector> 0021 #include <algorithm> 0022 0023 namespace soci 0024 { 0025 0026 namespace details 0027 { 0028 0029 namespace firebird 0030 { 0031 0032 char * allocBuffer(XSQLVAR* var); 0033 0034 void tmEncode(short type, std::tm * src, void * dst); 0035 0036 void tmDecode(short type, void * src, std::tm * dst); 0037 0038 void setTextParam(char const * s, std::size_t size, char * buf_, 0039 XSQLVAR * var); 0040 0041 std::string getTextParam(XSQLVAR const *var); 0042 0043 // Copy contents of a BLOB in buf into the given string. 0044 void copy_from_blob(firebird_statement_backend &st, char *buf, std::string &out); 0045 0046 template <typename IntType> 0047 const char *str2dec(const char * s, IntType &out, short &scale) 0048 { 0049 int sign = 1; 0050 if ('+' == *s) 0051 ++s; 0052 else if ('-' == *s) 0053 { 0054 sign = -1; 0055 ++s; 0056 } 0057 scale = 0; 0058 bool period = false; 0059 IntType res = 0; 0060 for (out = 0; *s; ++s, out = res) 0061 { 0062 if (*s == '.') 0063 { 0064 if (period) 0065 return s; 0066 period = true; 0067 continue; 0068 } 0069 int d = *s - '0'; 0070 if (d < 0 || d > 9) 0071 return s; 0072 res = res * 10 + static_cast<IntType>(d * sign); 0073 if (1 == sign) 0074 { 0075 if (res < out) 0076 return s; 0077 } 0078 else 0079 { 0080 if (res > out) 0081 return s; 0082 } 0083 if (period) 0084 ++scale; 0085 } 0086 return s; 0087 } 0088 0089 template <typename T> 0090 inline 0091 T round_for_isc(T value) 0092 { 0093 return value; 0094 } 0095 0096 inline 0097 double round_for_isc(double value) 0098 { 0099 // Unfortunately all the rounding functions are C99 and so are not supported 0100 // by MSVC, so do it manually. 0101 return value < 0 ? value - 0.5 : value + 0.5; 0102 } 0103 0104 //helper template to generate proper code based on compile time type check 0105 template<bool cond> struct cond_to_isc {}; 0106 template<> struct cond_to_isc<false> 0107 { 0108 static void checkInteger(short scale, short type) 0109 { 0110 if( scale >= 0 && (type == SQL_SHORT || type == SQL_LONG || type == SQL_INT64) ) 0111 throw soci_error("Can't convert non-integral value to integral column type"); 0112 } 0113 }; 0114 template<> struct cond_to_isc<true> 0115 { 0116 static void checkInteger(short scale,short type) { SOCI_UNUSED(scale) SOCI_UNUSED(type) } 0117 }; 0118 0119 template<typename T1> 0120 void to_isc(void * val, XSQLVAR * var, short x_scale = 0) 0121 { 0122 T1 value = *reinterpret_cast<T1*>(val); 0123 short scale = var->sqlscale + x_scale; 0124 short type = var->sqltype & ~1; 0125 long long divisor = 1, multiplier = 1; 0126 0127 cond_to_isc<std::numeric_limits<T1>::is_integer>::checkInteger(scale,type); 0128 0129 for (int i = 0; i > scale; --i) 0130 multiplier *= 10; 0131 for (int i = 0; i < scale; ++i) 0132 divisor *= 10; 0133 0134 switch (type) 0135 { 0136 case SQL_SHORT: 0137 { 0138 short tmp = static_cast<short>(round_for_isc(value*multiplier)/divisor); 0139 std::memcpy(var->sqldata, &tmp, sizeof(short)); 0140 } 0141 break; 0142 case SQL_LONG: 0143 { 0144 int tmp = static_cast<int>(round_for_isc(value*multiplier)/divisor); 0145 std::memcpy(var->sqldata, &tmp, sizeof(int)); 0146 } 0147 break; 0148 case SQL_INT64: 0149 { 0150 long long tmp = static_cast<long long>(round_for_isc(value*multiplier)/divisor); 0151 std::memcpy(var->sqldata, &tmp, sizeof(long long)); 0152 } 0153 break; 0154 case SQL_FLOAT: 0155 { 0156 float sql_value = static_cast<float>(value); 0157 std::memcpy(var->sqldata, &sql_value, sizeof(float)); 0158 } 0159 break; 0160 case SQL_DOUBLE: 0161 { 0162 double sql_value = static_cast<double>(value); 0163 std::memcpy(var->sqldata, &sql_value, sizeof(double)); 0164 } 0165 break; 0166 default: 0167 throw soci_error("Incorrect data type for numeric conversion"); 0168 } 0169 } 0170 0171 template<typename IntType, typename UIntType> 0172 void parse_decimal(void * val, XSQLVAR * var, const char * s) 0173 { 0174 short scale; 0175 UIntType t1; 0176 IntType t2; 0177 if (!*str2dec(s, t1, scale)) 0178 std::memcpy(val, &t1, sizeof(t1)); 0179 else if (!*str2dec(s, t2, scale)) 0180 std::memcpy(val, &t2, sizeof(t2)); 0181 else 0182 throw soci_error("Could not parse decimal value."); 0183 to_isc<IntType>(val, var, scale); 0184 } 0185 0186 template<typename IntType> 0187 std::string format_decimal(const void *sqldata, int sqlscale) 0188 { 0189 IntType x = *reinterpret_cast<const IntType *>(sqldata); 0190 std::stringstream out; 0191 out << x; 0192 std::string r = out.str(); 0193 if (sqlscale < 0) 0194 { 0195 if (static_cast<int>(r.size()) - (x < 0) <= -sqlscale) 0196 { 0197 r = std::string(size_t(x < 0), '-') + 0198 std::string(-sqlscale - (r.size() - (x < 0)) + 1, '0') + 0199 r.substr(size_t(x < 0), std::string::npos); 0200 } 0201 return r.substr(0, r.size() + sqlscale) + '.' + 0202 r.substr(r.size() + sqlscale, std::string::npos); 0203 } 0204 return r + std::string(sqlscale, '0'); 0205 } 0206 0207 0208 template<bool cond> struct cond_from_isc {}; 0209 template<> struct cond_from_isc<true> { 0210 static void checkInteger(short scale) 0211 { 0212 std::ostringstream msg; 0213 msg << "Can't convert value with scale " << -scale 0214 << " to integral type"; 0215 throw soci_error(msg.str()); 0216 } 0217 }; 0218 template<> struct cond_from_isc<false> 0219 { 0220 static void checkInteger(short scale) { SOCI_UNUSED(scale) } 0221 }; 0222 0223 template<typename T1> 0224 T1 from_isc(XSQLVAR * var) 0225 { 0226 short scale = var->sqlscale; 0227 T1 tens = 1; 0228 0229 if (scale < 0) 0230 { 0231 cond_from_isc<std::numeric_limits<T1>::is_integer>::checkInteger(scale); 0232 for (int i = 0; i > scale; --i) 0233 { 0234 tens *= 10; 0235 } 0236 } 0237 0238 SOCI_GCC_WARNING_SUPPRESS(cast-align) 0239 0240 switch (var->sqltype & ~1) 0241 { 0242 case SQL_SHORT: 0243 return static_cast<T1>(*reinterpret_cast<short*>(var->sqldata)/tens); 0244 case SQL_LONG: 0245 return static_cast<T1>(*reinterpret_cast<int*>(var->sqldata)/tens); 0246 case SQL_INT64: 0247 return static_cast<T1>(*reinterpret_cast<long long*>(var->sqldata)/tens); 0248 case SQL_FLOAT: 0249 return static_cast<T1>(*reinterpret_cast<float*>(var->sqldata)); 0250 case SQL_DOUBLE: 0251 return static_cast<T1>(*reinterpret_cast<double*>(var->sqldata)); 0252 default: 0253 throw soci_error("Incorrect data type for numeric conversion"); 0254 } 0255 0256 SOCI_GCC_WARNING_RESTORE(cast-align) 0257 } 0258 0259 } // namespace firebird 0260 0261 } // namespace details 0262 0263 } // namespace soci 0264 0265 #endif // SOCI_FIREBIRD_COMMON_H_INCLUDED