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 }