SOCI Logo Get SOCI at SourceForge.net. Fast, secure and Free Open Source software downloads

test-firebird.cpp

Go to the documentation of this file.
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
SourceForge Logo

Generated on Sun Oct 3 2010 17:42:16 for EXTRAS-SOCI by Doxygen 1.7.1