Warning, file /sdk/codevis/thirdparty/soci/tests/odbc/test-odbc-postgresql.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 // 0002 // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton, David Courtney 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.h" 0009 #include "soci/odbc/soci-odbc.h" 0010 #include "common-tests.h" 0011 #include <iostream> 0012 #include <string> 0013 #include <cstdio> 0014 #include <ctime> 0015 #include <cmath> 0016 0017 using namespace soci; 0018 using namespace soci::tests; 0019 0020 // A generic version class: we might want to factor it out later if it is 0021 // needed elsewhere (it would probably also need to be renamed to something 0022 // less generic then). 0023 class odbc_version 0024 { 0025 public: 0026 odbc_version() 0027 { 0028 initialized_ = false; 0029 } 0030 0031 odbc_version(unsigned major, unsigned minor, unsigned release) 0032 : major_(major), minor_(minor), release_(release) 0033 { 0034 initialized_ = true; 0035 } 0036 0037 bool init_from_string(char const* s) 0038 { 0039 initialized_ = std::sscanf(s, "%u.%u.%u", 0040 &major_, &minor_, &release_) == 3; 0041 return initialized_; 0042 } 0043 0044 bool is_initialized() const { return initialized_; } 0045 0046 std::string as_string() const 0047 { 0048 if (initialized_) 0049 { 0050 char buf[128]; 0051 // This uses the ODBC convention of padding the minor and release 0052 // versions with 0 and might be not appropriate in general. 0053 std::sprintf(buf, "%u.%02u.%04u", major_, minor_, release_); 0054 return buf; 0055 } 0056 else 0057 { 0058 return "(uninitialized)"; 0059 } 0060 } 0061 0062 // Compare versions using the lexicographical sort order, with 0063 // uninitialized version considered less than any initialized one. 0064 bool operator<(odbc_version const& v) const 0065 { 0066 if (!initialized_) 0067 return v.initialized_; 0068 0069 return major_ < v.major_ || 0070 (major_ == v.major_ && (minor_ < v.minor_ || 0071 (minor_ == v.minor_ && release_ < v.release_))); 0072 } 0073 0074 private: 0075 unsigned major_, minor_, release_; 0076 bool initialized_; 0077 }; 0078 0079 std::ostream& operator<<(std::ostream& os, odbc_version const& v) 0080 { 0081 os << v.as_string(); 0082 return os; 0083 } 0084 0085 std::string connectString; 0086 backend_factory const &backEnd = *soci::factory_odbc(); 0087 0088 // DDL Creation objects for common tests 0089 struct table_creator_one : public table_creator_base 0090 { 0091 table_creator_one(soci::session & sql) 0092 : table_creator_base(sql) 0093 { 0094 sql << "create table soci_test(id integer, val integer, c char, " 0095 "str varchar(20), sh int2, ul numeric(20), d float8, " 0096 "num76 numeric(7,6), " 0097 "tm timestamp, i1 integer, i2 integer, i3 integer, " 0098 "name varchar(20))"; 0099 } 0100 }; 0101 0102 struct table_creator_two : public table_creator_base 0103 { 0104 table_creator_two(soci::session & sql) 0105 : table_creator_base(sql) 0106 { 0107 sql << "create table soci_test(num_float float8, num_int integer," 0108 " name varchar(20), sometime timestamp, chr char)"; 0109 } 0110 }; 0111 0112 struct table_creator_three : public table_creator_base 0113 { 0114 table_creator_three(soci::session & sql) 0115 : table_creator_base(sql) 0116 { 0117 sql << "create table soci_test(name varchar(100) not null, " 0118 "phone varchar(15))"; 0119 } 0120 }; 0121 0122 struct table_creator_for_get_affected_rows : table_creator_base 0123 { 0124 table_creator_for_get_affected_rows(soci::session & sql) 0125 : table_creator_base(sql) 0126 { 0127 sql << "create table soci_test(val integer)"; 0128 } 0129 }; 0130 0131 struct table_creator_for_xml : table_creator_base 0132 { 0133 table_creator_for_xml(soci::session& sql) 0134 : table_creator_base(sql) 0135 { 0136 sql << "create table soci_test(id integer, x xml)"; 0137 } 0138 }; 0139 0140 struct table_creator_for_clob : table_creator_base 0141 { 0142 table_creator_for_clob(soci::session& sql) 0143 : table_creator_base(sql) 0144 { 0145 sql << "create table soci_test(id integer, s text)"; 0146 } 0147 }; 0148 0149 // 0150 // Support for SOCI Common Tests 0151 // 0152 0153 class test_context : public test_context_base 0154 { 0155 public: 0156 test_context(backend_factory const &backend, 0157 std::string const &connstr) 0158 : test_context_base(backend, connstr), 0159 m_verDriver(get_driver_version()) 0160 { 0161 std::cout << "Using ODBC driver version " << m_verDriver << "\n"; 0162 } 0163 0164 table_creator_base * table_creator_1(soci::session& s) const override 0165 { 0166 return new table_creator_one(s); 0167 } 0168 0169 table_creator_base * table_creator_2(soci::session& s) const override 0170 { 0171 return new table_creator_two(s); 0172 } 0173 0174 table_creator_base * table_creator_3(soci::session& s) const override 0175 { 0176 return new table_creator_three(s); 0177 } 0178 0179 table_creator_base * table_creator_4(soci::session& s) const override 0180 { 0181 return new table_creator_for_get_affected_rows(s); 0182 } 0183 0184 table_creator_base* table_creator_xml(soci::session& s) const override 0185 { 0186 return new table_creator_for_xml(s); 0187 } 0188 0189 table_creator_base* table_creator_clob(soci::session& s) const override 0190 { 0191 return new table_creator_for_clob(s); 0192 } 0193 0194 bool has_real_xml_support() const override 0195 { 0196 return true; 0197 } 0198 0199 std::string to_date_time(std::string const &datdt_string) const override 0200 { 0201 return "timestamptz(\'" + datdt_string + "\')"; 0202 } 0203 0204 bool has_fp_bug() const override 0205 { 0206 // The bug with using insufficiently many digits for double values was 0207 // only fixed in 9.03.0400 version of the ODBC driver (see commit 0208 // a5fed2338b59ae16a2d3a8d2744b084949684775 in its repository), so we 0209 // need to check for its version here. 0210 // 0211 // Be pessimistic if we failed to retrieve the version at all. 0212 return !m_verDriver.is_initialized() || m_verDriver < odbc_version(9, 3, 400); 0213 } 0214 0215 std::string fix_crlf_if_necessary(std::string const& s) const override 0216 { 0217 // Version 9.03.0300 (ancient, but still used on AppVeyor CI) is known 0218 // to have a bug which replaces new lines, i.e. LF characters, with CR 0219 // LF when reading CLOBs. Assume it was also fixed in later versions. 0220 if ( m_verDriver.is_initialized() && odbc_version(9, 3, 300) < m_verDriver ) 0221 return s; 0222 0223 std::string s2; 0224 s2.reserve(s.size()); 0225 for (std::size_t i = 0; i < s.size(); ++i) 0226 { 0227 if (s[i] == '\r') 0228 continue; 0229 0230 s2 += s[i]; 0231 } 0232 0233 return s2; 0234 } 0235 0236 std::string sql_length(std::string const& s) const override 0237 { 0238 return "char_length(" + s + ")"; 0239 } 0240 0241 private: 0242 odbc_version get_driver_version() const 0243 { 0244 try 0245 { 0246 soci::session sql(get_backend_factory(), get_connect_string()); 0247 odbc_session_backend* const 0248 odbc_session = static_cast<odbc_session_backend*>(sql.get_backend()); 0249 if (!odbc_session) 0250 { 0251 std::cerr << "Failed to get odbc_session_backend?\n"; 0252 return odbc_version(); 0253 } 0254 0255 char driver_ver[1024]; 0256 SQLSMALLINT len = sizeof(driver_ver); 0257 SQLRETURN rc = SQLGetInfo(odbc_session->hdbc_, SQL_DRIVER_VER, 0258 driver_ver, len, &len); 0259 if (soci::is_odbc_error(rc)) 0260 { 0261 std::cerr << "Retrieving ODBC driver version failed: " 0262 << rc << "\n"; 0263 return odbc_version(); 0264 } 0265 0266 odbc_version v; 0267 if (!v.init_from_string(driver_ver)) 0268 { 0269 std::cerr << "Unknown ODBC driver version format: \"" 0270 << driver_ver << "\"\n"; 0271 } 0272 0273 return v; 0274 } 0275 catch ( ... ) 0276 { 0277 // Failure getting the version is not fatal. 0278 return odbc_version(); 0279 } 0280 } 0281 0282 odbc_version const m_verDriver; 0283 }; 0284 0285 int main(int argc, char** argv) 0286 { 0287 0288 #ifdef _MSC_VER 0289 // Redirect errors, unrecoverable problems, and assert() failures to STDERR, 0290 // instead of debug message window. 0291 // This hack is required to run assert()-driven tests by Buildbot. 0292 // NOTE: Comment this 2 lines for debugging with Visual C++ debugger to catch assertions inside. 0293 _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE); 0294 _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR); 0295 #endif //_MSC_VER 0296 0297 if (argc >= 2 && argv[1][0] != '-') 0298 { 0299 connectString = argv[1]; 0300 0301 // Replace the connect string with the process name to ensure that 0302 // CATCH uses the correct name in its messages. 0303 argv[1] = argv[0]; 0304 0305 argc--; 0306 argv++; 0307 } 0308 else 0309 { 0310 connectString = "FILEDSN=./test-postgresql.dsn"; 0311 } 0312 0313 test_context tc(backEnd, connectString); 0314 0315 return Catch::Session().run(argc, argv); 0316 }