Warning, file /sdk/codevis/thirdparty/soci/tests/oracle/test-oracle.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 // 0002 // // Copyright (C) 2004-2007 Maciej Sobczak, Stephen Hutton 0003 // Distributed under the Boost Software License, Version 1.0. 0004 // (See accompanying file LICENSE_1_0.txt or copy at 0005 // http://www.boost.org/LICENSE_1_0.txt) 0006 // 0007 0008 #include "common-tests.h" 0009 #include "soci/soci.h" 0010 #include "soci/oracle/soci-oracle.h" 0011 #include <iostream> 0012 #include <string> 0013 #include <cstdlib> 0014 #include <cstring> 0015 #include <ctime> 0016 0017 using namespace soci; 0018 using namespace soci::tests; 0019 0020 std::string connectString; 0021 backend_factory const &backEnd = *soci::factory_oracle(); 0022 0023 // Extra tests for date/time 0024 TEST_CASE("Oracle datetime", "[oracle][datetime]") 0025 { 0026 soci::session sql(backEnd, connectString); 0027 0028 { 0029 std::time_t now = std::time(NULL); 0030 std::tm t1, t2; 0031 t2 = *std::localtime(&now); 0032 0033 sql << "select t from (select :t as t from dual)", 0034 into(t1), use(t2); 0035 0036 CHECK(t1.tm_sec == t2.tm_sec); 0037 CHECK(t1.tm_min == t2.tm_min); 0038 CHECK(t1.tm_hour == t2.tm_hour); 0039 CHECK(t1.tm_mday == t2.tm_mday); 0040 CHECK(t1.tm_mon == t2.tm_mon); 0041 CHECK(t1.tm_year == t2.tm_year); 0042 CHECK(t1.tm_wday == t2.tm_wday); 0043 CHECK(t1.tm_yday == t2.tm_yday); 0044 CHECK(t1.tm_isdst == t2.tm_isdst); 0045 0046 // make sure the date is stored properly in Oracle 0047 char buf[25]; 0048 strftime(buf, sizeof(buf), "%m-%d-%Y %H:%M:%S", &t2); 0049 0050 std::string t_out; 0051 std::string format("MM-DD-YYYY HH24:MI:SS"); 0052 sql << "select to_char(t, :format) from (select :t as t from dual)", 0053 into(t_out), use(format), use(t2); 0054 0055 CHECK(t_out == std::string(buf)); 0056 } 0057 0058 { 0059 // date and time - before year 2000 0060 std::time_t then = std::time(NULL) - 17*365*24*60*60; 0061 std::tm t1, t2; 0062 t2 = *std::localtime(&then); 0063 0064 sql << "select t from (select :t as t from dual)", 0065 into(t1), use(t2); 0066 0067 CHECK(t1.tm_sec == t2.tm_sec); 0068 CHECK(t1.tm_min == t2.tm_min); 0069 CHECK(t1.tm_hour == t2.tm_hour); 0070 CHECK(t1.tm_mday == t2.tm_mday); 0071 CHECK(t1.tm_mon == t2.tm_mon); 0072 CHECK(t1.tm_year == t2.tm_year); 0073 CHECK(t1.tm_wday == t2.tm_wday); 0074 CHECK(t1.tm_yday == t2.tm_yday); 0075 CHECK(t1.tm_isdst == t2.tm_isdst); 0076 0077 // make sure the date is stored properly in Oracle 0078 char buf[25]; 0079 strftime(buf, sizeof(buf), "%m-%d-%Y %H:%M:%S", &t2); 0080 0081 std::string t_out; 0082 std::string format("MM-DD-YYYY HH24:MI:SS"); 0083 sql << "select to_char(t, :format) from (select :t as t from dual)", 0084 into(t_out), use(format), use(t2); 0085 0086 CHECK(t_out == std::string(buf)); 0087 } 0088 } 0089 0090 // explicit calls test 0091 TEST_CASE("Oracle explicit calls", "[oracle]") 0092 { 0093 soci::session sql(backEnd, connectString); 0094 0095 statement st(sql); 0096 st.alloc(); 0097 int i = 0; 0098 st.exchange(into(i)); 0099 st.prepare("select 7 from dual"); 0100 st.define_and_bind(); 0101 st.execute(1); 0102 CHECK(i == 7); 0103 } 0104 0105 // DDL + blob test 0106 0107 struct blob_table_creator : public table_creator_base 0108 { 0109 blob_table_creator(soci::session & sql) 0110 : table_creator_base(sql) 0111 { 0112 sql << 0113 "create table soci_test (" 0114 " id number(10) not null," 0115 " img blob" 0116 ")"; 0117 } 0118 }; 0119 0120 TEST_CASE("Oracle blob", "[oracle][blob]") 0121 { 0122 soci::session sql(backEnd, connectString); 0123 0124 blob_table_creator tableCreator(sql); 0125 0126 char buf[] = "abcdefghijklmnopqrstuvwxyz"; 0127 sql << "insert into soci_test (id, img) values (7, empty_blob())"; 0128 0129 { 0130 blob b(sql); 0131 0132 oracle_session_backend *sessionBackEnd 0133 = static_cast<oracle_session_backend *>(sql.get_backend()); 0134 0135 oracle_blob_backend *blobBackEnd 0136 = static_cast<oracle_blob_backend *>(b.get_backend()); 0137 0138 OCILobDisableBuffering(sessionBackEnd->svchp_, 0139 sessionBackEnd->errhp_, blobBackEnd->lobp_); 0140 0141 sql << "select img from soci_test where id = 7", into(b); 0142 CHECK(b.get_len() == 0); 0143 0144 b.write_from_start(buf, sizeof(buf)); 0145 CHECK(b.get_len() == sizeof(buf)); 0146 b.trim(10); 0147 CHECK(b.get_len() == 10); 0148 0149 // append does not work (Oracle bug #886191 ?) 0150 //b.append(buf, sizeof(buf)); 0151 //assert(b.get_len() == sizeof(buf) + 10); 0152 sql.commit(); 0153 } 0154 0155 { 0156 blob b(sql); 0157 sql << "select img from soci_test where id = 7", into(b); 0158 //assert(b.get_len() == sizeof(buf) + 10); 0159 CHECK(b.get_len() == 10); 0160 char buf2[100]; 0161 b.read_from_start(buf2, 10); 0162 CHECK(strncmp(buf2, "abcdefghij", 10) == 0); 0163 } 0164 } 0165 0166 // nested statement test 0167 // (the same syntax is used for output cursors in PL/SQL) 0168 0169 struct basic_table_creator : public table_creator_base 0170 { 0171 basic_table_creator(soci::session & sql) 0172 : table_creator_base(sql) 0173 { 0174 sql << 0175 "create table soci_test (" 0176 " id number(5) not null," 0177 " name varchar2(100)," 0178 " code number(5)" 0179 ")"; 0180 } 0181 }; 0182 0183 TEST_CASE("Oracle nested statement", "[oracle][blob]") 0184 { 0185 soci::session sql(backEnd, connectString); 0186 basic_table_creator tableCreator(sql); 0187 0188 int id; 0189 std::string name; 0190 { 0191 statement st1 = (sql.prepare << 0192 "insert into soci_test (id, name) values (:id, :name)", 0193 use(id), use(name)); 0194 0195 id = 1; name = "John"; st1.execute(1); 0196 id = 2; name = "Anna"; st1.execute(1); 0197 id = 3; name = "Mike"; st1.execute(1); 0198 } 0199 0200 statement stInner(sql); 0201 statement stOuter = (sql.prepare << 0202 "select cursor(select name from soci_test order by id)" 0203 " from soci_test where id = 1", 0204 into(stInner)); 0205 stInner.exchange(into(name)); 0206 stOuter.execute(); 0207 stOuter.fetch(); 0208 0209 std::vector<std::string> names; 0210 while (stInner.fetch()) { names.push_back(name); } 0211 0212 REQUIRE(names.size() == 3); 0213 CHECK(names[0] == "John"); 0214 CHECK(names[1] == "Anna"); 0215 CHECK(names[2] == "Mike"); 0216 } 0217 0218 0219 // ROWID test 0220 TEST_CASE("Oracle rowid", "[oracle][rowid]") 0221 { 0222 soci::session sql(backEnd, connectString); 0223 basic_table_creator tableCreator(sql); 0224 0225 sql << "insert into soci_test(id, name) values(7, \'John\')"; 0226 0227 rowid rid(sql); 0228 sql << "select rowid from soci_test where id = 7", into(rid); 0229 0230 int id; 0231 std::string name; 0232 sql << "select id, name from soci_test where rowid = :rid", 0233 into(id), into(name), use(rid); 0234 0235 CHECK(id == 7); 0236 CHECK(name == "John"); 0237 } 0238 0239 // Stored procedures 0240 struct procedure_creator : procedure_creator_base 0241 { 0242 procedure_creator(soci::session & sql) 0243 : procedure_creator_base(sql) 0244 { 0245 sql << 0246 "create or replace procedure soci_test(output out varchar2," 0247 "input in varchar2) as " 0248 "begin output := input; end;"; 0249 } 0250 }; 0251 0252 TEST_CASE("Oracle stored procedure", "[oracle][stored-procedure]") 0253 { 0254 soci::session sql(backEnd, connectString); 0255 procedure_creator procedure_creator(sql); 0256 0257 std::string in("my message"); 0258 std::string out; 0259 statement st = (sql.prepare << 0260 "begin soci_test(:output, :input); end;", 0261 use(out, "output"), 0262 use(in, "input")); 0263 st.execute(1); 0264 CHECK(out == in); 0265 0266 // explicit procedure syntax 0267 { 0268 std::string in("my message2"); 0269 std::string out; 0270 procedure proc = (sql.prepare << 0271 "soci_test(:output, :input)", 0272 use(out, "output"), use(in, "input")); 0273 proc.execute(1); 0274 CHECK(out == in); 0275 } 0276 } 0277 0278 // bind into user-defined objects 0279 struct string_holder 0280 { 0281 string_holder() {} 0282 string_holder(const char* s) : s_(s) {} 0283 string_holder(std::string s) : s_(s) {} 0284 std::string get() const { return s_; } 0285 private: 0286 std::string s_; 0287 }; 0288 0289 namespace soci 0290 { 0291 template <> 0292 struct type_conversion<string_holder> 0293 { 0294 typedef std::string base_type; 0295 static void from_base(const std::string &s, indicator /* ind */, 0296 string_holder &sh) 0297 { 0298 sh = string_holder(s); 0299 } 0300 0301 static void to_base(const string_holder &sh, std::string &s, indicator &ind) 0302 { 0303 s = sh.get(); 0304 ind = i_ok; 0305 } 0306 }; 0307 } 0308 0309 struct in_out_procedure_creator : public procedure_creator_base 0310 { 0311 in_out_procedure_creator(soci::session & sql) 0312 : procedure_creator_base(sql) 0313 { 0314 sql << "create or replace procedure soci_test(s in out varchar2)" 0315 " as begin s := s || s; end;"; 0316 } 0317 }; 0318 0319 struct returns_null_procedure_creator : public procedure_creator_base 0320 { 0321 returns_null_procedure_creator(soci::session & sql) 0322 : procedure_creator_base(sql) 0323 { 0324 sql << "create or replace procedure soci_test(s in out varchar2)" 0325 " as begin s := NULL; end;"; 0326 } 0327 }; 0328 0329 TEST_CASE("Oracle user-defined objects", "[oracle][type_conversion]") 0330 { 0331 soci::session sql(backEnd, connectString); 0332 { 0333 basic_table_creator tableCreator(sql); 0334 0335 int id(1); 0336 string_holder in("my string"); 0337 sql << "insert into soci_test(id, name) values(:id, :name)", use(id), use(in); 0338 0339 string_holder out; 0340 sql << "select name from soci_test", into(out); 0341 CHECK(out.get() == "my string"); 0342 0343 row r; 0344 sql << "select * from soci_test", into(r); 0345 string_holder dynamicOut = r.get<string_holder>(1); 0346 CHECK(dynamicOut.get() == "my string"); 0347 } 0348 } 0349 0350 TEST_CASE("Oracle user-defined objects in/out", "[oracle][type_conversion]") 0351 { 0352 soci::session sql(backEnd, connectString); 0353 0354 // test procedure with user-defined type as in-out parameter 0355 { 0356 in_out_procedure_creator procedureCreator(sql); 0357 0358 std::string sh("test"); 0359 procedure proc = (sql.prepare << "soci_test(:s)", use(sh)); 0360 proc.execute(1); 0361 CHECK(sh == "testtest"); 0362 } 0363 0364 // test procedure with user-defined type as in-out parameter 0365 { 0366 in_out_procedure_creator procedureCreator(sql); 0367 0368 string_holder sh("test"); 0369 procedure proc = (sql.prepare << "soci_test(:s)", use(sh)); 0370 proc.execute(1); 0371 CHECK(sh.get() == "testtest"); 0372 } 0373 } 0374 0375 TEST_CASE("Oracle null user-defined objects in/out", "[oracle][null][type_conversion]") 0376 { 0377 soci::session sql(backEnd, connectString); 0378 0379 // test procedure which returns null 0380 returns_null_procedure_creator procedureCreator(sql); 0381 0382 string_holder sh; 0383 indicator ind = i_ok; 0384 procedure proc = (sql.prepare << "soci_test(:s)", use(sh, ind)); 0385 proc.execute(1); 0386 CHECK(ind == i_null); 0387 } 0388 0389 // test bulk insert features 0390 TEST_CASE("Oracle bulk insert", "[oracle][insert][bulk]") 0391 { 0392 soci::session sql(backEnd, connectString); 0393 0394 basic_table_creator tableCreator(sql); 0395 0396 // verify exception is thrown if vectors of unequal size are passed in 0397 { 0398 std::vector<int> ids; 0399 ids.push_back(1); 0400 ids.push_back(2); 0401 std::vector<int> codes; 0402 codes.push_back(1); 0403 0404 try 0405 { 0406 sql << "insert into soci_test(id,code) values(:id,:code)", 0407 use(ids), use(codes); 0408 FAIL("expected exception not thrown"); 0409 } 0410 catch (soci_error const &e) 0411 { 0412 std::string const error = e.what(); 0413 CAPTURE(error); 0414 CHECK(error.find("Bind variable size mismatch") 0415 != std::string::npos); 0416 } 0417 0418 try 0419 { 0420 sql << "select from soci_test", into(ids), into(codes); 0421 FAIL("expected exception not thrown"); 0422 } 0423 catch (std::exception const &e) 0424 { 0425 std::string const error = e.what(); 0426 CAPTURE(error); 0427 CHECK(error.find("Bind variable size mismatch") 0428 != std::string::npos); 0429 } 0430 } 0431 0432 // verify partial insert occurs when one of the records is bad 0433 { 0434 std::vector<int> ids; 0435 ids.push_back(100); 0436 ids.push_back(1000000); // too big for column 0437 0438 try 0439 { 0440 sql << "insert into soci_test (id) values(:id)", use(ids, "id"); 0441 FAIL("expected exception not thrown"); 0442 } 0443 catch (soci_error const &e) 0444 { 0445 std::string const error = e.what(); 0446 //TODO e could be made to tell which row(s) failed 0447 CAPTURE(error); 0448 CHECK(error.find("ORA-01438") != std::string::npos); 0449 } 0450 sql.commit(); 0451 int count(7); 0452 sql << "select count(*) from soci_test", into(count); 0453 CHECK(count == 1); 0454 sql << "delete from soci_test"; 0455 } 0456 0457 // test insert 0458 { 0459 std::vector<int> ids; 0460 for (int i = 0; i != 3; ++i) 0461 { 0462 ids.push_back(i+10); 0463 } 0464 0465 statement st = (sql.prepare << "insert into soci_test(id) values(:id)", 0466 use(ids)); 0467 st.execute(1); 0468 int count; 0469 sql << "select count(*) from soci_test", into(count); 0470 CHECK(count == 3); 0471 } 0472 0473 //verify an exception is thrown if into vector is zero length 0474 { 0475 std::vector<int> ids; 0476 CHECK_THROWS_AS((sql << "select id from soci_test", into(ids)), soci_error); 0477 } 0478 0479 // verify an exception is thrown if use vector is zero length 0480 { 0481 std::vector<int> ids; 0482 CHECK_THROWS_AS((sql << "insert into soci_test(id) values(:id)", use(ids)), soci_error); 0483 } 0484 0485 // test "no data" condition 0486 { 0487 std::vector<indicator> inds(3); 0488 std::vector<int> ids_out(3); 0489 statement st = (sql.prepare << "select id from soci_test where 1=0", 0490 into(ids_out, inds)); 0491 0492 // false return value means "no data" 0493 CHECK(st.execute(1) == false); 0494 0495 // that's it - nothing else is guaranteed 0496 // and nothing else is to be tested here 0497 } 0498 0499 // test NULL indicators 0500 { 0501 std::vector<int> ids(3); 0502 sql << "select id from soci_test", into(ids); 0503 0504 std::vector<indicator> inds_in; 0505 inds_in.push_back(i_ok); 0506 inds_in.push_back(i_null); 0507 inds_in.push_back(i_ok); 0508 0509 std::vector<int> new_codes; 0510 new_codes.push_back(10); 0511 new_codes.push_back(11); 0512 new_codes.push_back(10); 0513 0514 sql << "update soci_test set code = :code where id = :id", 0515 use(new_codes, inds_in), use(ids); 0516 0517 std::vector<indicator> inds_out(3); 0518 std::vector<int> codes(3); 0519 0520 sql << "select code from soci_test", into(codes, inds_out); 0521 REQUIRE(codes.size() == 3); 0522 REQUIRE(inds_out.size() == 3); 0523 CHECK(codes[0] == 10); 0524 CHECK(codes[2] == 10); 0525 CHECK(inds_out[0] == i_ok); 0526 CHECK(inds_out[1] == i_null); 0527 CHECK(inds_out[2] == i_ok); 0528 } 0529 0530 // verify an exception is thrown if null is selected 0531 // and no indicator was provided 0532 { 0533 std::string msg; 0534 std::vector<int> intos(3); 0535 try 0536 { 0537 sql << "select code from soci_test", into(intos); 0538 FAIL("expected exception not thrown"); 0539 } 0540 catch (soci_error const &e) 0541 { 0542 CHECK(e.get_error_message() == 0543 "Null value fetched and no indicator defined." ); 0544 } 0545 } 0546 0547 // test basic select 0548 { 0549 const size_t sz = 3; 0550 std::vector<indicator> inds(sz); 0551 std::vector<int> ids_out(sz); 0552 statement st = (sql.prepare << "select id from soci_test", 0553 into(ids_out, inds)); 0554 const bool gotData = st.execute(true); 0555 CHECK(gotData); 0556 REQUIRE(ids_out.size() == sz); 0557 CHECK(ids_out[0] == 10); 0558 CHECK(ids_out[2] == 12); 0559 REQUIRE(inds.size() == 3); 0560 CHECK(inds[0] == i_ok); 0561 CHECK(inds[1] == i_ok); 0562 CHECK(inds[2] == i_ok); 0563 } 0564 0565 // verify execute(0) 0566 { 0567 std::vector<int> ids_out(2); 0568 statement st = (sql.prepare << "select id from soci_test", 0569 into(ids_out)); 0570 0571 st.execute(); 0572 REQUIRE(ids_out.size() == 2); 0573 bool gotData = st.fetch(); 0574 CHECK(gotData); 0575 REQUIRE(ids_out.size() == 2); 0576 CHECK(ids_out[0] == 10); 0577 CHECK(ids_out[1] == 11); 0578 gotData = st.fetch(); 0579 CHECK(gotData); 0580 REQUIRE(ids_out.size() == 1); 0581 CHECK(ids_out[0] == 12); 0582 gotData = st.fetch(); 0583 CHECK(gotData == false); 0584 } 0585 0586 // verify resizing happens if vector is larger 0587 // than number of rows returned 0588 { 0589 std::vector<int> ids_out(4); // one too many 0590 statement st2 = (sql.prepare << "select id from soci_test", 0591 into(ids_out)); 0592 bool gotData = st2.execute(true); 0593 CHECK(gotData); 0594 REQUIRE(ids_out.size() == 3); 0595 CHECK(ids_out[0] == 10); 0596 CHECK(ids_out[2] == 12); 0597 } 0598 0599 // verify resizing happens properly during fetch() 0600 { 0601 std::vector<int> more; 0602 more.push_back(13); 0603 more.push_back(14); 0604 sql << "insert into soci_test(id) values(:id)", use(more); 0605 0606 std::vector<int> ids(2); 0607 statement st3 = (sql.prepare << "select id from soci_test", into(ids)); 0608 bool gotData = st3.execute(true); 0609 CHECK(gotData); 0610 CHECK(ids[0] == 10); 0611 CHECK(ids[1] == 11); 0612 0613 gotData = st3.fetch(); 0614 CHECK(gotData); 0615 CHECK(ids[0] == 12); 0616 CHECK(ids[1] == 13); 0617 0618 gotData = st3.fetch(); 0619 CHECK(gotData); 0620 REQUIRE(ids.size() == 1); 0621 CHECK(ids[0] == 14); 0622 0623 gotData = st3.fetch(); 0624 CHECK(gotData == false); 0625 } 0626 } 0627 0628 // more tests for bulk fetch 0629 TEST_CASE("Oracle bulk fetch", "[oracle][fetch][bulk]") 0630 { 0631 soci::session sql(backEnd, connectString); 0632 0633 basic_table_creator tableCreator(sql); 0634 0635 std::vector<int> in; 0636 for (int i = 1; i <= 10; ++i) 0637 { 0638 in.push_back(i); 0639 } 0640 0641 sql << "insert into soci_test (id) values(:id)", use(in); 0642 0643 int count(0); 0644 sql << "select count(*) from soci_test", into(count); 0645 CHECK(count == 10); 0646 0647 // verify that the exception is thrown when trying to resize 0648 // the output vector to the size that is bigger than that 0649 // at the time of binding 0650 { 0651 std::vector<int> out(4); 0652 statement st = (sql.prepare << 0653 "select id from soci_test", into(out)); 0654 0655 st.execute(); 0656 0657 st.fetch(); 0658 REQUIRE(out.size() == 4); 0659 CHECK(out[0] == 1); 0660 CHECK(out[1] == 2); 0661 CHECK(out[2] == 3); 0662 CHECK(out[3] == 4); 0663 out.resize(5); // this should be detected as error 0664 try 0665 { 0666 st.fetch(); 0667 FAIL("expected exception not thrown"); 0668 } 0669 catch (soci_error const &e) 0670 { 0671 CHECK(e.get_error_message() == 0672 "Increasing the size of the output vector is not supported."); 0673 } 0674 } 0675 0676 // on the other hand, downsizing is OK 0677 { 0678 std::vector<int> out(4); 0679 statement st = (sql.prepare << 0680 "select id from soci_test", into(out)); 0681 0682 st.execute(); 0683 0684 st.fetch(); 0685 REQUIRE(out.size() == 4); 0686 CHECK(out[0] == 1); 0687 CHECK(out[1] == 2); 0688 CHECK(out[2] == 3); 0689 CHECK(out[3] == 4); 0690 out.resize(3); // ok 0691 st.fetch(); 0692 REQUIRE(out.size() == 3); 0693 CHECK(out[0] == 5); 0694 CHECK(out[1] == 6); 0695 CHECK(out[2] == 7); 0696 out.resize(4); // ok, not bigger than initially 0697 st.fetch(); 0698 REQUIRE(out.size() == 3); // downsized because of end of data 0699 CHECK(out[0] == 8); 0700 CHECK(out[1] == 9); 0701 CHECK(out[2] == 10); 0702 bool gotData = st.fetch(); 0703 CHECK(gotData == false); // end of data 0704 } 0705 } 0706 0707 struct person 0708 { 0709 int id; 0710 std::string firstName; 0711 string_holder lastName; //test mapping of type_conversion-based types 0712 std::string gender; 0713 }; 0714 0715 // Object-Relational Mapping 0716 // Note: Use the values class as shown below in type_conversions 0717 // to achieve object relational mapping. The values class should 0718 // not be used directly in any other fashion. 0719 namespace soci 0720 { 0721 // name-based conversion 0722 template<> struct type_conversion<person> 0723 { 0724 typedef values base_type; 0725 0726 static void from_base(values const &v, indicator /* ind */, person &p) 0727 { 0728 // ignoring possibility that the whole object might be NULL 0729 0730 p.id = v.get<int>("ID"); 0731 p.firstName = v.get<std::string>("FIRST_NAME"); 0732 p.lastName = v.get<string_holder>("LAST_NAME"); 0733 p.gender = v.get<std::string>("GENDER", "unknown"); 0734 } 0735 0736 static void to_base(person const & p, values & v, indicator & ind) 0737 { 0738 v.set("ID", p.id); 0739 v.set("FIRST_NAME", p.firstName); 0740 v.set("LAST_NAME", p.lastName); 0741 v.set("GENDER", p.gender, p.gender.empty() ? i_null : i_ok); 0742 ind = i_ok; 0743 } 0744 }; 0745 } 0746 0747 struct person_table_creator : public table_creator_base 0748 { 0749 person_table_creator(soci::session & sql) 0750 : table_creator_base(sql) 0751 { 0752 sql << "create table soci_test(id numeric(5,0) NOT NULL," 0753 << " last_name varchar2(20), first_name varchar2(20), " 0754 " gender varchar2(10))"; 0755 } 0756 }; 0757 0758 struct times100_procedure_creator : public procedure_creator_base 0759 { 0760 times100_procedure_creator(soci::session & sql) 0761 : procedure_creator_base(sql) 0762 { 0763 sql << "create or replace procedure soci_test(id in out number)" 0764 " as begin id := id * 100; end;"; 0765 } 0766 }; 0767 0768 TEST_CASE("Oracle ORM", "[oracle][orm]") 0769 { 0770 soci::session sql(backEnd, connectString); 0771 0772 { 0773 person_table_creator tableCreator(sql); 0774 0775 person p; 0776 p.id = 1; 0777 p.lastName = "Smith"; 0778 p.firstName = "Pat"; 0779 sql << "insert into soci_test(id, first_name, last_name, gender) " 0780 << "values(:ID, :FIRST_NAME, :LAST_NAME, :GENDER)", use(p); 0781 0782 // p should be unchanged 0783 CHECK(p.id == 1); 0784 CHECK(p.firstName == "Pat"); 0785 CHECK(p.lastName.get() == "Smith"); 0786 0787 person p1; 0788 sql << "select * from soci_test", into(p1); 0789 CHECK(p1.id == 1); 0790 CHECK(p1.firstName == "Pat"); 0791 CHECK(p1.lastName.get() == "Smith"); 0792 CHECK(p1.gender == "unknown"); 0793 0794 p.firstName = "Patricia"; 0795 sql << "update soci_test set first_name = :FIRST_NAME " 0796 "where id = :ID", use(p); 0797 0798 // p should be unchanged 0799 CHECK(p.id == 1); 0800 CHECK(p.firstName == "Patricia"); 0801 CHECK(p.lastName.get() == "Smith"); 0802 // Note: gender is now "unknown" because of the mapping, not "" 0803 CHECK(p.gender == "unknown"); 0804 0805 person p2; 0806 sql << "select * from soci_test", into(p2); 0807 CHECK(p2.id == 1); 0808 CHECK(p2.firstName == "Patricia"); 0809 CHECK(p2.lastName.get() == "Smith"); 0810 0811 // insert a second row so we can test fetching 0812 person p3; 0813 p3.id = 2; 0814 p3.firstName = "Joe"; 0815 p3.lastName = "Smith"; 0816 sql << "insert into soci_test(id, first_name, last_name, gender) " 0817 << "values(:ID, :FIRST_NAME, :LAST_NAME, :GENDER)", use(p3); 0818 0819 person p4; 0820 statement st = (sql.prepare << "select * from soci_test order by id", 0821 into(p4)); 0822 0823 st.execute(); 0824 bool gotData = st.fetch(); 0825 CHECK(gotData); 0826 CHECK(p4.id == 1); 0827 CHECK(p4.firstName == "Patricia"); 0828 0829 gotData = st.fetch(); 0830 CHECK(gotData); 0831 CHECK(p4.id == 2); 0832 CHECK(p4.firstName == "Joe"); 0833 gotData = st.fetch(); 0834 CHECK(gotData == false); 0835 } 0836 0837 // test with stored procedure 0838 { 0839 times100_procedure_creator procedureCreator(sql); 0840 0841 person p; 0842 p.id = 1; 0843 p.firstName = "Pat"; 0844 p.lastName = "Smith"; 0845 procedure proc = (sql.prepare << "soci_test(:ID)", use(p)); 0846 proc.execute(1); 0847 CHECK(p.id == 100); 0848 CHECK(p.firstName == "Pat"); 0849 CHECK(p.lastName.get() == "Smith"); 0850 } 0851 0852 // test with stored procedure which returns null 0853 { 0854 returns_null_procedure_creator procedureCreator(sql); 0855 0856 person p; 0857 try 0858 { 0859 procedure proc = (sql.prepare << "soci_test(:FIRST_NAME)", 0860 use(p)); 0861 proc.execute(1); 0862 FAIL("expected exception not thrown"); 0863 } 0864 catch (soci_error& e) 0865 { 0866 CHECK(e.get_error_message() == 0867 "Null value not allowed for this type"); 0868 } 0869 0870 procedure proc = (sql.prepare << "soci_test(:GENDER)", 0871 use(p)); 0872 proc.execute(1); 0873 CHECK(p.gender == "unknown"); 0874 0875 } 0876 } 0877 0878 // Experimental support for position based O/R Mapping 0879 0880 // additional type for position-based test 0881 struct person2 0882 { 0883 int id; 0884 std::string firstName; 0885 std::string lastName; 0886 std::string gender; 0887 }; 0888 0889 // additional type for stream-like test 0890 struct person3 : person2 {}; 0891 0892 namespace soci 0893 { 0894 // position-based conversion 0895 template<> struct type_conversion<person2> 0896 { 0897 typedef values base_type; 0898 0899 static void from_base(values const &v, indicator /* ind */, person2 &p) 0900 { 0901 p.id = v.get<int>(0); 0902 p.firstName = v.get<std::string>(1); 0903 p.lastName = v.get<std::string>(2); 0904 p.gender = v.get<std::string>(3, "whoknows"); 0905 } 0906 0907 // What about the "to" part? Does it make any sense to have it? 0908 }; 0909 0910 // stream-like conversion 0911 template<> struct type_conversion<person3> 0912 { 0913 typedef values base_type; 0914 0915 static void from_base(values const &v, indicator /* ind */, person3 &p) 0916 { 0917 v >> p.id >> p.firstName >> p.lastName >> p.gender; 0918 } 0919 // TODO: The "to" part is certainly needed. 0920 }; 0921 } 0922 0923 TEST_CASE("Oracle ORM by index", "[oracle][orm]") 0924 { 0925 soci::session sql(backEnd, connectString); 0926 0927 person_table_creator tableCreator(sql); 0928 0929 person p; 0930 p.id = 1; 0931 p.lastName = "Smith"; 0932 p.firstName = "Patricia"; 0933 sql << "insert into soci_test(id, first_name, last_name, gender) " 0934 << "values(:ID, :FIRST_NAME, :LAST_NAME, :GENDER)", use(p); 0935 0936 // test position-based conversion 0937 person2 p3; 0938 sql << "select id, first_name, last_name, gender from soci_test", into(p3); 0939 CHECK(p3.id == 1); 0940 CHECK(p3.firstName == "Patricia"); 0941 CHECK(p3.lastName == "Smith"); 0942 CHECK(p3.gender == "whoknows"); 0943 0944 sql << "update soci_test set gender = 'F' where id = 1"; 0945 0946 // additional test for stream-like conversion 0947 person3 p4; 0948 sql << "select id, first_name, last_name, gender from soci_test", into(p4); 0949 CHECK(p4.id == 1); 0950 CHECK(p4.firstName == "Patricia"); 0951 CHECK(p4.lastName == "Smith"); 0952 CHECK(p4.gender == "F"); 0953 } 0954 0955 // 0956 // Backwards compatibility - support use of large strings with 0957 // columns of type LONG 0958 /// 0959 struct long_table_creator : public table_creator_base 0960 { 0961 long_table_creator(soci::session & sql) 0962 : table_creator_base(sql) 0963 { 0964 sql << "create table soci_test(l long)"; 0965 } 0966 }; 0967 0968 TEST_CASE("Oracle large strings as long", "[oracle][compatibility]") 0969 { 0970 soci::session sql(backEnd, connectString); 0971 long_table_creator creator(sql); 0972 0973 const std::string::size_type max = 32768; 0974 std::string in(max, 'X'); 0975 0976 sql << "insert into soci_test values(:l)", use(in); 0977 0978 std::string out; 0979 sql << "select l from soci_test", into(out); 0980 0981 CHECK(out.size() == max); 0982 CHECK(in == out); 0983 } 0984 0985 // test for modifiable and const use elements 0986 TEST_CASE("Oracle const and modifiable parameters", "[oracle][use]") 0987 { 0988 soci::session sql(backEnd, connectString); 0989 0990 int i = 7; 0991 sql << "begin " 0992 "select 2 * :i into :i from dual; " 0993 "end;", use(i); 0994 CHECK(i == 14); 0995 0996 const int j = 7; 0997 try 0998 { 0999 sql << "begin " 1000 "select 2 * :i into :i from dual;" 1001 " end;", use(j); 1002 1003 FAIL("expected exception not thrown"); 1004 } 1005 catch (soci_error const & e) 1006 { 1007 CHECK(e.get_error_message() == 1008 "Attempted modification of const use element"); 1009 } 1010 } 1011 1012 struct longlong_table_creator : table_creator_base 1013 { 1014 longlong_table_creator(soci::session & sql) 1015 : table_creator_base(sql) 1016 { 1017 sql << "create table soci_test(val number(20))"; 1018 } 1019 }; 1020 1021 // test using the result of to_number() which uses the default NUMBER type, 1022 // with precision == scale == 0, with rowset 1023 TEST_CASE("Oracle to_number with rowset", "[oracle][rowset][to_number]") 1024 { 1025 soci::session sql(backEnd, connectString); 1026 1027 soci::rowset<soci::row> 1028 rs = (sql.prepare << "select to_number('123456789012345') from dual"); 1029 double d = rs.begin()->get<double>(0); 1030 ASSERT_EQUAL_EXACT(d, 123456789012345); 1031 1032 rs = (sql.prepare << "select to_number(:t) from dual", use(3.14)); 1033 d = rs.begin()->get<double>(0); 1034 ASSERT_EQUAL_EXACT(d, 3.14); 1035 } 1036 1037 // long long test 1038 TEST_CASE("Oracle long long", "[oracle][longlong]") 1039 { 1040 { 1041 soci::session sql(backEnd, connectString); 1042 1043 longlong_table_creator tableCreator(sql); 1044 1045 long long v1 = 1000000000000LL; 1046 sql << "insert into soci_test(val) values(:val)", use(v1); 1047 1048 long long v2 = 0LL; 1049 sql << "select val from soci_test", into(v2); 1050 1051 CHECK(v2 == v1); 1052 } 1053 1054 // vector<long long> 1055 { 1056 soci::session sql(backEnd, connectString); 1057 1058 longlong_table_creator tableCreator(sql); 1059 1060 std::vector<long long> v1; 1061 v1.push_back(1000000000000LL); 1062 v1.push_back(1000000000001LL); 1063 v1.push_back(1000000000002LL); 1064 v1.push_back(1000000000003LL); 1065 v1.push_back(1000000000004LL); 1066 1067 sql << "insert into soci_test(val) values(:val)", use(v1); 1068 1069 std::vector<long long> v2(10); 1070 sql << "select val from soci_test order by val desc", into(v2); 1071 1072 REQUIRE(v2.size() == 5); 1073 CHECK(v2[0] == 1000000000004LL); 1074 CHECK(v2[1] == 1000000000003LL); 1075 CHECK(v2[2] == 1000000000002LL); 1076 CHECK(v2[3] == 1000000000001LL); 1077 CHECK(v2[4] == 1000000000000LL); 1078 } 1079 } 1080 1081 // Test the DDL and metadata functionality 1082 TEST_CASE("Oracle DDL with metadata", "[oracle][ddl]") 1083 { 1084 soci::session sql(backEnd, connectString); 1085 1086 // note: prepare_column_descriptions expects l-value 1087 std::string ddl_t1 = "DDL_T1"; 1088 std::string ddl_t2 = "DDL_T2"; 1089 std::string ddl_t3 = "DDL_T3"; 1090 1091 // single-expression variant: 1092 sql.create_table(ddl_t1).column("I", soci::dt_integer).column("J", soci::dt_integer); 1093 1094 // check whether this table was created: 1095 1096 bool ddl_t1_found = false; 1097 bool ddl_t2_found = false; 1098 bool ddl_t3_found = false; 1099 std::string table_name; 1100 soci::statement st = (sql.prepare_table_names(), into(table_name)); 1101 st.execute(); 1102 while (st.fetch()) 1103 { 1104 if (table_name == ddl_t1) { ddl_t1_found = true; } 1105 if (table_name == ddl_t2) { ddl_t2_found = true; } 1106 if (table_name == ddl_t3) { ddl_t3_found = true; } 1107 } 1108 1109 CHECK(ddl_t1_found); 1110 CHECK(ddl_t2_found == false); 1111 CHECK(ddl_t3_found == false); 1112 1113 // check whether ddl_t1 has the right structure: 1114 1115 bool i_found = false; 1116 bool j_found = false; 1117 bool other_found = false; 1118 soci::column_info ci; 1119 soci::statement st1 = (sql.prepare_column_descriptions(ddl_t1), into(ci)); 1120 st1.execute(); 1121 while (st1.fetch()) 1122 { 1123 if (ci.name == "I") 1124 { 1125 CHECK(ci.type == soci::dt_integer); 1126 CHECK(ci.nullable); 1127 i_found = true; 1128 } 1129 else if (ci.name == "J") 1130 { 1131 CHECK(ci.type == soci::dt_integer); 1132 CHECK(ci.nullable); 1133 j_found = true; 1134 } 1135 else 1136 { 1137 other_found = true; 1138 } 1139 } 1140 1141 CHECK(i_found); 1142 CHECK(j_found); 1143 CHECK(other_found == false); 1144 1145 // two more tables: 1146 1147 // separately defined columns: 1148 // (note: statement is executed when ddl object goes out of scope) 1149 { 1150 soci::ddl_type ddl = sql.create_table(ddl_t2); 1151 ddl.column("I", soci::dt_integer); 1152 ddl.column("J", soci::dt_integer); 1153 ddl.column("K", soci::dt_integer)("not null"); 1154 ddl.primary_key("t2_pk", "J"); 1155 } 1156 1157 sql.add_column(ddl_t1, "K", soci::dt_integer); 1158 sql.add_column(ddl_t1, "BIG", soci::dt_string, 0); // "unlimited" length -> CLOB 1159 sql.drop_column(ddl_t1, "I"); 1160 1161 // or with constraint as in t2: 1162 sql.add_column(ddl_t2, "M", soci::dt_integer)("not null"); 1163 1164 // third table with a foreign key to the second one 1165 { 1166 soci::ddl_type ddl = sql.create_table(ddl_t3); 1167 ddl.column("X", soci::dt_integer); 1168 ddl.column("Y", soci::dt_integer); 1169 ddl.foreign_key("t3_fk", "X", ddl_t2, "J"); 1170 } 1171 1172 // check if all tables were created: 1173 1174 ddl_t1_found = false; 1175 ddl_t2_found = false; 1176 ddl_t3_found = false; 1177 soci::statement st2 = (sql.prepare_table_names(), into(table_name)); 1178 st2.execute(); 1179 while (st2.fetch()) 1180 { 1181 if (table_name == ddl_t1) { ddl_t1_found = true; } 1182 if (table_name == ddl_t2) { ddl_t2_found = true; } 1183 if (table_name == ddl_t3) { ddl_t3_found = true; } 1184 } 1185 1186 CHECK(ddl_t1_found); 1187 CHECK(ddl_t2_found); 1188 CHECK(ddl_t3_found); 1189 1190 // check if ddl_t1 has the right structure (it was altered): 1191 1192 i_found = false; 1193 j_found = false; 1194 bool k_found = false; 1195 bool big_found = false; 1196 other_found = false; 1197 soci::statement st3 = (sql.prepare_column_descriptions(ddl_t1), into(ci)); 1198 st3.execute(); 1199 while (st3.fetch()) 1200 { 1201 if (ci.name == "J") 1202 { 1203 CHECK(ci.type == soci::dt_integer); 1204 CHECK(ci.nullable); 1205 j_found = true; 1206 } 1207 else if (ci.name == "K") 1208 { 1209 CHECK(ci.type == soci::dt_integer); 1210 CHECK(ci.nullable); 1211 k_found = true; 1212 } 1213 else if (ci.name == "BIG") 1214 { 1215 CHECK(ci.type == soci::dt_string); 1216 CHECK(ci.precision == 0); // "unlimited" for strings 1217 big_found = true; 1218 } 1219 else 1220 { 1221 other_found = true; 1222 } 1223 } 1224 1225 CHECK(i_found == false); 1226 CHECK(j_found); 1227 CHECK(k_found); 1228 CHECK(big_found); 1229 CHECK(other_found == false); 1230 1231 // check if ddl_t2 has the right structure: 1232 1233 i_found = false; 1234 j_found = false; 1235 k_found = false; 1236 bool m_found = false; 1237 other_found = false; 1238 soci::statement st4 = (sql.prepare_column_descriptions(ddl_t2), into(ci)); 1239 st4.execute(); 1240 while (st4.fetch()) 1241 { 1242 if (ci.name == "I") 1243 { 1244 CHECK(ci.type == soci::dt_integer); 1245 CHECK(ci.nullable); 1246 i_found = true; 1247 } 1248 else if (ci.name == "J") 1249 { 1250 CHECK(ci.type == soci::dt_integer); 1251 CHECK(ci.nullable == false); // primary key 1252 j_found = true; 1253 } 1254 else if (ci.name == "K") 1255 { 1256 CHECK(ci.type == soci::dt_integer); 1257 CHECK(ci.nullable == false); 1258 k_found = true; 1259 } 1260 else if (ci.name == "M") 1261 { 1262 CHECK(ci.type == soci::dt_integer); 1263 CHECK(ci.nullable == false); 1264 m_found = true; 1265 } 1266 else 1267 { 1268 other_found = true; 1269 } 1270 } 1271 1272 CHECK(i_found); 1273 CHECK(j_found); 1274 CHECK(k_found); 1275 CHECK(m_found); 1276 CHECK(other_found == false); 1277 1278 sql.drop_table(ddl_t1); 1279 sql.drop_table(ddl_t3); // note: this must be dropped before ddl_t2 1280 sql.drop_table(ddl_t2); 1281 1282 // check if all tables were dropped: 1283 1284 ddl_t1_found = false; 1285 ddl_t2_found = false; 1286 ddl_t3_found = false; 1287 st2 = (sql.prepare_table_names(), into(table_name)); 1288 st2.execute(); 1289 while (st2.fetch()) 1290 { 1291 if (table_name == ddl_t1) { ddl_t1_found = true; } 1292 if (table_name == ddl_t2) { ddl_t2_found = true; } 1293 if (table_name == ddl_t3) { ddl_t3_found = true; } 1294 } 1295 1296 CHECK(ddl_t1_found == false); 1297 CHECK(ddl_t2_found == false); 1298 CHECK(ddl_t3_found == false); 1299 1300 int i = -1; 1301 sql << "select length(" + sql.empty_blob() + ") from dual", into(i); 1302 CHECK(i == 0); 1303 sql << "select " + sql.nvl() + "(1, 2) from dual", into(i); 1304 CHECK(i == 1); 1305 sql << "select " + sql.nvl() + "(NULL, 2) from dual", into(i); 1306 CHECK(i == 2); 1307 } 1308 1309 // Test the bulk iterators functionality 1310 TEST_CASE("Bulk iterators", "[oracle][bulkiters]") 1311 { 1312 soci::session sql(backEnd, connectString); 1313 1314 sql << "create table t (i integer)"; 1315 1316 // test bulk iterators with basic types 1317 { 1318 std::vector<int> v; 1319 v.push_back(10); 1320 v.push_back(20); 1321 v.push_back(30); 1322 v.push_back(40); 1323 v.push_back(50); 1324 1325 std::size_t begin = 2; 1326 std::size_t end = 5; 1327 sql << "insert into t (i) values (:v)", soci::use(v, begin, end); 1328 1329 v.clear(); 1330 v.resize(20); 1331 begin = 5; 1332 end = 20; 1333 sql << "select i from t", soci::into(v, begin, end); 1334 1335 CHECK(end == 8); 1336 for (std::size_t i = 0; i != 5; ++i) 1337 { 1338 CHECK(v[i] == 0); 1339 } 1340 CHECK(v[5] == 30); 1341 CHECK(v[6] == 40); 1342 CHECK(v[7] == 50); 1343 for (std::size_t i = end; i != 20; ++i) 1344 { 1345 CHECK(v[i] == 0); 1346 } 1347 } 1348 1349 sql << "delete from t"; 1350 1351 // test bulk iterators with user types 1352 { 1353 std::vector<MyInt> v; 1354 v.push_back(MyInt(10)); 1355 v.push_back(MyInt(20)); 1356 v.push_back(MyInt(30)); 1357 v.push_back(MyInt(40)); 1358 v.push_back(MyInt(50)); 1359 1360 std::size_t begin = 2; 1361 std::size_t end = 5; 1362 sql << "insert into t (i) values (:v)", soci::use(v, begin, end); 1363 1364 v.clear(); 1365 for (std::size_t i = 0; i != 20; ++i) 1366 { 1367 v.push_back(MyInt(-1)); 1368 } 1369 1370 begin = 5; 1371 end = 20; 1372 sql << "select i from t", soci::into(v, begin, end); 1373 1374 CHECK(end == 8); 1375 for (std::size_t i = 0; i != 5; ++i) 1376 { 1377 CHECK(v[i].get() == -1); 1378 } 1379 CHECK(v[5].get() == 30); 1380 CHECK(v[6].get() == 40); 1381 CHECK(v[7].get() == 50); 1382 for (std::size_t i = end; i != 20; ++i) 1383 { 1384 CHECK(v[i].get() == -1); 1385 } 1386 } 1387 1388 sql << "drop table t"; 1389 } 1390 1391 // 1392 // Support for soci Common Tests 1393 // 1394 1395 struct table_creator_one : public table_creator_base 1396 { 1397 table_creator_one(soci::session & sql) 1398 : table_creator_base(sql) 1399 { 1400 sql << "create table soci_test(id number(10,0), val number(4,0), c char, " 1401 "str varchar2(20), sh number, ul number, d number, " 1402 "num76 numeric(7,6), " 1403 "tm date, i1 number, i2 number, i3 number, name varchar2(20))"; 1404 } 1405 }; 1406 1407 struct table_creator_two : public table_creator_base 1408 { 1409 table_creator_two(soci::session & sql) 1410 : table_creator_base(sql) 1411 { 1412 sql << "create table soci_test(num_float number, num_int numeric(4,0)," 1413 " name varchar2(20), sometime date, chr char)"; 1414 } 1415 }; 1416 1417 struct table_creator_three : public table_creator_base 1418 { 1419 table_creator_three(soci::session & sql) 1420 : table_creator_base(sql) 1421 { 1422 sql << "create table soci_test(name varchar2(100) not null, " 1423 "phone varchar2(15))"; 1424 } 1425 }; 1426 1427 struct table_creator_four : public table_creator_base 1428 { 1429 table_creator_four(soci::session & sql) 1430 : table_creator_base(sql) 1431 { 1432 sql << "create table soci_test(val number)"; 1433 } 1434 }; 1435 1436 struct table_creator_for_xml : table_creator_base 1437 { 1438 table_creator_for_xml(soci::session& sql) 1439 : table_creator_base(sql) 1440 { 1441 sql << "create table soci_test(id integer, x xmltype)"; 1442 } 1443 }; 1444 1445 struct table_creator_for_clob : table_creator_base 1446 { 1447 table_creator_for_clob(soci::session& sql) 1448 : table_creator_base(sql) 1449 { 1450 sql << "create table soci_test(id integer, s clob)"; 1451 } 1452 }; 1453 1454 class test_context :public test_context_base 1455 { 1456 public: 1457 test_context(backend_factory const &backEnd, 1458 std::string const &connectString) 1459 : test_context_base(backEnd, connectString) {} 1460 1461 table_creator_base* table_creator_1(soci::session& s) const override 1462 { 1463 return new table_creator_one(s); 1464 } 1465 1466 table_creator_base* table_creator_2(soci::session& s) const override 1467 { 1468 return new table_creator_two(s); 1469 } 1470 1471 table_creator_base* table_creator_3(soci::session& s) const override 1472 { 1473 return new table_creator_three(s); 1474 } 1475 1476 table_creator_base* table_creator_4(soci::session& s) const override 1477 { 1478 return new table_creator_four(s); 1479 } 1480 1481 table_creator_base* table_creator_clob(soci::session& s) const override 1482 { 1483 return new table_creator_for_clob(s); 1484 } 1485 1486 table_creator_base* table_creator_xml(soci::session& s) const override 1487 { 1488 return new table_creator_for_xml(s); 1489 } 1490 1491 std::string to_xml(std::string const& x) const override 1492 { 1493 return "xmltype(" + x + ")"; 1494 } 1495 1496 std::string from_xml(std::string const& x) const override 1497 { 1498 // Notice that using just x.getCLOBVal() doesn't work, only 1499 // table.x.getCLOBVal() or (x).getCLOBVal(), as used here, does. 1500 return "(" + x + ").getCLOBVal()"; 1501 } 1502 1503 bool has_real_xml_support() const override 1504 { 1505 return true; 1506 } 1507 1508 bool treats_empty_strings_as_null() const override 1509 { 1510 return true; 1511 } 1512 1513 std::string to_date_time(std::string const &datdt_string) const override 1514 { 1515 return "to_date('" + datdt_string + "', 'YYYY-MM-DD HH24:MI:SS')"; 1516 } 1517 1518 std::string sql_length(std::string const& s) const override 1519 { 1520 // Oracle treats empty strings as NULLs, but we want to return the 1521 // length of 0 for them for consistency with the other backends, so use 1522 // nvl() explicitly to achieve this. 1523 return "nvl(length(" + s + "), 0)"; 1524 } 1525 }; 1526 1527 int main(int argc, char** argv) 1528 { 1529 #ifdef _MSC_VER 1530 // Redirect errors, unrecoverable problems, and assert() failures to STDERR, 1531 // instead of debug message window. 1532 // This hack is required to run assert()-driven tests by Buildbot. 1533 // NOTE: Comment this 2 lines for debugging with Visual C++ debugger to catch assertions inside. 1534 _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE); 1535 _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR); 1536 #endif //_MSC_VER 1537 1538 if (argc >= 2) 1539 { 1540 connectString = argv[1]; 1541 1542 // Replace the connect string with the process name to ensure that 1543 // CATCH uses the correct name in its messages. 1544 argv[1] = argv[0]; 1545 1546 argc--; 1547 argv++; 1548 } 1549 else 1550 { 1551 std::cout << "usage: " << argv[0] 1552 << " connectstring [test-arguments...]\n" 1553 << "example: " << argv[0] 1554 << " \'service=orcl user=scott password=tiger\'\n"; 1555 std::exit(1); 1556 } 1557 1558 if (!std::getenv("ORACLE_HOME")) 1559 { 1560 std::cerr << "ORACLE_HOME environment variable must be defined for Oracle tests.\n"; 1561 std::exit(1); 1562 } 1563 1564 test_context tc(backEnd, connectString); 1565 1566 return Catch::Session().run(argc, argv); 1567 }