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

test-oracle.cpp

Go to the documentation of this file.
00001 //
00002 // // Copyright (C) 2004-2007 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/oracle/soci-oracle.h>
00012 #       include <soci/core/test/common-tests.h>
00013 #else
00014 #       include <soci.h>
00015 #       include <soci-oracle.h>
00016 #       include <test/common-tests.h>
00017 #endif
00018 //
00019 #include <iostream>
00020 #include <string>
00021 #include <cassert>
00022 #include <ctime>
00023 #include <cstring>
00024 
00025 using namespace soci;
00026 using namespace soci::tests;
00027 
00028 std::string connectString;
00029 backend_factory const &backEnd = oracle;
00030 
00031 // Extra tests for date/time
00032 void test1()
00033 {
00034     session sql(backEnd, connectString);
00035 
00036     {
00037         std::time_t now = std::time(NULL);
00038         std::tm t1, t2;
00039         t2 = *std::localtime(&now);
00040 
00041         sql << "select t from (select :t as t from dual)",
00042             into(t1), use(t2);
00043         assert(memcmp(&t1, &t2, sizeof(std::tm)) == 0);
00044 
00045         // make sure the date is stored properly in Oracle
00046         char buf[25];
00047         strftime(buf, sizeof(buf), "%m-%d-%Y %H:%M:%S", &t2);
00048 
00049         std::string t_out;
00050         std::string format("MM-DD-YYYY HH24:MI:SS");
00051         sql << "select to_char(t, :format) from (select :t as t from dual)",
00052             into(t_out), use(format), use(t2);
00053 
00054         assert(t_out == std::string(buf));
00055     }
00056 
00057     {
00058         // date and time - before year 2000
00059         std::time_t then = std::time(NULL) - 17*365*24*60*60;
00060         std::tm t1, t2;
00061         t2 = *std::localtime(&then);
00062 
00063         sql << "select t from (select :t as t from dual)",
00064              into(t1), use(t2);
00065 
00066         assert(memcmp(&t1, &t2, sizeof(std::tm)) == 0);
00067 
00068         // make sure the date is stored properly in Oracle
00069         char buf[25];
00070         strftime(buf, sizeof(buf), "%m-%d-%Y %H:%M:%S", &t2);
00071 
00072         std::string t_out;
00073         std::string format("MM-DD-YYYY HH24:MI:SS");
00074         sql << "select to_char(t, :format) from (select :t as t from dual)",
00075             into(t_out), use(format), use(t2);
00076 
00077         assert(t_out == std::string(buf));
00078     }
00079 
00080     std::cout << "test 1 passed" << std::endl;
00081 }
00082 
00083 // explicit calls test
00084 void test2()
00085 {
00086     session sql(backEnd, connectString);
00087 
00088     statement st(sql);
00089     st.alloc();
00090     int i = 0;
00091     st.exchange(into(i));
00092     st.prepare("select 7 from dual");
00093     st.define_and_bind();
00094     st.execute(1);
00095     assert(i == 7);
00096 
00097     std::cout << "test 2 passed" << std::endl;
00098 }
00099 
00100 // DDL + blob test
00101 
00102 struct blob_table_creator : public table_creator_base
00103 {
00104     blob_table_creator(session & sql)
00105     : table_creator_base(sql)
00106     {
00107         sql <<
00108             "create table soci_test ("
00109             "    id number(10) not null,"
00110             "    img blob"
00111             ")";
00112     }
00113 };
00114 
00115 void test3()
00116 {
00117     session sql(backEnd, connectString);
00118     
00119     blob_table_creator tableCreator(sql);
00120 
00121     char buf[] = "abcdefghijklmnopqrstuvwxyz";
00122     sql << "insert into soci_test (id, img) values (7, empty_blob())";
00123 
00124     {
00125         blob b(sql);
00126 
00127         oracle_session_backend *sessionBackEnd
00128             = static_cast<oracle_session_backend *>(sql.get_backend());
00129 
00130         oracle_blob_backend *blobBackEnd
00131             = static_cast<oracle_blob_backend *>(b.get_backend());
00132 
00133         OCILobDisableBuffering(sessionBackEnd->svchp_,
00134             sessionBackEnd->errhp_, blobBackEnd->lobp_);
00135 
00136         sql << "select img from soci_test where id = 7", into(b);
00137         assert(b.get_len() == 0);
00138 
00139         // note: blob offsets start from 1
00140         b.write(1, buf, sizeof(buf));
00141         assert(b.get_len() == sizeof(buf));
00142         b.trim(10);
00143         assert(b.get_len() == 10);
00144 
00145         // append does not work (Oracle bug #886191 ?)
00146         //b.append(buf, sizeof(buf));
00147         //assert(b.get_len() == sizeof(buf) + 10);
00148         sql.commit();
00149     }
00150 
00151     {
00152         blob b(sql);
00153         sql << "select img from soci_test where id = 7", into(b);
00154         //assert(b.get_len() == sizeof(buf) + 10);
00155         assert(b.get_len() == 10);
00156         char buf2[100];
00157         b.read(1, buf2, 10);
00158         assert(strncmp(buf2, "abcdefghij", 10) == 0);
00159     }
00160 
00161     std::cout << "test 3 passed" << std::endl;
00162 }
00163 
00164 // nested statement test
00165 // (the same syntax is used for output cursors in PL/SQL)
00166 
00167 struct basic_table_creator : public table_creator_base
00168 {
00169     basic_table_creator(session & sql)
00170         : table_creator_base(sql)
00171     {
00172         sql <<
00173                     "create table soci_test ("
00174                     "    id number(5) not null,"
00175                     "    name varchar2(100),"
00176                     "    code number(5)"
00177                     ")";
00178     }
00179 };
00180 
00181 void test4()
00182 {
00183     session sql(backEnd, connectString);
00184     basic_table_creator tableCreator(sql);
00185 
00186     int id;
00187     std::string name;
00188     {
00189         statement st1 = (sql.prepare <<
00190             "insert into soci_test (id, name) values (:id, :name)",
00191             use(id), use(name));
00192 
00193         id = 1; name = "John"; st1.execute(1);
00194         id = 2; name = "Anna"; st1.execute(1);
00195         id = 3; name = "Mike"; st1.execute(1);
00196     }
00197 
00198     statement stInner(sql);
00199     statement stOuter = (sql.prepare <<
00200         "select cursor(select name from soci_test order by id)"
00201         " from soci_test where id = 1",
00202         into(stInner));
00203     stInner.exchange(into(name));
00204     stOuter.execute();
00205     stOuter.fetch();
00206 
00207     std::vector<std::string> names;
00208     while (stInner.fetch())    { names.push_back(name); }
00209 
00210     assert(names.size() == 3);
00211     assert(names[0] == "John");
00212     assert(names[1] == "Anna");
00213     assert(names[2] == "Mike");
00214 
00215     std::cout << "test 4 passed" << std::endl;
00216 }
00217 
00218 
00219 // ROWID test
00220 void test5()
00221 {
00222     session sql(backEnd, connectString);
00223     basic_table_creator tableCreator(sql);
00224 
00225     sql << "insert into soci_test(id, name) values(7, \'John\')";
00226 
00227     rowid rid(sql);
00228     sql << "select rowid from soci_test where id = 7", into(rid);
00229 
00230     int id;
00231     std::string name;
00232     sql << "select id, name from soci_test where rowid = :rid",
00233         into(id), into(name), use(rid);
00234 
00235     assert(id == 7);
00236     assert(name == "John");
00237 
00238     std::cout << "test 5 passed" << std::endl;
00239 }
00240 
00241 // Stored procedures
00242 struct procedure_creator : procedure_creator_base
00243 {
00244     procedure_creator(session & sql)
00245         : procedure_creator_base(sql)
00246     {
00247         sql <<
00248              "create or replace procedure soci_test(output out varchar2,"
00249              "input in varchar2) as "
00250              "begin output := input; end;";
00251     }
00252 };
00253 
00254 void test6()
00255 {
00256     {
00257         session sql(backEnd, connectString);
00258         procedure_creator procedure_creator(sql);
00259 
00260         std::string in("my message");
00261         std::string out;
00262         statement st = (sql.prepare <<
00263             "begin soci_test(:output, :input); end;",
00264             use(out, "output"),
00265             use(in, "input"));
00266         st.execute(1);
00267         assert(out == in);
00268 
00269         // explicit procedure syntax
00270         {
00271             std::string in("my message2");
00272             std::string out;
00273             procedure proc = (sql.prepare <<
00274                 "soci_test(:output, :input)",
00275                 use(out, "output"), use(in, "input"));
00276             proc.execute(1);
00277             assert(out == in);
00278         }
00279     }
00280 
00281     std::cout << "test 6 passed" << std::endl;
00282 }
00283 
00284 // bind into user-defined objects
00285 struct string_holder
00286 {
00287     string_holder() {}
00288     string_holder(const char* s) : s_(s) {}
00289     string_holder(std::string s) : s_(s) {}
00290     std::string get() const { return s_; }
00291 private:
00292     std::string s_;
00293 };
00294 
00295 namespace soci
00296 {
00297     template <>
00298     struct type_conversion<string_holder>
00299     {
00300         typedef std::string base_type;
00301         static void from_base(const std::string &s, indicator /* ind */,
00302             string_holder &sh)
00303         {
00304             sh = string_holder(s);
00305         }
00306 
00307         static void to_base(const string_holder &sh, std::string &s, indicator &ind)
00308         {
00309             s = sh.get();
00310             ind = i_ok;
00311         }
00312     };
00313 }
00314 
00315 struct in_out_procedure_creator : public procedure_creator_base
00316 {
00317     in_out_procedure_creator(session & sql)
00318         : procedure_creator_base(sql)
00319     {
00320         sql << "create or replace procedure soci_test(s in out varchar2)"
00321                 " as begin s := s || s; end;";
00322     }
00323 };
00324 
00325 struct returns_null_procedure_creator : public procedure_creator_base
00326 {
00327     returns_null_procedure_creator(session & sql)
00328         : procedure_creator_base(sql)
00329     {
00330         sql << "create or replace procedure soci_test(s in out varchar2)"
00331             " as begin s := NULL; end;";
00332     }
00333 };
00334 
00335 void test7()
00336 {
00337     session sql(backEnd, connectString);
00338     {
00339         basic_table_creator tableCreator(sql);
00340 
00341         int id(1);
00342         string_holder in("my string");
00343         sql << "insert into soci_test(id, name) values(:id, :name)", use(id), use(in);
00344 
00345         string_holder out;
00346         sql << "select name from soci_test", into(out);
00347         assert(out.get() == "my string");
00348 
00349         row r;
00350         sql << "select * from soci_test", into(r);
00351         string_holder dynamicOut = r.get<string_holder>(1);
00352         assert(dynamicOut.get() == "my string");
00353     }
00354 
00355     // test procedure with user-defined type as in-out parameter
00356     {
00357         in_out_procedure_creator procedureCreator(sql);
00358 
00359         string_holder sh("test");
00360         procedure proc = (sql.prepare << "soci_test(:s)", use(sh));
00361         proc.execute(1);
00362         assert(sh.get() == "testtest");
00363     }
00364 
00365     // test procedure which returns null
00366     {
00367          returns_null_procedure_creator procedureCreator(sql);
00368 
00369          string_holder sh;
00370          indicator ind = i_ok;
00371          procedure proc = (sql.prepare << "soci_test(:s)", use(sh, ind));
00372          proc.execute(1);
00373          assert(ind == i_null);
00374     }
00375 
00376     std::cout << "test 7 passed" << std::endl;
00377 }
00378 
00379 // test bulk insert features
00380 void test8()
00381 {
00382     session sql(backEnd, connectString);
00383 
00384     basic_table_creator tableCreator(sql);
00385 
00386     // verify exception is thrown if vectors of unequal size are passed in
00387     {
00388         std::vector<int> ids;
00389         ids.push_back(1);
00390         ids.push_back(2);
00391         std::vector<int> codes;
00392         codes.push_back(1);
00393         std::string error;
00394 
00395         try
00396         {
00397             sql << "insert into soci_test(id,code) values(:id,:code)",
00398                 use(ids), use(codes);
00399         }
00400         catch (soci_error const &e)
00401         {
00402             error = e.what();
00403         }
00404         assert(error.find("Bind variable size mismatch")
00405             != std::string::npos);
00406 
00407         try
00408         {
00409             sql << "select from soci_test", into(ids), into(codes);
00410         }
00411         catch (std::exception const &e)
00412         {
00413             error = e.what();
00414         }
00415         assert(error.find("Bind variable size mismatch")
00416             != std::string::npos);
00417     }
00418 
00419     // verify partial insert occurs when one of the records is bad
00420     {
00421         std::vector<int> ids;
00422         ids.push_back(100);
00423         ids.push_back(1000000); // too big for column
00424 
00425         std::string error;
00426         try
00427         {
00428             sql << "insert into soci_test (id) values(:id)", use(ids, "id");
00429         }
00430         catch (soci_error const &e)
00431         {
00432             error = e.what();
00433             //TODO e could be made to tell which row(s) failed
00434         }
00435         sql.commit();
00436         assert(error.find("ORA-01438") != std::string::npos);
00437         int count(7);
00438         sql << "select count(*) from soci_test", into(count);
00439         assert(count == 1);
00440         sql << "delete from soci_test";
00441     }
00442 
00443     // test insert
00444     {
00445         std::vector<int> ids;
00446         for (int i = 0; i != 3; ++i)
00447         {
00448             ids.push_back(i+10);
00449         }
00450 
00451         statement st = (sql.prepare << "insert into soci_test(id) values(:id)",
00452                             use(ids));
00453         st.execute(1);
00454         int count;
00455         sql << "select count(*) from soci_test", into(count);
00456         assert(count == 3);
00457     }
00458 
00459     //verify an exception is thrown if into vector is zero length
00460     {
00461         std::vector<int> ids;
00462         bool caught(false);
00463         try
00464         {
00465             sql << "select id from soci_test", into(ids);
00466         }
00467         catch (soci_error const &)
00468         {
00469             caught = true;
00470         }
00471         assert(caught);
00472     }
00473 
00474     // verify an exception is thrown if use vector is zero length
00475     {
00476         std::vector<int> ids;
00477         bool caught(false);
00478         try
00479         {
00480             sql << "insert into soci_test(id) values(:id)", use(ids);
00481         }
00482         catch (soci_error const &)
00483         {
00484             caught = true;
00485         }
00486         assert(caught);
00487     }
00488 
00489     // test "no data" condition
00490     {
00491         std::vector<indicator> inds(3);
00492         std::vector<int> ids_out(3);
00493         statement st = (sql.prepare << "select id from soci_test where 1=0",
00494                         into(ids_out, inds));
00495 
00496         // false return value means "no data"
00497         assert(st.execute(1) == false);
00498 
00499         // that's it - nothing else is guaranteed
00500         // and nothing else is to be tested here
00501     }
00502 
00503     // test NULL indicators
00504     {
00505         std::vector<int> ids(3);
00506         sql << "select id from soci_test", into(ids);
00507 
00508         std::vector<indicator> inds_in;
00509         inds_in.push_back(i_ok);
00510         inds_in.push_back(i_null);
00511         inds_in.push_back(i_ok);
00512 
00513         std::vector<int> new_codes;
00514         new_codes.push_back(10);
00515         new_codes.push_back(11);
00516         new_codes.push_back(10);
00517 
00518         sql << "update soci_test set code = :code where id = :id",
00519                 use(new_codes, inds_in), use(ids);
00520 
00521         std::vector<indicator> inds_out(3);
00522         std::vector<int> codes(3);
00523 
00524         sql << "select code from soci_test", into(codes, inds_out);
00525         assert(codes.size() == 3 && inds_out.size() == 3);
00526         assert(codes[0] == 10 && codes[2] == 10);
00527         assert(inds_out[0] == i_ok && inds_out[1] == i_null
00528             && inds_out[2] == i_ok);
00529     }
00530 
00531     // verify an exception is thrown if null is selected
00532     //  and no indicator was provided
00533     {
00534         std::string msg;
00535         std::vector<int> intos(3);
00536         try
00537         {
00538             sql << "select code from soci_test", into(intos);
00539         }
00540         catch (soci_error const &e)
00541         {
00542             msg = e.what();
00543         }
00544         assert(msg == "Null value fetched and no indicator defined." );
00545     }
00546 
00547     // test basic select
00548     {
00549         const size_t sz = 3;
00550         std::vector<indicator> inds(sz);
00551         std::vector<int> ids_out(sz);
00552         statement st = (sql.prepare << "select id from soci_test",
00553             into(ids_out, inds));
00554         const bool gotData = st.execute(true);
00555         assert(gotData);
00556         assert(ids_out.size() == sz);
00557         assert(ids_out[0] == 10);
00558         assert(ids_out[2] == 12);
00559         assert(inds.size() == 3 && inds[0] == i_ok
00560             && inds[1] == i_ok && inds[2] == i_ok);
00561     }
00562 
00563     // verify execute(0)
00564     {
00565         std::vector<int> ids_out(2);
00566         statement st = (sql.prepare << "select id from soci_test",
00567             into(ids_out));
00568 
00569         st.execute();
00570         assert(ids_out.size() == 2);
00571         bool gotData = st.fetch();
00572         assert(gotData);
00573         assert(ids_out.size() == 2 && ids_out[0] == 10 && ids_out[1] == 11);
00574         gotData = st.fetch();
00575         assert(gotData);
00576         assert(ids_out.size() == 1 && ids_out[0] == 12);
00577         gotData = st.fetch();
00578         assert(gotData == false);
00579     }
00580 
00581     // verify resizing happens if vector is larger
00582     // than number of rows returned
00583     {
00584         std::vector<int> ids_out(4); // one too many
00585         statement st2 = (sql.prepare << "select id from soci_test",
00586             into(ids_out));
00587         bool gotData = st2.execute(true);
00588         assert(gotData);
00589         assert(ids_out.size() == 3);
00590         assert(ids_out[0] == 10);
00591         assert(ids_out[2] == 12);
00592     }
00593 
00594     // verify resizing happens properly during fetch()
00595     {
00596         std::vector<int> more;
00597         more.push_back(13);
00598         more.push_back(14);
00599         sql << "insert into soci_test(id) values(:id)", use(more);
00600 
00601         std::vector<int> ids(2);
00602         statement st3 = (sql.prepare << "select id from soci_test", into(ids));
00603         bool gotData = st3.execute(true);
00604         assert(gotData);
00605         assert(ids[0] == 10);
00606         assert(ids[1] == 11);
00607 
00608         gotData = st3.fetch();
00609         assert(gotData);
00610         assert(ids[0] == 12);
00611         assert(ids[1] == 13);
00612 
00613         gotData = st3.fetch();
00614         assert(gotData);
00615         assert(ids.size() == 1);
00616         assert(ids[0] == 14);
00617 
00618         gotData = st3.fetch();
00619         assert(gotData == false);
00620     }
00621 
00622     std::cout << "test 8 passed" << std::endl;
00623 }
00624 
00625 // more tests for bulk fetch
00626 void test9()
00627 {
00628     session sql(backEnd, connectString);
00629 
00630     basic_table_creator tableCreator(sql);
00631 
00632     std::vector<int> in;
00633     for (int i = 1; i <= 10; ++i)
00634     {
00635         in.push_back(i);
00636     }
00637 
00638     sql << "insert into soci_test (id) values(:id)", use(in);
00639 
00640     int count(0);
00641     sql << "select count(*) from soci_test", into(count);
00642     assert(count == 10);
00643 
00644     // verify that the exception is thrown when trying to resize
00645     // the output vector to the size that is bigger than that
00646     // at the time of binding
00647     {
00648         std::vector<int> out(4);
00649         statement st = (sql.prepare <<
00650             "select id from soci_test", into(out));
00651 
00652         st.execute();
00653 
00654         st.fetch();
00655         assert(out.size() == 4);
00656         assert(out[0] == 1);
00657         assert(out[1] == 2);
00658         assert(out[2] == 3);
00659         assert(out[3] == 4);
00660         out.resize(5); // this should be detected as error
00661         try
00662         {
00663             st.fetch();
00664             assert(false); // should never reach here
00665         }
00666         catch (soci_error const &e)
00667         {
00668             assert(std::string(e.what()) ==
00669                 "Increasing the size of the output vector is not supported.");
00670         }
00671     }
00672 
00673     // on the other hand, downsizing is OK
00674     {
00675         std::vector<int> out(4);
00676         statement st = (sql.prepare <<
00677             "select id from soci_test", into(out));
00678 
00679         st.execute();
00680 
00681         st.fetch();
00682         assert(out.size() == 4);
00683         assert(out[0] == 1);
00684         assert(out[1] == 2);
00685         assert(out[2] == 3);
00686         assert(out[3] == 4);
00687         out.resize(3); // ok
00688         st.fetch();
00689         assert(out.size() == 3);
00690         assert(out[0] == 5);
00691         assert(out[1] == 6);
00692         assert(out[2] == 7);
00693         out.resize(4); // ok, not bigger than initially
00694         st.fetch();
00695         assert(out.size() == 3); // downsized because of end of data
00696         assert(out[0] == 8);
00697         assert(out[1] == 9);
00698         assert(out[2] == 10);
00699         bool gotData = st.fetch();
00700         assert(gotData == false); // end of data
00701     }
00702 
00703     std::cout << "test 9 passed" << std::endl;
00704 }
00705 
00706 struct person
00707 {
00708     int id;
00709     std::string firstName;
00710     string_holder lastName; //test mapping of type_conversion-based types
00711     std::string gender;
00712 };
00713 
00714 // Object-Relational Mapping
00715 // Note: Use the values class as shown below in type_conversions
00716 // to achieve object relational mapping.  The values class should
00717 // not be used directly in any other fashion.
00718 namespace soci
00719 {
00720     // name-based conversion
00721     template<> struct type_conversion<person>
00722     {
00723         typedef values base_type;
00724 
00725         static void from_base(values const &v, indicator /* ind */, person &p)
00726         {
00727             // ignoring possibility that the whole object might be NULL
00728 
00729             p.id = v.get<int>("ID");
00730             p.firstName = v.get<std::string>("FIRST_NAME");
00731             p.lastName = v.get<string_holder>("LAST_NAME");
00732             p.gender = v.get<std::string>("GENDER", "unknown");
00733         }
00734 
00735         static void to_base(person const & p, values & v, indicator & ind)
00736         {
00737             v.set("ID", p.id);
00738             v.set("FIRST_NAME", p.firstName);
00739             v.set("LAST_NAME", p.lastName);
00740             v.set("GENDER", p.gender, p.gender.empty() ? i_null : i_ok);
00741             ind = i_ok;
00742         }
00743     };
00744 }
00745 
00746 struct person_table_creator : public table_creator_base
00747 {
00748     person_table_creator(session & sql)
00749         : table_creator_base(sql)
00750     {
00751         sql << "create table soci_test(id numeric(5,0) NOT NULL,"
00752              << " last_name varchar2(20), first_name varchar2(20), "
00753                 " gender varchar2(10))";
00754     }
00755 };
00756 
00757 struct times100_procedure_creator : public procedure_creator_base
00758 {
00759     times100_procedure_creator(session & sql)
00760         : procedure_creator_base(sql)
00761     {
00762         sql << "create or replace procedure soci_test(id in out number)"
00763                " as begin id := id * 100; end;";
00764     }
00765 };
00766 
00767 void test10()
00768 {
00769     session sql(backEnd, connectString);
00770 
00771     {
00772         person_table_creator tableCreator(sql);
00773 
00774         person p;
00775         p.id = 1;
00776         p.lastName = "Smith";
00777         p.firstName = "Pat";
00778         sql << "insert into soci_test(id, first_name, last_name, gender) "
00779             << "values(:ID, :FIRST_NAME, :LAST_NAME, :GENDER)", use(p);
00780 
00781         // p should be unchanged
00782         assert(p.id == 1);
00783         assert(p.firstName == "Pat");
00784         assert(p.lastName.get() == "Smith");
00785 
00786         person p1;
00787         sql << "select * from soci_test", into(p1);
00788         assert(p1.id == 1);
00789         assert(p1.firstName + p1.lastName.get() == "PatSmith");
00790         assert(p1.gender == "unknown");
00791 
00792         p.firstName = "Patricia";
00793         sql << "update soci_test set first_name = :FIRST_NAME "
00794                "where id = :ID", use(p);
00795 
00796         // p should be unchanged
00797         assert(p.id == 1);
00798         assert(p.firstName == "Patricia");
00799         assert(p.lastName.get() == "Smith");
00800         // Note: gender is now "unknown" because of the mapping, not ""
00801         assert(p.gender == "unknown");
00802 
00803         person p2;
00804         sql << "select * from soci_test", into(p2);
00805         assert(p2.id == 1);
00806         assert(p2.firstName + p2.lastName.get() == "PatriciaSmith");
00807 
00808         // insert a second row so we can test fetching
00809         person p3;
00810         p3.id = 2;
00811         p3.firstName = "Joe";
00812         p3.lastName = "Smith";
00813         sql << "insert into soci_test(id, first_name, last_name, gender) "
00814             << "values(:ID, :FIRST_NAME, :LAST_NAME, :GENDER)", use(p3);
00815 
00816         person p4;
00817         statement st = (sql.prepare << "select * from soci_test order by id",
00818                     into(p4));
00819 
00820         st.execute();
00821         bool gotData = st.fetch();
00822         assert(gotData);
00823         assert(p4.id == 1);
00824         assert(p4.firstName == "Patricia");
00825 
00826         gotData = st.fetch();
00827         assert(gotData);
00828         assert(p4.id == 2);
00829         assert(p4.firstName == "Joe");
00830         gotData = st.fetch();
00831         assert(gotData == false);
00832     }
00833 
00834     // test with stored procedure
00835     {
00836         times100_procedure_creator procedureCreator(sql);
00837 
00838         person p;
00839         p.id = 1;
00840         p.firstName = "Pat";
00841         p.lastName = "Smith";
00842         procedure proc = (sql.prepare << "soci_test(:ID)", use(p));
00843         proc.execute(1);
00844         assert(p.id == 100);
00845         assert(p.firstName == "Pat");
00846         assert(p.lastName.get() == "Smith");
00847     }
00848 
00849     // test with stored procedure which returns null
00850     {
00851         returns_null_procedure_creator procedureCreator(sql);
00852 
00853         std::string msg;
00854         person p;
00855         try
00856         {
00857             procedure proc = (sql.prepare << "soci_test(:FIRST_NAME)",
00858                                 use(p));
00859             proc.execute(1);
00860         }
00861         catch (soci_error& e)
00862         {
00863             msg = e.what();
00864         }
00865         assert(msg == "Null value not allowed for this type");
00866 
00867         procedure proc = (sql.prepare << "soci_test(:GENDER)",
00868                                 use(p));
00869         proc.execute(1);
00870         assert(p.gender == "unknown");
00871 
00872     }
00873     std::cout << "test 10 passed" << std::endl;
00874 }
00875 
00876 // Experimental support for position based O/R Mapping
00877 
00878 // additional type for position-based test
00879 struct person2
00880 {
00881     int id;
00882     std::string firstName;
00883     std::string lastName;
00884     std::string gender;
00885 };
00886 
00887 // additional type for stream-like test
00888 struct person3 : person2 {};
00889 
00890 namespace soci
00891 {
00892     // position-based conversion
00893     template<> struct type_conversion<person2>
00894     {
00895         typedef values base_type;
00896 
00897         static void from_base(values const &v, indicator /* ind */, person2 &p)
00898         {
00899             p.id = v.get<int>(0);
00900             p.firstName = v.get<std::string>(1);
00901             p.lastName = v.get<std::string>(2);
00902             p.gender = v.get<std::string>(3, "whoknows");
00903         }
00904 
00905         // What about the "to" part? Does it make any sense to have it?
00906     };
00907 
00908     // stream-like conversion
00909     template<> struct type_conversion<person3>
00910     {
00911         typedef values base_type;
00912 
00913         static void from_base(values const &v, indicator /* ind */, person3 &p)
00914         {
00915             v >> p.id >> p.firstName >> p.lastName >> p.gender;
00916         }
00917         // TODO: The "to" part is certainly needed.
00918     };
00919 }
00920 
00921 void test11()
00922 {
00923     session sql(backEnd, connectString);
00924 
00925     person_table_creator tableCreator(sql);
00926 
00927     person p;
00928     p.id = 1;
00929     p.lastName = "Smith";
00930     p.firstName = "Patricia";
00931     sql << "insert into soci_test(id, first_name, last_name, gender) "
00932         << "values(:ID, :FIRST_NAME, :LAST_NAME, :GENDER)", use(p);
00933 
00934     //  test position-based conversion
00935     person2 p3;
00936     sql << "select id, first_name, last_name, gender from soci_test", into(p3);
00937     assert(p3.id == 1);
00938     assert(p3.firstName + p3.lastName == "PatriciaSmith");
00939     assert(p3.gender == "whoknows");
00940 
00941     sql << "update soci_test set gender = 'F' where id = 1";
00942 
00943     // additional test for stream-like conversion
00944     person3 p4;
00945     sql << "select id, first_name, last_name, gender from soci_test", into(p4);
00946     assert(p4.id == 1);
00947     assert(p4.firstName + p4.lastName == "PatriciaSmith");
00948     assert(p4.gender == "F");
00949 
00950     std::cout << "test 11 passed" << std::endl;
00951 }
00952 
00953 //
00954 // Backwards compatibility - support use of large strings with
00955 // columns of type LONG
00957 struct long_table_creator : public table_creator_base
00958 {
00959     long_table_creator(session & sql)
00960         : table_creator_base(sql)
00961     {
00962         sql << "create table soci_test(l long)";
00963     }
00964 };
00965 
00966 void test12()
00967 {
00968     session sql(backEnd, connectString);
00969     long_table_creator creator(sql);
00970 
00971     const std::string::size_type max = 32768;
00972     std::string in(max, 'X');
00973 
00974     sql << "insert into soci_test values(:l)", use(in);
00975 
00976     std::string out;
00977     sql << "select l from soci_test", into(out);
00978 
00979     assert(out.size() == max);
00980     assert(in == out);
00981 
00982     std::cout << "test 12 passed" << std::endl;
00983 }
00984 
00985 // test for modifiable and const use elements
00986 void test13()
00987 {
00988     session sql(backEnd, connectString);
00989 
00990     int i = 7;
00991     sql << "begin "
00992         "select 2 * :i into :i from dual; "
00993         "end;", use(i);
00994     assert(i == 14);
00995 
00996     const int j = 7;
00997     try
00998     {
00999         sql << "begin "
01000             "select 2 * :i into :i from dual;"
01001             " end;", use(j);
01002 
01003         assert(false); // should never get here
01004     }
01005     catch (soci_error const & e)
01006     {
01007         const std::string msg = e.what();
01008         assert(msg == "Attempted modification of const use element");
01009     }
01010 
01011     std::cout << "test 13 passed" << std::endl;
01012 }
01013 
01014 struct longlong_table_creator : table_creator_base
01015 {
01016     longlong_table_creator(session & sql)
01017         : table_creator_base(sql)
01018     {
01019         sql << "create table soci_test(val number(20))";
01020     }
01021 };
01022 
01023 // long long test
01024 void test14()
01025 {
01026     {
01027         session sql(backEnd, connectString);
01028 
01029         longlong_table_creator tableCreator(sql);
01030 
01031         long long v1 = 1000000000000LL;
01032         assert(v1 / 1000000 == 1000000);
01033 
01034         sql << "insert into soci_test(val) values(:val)", use(v1);
01035 
01036         long long v2 = 0LL;
01037         sql << "select val from soci_test", into(v2);
01038 
01039         assert(v2 == v1);
01040     }
01041 
01042     // vector<long long>
01043     {
01044         session sql(backEnd, connectString);
01045 
01046         longlong_table_creator tableCreator(sql);
01047 
01048         std::vector<long long> v1;
01049         v1.push_back(1000000000000LL);
01050         v1.push_back(1000000000001LL);
01051         v1.push_back(1000000000002LL);
01052         v1.push_back(1000000000003LL);
01053         v1.push_back(1000000000004LL);
01054 
01055         sql << "insert into soci_test(val) values(:val)", use(v1);
01056 
01057         std::vector<long long> v2(10);
01058         sql << "select val from soci_test order by val desc", into(v2);
01059 
01060         assert(v2.size() == 5);
01061         assert(v2[0] == 1000000000004LL);
01062         assert(v2[1] == 1000000000003LL);
01063         assert(v2[2] == 1000000000002LL);
01064         assert(v2[3] == 1000000000001LL);
01065         assert(v2[4] == 1000000000000LL);
01066     }
01067 
01068     std::cout << "test 14 passed" << std::endl;
01069 }
01070 
01071 //
01072 // Support for soci Common Tests
01073 //
01074 
01075 struct table_creator_one : public table_creator_base
01076 {
01077     table_creator_one(session & sql)
01078         : table_creator_base(sql)
01079     {
01080         sql << "create table soci_test(id number(10,0), val number(4,0), c char, "
01081                  "str varchar2(20), sh number, ul number, d number, "
01082                  "tm date, i1 number, i2 number, i3 number, name varchar2(20))";
01083     }
01084 };
01085 
01086 struct table_creator_two : public table_creator_base
01087 {
01088     table_creator_two(session & sql)
01089         : table_creator_base(sql)
01090     {
01091         sql  << "create table soci_test(num_float number, num_int numeric(4,0),"
01092                     " name varchar2(20), sometime date, chr char)";
01093     }
01094 };
01095 
01096 struct table_creator_three : public table_creator_base
01097 {
01098     table_creator_three(session & sql)
01099         : table_creator_base(sql)
01100     {
01101         sql << "create table soci_test(name varchar2(100) not null, "
01102             "phone varchar2(15))";
01103     }
01104 };
01105 
01106 class test_context :public test_context_base
01107 {
01108 public:
01109     test_context(backend_factory const &backEnd,
01110                 std::string const &connectString)
01111         : test_context_base(backEnd, connectString) {}
01112 
01113     table_creator_base* table_creator_1(session& s) const
01114     {
01115         return new table_creator_one(s);
01116     }
01117 
01118     table_creator_base* table_creator_2(session& s) const
01119     {
01120         return new table_creator_two(s);
01121     }
01122 
01123     table_creator_base* table_creator_3(session& s) const
01124     {
01125         return new table_creator_three(s);
01126     }
01127 
01128     std::string to_date_time(std::string const &datdt_string) const
01129     {
01130         return "to_date('" + datdt_string + "', 'YYYY-MM-DD HH24:MI:SS')";
01131     }
01132 };
01133 
01134 int main(int argc, char** argv)
01135 {
01136 #ifdef _MSC_VER
01137     // Redirect errors, unrecoverable problems, and assert() failures to STDERR,
01138     // instead of debug message window.
01139     // This hack is required to run asser()-driven tests by Buildbot.
01140     // NOTE: Comment this 2 lines for debugging with Visual C++ debugger to catch assertions inside.
01141     _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
01142     _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
01143 #endif //_MSC_VER
01144 
01145     if (argc == 2)
01146     {
01147         connectString = argv[1];
01148     }
01149     else
01150     {
01151         std::cout << "usage: " << argv[0]
01152             << " connectstring\n"
01153             << "example: " << argv[0]
01154             << " \'service=orcl user=scott password=tiger\'\n";
01155         std::exit(1);
01156     }
01157 
01158     try
01159     {
01160         test_context tc(backEnd, connectString);
01161         common_tests tests(tc);
01162         tests.run();
01163 
01164         std::cout << "\nsoci Oracle tests:\n\n";
01165         test1();
01166         test2();
01167         test3();
01168         test4();
01169         test5();
01170         test6();
01171         test7();
01172         test8();
01173         test9();
01174         test10();
01175         test11();
01176         test12();
01177         test13();
01178         test14();
01179 
01180         std::cout << "\nOK, all tests passed.\n\n";
01181     }
01182     catch (std::exception const & e)
01183     {
01184         std::cout << e.what() << '\n';
01185     }
01186     return 0;
01187 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
SourceForge Logo

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