Warning, file /sdk/codevis/thirdparty/soci/tests/mysql/test-mysql.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
0003 // MySQL backend copyright (C) 2006 Pawel Aleksander Fedorynski
0004 // Distributed under the Boost Software License, Version 1.0.
0005 // (See accompanying file LICENSE_1_0.txt or copy at
0006 // http://www.boost.org/LICENSE_1_0.txt)
0007 //
0008 
0009 #include "soci/soci.h"
0010 
0011 #include "soci-compiler.h"
0012 #include "soci/mysql/soci-mysql.h"
0013 #include "mysql/test-mysql.h"
0014 #include <string.h>
0015 #include <iostream>
0016 #include <sstream>
0017 #include <string>
0018 #include <vector>
0019 #include <cmath>
0020 #include <ctime>
0021 #include <ciso646>
0022 #include <cstdlib>
0023 #include <mysqld_error.h>
0024 #include <errmsg.h>
0025 
0026 std::string connectString;
0027 backend_factory const &backEnd = *soci::factory_mysql();
0028 
0029 // procedure call test
0030 TEST_CASE("MySQL stored procedures", "[mysql][stored-procedure]")
0031 {
0032     soci::session sql(backEnd, connectString);
0033 
0034     mysql_session_backend *sessionBackEnd
0035         = static_cast<mysql_session_backend *>(sql.get_backend());
0036     std::string version = mysql_get_server_info(sessionBackEnd->conn_);
0037     int v;
0038     std::istringstream iss(version);
0039     if ((iss >> v) && v < 5)
0040     {
0041         WARN("MySQL server version " << v
0042                 << " does not support stored procedures, skipping test.");
0043         return;
0044     }
0045 
0046     try { sql << "drop function myecho"; }
0047     catch (soci_error const &) {}
0048 
0049     sql <<
0050         "create function myecho(msg text) "
0051         "returns text deterministic "
0052         "  return msg; ";
0053 
0054     std::string in("my message");
0055     std::string out;
0056 
0057     statement st = (sql.prepare <<
0058         "select myecho(:input)",
0059         into(out),
0060         use(in, "input"));
0061 
0062     st.execute(1);
0063     CHECK(out == in);
0064 
0065     // explicit procedure syntax
0066     {
0067         procedure proc = (sql.prepare <<
0068             "myecho(:input)",
0069             into(out), use(in, "input"));
0070 
0071         proc.execute(1);
0072         CHECK(out == in);
0073     }
0074 
0075     sql << "drop function myecho";
0076 }
0077 
0078 // MySQL error reporting test.
0079 TEST_CASE("MySQL error reporting", "[mysql][exception]")
0080 {
0081     {
0082         try
0083         {
0084             soci::session sql(backEnd, "host=test.soci.invalid");
0085         }
0086         catch (mysql_soci_error const &e)
0087         {
0088             if (e.err_num_ != CR_UNKNOWN_HOST &&
0089                    e.err_num_ != CR_CONN_HOST_ERROR)
0090             {
0091                 CAPTURE(e.err_num_);
0092                 FAIL("Unexpected error trying to connect to invalid host.");
0093             }
0094         }
0095     }
0096 
0097     {
0098         soci::session sql(backEnd, connectString);
0099         sql << "create table soci_test (id integer)";
0100         try
0101         {
0102             int n;
0103             sql << "select id from soci_test_nosuchtable", into(n);
0104         }
0105         catch (mysql_soci_error const &e)
0106         {
0107             CHECK(e.err_num_ == ER_NO_SUCH_TABLE);
0108         }
0109         try
0110         {
0111             sql << "insert into soci_test (invalid) values (256)";
0112         }
0113         catch (mysql_soci_error const &e)
0114         {
0115             CHECK(e.err_num_ == ER_BAD_FIELD_ERROR);
0116         }
0117         // A bulk operation.
0118         try
0119         {
0120             std::vector<int> v(3, 5);
0121             sql << "insert into soci_test_nosuchtable values (:n)", use(v);
0122         }
0123         catch (mysql_soci_error const &e)
0124         {
0125             CHECK(e.err_num_ == ER_NO_SUCH_TABLE);
0126         }
0127         sql << "drop table soci_test";
0128     }
0129 }
0130 
0131 struct bigint_table_creator : table_creator_base
0132 {
0133     bigint_table_creator(soci::session & sql)
0134         : table_creator_base(sql)
0135     {
0136         sql << "create table soci_test(val bigint)";
0137     }
0138 };
0139 
0140 struct bigint_unsigned_table_creator : table_creator_base
0141 {
0142     bigint_unsigned_table_creator(soci::session & sql)
0143         : table_creator_base(sql)
0144     {
0145         sql << "create table soci_test(val bigint unsigned)";
0146     }
0147 };
0148 
0149 TEST_CASE("MySQL long long", "[mysql][longlong]")
0150 {
0151     {
0152         soci::session sql(backEnd, connectString);
0153 
0154         bigint_table_creator tableCreator(sql);
0155 
0156         long long v1 = 1000000000000LL;
0157         sql << "insert into soci_test(val) values(:val)", use(v1);
0158 
0159         long long v2 = 0LL;
0160         sql << "select val from soci_test", into(v2);
0161 
0162         CHECK(v2 == v1);
0163     }
0164 
0165     // vector<long long>
0166     {
0167         soci::session sql(backEnd, connectString);
0168 
0169         bigint_table_creator tableCreator(sql);
0170 
0171         std::vector<long long> v1;
0172         v1.push_back(1000000000000LL);
0173         v1.push_back(1000000000001LL);
0174         v1.push_back(1000000000002LL);
0175         v1.push_back(1000000000003LL);
0176         v1.push_back(1000000000004LL);
0177 
0178         sql << "insert into soci_test(val) values(:val)", use(v1);
0179 
0180         std::vector<long long> v2(10);
0181         sql << "select val from soci_test order by val desc", into(v2);
0182 
0183         REQUIRE(v2.size() == 5);
0184         CHECK(v2[0] == 1000000000004LL);
0185         CHECK(v2[1] == 1000000000003LL);
0186         CHECK(v2[2] == 1000000000002LL);
0187         CHECK(v2[3] == 1000000000001LL);
0188         CHECK(v2[4] == 1000000000000LL);
0189     }
0190 
0191     {
0192         soci::session sql(backEnd, connectString);
0193 
0194         bigint_unsigned_table_creator tableCreator(sql);
0195 
0196         sql << "insert into soci_test set val = 18446744073709551615";
0197         row v;
0198         sql << "select * from soci_test", into(v);
0199     }
0200 
0201     {
0202         soci::session sql(backEnd, connectString);
0203 
0204         bigint_unsigned_table_creator tableCreator(sql);
0205 
0206         const char* source = "18446744073709551615";
0207         sql << "insert into soci_test set val = " << source;
0208         unsigned long long vv = 0;
0209         sql << "select val from soci_test", into(vv);
0210         std::stringstream buf;
0211         buf << vv;
0212         CHECK(buf.str() == source);
0213     }
0214 
0215     {
0216         soci::session sql(backEnd, connectString);
0217 
0218         bigint_unsigned_table_creator tableCreator(sql);
0219 
0220         const char* source = "18446744073709551615";
0221         sql << "insert into soci_test set val = " << source;
0222         std::vector<unsigned long long> v(1);
0223         sql << "select val from soci_test", into(v);
0224         std::stringstream buf;
0225         buf << v.at(0);
0226         CHECK(buf.str() == source);
0227     }
0228 
0229     {
0230         soci::session sql(backEnd, connectString);
0231 
0232         bigint_unsigned_table_creator tableCreator(sql);
0233 
0234         unsigned long long n = 18446744073709551615ULL;
0235         sql << "insert into soci_test(val) values (:n)", use(n);
0236         unsigned long long m = 0;
0237         sql << "select val from soci_test", into(m);
0238         CHECK(n == m);
0239     }
0240 
0241     {
0242         soci::session sql(backEnd, connectString);
0243 
0244         bigint_unsigned_table_creator tableCreator(sql);
0245 
0246         std::vector<unsigned long long> v1;
0247         v1.push_back(18446744073709551615ULL);
0248         v1.push_back(18446744073709551614ULL);
0249         v1.push_back(18446744073709551613ULL);
0250         sql << "insert into soci_test(val) values(:val)", use(v1);
0251 
0252         std::vector<unsigned long long> v2(10);
0253         sql << "select val from soci_test order by val", into(v2);
0254 
0255         REQUIRE(v2.size() == 3);
0256         CHECK(v2[0] == 18446744073709551613ULL);
0257         CHECK(v2[1] == 18446744073709551614ULL);
0258         CHECK(v2[2] == 18446744073709551615ULL);
0259     }
0260 }
0261 
0262 template <typename T>
0263 void test_num(const char* s, bool valid, T value)
0264 {
0265     try
0266     {
0267         soci::session sql(backEnd, connectString);
0268         T val;
0269         sql << "select \'" << s << "\'", into(val);
0270         if (valid)
0271         {
0272             double v1 = static_cast<double>(value);
0273             double v2 = static_cast<double>(val);
0274             double d = std::fabs(v1 - v2);
0275             double epsilon = 0.001;
0276             if (d >= epsilon &&
0277                    d >= epsilon * (std::fabs(v1) + std::fabs(v2)))
0278             {
0279                 FAIL("Difference between " << value
0280                        << " and " << val << " is too big.");
0281             }
0282         }
0283         else
0284         {
0285             FAIL("string \"" << s << "\" parsed as " << val
0286                       << " but should have failed.");
0287         }
0288     }
0289     catch (soci_error const& e)
0290     {
0291         if (valid)
0292         {
0293             FAIL("couldn't parse number: \"" << s << "\"");
0294         }
0295         else
0296         {
0297             char const * expectedPrefix = "Cannot convert data";
0298             CAPTURE(e.what());
0299             CHECK(strncmp(e.what(), expectedPrefix, strlen(expectedPrefix)) == 0);
0300         }
0301     }
0302 }
0303 
0304 // Number conversion test.
0305 TEST_CASE("MySQL number conversion", "[mysql][float][int]")
0306 {
0307     test_num<double>("", false, 0);
0308     test_num<double>("foo", false, 0);
0309     test_num<double>("1", true, 1);
0310     test_num<double>("12", true, 12);
0311     test_num<double>("123", true, 123);
0312     test_num<double>("12345", true, 12345);
0313     test_num<double>("12341234123412341234123412341234123412341234123412341",
0314         true, 1.23412e+52);
0315     test_num<double>("99999999999999999999999912222222222222222222222222223"
0316         "9999999999999999999999991222222222222222222222222222333333333333"
0317         "9999999999999999999999991222222222222222222222222222333333333333"
0318         "9999999999999999999999991222222222222222222222222222333333333333"
0319         "9999999999999999999999991222222222222222222222222222333333333333"
0320         "9999999999999999999999991222222222222222222222222222333333333333"
0321         "9999999999999999999999991222222222222222222222222222333333333333"
0322         "9999999999999999999999991222222222222222222222222222333333333333"
0323         "9999999999999999999999991222222222222222222222222222333333333333"
0324         "9999999999999999999999991222222222222222222222222222333333333333"
0325         "9999999999999999999999991222222222222222222222222222333333333333"
0326         "9999999999999999999999991222222222222222222222222222333333333333"
0327         "9999999999999999999999991222222222222222222222222222333333333333"
0328         "9999999999999999999999991222222222222222222222222222333333333333"
0329         "9999999999999999999999991222222222222222222222222222333333333333",
0330         false, 0);
0331     test_num<double>("1e3", true, 1000);
0332     test_num<double>("1.2", true, 1.2);
0333     test_num<double>("1.2345e2", true, 123.45);
0334     test_num<double>("1 ", false, 0);
0335     test_num<double>("     123", true, 123);
0336     test_num<double>("1,2", false, 0);
0337     test_num<double>("123abc", false, 0);
0338     test_num<double>("-0", true, 0);
0339 
0340     test_num<short>("123", true, 123);
0341     test_num<short>("100000", false, 0);
0342 
0343     test_num<int>("123", true, 123);
0344     test_num<int>("2147483647", true, 2147483647);
0345     test_num<int>("2147483647a", false, 0);
0346     test_num<int>("2147483648", false, 0);
0347     // -2147483648 causes a warning because it is interpreted as
0348     // 2147483648 (which doesn't fit in an integer) to which a negation
0349     // is applied.
0350     test_num<int>("-2147483648", true, -2147483647 - 1);
0351     test_num<int>("-2147483649", false, 0);
0352     test_num<int>("-0", true, 0);
0353     test_num<int>("1.1", false, 0);
0354 
0355     test_num<long long>("123", true, 123);
0356     test_num<long long>("9223372036854775807", true, 9223372036854775807LL);
0357     test_num<long long>("9223372036854775808", false, 0);
0358 }
0359 
0360 TEST_CASE("MySQL datetime", "[mysql][datetime]")
0361 {
0362     soci::session sql(backEnd, connectString);
0363     std::tm t = std::tm();
0364     sql << "select maketime(19, 54, 52)", into(t);
0365     CHECK(t.tm_year == 0);
0366     CHECK(t.tm_mon == 0);
0367     CHECK(t.tm_mday == 1);
0368     CHECK(t.tm_hour == 19);
0369     CHECK(t.tm_min == 54);
0370     CHECK(t.tm_sec == 52);
0371 }
0372 
0373 // TEXT and BLOB types support test.
0374 TEST_CASE("MySQL text and blob", "[mysql][text][blob]")
0375 {
0376     soci::session sql(backEnd, connectString);
0377     std::string a("asdfg\0hjkl", 10);
0378     std::string b("lkjhg\0fd\0\0sa\0", 13);
0379     std::string c("\\0aa\\0bb\\0cc\\0", 10);
0380     // The maximum length for TEXT and BLOB is 65536.
0381     std::string x(60000, 'X');
0382     std::string y(60000, 'Y');
0383     // The default max_allowed_packet value for a MySQL server is 1M,
0384     // so let's limit ourselves to 800k, even though the maximum length
0385     // for LONGBLOB is 4G.
0386     std::string z(800000, 'Z');
0387 
0388     sql << "create table soci_test (id int, text_value text, "
0389         "blob_value blob, longblob_value longblob)";
0390     sql << "insert into soci_test values (1, \'foo\', \'bar\', \'baz\')";
0391     sql << "insert into soci_test "
0392         << "values (2, \'qwerty\\0uiop\', \'zxcv\\0bnm\', "
0393         << "\'qwerty\\0uiop\\0zxcvbnm\\0\')";
0394     sql << "insert into soci_test values (3, :a, :b, :c)",
0395            use(a), use(b), use(c);
0396     sql << "insert into soci_test values (4, :x, :y, :z)",
0397            use(x), use(y), use(z);
0398 
0399     std::vector<std::string> text_vec(100);
0400     std::vector<std::string> blob_vec(100);
0401     std::vector<std::string> longblob_vec(100);
0402     sql << "select text_value, blob_value, longblob_value "
0403         << "from soci_test order by id",
0404            into(text_vec), into(blob_vec), into(longblob_vec);
0405     REQUIRE(text_vec.size() == 4);
0406     REQUIRE(blob_vec.size() == 4);
0407     REQUIRE(longblob_vec.size() == 4);
0408     CHECK(text_vec[0] == "foo");
0409     CHECK(blob_vec[0] == "bar");
0410     CHECK(longblob_vec[0] == "baz");
0411     CHECK(text_vec[1] == std::string("qwerty\0uiop", 11));
0412     CHECK(blob_vec[1] == std::string("zxcv\0bnm", 8));
0413     CHECK(longblob_vec[1] == std::string("qwerty\0uiop\0zxcvbnm\0", 20));
0414     CHECK(text_vec[2] == a);
0415     CHECK(blob_vec[2] == b);
0416     CHECK(longblob_vec[2] == c);
0417     CHECK(text_vec[3] == x);
0418     CHECK(blob_vec[3] == y);
0419     CHECK(longblob_vec[3] == z);
0420 
0421     std::string text, blob, longblob;
0422     sql << "select text_value, blob_value, longblob_value "
0423         << "from soci_test where id = 1",
0424            into(text), into(blob), into(longblob);
0425     CHECK(text == "foo");
0426     CHECK(blob == "bar");
0427     CHECK(longblob == "baz");
0428     sql << "select text_value, blob_value, longblob_value "
0429         << "from soci_test where id = 2",
0430            into(text), into(blob), into(longblob);
0431     CHECK(text == std::string("qwerty\0uiop", 11));
0432     CHECK(blob == std::string("zxcv\0bnm", 8));
0433     CHECK(longblob == std::string("qwerty\0uiop\0zxcvbnm\0", 20));
0434     sql << "select text_value, blob_value, longblob_value "
0435         << "from soci_test where id = 3",
0436            into(text), into(blob), into(longblob);
0437     CHECK(text == a);
0438     CHECK(blob == b);
0439     CHECK(longblob == c);
0440     sql << "select text_value, blob_value, longblob_value "
0441         << "from soci_test where id = 4",
0442            into(text), into(blob), into(longblob);
0443     CHECK(text == x);
0444     CHECK(blob == y);
0445     CHECK(longblob == z);
0446 
0447     rowset<row> rs =
0448         (sql.prepare << "select text_value, blob_value, longblob_value "
0449                         "from soci_test order by id");
0450     rowset<row>::const_iterator r = rs.begin();
0451     CHECK(r->get_properties(0).get_data_type() == dt_string);
0452     CHECK(r->get<std::string>(0) == "foo");
0453     CHECK(r->get_properties(1).get_data_type() == dt_string);
0454     CHECK(r->get<std::string>(1) == "bar");
0455     CHECK(r->get_properties(2).get_data_type() == dt_string);
0456     CHECK(r->get<std::string>(2) == "baz");
0457     ++r;
0458     CHECK(r->get_properties(0).get_data_type() == dt_string);
0459     CHECK(r->get<std::string>(0) == std::string("qwerty\0uiop", 11));
0460     CHECK(r->get_properties(1).get_data_type() == dt_string);
0461     CHECK(r->get<std::string>(1) == std::string("zxcv\0bnm", 8));
0462     CHECK(r->get_properties(2).get_data_type() == dt_string);
0463     CHECK(r->get<std::string>(2) ==
0464            std::string("qwerty\0uiop\0zxcvbnm\0", 20));
0465     ++r;
0466     CHECK(r->get_properties(0).get_data_type() == dt_string);
0467     CHECK(r->get<std::string>(0) == a);
0468     CHECK(r->get_properties(1).get_data_type() == dt_string);
0469     CHECK(r->get<std::string>(1) == b);
0470     CHECK(r->get_properties(2).get_data_type() == dt_string);
0471     CHECK(r->get<std::string>(2) == c);
0472     ++r;
0473     CHECK(r->get_properties(0).get_data_type() == dt_string);
0474     CHECK(r->get<std::string>(0) == x);
0475     CHECK(r->get_properties(1).get_data_type() == dt_string);
0476     CHECK(r->get<std::string>(1) == y);
0477     CHECK(r->get_properties(2).get_data_type() == dt_string);
0478     CHECK(r->get<std::string>(2) == z);
0479     ++r;
0480     CHECK(r == rs.end());
0481 
0482     sql << "drop table soci_test";
0483 }
0484 
0485 // test for number of affected rows
0486 
0487 struct integer_value_table_creator : table_creator_base
0488 {
0489     integer_value_table_creator(soci::session & sql)
0490         : table_creator_base(sql)
0491     {
0492         sql << "create table soci_test(val integer)";
0493     }
0494 };
0495 
0496 TEST_CASE("MySQL get affected rows", "[mysql][affected-rows]")
0497 {
0498     soci::session sql(backEnd, connectString);
0499 
0500     integer_value_table_creator tableCreator(sql);
0501 
0502     for (int i = 0; i != 10; i++)
0503     {
0504         sql << "insert into soci_test(val) values(:val)", use(i);
0505     }
0506 
0507     statement st1 = (sql.prepare <<
0508         "update soci_test set val = val + 1");
0509     st1.execute(false);
0510 
0511     CHECK(st1.get_affected_rows() == 10);
0512 
0513     statement st2 = (sql.prepare <<
0514         "delete from soci_test where val <= 5");
0515     st2.execute(false);
0516 
0517     CHECK(st2.get_affected_rows() == 5);
0518 }
0519 
0520 
0521 // The prepared statements should survive session::reconnect().
0522 // However currently it doesn't and attempting to use it results in crashes due
0523 // to accessing the already destroyed session backend, so disable this test.
0524 TEST_CASE("MySQL statements after reconnect", "[mysql][connect][.]")
0525 {
0526     soci::session sql(backEnd, connectString);
0527 
0528     integer_value_table_creator tableCreator(sql);
0529 
0530     int i;
0531     statement st = (sql.prepare
0532         << "insert into soci_test(val) values(:val)", use(i));
0533     i = 5;
0534     st.execute(true);
0535 
0536     sql.reconnect();
0537 
0538     i = 6;
0539     st.execute(true);
0540 
0541     sql.close();
0542     sql.reconnect();
0543 
0544     i = 7;
0545     st.execute(true);
0546 
0547     std::vector<int> v(5);
0548     sql << "select val from soci_test order by val", into(v);
0549     REQUIRE(v.size() == 3);
0550     CHECK(v[0] == 5);
0551     CHECK(v[1] == 6);
0552     CHECK(v[2] == 7);
0553 }
0554 
0555 struct unsigned_value_table_creator : table_creator_base
0556 {
0557     unsigned_value_table_creator(soci::session & sql)
0558         : table_creator_base(sql)
0559     {
0560         sql << "create table soci_test(val int unsigned)";
0561     }
0562 };
0563 
0564 // rowset<> should be able to take INT UNSIGNED.
0565 TEST_CASE("MySQL unsigned int", "[mysql][int]")
0566 {
0567     soci::session sql(backEnd, connectString);
0568 
0569     unsigned_value_table_creator tableCreator(sql);
0570 
0571     unsigned int mask = 0xffffff00;
0572     sql << "insert into soci_test set val = " << mask;
0573     soci::rowset<> rows(sql.prepare << "select val from soci_test");
0574     int cnt = 0;
0575     for (soci::rowset<>::iterator it = rows.begin(), end = rows.end();
0576          it != end; ++it)
0577     {
0578         cnt++;
0579     }
0580     CHECK(cnt == 1);
0581 }
0582 
0583 TEST_CASE("MySQL function call", "[mysql][function]")
0584 {
0585     soci::session sql(backEnd, connectString);
0586 
0587     row r;
0588 
0589     sql << "set @day = '5'";
0590     sql << "set @mm = 'december'";
0591     sql << "set @year = '2012'";
0592     sql << "select concat(@day,' ',@mm,' ',@year)", into(r);
0593 }
0594 
0595 struct double_value_table_creator : table_creator_base
0596 {
0597     double_value_table_creator(soci::session & sql)
0598         : table_creator_base(sql)
0599     {
0600         sql << "create table soci_test(val double)";
0601     }
0602 };
0603 
0604 TEST_CASE("MySQL special floating point values", "[mysql][float]")
0605 {
0606     static bool is_iec559 = std::numeric_limits<double>::is_iec559;
0607     if (!is_iec559)
0608     {
0609         WARN("C++ double type is not IEC-559, skipping test.");
0610         return;
0611     }
0612 
0613   const std::string expectedError =
0614       "Use element used with infinity or NaN, which are "
0615       "not supported by the MySQL server.";
0616   {
0617     soci::session sql(backEnd, connectString);
0618 
0619     double x = std::numeric_limits<double>::quiet_NaN();
0620     statement st = (sql.prepare << "SELECT :x", use(x, "x"));
0621     try {
0622         st.execute(true);
0623     } catch (soci_error const &e) {
0624         CHECK(e.get_error_message() == expectedError);
0625     }
0626   }
0627   {
0628     soci::session sql(backEnd, connectString);
0629 
0630     double x = std::numeric_limits<double>::infinity();
0631     statement st = (sql.prepare << "SELECT :x", use(x, "x"));
0632     try {
0633         st.execute(true);
0634     } catch (soci_error const &e) {
0635         CHECK(e.get_error_message() == expectedError);
0636     }
0637   }
0638   {
0639     soci::session sql(backEnd, connectString);
0640     double_value_table_creator tableCreator(sql);
0641 
0642     std::vector<double> v(1, std::numeric_limits<double>::quiet_NaN());
0643     try {
0644         sql << "insert into soci_test (val) values (:val)", use(v);
0645     } catch (soci_error const &e) {
0646         CHECK(e.get_error_message() == expectedError);
0647     }
0648   }
0649   {
0650     soci::session sql(backEnd, connectString);
0651     double_value_table_creator tableCreator(sql);
0652 
0653     std::vector<double> v(1, std::numeric_limits<double>::infinity());
0654     try {
0655         sql << "insert into soci_test (val) values (:val)", use(v);
0656     } catch (soci_error const &e) {
0657         CHECK(e.get_error_message() == expectedError);
0658     }
0659   }
0660 }
0661 
0662 struct tinyint_value_table_creator : table_creator_base
0663 {
0664     tinyint_value_table_creator(soci::session & sql)
0665         : table_creator_base(sql)
0666     {
0667         sql << "create table soci_test(val tinyint)";
0668     }
0669 };
0670 
0671 struct tinyint_unsigned_value_table_creator : table_creator_base
0672 {
0673     tinyint_unsigned_value_table_creator(soci::session & sql)
0674         : table_creator_base(sql)
0675     {
0676         sql << "create table soci_test(val tinyint unsigned)";
0677     }
0678 };
0679 
0680 TEST_CASE("MySQL tinyint", "[mysql][int][tinyint]")
0681 {
0682   {
0683     soci::session sql(backEnd, connectString);
0684     unsigned_value_table_creator tableCreator(sql);
0685     unsigned int mask = 0xffffff00;
0686     sql << "insert into soci_test set val = " << mask;
0687     row r;
0688     sql << "select val from soci_test", into(r);
0689     REQUIRE(r.size() == 1);
0690     CHECK(r.get_properties("val").get_data_type() == dt_long_long);
0691     CHECK(r.get<long long>("val") == 0xffffff00);
0692     CHECK(r.get<unsigned>("val") == 0xffffff00);
0693   }
0694   {
0695     soci::session sql(backEnd, connectString);
0696     tinyint_value_table_creator tableCreator(sql);
0697     sql << "insert into soci_test set val = -123";
0698     row r;
0699     sql << "select val from soci_test", into(r);
0700     REQUIRE(r.size() == 1);
0701     CHECK(r.get_properties("val").get_data_type() == dt_integer);
0702     CHECK(r.get<int>("val") == -123);
0703   }
0704   {
0705     soci::session sql(backEnd, connectString);
0706     tinyint_unsigned_value_table_creator tableCreator(sql);
0707     sql << "insert into soci_test set val = 123";
0708     row r;
0709     sql << "select val from soci_test", into(r);
0710     REQUIRE(r.size() == 1);
0711     CHECK(r.get_properties("val").get_data_type() == dt_integer);
0712     CHECK(r.get<int>("val") == 123);
0713   }
0714   {
0715     soci::session sql(backEnd, connectString);
0716     bigint_unsigned_table_creator tableCreator(sql);
0717     sql << "insert into soci_test set val = 123456789012345";
0718     row r;
0719     sql << "select val from soci_test", into(r);
0720     REQUIRE(r.size() == 1);
0721     CHECK(r.get_properties("val").get_data_type() == dt_unsigned_long_long);
0722     CHECK(r.get<unsigned long long>("val") == 123456789012345ULL);
0723   }
0724   {
0725     soci::session sql(backEnd, connectString);
0726     bigint_table_creator tableCreator(sql);
0727     sql << "insert into soci_test set val = -123456789012345";
0728     row r;
0729     sql << "select val from soci_test", into(r);
0730     REQUIRE(r.size() == 1);
0731     CHECK(r.get_properties("val").get_data_type() == dt_long_long);
0732     CHECK(r.get<long long>("val") == -123456789012345LL);
0733   }
0734 }
0735 
0736 struct strings_table_creator : table_creator_base
0737 {
0738     strings_table_creator(soci::session & sql)
0739         : table_creator_base(sql)
0740     {
0741         sql << "create table soci_test(s1 char(20), s2 varchar(20), "
0742             "s3 tinytext, s4 mediumtext, s5 text, s6 longtext, "
0743             "b1 binary(20), b2 varbinary(20), b3 tinyblob, b4 mediumblob, "
0744             "b5 blob, b6 longblob, e1 enum ('foo', 'bar', 'baz'))";
0745     }
0746 };
0747 
0748 TEST_CASE("MySQL strings", "[mysql][string]")
0749 {
0750     soci::session sql(backEnd, connectString);
0751     strings_table_creator tableCreator(sql);
0752     std::string text = "Ala ma kota.";
0753     std::string binary("Ala\0ma\0kota.........", 20);
0754     sql << "insert into soci_test "
0755         "(s1, s2, s3, s4, s5, s6, b1, b2, b3, b4, b5, b6, e1) values "
0756         "(:s1, :s2, :s3, :s4, :d5, :s6, :b1, :b2, :b3, :b4, :b5, :b6, "
0757         "\'foo\')",
0758         use(text), use(text), use(text), use(text), use(text), use(text),
0759         use(binary), use(binary), use(binary), use(binary), use(binary),
0760         use(binary);
0761     row r;
0762     sql << "select s1, s2, s3, s4, s5, s6, b1, b2, b3, b4, b5, b6, e1 "
0763         "from soci_test", into(r);
0764     REQUIRE(r.size() == 13);
0765     for (int i = 0; i < 13; i++) {
0766         CHECK(r.get_properties(i).get_data_type() == dt_string);
0767         if (i < 6) {
0768             CHECK(r.get<std::string>(i) == text);
0769         } else if (i < 12) {
0770             CHECK(r.get<std::string>(i) == binary);
0771         } else {
0772             CHECK(r.get<std::string>(i) == "foo");
0773         }
0774     }
0775 }
0776 
0777 struct table_creator_for_get_last_insert_id : table_creator_base
0778 {
0779     table_creator_for_get_last_insert_id(soci::session & sql)
0780         : table_creator_base(sql)
0781     {
0782         sql << "create table soci_test(id integer not null auto_increment, "
0783             "primary key (id))";
0784         sql << "alter table soci_test auto_increment = 42";
0785     }
0786 };
0787 
0788 TEST_CASE("MySQL last insert id", "[mysql][last-insert-id]")
0789 {
0790     soci::session sql(backEnd, connectString);
0791     table_creator_for_get_last_insert_id tableCreator(sql);
0792     sql << "insert into soci_test () values ()";
0793     long long id;
0794     bool result = sql.get_last_insert_id("soci_test", id);
0795     CHECK(result == true);
0796     CHECK(id == 42);
0797 }
0798 
0799 std::string escape_string(soci::session& sql, const std::string& s)
0800 {
0801     mysql_session_backend* backend = static_cast<mysql_session_backend*>(
0802         sql.get_backend());
0803     char* escaped = new char[2 * s.size() + 1];
0804     mysql_real_escape_string(backend->conn_, escaped, s.data(), static_cast<unsigned long>(s.size()));
0805     std::string retv = escaped;
0806     delete [] escaped;
0807     return retv;
0808 }
0809 
0810 void test14()
0811 {
0812     {
0813         soci::session sql(backEnd, connectString);
0814         strings_table_creator tableCreator(sql);
0815         std::string s = "word1'word2:word3";
0816         std::string escaped = escape_string(sql, s);
0817         std::string query = "insert into soci_test (s5) values ('";
0818         query.append(escaped);
0819         query.append("')");
0820         sql << query;
0821         std::string s2;
0822         sql << "select s5 from soci_test", into(s2);
0823         CHECK(s == s2);
0824     }
0825 
0826     std::cout << "test 14 passed" << std::endl;
0827 }
0828 
0829 void test15()
0830 {
0831     {
0832         soci::session sql(backEnd, connectString);
0833         int n;
0834         sql << "select @a := 123", into(n);
0835         CHECK(n == 123);
0836     }
0837 
0838     std::cout << "test 15 passed" << std::endl;
0839 }
0840 
0841 int main(int argc, char** argv)
0842 {
0843     if (argc >= 2)
0844     {
0845         connectString = argv[1];
0846 
0847         // Replace the connect string with the process name to ensure that
0848         // CATCH uses the correct name in its messages.
0849         argv[1] = argv[0];
0850 
0851         argc--;
0852         argv++;
0853     }
0854     else
0855     {
0856         std::cout << "usage: " << argv[0]
0857             << " connectstring [test-arguments...]\n"
0858             << "example: " << argv[0]
0859             << " \"dbname=test user=root password=\'Ala ma kota\'\"\n";
0860         std::exit(1);
0861     }
0862 
0863     test_context tc(backEnd, connectString);
0864 
0865     return Catch::Session().run(argc, argv);
0866 }