test-oracle.cpp
Go to the documentation of this file.
1 //
2 // // Copyright (C) 2004-2007 Maciej Sobczak, Stephen Hutton
3 // Distributed under the Boost Software License, Version 1.0.
4 // (See accompanying file LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
6 //
7 
8 #include "soci.h"
9 #include "soci-oracle.h"
10 #include "common-tests.h"
11 #include <iostream>
12 #include <string>
13 #include <cstring>
14 #include <cassert>
15 #include <ctime>
16 
17 using namespace soci;
18 using namespace soci::tests;
19 
20 std::string connectString;
22 
23 // Extra tests for date/time
24 void test1()
25 {
26  session sql(backEnd, connectString);
27 
28  {
29  std::time_t now = std::time(NULL);
30  std::tm t1, t2;
31  t2 = *std::localtime(&now);
32 
33  sql << "select t from (select :t as t from dual)",
34  into(t1), use(t2);
35 
36  assert(t1.tm_sec == t2.tm_sec);
37  assert(t1.tm_min == t2.tm_min);
38  assert(t1.tm_hour == t2.tm_hour);
39  assert(t1.tm_mday == t2.tm_mday);
40  assert(t1.tm_mon == t2.tm_mon);
41  assert(t1.tm_year == t2.tm_year);
42  assert(t1.tm_wday == t2.tm_wday);
43  assert(t1.tm_yday == t2.tm_yday);
44  assert(t1.tm_isdst == t2.tm_isdst);
45 
46  // make sure the date is stored properly in Oracle
47  char buf[25];
48  strftime(buf, sizeof(buf), "%m-%d-%Y %H:%M:%S", &t2);
49 
50  std::string t_out;
51  std::string format("MM-DD-YYYY HH24:MI:SS");
52  sql << "select to_char(t, :format) from (select :t as t from dual)",
53  into(t_out), use(format), use(t2);
54 
55  assert(t_out == std::string(buf));
56  }
57 
58  {
59  // date and time - before year 2000
60  std::time_t then = std::time(NULL) - 17*365*24*60*60;
61  std::tm t1, t2;
62  t2 = *std::localtime(&then);
63 
64  sql << "select t from (select :t as t from dual)",
65  into(t1), use(t2);
66 
67  assert(t1.tm_sec == t2.tm_sec);
68  assert(t1.tm_min == t2.tm_min);
69  assert(t1.tm_hour == t2.tm_hour);
70  assert(t1.tm_mday == t2.tm_mday);
71  assert(t1.tm_mon == t2.tm_mon);
72  assert(t1.tm_year == t2.tm_year);
73  assert(t1.tm_wday == t2.tm_wday);
74  assert(t1.tm_yday == t2.tm_yday);
75  assert(t1.tm_isdst == t2.tm_isdst);
76 
77  // make sure the date is stored properly in Oracle
78  char buf[25];
79  strftime(buf, sizeof(buf), "%m-%d-%Y %H:%M:%S", &t2);
80 
81  std::string t_out;
82  std::string format("MM-DD-YYYY HH24:MI:SS");
83  sql << "select to_char(t, :format) from (select :t as t from dual)",
84  into(t_out), use(format), use(t2);
85 
86  assert(t_out == std::string(buf));
87  }
88 
89  std::cout << "test 1 passed" << std::endl;
90 }
91 
92 // explicit calls test
93 void test2()
94 {
95  session sql(backEnd, connectString);
96 
97  statement st(sql);
98  st.alloc();
99  int i = 0;
100  st.exchange(into(i));
101  st.prepare("select 7 from dual");
102  st.define_and_bind();
103  st.execute(1);
104  assert(i == 7);
105 
106  std::cout << "test 2 passed" << std::endl;
107 }
108 
109 // DDL + blob test
110 
112 {
114  : table_creator_base(sql)
115  {
116  sql <<
117  "create table soci_test ("
118  " id number(10) not null,"
119  " img blob"
120  ")";
121  }
122 };
123 
124 void test3()
125 {
126  session sql(backEnd, connectString);
127 
128  blob_table_creator tableCreator(sql);
129 
130  char buf[] = "abcdefghijklmnopqrstuvwxyz";
131  sql << "insert into soci_test (id, img) values (7, empty_blob())";
132 
133  {
134  blob b(sql);
135 
136  oracle_session_backend *sessionBackEnd
137  = static_cast<oracle_session_backend *>(sql.get_backend());
138 
139  oracle_blob_backend *blobBackEnd
140  = static_cast<oracle_blob_backend *>(b.get_backend());
141 
142  OCILobDisableBuffering(sessionBackEnd->svchp_,
143  sessionBackEnd->errhp_, blobBackEnd->lobp_);
144 
145  sql << "select img from soci_test where id = 7", into(b);
146  assert(b.get_len() == 0);
147 
148  // note: blob offsets start from 1
149  b.write(1, buf, sizeof(buf));
150  assert(b.get_len() == sizeof(buf));
151  b.trim(10);
152  assert(b.get_len() == 10);
153 
154  // append does not work (Oracle bug #886191 ?)
155  //b.append(buf, sizeof(buf));
156  //assert(b.get_len() == sizeof(buf) + 10);
157  sql.commit();
158  }
159 
160  {
161  blob b(sql);
162  sql << "select img from soci_test where id = 7", into(b);
163  //assert(b.get_len() == sizeof(buf) + 10);
164  assert(b.get_len() == 10);
165  char buf2[100];
166  b.read(1, buf2, 10);
167  assert(strncmp(buf2, "abcdefghij", 10) == 0);
168  }
169 
170  std::cout << "test 3 passed" << std::endl;
171 }
172 
173 // nested statement test
174 // (the same syntax is used for output cursors in PL/SQL)
175 
177 {
179  : table_creator_base(sql)
180  {
181  sql <<
182  "create table soci_test ("
183  " id number(5) not null,"
184  " name varchar2(100),"
185  " code number(5)"
186  ")";
187  }
188 };
189 
190 void test4()
191 {
192  session sql(backEnd, connectString);
193  basic_table_creator tableCreator(sql);
194 
195  int id;
196  std::string name;
197  {
198  statement st1 = (sql.prepare <<
199  "insert into soci_test (id, name) values (:id, :name)",
200  use(id), use(name));
201 
202  id = 1; name = "John"; st1.execute(1);
203  id = 2; name = "Anna"; st1.execute(1);
204  id = 3; name = "Mike"; st1.execute(1);
205  }
206 
207  statement stInner(sql);
208  statement stOuter = (sql.prepare <<
209  "select cursor(select name from soci_test order by id)"
210  " from soci_test where id = 1",
211  into(stInner));
212  stInner.exchange(into(name));
213  stOuter.execute();
214  stOuter.fetch();
215 
216  std::vector<std::string> names;
217  while (stInner.fetch()) { names.push_back(name); }
218 
219  assert(names.size() == 3);
220  assert(names[0] == "John");
221  assert(names[1] == "Anna");
222  assert(names[2] == "Mike");
223 
224  std::cout << "test 4 passed" << std::endl;
225 }
226 
227 
228 // ROWID test
229 void test5()
230 {
231  session sql(backEnd, connectString);
232  basic_table_creator tableCreator(sql);
233 
234  sql << "insert into soci_test(id, name) values(7, \'John\')";
235 
236  rowid rid(sql);
237  sql << "select rowid from soci_test where id = 7", into(rid);
238 
239  int id;
240  std::string name;
241  sql << "select id, name from soci_test where rowid = :rid",
242  into(id), into(name), use(rid);
243 
244  assert(id == 7);
245  assert(name == "John");
246 
247  std::cout << "test 5 passed" << std::endl;
248 }
249 
250 // Stored procedures
252 {
255  {
256  sql <<
257  "create or replace procedure soci_test(output out varchar2,"
258  "input in varchar2) as "
259  "begin output := input; end;";
260  }
261 };
262 
263 void test6()
264 {
265  {
266  session sql(backEnd, connectString);
268 
269  std::string in("my message");
270  std::string out;
271  statement st = (sql.prepare <<
272  "begin soci_test(:output, :input); end;",
273  use(out, "output"),
274  use(in, "input"));
275  st.execute(1);
276  assert(out == in);
277 
278  // explicit procedure syntax
279  {
280  std::string in("my message2");
281  std::string out;
282  procedure proc = (sql.prepare <<
283  "soci_test(:output, :input)",
284  use(out, "output"), use(in, "input"));
285  proc.execute(1);
286  assert(out == in);
287  }
288  }
289 
290  std::cout << "test 6 passed" << std::endl;
291 }
292 
293 // bind into user-defined objects
295 {
297  string_holder(const char* s) : s_(s) {}
298  string_holder(std::string s) : s_(s) {}
299  std::string get() const { return s_; }
300 private:
301  std::string s_;
302 };
303 
304 namespace soci
305 {
306  template <>
308  {
309  typedef std::string base_type;
310  static void from_base(const std::string &s, indicator /* ind */,
311  string_holder &sh)
312  {
313  sh = string_holder(s);
314  }
315 
316  static void to_base(const string_holder &sh, std::string &s, indicator &ind)
317  {
318  s = sh.get();
319  ind = i_ok;
320  }
321  };
322 }
323 
325 {
328  {
329  sql << "create or replace procedure soci_test(s in out varchar2)"
330  " as begin s := s || s; end;";
331  }
332 };
333 
335 {
338  {
339  sql << "create or replace procedure soci_test(s in out varchar2)"
340  " as begin s := NULL; end;";
341  }
342 };
343 
344 void test7()
345 {
346  {
347  session sql(backEnd, connectString);
348  {
349  basic_table_creator tableCreator(sql);
350 
351  int id(1);
352  string_holder in("my string");
353  sql << "insert into soci_test(id, name) values(:id, :name)", use(id), use(in);
354 
355  string_holder out;
356  sql << "select name from soci_test", into(out);
357  assert(out.get() == "my string");
358 
359  row r;
360  sql << "select * from soci_test", into(r);
361  string_holder dynamicOut = r.get<string_holder>(1);
362  assert(dynamicOut.get() == "my string");
363  }
364  }
365  std::cout << "test 7 passed" << std::endl;
366 }
367 
369 {
370  {
371  session sql(backEnd, connectString);
372 
373  // test procedure with user-defined type as in-out parameter
374  {
375  in_out_procedure_creator procedureCreator(sql);
376 
377  std::string sh("test");
378  procedure proc = (sql.prepare << "soci_test(:s)", use(sh));
379  proc.execute(1);
380  assert(sh == "testtest");
381  }
382 
383  // test procedure with user-defined type as in-out parameter
384  {
385  in_out_procedure_creator procedureCreator(sql);
386 
387  string_holder sh("test");
388  procedure proc = (sql.prepare << "soci_test(:s)", use(sh));
389  proc.execute(1);
390  assert(sh.get() == "testtest");
391  }
392  }
393  std::cout << "test 7-inout passed" << std::endl;
394 }
395 
397 {
398  {
399  session sql(backEnd, connectString);
400 
401  // test procedure which returns null
402  {
403  returns_null_procedure_creator procedureCreator(sql);
404 
405  string_holder sh;
406  indicator ind = i_ok;
407  procedure proc = (sql.prepare << "soci_test(:s)", use(sh, ind));
408  proc.execute(1);
409  assert(ind == i_null);
410  }
411  }
412  std::cout << "test 7-outnull passed" << std::endl;
413 }
414 
415 // test bulk insert features
416 void test8()
417 {
418  session sql(backEnd, connectString);
419 
420  basic_table_creator tableCreator(sql);
421 
422  // verify exception is thrown if vectors of unequal size are passed in
423  {
424  std::vector<int> ids;
425  ids.push_back(1);
426  ids.push_back(2);
427  std::vector<int> codes;
428  codes.push_back(1);
429  std::string error;
430 
431  try
432  {
433  sql << "insert into soci_test(id,code) values(:id,:code)",
434  use(ids), use(codes);
435  }
436  catch (soci_error const &e)
437  {
438  error = e.what();
439  }
440  assert(error.find("Bind variable size mismatch")
441  != std::string::npos);
442 
443  try
444  {
445  sql << "select from soci_test", into(ids), into(codes);
446  }
447  catch (std::exception const &e)
448  {
449  error = e.what();
450  }
451  assert(error.find("Bind variable size mismatch")
452  != std::string::npos);
453  }
454 
455  // verify partial insert occurs when one of the records is bad
456  {
457  std::vector<int> ids;
458  ids.push_back(100);
459  ids.push_back(1000000); // too big for column
460 
461  std::string error;
462  try
463  {
464  sql << "insert into soci_test (id) values(:id)", use(ids, "id");
465  }
466  catch (soci_error const &e)
467  {
468  error = e.what();
469  //TODO e could be made to tell which row(s) failed
470  }
471  sql.commit();
472  assert(error.find("ORA-01438") != std::string::npos);
473  int count(7);
474  sql << "select count(*) from soci_test", into(count);
475  assert(count == 1);
476  sql << "delete from soci_test";
477  }
478 
479  // test insert
480  {
481  std::vector<int> ids;
482  for (int i = 0; i != 3; ++i)
483  {
484  ids.push_back(i+10);
485  }
486 
487  statement st = (sql.prepare << "insert into soci_test(id) values(:id)",
488  use(ids));
489  st.execute(1);
490  int count;
491  sql << "select count(*) from soci_test", into(count);
492  assert(count == 3);
493  }
494 
495  //verify an exception is thrown if into vector is zero length
496  {
497  std::vector<int> ids;
498  bool caught(false);
499  try
500  {
501  sql << "select id from soci_test", into(ids);
502  }
503  catch (soci_error const &)
504  {
505  caught = true;
506  }
507  assert(caught);
508  }
509 
510  // verify an exception is thrown if use vector is zero length
511  {
512  std::vector<int> ids;
513  bool caught(false);
514  try
515  {
516  sql << "insert into soci_test(id) values(:id)", use(ids);
517  }
518  catch (soci_error const &)
519  {
520  caught = true;
521  }
522  assert(caught);
523  }
524 
525  // test "no data" condition
526  {
527  std::vector<indicator> inds(3);
528  std::vector<int> ids_out(3);
529  statement st = (sql.prepare << "select id from soci_test where 1=0",
530  into(ids_out, inds));
531 
532  // false return value means "no data"
533  assert(st.execute(1) == false);
534 
535  // that's it - nothing else is guaranteed
536  // and nothing else is to be tested here
537  }
538 
539  // test NULL indicators
540  {
541  std::vector<int> ids(3);
542  sql << "select id from soci_test", into(ids);
543 
544  std::vector<indicator> inds_in;
545  inds_in.push_back(i_ok);
546  inds_in.push_back(i_null);
547  inds_in.push_back(i_ok);
548 
549  std::vector<int> new_codes;
550  new_codes.push_back(10);
551  new_codes.push_back(11);
552  new_codes.push_back(10);
553 
554  sql << "update soci_test set code = :code where id = :id",
555  use(new_codes, inds_in), use(ids);
556 
557  std::vector<indicator> inds_out(3);
558  std::vector<int> codes(3);
559 
560  sql << "select code from soci_test", into(codes, inds_out);
561  assert(codes.size() == 3 && inds_out.size() == 3);
562  assert(codes[0] == 10 && codes[2] == 10);
563  assert(inds_out[0] == i_ok && inds_out[1] == i_null
564  && inds_out[2] == i_ok);
565  }
566 
567  // verify an exception is thrown if null is selected
568  // and no indicator was provided
569  {
570  std::string msg;
571  std::vector<int> intos(3);
572  try
573  {
574  sql << "select code from soci_test", into(intos);
575  }
576  catch (soci_error const &e)
577  {
578  msg = e.what();
579  }
580  assert(msg == "Null value fetched and no indicator defined." );
581  }
582 
583  // test basic select
584  {
585  const size_t sz = 3;
586  std::vector<indicator> inds(sz);
587  std::vector<int> ids_out(sz);
588  statement st = (sql.prepare << "select id from soci_test",
589  into(ids_out, inds));
590  const bool gotData = st.execute(true);
591  assert(gotData);
592  assert(ids_out.size() == sz);
593  assert(ids_out[0] == 10);
594  assert(ids_out[2] == 12);
595  assert(inds.size() == 3 && inds[0] == i_ok
596  && inds[1] == i_ok && inds[2] == i_ok);
597  }
598 
599  // verify execute(0)
600  {
601  std::vector<int> ids_out(2);
602  statement st = (sql.prepare << "select id from soci_test",
603  into(ids_out));
604 
605  st.execute();
606  assert(ids_out.size() == 2);
607  bool gotData = st.fetch();
608  assert(gotData);
609  assert(ids_out.size() == 2 && ids_out[0] == 10 && ids_out[1] == 11);
610  gotData = st.fetch();
611  assert(gotData);
612  assert(ids_out.size() == 1 && ids_out[0] == 12);
613  gotData = st.fetch();
614  assert(gotData == false);
615  }
616 
617  // verify resizing happens if vector is larger
618  // than number of rows returned
619  {
620  std::vector<int> ids_out(4); // one too many
621  statement st2 = (sql.prepare << "select id from soci_test",
622  into(ids_out));
623  bool gotData = st2.execute(true);
624  assert(gotData);
625  assert(ids_out.size() == 3);
626  assert(ids_out[0] == 10);
627  assert(ids_out[2] == 12);
628  }
629 
630  // verify resizing happens properly during fetch()
631  {
632  std::vector<int> more;
633  more.push_back(13);
634  more.push_back(14);
635  sql << "insert into soci_test(id) values(:id)", use(more);
636 
637  std::vector<int> ids(2);
638  statement st3 = (sql.prepare << "select id from soci_test", into(ids));
639  bool gotData = st3.execute(true);
640  assert(gotData);
641  assert(ids[0] == 10);
642  assert(ids[1] == 11);
643 
644  gotData = st3.fetch();
645  assert(gotData);
646  assert(ids[0] == 12);
647  assert(ids[1] == 13);
648 
649  gotData = st3.fetch();
650  assert(gotData);
651  assert(ids.size() == 1);
652  assert(ids[0] == 14);
653 
654  gotData = st3.fetch();
655  assert(gotData == false);
656  }
657 
658  std::cout << "test 8 passed" << std::endl;
659 }
660 
661 // more tests for bulk fetch
662 void test9()
663 {
664  session sql(backEnd, connectString);
665 
666  basic_table_creator tableCreator(sql);
667 
668  std::vector<int> in;
669  for (int i = 1; i <= 10; ++i)
670  {
671  in.push_back(i);
672  }
673 
674  sql << "insert into soci_test (id) values(:id)", use(in);
675 
676  int count(0);
677  sql << "select count(*) from soci_test", into(count);
678  assert(count == 10);
679 
680  // verify that the exception is thrown when trying to resize
681  // the output vector to the size that is bigger than that
682  // at the time of binding
683  {
684  std::vector<int> out(4);
685  statement st = (sql.prepare <<
686  "select id from soci_test", into(out));
687 
688  st.execute();
689 
690  st.fetch();
691  assert(out.size() == 4);
692  assert(out[0] == 1);
693  assert(out[1] == 2);
694  assert(out[2] == 3);
695  assert(out[3] == 4);
696  out.resize(5); // this should be detected as error
697  try
698  {
699  st.fetch();
700  assert(false); // should never reach here
701  }
702  catch (soci_error const &e)
703  {
704  assert(std::string(e.what()) ==
705  "Increasing the size of the output vector is not supported.");
706  }
707  }
708 
709  // on the other hand, downsizing is OK
710  {
711  std::vector<int> out(4);
712  statement st = (sql.prepare <<
713  "select id from soci_test", into(out));
714 
715  st.execute();
716 
717  st.fetch();
718  assert(out.size() == 4);
719  assert(out[0] == 1);
720  assert(out[1] == 2);
721  assert(out[2] == 3);
722  assert(out[3] == 4);
723  out.resize(3); // ok
724  st.fetch();
725  assert(out.size() == 3);
726  assert(out[0] == 5);
727  assert(out[1] == 6);
728  assert(out[2] == 7);
729  out.resize(4); // ok, not bigger than initially
730  st.fetch();
731  assert(out.size() == 3); // downsized because of end of data
732  assert(out[0] == 8);
733  assert(out[1] == 9);
734  assert(out[2] == 10);
735  bool gotData = st.fetch();
736  assert(gotData == false); // end of data
737  }
738 
739  std::cout << "test 9 passed" << std::endl;
740 }
741 
742 struct person
743 {
744  int id;
745  std::string firstName;
746  string_holder lastName; //test mapping of type_conversion-based types
747  std::string gender;
748 };
749 
750 // Object-Relational Mapping
751 // Note: Use the values class as shown below in type_conversions
752 // to achieve object relational mapping. The values class should
753 // not be used directly in any other fashion.
754 namespace soci
755 {
756  // name-based conversion
757  template<> struct type_conversion<person>
758  {
759  typedef values base_type;
760 
761  static void from_base(values const &v, indicator /* ind */, person &p)
762  {
763  // ignoring possibility that the whole object might be NULL
764 
765  p.id = v.get<int>("ID");
766  p.firstName = v.get<std::string>("FIRST_NAME");
767  p.lastName = v.get<string_holder>("LAST_NAME");
768  p.gender = v.get<std::string>("GENDER", "unknown");
769  }
770 
771  static void to_base(person const & p, values & v, indicator & ind)
772  {
773  v.set("ID", p.id);
774  v.set("FIRST_NAME", p.firstName);
775  v.set("LAST_NAME", p.lastName);
776  v.set("GENDER", p.gender, p.gender.empty() ? i_null : i_ok);
777  ind = i_ok;
778  }
779  };
780 }
781 
783 {
785  : table_creator_base(sql)
786  {
787  sql << "create table soci_test(id numeric(5,0) NOT NULL,"
788  << " last_name varchar2(20), first_name varchar2(20), "
789  " gender varchar2(10))";
790  }
791 };
792 
794 {
797  {
798  sql << "create or replace procedure soci_test(id in out number)"
799  " as begin id := id * 100; end;";
800  }
801 };
802 
803 void test10()
804 {
805  session sql(backEnd, connectString);
806 
807  {
808  person_table_creator tableCreator(sql);
809 
810  person p;
811  p.id = 1;
812  p.lastName = "Smith";
813  p.firstName = "Pat";
814  sql << "insert into soci_test(id, first_name, last_name, gender) "
815  << "values(:ID, :FIRST_NAME, :LAST_NAME, :GENDER)", use(p);
816 
817  // p should be unchanged
818  assert(p.id == 1);
819  assert(p.firstName == "Pat");
820  assert(p.lastName.get() == "Smith");
821 
822  person p1;
823  sql << "select * from soci_test", into(p1);
824  assert(p1.id == 1);
825  assert(p1.firstName + p1.lastName.get() == "PatSmith");
826  assert(p1.gender == "unknown");
827 
828  p.firstName = "Patricia";
829  sql << "update soci_test set first_name = :FIRST_NAME "
830  "where id = :ID", use(p);
831 
832  // p should be unchanged
833  assert(p.id == 1);
834  assert(p.firstName == "Patricia");
835  assert(p.lastName.get() == "Smith");
836  // Note: gender is now "unknown" because of the mapping, not ""
837  assert(p.gender == "unknown");
838 
839  person p2;
840  sql << "select * from soci_test", into(p2);
841  assert(p2.id == 1);
842  assert(p2.firstName + p2.lastName.get() == "PatriciaSmith");
843 
844  // insert a second row so we can test fetching
845  person p3;
846  p3.id = 2;
847  p3.firstName = "Joe";
848  p3.lastName = "Smith";
849  sql << "insert into soci_test(id, first_name, last_name, gender) "
850  << "values(:ID, :FIRST_NAME, :LAST_NAME, :GENDER)", use(p3);
851 
852  person p4;
853  statement st = (sql.prepare << "select * from soci_test order by id",
854  into(p4));
855 
856  st.execute();
857  bool gotData = st.fetch();
858  assert(gotData);
859  assert(p4.id == 1);
860  assert(p4.firstName == "Patricia");
861 
862  gotData = st.fetch();
863  assert(gotData);
864  assert(p4.id == 2);
865  assert(p4.firstName == "Joe");
866  gotData = st.fetch();
867  assert(gotData == false);
868  }
869 
870  // test with stored procedure
871  {
872  times100_procedure_creator procedureCreator(sql);
873 
874  person p;
875  p.id = 1;
876  p.firstName = "Pat";
877  p.lastName = "Smith";
878  procedure proc = (sql.prepare << "soci_test(:ID)", use(p));
879  proc.execute(1);
880  assert(p.id == 100);
881  assert(p.firstName == "Pat");
882  assert(p.lastName.get() == "Smith");
883  }
884 
885  // test with stored procedure which returns null
886  {
887  returns_null_procedure_creator procedureCreator(sql);
888 
889  std::string msg;
890  person p;
891  try
892  {
893  procedure proc = (sql.prepare << "soci_test(:FIRST_NAME)",
894  use(p));
895  proc.execute(1);
896  }
897  catch (soci_error& e)
898  {
899  msg = e.what();
900  }
901  assert(msg == "Null value not allowed for this type");
902 
903  procedure proc = (sql.prepare << "soci_test(:GENDER)",
904  use(p));
905  proc.execute(1);
906  assert(p.gender == "unknown");
907 
908  }
909  std::cout << "test 10 passed" << std::endl;
910 }
911 
912 // Experimental support for position based O/R Mapping
913 
914 // additional type for position-based test
915 struct person2
916 {
917  int id;
918  std::string firstName;
919  std::string lastName;
920  std::string gender;
921 };
922 
923 // additional type for stream-like test
924 struct person3 : person2 {};
925 
926 namespace soci
927 {
928  // position-based conversion
929  template<> struct type_conversion<person2>
930  {
931  typedef values base_type;
932 
933  static void from_base(values const &v, indicator /* ind */, person2 &p)
934  {
935  p.id = v.get<int>(0);
936  p.firstName = v.get<std::string>(1);
937  p.lastName = v.get<std::string>(2);
938  p.gender = v.get<std::string>(3, "whoknows");
939  }
940 
941  // What about the "to" part? Does it make any sense to have it?
942  };
943 
944  // stream-like conversion
945  template<> struct type_conversion<person3>
946  {
947  typedef values base_type;
948 
949  static void from_base(values const &v, indicator /* ind */, person3 &p)
950  {
951  v >> p.id >> p.firstName >> p.lastName >> p.gender;
952  }
953  // TODO: The "to" part is certainly needed.
954  };
955 }
956 
957 void test11()
958 {
959  session sql(backEnd, connectString);
960 
961  person_table_creator tableCreator(sql);
962 
963  person p;
964  p.id = 1;
965  p.lastName = "Smith";
966  p.firstName = "Patricia";
967  sql << "insert into soci_test(id, first_name, last_name, gender) "
968  << "values(:ID, :FIRST_NAME, :LAST_NAME, :GENDER)", use(p);
969 
970  // test position-based conversion
971  person2 p3;
972  sql << "select id, first_name, last_name, gender from soci_test", into(p3);
973  assert(p3.id == 1);
974  assert(p3.firstName + p3.lastName == "PatriciaSmith");
975  assert(p3.gender == "whoknows");
976 
977  sql << "update soci_test set gender = 'F' where id = 1";
978 
979  // additional test for stream-like conversion
980  person3 p4;
981  sql << "select id, first_name, last_name, gender from soci_test", into(p4);
982  assert(p4.id == 1);
983  assert(p4.firstName + p4.lastName == "PatriciaSmith");
984  assert(p4.gender == "F");
985 
986  std::cout << "test 11 passed" << std::endl;
987 }
988 
989 //
990 // Backwards compatibility - support use of large strings with
991 // columns of type LONG
994 {
996  : table_creator_base(sql)
997  {
998  sql << "create table soci_test(l long)";
999  }
1000 };
1001 
1002 void test12()
1003 {
1004  session sql(backEnd, connectString);
1005  long_table_creator creator(sql);
1006 
1007  const std::string::size_type max = 32768;
1008  std::string in(max, 'X');
1009 
1010  sql << "insert into soci_test values(:l)", use(in);
1011 
1012  std::string out;
1013  sql << "select l from soci_test", into(out);
1014 
1015  assert(out.size() == max);
1016  assert(in == out);
1017 
1018  std::cout << "test 12 passed" << std::endl;
1019 }
1020 
1021 // test for modifiable and const use elements
1022 void test13()
1023 {
1024  session sql(backEnd, connectString);
1025 
1026  int i = 7;
1027  sql << "begin "
1028  "select 2 * :i into :i from dual; "
1029  "end;", use(i);
1030  assert(i == 14);
1031 
1032  const int j = 7;
1033  try
1034  {
1035  sql << "begin "
1036  "select 2 * :i into :i from dual;"
1037  " end;", use(j);
1038 
1039  assert(false); // should never get here
1040  }
1041  catch (soci_error const & e)
1042  {
1043  const std::string msg = e.what();
1044  assert(msg == "Attempted modification of const use element");
1045  }
1046 
1047  std::cout << "test 13 passed" << std::endl;
1048 }
1049 
1051 {
1053  : table_creator_base(sql)
1054  {
1055  sql << "create table soci_test(val number(20))";
1056  }
1057 };
1058 
1059 // long long test
1060 void test14()
1061 {
1062  {
1063  session sql(backEnd, connectString);
1064 
1065  longlong_table_creator tableCreator(sql);
1066 
1067  long long v1 = 1000000000000LL;
1068  assert(v1 / 1000000 == 1000000);
1069 
1070  sql << "insert into soci_test(val) values(:val)", use(v1);
1071 
1072  long long v2 = 0LL;
1073  sql << "select val from soci_test", into(v2);
1074 
1075  assert(v2 == v1);
1076  }
1077 
1078  // vector<long long>
1079  {
1080  session sql(backEnd, connectString);
1081 
1082  longlong_table_creator tableCreator(sql);
1083 
1084  std::vector<long long> v1;
1085  v1.push_back(1000000000000LL);
1086  v1.push_back(1000000000001LL);
1087  v1.push_back(1000000000002LL);
1088  v1.push_back(1000000000003LL);
1089  v1.push_back(1000000000004LL);
1090 
1091  sql << "insert into soci_test(val) values(:val)", use(v1);
1092 
1093  std::vector<long long> v2(10);
1094  sql << "select val from soci_test order by val desc", into(v2);
1095 
1096  assert(v2.size() == 5);
1097  assert(v2[0] == 1000000000004LL);
1098  assert(v2[1] == 1000000000003LL);
1099  assert(v2[2] == 1000000000002LL);
1100  assert(v2[3] == 1000000000001LL);
1101  assert(v2[4] == 1000000000000LL);
1102  }
1103 
1104  std::cout << "test 14 passed" << std::endl;
1105 }
1106 
1107 //
1108 // Support for soci Common Tests
1109 //
1110 
1111 struct table_creator_one : public table_creator_base
1112 {
1114  : table_creator_base(sql)
1115  {
1116  sql << "create table soci_test(id number(10,0), val number(4,0), c char, "
1117  "str varchar2(20), sh number, ul number, d number, "
1118  "tm date, i1 number, i2 number, i3 number, name varchar2(20))";
1119  }
1120 };
1121 
1122 struct table_creator_two : public table_creator_base
1123 {
1125  : table_creator_base(sql)
1126  {
1127  sql << "create table soci_test(num_float number, num_int numeric(4,0),"
1128  " name varchar2(20), sometime date, chr char)";
1129  }
1130 };
1131 
1133 {
1135  : table_creator_base(sql)
1136  {
1137  sql << "create table soci_test(name varchar2(100) not null, "
1138  "phone varchar2(15))";
1139  }
1140 };
1141 
1143 {
1145  : table_creator_base(sql)
1146  {
1147  sql << "create table soci_test(val number)";
1148  }
1149 };
1150 
1151 class test_context :public test_context_base
1152 {
1153 public:
1155  std::string const &connectString)
1156  : test_context_base(backEnd, connectString) {}
1157 
1159  {
1160  return new table_creator_one(s);
1161  }
1162 
1164  {
1165  return new table_creator_two(s);
1166  }
1167 
1169  {
1170  return new table_creator_three(s);
1171  }
1172 
1174  {
1175  return new table_creator_four(s);
1176  }
1177 
1178  std::string to_date_time(std::string const &datdt_string) const
1179  {
1180  return "to_date('" + datdt_string + "', 'YYYY-MM-DD HH24:MI:SS')";
1181  }
1182 };
1183 
1184 int main(int argc, char** argv)
1185 {
1186 #ifdef _MSC_VER
1187  // Redirect errors, unrecoverable problems, and assert() failures to STDERR,
1188  // instead of debug message window.
1189  // This hack is required to run asser()-driven tests by Buildbot.
1190  // NOTE: Comment this 2 lines for debugging with Visual C++ debugger to catch assertions inside.
1191  _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
1192  _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
1193 #endif //_MSC_VER
1194 
1195  if (argc == 2)
1196  {
1197  connectString = argv[1];
1198  }
1199  else
1200  {
1201  std::cout << "usage: " << argv[0]
1202  << " connectstring\n"
1203  << "example: " << argv[0]
1204  << " \'service=orcl user=scott password=tiger\'\n";
1205  std::exit(1);
1206  }
1207 
1208  try
1209  {
1210  test_context tc(backEnd, connectString);
1211  common_tests tests(tc);
1212  tests.run();
1213 
1214  std::cout << "\nsoci Oracle tests:\n\n";
1215  test1();
1216  test2();
1217  test3();
1218  test4();
1219  test5();
1220  test6();
1221  test7();
1222  test7inout();
1223  test7outnull();
1224  test8();
1225  test9();
1226  test10();
1227  test11();
1228  test12();
1229  test13();
1230  test14();
1231 
1232  std::cout << "\nOK, all tests passed.\n\n";
1233 
1234  return EXIT_SUCCESS;
1235  }
1236  catch (std::exception const & e)
1237  {
1238  std::cout << e.what() << '\n';
1239  }
1240  return EXIT_FAILURE;
1241 }
void test13()
details::into_container< T, details::no_indicator > into(T &t)
Definition: into.h:51
static void from_base(const std::string &s, indicator, string_holder &sh)
void set(std::string const &name, T const &value, indicator indic=i_ok)
Definition: values.h:166
void test4()
test_context(backend_factory const &backEnd, std::string const &connectString)
void test7()
table_creator_four(session &sql)
table_creator_base * table_creator_2(session &s) const
void test1()
Definition: test-oracle.cpp:24
void run(bool dbSupportsTransactions=true)
Definition: common-tests.h:293
std::string firstName
std::string firstName
SOCI_ORACLE_DECL backend_factory const * factory_oracle()
Definition: row.h:41
details::session_backend * get_backend()
Definition: session.h:118
void test11()
void trim(std::size_t newLen)
Definition: core/blob.cpp:47
std::size_t read(std::size_t offset, char *buf, std::size_t toRead)
Definition: core/blob.cpp:31
std::string get() const
in_out_procedure_creator(session &sql)
void test8()
static void to_base(person const &p, values &v, indicator &ind)
string_holder(const char *s)
table_creator_one(session &sql)
backend_factory const & backEnd
Definition: test-oracle.cpp:21
table_creator_base * table_creator_4(session &s) const
std::string gender
void test2()
Definition: test-oracle.cpp:93
times100_procedure_creator(session &sql)
static void from_base(values const &v, indicator, person2 &p)
void test7inout()
void prepare(std::string const &query, details::statement_type eType=details::st_repeatable_query)
Definition: statement.h:200
static void from_base(values const &v, indicator, person3 &p)
bool execute(bool withDataExchange=false)
Definition: procedure.h:65
static void from_base(values const &v, indicator, person &p)
blob_table_creator(session &sql)
void test9()
string_holder(std::string s)
void test5()
void test10()
void test12()
returns_null_procedure_creator(session &sql)
table_creator_base * table_creator_1(session &s) const
std::string lastName
longlong_table_creator(session &sql)
table_creator_base * table_creator_3(session &s) const
std::string connectString
Definition: test-oracle.cpp:20
void test14()
person_table_creator(session &sql)
void define_and_bind()
Definition: statement.h:206
procedure_creator(session &sql)
long_table_creator(session &sql)
details::blob_backend * get_backend()
Definition: blob.h:39
void test3()
std::string s_
T get(std::size_t pos) const
Definition: values.h:58
std::string to_date_time(std::string const &datdt_string) const
basic_table_creator(session &sql)
std::size_t get_len()
Definition: core/blob.cpp:26
table_creator_two(session &sql)
OCILobLocator * lobp_
Definition: soci-oracle.h:240
int main(int argc, char **argv)
details::prepare_type prepare
Definition: session.h:69
static void to_base(const string_holder &sh, std::string &s, indicator &ind)
std::string gender
void exchange(details::into_type_ptr const &i)
Definition: statement.h:192
table_creator_three(session &sql)
details::use_container< T, details::no_indicator > use(T &t, const std::string &name=std::string())
Definition: use.h:43
void test6()
string_holder lastName
bool execute(bool withDataExchange=false)
Definition: statement.h:208
void test7outnull()
std::size_t write(std::size_t offset, char const *buf, std::size_t toWrite)
Definition: core/blob.cpp:36


asr_lib_ism
Author(s): Hanselmann Fabian, Heller Florian, Heizmann Heinrich, Kübler Marcel, Mehlhaus Jonas, Meißner Pascal, Qattan Mohamad, Reckling Reno, Stroh Daniel
autogenerated on Wed Jan 8 2020 04:02:41