Warning, file /sdk/codevis/thirdparty/soci/tests/odbc/test-odbc-mssql.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 <ctime>
0014 #include <cmath>
0015 
0016 using namespace soci;
0017 using namespace soci::tests;
0018 
0019 std::string connectString;
0020 backend_factory const &backEnd = *soci::factory_odbc();
0021 
0022 // MS SQL-specific tests
0023 TEST_CASE("MS SQL long string", "[odbc][mssql][long]")
0024 {
0025     soci::session sql(backEnd, connectString);
0026 
0027     struct long_text_table_creator : public table_creator_base
0028     {
0029         explicit long_text_table_creator(soci::session& sql)
0030             : table_creator_base(sql)
0031         {
0032             // Notice that 4000 is the maximal length of an nvarchar() column,
0033             // at least when using FreeTDS ODBC driver.
0034             sql << "create table soci_test ("
0035                         "long_text nvarchar(max) null, "
0036                         "fixed_text nvarchar(4000) null"
0037                     ")";
0038         }
0039     } long_text_table_creator(sql);
0040 
0041     // Build a string at least 8000 characters long to test that it survives
0042     // the round trip unscathed.
0043     std::ostringstream os;
0044     for ( int n = 0; n < 1000; ++n )
0045     {
0046         os << "Line #" << n << "\n";
0047     }
0048 
0049     std::string const str_in = os.str();
0050     CHECK_NOTHROW((
0051         sql << "insert into soci_test(long_text) values(:str)", use(str_in)
0052     ));
0053 
0054     std::string str_out;
0055     sql << "select long_text from soci_test", into(str_out);
0056 
0057     // Don't just compare the strings because the error message in case they
0058     // differ is completely unreadable due to their size, so give a better
0059     // error in the common failure case.
0060     if (str_out.length() != str_in.length())
0061     {
0062         FAIL("Read back string of length " << str_out.length() <<
0063              " instead of expected " << str_in.length());
0064     }
0065     else
0066     {
0067         CHECK(str_out == str_in);
0068     }
0069 
0070     // The long string should be truncated when inserting it into a fixed size
0071     // column.
0072     CHECK_THROWS_AS(
0073         (sql << "insert into soci_test(fixed_text) values(:str)", use(str_in)),
0074         soci_error
0075     );
0076 }
0077 
0078 // DDL Creation objects for common tests
0079 struct table_creator_one : public table_creator_base
0080 {
0081     table_creator_one(soci::session & sql)
0082         : table_creator_base(sql)
0083     {
0084         sql << "create table soci_test(id integer, val integer, c char, "
0085                  "str varchar(20), sh smallint, ul numeric(20), d float, "
0086                  "num76 numeric(7,6), "
0087                  "tm datetime, i1 integer, i2 integer, i3 integer, "
0088                  "name varchar(20))";
0089     }
0090 };
0091 
0092 struct table_creator_two : public table_creator_base
0093 {
0094     table_creator_two(soci::session & sql)
0095         : table_creator_base(sql)
0096     {
0097         sql  << "create table soci_test(num_float float, num_int integer,"
0098                      " name varchar(20), sometime datetime, chr char)";
0099     }
0100 };
0101 
0102 struct table_creator_three : public table_creator_base
0103 {
0104     table_creator_three(soci::session & sql)
0105         : table_creator_base(sql)
0106     {
0107         sql << "create table soci_test(name varchar(100) not null, "
0108             "phone varchar(15))";
0109     }
0110 };
0111 
0112 struct table_creator_for_get_affected_rows : table_creator_base
0113 {
0114     table_creator_for_get_affected_rows(soci::session & sql)
0115         : table_creator_base(sql)
0116     {
0117         sql << "create table soci_test(val integer)";
0118     }
0119 };
0120 
0121 struct table_creator_for_clob : table_creator_base
0122 {
0123     table_creator_for_clob(soci::session & sql)
0124         : table_creator_base(sql)
0125     {
0126         sql << "create table soci_test(id integer, s text)";
0127     }
0128 };
0129 
0130 struct table_creator_for_xml : table_creator_base
0131 {
0132     table_creator_for_xml(soci::session & sql)
0133         : table_creator_base(sql)
0134     {
0135         sql << "create table soci_test(id integer, x xml)";
0136     }
0137 };
0138 
0139 struct table_creator_for_get_last_insert_id : table_creator_base
0140 {
0141     table_creator_for_get_last_insert_id(soci::session & sql)
0142         : table_creator_base(sql)
0143     {
0144         sql << "create table soci_test (id integer identity(1, 1), val integer)";
0145     }
0146 };
0147 
0148 //
0149 // Support for SOCI Common Tests
0150 //
0151 
0152 class test_context : public test_context_base
0153 {
0154 public:
0155     test_context(backend_factory const &backend,
0156                 std::string const &connstr)
0157         : test_context_base(backend, connstr) {}
0158 
0159     table_creator_base* table_creator_1(soci::session& s) const override
0160     {
0161         return new table_creator_one(s);
0162     }
0163 
0164     table_creator_base* table_creator_2(soci::session& s) const override
0165     {
0166         return new table_creator_two(s);
0167     }
0168 
0169     table_creator_base* table_creator_3(soci::session& s) const override
0170     {
0171         return new table_creator_three(s);
0172     }
0173 
0174     table_creator_base * table_creator_4(soci::session& s) const override
0175     {
0176         return new table_creator_for_get_affected_rows(s);
0177     }
0178 
0179     tests::table_creator_base* table_creator_clob(soci::session& s) const override
0180     {
0181         return new table_creator_for_clob(s);
0182     }
0183 
0184     tests::table_creator_base* table_creator_xml(soci::session& s) const override
0185     {
0186         return new table_creator_for_xml(s);
0187     }
0188 
0189     tests::table_creator_base* table_creator_get_last_insert_id(soci::session& s) const override
0190     {
0191         return new table_creator_for_get_last_insert_id(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 "convert(datetime, \'" + datdt_string + "\', 120)";
0202     }
0203 
0204     bool has_multiple_select_bug() const override
0205     {
0206         // MS SQL does support MARS (multiple active result sets) since 2005
0207         // version, but this support needs to be explicitly enabled and is not
0208         // implemented in FreeTDS ODBC driver used under Unix currently, so err
0209         // on the side of caution and suppose that it's not supported.
0210         return true;
0211     }
0212 
0213     std::string sql_length(std::string const& s) const override
0214     {
0215         return "len(" + s + ")";
0216     }
0217 };
0218 
0219 int main(int argc, char** argv)
0220 {
0221 #ifdef _MSC_VER
0222     // Redirect errors, unrecoverable problems, and assert() failures to STDERR,
0223     // instead of debug message window.
0224     // This hack is required to run assert()-driven tests by Buildbot.
0225     // NOTE: Comment this 2 lines for debugging with Visual C++ debugger to catch assertions inside.
0226     _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
0227     _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
0228 #endif //_MSC_VER
0229 
0230     if (argc >= 2 && argv[1][0] != '-')
0231     {
0232         connectString = argv[1];
0233 
0234         // Replace the connect string with the process name to ensure that
0235         // CATCH uses the correct name in its messages.
0236         argv[1] = argv[0];
0237 
0238         argc--;
0239         argv++;
0240     }
0241     else
0242     {
0243         connectString = "FILEDSN=./test-mssql.dsn";
0244     }
0245 
0246     test_context tc(backEnd, connectString);
0247 
0248     return Catch::Session().run(argc, argv);
0249 }