00001 // 00002 // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton, Rafal Bobrowski 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 // 00010 #if defined(SOCI_HEADERS_BURIED) 00011 # include <soci/core/soci.h> 00012 # include <soci/core/test/common-tests.h> 00013 # include <soci/backends/firebird/soci-firebird.h> 00014 # include <soci/backends/firebird/error-firebird.h> 00015 #else 00016 # include <soci.h> 00017 # include <test/common-tests.h> 00018 # include <soci-firebird.h> 00019 # include <error-firebird.h> // soci::details::Firebird::throw_iscerror() 00020 #endif 00021 // 00022 // STL 00023 #include <iostream> 00024 #include <string> 00025 #include <cassert> 00026 #include <ctime> 00027 #include <cstring> 00028 00029 using namespace soci; 00030 00031 std::string connectString; 00032 soci::backend_factory const &backEnd = firebird; 00033 00034 // fundamental tests - transactions in Firebird 00035 void test1() 00036 { 00037 { 00038 session sql(backEnd, connectString); 00039 00040 // In Firebird transaction is always required and is started 00041 // automatically when session is opened. There is no need to 00042 // call session::begin(); it will do nothing if there is active 00043 // transaction. 00044 00045 // sql.begin(); 00046 00047 try 00048 { 00049 sql << "drop table test1"; 00050 } 00051 catch (soci_error const &) 00052 {} // ignore if error 00053 00054 sql << "create table test1 (id integer)"; 00055 00056 // After DDL statement transaction must be commited or changes 00057 // won't be visible to active transaction. 00058 sql.commit(); 00059 00060 // After commit or rollback, transaction must be started manually. 00061 sql.begin(); 00062 00063 sql << "insert into test1(id) values(5)"; 00064 sql << "drop table test1"; 00065 00066 // Transaction is automatically commited in session's destructor 00067 } 00068 00069 std::cout << "test 1 passed" << std::endl; 00070 } 00071 00072 // character types 00073 void test2() 00074 { 00075 session sql(backEnd, connectString); 00076 00077 try 00078 { 00079 sql << "drop table test2"; 00080 } 00081 catch (soci_error const &) 00082 {} // ignore if error 00083 00084 sql << "create table test2 (p1 char(10), p2 varchar(10))"; 00085 sql.commit(); 00086 00087 sql.begin(); 00088 00089 { 00090 char a('a'), b('b'), c1, c2; 00091 00092 sql << "insert into test2(p1,p2) values(?,?)", use(a), use(b); 00093 00094 sql << "select p1,p2 from test2", into(c1), into(c2); 00095 assert(c1 == 'a' && c2 == 'b'); 00096 00097 sql << "delete from test2"; 00098 } 00099 00100 { 00101 std::string b1 ("Hello, Firebird!"); 00102 sql << "insert into test2(p1, p2) values (?,?)", use(b1), use(b1); 00103 std::string b2; 00104 std::string b3; 00105 sql << "select p1, p2 from test2", into(b2), into(b3); 00106 00107 assert( 00108 b2[0] == 'H' && b3[0] == 'H' && 00109 b2[1] == 'e' && b3[1] == 'e' && 00110 b2[2] == 'l' && b3[2] == 'l' && 00111 b2[3] == 'l' && b3[3] == 'l' && 00112 b2[4] == 'o' && b3[4] == 'o' && 00113 b2[5] == ',' && b3[5] == ',' && 00114 b2[6] == ' ' && b3[6] == ' ' && 00115 b2[7] == 'F' && b3[7] == 'F' && 00116 b2[8] == 'i' && b3[8] == 'i' && 00117 b2[9] == 'r' && b3[9] == 'r' && 00118 b2[10] == '\0' && b3[10] == '\0'); 00119 00120 sql << "delete from test2"; 00121 } 00122 00123 { 00124 std::string b1 ("Hello, Firebird!"); 00125 sql << "insert into test2(p1, p2) values (?,?)", use(b1), use(b1); 00126 std::string b2; 00127 std::string b3; 00128 sql << "select p1, p2 from test2", into(b2), into(b3); 00129 00130 assert( 00131 b2[0] == 'H' && b3[0] == 'H' && 00132 b2[1] == 'e' && b3[1] == 'e' && 00133 b2[2] == 'l' && b3[2] == 'l' && 00134 b2[3] == 'l' && b3[3] == 'l' && 00135 b2[4] == 'o' && b3[4] == 'o' && 00136 b2[5] == ',' && b3[5] == ',' && 00137 b2[6] == ' ' && b3[6] == ' ' && 00138 b2[7] == 'F' && b3[7] == 'F' && 00139 b2[8] == 'i' && b3[8] == 'i' && 00140 b2[9] == 'r' && b3[9] == 'r' && 00141 b2[10] == '\0' && b3[10] == '\0'); 00142 00143 sql << "delete from test2"; 00144 } 00145 00146 { 00147 // verify blank padding in CHAR fields 00148 // In Firebird, CHAR fields are always padded with whitespaces. 00149 std::string b1 ("Hello"); 00150 sql << "insert into test2(p1) values(\'" << b1 << "\')"; 00151 std::string b2; 00152 sql << "select p1 from test2", into(b2); 00153 00154 // assert(std::strncmp(b1, b2, 5) == 0); 00155 // assert(std::strncmp(b2+5, " ", 5) == 0); 00156 00157 sql << "delete from test2"; 00158 } 00159 00160 { 00161 std::string str1("Hello, Firebird!"), str2, str3; 00162 sql << "insert into test2(p1, p2) values (?, ?)", 00163 use(str1), use(str1); 00164 00165 sql << "select p1, p2 from test2", into(str2), into(str3); 00166 assert(str2 == "Hello, Fir" && str3 == "Hello, Fir"); 00167 00168 sql << "delete from test2"; 00169 } 00170 00171 sql << "drop table test2"; 00172 std::cout << "test 2 passed" << std::endl; 00173 } 00174 00175 // date and time 00176 void test3() 00177 { 00178 session sql(backEnd, connectString); 00179 00180 try 00181 { 00182 sql << "drop table test3"; 00183 } 00184 catch (soci_error const &) 00185 {} // ignore if error 00186 00187 sql << "create table test3 (p1 timestamp, p2 date, p3 time)"; 00188 sql.commit(); 00189 00190 sql.begin(); 00191 00192 std::tm t1, t2, t3; 00193 std::time_t now = std::time(NULL); 00194 std::tm t = *std::localtime(&now); 00195 00196 sql << "insert into test3(p1, p2, p3) " 00197 << "values (?,?,?)", use(t), use(t), use(t); 00198 00199 sql << "select p1, p2, p3 from test3", into(t1), into(t2), into(t3); 00200 00201 // timestamp 00202 assert(t1.tm_year == t.tm_year); 00203 assert(t1.tm_mon == t.tm_mon); 00204 assert(t1.tm_mday == t.tm_mday); 00205 assert(t1.tm_hour == t.tm_hour); 00206 assert(t1.tm_min == t.tm_min); 00207 assert(t1.tm_sec == t.tm_sec); 00208 00209 // date 00210 assert(t2.tm_year == t.tm_year); 00211 assert(t2.tm_mon == t.tm_mon); 00212 assert(t2.tm_mday == t.tm_mday); 00213 assert(t2.tm_hour == 0); 00214 assert(t2.tm_min == 0); 00215 assert(t2.tm_sec == 0); 00216 00217 // time 00218 assert(t3.tm_year == 0); 00219 assert(t3.tm_mon == 0); 00220 assert(t3.tm_mday == 0); 00221 assert(t3.tm_hour == t.tm_hour); 00222 assert(t3.tm_min == t.tm_min); 00223 assert(t3.tm_sec == t.tm_sec); 00224 00225 sql << "drop table test3"; 00226 std::cout << "test 3 passed" << std::endl; 00227 } 00228 00229 // floating points 00230 void test4() 00231 { 00232 session sql(backEnd, connectString); 00233 00234 try 00235 { 00236 sql << "drop table test4"; 00237 } 00238 catch (soci_error const &) 00239 {} // ignore if error 00240 00241 sql << "create table test4 (p1 numeric(8,2), " 00242 << "p2 decimal(14,8), p3 double precision, p4 integer)"; 00243 sql.commit(); 00244 00245 sql.begin(); 00246 00247 double d1 = 1234.23, d2 = 1e8, d3 = 1.0/1440.0, 00248 d4, d5, d6; 00249 00250 sql << "insert into test4(p1, p2, p3) values (?,?,?)", 00251 use(d1), use(d2), use(d3); 00252 00253 sql << "select p1, p2, p3 from test4", 00254 into(d4), into(d5), into(d6); 00255 00256 assert(d1 == d4 && d2 == d5 && d3 == d6); 00257 00258 // verify an exception is thrown when fetching non-integral value 00259 // to integral variable 00260 try 00261 { 00262 int i; 00263 sql << "select p1 from test4", into(i); 00264 00265 // expecting error 00266 assert(false); 00267 } 00268 catch (soci_error const &e) 00269 { 00270 std::string error = e.what(); 00271 assert(error == 00272 "Can't convert value with scale 2 to integral type"); 00273 } 00274 00275 // verify an exception is thrown when inserting non-integral value 00276 // to integral column 00277 try 00278 { 00279 sql << "insert into test4(p4) values(?)", use(d1); 00280 00281 // expecting error 00282 assert(false); 00283 } 00284 catch (soci_error const &e) 00285 { 00286 std::string error = e.what(); 00287 assert(error == 00288 "Can't convert non-integral value to integral column type"); 00289 } 00290 00291 sql << "drop table test4"; 00292 std::cout << "test 4 passed" << std::endl; 00293 } 00294 00295 // integer types and indicators 00296 void test5() 00297 { 00298 session sql(backEnd, connectString); 00299 00300 { 00301 short sh(0); 00302 sql << "select 3 from rdb$database", into(sh); 00303 assert(sh == 3); 00304 } 00305 00306 { 00307 int i(0); 00308 sql << "select 5 from rdb$database", into(i); 00309 assert(i == 5); 00310 } 00311 00312 { 00313 unsigned long ul(0); 00314 sql << "select 7 from rdb$database", into(ul); 00315 assert(ul == 7); 00316 } 00317 00318 { 00319 // test indicators 00320 indicator ind; 00321 int i; 00322 00323 sql << "select 2 from rdb$database", into(i, ind); 00324 assert(ind == i_ok); 00325 00326 sql << "select NULL from rdb$database", into(i, ind); 00327 assert(ind == i_null); 00328 00329 std::string buf; 00330 sql << "select \'Hello\' from rdb$database", into(buf, ind); 00331 assert(ind == i_truncated); 00332 00333 sql << "select 5 from rdb$database where 0 = 1", into(i, ind); 00334 assert(sql.got_data() == false); 00335 00336 try 00337 { 00338 // expect error 00339 sql << "select NULL from rdb$database", into(i); 00340 assert(false); 00341 } 00342 catch (soci_error const &e) 00343 { 00344 std::string error = e.what(); 00345 assert(error == 00346 "Null value fetched and no indicator defined."); 00347 } 00348 00349 try 00350 { 00351 // expect error 00352 sql << "select 5 from rdb$database where 0 = 1", into(i); 00353 assert(false); 00354 } 00355 catch (soci_error const &e) 00356 { 00357 std::string error = e.what(); 00358 assert(error == 00359 "No data fetched and no indicator defined."); 00360 } 00361 } 00362 00363 std::cout << "test 5 passed" << std::endl; 00364 } 00365 00366 // repeated fetch and bulk operations for character types 00367 void test6() 00368 { 00369 session sql(backEnd, connectString); 00370 00371 try 00372 { 00373 sql << "drop table test6"; 00374 } 00375 catch (soci_error const &) 00376 {} // ignore if error 00377 00378 sql << "create table test6 (p1 char(10), p2 varchar(10))"; 00379 sql.commit(); 00380 00381 sql.begin(); 00382 00383 for (char c = 'a'; c <= 'z'; ++c) 00384 { 00385 sql << "insert into test6(p1, p2) values(?,?)", use(c), use(c); 00386 } 00387 00388 { 00389 char c='a', c1, c2; 00390 00391 statement st = (sql.prepare << 00392 "select p1,p2 from test6 order by p1", into(c1), into(c2)); 00393 00394 st.execute(); 00395 while (st.fetch()) 00396 { 00397 assert(c == c1 && c == c2); 00398 ++c; 00399 } 00400 assert(c == 'z'+1); 00401 } 00402 00403 { 00404 char c='a'; 00405 00406 std::vector<char> c1(10), c2(10); 00407 00408 statement st = (sql.prepare << 00409 "select p1,p2 from test6 order by p1", into(c1), into(c2)); 00410 00411 st.execute(); 00412 while (st.fetch()) 00413 { 00414 for (std::size_t i = 0; i != c1.size(); ++i) 00415 { 00416 assert(c == c1[i] && c == c2[i]); 00417 ++c; 00418 } 00419 } 00420 assert(c == 'z' + 1); 00421 } 00422 00423 { 00424 // verify an exception is thrown when empty vector is used 00425 std::vector<char> vec; 00426 try 00427 { 00428 sql << "select p1 from test6", into(vec); 00429 assert(false); 00430 } 00431 catch (soci_error const &e) 00432 { 00433 std::string msg = e.what(); 00434 assert(msg == "Vectors of size 0 are not allowed."); 00435 } 00436 } 00437 00438 sql << "delete from test6"; 00439 00440 // verifying std::string 00441 int const rowsToTest = 10; 00442 for (int i = 0; i != rowsToTest; ++i) 00443 { 00444 std::ostringstream ss; 00445 ss << "Hello_" << i; 00446 00447 std::string const &x = ss.str(); 00448 00449 sql << "insert into test6(p1, p2) values(\'" 00450 << x << "\', \'" << x << "\')"; 00451 } 00452 00453 int count; 00454 sql << "select count(*) from test6", into(count); 00455 assert(count == rowsToTest); 00456 00457 { 00458 int i = 0; 00459 std::string s1, s2; 00460 statement st = (sql.prepare << 00461 "select p1, p2 from test6 order by p1", into(s1), into(s2)); 00462 00463 st.execute(); 00464 while (st.fetch()) 00465 { 00466 std::ostringstream ss; 00467 ss << "Hello_" << i; 00468 std::string const &x = ss.str(); 00469 00470 // Note: CHAR fields are always padded with whitespaces 00471 ss << " "; 00472 assert(s1 == ss.str() && s2 == x); 00473 ++i; 00474 } 00475 assert(i == rowsToTest); 00476 } 00477 00478 { 00479 int i = 0; 00480 00481 std::vector<std::string> s1(4), s2(4); 00482 statement st = (sql.prepare << 00483 "select p1, p2 from test6 order by p1", into(s1), into(s2)); 00484 st.execute(); 00485 while (st.fetch()) 00486 { 00487 for (std::size_t j = 0; j != s1.size(); ++j) 00488 { 00489 std::ostringstream ss; 00490 ss << "Hello_" << i; 00491 std::string const &x = ss.str(); 00492 00493 // Note: CHAR fields are always padded with whitespaces 00494 ss << " "; 00495 assert(ss.str() == s1[j] && x == s2[j]); 00496 ++i; 00497 } 00498 } 00499 assert(i == rowsToTest); 00500 } 00501 00502 sql << "drop table test6"; 00503 std::cout << "test 6 passed" << std::endl; 00504 } 00505 00506 // blob test 00507 void test7() 00508 { 00509 session sql(backEnd, connectString); 00510 00511 try 00512 { 00513 sql << "drop table test7"; 00514 } 00515 catch (std::runtime_error &) 00516 {} // ignore if error 00517 00518 sql << "create table test7(id integer, img blob)"; 00519 sql.commit(); 00520 00521 sql.begin(); 00522 { 00523 // verify empty blob 00524 blob b(sql); 00525 indicator ind; 00526 00527 sql << "insert into test7(id, img) values(1,?)", use(b); 00528 sql << "select img from test7 where id = 1", into(b, ind); 00529 00530 assert(ind == i_ok); 00531 assert(b.get_len() == 0); 00532 00533 sql << "delete from test7"; 00534 } 00535 00536 { 00537 // create a new blob 00538 blob b(sql); 00539 00540 char str1[] = "Hello"; 00541 b.write(0, str1, strlen(str1)); 00542 00543 char str2[20]; 00544 std::size_t i = b.read(3, str2, 2); 00545 str2[i] = '\0'; 00546 assert(str2[0] == 'l' && str2[1] == 'o' && str2[2] == '\0'); 00547 00548 char str3[] = ", Firebird!"; 00549 b.append(str3, strlen(str3)); 00550 00551 sql << "insert into test7(id, img) values(1,?)", use(b); 00552 } 00553 00554 { 00555 // read & update blob 00556 blob b(sql); 00557 00558 sql << "select img from test7 where id = 1", into(b); 00559 00560 std::vector<char> text(b.get_len()); 00561 b.read(0, &text[0], b.get_len()); 00562 assert(strncmp(&text[0], "Hello, Firebird!", b.get_len()) == 0); 00563 00564 char str1[] = "FIREBIRD"; 00565 b.write(7, str1, strlen(str1)); 00566 00567 // after modification blob must be written to database 00568 sql << "update test7 set img=? where id=1", use(b); 00569 } 00570 00571 { 00572 // read blob from database, modify and write to another record 00573 blob b(sql); 00574 00575 sql << "select img from test7 where id = 1", into(b); 00576 00577 std::vector<char> text(b.get_len()); 00578 b.read(0, &text[0], b.get_len()); 00579 00580 char str1[] = "HELLO"; 00581 b.write(0, str1, strlen(str1)); 00582 00583 b.read(0, &text[0], b.get_len()); 00584 assert(strncmp(&text[0], "HELLO, FIREBIRD!", b.get_len()) == 0); 00585 00586 b.trim(5); 00587 sql << "insert into test7(id, img) values(2,?)", use(b); 00588 } 00589 00590 { 00591 blob b(sql); 00592 statement st = (sql.prepare << "select img from test7", into(b)); 00593 00594 st.execute(); 00595 00596 st.fetch(); 00597 std::vector<char> text(b.get_len()); 00598 b.read(0, &text[0], b.get_len()); 00599 assert(strncmp(&text[0], "Hello, FIREBIRD!", b.get_len()) == 0); 00600 00601 st.fetch(); 00602 text.resize(b.get_len()); 00603 b.read(0, &text[0], b.get_len()); 00604 assert(strncmp(&text[0], "HELLO", b.get_len()) == 0); 00605 } 00606 00607 { 00608 // delete blob 00609 blob b(sql); 00610 indicator ind=i_null; 00611 sql << "update test7 set img=? where id = 1", use(b, ind); 00612 00613 sql << "select img from test7 where id = 2", into(b, ind); 00614 assert(ind==i_ok); 00615 00616 sql << "select img from test7 where id = 1", into(b, ind); 00617 assert(ind==i_null); 00618 } 00619 00620 sql << "drop table test7"; 00621 std::cout << "test 7 passed" << std::endl; 00622 } 00623 00624 // named parameters 00625 void test8() 00626 { 00627 session sql(backEnd, connectString); 00628 00629 try 00630 { 00631 sql << "drop table test8"; 00632 } 00633 catch (std::runtime_error &) 00634 {} // ignore if error 00635 00636 sql << "create table test8(id1 integer, id2 integer)"; 00637 sql.commit(); 00638 00639 sql.begin(); 00640 00641 int j = 13, k = 4, i, m; 00642 sql << "insert into test8(id1, id2) values(:id1, :id2)", 00643 use(k, "id2"), use(j, "id1"); 00644 sql << "select id1, id2 from test8", into(i), into(m); 00645 assert(i == j && m == k); 00646 00647 sql << "delete from test8"; 00648 00649 std::vector<int> in1(3), in2(3); 00650 in1[0] = 3; 00651 in1[1] = 2; 00652 in1[2] = 1; 00653 in2[0] = 4; 00654 in2[1] = 5; 00655 in2[2] = 6; 00656 00657 { 00658 statement st = (sql.prepare << 00659 "insert into test8(id1, id2) values(:id1, :id2)", 00660 use(k, "id2"), use(j, "id1")); 00661 00662 std::size_t s = in1.size(); 00663 for (std::size_t x = 0; x < s; ++x) 00664 { 00665 j = in1[x]; 00666 k = in2[x]; 00667 st.execute(); 00668 } 00669 } 00670 00671 { 00672 statement st = ( 00673 sql.prepare << "select id1, id2 from test8", into(i), into(m)); 00674 st.execute(); 00675 00676 std::size_t x(0); 00677 while (st.fetch()) 00678 { 00679 assert(i = in1[x] && m == in2[x]); 00680 ++x; 00681 } 00682 } 00683 00684 sql << "delete from test8"; 00685 00686 // test vectors 00687 sql << "insert into test8(id1, id2) values(:id1, :id2)", 00688 use(in1, "id1"), use(in2, "id2"); 00689 00690 std::vector<int> out1(3), out2(3); 00691 00692 sql << "select id1, id2 from test8", into(out1), into(out2); 00693 std::size_t s = out1.size(); 00694 assert(s == 3); 00695 00696 for (std::size_t x = 0; x<s; ++x) 00697 { 00698 assert(out1[x] == in1[x] && out2[x] == in2[x]); 00699 } 00700 00701 sql << "drop table test8"; 00702 std::cout << "test 8 passed" << std::endl; 00703 } 00704 00705 // Dynamic binding to row objects 00706 void test9() 00707 { 00708 session sql(backEnd, connectString); 00709 00710 try 00711 { 00712 sql << "drop table test9"; 00713 } 00714 catch (std::runtime_error &) 00715 {} // ignore if error 00716 00717 sql << "create table test9(id integer, msg varchar(20), ntest numeric(10,2))"; 00718 sql.commit(); 00719 00720 sql.begin(); 00721 00722 { 00723 row r; 00724 sql << "select * from test9", into(r); 00725 assert(sql.got_data() == false); 00726 } 00727 00728 std::string msg("Hello"); 00729 int i(1); 00730 double d(3.14); 00731 indicator ind(i_ok); 00732 00733 { 00734 statement st((sql.prepare << "insert into test9(id, msg, ntest) " 00735 << "values(:id,:msg,:ntest)", 00736 use(i, "id"), use(msg, "msg"), use(d, ind, "ntest"))); 00737 00738 st.execute(1); 00739 00740 i = 2; 00741 msg = "Firebird"; 00742 ind = i_null; 00743 st.execute(1); 00744 } 00745 00746 row r; 00747 statement st = (sql.prepare << 00748 "select * from test9", into(r)); 00749 st.execute(1); 00750 00751 assert(r.size() == 3); 00752 00753 // get properties by position 00754 assert(r.get_properties(0).get_name() == "ID"); 00755 assert(r.get_properties(1).get_name() == "MSG"); 00756 assert(r.get_properties(2).get_name() == "NTEST"); 00757 00758 assert(r.get_properties(0).get_data_type() == dt_integer); 00759 assert(r.get_properties(1).get_data_type() == dt_string); 00760 assert(r.get_properties(2).get_data_type() == dt_double); 00761 00762 // get properties by name 00763 assert(r.get_properties("ID").get_name() == "ID"); 00764 assert(r.get_properties("MSG").get_name() == "MSG"); 00765 assert(r.get_properties("NTEST").get_name() == "NTEST"); 00766 00767 assert(r.get_properties("ID").get_data_type() == dt_integer); 00768 assert(r.get_properties("MSG").get_data_type() == dt_string); 00769 assert(r.get_properties("NTEST").get_data_type() == dt_double); 00770 00771 // get values by position 00772 assert(r.get<int>(0) == 1); 00773 assert(r.get<std::string>(1) == "Hello"); 00774 assert(r.get<double>(2) == d); 00775 00776 // get values by name 00777 assert(r.get<int>("ID") == 1); 00778 assert(r.get<std::string>("MSG") == "Hello"); 00779 assert(r.get<double>("NTEST") == d); 00780 00781 st.fetch(); 00782 assert(r.get<int>(0) == 2); 00783 assert(r.get<std::string>("MSG") == "Firebird"); 00784 assert(r.get_indicator(2) == i_null); 00785 00786 // verify default values 00787 assert(r.get<double>("NTEST", 2) == 2); 00788 bool caught = false; 00789 try 00790 { 00791 double d1 = r.get<double>("NTEST"); 00792 std::cout << d1 << std::endl; // just for compiler 00793 } 00794 catch (soci_error&) 00795 { 00796 caught = true; 00797 } 00798 assert(caught); 00799 00800 // verify exception thrown on invalid get<> 00801 caught = false; 00802 try 00803 { 00804 r.get<std::string>(0); 00805 } 00806 catch (std::bad_cast const &) 00807 { 00808 caught = true; 00809 } 00810 assert(caught); 00811 00812 sql << "drop table test9"; 00813 std::cout << "test 9 passed" << std::endl; 00814 } 00815 00816 // stored procedures 00817 void test10() 00818 { 00819 session sql(backEnd, connectString); 00820 00821 try 00822 { 00823 sql << "drop procedure sp_test10"; 00824 } 00825 catch (std::runtime_error &) 00826 {} // ignore if error 00827 00828 try 00829 { 00830 sql << "drop procedure sp_test10a"; 00831 } 00832 catch (std::runtime_error &) 00833 {} // ignore if error 00834 00835 try 00836 { 00837 sql << "drop table test10"; 00838 } 00839 catch (std::runtime_error &) 00840 {} // ignore if error 00841 00842 sql << "create table test10(id integer, id2 integer)"; 00843 00844 sql << "create procedure sp_test10\n" 00845 << "returns (rid integer, rid2 integer)\n" 00846 << "as begin\n" 00847 << "for select id, id2 from test10 into rid, rid2 do begin\n" 00848 << "suspend;\n" 00849 << "end\n" 00850 << "end;\n"; 00851 00852 sql << "create procedure sp_test10a (pid integer, pid2 integer)\n" 00853 << "as begin\n" 00854 << "insert into test10(id, id2) values (:pid, :pid2);\n" 00855 << "end;\n"; 00856 00857 sql.commit(); 00858 00859 sql.begin(); 00860 00861 row r; 00862 int p1 = 3, p2 = 4; 00863 00864 // calling procedures that do not return values requires 00865 // 'execute procedure ...' statement 00866 sql << "execute procedure sp_test10a ?, ?", use(p1), use(p2); 00867 00868 // calling procedures that return values requires 00869 // 'select ... from ...' statement 00870 sql << "select * from sp_test10", into(r); 00871 00872 assert(r.get<int>(0) == p1 && r.get<int>(1) == p2); 00873 00874 sql << "delete from test10"; 00875 00876 p1 = 5; 00877 p2 = 6; 00878 { 00879 procedure proc = ( 00880 sql.prepare << "sp_test10a :p1, :p2", 00881 use(p2, "p2"), use(p1, "p1")); 00882 proc.execute(1); 00883 } 00884 00885 { 00886 row rw; 00887 procedure proc = (sql.prepare << "sp_test10", into(rw)); 00888 proc.execute(1); 00889 00890 assert(rw.get<int>(0) == p1 && rw.get<int>(1) == p2); 00891 } 00892 00893 sql << "delete from test10"; 00894 00895 // test vectors 00896 std::vector<int> in1(3), in2(3); 00897 in1[0] = 3; 00898 in1[1] = 2; 00899 in1[2] = 1; 00900 in2[0] = 4; 00901 in2[1] = 5; 00902 in2[2] = 6; 00903 00904 { 00905 procedure proc = ( 00906 sql.prepare << "sp_test10a :p1, :p2", 00907 use(in2, "p2"), use(in1, "p1")); 00908 proc.execute(1); 00909 } 00910 00911 { 00912 row rw; 00913 procedure proc = (sql.prepare << "sp_test10", into(rw)); 00914 00915 proc.execute(1); 00916 assert(rw.get<int>(0) == in1[0] && rw.get<int>(1) == in2[0]); 00917 proc.fetch(); 00918 assert(rw.get<int>(0) == in1[1] && rw.get<int>(1) == in2[1]); 00919 proc.fetch(); 00920 assert(rw.get<int>(0) == in1[2] && rw.get<int>(1) == in2[2]); 00921 assert(proc.fetch() == false); 00922 } 00923 00924 { 00925 std::vector<int> out1(3), out2(3); 00926 procedure proc = (sql.prepare << "sp_test10", into(out1), into(out2)); 00927 proc.execute(1); 00928 00929 std::size_t s = out1.size(); 00930 assert(s == 3); 00931 00932 for (std::size_t x = 0; x < s; ++x) 00933 { 00934 assert(out1[x] == in1[x] && out2[x] == in2[x]); 00935 } 00936 } 00937 00938 sql.rollback(); 00939 00940 sql.begin(); 00941 sql << "drop procedure sp_test10"; 00942 sql << "drop procedure sp_test10a"; 00943 sql << "drop table test10"; 00944 00945 std::cout << "test 10 passed" << std::endl; 00946 } 00947 00948 // direct access to Firebird using handles exposed by 00949 // soci::FirebirdStatmentBackend 00950 namespace soci 00951 { 00952 enum eRowCountType 00953 { 00954 eRowsSelected = isc_info_req_select_count, 00955 eRowsInserted = isc_info_req_insert_count, 00956 eRowsUpdated = isc_info_req_update_count, 00957 eRowsDeleted = isc_info_req_delete_count 00958 }; 00959 00960 // Returns number of rows afected by last statement 00961 // or -1 if there is no such counter available. 00962 long getRowCount(soci::statement & statement, eRowCountType type) 00963 { 00964 ISC_STATUS stat[20]; 00965 char cnt_req[2], cnt_info[128]; 00966 00967 cnt_req[0]=isc_info_sql_records; 00968 cnt_req[1]=isc_info_end; 00969 00970 firebird_statement_backend* statementBackEnd 00971 = static_cast<firebird_statement_backend*>(statement.get_backend()); 00972 00973 // Note: This is very poorly documented function. 00974 // It can extract number of rows returned by select statement, 00975 // but it appears that this is only number of rows prefetched by 00976 // client library, not total number of selected rows. 00977 if (isc_dsql_sql_info(stat, &statementBackEnd->stmtp_, sizeof(cnt_req), 00978 cnt_req, sizeof(cnt_info), cnt_info)) 00979 { 00980 soci::details::firebird::throw_iscerror(stat); 00981 } 00982 00983 long count = -1; 00984 char type_ = static_cast<char>(type); 00985 for (char *ptr = cnt_info + 3; *ptr != isc_info_end;) 00986 { 00987 char count_type = *ptr++; 00988 int m = isc_vax_integer(ptr, 2); 00989 ptr += 2; 00990 count = isc_vax_integer(ptr, m); 00991 00992 if (count_type == type_) 00993 { 00994 // this is requested number 00995 break; 00996 } 00997 ptr += m; 00998 } 00999 01000 return count; 01001 } 01002 01003 } // namespace soci 01004 01005 void test11() 01006 { 01007 session sql(backEnd, connectString); 01008 01009 try 01010 { 01011 sql << "drop table test11"; 01012 } 01013 catch (std::runtime_error &) 01014 {} // ignore if error 01015 01016 sql << "create table test11(id integer)"; 01017 sql.commit(); 01018 01019 sql.begin(); 01020 01021 { 01022 std::vector<int> in(3); 01023 in[0] = 3; 01024 in[1] = 2; 01025 in[2] = 1; 01026 01027 statement st = (sql.prepare << "insert into test11(id) values(?)", 01028 use(in)); 01029 st.execute(1); 01030 01031 // Note: Firebird backend inserts every row with separate insert 01032 // statement to achieve the effect of inserting vectors of values. 01033 // Since getRowCount() returns number of rows affected by the *last* 01034 // statement, it will return 1 here. 01035 assert(getRowCount(st, eRowsInserted) == 1); 01036 } 01037 01038 { 01039 int i = 5; 01040 statement st = (sql.prepare << "update test11 set id = ? where id<3", 01041 use(i)); 01042 st.execute(1); 01043 assert(getRowCount(st, eRowsUpdated) == 2); 01044 01045 // verify that no rows were deleted 01046 assert(getRowCount(st, eRowsDeleted) == 0); 01047 } 01048 01049 { 01050 std::vector<int> out(3); 01051 statement st = (sql.prepare << "select id from test11", into(out)); 01052 st.execute(1); 01053 01054 assert(getRowCount(st, eRowsSelected) == 3); 01055 } 01056 01057 { 01058 statement st = (sql.prepare << "delete from test11 where id=10"); 01059 st.execute(1); 01060 assert(getRowCount(st, eRowsDeleted) == 0); 01061 } 01062 01063 { 01064 statement st = (sql.prepare << "delete from test11"); 01065 st.execute(1); 01066 assert(getRowCount(st, eRowsDeleted) == 3); 01067 } 01068 01069 sql << "drop table test11"; 01070 std::cout << "test 11 passed" << std::endl; 01071 } 01072 01073 // 01074 // Support for soci Common Tests 01075 // 01076 01077 struct table_creator_one : public tests::table_creator_base 01078 { 01079 table_creator_one(session & sql) 01080 : tests::table_creator_base(sql) 01081 { 01082 sql << "create table soci_test(id integer, val integer, c char, " 01083 "str varchar(20), sh smallint, ul decimal(9,0), d double precision, " 01084 "tm timestamp, i1 integer, i2 integer, i3 integer, name varchar(20))"; 01085 sql.commit(); 01086 sql.begin(); 01087 } 01088 }; 01089 01090 struct table_creator_two : public tests::table_creator_base 01091 { 01092 table_creator_two(session & sql) 01093 : tests::table_creator_base(sql) 01094 { 01095 sql << "create table soci_test(\"num_float\" float, \"num_int\" integer, " 01096 "\"name\" varchar(20), \"sometime\" timestamp, \"chr\" char)"; 01097 sql.commit(); 01098 sql.begin(); 01099 } 01100 }; 01101 01102 struct table_creator_three : public tests::table_creator_base 01103 { 01104 table_creator_three(session & sql) 01105 : tests::table_creator_base(sql) 01106 { 01107 // CommonTest uses lower-case column names, 01108 // so we need to enforce such names here. 01109 // That's why column names are enclosed in "" 01110 sql << "create table soci_test(\"name\" varchar(100) not null, " 01111 "\"phone\" varchar(15))"; 01112 sql.commit(); 01113 sql.begin(); 01114 } 01115 }; 01116 01117 class test_context : public tests::test_context_base 01118 { 01119 public: 01120 test_context(backend_factory const &backEnd, 01121 std::string const &connectString) 01122 : test_context_base(backEnd, connectString) 01123 {} 01124 01125 tests::table_creator_base* table_creator_1(session& s) const 01126 { 01127 return new table_creator_one(s); 01128 } 01129 01130 tests::table_creator_base* table_creator_2(session& s) const 01131 { 01132 return new table_creator_two(s); 01133 } 01134 01135 tests::table_creator_base* table_creator_3(session& s) const 01136 { 01137 return new table_creator_three(s); 01138 } 01139 01140 std::string to_date_time(std::string const &datdt_string) const 01141 { 01142 return "'" + datdt_string + "'"; 01143 } 01144 }; 01145 01146 01147 int main(int argc, char** argv) 01148 { 01149 01150 #ifdef _MSC_VER 01151 // Redirect errors, unrecoverable problems, and assert() failures to STDERR, 01152 // instead of debug message window. 01153 // This hack is required to run asser()-driven tests by Buildbot. 01154 // NOTE: Comment this 2 lines for debugging with Visual C++ debugger to catch assertions inside. 01155 _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE); 01156 _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR); 01157 #endif //_MSC_VER 01158 01159 if (argc == 2) 01160 { 01161 connectString = argv[1]; 01162 } 01163 else 01164 { 01165 std::ostringstream msg; 01166 msg << "usage: " << argv[0] 01167 << " connectstring\n" 01168 << "example: " << argv[0] 01169 << " \"service=/usr/local/firebird/db/test.fdb user=SYSDBA password=masterkey\"\n"; 01170 01171 std::cout << msg.str().c_str(); 01172 std::exit(1); 01173 } 01174 01175 try 01176 { 01177 test_context tc(backEnd, connectString); 01178 tests::common_tests tests(tc); 01179 tests.run(); 01180 01181 test1(); 01182 test2(); 01183 test3(); 01184 test4(); 01185 test5(); 01186 test6(); 01187 test7(); 01188 test8(); 01189 test9(); 01190 test10(); 01191 test11(); 01192 01193 std::cout << "\nOK, all tests passed.\n\n"; 01194 } 01195 catch (std::exception const & e) 01196 { 01197 std::cout << e.what() << '\n'; 01198 } 01199 }
Generated on Sun Oct 3 2010 17:42:16 for EXTRAS-SOCI by Doxygen 1.7.1