00001 // 00002 // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton 00003 // MySQL backend copyright (C) 2006 Pawel Aleksander Fedorynski 00004 // Distributed under the Boost Software License, Version 1.0. 00005 // (See accompanying file LICENSE_1_0.txt or copy at 00006 // http://www.boost.org/LICENSE_1_0.txt) 00007 // 00008 00009 // 00010 #if defined(SOCI_HEADERS_BURIED) 00011 # include <soci/core/soci.h> 00012 # include <soci/backends/mysql/soci-mysql.h> 00013 # include <soci/core/test/common-tests.h> 00014 #else 00015 # include <soci.h> 00016 # include <soci-mysql.h> 00017 # include <test/common-tests.h> 00018 #endif 00019 // 00020 #include <iostream> 00021 #include <sstream> 00022 #include <string> 00023 #include <vector> 00024 #include <cassert> 00025 #include <cmath> 00026 #include <ctime> 00027 #include <ciso646> 00028 #include <cstdlib> 00029 // MySQL Client 00030 #if defined(SOCI_MYSQL_HEADERS_BURIED) 00031 # include <mysql/mysqld_error.h> 00032 # include <mysql/errmsg.h> 00033 #else 00034 # include <mysqld_error.h> 00035 # include <errmsg.h> 00036 #endif 00037 00038 using namespace soci; 00039 using namespace soci::tests; 00040 00041 std::string connectString; 00042 backend_factory const &backEnd = mysql; 00043 00044 00045 // procedure call test 00046 void test1() 00047 { 00048 { 00049 session sql(backEnd, connectString); 00050 00051 mysql_session_backend *sessionBackEnd 00052 = static_cast<mysql_session_backend *>(sql.get_backend()); 00053 std::string version = mysql_get_server_info(sessionBackEnd->conn_); 00054 int v; 00055 std::istringstream iss(version); 00056 if ((iss >> v) and v < 5) 00057 { 00058 std::cout << "skipping test 1 (MySQL server version "; 00059 std::cout << version << " does not support stored procedures)\n"; 00060 return; 00061 } 00062 00063 try { sql << "drop function myecho"; } 00064 catch (soci_error const &) {} 00065 00066 sql << 00067 "create function myecho(msg text) " 00068 "returns text deterministic " 00069 " return msg; "; 00070 00071 std::string in("my message"); 00072 std::string out; 00073 00074 statement st = (sql.prepare << 00075 "select myecho(:input)", 00076 into(out), 00077 use(in, "input")); 00078 00079 st.execute(1); 00080 assert(out == in); 00081 00082 // explicit procedure syntax 00083 { 00084 std::string in("my message2"); 00085 std::string out; 00086 00087 procedure proc = (sql.prepare << 00088 "myecho(:input)", 00089 into(out), use(in, "input")); 00090 00091 proc.execute(1); 00092 assert(out == in); 00093 } 00094 00095 sql << "drop function myecho"; 00096 } 00097 00098 std::cout << "test 1 passed" << std::endl; 00099 } 00100 00101 // MySQL error reporting test. 00102 void test2() 00103 { 00104 { 00105 try 00106 { 00107 session sql(backEnd, "host=test.soci.invalid"); 00108 } 00109 catch (mysql_soci_error const &e) 00110 { 00111 assert(e.err_num_ == CR_UNKNOWN_HOST); 00112 } 00113 } 00114 00115 { 00116 session sql(backEnd, connectString); 00117 sql << "create table soci_test (id integer)"; 00118 try 00119 { 00120 int n; 00121 sql << "select id from soci_test_nosuchtable", into(n); 00122 } 00123 catch (mysql_soci_error const &e) 00124 { 00125 assert(e.err_num_ == ER_NO_SUCH_TABLE); 00126 } 00127 try 00128 { 00129 sql << "insert into soci_test (invalid) values (256)"; 00130 } 00131 catch (mysql_soci_error const &e) 00132 { 00133 assert(e.err_num_ == ER_BAD_FIELD_ERROR); 00134 } 00135 // A bulk operation. 00136 try 00137 { 00138 std::vector<int> v(3, 5); 00139 sql << "insert into soci_test_nosuchtable values (:n)", use(v); 00140 } 00141 catch (mysql_soci_error const &e) 00142 { 00143 assert(e.err_num_ == ER_NO_SUCH_TABLE); 00144 } 00145 sql << "drop table soci_test"; 00146 } 00147 00148 std::cout << "test 2 passed" << std::endl; 00149 } 00150 00151 struct longlong_table_creator : table_creator_base 00152 { 00153 longlong_table_creator(session & sql) 00154 : table_creator_base(sql) 00155 { 00156 sql << "create table soci_test(val bigint)"; 00157 } 00158 }; 00159 00160 // long long test 00161 void test3() 00162 { 00163 { 00164 session sql(backEnd, connectString); 00165 00166 longlong_table_creator tableCreator(sql); 00167 00168 long long v1 = 1000000000000LL; 00169 assert(v1 / 1000000 == 1000000); 00170 00171 sql << "insert into soci_test(val) values(:val)", use(v1); 00172 00173 long long v2 = 0LL; 00174 sql << "select val from soci_test", into(v2); 00175 00176 assert(v2 == v1); 00177 } 00178 00179 // vector<long long> 00180 { 00181 session sql(backEnd, connectString); 00182 00183 longlong_table_creator tableCreator(sql); 00184 00185 std::vector<long long> v1; 00186 v1.push_back(1000000000000LL); 00187 v1.push_back(1000000000001LL); 00188 v1.push_back(1000000000002LL); 00189 v1.push_back(1000000000003LL); 00190 v1.push_back(1000000000004LL); 00191 00192 sql << "insert into soci_test(val) values(:val)", use(v1); 00193 00194 std::vector<long long> v2(10); 00195 sql << "select val from soci_test order by val desc", into(v2); 00196 00197 assert(v2.size() == 5); 00198 assert(v2[0] == 1000000000004LL); 00199 assert(v2[1] == 1000000000003LL); 00200 assert(v2[2] == 1000000000002LL); 00201 assert(v2[3] == 1000000000001LL); 00202 assert(v2[4] == 1000000000000LL); 00203 } 00204 00205 std::cout << "test 3 passed" << std::endl; 00206 } 00207 00208 template <typename T> 00209 void test_num(const char* s, bool valid, T value) 00210 { 00211 try 00212 { 00213 session sql(backEnd, connectString); 00214 T val; 00215 sql << "select \'" << s << "\'", into(val); 00216 if (valid) 00217 { 00218 double v1 = value; 00219 double v2 = val; 00220 double d = std::fabs(v1 - v2); 00221 double epsilon = 0.001; 00222 assert(d < epsilon || 00223 d < epsilon * (std::fabs(v1) + std::fabs(v2))); 00224 } 00225 else 00226 { 00227 std::cout << "string \"" << s << "\" parsed as " << val 00228 << " but should have failed.\n"; 00229 assert(false); 00230 } 00231 } 00232 catch (soci_error const& e) 00233 { 00234 if (valid) 00235 { 00236 std::cout << "couldn't parse number: \"" << s << "\"\n"; 00237 assert(false); 00238 } 00239 else 00240 { 00241 assert(std::string(e.what()) == "Cannot convert data."); 00242 } 00243 } 00244 } 00245 00246 // Number conversion test. 00247 void test4() 00248 { 00249 test_num<double>("", false, 0); 00250 test_num<double>("foo", false, 0); 00251 test_num<double>("1", true, 1); 00252 test_num<double>("12", true, 12); 00253 test_num<double>("123", true, 123); 00254 test_num<double>("12345", true, 12345); 00255 test_num<double>("12341234123412341234123412341234123412341234123412341", 00256 true, 1.23412e+52); 00257 test_num<double>("99999999999999999999999912222222222222222222222222223" 00258 "9999999999999999999999991222222222222222222222222222333333333333" 00259 "9999999999999999999999991222222222222222222222222222333333333333" 00260 "9999999999999999999999991222222222222222222222222222333333333333" 00261 "9999999999999999999999991222222222222222222222222222333333333333" 00262 "9999999999999999999999991222222222222222222222222222333333333333" 00263 "9999999999999999999999991222222222222222222222222222333333333333" 00264 "9999999999999999999999991222222222222222222222222222333333333333" 00265 "9999999999999999999999991222222222222222222222222222333333333333" 00266 "9999999999999999999999991222222222222222222222222222333333333333" 00267 "9999999999999999999999991222222222222222222222222222333333333333" 00268 "9999999999999999999999991222222222222222222222222222333333333333" 00269 "9999999999999999999999991222222222222222222222222222333333333333" 00270 "9999999999999999999999991222222222222222222222222222333333333333" 00271 "9999999999999999999999991222222222222222222222222222333333333333", 00272 false, 0); 00273 test_num<double>("1e3", true, 1000); 00274 test_num<double>("1.2", true, 1.2); 00275 test_num<double>("1.2345e2", true, 123.45); 00276 test_num<double>("1 ", false, 0); 00277 test_num<double>(" 123", true, 123); 00278 test_num<double>("1,2", false, 0); 00279 test_num<double>("123abc", false, 0); 00280 test_num<double>("-0", true, 0); 00281 00282 test_num<short>("123", true, 123); 00283 test_num<short>("100000", false, 0); 00284 00285 test_num<int>("123", true, 123); 00286 test_num<int>("2147483647", true, 2147483647); 00287 test_num<int>("2147483647a", false, 0); 00288 test_num<int>("2147483648", false, 0); 00289 // -2147483648 causes a warning because it is interpreted as 00290 // 2147483648 (which doesn't fit in an integer) to which a negation 00291 // is applied. 00292 test_num<int>("-2147483648", true, -2147483647 - 1); 00293 test_num<int>("-2147483649", false, 0); 00294 test_num<int>("-0", true, 0); 00295 test_num<int>("1.1", false, 0); 00296 00297 test_num<long long>("123", true, 123); 00298 test_num<long long>("9223372036854775807", true, 9223372036854775807LL); 00299 test_num<long long>("9223372036854775808", false, 0); 00300 00301 std::cout << "test 4 passed" << std::endl; 00302 } 00303 00304 void test5() 00305 { 00306 session sql(backEnd, connectString); 00307 std::tm t; 00308 sql << "select maketime(19, 54, 52)", into(t); 00309 assert(t.tm_year == 100); 00310 assert(t.tm_mon == 0); 00311 assert(t.tm_mday == 1); 00312 assert(t.tm_hour == 19); 00313 assert(t.tm_min == 54); 00314 assert(t.tm_sec == 52); 00315 00316 std::cout << "test 5 passed" << std::endl; 00317 } 00318 00319 // TEXT and BLOB types support test. 00320 void test6() 00321 { 00322 session sql(backEnd, connectString); 00323 std::string a("asdfg\0hjkl", 10); 00324 std::string b("lkjhg\0fd\0\0sa\0", 13); 00325 std::string c("\\0aa\\0bb\\0cc\\0", 10); 00326 // The maximum length for TEXT and BLOB is 65536. 00327 std::string x(60000, 'X'); 00328 std::string y(60000, 'Y'); 00329 // The default max_allowed_packet value for a MySQL server is 1M, 00330 // so let's limit ourselves to 800k, even though the maximum length 00331 // for LONGBLOB is 4G. 00332 std::string z(800000, 'Z'); 00333 00334 sql << "create table soci_test (id int, text_value text, " 00335 "blob_value blob, longblob_value longblob)"; 00336 sql << "insert into soci_test values (1, \'foo\', \'bar\', \'baz\')"; 00337 sql << "insert into soci_test " 00338 << "values (2, \'qwerty\\0uiop\', \'zxcv\\0bnm\', " 00339 << "\'qwerty\\0uiop\\0zxcvbnm\\0\')"; 00340 sql << "insert into soci_test values (3, :a, :b, :c)", 00341 use(a), use(b), use(c); 00342 sql << "insert into soci_test values (4, :x, :y, :z)", 00343 use(x), use(y), use(z); 00344 00345 std::vector<std::string> text_vec(100); 00346 std::vector<std::string> blob_vec(100); 00347 std::vector<std::string> longblob_vec(100); 00348 sql << "select text_value, blob_value, longblob_value " 00349 << "from soci_test order by id", 00350 into(text_vec), into(blob_vec), into(longblob_vec); 00351 assert(text_vec.size() == 4); 00352 assert(blob_vec.size() == 4); 00353 assert(longblob_vec.size() == 4); 00354 assert(text_vec[0] == "foo"); 00355 assert(blob_vec[0] == "bar"); 00356 assert(longblob_vec[0] == "baz"); 00357 assert(text_vec[1] == std::string("qwerty\0uiop", 11)); 00358 assert(blob_vec[1] == std::string("zxcv\0bnm", 8)); 00359 assert(longblob_vec[1] == std::string("qwerty\0uiop\0zxcvbnm\0", 20)); 00360 assert(text_vec[2] == a); 00361 assert(blob_vec[2] == b); 00362 assert(longblob_vec[2] == c); 00363 assert(text_vec[3] == x); 00364 assert(blob_vec[3] == y); 00365 assert(longblob_vec[3] == z); 00366 00367 std::string text, blob, longblob; 00368 sql << "select text_value, blob_value, longblob_value " 00369 << "from soci_test where id = 1", 00370 into(text), into(blob), into(longblob); 00371 assert(text == "foo"); 00372 assert(blob == "bar"); 00373 assert(longblob == "baz"); 00374 sql << "select text_value, blob_value, longblob_value " 00375 << "from soci_test where id = 2", 00376 into(text), into(blob), into(longblob); 00377 assert(text == std::string("qwerty\0uiop", 11)); 00378 assert(blob == std::string("zxcv\0bnm", 8)); 00379 assert(longblob == std::string("qwerty\0uiop\0zxcvbnm\0", 20)); 00380 sql << "select text_value, blob_value, longblob_value " 00381 << "from soci_test where id = 3", 00382 into(text), into(blob), into(longblob); 00383 assert(text == a); 00384 assert(blob == b); 00385 assert(longblob == c); 00386 sql << "select text_value, blob_value, longblob_value " 00387 << "from soci_test where id = 4", 00388 into(text), into(blob), into(longblob); 00389 assert(text == x); 00390 assert(blob == y); 00391 assert(longblob == z); 00392 00393 rowset<row> rs = 00394 (sql.prepare << "select text_value, blob_value, longblob_value " 00395 "from soci_test order by id"); 00396 rowset<row>::const_iterator r = rs.begin(); 00397 assert(r->get_properties(0).get_data_type() == dt_string); 00398 assert(r->get<std::string>(0) == "foo"); 00399 assert(r->get_properties(1).get_data_type() == dt_string); 00400 assert(r->get<std::string>(1) == "bar"); 00401 assert(r->get_properties(2).get_data_type() == dt_string); 00402 assert(r->get<std::string>(2) == "baz"); 00403 ++r; 00404 assert(r->get_properties(0).get_data_type() == dt_string); 00405 assert(r->get<std::string>(0) == std::string("qwerty\0uiop", 11)); 00406 assert(r->get_properties(1).get_data_type() == dt_string); 00407 assert(r->get<std::string>(1) == std::string("zxcv\0bnm", 8)); 00408 assert(r->get_properties(2).get_data_type() == dt_string); 00409 assert(r->get<std::string>(2) == 00410 std::string("qwerty\0uiop\0zxcvbnm\0", 20)); 00411 ++r; 00412 assert(r->get_properties(0).get_data_type() == dt_string); 00413 assert(r->get<std::string>(0) == a); 00414 assert(r->get_properties(1).get_data_type() == dt_string); 00415 assert(r->get<std::string>(1) == b); 00416 assert(r->get_properties(2).get_data_type() == dt_string); 00417 assert(r->get<std::string>(2) == c); 00418 ++r; 00419 assert(r->get_properties(0).get_data_type() == dt_string); 00420 assert(r->get<std::string>(0) == x); 00421 assert(r->get_properties(1).get_data_type() == dt_string); 00422 assert(r->get<std::string>(1) == y); 00423 assert(r->get_properties(2).get_data_type() == dt_string); 00424 assert(r->get<std::string>(2) == z); 00425 ++r; 00426 assert(r == rs.end()); 00427 00428 sql << "drop table soci_test"; 00429 00430 std::cout << "test 6 passed" << std::endl; 00431 } 00432 00433 // DDL Creation objects for common tests 00434 struct table_creator_one : public table_creator_base 00435 { 00436 table_creator_one(session & sql) 00437 : table_creator_base(sql) 00438 { 00439 sql << "create table soci_test(id integer, val integer, c char, " 00440 "str varchar(20), sh int2, ul numeric(20), d float8, " 00441 "tm datetime, i1 integer, i2 integer, i3 integer, " 00442 "name varchar(20)) type=InnoDB"; 00443 } 00444 }; 00445 00446 struct table_creator_two : public table_creator_base 00447 { 00448 table_creator_two(session & sql) 00449 : table_creator_base(sql) 00450 { 00451 sql << "create table soci_test(num_float float8, num_int integer," 00452 " name varchar(20), sometime datetime, chr char)"; 00453 } 00454 }; 00455 00456 struct table_creator_three : public table_creator_base 00457 { 00458 table_creator_three(session & sql) 00459 : table_creator_base(sql) 00460 { 00461 sql << "create table soci_test(name varchar(100) not null, " 00462 "phone varchar(15))"; 00463 } 00464 }; 00465 00466 // 00467 // Support for SOCI Common Tests 00468 // 00469 00470 class test_context : public test_context_base 00471 { 00472 public: 00473 test_context(backend_factory const &backEnd, 00474 std::string const &connectString) 00475 : test_context_base(backEnd, connectString) {} 00476 00477 table_creator_base* table_creator_1(session& s) const 00478 { 00479 return new table_creator_one(s); 00480 } 00481 00482 table_creator_base* table_creator_2(session& s) const 00483 { 00484 return new table_creator_two(s); 00485 } 00486 00487 table_creator_base* table_creator_3(session& s) const 00488 { 00489 return new table_creator_three(s); 00490 } 00491 00492 std::string to_date_time(std::string const &datdt_string) const 00493 { 00494 return "\'" + datdt_string + "\'"; 00495 } 00496 00497 }; 00498 00499 bool are_transactions_supported() 00500 { 00501 session sql(backEnd, connectString); 00502 sql << "drop table if exists soci_test"; 00503 sql << "create table soci_test (id int) type=InnoDB"; 00504 row r; 00505 sql << "show table status like \'soci_test\'", into(r); 00506 bool retv = (r.get<std::string>(1) == "InnoDB"); 00507 sql << "drop table soci_test"; 00508 return retv; 00509 } 00510 00511 int main(int argc, char** argv) 00512 { 00513 if (argc == 2) 00514 { 00515 connectString = argv[1]; 00516 } 00517 else 00518 { 00519 std::cout << "usage: " << argv[0] 00520 << " connectstring\n" 00521 << "example: " << argv[0] 00522 << " \"dbname=test user=root password=\'Ala ma kota\'\"\n"; 00523 std::exit(1); 00524 } 00525 00526 try 00527 { 00528 test_context tc(backEnd, connectString); 00529 common_tests tests(tc); 00530 bool checkTransactions = are_transactions_supported(); 00531 tests.run(checkTransactions); 00532 00533 std::cout << "\nSOCI MySQL Tests:\n\n"; 00534 00535 test1(); 00536 test2(); 00537 test3(); 00538 test4(); 00539 test5(); 00540 test6(); 00541 00542 std::cout << "\nOK, all tests passed.\n\n"; 00543 return EXIT_SUCCESS; 00544 } 00545 catch (std::exception const & e) 00546 { 00547 std::cout << e.what() << '\n'; 00548 return EXIT_FAILURE; 00549 } 00550 }
Generated on Sun Oct 3 2010 17:42:16 for EXTRAS-SOCI by Doxygen 1.7.1