00001 // 00002 // Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton 00003 // Distributed under the Boost Software License, Version 1.0. 00004 // (See accompanying file LICENSE_1_0.txt or copy at 00005 // http://www.boost.org/LICENSE_1_0.txt) 00006 // 00007 00008 // 00009 #if defined(SOCI_HEADERS_BURIED) 00010 # include <soci/core/soci.h> 00011 # include <soci/backends/postgresql/soci-postgresql.h> 00012 # include <soci/core/test/common-tests.h> 00013 #else 00014 # include <soci.h> 00015 # include <soci-postgresql.h> 00016 # include <test/common-tests.h> 00017 #endif 00018 // 00019 #include <iostream> 00020 #include <sstream> 00021 #include <string> 00022 #include <cassert> 00023 #include <cmath> 00024 #include <cstring> 00025 #include <ctime> 00026 #include <cstdlib> 00027 00028 using namespace soci; 00029 using namespace soci::tests; 00030 00031 std::string connectString; 00032 backend_factory const &backEnd = postgresql; 00033 00034 // Postgres-specific tests 00035 00036 struct oid_table_creator : public table_creator_base 00037 { 00038 oid_table_creator(session& sql) 00039 : table_creator_base(sql) 00040 { 00041 sql << "create table soci_test (" 00042 " id integer," 00043 " name varchar(100)" 00044 ") with oids"; 00045 } 00046 }; 00047 00048 // ROWID test 00049 // Note: in PostgreSQL, there is no ROWID, there is OID. 00050 // It is still provided as a separate type for "portability", 00051 // whatever that means. 00052 void test1() 00053 { 00054 { 00055 session sql(backEnd, connectString); 00056 00057 oid_table_creator tableCreator(sql); 00058 00059 sql << "insert into soci_test(id, name) values(7, \'John\')"; 00060 00061 rowid rid(sql); 00062 sql << "select oid from soci_test where id = 7", into(rid); 00063 00064 int id; 00065 std::string name; 00066 00067 #ifndef SOCI_PGSQL_NOPARAMS 00068 00069 sql << "select id, name from soci_test where oid = :rid", 00070 into(id), into(name), use(rid); 00071 00072 #else 00073 // Older PostgreSQL does not support use elements. 00074 00075 postgresql_rowid_backend *rbe 00076 = static_cast<postgresql_rowid_backend *>(rid.get_backend()); 00077 00078 unsigned long oid = rbe->value_; 00079 00080 sql << "select id, name from soci_test where oid = " << oid, 00081 into(id), into(name); 00082 00083 #endif // SOCI_PGSQL_NOPARAMS 00084 00085 assert(id == 7); 00086 assert(name == "John"); 00087 } 00088 00089 std::cout << "test 1 passed" << std::endl; 00090 } 00091 00092 // function call test 00093 class function_creator : function_creator_base 00094 { 00095 public: 00096 00097 function_creator(session & sql) 00098 : function_creator_base(sql) 00099 { 00100 // before a language can be used it must be defined 00101 // if it has already been defined then an error will occur 00102 try { sql << "create language plpgsql"; } 00103 catch (soci_error const &) {} // ignore if error 00104 00105 #ifndef SOCI_PGSQL_NOPARAMS 00106 00107 sql << 00108 "create or replace function soci_test(msg varchar) " 00109 "returns varchar as $$ " 00110 "begin " 00111 " return msg; " 00112 "end $$ language plpgsql"; 00113 #else 00114 00115 sql << 00116 "create or replace function soci_test(varchar) " 00117 "returns varchar as \' " 00118 "begin " 00119 " return $1; " 00120 "end \' language plpgsql"; 00121 #endif 00122 } 00123 00124 protected: 00125 00126 std::string drop_statement() 00127 { 00128 return "drop function soci_test(varchar)"; 00129 } 00130 }; 00131 00132 void test2() 00133 { 00134 { 00135 session sql(backEnd, connectString); 00136 00137 function_creator functionCreator(sql); 00138 00139 std::string in("my message"); 00140 std::string out; 00141 00142 #ifndef SOCI_PGSQL_NOPARAMS 00143 00144 statement st = (sql.prepare << 00145 "select soci_test(:input)", 00146 into(out), 00147 use(in, "input")); 00148 00149 #else 00150 // Older PostgreSQL does not support use elements. 00151 00152 statement st = (sql.prepare << 00153 "select soci_test(\'" << in << "\')", 00154 into(out)); 00155 00156 #endif // SOCI_PGSQL_NOPARAMS 00157 00158 st.execute(true); 00159 assert(out == in); 00160 00161 // explicit procedure syntax 00162 { 00163 std::string in("my message2"); 00164 std::string out; 00165 00166 #ifndef SOCI_PGSQL_NOPARAMS 00167 00168 procedure proc = (sql.prepare << 00169 "soci_test(:input)", 00170 into(out), use(in, "input")); 00171 00172 #else 00173 // Older PostgreSQL does not support use elements. 00174 00175 procedure proc = (sql.prepare << 00176 "soci_test(\'" << in << "\')", into(out)); 00177 00178 #endif // SOCI_PGSQL_NOPARAMS 00179 00180 proc.execute(true); 00181 assert(out == in); 00182 } 00183 } 00184 00185 std::cout << "test 2 passed" << std::endl; 00186 } 00187 00188 // BLOB test 00189 struct blob_table_creator : public table_creator_base 00190 { 00191 blob_table_creator(session & sql) 00192 : table_creator_base(sql) 00193 { 00194 sql << 00195 "create table soci_test (" 00196 " id integer," 00197 " img oid" 00198 ")"; 00199 } 00200 }; 00201 00202 void test3() 00203 { 00204 { 00205 session sql(backEnd, connectString); 00206 00207 blob_table_creator tableCreator(sql); 00208 00209 char buf[] = "abcdefghijklmnopqrstuvwxyz"; 00210 00211 sql << "insert into soci_test(id, img) values(7, lo_creat(-1))"; 00212 00213 // in PostgreSQL, BLOB operations must be within transaction block 00214 transaction tr(sql); 00215 00216 { 00217 blob b(sql); 00218 00219 sql << "select img from soci_test where id = 7", into(b); 00220 assert(b.get_len() == 0); 00221 00222 b.write(0, buf, sizeof(buf)); 00223 assert(b.get_len() == sizeof(buf)); 00224 00225 b.append(buf, sizeof(buf)); 00226 assert(b.get_len() == 2 * sizeof(buf)); 00227 } 00228 { 00229 blob b(sql); 00230 sql << "select img from soci_test where id = 7", into(b); 00231 assert(b.get_len() == 2 * sizeof(buf)); 00232 char buf2[100]; 00233 b.read(0, buf2, 10); 00234 assert(std::strncmp(buf2, "abcdefghij", 10) == 0); 00235 } 00236 00237 unsigned long oid; 00238 sql << "select img from soci_test where id = 7", into(oid); 00239 sql << "select lo_unlink(" << oid << ")"; 00240 } 00241 00242 std::cout << "test 3 passed" << std::endl; 00243 } 00244 00245 struct longlong_table_creator : table_creator_base 00246 { 00247 longlong_table_creator(session & sql) 00248 : table_creator_base(sql) 00249 { 00250 sql << "create table soci_test(val int8)"; 00251 } 00252 }; 00253 00254 // long long test 00255 void test4() 00256 { 00257 { 00258 session sql(backEnd, connectString); 00259 00260 longlong_table_creator tableCreator(sql); 00261 00262 long long v1 = 1000000000000LL; 00263 assert(v1 / 1000000 == 1000000); 00264 00265 sql << "insert into soci_test(val) values(:val)", use(v1); 00266 00267 long long v2 = 0LL; 00268 sql << "select val from soci_test", into(v2); 00269 00270 assert(v2 == v1); 00271 } 00272 00273 // vector<long long> 00274 { 00275 session sql(backEnd, connectString); 00276 00277 longlong_table_creator tableCreator(sql); 00278 00279 std::vector<long long> v1; 00280 v1.push_back(1000000000000LL); 00281 v1.push_back(1000000000001LL); 00282 v1.push_back(1000000000002LL); 00283 v1.push_back(1000000000003LL); 00284 v1.push_back(1000000000004LL); 00285 00286 sql << "insert into soci_test(val) values(:val)", use(v1); 00287 00288 std::vector<long long> v2(10); 00289 sql << "select val from soci_test order by val desc", into(v2); 00290 00291 assert(v2.size() == 5); 00292 assert(v2[0] == 1000000000004LL); 00293 assert(v2[1] == 1000000000003LL); 00294 assert(v2[2] == 1000000000002LL); 00295 assert(v2[3] == 1000000000001LL); 00296 assert(v2[4] == 1000000000000LL); 00297 } 00298 00299 std::cout << "test 4 passed" << std::endl; 00300 } 00301 00302 struct boolean_table_creator : table_creator_base 00303 { 00304 boolean_table_creator(session & sql) 00305 : table_creator_base(sql) 00306 { 00307 sql << "create table soci_test(val boolean)"; 00308 } 00309 }; 00310 00311 void test5() 00312 { 00313 { 00314 session sql(backEnd, connectString); 00315 00316 boolean_table_creator tableCreator(sql); 00317 00318 int i1 = 0; 00319 00320 sql << "insert into soci_test(val) values(:val)", use(i1); 00321 00322 int i2 = 7; 00323 sql << "select val from soci_test", into(i2); 00324 00325 assert(i2 == i1); 00326 00327 sql << "update soci_test set val = true"; 00328 sql << "select val from soci_test", into(i2); 00329 assert(i2 == 1); 00330 } 00331 00332 std::cout << "test 5 passed" << std::endl; 00333 } 00334 00335 // dynamic backend test 00336 void test6() 00337 { 00338 try 00339 { 00340 session sql("nosuchbackend://" + connectString); 00341 assert(false); 00342 } 00343 catch (soci_error const & e) 00344 { 00345 assert(e.what() == std::string("Failed to open: libsoci_nosuchbackend.so")); 00346 } 00347 00348 { 00349 dynamic_backends::register_backend("pgsql", backEnd); 00350 00351 std::vector<std::string> backends = dynamic_backends::list_all(); 00352 assert(backends.size() == 1); 00353 assert(backends[0] == "pgsql"); 00354 00355 { 00356 session sql("pgsql://" + connectString); 00357 } 00358 00359 dynamic_backends::unload("pgsql"); 00360 00361 backends = dynamic_backends::list_all(); 00362 assert(backends.empty()); 00363 } 00364 00365 { 00366 session sql("postgresql://" + connectString); 00367 } 00368 00369 std::cout << "test 6 passed" << std::endl; 00370 } 00371 00372 void test7() 00373 { 00374 { 00375 session sql(backEnd, connectString); 00376 00377 int i; 00378 sql << "select 123", into(i); 00379 assert(i == 123); 00380 00381 try 00382 { 00383 sql << "select 'ABC'", into (i); 00384 assert(false); 00385 } 00386 catch (soci_error const & e) 00387 { 00388 assert(e.what() == std::string("Cannot convert data.")); 00389 } 00390 } 00391 00392 std::cout << "test 7 passed" << std::endl; 00393 } 00394 00395 void test8() 00396 { 00397 { 00398 session sql(backEnd, connectString); 00399 00400 assert(sql.get_backend_name() == "postgresql"); 00401 } 00402 00403 std::cout << "test 8 passed" << std::endl; 00404 } 00405 00406 // test for double-colon cast in SQL expressions 00407 void test9() 00408 { 00409 { 00410 session sql(backEnd, connectString); 00411 00412 int a = 123; 00413 int b = 0; 00414 sql << "select :a::integer", use(a), into(b); 00415 assert(b == a); 00416 } 00417 00418 std::cout << "test 9 passed" << std::endl; 00419 } 00420 00421 // test for date, time and timestamp parsing 00422 void test10() 00423 { 00424 { 00425 session sql(backEnd, connectString); 00426 00427 std::string someDate = "2009-06-17 22:51:03.123"; 00428 std::tm t1, t2, t3; 00429 00430 sql << "select :sd::date, :sd::time, :sd::timestamp", 00431 use(someDate, "sd"), into(t1), into(t2), into(t3); 00432 00433 // t1 should contain only the date part 00434 assert(t1.tm_year == 2009 - 1900); 00435 assert(t1.tm_mon == 6 - 1); 00436 assert(t1.tm_mday == 17); 00437 assert(t1.tm_hour == 0); 00438 assert(t1.tm_min == 0); 00439 assert(t1.tm_sec == 0); 00440 00441 // t2 should contain only the time of day part 00442 assert(t2.tm_year == 0); 00443 assert(t2.tm_mon == 0); 00444 assert(t2.tm_mday == 1); 00445 assert(t2.tm_hour == 22); 00446 assert(t2.tm_min == 51); 00447 assert(t2.tm_sec == 3); 00448 00449 // t3 should contain all information 00450 assert(t3.tm_year == 2009 - 1900); 00451 assert(t3.tm_mon == 6 - 1); 00452 assert(t3.tm_mday == 17); 00453 assert(t3.tm_hour == 22); 00454 assert(t3.tm_min == 51); 00455 assert(t3.tm_sec == 3); 00456 } 00457 00458 std::cout << "test 10 passed" << std::endl; 00459 } 00460 00461 // DDL Creation objects for common tests 00462 struct table_creator_one : public table_creator_base 00463 { 00464 table_creator_one(session & sql) 00465 : table_creator_base(sql) 00466 { 00467 sql << "create table soci_test(id integer, val integer, c char, " 00468 "str varchar(20), sh int2, ul numeric(20), d float8, " 00469 "tm timestamp, i1 integer, i2 integer, i3 integer, " 00470 "name varchar(20))"; 00471 } 00472 }; 00473 00474 struct table_creator_two : public table_creator_base 00475 { 00476 table_creator_two(session & sql) 00477 : table_creator_base(sql) 00478 { 00479 sql << "create table soci_test(num_float float8, num_int integer," 00480 " name varchar(20), sometime timestamp, chr char)"; 00481 } 00482 }; 00483 00484 struct table_creator_three : public table_creator_base 00485 { 00486 table_creator_three(session & sql) 00487 : table_creator_base(sql) 00488 { 00489 sql << "create table soci_test(name varchar(100) not null, " 00490 "phone varchar(15))"; 00491 } 00492 }; 00493 00494 // 00495 // Support for soci Common Tests 00496 // 00497 00498 class test_context : public test_context_base 00499 { 00500 public: 00501 test_context(backend_factory const &backEnd, 00502 std::string const &connectString) 00503 : test_context_base(backEnd, connectString) {} 00504 00505 table_creator_base* table_creator_1(session& s) const 00506 { 00507 return new table_creator_one(s); 00508 } 00509 00510 table_creator_base* table_creator_2(session& s) const 00511 { 00512 return new table_creator_two(s); 00513 } 00514 00515 table_creator_base* table_creator_3(session& s) const 00516 { 00517 return new table_creator_three(s); 00518 } 00519 00520 std::string to_date_time(std::string const &datdt_string) const 00521 { 00522 return "timestamptz(\'" + datdt_string + "\')"; 00523 } 00524 00525 }; 00526 00527 00528 int main(int argc, char** argv) 00529 { 00530 00531 #ifdef _MSC_VER 00532 // Redirect errors, unrecoverable problems, and assert() failures to STDERR, 00533 // instead of debug message window. 00534 // This hack is required to run asser()-driven tests by Buildbot. 00535 // NOTE: Comment this 2 lines for debugging with Visual C++ debugger to catch assertions inside. 00536 _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE); 00537 _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR); 00538 #endif //_MSC_VER 00539 00540 if (argc == 2) 00541 { 00542 connectString = argv[1]; 00543 } 00544 else 00545 { 00546 std::cout << "usage: " << argv[0] 00547 << " connectstring\n" 00548 << "example: " << argv[0] 00549 << " \'connect_string_for_PostgreSQL\'\n"; 00550 return EXIT_FAILURE; 00551 } 00552 00553 try 00554 { 00555 test_context tc(backEnd, connectString); 00556 common_tests tests(tc); 00557 tests.run(); 00558 00559 std::cout << "\nSOCI Postgres Tests:\n\n"; 00560 00561 test1(); 00562 test2(); 00563 test3(); 00564 test4(); 00565 test5(); 00566 00567 // test6(); 00568 std::cout << "test 6 skipped (dynamic backend)\n"; 00569 00570 test7(); 00571 test8(); 00572 test9(); 00573 test10(); 00574 00575 std::cout << "\nOK, all tests passed.\n\n"; 00576 return EXIT_SUCCESS; 00577 } 00578 catch (std::exception const & e) 00579 { 00580 std::cout << e.what() << '\n'; 00581 return EXIT_FAILURE; 00582 } 00583 }
Generated on Sun Oct 3 2010 17:42:17 for EXTRAS-SOCI by Doxygen 1.7.1