File indexing completed on 2025-02-23 05:15:16
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 #include "soci/soci-platform.h" 0009 #include "firebird/common.h" 0010 #include "soci/soci-backend.h" 0011 #include "soci-compiler.h" 0012 #include <ibase.h> // FireBird 0013 #include <cstddef> 0014 #include <cstring> 0015 #include <cstdio> 0016 #include <sstream> 0017 #include <iostream> 0018 #include <string> 0019 0020 namespace soci 0021 { 0022 0023 namespace details 0024 { 0025 0026 namespace firebird 0027 { 0028 0029 char * allocBuffer(XSQLVAR* var) 0030 { 0031 std::size_t size; 0032 int type = var->sqltype & ~1; 0033 if (type == SQL_VARYING) 0034 { 0035 size = var->sqllen + sizeof(short); 0036 } 0037 else if (type == SQL_TIMESTAMP || type == SQL_TYPE_TIME 0038 || type == SQL_TYPE_DATE) 0039 { 0040 size = sizeof(std::tm); 0041 } 0042 else 0043 { 0044 size = var->sqllen; 0045 } 0046 0047 return new char[size]; 0048 } 0049 0050 void tmEncode(short type, std::tm * src, void * dst) 0051 { 0052 switch (type & ~1) 0053 { 0054 // In Interbase v6 DATE represents a date-only data type, 0055 // in InterBase v5 DATE represents a date+time data type. 0056 case SQL_TIMESTAMP: 0057 isc_encode_timestamp(src, static_cast<ISC_TIMESTAMP*>(dst)); 0058 break; 0059 case SQL_TYPE_TIME: 0060 isc_encode_sql_time(src, static_cast<ISC_TIME*>(dst)); 0061 break; 0062 case SQL_TYPE_DATE: 0063 isc_encode_sql_date(src, static_cast<ISC_DATE*>(dst)); 0064 break; 0065 default: 0066 std::ostringstream msg; 0067 msg << "Unexpected type of date/time field (" << type << ")"; 0068 throw soci_error(msg.str()); 0069 } 0070 } 0071 0072 void tmDecode(short type, void * src, std::tm * dst) 0073 { 0074 switch (type & ~1) 0075 { 0076 case SQL_TIMESTAMP: 0077 isc_decode_timestamp(static_cast<ISC_TIMESTAMP*>(src), dst); 0078 break; 0079 case SQL_TYPE_TIME: 0080 isc_decode_sql_time(static_cast<ISC_TIME*>(src), dst); 0081 break; 0082 case SQL_TYPE_DATE: 0083 isc_decode_sql_date(static_cast<ISC_DATE*>(src), dst); 0084 break; 0085 default: 0086 std::ostringstream msg; 0087 msg << "Unexpected type of date/time field (" << type << ")"; 0088 throw soci_error(msg.str()); 0089 } 0090 } 0091 0092 void setTextParam(char const * s, std::size_t size, char * buf_, 0093 XSQLVAR * var) 0094 { 0095 int const sqltype = var->sqltype & ~1; 0096 0097 if (sqltype == SQL_VARYING || sqltype == SQL_TEXT) 0098 { 0099 if (size > static_cast<std::size_t>(var->sqllen)) 0100 { 0101 std::ostringstream msg; 0102 msg << "Value \"" << s << "\" is too long (" 0103 << size << " bytes) to be stored in column of size " 0104 << var->sqllen << " bytes"; 0105 throw soci_error(msg.str()); 0106 } 0107 0108 short const sz = static_cast<short>(size); 0109 0110 if (sqltype == SQL_VARYING) 0111 { 0112 std::memcpy(buf_, &sz, sizeof(short)); 0113 std::memcpy(buf_ + sizeof(short), s, sz); 0114 } 0115 else // sqltype == SQL_TEXT 0116 { 0117 std::memcpy(buf_, s, sz); 0118 if (sz < var->sqllen) 0119 { 0120 std::memset(buf_+sz, ' ', var->sqllen - sz); 0121 } 0122 } 0123 } 0124 else if (sqltype == SQL_SHORT) 0125 { 0126 parse_decimal<short, unsigned short>(buf_, var, s); 0127 } 0128 else if (sqltype == SQL_LONG) 0129 { 0130 parse_decimal<int, unsigned int>(buf_, var, s); 0131 } 0132 else if (sqltype == SQL_INT64) 0133 { 0134 parse_decimal<long long, unsigned long long>(buf_, var, s); 0135 } 0136 else if (sqltype == SQL_TIMESTAMP 0137 || sqltype == SQL_TYPE_DATE) 0138 { 0139 unsigned short year, month, day, hour, min, sec; 0140 if (std::sscanf(s, "%hu-%hu-%hu %hu:%hu:%hu", 0141 &year, &month, &day, &hour, &min, &sec) != 6) 0142 { 0143 if (std::sscanf(s, "%hu-%hu-%huT%hu:%hu:%hu", 0144 &year, &month, &day, &hour, &min, &sec) != 6) 0145 { 0146 hour = min = sec = 0; 0147 if (std::sscanf(s, "%hu-%hu-%hu", &year, &month, &day) != 3) 0148 { 0149 throw soci_error("Could not parse timestamp value."); 0150 } 0151 } 0152 } 0153 std::tm t; 0154 std::memset(&t, 0, sizeof(t)); 0155 t.tm_year = year - 1900; 0156 t.tm_mon = month - 1; 0157 t.tm_mday = day; 0158 t.tm_hour = hour; 0159 t.tm_min = min; 0160 t.tm_sec = sec; 0161 std::memcpy(buf_, &t, sizeof(t)); 0162 tmEncode(var->sqltype, &t, buf_); 0163 } 0164 else if (sqltype == SQL_TYPE_TIME) 0165 { 0166 unsigned short hour, min, sec; 0167 if (std::sscanf(s, "%hu:%hu:%hu", &hour, &min, &sec) != 3) 0168 { 0169 throw soci_error("Could not parse timestamp value."); 0170 } 0171 std::tm t; 0172 std::memset(&t, 0, sizeof(t)); 0173 t.tm_hour = hour; 0174 t.tm_min = min; 0175 t.tm_sec = sec; 0176 std::memcpy(buf_, &t, sizeof(t)); 0177 tmEncode(var->sqltype, &t, buf_); 0178 } 0179 else 0180 { 0181 throw soci_error("Unexpected string type."); 0182 } 0183 } 0184 0185 std::string getTextParam(XSQLVAR const *var) 0186 { 0187 //std::cerr << "getTextParam: var->sqltype=" << var->sqltype << std::endl; 0188 short size; 0189 std::size_t offset = 0; 0190 0191 if ((var->sqltype & ~1) == SQL_VARYING) 0192 { 0193 SOCI_GCC_WARNING_SUPPRESS(cast-align) 0194 0195 size = *reinterpret_cast<short*>(var->sqldata); 0196 0197 SOCI_GCC_WARNING_RESTORE(cast-align) 0198 0199 offset = sizeof(short); 0200 } 0201 else if ((var->sqltype & ~1) == SQL_TEXT) 0202 { 0203 size = var->sqllen; 0204 } 0205 else if ((var->sqltype & ~1) == SQL_SHORT) 0206 { 0207 return format_decimal<short>(var->sqldata, var->sqlscale); 0208 } 0209 else if ((var->sqltype & ~1) == SQL_LONG) 0210 { 0211 return format_decimal<int>(var->sqldata, var->sqlscale); 0212 } 0213 else if ((var->sqltype & ~1) == SQL_INT64) 0214 { 0215 return format_decimal<long long>(var->sqldata, var->sqlscale); 0216 } 0217 else 0218 throw soci_error("Unexpected string type"); 0219 0220 return std::string(var->sqldata + offset, size); 0221 } 0222 0223 void copy_from_blob(firebird_statement_backend &st, char *buf, std::string &out) 0224 { 0225 firebird_blob_backend blob(st.session_); 0226 0227 SOCI_GCC_WARNING_SUPPRESS(cast-align) 0228 0229 blob.assign(*reinterpret_cast<ISC_QUAD*>(buf)); 0230 0231 SOCI_GCC_WARNING_RESTORE(cast-align) 0232 0233 std::size_t const len_total = blob.get_len(); 0234 out.resize(len_total); 0235 0236 std::size_t const len_read = blob.read_from_start(&out[0], len_total); 0237 if (len_read != len_total) 0238 { 0239 std::ostringstream os; 0240 os << "Read " << len_read << " bytes instead of expected " 0241 << len_total << " from Firebird text blob object"; 0242 throw soci_error(os.str()); 0243 } 0244 } 0245 0246 } // namespace firebird 0247 0248 } // namespace details 0249 0250 } // namespace soci