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 }