common-tests.h
Go to the documentation of this file.
1 //
2 // Copyright (C) 2004-2008 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 #ifndef SOCI_COMMON_TESTS_H_INCLUDED
9 #define SOCI_COMMON_TESTS_H_INCLUDED
10 
11 #include "soci.h"
12 #include "soci-config.h"
13 
14 #ifdef HAVE_BOOST
15 // explicitly pull conversions for Boost's optional, tuple and fusion:
16 #include <boost/version.hpp>
17 #include <boost-optional.h>
18 #include <boost-tuple.h>
19 #include <boost-gregorian-date.h>
20 #if defined(BOOST_VERSION) && BOOST_VERSION >= 103500
21 #include <boost-fusion.h>
22 #include <boost-tuple.h>
23 #endif // BOOST_VERSION
24 #endif // HAVE_BOOST
25 
26 #include <algorithm>
27 #include <cmath>
28 #include <iostream>
29 #include <limits>
30 #include <string>
31 #include <typeinfo>
32 
33 // Objects used later in tests 14,15
35 {
36  std::string name;
37  std::string phone;
38 };
39 
41 {
42 };
43 
45 {
46 public:
47  void setName(std::string const & n) { name_ = n; }
48  std::string getName() const { return name_; }
49 
50  void setPhone(std::string const & p) { phone_ = p; }
51  std::string getPhone() const { return phone_; }
52 
53 public:
54  std::string name_;
55  std::string phone_;
56 };
57 
58 // user-defined object for test26 and test28
59 class MyInt
60 {
61 public:
62  MyInt() {}
63  MyInt(int i) : i_(i) {}
64  void set(int i) { i_ = i; }
65  int get() const { return i_; }
66 private:
67  int i_;
68 };
69 
70 namespace soci
71 {
72 
73 // basic type conversion for user-defined type with single base value
74 template<> struct type_conversion<MyInt>
75 {
76  typedef int base_type;
77 
78  static void from_base(int i, indicator ind, MyInt &mi)
79  {
80  if (ind == i_ok)
81  {
82  mi.set(i);
83  }
84  }
85 
86  static void to_base(MyInt const &mi, int &i, indicator &ind)
87  {
88  i = mi.get();
89  ind = i_ok;
90  }
91 };
92 
93 // basic type conversion on many values (ORM)
94 template<> struct type_conversion<PhonebookEntry>
95 {
97 
98  static void from_base(values const &v, indicator /* ind */, PhonebookEntry &pe)
99  {
100  // here we ignore the possibility the the whole object might be NULL
101  pe.name = v.get<std::string>("NAME");
102  pe.phone = v.get<std::string>("PHONE", "<NULL>");
103  }
104 
105  static void to_base(PhonebookEntry const &pe, values &v, indicator &ind)
106  {
107  v.set("NAME", pe.name);
108  v.set("PHONE", pe.phone, pe.phone.empty() ? i_null : i_ok);
109  ind = i_ok;
110  }
111 };
112 
113 // type conversion which directly calls values::get_indicator()
115 {
117 
118  static void from_base(values const &v, indicator /* ind */, PhonebookEntry2 &pe)
119  {
120  // here we ignore the possibility the the whole object might be NULL
121 
122  pe.name = v.get<std::string>("NAME");
123  indicator ind = v.get_indicator("PHONE"); //another way to test for null
124  pe.phone = ind == i_null ? "<NULL>" : v.get<std::string>("PHONE");
125  }
126 
127  static void to_base(PhonebookEntry2 const &pe, values &v, indicator &ind)
128  {
129  v.set("NAME", pe.name);
130  v.set("PHONE", pe.phone, pe.phone.empty() ? i_null : i_ok);
131  ind = i_ok;
132  }
133 };
134 
136 {
138 
139  static void from_base(values const &v, indicator /* ind */, PhonebookEntry3 &pe)
140  {
141  // here we ignore the possibility the the whole object might be NULL
142 
143  pe.setName(v.get<std::string>("NAME"));
144  pe.setPhone(v.get<std::string>("PHONE", "<NULL>"));
145  }
146 
147  static void to_base(PhonebookEntry3 const &pe, values &v, indicator &ind)
148  {
149  v.set("NAME", pe.getName());
150  v.set("PHONE", pe.getPhone(), pe.getPhone().empty() ? i_null : i_ok);
151  ind = i_ok;
152  }
153 };
154 
155 } // namespace soci
156 
157 namespace soci
158 {
159 namespace tests
160 {
161 
162 // ensure connection is checked, no crash occurs
163 
164 #define SOCI_TEST_ENSURE_CONNECTED(sql, method) { \
165  std::string msg; \
166  try { \
167  (sql.method)(); \
168  assert(!"exception expected"); \
169  } catch (soci_error const &e) { msg = e.what(); } \
170  assert(msg.empty() == false); } (void)sql
171 
172 #define SOCI_TEST_ENSURE_CONNECTED2(sql, method) { \
173  std::string msg; \
174  try { std::string seq; long v(0); \
175  (sql.method)(seq, v); \
176  assert(!"exception expected"); \
177  } catch (soci_error const &e) { msg = e.what(); } \
178  assert(msg.empty() == false); } (void)sql
179 
180 inline bool equal_approx(double const a, double const b)
181 {
182  // The formula taken from CATCH test framework
183  // https://github.com/philsquared/Catch/
184  // Thanks to Richard Harris for his help refining this formula
185  double const epsilon(std::numeric_limits<float>::epsilon() * 100);
186  double const scale(1.0);
187  return std::fabs(a - b) < epsilon * (scale + (std::max)(std::fabs(a), std::fabs(b)));
188 }
189 
190 // TODO: improve cleanup capabilities by subtypes, soci_test name may be omitted --mloskot
191 // i.e. optional ctor param accepting custom table name
193 {
194 public:
196  : msession(sql) { drop(); }
197 
198  virtual ~table_creator_base() { drop();}
199 private:
200  void drop()
201  {
202  try
203  {
204  msession << "drop table soci_test";
205  }
206  catch (soci_error const& e)
207  {
208  //std::cerr << e.what() << std::endl;
209  e.what();
210  }
211  }
213 };
214 
216 {
217 public:
219  : msession(sql) { drop(); }
220 
221  virtual ~procedure_creator_base() { drop();}
222 private:
223  void drop()
224  {
225  try { msession << "drop procedure soci_test"; } catch (soci_error&) {}
226  }
228 };
229 
231 {
232 public:
234  : msession(sql) { drop(); }
235 
236  virtual ~function_creator_base() { drop();}
237 
238 protected:
239  virtual std::string dropstatement()
240  {
241  return "drop function soci_test";
242  }
243 
244 private:
245  void drop()
246  {
247  try { msession << dropstatement(); } catch (soci_error&) {}
248  }
250 };
251 
253 {
254 public:
256  std::string const &connectString)
257  : backEndFactory_(backEnd),
258  connectString_(connectString) {}
259 
261  {
262  return backEndFactory_;
263  }
264 
265  std::string get_connect_string() const
266  {
267  return connectString_;
268  }
269 
270  virtual std::string to_date_time(std::string const &dateTime) const = 0;
271 
272  virtual table_creator_base* table_creator_1(session&) const = 0;
273  virtual table_creator_base* table_creator_2(session&) const = 0;
274  virtual table_creator_base* table_creator_3(session&) const = 0;
275  virtual table_creator_base* table_creator_4(session&) const = 0;
276 
277  virtual ~test_context_base() {} // quiet the compiler
278 
279 private:
281  std::string const connectString_;
282 };
283 
285 {
286 public:
288  : tc_(tc),
289  backEndFactory_(tc.get_backend_factory()),
290  connectString_(tc.get_connect_string())
291  {}
292 
293  void run(bool dbSupportsTransactions = true)
294  {
295  std::cout<<"\nSOCI Common Tests:\n\n";
296 
297  test0();
298  test1();
299  test2();
300  test3();
301  test4();
302  test5();
303  test6();
304  test7();
305  test8();
306  test9();
307 
308  if (dbSupportsTransactions)
309  {
310  test10();
311  }
312  else
313  {
314  std::cout<<"skipping test 10 (database doesn't support transactions)\n";
315  }
316 
317  test11();
318  test12();
319  test13();
320  test14();
321  test15();
322  test16();
323  test17();
324  test18();
325  test19();
326  test20();
327  test21();
328  test22();
329  test23();
330  test24();
331  test25();
332  test26();
333  test27();
334  test28();
335  test29();
336  test30();
337  test31();
338  test_get_affected_rows();
339  test_query_transformation();
340  test_query_transformation_with_connection_pool();
341  test_pull5();
342  test_issue67();
343  test_prepared_insert_with_orm_type();
344  test_issue154();
345  test_placeholder_partial_matching_with_orm_type();
346  }
347 
348 private:
351  std::string const connectString_;
352 
353 typedef std::auto_ptr<table_creator_base> auto_table_creator;
354 
355 void test0()
356 {
357  {
358  soci::session sql; // no connection
359  SOCI_TEST_ENSURE_CONNECTED(sql, begin);
360  SOCI_TEST_ENSURE_CONNECTED(sql, commit);
361  SOCI_TEST_ENSURE_CONNECTED(sql, rollback);
362  SOCI_TEST_ENSURE_CONNECTED(sql, get_backend_name);
363  SOCI_TEST_ENSURE_CONNECTED(sql, make_statement_backend);
364  SOCI_TEST_ENSURE_CONNECTED(sql, make_rowid_backend);
365  SOCI_TEST_ENSURE_CONNECTED(sql, make_blob_backend);
366  SOCI_TEST_ENSURE_CONNECTED2(sql, get_next_sequence_value);
367  SOCI_TEST_ENSURE_CONNECTED2(sql, get_last_insert_id);
368  }
369  std::cout << "test 0 passed\n";
370 }
371 void test1()
372 {
373  session sql(backEndFactory_, connectString_);
374 
375  auto_table_creator tableCreator(tc_.table_creator_1(sql));
376 
377  std::string msg;
378  try
379  {
380  // expected error
381  sql << "drop table soci_test_nosuchtable";
382  assert(false);
383  }
384  catch (soci_error const &e)
385  {
386  msg = e.what();
387  }
388  assert(msg.empty() == false);
389 
390  sql << "insert into soci_test (id) values (" << 123 << ")";
391  int id;
392  sql << "select id from soci_test", into(id);
393  assert(id == 123);
394 
395  std::cout << "test 1 passed\n";
396 }
397 
398 // "into" tests, type conversions, etc.
399 void test2()
400 {
401  {
402  session sql(backEndFactory_, connectString_);
403 
404  {
405  auto_table_creator tableCreator(tc_.table_creator_1(sql));
406 
407  char c('a');
408  sql << "insert into soci_test(c) values(:c)", use(c);
409  sql << "select c from soci_test", into(c);
410  assert(c == 'a');
411  }
412 
413  {
414  auto_table_creator tableCreator(tc_.table_creator_1(sql));
415 
416  std::string helloSOCI("Hello, SOCI!");
417  sql << "insert into soci_test(str) values(:s)", use(helloSOCI);
418  std::string str;
419  sql << "select str from soci_test", into(str);
420  assert(str == "Hello, SOCI!");
421  }
422 
423  {
424  auto_table_creator tableCreator(tc_.table_creator_1(sql));
425 
426  short three(3);
427  sql << "insert into soci_test(sh) values(:id)", use(three);
428  short sh(0);
429  sql << "select sh from soci_test", into(sh);
430  assert(sh == 3);
431  }
432 
433  {
434  auto_table_creator tableCreator(tc_.table_creator_1(sql));
435 
436  int five(5);
437  sql << "insert into soci_test(id) values(:id)", use(five);
438  int i(0);
439  sql << "select id from soci_test", into(i);
440  assert(i == 5);
441  }
442 
443  {
444  auto_table_creator tableCreator(tc_.table_creator_1(sql));
445  unsigned long seven(7);
446  sql << "insert into soci_test(ul) values(:ul)", use(seven);
447  unsigned long ul(0);
448  sql << "select ul from soci_test", into(ul);
449  assert(ul == 7);
450  }
451 
452  {
453  auto_table_creator tableCreator(tc_.table_creator_1(sql));
454 
455  double pi(3.14159265);
456  sql << "insert into soci_test(d) values(:d)", use(pi);
457  double d(0.0);
458  sql << "select d from soci_test", into(d);
459  assert(equal_approx(d, 3.14159265));
460  }
461 
462  {
463  auto_table_creator tableCreator(tc_.table_creator_1(sql));
464 
465  std::tm nov15;
466  nov15.tm_year = 105;
467  nov15.tm_mon = 10;
468  nov15.tm_mday = 15;
469  nov15.tm_hour = 0;
470  nov15.tm_min = 0;
471  nov15.tm_sec = 0;
472 
473  sql << "insert into soci_test(tm) values(:tm)", use(nov15);
474 
475  std::tm t;
476  sql << "select tm from soci_test", into(t);
477  assert(t.tm_year == 105);
478  assert(t.tm_mon == 10);
479  assert(t.tm_mday == 15);
480  assert(t.tm_hour == 0);
481  assert(t.tm_min == 0);
482  assert(t.tm_sec == 0);
483  }
484 
485  {
486  auto_table_creator tableCreator(tc_.table_creator_1(sql));
487 
488  std::tm nov15;
489  nov15.tm_year = 105;
490  nov15.tm_mon = 10;
491  nov15.tm_mday = 15;
492  nov15.tm_hour = 22;
493  nov15.tm_min = 14;
494  nov15.tm_sec = 17;
495 
496  sql << "insert into soci_test(tm) values(:tm)", use(nov15);
497 
498  std::tm t;
499  sql << "select tm from soci_test", into(t);
500  assert(t.tm_year == 105);
501  assert(t.tm_mon == 10);
502  assert(t.tm_mday == 15);
503  assert(t.tm_hour == 22);
504  assert(t.tm_min == 14);
505  assert(t.tm_sec == 17);
506  }
507 
508  // test indicators
509  {
510  auto_table_creator tableCreator(tc_.table_creator_1(sql));
511 
512  int id(1);
513  std::string str("Hello");
514  sql << "insert into soci_test(id, str) values(:id, :str)",
515  use(id), use(str);
516 
517  int i;
518  indicator ind;
519  sql << "select id from soci_test", into(i, ind);
520  assert(ind == i_ok);
521  }
522 
523  // more indicator tests, NULL values
524  {
525  auto_table_creator tableCreator(tc_.table_creator_1(sql));
526 
527  sql << "insert into soci_test(id,tm) values(NULL,NULL)";
528  int i;
529  indicator ind;
530  sql << "select id from soci_test", into(i, ind);
531  assert(ind == i_null);
532 
533  // additional test for NULL with std::tm
534  std::tm t;
535  sql << "select tm from soci_test", into(t, ind);
536  assert(ind == i_null);
537 
538  try
539  {
540  // expect error
541  sql << "select id from soci_test", into(i);
542  assert(false);
543  }
544  catch (soci_error const &e)
545  {
546  std::string error = e.what();
547  assert(error ==
548  "Null value fetched and no indicator defined.");
549  }
550 
551  sql << "select id from soci_test where id = 1000", into(i, ind);
552  assert(sql.got_data() == false);
553 
554  // no data expected
555  sql << "select id from soci_test where id = 1000", into(i);
556  assert(sql.got_data() == false);
557 
558  // no data expected, test correct behaviour with use
559  int id = 1000;
560  sql << "select id from soci_test where id = :id", use(id), into(i);
561  assert(sql.got_data() == false);
562  }
563  }
564 
565  std::cout << "test 2 passed" << std::endl;
566 }
567 
568 // repeated fetch and bulk fetch
569 void test3()
570 {
571  {
572  session sql(backEndFactory_, connectString_);
573 
574  // repeated fetch and bulk fetch of char
575  {
576  // create and populate the test table
577  auto_table_creator tableCreator(tc_.table_creator_1(sql));
578 
579  char c;
580  for (c = 'a'; c <= 'z'; ++c)
581  {
582  sql << "insert into soci_test(c) values(\'" << c << "\')";
583  }
584 
585  int count;
586  sql << "select count(*) from soci_test", into(count);
587  assert(count == 'z' - 'a' + 1);
588 
589  {
590  char c2 = 'a';
591 
592  statement st = (sql.prepare <<
593  "select c from soci_test order by c", into(c));
594 
595  st.execute();
596  while (st.fetch())
597  {
598  assert(c == c2);
599  ++c2;
600  }
601  assert(c2 == 'a' + count);
602  }
603  {
604  char c2 = 'a';
605 
606  std::vector<char> vec(10);
607  statement st = (sql.prepare <<
608  "select c from soci_test order by c", into(vec));
609  st.execute();
610  while (st.fetch())
611  {
612  for (std::size_t i = 0; i != vec.size(); ++i)
613  {
614  assert(c2 == vec[i]);
615  ++c2;
616  }
617 
618  vec.resize(10);
619  }
620  assert(c2 == 'a' + count);
621  }
622 
623  {
624  // verify an exception is thrown when empty vector is used
625  std::vector<char> vec;
626  try
627  {
628  sql << "select c from soci_test", into(vec);
629  assert(false);
630  }
631  catch (soci_error const &e)
632  {
633  std::string msg = e.what();
634  assert(msg == "Vectors of size 0 are not allowed.");
635  }
636  }
637 
638  }
639 
640  // repeated fetch and bulk fetch of std::string
641  {
642  // create and populate the test table
643  auto_table_creator tableCreator(tc_.table_creator_1(sql));
644 
645  int const rowsToTest = 10;
646  for (int i = 0; i != rowsToTest; ++i)
647  {
648  std::ostringstream ss;
649  ss << "Hello_" << i;
650 
651  sql << "insert into soci_test(str) values(\'"
652  << ss.str() << "\')";
653  }
654 
655  int count;
656  sql << "select count(*) from soci_test", into(count);
657  assert(count == rowsToTest);
658 
659  {
660  int i = 0;
661  std::string s;
662  statement st = (sql.prepare <<
663  "select str from soci_test order by str", into(s));
664 
665  st.execute();
666  while (st.fetch())
667  {
668  std::ostringstream ss;
669  ss << "Hello_" << i;
670  assert(s == ss.str());
671  ++i;
672  }
673  assert(i == rowsToTest);
674  }
675  {
676  int i = 0;
677 
678  std::vector<std::string> vec(4);
679  statement st = (sql.prepare <<
680  "select str from soci_test order by str", into(vec));
681  st.execute();
682  while (st.fetch())
683  {
684  for (std::size_t j = 0; j != vec.size(); ++j)
685  {
686  std::ostringstream ss;
687  ss << "Hello_" << i;
688  assert(ss.str() == vec[j]);
689  ++i;
690  }
691 
692  vec.resize(4);
693  }
694  assert(i == rowsToTest);
695  }
696  }
697 
698  // repeated fetch and bulk fetch of short
699  {
700  // create and populate the test table
701  auto_table_creator tableCreator(tc_.table_creator_1(sql));
702 
703  short const rowsToTest = 100;
704  short sh;
705  for (sh = 0; sh != rowsToTest; ++sh)
706  {
707  sql << "insert into soci_test(sh) values(" << sh << ")";
708  }
709 
710  int count;
711  sql << "select count(*) from soci_test", into(count);
712  assert(count == rowsToTest);
713 
714  {
715  short sh2 = 0;
716 
717  statement st = (sql.prepare <<
718  "select sh from soci_test order by sh", into(sh));
719 
720  st.execute();
721  while (st.fetch())
722  {
723  assert(sh == sh2);
724  ++sh2;
725  }
726  assert(sh2 == rowsToTest);
727  }
728  {
729  short sh2 = 0;
730 
731  std::vector<short> vec(8);
732  statement st = (sql.prepare <<
733  "select sh from soci_test order by sh", into(vec));
734  st.execute();
735  while (st.fetch())
736  {
737  for (std::size_t i = 0; i != vec.size(); ++i)
738  {
739  assert(sh2 == vec[i]);
740  ++sh2;
741  }
742 
743  vec.resize(8);
744  }
745  assert(sh2 == rowsToTest);
746  }
747  }
748 
749  // repeated fetch and bulk fetch of int (4-bytes)
750  {
751  // create and populate the test table
752  auto_table_creator tableCreator(tc_.table_creator_1(sql));
753 
754  int const rowsToTest = 100;
755  int i;
756  for (i = 0; i != rowsToTest; ++i)
757  {
758  sql << "insert into soci_test(id) values(" << i << ")";
759  }
760 
761  int count;
762  sql << "select count(*) from soci_test", into(count);
763  assert(count == rowsToTest);
764 
765  {
766  int i2 = 0;
767 
768  statement st = (sql.prepare <<
769  "select id from soci_test order by id", into(i));
770 
771  st.execute();
772  while (st.fetch())
773  {
774  assert(i == i2);
775  ++i2;
776  }
777  assert(i2 == rowsToTest);
778  }
779  {
780  // additional test with the use element
781 
782  int i2 = 0;
783  int cond = 0; // this condition is always true
784 
785  statement st = (sql.prepare <<
786  "select id from soci_test where id >= :cond order by id",
787  use(cond), into(i));
788 
789  st.execute();
790  while (st.fetch())
791  {
792  assert(i == i2);
793  ++i2;
794  }
795  assert(i2 == rowsToTest);
796  }
797  {
798  int i2 = 0;
799 
800  std::vector<int> vec(8);
801  statement st = (sql.prepare <<
802  "select id from soci_test order by id", into(vec));
803  st.execute();
804  while (st.fetch())
805  {
806  for (std::size_t i = 0; i != vec.size(); ++i)
807  {
808  assert(i2 == vec[i]);
809  ++i2;
810  }
811 
812  vec.resize(8);
813  }
814  assert(i2 == rowsToTest);
815  }
816  }
817 
818  // repeated fetch and bulk fetch of unsigned int (4-bytes)
819  {
820  // create and populate the test table
821  auto_table_creator tableCreator(tc_.table_creator_1(sql));
822 
823  unsigned int const rowsToTest = 100;
824  unsigned int ul;
825  for (ul = 0; ul != rowsToTest; ++ul)
826  {
827  sql << "insert into soci_test(ul) values(" << ul << ")";
828  }
829 
830  int count;
831  sql << "select count(*) from soci_test", into(count);
832  assert(count == static_cast<int>(rowsToTest));
833 
834  {
835  unsigned int ul2 = 0;
836 
837  statement st = (sql.prepare <<
838  "select ul from soci_test order by ul", into(ul));
839 
840  st.execute();
841  while (st.fetch())
842  {
843  assert(ul == ul2);
844  ++ul2;
845  }
846  assert(ul2 == rowsToTest);
847  }
848  {
849  unsigned int ul2 = 0;
850 
851  std::vector<unsigned int> vec(8);
852  statement st = (sql.prepare <<
853  "select ul from soci_test order by ul", into(vec));
854  st.execute();
855  while (st.fetch())
856  {
857  for (std::size_t i = 0; i != vec.size(); ++i)
858  {
859  assert(ul2 == vec[i]);
860  ++ul2;
861  }
862 
863  vec.resize(8);
864  }
865  assert(ul2 == rowsToTest);
866  }
867  }
868 
869  // repeated fetch and bulk fetch of double
870  {
871  // create and populate the test table
872  auto_table_creator tableCreator(tc_.table_creator_1(sql));
873 
874  int const rowsToTest = 100;
875  double d = 0.0;
876  for (int i = 0; i != rowsToTest; ++i)
877  {
878  sql << "insert into soci_test(d) values(" << d << ")";
879  d += 0.6;
880  }
881 
882  int count;
883  sql << "select count(*) from soci_test", into(count);
884  assert(count == rowsToTest);
885 
886  {
887  double d2 = 0.0;
888  int i = 0;
889 
890  statement st = (sql.prepare <<
891  "select d from soci_test order by d", into(d));
892 
893  st.execute();
894  while (st.fetch())
895  {
896  assert(equal_approx(d, d2));
897  d2 += 0.6;
898  ++i;
899  }
900  assert(i == rowsToTest);
901  }
902  {
903  double d2 = 0.0;
904  int i = 0;
905 
906  std::vector<double> vec(8);
907  statement st = (sql.prepare <<
908  "select d from soci_test order by d", into(vec));
909  st.execute();
910  while (st.fetch())
911  {
912  for (std::size_t j = 0; j != vec.size(); ++j)
913  {
914  assert(equal_approx(d2, vec[j]));
915  d2 += 0.6;
916  ++i;
917  }
918 
919  vec.resize(8);
920  }
921  assert(i == rowsToTest);
922  }
923  }
924 
925  // repeated fetch and bulk fetch of std::tm
926  {
927  // create and populate the test table
928  auto_table_creator tableCreator(tc_.table_creator_1(sql));
929 
930  int const rowsToTest = 8;
931  for (int i = 0; i != rowsToTest; ++i)
932  {
933  std::ostringstream ss;
934  ss << 2000 + i << "-0" << 1 + i << '-' << 20 - i << ' '
935  << 15 + i << ':' << 50 - i << ':' << 40 + i;
936 
937  sql << "insert into soci_test(id, tm) values(" << i
938  << ", " << tc_.to_date_time(ss.str()) << ")";
939  }
940 
941  int count;
942  sql << "select count(*) from soci_test", into(count);
943  assert(count == rowsToTest);
944 
945  {
946  std::tm t;
947  int i = 0;
948 
949  statement st = (sql.prepare <<
950  "select tm from soci_test order by id", into(t));
951 
952  st.execute();
953  while (st.fetch())
954  {
955  assert(t.tm_year + 1900 == 2000 + i);
956  assert(t.tm_mon + 1 == 1 + i);
957  assert(t.tm_mday == 20 - i);
958  assert(t.tm_hour == 15 + i);
959  assert(t.tm_min == 50 - i);
960  assert(t.tm_sec == 40 + i);
961 
962  ++i;
963  }
964  assert(i == rowsToTest);
965  }
966  {
967  int i = 0;
968 
969  std::vector<std::tm> vec(3);
970  statement st = (sql.prepare <<
971  "select tm from soci_test order by id", into(vec));
972  st.execute();
973  while (st.fetch())
974  {
975  for (std::size_t j = 0; j != vec.size(); ++j)
976  {
977  assert(vec[j].tm_year + 1900 == 2000 + i);
978  assert(vec[j].tm_mon + 1 == 1 + i);
979  assert(vec[j].tm_mday == 20 - i);
980  assert(vec[j].tm_hour == 15 + i);
981  assert(vec[j].tm_min == 50 - i);
982  assert(vec[j].tm_sec == 40 + i);
983 
984  ++i;
985  }
986 
987  vec.resize(3);
988  }
989  assert(i == rowsToTest);
990  }
991  }
992  }
993 
994  std::cout << "test 3 passed" << std::endl;
995 }
996 
997 // test for indicators (repeated fetch and bulk)
998 void test4()
999 {
1000  session sql(backEndFactory_, connectString_);
1001 
1002  // create and populate the test table
1003  auto_table_creator tableCreator(tc_.table_creator_1(sql));
1004  {
1005  sql << "insert into soci_test(id, val) values(1, 10)";
1006  sql << "insert into soci_test(id, val) values(2, 11)";
1007  sql << "insert into soci_test(id, val) values(3, NULL)";
1008  sql << "insert into soci_test(id, val) values(4, NULL)";
1009  sql << "insert into soci_test(id, val) values(5, 12)";
1010 
1011  {
1012  int val;
1013  indicator ind;
1014 
1015  statement st = (sql.prepare <<
1016  "select val from soci_test order by id", into(val, ind));
1017 
1018  st.execute();
1019  bool gotData = st.fetch();
1020  assert(gotData);
1021  assert(ind == i_ok);
1022  assert(val == 10);
1023  gotData = st.fetch();
1024  assert(gotData);
1025  assert(ind == i_ok);
1026  assert(val == 11);
1027  gotData = st.fetch();
1028  assert(gotData);
1029  assert(ind == i_null);
1030  gotData = st.fetch();
1031  assert(gotData);
1032  assert(ind == i_null);
1033  gotData = st.fetch();
1034  assert(gotData);
1035  assert(ind == i_ok);
1036  assert(val == 12);
1037  gotData = st.fetch();
1038  assert(gotData == false);
1039  }
1040  {
1041  std::vector<int> vals(3);
1042  std::vector<indicator> inds(3);
1043 
1044  statement st = (sql.prepare <<
1045  "select val from soci_test order by id", into(vals, inds));
1046 
1047  st.execute();
1048  bool gotData = st.fetch();
1049  assert(gotData);
1050  assert(vals.size() == 3);
1051  assert(inds.size() == 3);
1052  assert(inds[0] == i_ok);
1053  assert(vals[0] == 10);
1054  assert(inds[1] == i_ok);
1055  assert(vals[1] == 11);
1056  assert(inds[2] == i_null);
1057  gotData = st.fetch();
1058  assert(gotData);
1059  assert(vals.size() == 2);
1060  assert(inds[0] == i_null);
1061  assert(inds[1] == i_ok);
1062  assert(vals[1] == 12);
1063  gotData = st.fetch();
1064  assert(gotData == false);
1065  }
1066 
1067  // additional test for "no data" condition
1068  {
1069  std::vector<int> vals(3);
1070  std::vector<indicator> inds(3);
1071 
1072  statement st = (sql.prepare <<
1073  "select val from soci_test where 0 = 1", into(vals, inds));
1074 
1075  bool gotData = st.execute(true);
1076  assert(gotData == false);
1077 
1078  // for convenience, vectors should be truncated
1079  assert(vals.empty());
1080  assert(inds.empty());
1081 
1082  // for even more convenience, fetch should not fail
1083  // but just report end of rowset
1084  // (and vectors should be truncated)
1085 
1086  vals.resize(1);
1087  inds.resize(1);
1088 
1089  gotData = st.fetch();
1090  assert(gotData == false);
1091  assert(vals.empty());
1092  assert(inds.empty());
1093  }
1094 
1095  // additional test for "no data" without prepared statement
1096  {
1097  std::vector<int> vals(3);
1098  std::vector<indicator> inds(3);
1099 
1100  sql << "select val from soci_test where 0 = 1",
1101  into(vals, inds);
1102 
1103  // vectors should be truncated
1104  assert(vals.empty());
1105  assert(inds.empty());
1106  }
1107  }
1108 
1109  std::cout << "test 4 passed" << std::endl;
1110 }
1111 
1112 // test for different sizes of data vector and indicators vector
1113 // (library should force ind. vector to have same size as data vector)
1114 void test5()
1115 {
1116  session sql(backEndFactory_, connectString_);
1117 
1118  // create and populate the test table
1119  auto_table_creator tableCreator(tc_.table_creator_1(sql));
1120  {
1121  sql << "insert into soci_test(id, val) values(1, 10)";
1122  sql << "insert into soci_test(id, val) values(2, 11)";
1123  sql << "insert into soci_test(id, val) values(3, NULL)";
1124  sql << "insert into soci_test(id, val) values(4, NULL)";
1125  sql << "insert into soci_test(id, val) values(5, 12)";
1126 
1127  {
1128  std::vector<int> vals(4);
1129  std::vector<indicator> inds;
1130 
1131  statement st = (sql.prepare <<
1132  "select val from soci_test order by id", into(vals, inds));
1133 
1134  st.execute();
1135  st.fetch();
1136  assert(vals.size() == 4);
1137  assert(inds.size() == 4);
1138  vals.resize(3);
1139  st.fetch();
1140  assert(vals.size() == 1);
1141  assert(inds.size() == 1);
1142  }
1143  }
1144 
1145  std::cout << "test 5 passed" << std::endl;
1146 }
1147 
1148 // "use" tests, type conversions, etc.
1149 void test6()
1150 {
1151 // Note: this functionality is not available with older PostgreSQL
1152 #ifndef SOCI_POSTGRESQL_NOPARAMS
1153  {
1154  session sql(backEndFactory_, connectString_);
1155 
1156  // test for char
1157  {
1158  auto_table_creator tableCreator(tc_.table_creator_1(sql));
1159  char c('a');
1160  sql << "insert into soci_test(c) values(:c)", use(c);
1161 
1162  c = 'b';
1163  sql << "select c from soci_test", into(c);
1164  assert(c == 'a');
1165 
1166  }
1167 
1168  // test for std::string
1169  {
1170  auto_table_creator tableCreator(tc_.table_creator_1(sql));
1171  std::string s = "Hello SOCI!";
1172  sql << "insert into soci_test(str) values(:s)", use(s);
1173 
1174  std::string str;
1175  sql << "select str from soci_test", into(str);
1176 
1177  assert(str == "Hello SOCI!");
1178  }
1179 
1180  // test for short
1181  {
1182  auto_table_creator tableCreator(tc_.table_creator_1(sql));
1183  short s = 123;
1184  sql << "insert into soci_test(id) values(:id)", use(s);
1185 
1186  short s2 = 0;
1187  sql << "select id from soci_test", into(s2);
1188 
1189  assert(s2 == 123);
1190  }
1191 
1192  // test for int
1193  {
1194  auto_table_creator tableCreator(tc_.table_creator_1(sql));
1195  int i = -12345678;
1196  sql << "insert into soci_test(id) values(:i)", use(i);
1197 
1198  int i2 = 0;
1199  sql << "select id from soci_test", into(i2);
1200 
1201  assert(i2 == -12345678);
1202  }
1203 
1204  // test for unsigned long
1205  {
1206  auto_table_creator tableCreator(tc_.table_creator_1(sql));
1207  unsigned long ul = 4000000000ul;
1208  sql << "insert into soci_test(ul) values(:num)", use(ul);
1209 
1210  unsigned long ul2 = 0;
1211  sql << "select ul from soci_test", into(ul2);
1212 
1213  assert(ul2 == 4000000000ul);
1214  }
1215 
1216  // test for double
1217  {
1218  auto_table_creator tableCreator(tc_.table_creator_1(sql));
1219  double d = 3.14159265;
1220  sql << "insert into soci_test(d) values(:d)", use(d);
1221 
1222  double d2 = 0;
1223  sql << "select d from soci_test", into(d2);
1224 
1225  assert(equal_approx(d2, d));
1226  }
1227 
1228  // test for std::tm
1229  {
1230  auto_table_creator tableCreator(tc_.table_creator_1(sql));
1231  std::tm t;
1232  t.tm_year = 105;
1233  t.tm_mon = 10;
1234  t.tm_mday = 19;
1235  t.tm_hour = 21;
1236  t.tm_min = 39;
1237  t.tm_sec = 57;
1238  sql << "insert into soci_test(tm) values(:t)", use(t);
1239 
1240  std::tm t2;
1241  t2.tm_year = 0;
1242  t2.tm_mon = 0;
1243  t2.tm_mday = 0;
1244  t2.tm_hour = 0;
1245  t2.tm_min = 0;
1246  t2.tm_sec = 0;
1247 
1248  sql << "select tm from soci_test", into(t2);
1249 
1250  assert(t.tm_year == 105);
1251  assert(t.tm_mon == 10);
1252  assert(t.tm_mday == 19);
1253  assert(t.tm_hour == 21);
1254  assert(t.tm_min == 39);
1255  assert(t.tm_sec == 57);
1256  }
1257 
1258  // test for repeated use
1259  {
1260  auto_table_creator tableCreator(tc_.table_creator_1(sql));
1261  int i;
1262  statement st = (sql.prepare
1263  << "insert into soci_test(id) values(:id)", use(i));
1264 
1265  i = 5;
1266  st.execute(true);
1267  i = 6;
1268  st.execute(true);
1269  i = 7;
1270  st.execute(true);
1271 
1272  std::vector<int> v(5);
1273  sql << "select id from soci_test order by id", into(v);
1274 
1275  assert(v.size() == 3);
1276  assert(v[0] == 5);
1277  assert(v[1] == 6);
1278  assert(v[2] == 7);
1279  }
1280 
1281  // tests for use of const objects
1282 
1283  // test for char
1284  {
1285  auto_table_creator tableCreator(tc_.table_creator_1(sql));
1286  char const c('a');
1287  sql << "insert into soci_test(c) values(:c)", use(c);
1288 
1289  char c2 = 'b';
1290  sql << "select c from soci_test", into(c2);
1291  assert(c2 == 'a');
1292 
1293  }
1294 
1295  // test for std::string
1296  {
1297  auto_table_creator tableCreator(tc_.table_creator_1(sql));
1298  std::string const s = "Hello const SOCI!";
1299  sql << "insert into soci_test(str) values(:s)", use(s);
1300 
1301  std::string str;
1302  sql << "select str from soci_test", into(str);
1303 
1304  assert(str == "Hello const SOCI!");
1305  }
1306 
1307  // test for short
1308  {
1309  auto_table_creator tableCreator(tc_.table_creator_1(sql));
1310  short const s = 123;
1311  sql << "insert into soci_test(id) values(:id)", use(s);
1312 
1313  short s2 = 0;
1314  sql << "select id from soci_test", into(s2);
1315 
1316  assert(s2 == 123);
1317  }
1318 
1319  // test for int
1320  {
1321  auto_table_creator tableCreator(tc_.table_creator_1(sql));
1322  int const i = -12345678;
1323  sql << "insert into soci_test(id) values(:i)", use(i);
1324 
1325  int i2 = 0;
1326  sql << "select id from soci_test", into(i2);
1327 
1328  assert(i2 == -12345678);
1329  }
1330 
1331  // test for unsigned long
1332  {
1333  auto_table_creator tableCreator(tc_.table_creator_1(sql));
1334  unsigned long const ul = 4000000000ul;
1335  sql << "insert into soci_test(ul) values(:num)", use(ul);
1336 
1337  unsigned long ul2 = 0;
1338  sql << "select ul from soci_test", into(ul2);
1339 
1340  assert(ul2 == 4000000000ul);
1341  }
1342 
1343  // test for double
1344  {
1345  auto_table_creator tableCreator(tc_.table_creator_1(sql));
1346  double const d = 3.14159265;
1347  sql << "insert into soci_test(d) values(:d)", use(d);
1348 
1349  double d2 = 0;
1350  sql << "select d from soci_test", into(d2);
1351 
1352  assert(equal_approx(d2, d));
1353  }
1354 
1355  // test for std::tm
1356  {
1357  auto_table_creator tableCreator(tc_.table_creator_1(sql));
1358  std::tm t;
1359  t.tm_year = 105;
1360  t.tm_mon = 10;
1361  t.tm_mday = 19;
1362  t.tm_hour = 21;
1363  t.tm_min = 39;
1364  t.tm_sec = 57;
1365  std::tm const & ct = t;
1366  sql << "insert into soci_test(tm) values(:t)", use(ct);
1367 
1368  std::tm t2;
1369  t2.tm_year = 0;
1370  t2.tm_mon = 0;
1371  t2.tm_mday = 0;
1372  t2.tm_hour = 0;
1373  t2.tm_min = 0;
1374  t2.tm_sec = 0;
1375 
1376  sql << "select tm from soci_test", into(t2);
1377 
1378  assert(t.tm_year == 105);
1379  assert(t.tm_mon == 10);
1380  assert(t.tm_mday == 19);
1381  assert(t.tm_hour == 21);
1382  assert(t.tm_min == 39);
1383  assert(t.tm_sec == 57);
1384  }
1385  }
1386 
1387  std::cout << "test 6 passed" << std::endl;
1388 #endif // SOCI_POSTGRESQL_NOPARAMS
1389 }
1390 
1391 // test for multiple use (and into) elements
1392 void test7()
1393 {
1394  {
1395  session sql(backEndFactory_, connectString_);
1396  auto_table_creator tableCreator(tc_.table_creator_1(sql));
1397 
1398  {
1399  int i1 = 5;
1400  int i2 = 6;
1401  int i3 = 7;
1402 
1403 #ifndef SOCI_POSTGRESQL_NOPARAMS
1404 
1405  sql << "insert into soci_test(i1, i2, i3) values(:i1, :i2, :i3)",
1406  use(i1), use(i2), use(i3);
1407 
1408 #else
1409  // Older PostgreSQL does not support use elements.
1410 
1411  sql << "insert into soci_test(i1, i2, i3) values(5, 6, 7)";
1412 
1413 #endif // SOCI_POSTGRESQL_NOPARAMS
1414 
1415  i1 = 0;
1416  i2 = 0;
1417  i3 = 0;
1418  sql << "select i1, i2, i3 from soci_test",
1419  into(i1), into(i2), into(i3);
1420 
1421  assert(i1 == 5);
1422  assert(i2 == 6);
1423  assert(i3 == 7);
1424 
1425  // same for vectors
1426  sql << "delete from soci_test";
1427 
1428  i1 = 0;
1429  i2 = 0;
1430  i3 = 0;
1431 
1432 #ifndef SOCI_POSTGRESQL_NOPARAMS
1433 
1434  statement st = (sql.prepare
1435  << "insert into soci_test(i1, i2, i3) values(:i1, :i2, :i3)",
1436  use(i1), use(i2), use(i3));
1437 
1438  i1 = 1;
1439  i2 = 2;
1440  i3 = 3;
1441  st.execute(true);
1442  i1 = 4;
1443  i2 = 5;
1444  i3 = 6;
1445  st.execute(true);
1446  i1 = 7;
1447  i2 = 8;
1448  i3 = 9;
1449  st.execute(true);
1450 
1451 #else
1452  // Older PostgreSQL does not support use elements.
1453 
1454  sql << "insert into soci_test(i1, i2, i3) values(1, 2, 3)";
1455  sql << "insert into soci_test(i1, i2, i3) values(4, 5, 6)";
1456  sql << "insert into soci_test(i1, i2, i3) values(7, 8, 9)";
1457 
1458 #endif // SOCI_POSTGRESQL_NOPARAMS
1459 
1460  std::vector<int> v1(5);
1461  std::vector<int> v2(5);
1462  std::vector<int> v3(5);
1463 
1464  sql << "select i1, i2, i3 from soci_test order by i1",
1465  into(v1), into(v2), into(v3);
1466 
1467  assert(v1.size() == 3);
1468  assert(v2.size() == 3);
1469  assert(v3.size() == 3);
1470  assert(v1[0] == 1);
1471  assert(v1[1] == 4);
1472  assert(v1[2] == 7);
1473  assert(v2[0] == 2);
1474  assert(v2[1] == 5);
1475  assert(v2[2] == 8);
1476  assert(v3[0] == 3);
1477  assert(v3[1] == 6);
1478  assert(v3[2] == 9);
1479  }
1480  }
1481 
1482  std::cout << "test 7 passed" << std::endl;
1483 }
1484 
1485 // use vector elements
1486 void test8()
1487 {
1488 // Not supported with older PostgreSQL
1489 #ifndef SOCI_POSTGRESQL_NOPARAMS
1490 
1491  {
1492  session sql(backEndFactory_, connectString_);
1493 
1494  // test for char
1495  {
1496  auto_table_creator tableCreator(tc_.table_creator_1(sql));
1497 
1498  std::vector<char> v;
1499  v.push_back('a');
1500  v.push_back('b');
1501  v.push_back('c');
1502  v.push_back('d');
1503 
1504  sql << "insert into soci_test(c) values(:c)", use(v);
1505 
1506  std::vector<char> v2(4);
1507 
1508  sql << "select c from soci_test order by c", into(v2);
1509  assert(v2.size() == 4);
1510  assert(v2[0] == 'a');
1511  assert(v2[1] == 'b');
1512  assert(v2[2] == 'c');
1513  assert(v2[3] == 'd');
1514  }
1515 
1516  // test for std::string
1517  {
1518  auto_table_creator tableCreator(tc_.table_creator_1(sql));
1519 
1520  std::vector<std::string> v;
1521  v.push_back("ala");
1522  v.push_back("ma");
1523  v.push_back("kota");
1524 
1525  sql << "insert into soci_test(str) values(:s)", use(v);
1526 
1527  std::vector<std::string> v2(4);
1528 
1529  sql << "select str from soci_test order by str", into(v2);
1530  assert(v2.size() == 3);
1531  assert(v2[0] == "ala");
1532  assert(v2[1] == "kota");
1533  assert(v2[2] == "ma");
1534  }
1535 
1536  // test for short
1537  {
1538  auto_table_creator tableCreator(tc_.table_creator_1(sql));
1539 
1540  std::vector<short> v;
1541  v.push_back(-5);
1542  v.push_back(6);
1543  v.push_back(7);
1544  v.push_back(123);
1545 
1546  sql << "insert into soci_test(sh) values(:sh)", use(v);
1547 
1548  std::vector<short> v2(4);
1549 
1550  sql << "select sh from soci_test order by sh", into(v2);
1551  assert(v2.size() == 4);
1552  assert(v2[0] == -5);
1553  assert(v2[1] == 6);
1554  assert(v2[2] == 7);
1555  assert(v2[3] == 123);
1556  }
1557 
1558  // test for int
1559  {
1560  auto_table_creator tableCreator(tc_.table_creator_1(sql));
1561 
1562  std::vector<int> v;
1563  v.push_back(-2000000000);
1564  v.push_back(0);
1565  v.push_back(1);
1566  v.push_back(2000000000);
1567 
1568  sql << "insert into soci_test(id) values(:i)", use(v);
1569 
1570  std::vector<int> v2(4);
1571 
1572  sql << "select id from soci_test order by id", into(v2);
1573  assert(v2.size() == 4);
1574  assert(v2[0] == -2000000000);
1575  assert(v2[1] == 0);
1576  assert(v2[2] == 1);
1577  assert(v2[3] == 2000000000);
1578  }
1579 
1580  // test for unsigned int
1581  {
1582  auto_table_creator tableCreator(tc_.table_creator_1(sql));
1583 
1584  std::vector<unsigned int> v;
1585  v.push_back(0);
1586  v.push_back(1);
1587  v.push_back(123);
1588  v.push_back(1000);
1589 
1590  sql << "insert into soci_test(ul) values(:ul)", use(v);
1591 
1592  std::vector<unsigned int> v2(4);
1593 
1594  sql << "select ul from soci_test order by ul", into(v2);
1595  assert(v2.size() == 4);
1596  assert(v2[0] == 0);
1597  assert(v2[1] == 1);
1598  assert(v2[2] == 123);
1599  assert(v2[3] == 1000);
1600  }
1601 
1602  // test for double
1603  {
1604  auto_table_creator tableCreator(tc_.table_creator_1(sql));
1605 
1606  std::vector<double> v;
1607  v.push_back(0);
1608  v.push_back(-0.0001);
1609  v.push_back(0.0001);
1610  v.push_back(3.1415926);
1611 
1612  sql << "insert into soci_test(d) values(:d)", use(v);
1613 
1614  std::vector<double> v2(4);
1615 
1616  sql << "select d from soci_test order by d", into(v2);
1617  assert(v2.size() == 4);
1618  assert(equal_approx(v2[0],-0.0001));
1619  assert(equal_approx(v2[1], 0));
1620  assert(equal_approx(v2[2], 0.0001));
1621  assert(equal_approx(v2[3], 3.1415926));
1622  }
1623 
1624  // test for std::tm
1625  {
1626  auto_table_creator tableCreator(tc_.table_creator_1(sql));
1627 
1628  std::vector<std::tm> v;
1629  std::tm t;
1630  t.tm_year = 105;
1631  t.tm_mon = 10;
1632  t.tm_mday = 26;
1633  t.tm_hour = 22;
1634  t.tm_min = 45;
1635  t.tm_sec = 17;
1636 
1637  v.push_back(t);
1638 
1639  t.tm_sec = 37;
1640  v.push_back(t);
1641 
1642  t.tm_mday = 25;
1643  v.push_back(t);
1644 
1645  sql << "insert into soci_test(tm) values(:t)", use(v);
1646 
1647  std::vector<std::tm> v2(4);
1648 
1649  sql << "select tm from soci_test order by tm", into(v2);
1650  assert(v2.size() == 3);
1651  assert(v2[0].tm_year == 105);
1652  assert(v2[0].tm_mon == 10);
1653  assert(v2[0].tm_mday == 25);
1654  assert(v2[0].tm_hour == 22);
1655  assert(v2[0].tm_min == 45);
1656  assert(v2[0].tm_sec == 37);
1657  assert(v2[1].tm_year == 105);
1658  assert(v2[1].tm_mon == 10);
1659  assert(v2[1].tm_mday == 26);
1660  assert(v2[1].tm_hour == 22);
1661  assert(v2[1].tm_min == 45);
1662  assert(v2[1].tm_sec == 17);
1663  assert(v2[2].tm_year == 105);
1664  assert(v2[2].tm_mon == 10);
1665  assert(v2[2].tm_mday == 26);
1666  assert(v2[2].tm_hour == 22);
1667  assert(v2[2].tm_min == 45);
1668  assert(v2[2].tm_sec == 37);
1669  }
1670 
1671  // additional test for int (use const vector)
1672  {
1673  auto_table_creator tableCreator(tc_.table_creator_1(sql));
1674 
1675  std::vector<int> v;
1676  v.push_back(-2000000000);
1677  v.push_back(0);
1678  v.push_back(1);
1679  v.push_back(2000000000);
1680 
1681  std::vector<int> const & cv = v;
1682 
1683  sql << "insert into soci_test(id) values(:i)", use(cv);
1684 
1685  std::vector<int> v2(4);
1686 
1687  sql << "select id from soci_test order by id", into(v2);
1688  assert(v2.size() == 4);
1689  assert(v2[0] == -2000000000);
1690  assert(v2[1] == 0);
1691  assert(v2[2] == 1);
1692  assert(v2[3] == 2000000000);
1693  }
1694  }
1695 
1696  std::cout << "test 8 passed" << std::endl;
1697 
1698 #endif // SOCI_POSTGRESQL_NOPARAMS
1699 
1700 }
1701 
1702 // test for named binding
1703 void test9()
1704 {
1705 // Not supported with older PostgreSQL
1706 #ifndef SOCI_POSTGRESQL_NOPARAMS
1707 
1708  {
1709  session sql(backEndFactory_, connectString_);
1710  {
1711  auto_table_creator tableCreator(tc_.table_creator_1(sql));
1712 
1713  int i1 = 7;
1714  int i2 = 8;
1715 
1716  // verify the exception is thrown if both by position
1717  // and by name use elements are specified
1718  try
1719  {
1720  sql << "insert into soci_test(i1, i2) values(:i1, :i2)",
1721  use(i1, "i1"), use(i2);
1722 
1723  assert(false);
1724  }
1725  catch (soci_error const& e)
1726  {
1727  std::string what(e.what());
1728  assert(what ==
1729  "Binding for use elements must be either by position "
1730  "or by name.");
1731  }
1732 
1733  // normal test
1734  sql << "insert into soci_test(i1, i2) values(:i1, :i2)",
1735  use(i1, "i1"), use(i2, "i2");
1736 
1737  i1 = 0;
1738  i2 = 0;
1739  sql << "select i1, i2 from soci_test", into(i1), into(i2);
1740  assert(i1 == 7);
1741  assert(i2 == 8);
1742 
1743  i2 = 0;
1744  sql << "select i2 from soci_test where i1 = :i1", into(i2), use(i1);
1745  assert(i2 == 8);
1746 
1747  sql << "delete from soci_test";
1748 
1749  // test vectors
1750 
1751  std::vector<int> v1;
1752  v1.push_back(1);
1753  v1.push_back(2);
1754  v1.push_back(3);
1755 
1756  std::vector<int> v2;
1757  v2.push_back(4);
1758  v2.push_back(5);
1759  v2.push_back(6);
1760 
1761  sql << "insert into soci_test(i1, i2) values(:i1, :i2)",
1762  use(v1, "i1"), use(v2, "i2");
1763 
1764  sql << "select i2, i1 from soci_test order by i1 desc",
1765  into(v1), into(v2);
1766  assert(v1.size() == 3);
1767  assert(v2.size() == 3);
1768  assert(v1[0] == 6);
1769  assert(v1[1] == 5);
1770  assert(v1[2] == 4);
1771  assert(v2[0] == 3);
1772  assert(v2[1] == 2);
1773  assert(v2[2] == 1);
1774  }
1775  }
1776 
1777  std::cout << "test 9 passed" << std::endl;
1778 
1779 #endif // SOCI_POSTGRESQL_NOPARAMS
1780 
1781 }
1782 
1783 // transaction test
1784 void test10()
1785 {
1786  {
1787  session sql(backEndFactory_, connectString_);
1788 
1789  auto_table_creator tableCreator(tc_.table_creator_1(sql));
1790 
1791  int count;
1792  sql << "select count(*) from soci_test", into(count);
1793  assert(count == 0);
1794 
1795  {
1796  transaction tr(sql);
1797 
1798  sql << "insert into soci_test (id, name) values(1, 'John')";
1799  sql << "insert into soci_test (id, name) values(2, 'Anna')";
1800  sql << "insert into soci_test (id, name) values(3, 'Mike')";
1801 
1802  tr.commit();
1803  }
1804  {
1805  transaction tr(sql);
1806 
1807  sql << "select count(*) from soci_test", into(count);
1808  assert(count == 3);
1809 
1810  sql << "insert into soci_test (id, name) values(4, 'Stan')";
1811 
1812  sql << "select count(*) from soci_test", into(count);
1813  assert(count == 4);
1814 
1815  tr.rollback();
1816 
1817  sql << "select count(*) from soci_test", into(count);
1818  assert(count == 3);
1819  }
1820  {
1821  transaction tr(sql);
1822 
1823  sql << "delete from soci_test";
1824 
1825  sql << "select count(*) from soci_test", into(count);
1826  assert(count == 0);
1827 
1828  tr.rollback();
1829 
1830  sql << "select count(*) from soci_test", into(count);
1831  assert(count == 3);
1832  }
1833  {
1834  // additional test for detection of double commit
1835  transaction tr(sql);
1836  tr.commit();
1837  try
1838  {
1839  tr.commit();
1840  assert(false);
1841  }
1842  catch (soci_error const &e)
1843  {
1844  std::string msg = e.what();
1845  assert(msg ==
1846  "The transaction object cannot be handled twice.");
1847  }
1848  }
1849  }
1850 
1851  std::cout << "test 10 passed" << std::endl;
1852 }
1853 
1854 // test of use elements with indicators
1855 void test11()
1856 {
1857 #ifndef SOCI_POSTGRESQL_NOPARAMS
1858  {
1859  session sql(backEndFactory_, connectString_);
1860 
1861  auto_table_creator tableCreator(tc_.table_creator_1(sql));
1862 
1863  indicator ind1 = i_ok;
1864  indicator ind2 = i_ok;
1865 
1866  int id = 1;
1867  int val = 10;
1868 
1869  sql << "insert into soci_test(id, val) values(:id, :val)",
1870  use(id, ind1), use(val, ind2);
1871 
1872  id = 2;
1873  val = 11;
1874  ind2 = i_null;
1875  sql << "insert into soci_test(id, val) values(:id, :val)",
1876  use(id, ind1), use(val, ind2);
1877 
1878  sql << "select val from soci_test where id = 1", into(val, ind2);
1879  assert(ind2 == i_ok);
1880  assert(val == 10);
1881  sql << "select val from soci_test where id = 2", into(val, ind2);
1882  assert(ind2 == i_null);
1883 
1884  std::vector<int> ids;
1885  ids.push_back(3);
1886  ids.push_back(4);
1887  ids.push_back(5);
1888  std::vector<int> vals;
1889  vals.push_back(12);
1890  vals.push_back(13);
1891  vals.push_back(14);
1892  std::vector<indicator> inds;
1893  inds.push_back(i_ok);
1894  inds.push_back(i_null);
1895  inds.push_back(i_ok);
1896 
1897  sql << "insert into soci_test(id, val) values(:id, :val)",
1898  use(ids), use(vals, inds);
1899 
1900  ids.resize(5);
1901  vals.resize(5);
1902  sql << "select id, val from soci_test order by id desc",
1903  into(ids), into(vals, inds);
1904 
1905  assert(ids.size() == 5);
1906  assert(ids[0] == 5);
1907  assert(ids[1] == 4);
1908  assert(ids[2] == 3);
1909  assert(ids[3] == 2);
1910  assert(ids[4] == 1);
1911  assert(inds.size() == 5);
1912  assert(inds[0] == i_ok);
1913  assert(inds[1] == i_null);
1914  assert(inds[2] == i_ok);
1915  assert(inds[3] == i_null);
1916  assert(inds[4] == i_ok);
1917  assert(vals.size() == 5);
1918  assert(vals[0] == 14);
1919  assert(vals[2] == 12);
1920  assert(vals[4] == 10);
1921  }
1922 
1923  std::cout << "test 11 passed" << std::endl;
1924 
1925 #endif // SOCI_POSTGRESQL_NOPARAMS
1926 }
1927 
1928 // Dynamic binding to Row objects
1929 void test12()
1930 {
1931  {
1932  session sql(backEndFactory_, connectString_);
1933 
1934  sql.uppercase_column_names(true);
1935 
1936  auto_table_creator tableCreator(tc_.table_creator_2(sql));
1937 
1938  row r;
1939  sql << "select * from soci_test", into(r);
1940  assert(sql.got_data() == false);
1941 
1942  sql << "insert into soci_test"
1943  " values(3.14, 123, \'Johny\',"
1944  << tc_.to_date_time("2005-12-19 22:14:17")
1945  << ", 'a')";
1946 
1947  // select into a row
1948  {
1949  row r;
1950  statement st = (sql.prepare <<
1951  "select * from soci_test", into(r));
1952  st.execute(true);
1953  assert(r.size() == 5);
1954 
1955  assert(r.get_properties(0).get_data_type() == dt_double);
1956  assert(r.get_properties(1).get_data_type() == dt_integer);
1957  assert(r.get_properties(2).get_data_type() == dt_string);
1958  assert(r.get_properties(3).get_data_type() == dt_date);
1959 
1960  // type char is visible as string
1961  // - to comply with the implementation for Oracle
1962  assert(r.get_properties(4).get_data_type() == dt_string);
1963 
1964  assert(r.get_properties("NUM_INT").get_data_type() == dt_integer);
1965 
1966  assert(r.get_properties(0).get_name() == "NUM_FLOAT");
1967  assert(r.get_properties(1).get_name() == "NUM_INT");
1968  assert(r.get_properties(2).get_name() == "NAME");
1969  assert(r.get_properties(3).get_name() == "SOMETIME");
1970  assert(r.get_properties(4).get_name() == "CHR");
1971 
1972  assert(equal_approx(r.get<double>(0), 3.14));
1973  assert(r.get<int>(1) == 123);
1974  assert(r.get<std::string>(2) == "Johny");
1975  std::tm t = { 0 };
1976  t = r.get<std::tm>(3);
1977  assert(t.tm_year == 105);
1978 
1979  // again, type char is visible as string
1980  assert(r.get<std::string>(4) == "a");
1981 
1982  assert(equal_approx(r.get<double>("NUM_FLOAT"), 3.14));
1983  assert(r.get<int>("NUM_INT") == 123);
1984  assert(r.get<std::string>("NAME") == "Johny");
1985  assert(r.get<std::string>("CHR") == "a");
1986 
1987  assert(r.get_indicator(0) == i_ok);
1988 
1989  // verify exception thrown on invalid get<>
1990  bool caught = false;
1991  try
1992  {
1993  r.get<std::string>(0);
1994  }
1995  catch (std::bad_cast const &)
1996  {
1997  caught = true;
1998  }
1999  assert(caught);
2000 
2001  // additional test for stream-like extraction
2002  {
2003  double d;
2004  int i;
2005  std::string s;
2006  std::tm t;
2007  std::string c;
2008 
2009  r >> d >> i >> s >> t >> c;
2010 
2011  assert(equal_approx(d, 3.14));
2012  assert(i == 123);
2013  assert(s == "Johny");
2014  assert(t.tm_year == 105);
2015  assert(t.tm_mon == 11);
2016  assert(t.tm_mday == 19);
2017  assert(t.tm_hour == 22);
2018  assert(t.tm_min == 14);
2019  assert(t.tm_sec == 17);
2020  assert(c == "a");
2021  }
2022  }
2023 
2024  // additional test to check if the row object can be
2025  // reused between queries
2026  {
2027  row r;
2028  sql << "select * from soci_test", into(r);
2029 
2030  assert(r.size() == 5);
2031 
2032  assert(r.get_properties(0).get_data_type() == dt_double);
2033  assert(r.get_properties(1).get_data_type() == dt_integer);
2034  assert(r.get_properties(2).get_data_type() == dt_string);
2035  assert(r.get_properties(3).get_data_type() == dt_date);
2036 
2037  sql << "select name, num_int from soci_test", into(r);
2038 
2039  assert(r.size() == 2);
2040 
2041  assert(r.get_properties(0).get_data_type() == dt_string);
2042  assert(r.get_properties(1).get_data_type() == dt_integer);
2043  }
2044  }
2045 
2046  std::cout << "test 12 passed" << std::endl;
2047 }
2048 
2049 // more dynamic bindings
2050 void test13()
2051 {
2052  session sql(backEndFactory_, connectString_);
2053 
2054  auto_table_creator tableCreator(tc_.table_creator_1(sql));
2055 
2056  sql << "insert into soci_test(id, val) values(1, 10)";
2057  sql << "insert into soci_test(id, val) values(2, 20)";
2058  sql << "insert into soci_test(id, val) values(3, 30)";
2059 
2060 #ifndef SOCI_POSTGRESQL_NOPARAMS
2061  {
2062  int id = 2;
2063  row r;
2064  sql << "select val from soci_test where id = :id", use(id), into(r);
2065 
2066  assert(r.size() == 1);
2067  assert(r.get_properties(0).get_data_type() == dt_integer);
2068  assert(r.get<int>(0) == 20);
2069  }
2070  {
2071  int id;
2072  row r;
2073  statement st = (sql.prepare <<
2074  "select val from soci_test where id = :id", use(id), into(r));
2075 
2076  id = 2;
2077  st.execute(true);
2078  assert(r.size() == 1);
2079  assert(r.get_properties(0).get_data_type() == dt_integer);
2080  assert(r.get<int>(0) == 20);
2081 
2082  id = 3;
2083  st.execute(true);
2084  assert(r.size() == 1);
2085  assert(r.get_properties(0).get_data_type() == dt_integer);
2086  assert(r.get<int>(0) == 30);
2087 
2088  id = 1;
2089  st.execute(true);
2090  assert(r.size() == 1);
2091  assert(r.get_properties(0).get_data_type() == dt_integer);
2092  assert(r.get<int>(0) == 10);
2093  }
2094 #else
2095  {
2096  row r;
2097  sql << "select val from soci_test where id = 2", into(r);
2098 
2099  assert(r.size() == 1);
2100  assert(r.get_properties(0).get_data_type() == dt_integer);
2101  assert(r.get<int>(0) == 20);
2102  }
2103 #endif // SOCI_POSTGRESQL_NOPARAMS
2104 
2105  std::cout << "test 13 passed" << std::endl;
2106 }
2107 
2108 // More Dynamic binding to row objects
2109 void test14()
2110 {
2111  {
2112  session sql(backEndFactory_, connectString_);
2113 
2114  sql.uppercase_column_names(true);
2115 
2116  auto_table_creator tableCreator(tc_.table_creator_3(sql));
2117 
2118  row r1;
2119  sql << "select * from soci_test", into(r1);
2120  assert(sql.got_data() == false);
2121 
2122  sql << "insert into soci_test values('david', '(404)123-4567')";
2123  sql << "insert into soci_test values('john', '(404)123-4567')";
2124  sql << "insert into soci_test values('doe', '(404)123-4567')";
2125 
2126  row r2;
2127  statement st = (sql.prepare << "select * from soci_test", into(r2));
2128  st.execute();
2129 
2130  assert(r2.size() == 2);
2131 
2132  int count = 0;
2133  while (st.fetch())
2134  {
2135  ++count;
2136  assert(r2.get<std::string>("PHONE") == "(404)123-4567");
2137  }
2138  assert(count == 3);
2139  }
2140  std::cout << "test 14 passed" << std::endl;
2141 }
2142 
2143 // test15 is like test14 but with a type_conversion instead of a row
2144 void test15()
2145 {
2146  session sql(backEndFactory_, connectString_);
2147 
2148  sql.uppercase_column_names(true);
2149 
2150  // simple conversion (between single basic type and user type)
2151 
2152  {
2153  auto_table_creator tableCreator(tc_.table_creator_1(sql));
2154 
2155  MyInt mi;
2156  mi.set(123);
2157  sql << "insert into soci_test(id) values(:id)", use(mi);
2158 
2159  int i;
2160  sql << "select id from soci_test", into(i);
2161  assert(i == 123);
2162 
2163  sql << "update soci_test set id = id + 1";
2164 
2165  sql << "select id from soci_test", into(mi);
2166  assert(mi.get() == 124);
2167  }
2168 
2169  // simple conversion with use const
2170 
2171  {
2172  auto_table_creator tableCreator(tc_.table_creator_1(sql));
2173 
2174  MyInt mi;
2175  mi.set(123);
2176 
2177  MyInt const & cmi = mi;
2178  sql << "insert into soci_test(id) values(:id)", use(cmi);
2179 
2180  int i;
2181  sql << "select id from soci_test", into(i);
2182  assert(i == 123);
2183  }
2184 
2185  // conversions based on values (many fields involved -> ORM)
2186 
2187  {
2188  auto_table_creator tableCreator(tc_.table_creator_3(sql));
2189 
2190  PhonebookEntry p1;
2191  sql << "select * from soci_test", into(p1);
2192  assert(p1.name == "");
2193  assert(p1.phone == "");
2194 
2195  p1.name = "david";
2196 
2197  // Note: uppercase column names are used here (and later on)
2198  // for consistency with how they can be read from database
2199  // (which means forced to uppercase on Oracle) and how they are
2200  // set/get in the type conversion routines for PhonebookEntry.
2201  // In short, IF the database is Oracle,
2202  // then all column names for binding should be uppercase.
2203  sql << "insert into soci_test values(:NAME, :PHONE)", use(p1);
2204  sql << "insert into soci_test values('john', '(404)123-4567')";
2205  sql << "insert into soci_test values('doe', '(404)123-4567')";
2206 
2207  PhonebookEntry p2;
2208  statement st = (sql.prepare << "select * from soci_test", into(p2));
2209  st.execute();
2210 
2211  int count = 0;
2212  while (st.fetch())
2213  {
2214  ++count;
2215  if (p2.name == "david")
2216  {
2217  // see type_conversion<PhonebookEntry>
2218  assert(p2.phone =="<NULL>");
2219  }
2220  else
2221  {
2222  assert(p2.phone == "(404)123-4567");
2223  }
2224  }
2225  assert(count == 3);
2226  }
2227 
2228  // conversions based on values with use const
2229 
2230  {
2231  auto_table_creator tableCreator(tc_.table_creator_3(sql));
2232 
2233  PhonebookEntry p1;
2234  p1.name = "Joe Coder";
2235  p1.phone = "123-456";
2236 
2237  PhonebookEntry const & cp1 = p1;
2238 
2239  sql << "insert into soci_test values(:NAME, :PHONE)", use(cp1);
2240 
2241  PhonebookEntry p2;
2242  sql << "select * from soci_test", into(p2);
2243  assert(sql.got_data());
2244 
2245  assert(p2.name == "Joe Coder");
2246  assert(p2.phone == "123-456");
2247  }
2248 
2249  // conversions based on accessor functions (as opposed to direct variable bindings)
2250 
2251  {
2252  auto_table_creator tableCreator(tc_.table_creator_3(sql));
2253 
2254  PhonebookEntry3 p1;
2255  p1.setName("Joe Hacker");
2256  p1.setPhone("10010110");
2257 
2258  sql << "insert into soci_test values(:NAME, :PHONE)", use(p1);
2259 
2260  PhonebookEntry3 p2;
2261  sql << "select * from soci_test", into(p2);
2262  assert(sql.got_data());
2263 
2264  assert(p2.getName() == "Joe Hacker");
2265  assert(p2.getPhone() == "10010110");
2266  }
2267 
2268  {
2269  // Use the PhonebookEntry2 type conversion, to test
2270  // calls to values::get_indicator()
2271  auto_table_creator tableCreator(tc_.table_creator_3(sql));
2272 
2273  PhonebookEntry2 p1;
2274  sql << "select * from soci_test", into(p1);
2275  assert(p1.name == "");
2276  assert(p1.phone == "");
2277  p1.name = "david";
2278 
2279  sql << "insert into soci_test values(:NAME, :PHONE)", use(p1);
2280  sql << "insert into soci_test values('john', '(404)123-4567')";
2281  sql << "insert into soci_test values('doe', '(404)123-4567')";
2282 
2283  PhonebookEntry2 p2;
2284  statement st = (sql.prepare << "select * from soci_test", into(p2));
2285  st.execute();
2286 
2287  int count = 0;
2288  while (st.fetch())
2289  {
2290  ++count;
2291  if (p2.name == "david")
2292  {
2293  // see type_conversion<PhonebookEntry2>
2294  assert(p2.phone =="<NULL>");
2295  }
2296  else
2297  {
2298  assert(p2.phone == "(404)123-4567");
2299  }
2300  }
2301  assert(count == 3);
2302  }
2303 
2304  std::cout << "test 15 passed" << std::endl;
2305 }
2306 
2308 {
2309  {
2310  session sql(backEndFactory_, connectString_);
2311 
2312  sql.uppercase_column_names(true);
2313  auto_table_creator tableCreator(tc_.table_creator_3(sql));
2314 
2315  PhonebookEntry temp;
2316  PhonebookEntry e1 = { "name1", "phone1" };
2317  PhonebookEntry e2 = { "name2", "phone2" };
2318 
2319  //sql << "insert into soci_test values (:NAME, :PHONE)", use(temp);
2320  statement insertStatement = (sql.prepare << "insert into soci_test values (:NAME, :PHONE)", use(temp));
2321 
2322  temp = e1;
2323  insertStatement.execute(true);
2324  temp = e2;
2325  insertStatement.execute(true);
2326 
2327  int count = 0;
2328 
2329  sql << "select count(*) from soci_test where NAME in ('name1', 'name2')", into(count);
2330 
2331  assert(count == 2);
2332  }
2333 
2334  std::cout << "test test_prepared_insert_with_orm_type passed" << std::endl;
2335 }
2336 
2338 {
2339  {
2340  session sql(backEndFactory_, connectString_);
2341  sql.uppercase_column_names(true);
2342  auto_table_creator tableCreator(tc_.table_creator_3(sql));
2343 
2344  PhonebookEntry in = { "name1", "phone1" };
2345  std::string name = "nameA";
2346  sql << "insert into soci_test values (:NAMED, :PHONE)", use(in), use(name, "NAMED");
2347 
2348  PhonebookEntry out;
2349  sql << "select * from soci_test where PHONE = 'phone1'", into(out);
2350  assert(out.name == "nameA");
2351  assert(out.phone == "phone1");
2352  }
2353 
2354  std::cout << "test test_placeholder_partial_matching_with_orm_type passed" << std::endl;
2355 }
2356 
2357 // test for bulk fetch with single use
2358 void test16()
2359 {
2360 #ifndef SOCI_POSTGRESQL_NOPARAMS
2361  {
2362  session sql(backEndFactory_, connectString_);
2363 
2364  auto_table_creator tableCreator(tc_.table_creator_1(sql));
2365 
2366  sql << "insert into soci_test(name, id) values('john', 1)";
2367  sql << "insert into soci_test(name, id) values('george', 2)";
2368  sql << "insert into soci_test(name, id) values('anthony', 1)";
2369  sql << "insert into soci_test(name, id) values('marc', 3)";
2370  sql << "insert into soci_test(name, id) values('julian', 1)";
2371 
2372  int code = 1;
2373  std::vector<std::string> names(10);
2374  sql << "select name from soci_test where id = :id order by name",
2375  into(names), use(code);
2376 
2377  assert(names.size() == 3);
2378  assert(names[0] == "anthony");
2379  assert(names[1] == "john");
2380  assert(names[2] == "julian");
2381  }
2382 #endif // SOCI_POSTGRESQL_NOPARAMS
2383 
2384  std::cout << "test 16 passed" << std::endl;
2385 }
2386 
2387 // test for basic logging support
2388 void test17()
2389 {
2390  session sql(backEndFactory_, connectString_);
2391 
2392  std::ostringstream log;
2393  sql.set_log_stream(&log);
2394 
2395  try
2396  {
2397  sql << "drop table soci_test1";
2398  }
2399  catch (...) {}
2400 
2401  assert(sql.get_last_query() == "drop table soci_test1");
2402 
2403  sql.set_log_stream(NULL);
2404 
2405  try
2406  {
2407  sql << "drop table soci_test2";
2408  }
2409  catch (...) {}
2410 
2411  assert(sql.get_last_query() == "drop table soci_test2");
2412 
2413  sql.set_log_stream(&log);
2414 
2415  try
2416  {
2417  sql << "drop table soci_test3";
2418  }
2419  catch (...) {}
2420 
2421  assert(sql.get_last_query() == "drop table soci_test3");
2422  assert(log.str() ==
2423  "drop table soci_test1\n"
2424  "drop table soci_test3\n");
2425 
2426  std::cout << "test 17 passed\n";
2427 }
2428 
2429 // test for rowset creation and copying
2430 void test18()
2431 {
2432  session sql(backEndFactory_, connectString_);
2433 
2434  // create and populate the test table
2435  auto_table_creator tableCreator(tc_.table_creator_1(sql));
2436  {
2437  // Open empty rowset
2438  rowset<row> rs1 = (sql.prepare << "select * from soci_test");
2439  assert(rs1.begin() == rs1.end());
2440  }
2441 
2442  {
2443  // Copy construction
2444  rowset<row> rs1 = (sql.prepare << "select * from soci_test");
2445  rowset<row> rs2(rs1);
2446  rowset<row> rs3(rs1);
2447  rowset<row> rs4(rs3);
2448 
2449  assert(rs1.begin() == rs2.begin());
2450  assert(rs1.begin() == rs3.begin());
2451  assert(rs1.end() == rs2.end());
2452  assert(rs1.end() == rs3.end());
2453  }
2454 
2455  {
2456  // Assignment
2457  rowset<row> rs1 = (sql.prepare << "select * from soci_test");
2458  rowset<row> rs2 = (sql.prepare << "select * from soci_test");
2459  rowset<row> rs3 = (sql.prepare << "select * from soci_test");
2460  rs1 = rs2;
2461  rs3 = rs2;
2462 
2463  assert(rs1.begin() == rs2.begin());
2464  assert(rs1.begin() == rs3.begin());
2465  assert(rs1.end() == rs2.end());
2466  assert(rs1.end() == rs3.end());
2467  }
2468  std::cout << "test 18 passed" << std::endl;
2469 }
2470 
2471 // test for simple iterating using rowset iterator (without reading data)
2472 void test19()
2473 {
2474  session sql(backEndFactory_, connectString_);
2475 
2476  // create and populate the test table
2477  auto_table_creator tableCreator(tc_.table_creator_1(sql));
2478  {
2479  sql << "insert into soci_test(id, val) values(1, 10)";
2480  sql << "insert into soci_test(id, val) values(2, 11)";
2481  sql << "insert into soci_test(id, val) values(3, NULL)";
2482  sql << "insert into soci_test(id, val) values(4, NULL)";
2483  sql << "insert into soci_test(id, val) values(5, 12)";
2484  {
2485  rowset<row> rs = (sql.prepare << "select * from soci_test");
2486 
2487  assert(5 == std::distance(rs.begin(), rs.end()));
2488  }
2489  }
2490 
2491  std::cout << "test 19 passed" << std::endl;
2492 }
2493 
2494 // test for reading rowset<row> using iterator
2495 void test20()
2496 {
2497  session sql(backEndFactory_, connectString_);
2498 
2499  sql.uppercase_column_names(true);
2500 
2501  // create and populate the test table
2502  auto_table_creator tableCreator(tc_.table_creator_2(sql));
2503  {
2504  {
2505  // Empty rowset
2506  rowset<row> rs = (sql.prepare << "select * from soci_test");
2507  assert(0 == std::distance(rs.begin(), rs.end()));
2508  }
2509 
2510  {
2511  // Non-empty rowset
2512  sql << "insert into soci_test values(3.14, 123, \'Johny\',"
2513  << tc_.to_date_time("2005-12-19 22:14:17")
2514  << ", 'a')";
2515  sql << "insert into soci_test values(6.28, 246, \'Robert\',"
2516  << tc_.to_date_time("2004-10-01 18:44:10")
2517  << ", 'b')";
2518 
2519  rowset<row> rs = (sql.prepare << "select * from soci_test");
2520 
2522  assert(it != rs.end());
2523 
2524  //
2525  // First row
2526  //
2527  row const & r1 = (*it);
2528 
2529  // Properties
2530  assert(r1.size() == 5);
2531  assert(r1.get_properties(0).get_data_type() == dt_double);
2532  assert(r1.get_properties(1).get_data_type() == dt_integer);
2533  assert(r1.get_properties(2).get_data_type() == dt_string);
2534  assert(r1.get_properties(3).get_data_type() == dt_date);
2535  assert(r1.get_properties(4).get_data_type() == dt_string);
2536  assert(r1.get_properties("NUM_INT").get_data_type() == dt_integer);
2537 
2538  // Data
2539 
2540  // Since we didn't specify order by in the above query,
2541  // the 2 rows may be returned in either order
2542  // (If we specify order by, we can't do it in a cross db
2543  // compatible way, because the Oracle table for this has been
2544  // created with lower case column names)
2545 
2546  std::string name = r1.get<std::string>(2);
2547 
2548  assert(name == "Johny" || name == "Robert");
2549  if (name == "Johny")
2550  {
2551  assert(equal_approx(r1.get<double>(0), 3.14));
2552  assert(r1.get<int>(1) == 123);
2553  assert(r1.get<std::string>(2) == "Johny");
2554  std::tm t1 = { 0 };
2555  t1 = r1.get<std::tm>(3);
2556  assert(t1.tm_year == 105);
2557  assert(r1.get<std::string>(4) == "a");
2558  assert(equal_approx(r1.get<double>("NUM_FLOAT"), 3.14));
2559  assert(r1.get<int>("NUM_INT") == 123);
2560  assert(r1.get<std::string>("NAME") == "Johny");
2561  assert(r1.get<std::string>("CHR") == "a");
2562  }
2563  else
2564  {
2565  assert(equal_approx(r1.get<double>(0), 6.28));
2566  assert(r1.get<int>(1) == 246);
2567  assert(r1.get<std::string>(2) == "Robert");
2568  std::tm t1 = r1.get<std::tm>(3);
2569  assert(t1.tm_year == 104);
2570  assert(r1.get<std::string>(4) == "b");
2571  assert(equal_approx(r1.get<double>("NUM_FLOAT"), 6.28));
2572  assert(r1.get<int>("NUM_INT") == 246);
2573  assert(r1.get<std::string>("NAME") == "Robert");
2574  assert(r1.get<std::string>("CHR") == "b");
2575  }
2576 
2577  //
2578  // Iterate to second row
2579  //
2580  ++it;
2581  assert(it != rs.end());
2582 
2583  //
2584  // Second row
2585  //
2586  row const & r2 = (*it);
2587 
2588  // Properties
2589  assert(r2.size() == 5);
2590  assert(r2.get_properties(0).get_data_type() == dt_double);
2591  assert(r2.get_properties(1).get_data_type() == dt_integer);
2592  assert(r2.get_properties(2).get_data_type() == dt_string);
2593  assert(r2.get_properties(3).get_data_type() == dt_date);
2594  assert(r2.get_properties(4).get_data_type() == dt_string);
2595  assert(r2.get_properties("NUM_INT").get_data_type() == dt_integer);
2596 
2597  std::string newName = r2.get<std::string>(2);
2598  assert(name != newName);
2599  assert(newName == "Johny" || newName == "Robert");
2600 
2601  if (newName == "Johny")
2602  {
2603  assert(equal_approx(r2.get<double>(0), 3.14));
2604  assert(r2.get<int>(1) == 123);
2605  assert(r2.get<std::string>(2) == "Johny");
2606  std::tm t2 = r2.get<std::tm>(3);
2607  assert(t2.tm_year == 105);
2608  assert(r2.get<std::string>(4) == "a");
2609  assert(equal_approx(r2.get<double>("NUM_FLOAT"), 3.14));
2610  assert(r2.get<int>("NUM_INT") == 123);
2611  assert(r2.get<std::string>("NAME") == "Johny");
2612  assert(r2.get<std::string>("CHR") == "a");
2613  }
2614  else
2615  {
2616  assert(equal_approx(r2.get<double>(0), 6.28));
2617  assert(r2.get<int>(1) == 246);
2618  assert(r2.get<std::string>(2) == "Robert");
2619  std::tm t2 = r2.get<std::tm>(3);
2620  assert(t2.tm_year == 104);
2621  assert(r2.get<std::string>(4) == "b");
2622  assert(equal_approx(r2.get<double>("NUM_FLOAT"), 6.28));
2623  assert(r2.get<int>("NUM_INT") == 246);
2624  assert(r2.get<std::string>("NAME") == "Robert");
2625  assert(r2.get<std::string>("CHR") == "b");
2626  }
2627  }
2628 
2629  {
2630  // Non-empty rowset with NULL values
2631  sql << "insert into soci_test "
2632  << "(num_int, num_float , name, sometime, chr) "
2633  << "values (0, NULL, NULL, NULL, NULL)";
2634 
2635  rowset<row> rs = (sql.prepare
2636  << "select num_int, num_float, name, sometime, chr "
2637  << "from soci_test where num_int = 0");
2638 
2640  assert(it != rs.end());
2641 
2642  //
2643  // First row
2644  //
2645  row const& r1 = (*it);
2646 
2647  // Properties
2648  assert(r1.size() == 5);
2649  assert(r1.get_properties(0).get_data_type() == dt_integer);
2650  assert(r1.get_properties(1).get_data_type() == dt_double);
2651  assert(r1.get_properties(2).get_data_type() == dt_string);
2652  assert(r1.get_properties(3).get_data_type() == dt_date);
2653  assert(r1.get_properties(4).get_data_type() == dt_string);
2654 
2655  // Data
2656  assert(r1.get_indicator(0) == soci::i_ok);
2657  assert(r1.get<int>(0) == 0);
2658  assert(r1.get_indicator(1) == soci::i_null);
2659  assert(r1.get_indicator(2) == soci::i_null);
2660  assert(r1.get_indicator(3) == soci::i_null);
2661  assert(r1.get_indicator(4) == soci::i_null);
2662  }
2663  }
2664 
2665  std::cout << "test 20 passed" << std::endl;
2666 }
2667 
2668 // test for reading rowset<int> using iterator
2669 void test21()
2670 {
2671  session sql(backEndFactory_, connectString_);
2672 
2673  // create and populate the test table
2674  auto_table_creator tableCreator(tc_.table_creator_1(sql));
2675  {
2676  sql << "insert into soci_test(id) values(1)";
2677  sql << "insert into soci_test(id) values(2)";
2678  sql << "insert into soci_test(id) values(3)";
2679  sql << "insert into soci_test(id) values(4)";
2680  sql << "insert into soci_test(id) values(5)";
2681  {
2682  rowset<int> rs = (sql.prepare << "select id from soci_test order by id asc");
2683 
2684  // 1st row
2686  assert(1 == (*pos));
2687 
2688  // 3rd row
2689  std::advance(pos, 2);
2690  assert(3 == (*pos));
2691 
2692  // 5th row
2693  std::advance(pos, 2);
2694  assert(5 == (*pos));
2695 
2696  // The End
2697  ++pos;
2698  assert(pos == rs.end());
2699  }
2700  }
2701 
2702  std::cout << "test 21 passed" << std::endl;
2703 }
2704 
2705 // test for handling 'use' and reading rowset<std::string> using iterator
2706 void test22()
2707 {
2708  session sql(backEndFactory_, connectString_);
2709 
2710  // create and populate the test table
2711  auto_table_creator tableCreator(tc_.table_creator_1(sql));
2712  {
2713  sql << "insert into soci_test(str) values('abc')";
2714  sql << "insert into soci_test(str) values('def')";
2715  sql << "insert into soci_test(str) values('ghi')";
2716  sql << "insert into soci_test(str) values('jkl')";
2717  {
2718  // Expected result in numbers
2719  std::string idle("def");
2720  rowset<std::string> rs1 = (sql.prepare
2721  << "select str from soci_test where str = :idle",
2722  use(idle));
2723 
2724  assert(1 == std::distance(rs1.begin(), rs1.end()));
2725 
2726  // Expected result in value
2727  idle = "jkl";
2728  rowset<std::string> rs2 = (sql.prepare
2729  << "select str from soci_test where str = :idle",
2730  use(idle));
2731 
2732  assert(idle == *(rs2.begin()));
2733  }
2734  }
2735 
2736  std::cout << "test 22 passed" << std::endl;
2737 }
2738 
2739 // test for handling troublemaker
2740 void test23()
2741 {
2742  session sql(backEndFactory_, connectString_);
2743 
2744  // create and populate the test table
2745  auto_table_creator tableCreator(tc_.table_creator_1(sql));
2746  {
2747  sql << "insert into soci_test(str) values('abc')";
2748  {
2749  // verify exception thrown
2750  bool caught = false;
2751  try
2752  {
2753  std::string troublemaker;
2754  rowset<std::string> rs1 = (sql.prepare << "select str from soci_test",
2755  into(troublemaker));
2756  }
2757  catch (soci_error const&)
2758  {
2759  caught = true;
2760  }
2761  assert(caught);
2762  }
2763  std::cout << "test 23 passed" << std::endl;
2764  }
2765 
2766 }
2767 
2768 // test for handling NULL values with expected exception:
2769 // "Null value fetched and no indicator defined."
2770 void test24()
2771 {
2772  session sql(backEndFactory_, connectString_);
2773 
2774  // create and populate the test table
2775  auto_table_creator tableCreator(tc_.table_creator_1(sql));
2776  {
2777  sql << "insert into soci_test(val) values(1)";
2778  sql << "insert into soci_test(val) values(2)";
2779  sql << "insert into soci_test(val) values(NULL)";
2780  sql << "insert into soci_test(val) values(3)";
2781  {
2782  // verify exception thrown
2783  bool caught = false;
2784  try
2785  {
2786  rowset<int> rs = (sql.prepare << "select val from soci_test order by val asc");
2787 
2788  int tester = 0;
2789  for (rowset<int>::const_iterator it = rs.begin(); it != rs.end(); ++it)
2790  {
2791  tester = *it;
2792  }
2793  (void)tester;
2794 
2795  // Never should get here
2796  assert(false);
2797  }
2798  catch (soci_error const&)
2799  {
2800  caught = true;
2801  }
2802  assert(caught);
2803  }
2804  std::cout << "test 24 passed" << std::endl;
2805  }
2806 }
2807 
2808 // test25 is like test15 but with rowset and iterators use
2809 void test25()
2810 {
2811  session sql(backEndFactory_, connectString_);
2812 
2813  sql.uppercase_column_names(true);
2814 
2815  {
2816  auto_table_creator tableCreator(tc_.table_creator_3(sql));
2817 
2818  PhonebookEntry p1;
2819  sql << "select * from soci_test", into(p1);
2820  assert(p1.name == "");
2821  assert(p1.phone == "");
2822 
2823  p1.name = "david";
2824 
2825  sql << "insert into soci_test values(:NAME, :PHONE)", use(p1);
2826  sql << "insert into soci_test values('john', '(404)123-4567')";
2827  sql << "insert into soci_test values('doe', '(404)123-4567')";
2828 
2829  rowset<PhonebookEntry> rs = (sql.prepare << "select * from soci_test");
2830 
2831  int count = 0;
2832  for (rowset<PhonebookEntry>::const_iterator it = rs.begin(); it != rs.end(); ++it)
2833  {
2834  ++count;
2835  PhonebookEntry const& p2 = (*it);
2836  if (p2.name == "david")
2837  {
2838  // see type_conversion<PhonebookEntry>
2839  assert(p2.phone =="<NULL>");
2840  }
2841  else
2842  {
2843  assert(p2.phone == "(404)123-4567");
2844  }
2845  }
2846 
2847  assert(3 == count);
2848  }
2849  std::cout << "test 25 passed" << std::endl;
2850 }
2851 
2852 // test for handling NULL values with boost::optional
2853 // (both into and use)
2854 void test26()
2855 {
2856 #ifdef HAVE_BOOST
2857 
2858  session sql(backEndFactory_, connectString_);
2859 
2860  // create and populate the test table
2861  auto_table_creator tableCreator(tc_.table_creator_1(sql));
2862  {
2863  sql << "insert into soci_test(val) values(7)";
2864 
2865  {
2866  // verify non-null value is fetched correctly
2867  boost::optional<int> opt;
2868  sql << "select val from soci_test", into(opt);
2869  assert(opt.is_initialized());
2870  assert(opt.get() == 7);
2871 
2872  // indicators can be used with optional
2873  // (although that's just a consequence of implementation,
2874  // not an intended feature - but let's test it anyway)
2875  indicator ind;
2876  opt.reset();
2877  sql << "select val from soci_test", into(opt, ind);
2878  assert(opt.is_initialized());
2879  assert(opt.get() == 7);
2880  assert(ind == i_ok);
2881 
2882  // verify null value is fetched correctly
2883  sql << "select i1 from soci_test", into(opt);
2884  assert(opt.is_initialized() == false);
2885 
2886  // and with indicator
2887  opt = 5;
2888  sql << "select i1 from soci_test", into(opt, ind);
2889  assert(opt.is_initialized() == false);
2890  assert(ind == i_null);
2891 
2892  // verify non-null is inserted correctly
2893  opt = 3;
2894  sql << "update soci_test set val = :v", use(opt);
2895  int j = 0;
2896  sql << "select val from soci_test", into(j);
2897  assert(j == 3);
2898 
2899  // verify null is inserted correctly
2900  opt.reset();
2901  sql << "update soci_test set val = :v", use(opt);
2902  ind = i_ok;
2903  sql << "select val from soci_test", into(j, ind);
2904  assert(ind == i_null);
2905  }
2906 
2907  // vector tests (select)
2908 
2909  {
2910  sql << "delete from soci_test";
2911 
2912  // simple readout of non-null data
2913 
2914  sql << "insert into soci_test(id, val, str) values(1, 5, \'abc\')";
2915  sql << "insert into soci_test(id, val, str) values(2, 6, \'def\')";
2916  sql << "insert into soci_test(id, val, str) values(3, 7, \'ghi\')";
2917  sql << "insert into soci_test(id, val, str) values(4, 8, null)";
2918  sql << "insert into soci_test(id, val, str) values(5, 9, \'mno\')";
2919 
2920  std::vector<boost::optional<int> > v(10);
2921  sql << "select val from soci_test order by val", into(v);
2922 
2923  assert(v.size() == 5);
2924  assert(v[0].is_initialized());
2925  assert(v[0].get() == 5);
2926  assert(v[1].is_initialized());
2927  assert(v[1].get() == 6);
2928  assert(v[2].is_initialized());
2929  assert(v[2].get() == 7);
2930  assert(v[3].is_initialized());
2931  assert(v[3].get() == 8);
2932  assert(v[4].is_initialized());
2933  assert(v[4].get() == 9);
2934 
2935  // readout of nulls
2936 
2937  sql << "update soci_test set val = null where id = 2 or id = 4";
2938 
2939  std::vector<int> ids(5);
2940  sql << "select id, val from soci_test order by id", into(ids), into(v);
2941 
2942  assert(v.size() == 5);
2943  assert(ids.size() == 5);
2944  assert(v[0].is_initialized());
2945  assert(v[0].get() == 5);
2946  assert(v[1].is_initialized() == false);
2947  assert(v[2].is_initialized());
2948  assert(v[2].get() == 7);
2949  assert(v[3].is_initialized() == false);
2950  assert(v[4].is_initialized());
2951  assert(v[4].get() == 9);
2952 
2953  // readout with statement preparation
2954 
2955  int id = 1;
2956 
2957  ids.resize(3);
2958  v.resize(3);
2959  statement st = (sql.prepare <<
2960  "select id, val from soci_test order by id", into(ids), into(v));
2961  st.execute();
2962  while (st.fetch())
2963  {
2964  for (std::size_t i = 0; i != v.size(); ++i)
2965  {
2966  assert(id == ids[i]);
2967 
2968  if (id == 2 || id == 4)
2969  {
2970  assert(v[i].is_initialized() == false);
2971  }
2972  else
2973  {
2974  assert(v[i].is_initialized() && v[i].get() == id + 4);
2975  }
2976 
2977  ++id;
2978  }
2979 
2980  ids.resize(3);
2981  v.resize(3);
2982  }
2983  assert(id == 6);
2984  }
2985 
2986  // and why not stress iterators and the dynamic binding, too!
2987 
2988  {
2989  rowset<row> rs = (sql.prepare << "select id, val, str from soci_test order by id");
2990 
2992  assert(it != rs.end());
2993 
2994  row const& r1 = (*it);
2995 
2996  assert(r1.size() == 3);
2997 
2998  // Note: for the reason of differences between number(x,y) type and
2999  // binary representation of integers, the following commented assertions
3000  // do not work for Oracle.
3001  // The problem is that for this single table the data type used in Oracle
3002  // table creator for the id column is number(10,0),
3003  // which allows to insert all int values.
3004  // On the other hand, the column description scheme used in the Oracle
3005  // backend figures out that the natural type for such a column
3006  // is eUnsignedInt - this makes the following assertions fail.
3007  // Other database backends (like PostgreSQL) use other types like int
3008  // and this not only allows to insert all int values (obviously),
3009  // but is also recognized as int (obviously).
3010  // There is a similar problem with stream-like extraction,
3011  // where internally get<T> is called and the type mismatch is detected
3012  // for the id column - that's why the code below skips this column
3013  // and tests the remaining column only.
3014 
3015  //assert(r1.get_properties(0).get_data_type() == dt_integer);
3016  assert(r1.get_properties(1).get_data_type() == dt_integer);
3017  assert(r1.get_properties(2).get_data_type() == dt_string);
3018  //assert(r1.get<int>(0) == 1);
3019  assert(r1.get<int>(1) == 5);
3020  assert(r1.get<std::string>(2) == "abc");
3021  assert(r1.get<boost::optional<int> >(1).is_initialized());
3022  assert(r1.get<boost::optional<int> >(1).get() == 5);
3023  assert(r1.get<boost::optional<std::string> >(2).is_initialized());
3024  assert(r1.get<boost::optional<std::string> >(2).get() == "abc");
3025 
3026  ++it;
3027 
3028  row const& r2 = (*it);
3029 
3030  assert(r2.size() == 3);
3031 
3032  // assert(r2.get_properties(0).get_data_type() == dt_integer);
3033  assert(r2.get_properties(1).get_data_type() == dt_integer);
3034  assert(r2.get_properties(2).get_data_type() == dt_string);
3035  //assert(r2.get<int>(0) == 2);
3036  try
3037  {
3038  // expect exception here, this is NULL value
3039  (void)r1.get<int>(1);
3040  assert(false);
3041  }
3042  catch (soci_error const &) {}
3043 
3044  // but we can read it as optional
3045  assert(r2.get<boost::optional<int> >(1).is_initialized() == false);
3046 
3047  // stream-like data extraction
3048 
3049  ++it;
3050  row const &r3 = (*it);
3051 
3052  boost::optional<int> io;
3053  boost::optional<std::string> so;
3054 
3055  r3.skip(); // move to val and str columns
3056  r3 >> io >> so;
3057 
3058  assert(io.is_initialized() && io.get() == 7);
3059  assert(so.is_initialized() && so.get() == "ghi");
3060 
3061  ++it;
3062  row const &r4 = (*it);
3063 
3064  r3.skip(); // move to val and str columns
3065  r4 >> io >> so;
3066 
3067  assert(io.is_initialized() == false);
3068  assert(so.is_initialized() == false);
3069  }
3070 
3071  // bulk inserts of non-null data
3072 
3073  {
3074  sql << "delete from soci_test";
3075 
3076  std::vector<int> ids;
3077  std::vector<boost::optional<int> > v;
3078 
3079  ids.push_back(10); v.push_back(20);
3080  ids.push_back(11); v.push_back(21);
3081  ids.push_back(12); v.push_back(22);
3082  ids.push_back(13); v.push_back(23);
3083 
3084  sql << "insert into soci_test(id, val) values(:id, :val)",
3085  use(ids, "id"), use(v, "val");
3086 
3087  int sum;
3088  sql << "select sum(val) from soci_test", into(sum);
3089  assert(sum == 86);
3090 
3091  // bulk inserts of some-null data
3092 
3093  sql << "delete from soci_test";
3094 
3095  v[2].reset();
3096  v[3].reset();
3097 
3098  sql << "insert into soci_test(id, val) values(:id, :val)",
3099  use(ids, "id"), use(v, "val");
3100 
3101  sql << "select sum(val) from soci_test", into(sum);
3102  assert(sum == 41);
3103  }
3104 
3105  // composability with user conversions
3106 
3107  {
3108  sql << "delete from soci_test";
3109 
3110  boost::optional<MyInt> omi1;
3111  boost::optional<MyInt> omi2;
3112 
3113  omi1 = MyInt(125);
3114  omi2.reset();
3115 
3116  sql << "insert into soci_test(id, val) values(:id, :val)",
3117  use(omi1), use(omi2);
3118 
3119  sql << "select id, val from soci_test", into(omi2), into(omi1);
3120 
3121  assert(omi1.is_initialized() == false);
3122  assert(omi2.is_initialized() && omi2.get().get() == 125);
3123  }
3124 
3125  // use with const optional and user conversions
3126 
3127  {
3128  sql << "delete from soci_test";
3129 
3130  boost::optional<MyInt> omi1;
3131  boost::optional<MyInt> omi2;
3132 
3133  omi1 = MyInt(125);
3134  omi2.reset();
3135 
3136  boost::optional<MyInt> const & comi1 = omi1;
3137  boost::optional<MyInt> const & comi2 = omi2;
3138 
3139  sql << "insert into soci_test(id, val) values(:id, :val)",
3140  use(comi1), use(comi2);
3141 
3142  sql << "select id, val from soci_test", into(omi2), into(omi1);
3143 
3144  assert(omi1.is_initialized() == false);
3145  assert(omi2.is_initialized() && omi2.get().get() == 125);
3146  }
3147 
3148  // use with rowset and table containing null values
3149 
3150  {
3151  auto_table_creator tableCreator(tc_.table_creator_1(sql));
3152 
3153  sql << "insert into soci_test(id, val) values(1, 10)";
3154  sql << "insert into soci_test(id, val) values(2, 11)";
3155  sql << "insert into soci_test(id, val) values(3, NULL)";
3156  sql << "insert into soci_test(id, val) values(4, 13)";
3157 
3158  rowset<boost::optional<int> > rs = (sql.prepare <<
3159  "select val from soci_test order by id asc");
3160 
3161  // 1st row
3162  rowset<boost::optional<int> >::const_iterator pos = rs.begin();
3163  assert((*pos).is_initialized());
3164  assert(10 == (*pos).get());
3165 
3166  // 2nd row
3167  ++pos;
3168  assert((*pos).is_initialized());
3169  assert(11 == (*pos).get());
3170 
3171  // 3rd row
3172  ++pos;
3173  assert((*pos).is_initialized() == false);
3174 
3175  // 4th row
3176  ++pos;
3177  assert((*pos).is_initialized());
3178  assert(13 == (*pos).get());
3179  }
3180  }
3181 
3182  std::cout << "test 26 passed" << std::endl;
3183 #else
3184  std::cout << "test 26 skipped (no Boost)" << std::endl;
3185 #endif // HAVE_BOOST
3186 }
3187 
3188 // connection and reconnection tests
3189 void test27()
3190 {
3191  {
3192  // empty session
3193  session sql;
3194 
3195  // idempotent:
3196  sql.close();
3197 
3198  try
3199  {
3200  sql.reconnect();
3201  assert(false);
3202  }
3203  catch (soci_error const &e)
3204  {
3205  assert(e.what() == std::string(
3206  "Cannot reconnect without previous connection."));
3207  }
3208 
3209  // open from empty session
3210  sql.open(backEndFactory_, connectString_);
3211  sql.close();
3212 
3213  // reconnecting from closed session
3214  sql.reconnect();
3215 
3216  // opening already connected session
3217  try
3218  {
3219  sql.open(backEndFactory_, connectString_);
3220  assert(false);
3221  }
3222  catch (soci_error const &e)
3223  {
3224  assert(e.what() == std::string(
3225  "Cannot open already connected session."));
3226  }
3227 
3228  sql.close();
3229 
3230  // open from closed
3231  sql.open(backEndFactory_, connectString_);
3232 
3233  // reconnect from already connected session
3234  sql.reconnect();
3235  }
3236 
3237  {
3238  session sql;
3239 
3240  try
3241  {
3242  sql << "this statement cannot execute";
3243  assert(false);
3244  }
3245  catch (soci_error const &e)
3246  {
3247  assert(e.what() == std::string("Session is not connected."));
3248  }
3249  }
3250 
3251  std::cout << "test 27 passed" << std::endl;
3252 }
3253 
3254 void test28()
3255 {
3256 #ifdef HAVE_BOOST
3257  session sql(backEndFactory_, connectString_);
3258 
3259  auto_table_creator tableCreator(tc_.table_creator_2(sql));
3260  {
3261  boost::tuple<double, int, std::string> t1(3.5, 7, "Joe Hacker");
3262  assert(equal_approx(t1.get<0>(), 3.5));
3263  assert(t1.get<1>() == 7);
3264  assert(t1.get<2>() == "Joe Hacker");
3265 
3266  sql << "insert into soci_test(num_float, num_int, name) values(:d, :i, :s)", use(t1);
3267 
3268  // basic query
3269 
3270  boost::tuple<double, int, std::string> t2;
3271  sql << "select num_float, num_int, name from soci_test", into(t2);
3272 
3273  assert(equal_approx(t2.get<0>(), 3.5));
3274  assert(t2.get<1>() == 7);
3275  assert(t2.get<2>() == "Joe Hacker");
3276 
3277  sql << "delete from soci_test";
3278  }
3279 
3280  {
3281  // composability with boost::optional
3282 
3283  // use:
3284  boost::tuple<double, boost::optional<int>, std::string> t1(
3285  3.5, boost::optional<int>(7), "Joe Hacker");
3286  assert(equal_approx(t1.get<0>(), 3.5));
3287  assert(t1.get<1>().is_initialized());
3288  assert(t1.get<1>().get() == 7);
3289  assert(t1.get<2>() == "Joe Hacker");
3290 
3291  sql << "insert into soci_test(num_float, num_int, name) values(:d, :i, :s)", use(t1);
3292 
3293  // into:
3294  boost::tuple<double, boost::optional<int>, std::string> t2;
3295  sql << "select num_float, num_int, name from soci_test", into(t2);
3296 
3297  assert(equal_approx(t2.get<0>(), 3.5));
3298  assert(t2.get<1>().is_initialized());
3299  assert(t2.get<1>().get() == 7);
3300  assert(t2.get<2>() == "Joe Hacker");
3301 
3302  sql << "delete from soci_test";
3303  }
3304 
3305  {
3306  // composability with user-provided conversions
3307 
3308  // use:
3309  boost::tuple<double, MyInt, std::string> t1(3.5, 7, "Joe Hacker");
3310  assert(equal_approx(t1.get<0>(), 3.5));
3311  assert(t1.get<1>().get() == 7);
3312  assert(t1.get<2>() == "Joe Hacker");
3313 
3314  sql << "insert into soci_test(num_float, num_int, name) values(:d, :i, :s)", use(t1);
3315 
3316  // into:
3317  boost::tuple<double, MyInt, std::string> t2;
3318 
3319  sql << "select num_float, num_int, name from soci_test", into(t2);
3320 
3321  assert(equal_approx(t2.get<0>(), 3.5));
3322  assert(t2.get<1>().get() == 7);
3323  assert(t2.get<2>() == "Joe Hacker");
3324 
3325  sql << "delete from soci_test";
3326  }
3327 
3328  {
3329  // let's have fun - composition of tuple, optional and user-defined type
3330 
3331  // use:
3332  boost::tuple<double, boost::optional<MyInt>, std::string> t1(
3333  3.5, boost::optional<MyInt>(7), "Joe Hacker");
3334  assert(equal_approx(t1.get<0>(), 3.5));
3335  assert(t1.get<1>().is_initialized());
3336  assert(t1.get<1>().get().get() == 7);
3337  assert(t1.get<2>() == "Joe Hacker");
3338 
3339  sql << "insert into soci_test(num_float, num_int, name) values(:d, :i, :s)", use(t1);
3340 
3341  // into:
3342  boost::tuple<double, boost::optional<MyInt>, std::string> t2;
3343 
3344  sql << "select num_float, num_int, name from soci_test", into(t2);
3345 
3346  assert(equal_approx(t2.get<0>(), 3.5));
3347  assert(t2.get<1>().is_initialized());
3348  assert(t2.get<1>().get().get() == 7);
3349  assert(t2.get<2>() == "Joe Hacker");
3350 
3351  sql << "update soci_test set num_int = NULL";
3352 
3353  sql << "select num_float, num_int, name from soci_test", into(t2);
3354 
3355  assert(equal_approx(t2.get<0>(), 3.5));
3356  assert(t2.get<1>().is_initialized() == false);
3357  assert(t2.get<2>() == "Joe Hacker");
3358  }
3359 
3360  {
3361  // rowset<tuple>
3362 
3363  sql << "insert into soci_test(num_float, num_int, name) values(4.0, 8, 'Tony Coder')";
3364  sql << "insert into soci_test(num_float, num_int, name) values(4.5, NULL, 'Cecile Sharp')";
3365  sql << "insert into soci_test(num_float, num_int, name) values(5.0, 10, 'Djhava Ravaa')";
3366 
3367  typedef boost::tuple<double, boost::optional<int>, std::string> T;
3368 
3369  rowset<T> rs = (sql.prepare
3370  << "select num_float, num_int, name from soci_test order by num_float asc");
3371 
3372  rowset<T>::const_iterator pos = rs.begin();
3373 
3374  assert(equal_approx(pos->get<0>(), 3.5));
3375  assert(pos->get<1>().is_initialized() == false);
3376  assert(pos->get<2>() == "Joe Hacker");
3377 
3378  ++pos;
3379  assert(equal_approx(pos->get<0>(), 4.0));
3380  assert(pos->get<1>().is_initialized());
3381  assert(pos->get<1>().get() == 8);
3382  assert(pos->get<2>() == "Tony Coder");
3383 
3384  ++pos;
3385  assert(equal_approx(pos->get<0>(), 4.5));
3386  assert(pos->get<1>().is_initialized() == false);
3387  assert(pos->get<2>() == "Cecile Sharp");
3388 
3389  ++pos;
3390  assert(equal_approx(pos->get<0>(), 5.0));
3391  assert(pos->get<1>().is_initialized());
3392  assert(pos->get<1>().get() == 10);
3393  assert(pos->get<2>() == "Djhava Ravaa");
3394 
3395  ++pos;
3396  assert(pos == rs.end());
3397  }
3398 
3399  std::cout << "test 28 passed" << std::endl;
3400 #else
3401  std::cout << "test 28 skipped (no Boost)" << std::endl;
3402 #endif // HAVE_BOOST
3403 }
3404 
3405 void test29()
3406 {
3407 #ifdef HAVE_BOOST
3408 #if defined(BOOST_VERSION) && BOOST_VERSION >= 103500
3409 
3410  session sql(backEndFactory_, connectString_);
3411 
3412  auto_table_creator tableCreator(tc_.table_creator_2(sql));
3413  {
3414  boost::fusion::vector<double, int, std::string> t1(3.5, 7, "Joe Hacker");
3415  assert(equal_approx(boost::fusion::at_c<0>(t1), 3.5));
3416  assert(boost::fusion::at_c<1>(t1) == 7);
3417  assert(boost::fusion::at_c<2>(t1) == "Joe Hacker");
3418 
3419  sql << "insert into soci_test(num_float, num_int, name) values(:d, :i, :s)", use(t1);
3420 
3421  // basic query
3422 
3423  boost::fusion::vector<double, int, std::string> t2;
3424  sql << "select num_float, num_int, name from soci_test", into(t2);
3425 
3426  assert(equal_approx(boost::fusion::at_c<0>(t2), 3.5));
3427  assert(boost::fusion::at_c<1>(t2) == 7);
3428  assert(boost::fusion::at_c<2>(t2) == "Joe Hacker");
3429 
3430  sql << "delete from soci_test";
3431  }
3432 
3433  {
3434  // composability with boost::optional
3435 
3436  // use:
3437  boost::fusion::vector<double, boost::optional<int>, std::string> t1(
3438  3.5, boost::optional<int>(7), "Joe Hacker");
3439  assert(equal_approx(boost::fusion::at_c<0>(t1), 3.5));
3440  assert(boost::fusion::at_c<1>(t1).is_initialized());
3441  assert(boost::fusion::at_c<1>(t1).get() == 7);
3442  assert(boost::fusion::at_c<2>(t1) == "Joe Hacker");
3443 
3444  sql << "insert into soci_test(num_float, num_int, name) values(:d, :i, :s)", use(t1);
3445 
3446  // into:
3447  boost::fusion::vector<double, boost::optional<int>, std::string> t2;
3448  sql << "select num_float, num_int, name from soci_test", into(t2);
3449 
3450  assert(equal_approx(boost::fusion::at_c<0>(t2), 3.5));
3451  assert(boost::fusion::at_c<1>(t2).is_initialized());
3452  assert(boost::fusion::at_c<1>(t2) == 7);
3453  assert(boost::fusion::at_c<2>(t2) == "Joe Hacker");
3454 
3455  sql << "delete from soci_test";
3456  }
3457 
3458  {
3459  // composability with user-provided conversions
3460 
3461  // use:
3462  boost::fusion::vector<double, MyInt, std::string> t1(3.5, 7, "Joe Hacker");
3463  assert(equal_approx(boost::fusion::at_c<0>(t1), 3.5));
3464  assert(boost::fusion::at_c<1>(t1).get() == 7);
3465  assert(boost::fusion::at_c<2>(t1) == "Joe Hacker");
3466 
3467  sql << "insert into soci_test(num_float, num_int, name) values(:d, :i, :s)", use(t1);
3468 
3469  // into:
3470  boost::fusion::vector<double, MyInt, std::string> t2;
3471 
3472  sql << "select num_float, num_int, name from soci_test", into(t2);
3473 
3474  assert(equal_approx(boost::fusion::at_c<0>(t2), 3.5));
3475  assert(boost::fusion::at_c<1>(t2).get() == 7);
3476  assert(boost::fusion::at_c<2>(t2) == "Joe Hacker");
3477 
3478  sql << "delete from soci_test";
3479  }
3480 
3481  {
3482  // let's have fun - composition of tuple, optional and user-defined type
3483 
3484  // use:
3485  boost::fusion::vector<double, boost::optional<MyInt>, std::string> t1(
3486  3.5, boost::optional<MyInt>(7), "Joe Hacker");
3487  assert(equal_approx(boost::fusion::at_c<0>(t1), 3.5));
3488  assert(boost::fusion::at_c<1>(t1).is_initialized());
3489  assert(boost::fusion::at_c<1>(t1).get().get() == 7);
3490  assert(boost::fusion::at_c<2>(t1) == "Joe Hacker");
3491 
3492  sql << "insert into soci_test(num_float, num_int, name) values(:d, :i, :s)", use(t1);
3493 
3494  // into:
3495  boost::fusion::vector<double, boost::optional<MyInt>, std::string> t2;
3496 
3497  sql << "select num_float, num_int, name from soci_test", into(t2);
3498 
3499  assert(equal_approx(boost::fusion::at_c<0>(t2), 3.5));
3500  assert(boost::fusion::at_c<1>(t2).is_initialized());
3501  assert(boost::fusion::at_c<1>(t2).get().get() == 7);
3502  assert(boost::fusion::at_c<2>(t2) == "Joe Hacker");
3503 
3504  sql << "update soci_test set num_int = NULL";
3505 
3506  sql << "select num_float, num_int, name from soci_test", into(t2);
3507 
3508  assert(equal_approx(boost::fusion::at_c<0>(t2), 3.5));
3509  assert(boost::fusion::at_c<1>(t2).is_initialized() == false);
3510  assert(boost::fusion::at_c<2>(t2) == "Joe Hacker");
3511  }
3512 
3513  {
3514  // rowset<fusion::vector>
3515 
3516  sql << "insert into soci_test(num_float, num_int, name) values(4.0, 8, 'Tony Coder')";
3517  sql << "insert into soci_test(num_float, num_int, name) values(4.5, NULL, 'Cecile Sharp')";
3518  sql << "insert into soci_test(num_float, num_int, name) values(5.0, 10, 'Djhava Ravaa')";
3519 
3520  typedef boost::fusion::vector<double, boost::optional<int>, std::string> T;
3521 
3522  rowset<T> rs = (sql.prepare
3523  << "select num_float, num_int, name from soci_test order by num_float asc");
3524 
3525  rowset<T>::const_iterator pos = rs.begin();
3526 
3527  assert(equal_approx(boost::fusion::at_c<0>(*pos), 3.5));
3528  assert(boost::fusion::at_c<1>(*pos).is_initialized() == false);
3529  assert(boost::fusion::at_c<2>(*pos) == "Joe Hacker");
3530 
3531  ++pos;
3532  assert(equal_approx(boost::fusion::at_c<0>(*pos), 4.0));
3533  assert(boost::fusion::at_c<1>(*pos).is_initialized());
3534  assert(boost::fusion::at_c<1>(*pos).get() == 8);
3535  assert(boost::fusion::at_c<2>(*pos) == "Tony Coder");
3536 
3537  ++pos;
3538  assert(equal_approx(boost::fusion::at_c<0>(*pos), 4.5));
3539  assert(boost::fusion::at_c<1>(*pos).is_initialized() == false);
3540  assert(boost::fusion::at_c<2>(*pos) == "Cecile Sharp");
3541 
3542  ++pos;
3543  assert(equal_approx(boost::fusion::at_c<0>(*pos), 5.0));
3544  assert(boost::fusion::at_c<1>(*pos).is_initialized());
3545  assert(boost::fusion::at_c<1>(*pos).get() == 10);
3546  assert(boost::fusion::at_c<2>(*pos) == "Djhava Ravaa");
3547 
3548  ++pos;
3549  assert(pos == rs.end());
3550  }
3551 
3552  std::cout << "test 29 passed" << std::endl;
3553 
3554 #else
3555  std::cout << "test 29 skipped (no boost::fusion)" << std::endl;
3556 #endif // BOOST_VERSION
3557 
3558 #else
3559  std::cout << "test 29 skipped (no Boost)" << std::endl;
3560 #endif // HAVE_BOOST
3561 }
3562 
3563 // test for boost::gregorian::date
3564 void test30()
3565 {
3566 #ifdef HAVE_BOOST
3567 
3568  session sql(backEndFactory_, connectString_);
3569 
3570  {
3571  auto_table_creator tableCreator(tc_.table_creator_1(sql));
3572 
3573  std::tm nov15;
3574  nov15.tm_year = 105;
3575  nov15.tm_mon = 10;
3576  nov15.tm_mday = 15;
3577  nov15.tm_hour = 0;
3578  nov15.tm_min = 0;
3579  nov15.tm_sec = 0;
3580 
3581  sql << "insert into soci_test(tm) values(:tm)", use(nov15);
3582 
3583  boost::gregorian::date bgd;
3584  sql << "select tm from soci_test", into(bgd);
3585 
3586  assert(bgd.year() == 2005);
3587  assert(bgd.month() == 11);
3588  assert(bgd.day() == 15);
3589 
3590  sql << "update soci_test set tm = NULL";
3591  try
3592  {
3593  sql << "select tm from soci_test", into(bgd);
3594  assert(false);
3595  }
3596  catch (soci_error const & e)
3597  {
3598  assert(e.what() == std::string("Null value not allowed for this type"));
3599  }
3600  }
3601 
3602  {
3603  auto_table_creator tableCreator(tc_.table_creator_1(sql));
3604 
3605  boost::gregorian::date bgd(2008, boost::gregorian::May, 5);
3606 
3607  sql << "insert into soci_test(tm) values(:tm)", use(bgd);
3608 
3609  std::tm t;
3610  sql << "select tm from soci_test", into(t);
3611 
3612  assert(t.tm_year == 108);
3613  assert(t.tm_mon == 4);
3614  assert(t.tm_mday == 5);
3615  }
3616 
3617  std::cout << "test 30 passed" << std::endl;
3618 #else
3619  std::cout << "test 30 skipped (no Boost)" << std::endl;
3620 #endif // HAVE_BOOST
3621 }
3622 
3623 // connection pool - simple sequential test, no multiple threads
3624 void test31()
3625 {
3626  {
3627  // phase 1: preparation
3628  const size_t pool_size = 10;
3629  connection_pool pool(pool_size);
3630 
3631  for (std::size_t i = 0; i != pool_size; ++i)
3632  {
3633  session & sql = pool.at(i);
3634  sql.open(backEndFactory_, connectString_);
3635  }
3636 
3637  // phase 2: usage
3638  for (std::size_t i = 0; i != pool_size; ++i)
3639  {
3640  // poor man way to lease more than one connection
3641  session sql_unused1(pool);
3642  session sql(pool);
3643  session sql_unused2(pool);
3644  {
3645  auto_table_creator tableCreator(tc_.table_creator_1(sql));
3646 
3647  char c('a');
3648  sql << "insert into soci_test(c) values(:c)", use(c);
3649  sql << "select c from soci_test", into(c);
3650  assert(c == 'a');
3651  }
3652  }
3653  }
3654  std::cout << "test 31 passed\n";
3655 }
3656 
3657 // Issue 66 - test query transformation callback feature
3658 static std::string no_op_transform(std::string query)
3659 {
3660  return query;
3661 }
3662 
3663 static std::string lower_than_g(std::string query)
3664 {
3665  return query + " WHERE c < 'g'";
3666 }
3667 
3668 struct where_condition : std::unary_function<std::string, std::string>
3669 {
3670  where_condition(std::string const& where)
3671  : where_(where)
3672  {}
3673 
3674  result_type operator()(argument_type query) const
3675  {
3676  return query + " WHERE " + where_;
3677  }
3678 
3679  std::string where_;
3680 };
3681 
3682 
3684 {
3685  // create and populate the test table
3686  auto_table_creator tableCreator(tc_.table_creator_1(sql));
3687 
3688  for (char c = 'a'; c <= 'z'; ++c)
3689  {
3690  sql << "insert into soci_test(c) values(\'" << c << "\')";
3691  }
3692 
3693  char const* query = "select count(*) from soci_test";
3694 
3695  // free function, no-op
3696  {
3697  sql.set_query_transformation(no_op_transform);
3698  int count;
3699  sql << query, into(count);
3700  assert(count == 'z' - 'a' + 1);
3701  }
3702 
3703  // free function
3704  {
3705  sql.set_query_transformation(lower_than_g);
3706  int count;
3707  sql << query, into(count);
3708  assert(count == 'g' - 'a');
3709  }
3710 
3711  // function object with state
3712  {
3713  sql.set_query_transformation(where_condition("c > 'g' AND c < 'j'"));
3714  int count = 0;
3715  sql << query, into(count);
3716  assert(count == 'j' - 'h');
3717  count = 0;
3718  sql.set_query_transformation(where_condition("c > 's' AND c <= 'z'"));
3719  sql << query, into(count);
3720  assert(count == 'z' - 's');
3721  }
3722 
3723 // Bug in Visual Studio __cplusplus still means C++03
3724 // https://connect.microsoft.com/VisualStudio/feedback/details/763051/
3725 #if defined _MSC_VER && _MSC_VER>=1600
3726 #define SOCI_HAVE_CPP11 1
3727 #elif __cplusplus >= 201103L
3728 #define SOCI_HAVE_CPP11 1
3729 #else
3730 #undef SOCI_HAVE_CPP11
3731 #endif
3732 
3733 #ifdef SOCI_HAVE_CPP11
3734  // lambda
3735  {
3737  [](std::string const& query) {
3738  return query + " WHERE c > 'g' AND c < 'j'";
3739  });
3740 
3741  int count = 0;
3742  sql << query, into(count);
3743  assert(count == 'j' - 'h');
3744  }
3745 #endif
3746 #undef SOCI_HAVE_CPP11
3747 
3748  // prepared statements
3749 
3750  // constant effect (pre-prepare set transformation)
3751  {
3752  // set transformation after statement is prepared
3753  sql.set_query_transformation(lower_than_g);
3754  // prepare statement
3755  int count;
3756  statement st = (sql.prepare << query, into(count));
3757  // observe transformation effect
3758  st.execute(true);
3759  assert(count == 'g' - 'a');
3760  // reset transformation
3761  sql.set_query_transformation(no_op_transform);
3762  // observe the same transformation, no-op set above has no effect
3763  count = 0;
3764  st.execute(true);
3765  assert(count == 'g' - 'a');
3766  }
3767 
3768  // no effect (post-prepare set transformation)
3769  {
3770  // reset
3771  sql.set_query_transformation(no_op_transform);
3772 
3773  // prepare statement
3774  int count;
3775  statement st = (sql.prepare << query, into(count));
3776  // set transformation after statement is prepared
3777  sql.set_query_transformation(lower_than_g);
3778  // observe no effect of WHERE clause injection
3779  st.execute(true);
3780  assert(count == 'z' - 'a' + 1);
3781  }
3782 }
3783 
3785 {
3786  {
3787  session sql(backEndFactory_, connectString_);
3788  run_query_transformation_test(sql);
3789  }
3790  std::cout << "test query_transformation passed" << std::endl;
3791 }
3793 {
3794  {
3795  // phase 1: preparation
3796  const size_t pool_size = 10;
3797  connection_pool pool(pool_size);
3798 
3799  for (std::size_t i = 0; i != pool_size; ++i)
3800  {
3801  session & sql = pool.at(i);
3802  sql.open(backEndFactory_, connectString_);
3803  }
3804 
3805  session sql(pool);
3806  run_query_transformation_test(sql);
3807  }
3808  std::cout << "test query_transformation with connection pool passed" << std::endl;
3809 }
3810 
3811 // Originally, submitted to SQLite3 backend and later moved to common test.
3812 // Test commit b394d039530f124802d06c3b1a969c3117683152
3813 // Author: Mika Fischer <mika.fischer@zoopnet.de>
3814 // Date: Thu Nov 17 13:28:07 2011 +0100
3815 // Implement get_affected_rows for SQLite3 backend
3817 {
3818  {
3819  session sql(backEndFactory_, connectString_);
3820  auto_table_creator tableCreator(tc_.table_creator_4(sql));
3821  if (!tableCreator.get())
3822  {
3823  std::cout << "test get_affected_rows skipped (function not implemented)" << std::endl;
3824  return;
3825  }
3826 
3827  for (int i = 0; i != 10; i++)
3828  {
3829  sql << "insert into soci_test(val) values(:val)", use(i);
3830  }
3831 
3832  statement st1 = (sql.prepare <<
3833  "update soci_test set val = val + 1");
3834  st1.execute(true);
3835 
3836  assert(st1.get_affected_rows() == 10);
3837 
3838  statement st2 = (sql.prepare <<
3839  "delete from soci_test where val <= 5");
3840  st2.execute(true);
3841 
3842  assert(st2.get_affected_rows() == 5);
3843 
3844  statement st3 = (sql.prepare <<
3845  "update soci_test set val = val + 1");
3846  st3.execute(true);
3847 
3848  assert(st3.get_affected_rows() == 5);
3849 
3850  std::vector<int> v(5, 0);
3851  for (std::size_t i = 0; i < v.size(); ++i)
3852  {
3853  v[i] = (7 + i);
3854  }
3855 
3856  // test affected rows for bulk operations.
3857  statement st4 = (sql.prepare <<
3858  "delete from soci_test where val = :v", use(v));
3859  st4.execute(true);
3860 
3861  assert(st4.get_affected_rows() == 5);
3862 
3863  std::vector<std::string> w(2, "1");
3864  w[1] = "a"; // this invalid value may cause an exception.
3865  statement st5 = (sql.prepare <<
3866  "insert into soci_test(val) values(:val)", use(w));
3867  try { st5.execute(true); }
3868  catch(...) {}
3869 
3870  // confirm the partial insertion.
3871  int val = 0;
3872  sql << "select count(val) from soci_test", into(val);
3873  if(val != 0)
3874  {
3875  // test the preserved 'number of rows
3876  // affected' after a potential failure.
3877  assert(st5.get_affected_rows() != 0);
3878  }
3879  }
3880 
3881  std::cout << "test get_affected_rows passed" << std::endl;
3882 }
3883 
3884 // test fix for: Backend is not set properly with connection pool (pull #5)
3886 {
3887  {
3888  const size_t pool_size = 1;
3889  connection_pool pool(pool_size);
3890 
3891  for (std::size_t i = 0; i != pool_size; ++i)
3892  {
3893  session & sql = pool.at(i);
3894  sql.open(backEndFactory_, connectString_);
3895  }
3896 
3897  soci::session sql(pool);
3898  sql.reconnect();
3899  sql.begin(); // no crash expected
3900  }
3901 
3902  std::cout << "test pull-5 passed\n";
3903 }
3904 
3905 // issue 67 - Allocated statement backend memory leaks on exception
3906 // If the test runs under memory debugger and it passes, then
3907 // soci::details::statement_impl::backEnd_ must not leak
3909 {
3910  session sql(backEndFactory_, connectString_);
3911  auto_table_creator tableCreator(tc_.table_creator_1(sql));
3912  {
3913  try
3914  {
3915  rowset<row> rs1 = (sql.prepare << "select * from soci_testX");
3916 
3917  // TODO: On Linux, no exception thrown; neither from prepare, nor from execute?
3918  // soci_odbc_test_postgresql:
3919  // /home/travis/build/SOCI/soci/src/core/test/common-tests.h:3505:
3920  // void soci::tests::common_tests::test_issue67(): Assertion `!"exception expected"' failed.
3921  //assert(!"exception expected"); // relax temporarily
3922  }
3923  catch (soci_error const &e)
3924  {
3925  (void)e;
3926  assert("expected exception caught");
3927  std::cout << "test issue-67 passed - check memory debugger output for leaks" << std::endl;
3928  }
3929  }
3930 
3931 }
3932 
3933 // issue 154 - Calling undefine_and_bind and then define_and_bind causes a leak.
3934 // If the test runs under memory debugger and it passes, then
3935 // soci::details::standard_use_type_backend and vector_use_type_backend must not leak
3937 {
3938  session sql(backEndFactory_, connectString_);
3939  auto_table_creator tableCreator(tc_.table_creator_1(sql));
3940  sql << "insert into soci_test(id) values (1)";
3941  {
3942  int id = 1;
3943  int val = 0;
3944  statement st(sql);
3945  st.exchange(use(id));
3946  st.alloc();
3947  st.prepare("select id from soci_test where id = :1");
3948  st.define_and_bind();
3949  st.undefine_and_bind();
3950  st.exchange(soci::into(val));
3951  st.define_and_bind();
3952  st.execute(true);
3953  assert(val == 1);
3954  }
3955  // vector variation
3956  {
3957  std::vector<int> ids(1, 2);
3958  std::vector<int> vals(1, 1);
3959  int val = 0;
3960  statement st(sql);
3961  st.exchange(use(ids));
3962  st.alloc();
3963  st.prepare("insert into soci_test(id, val) values (:1, :2)");
3964  st.define_and_bind();
3965  st.undefine_and_bind();
3966  st.exchange(use(vals));
3967  st.define_and_bind();
3968  st.execute(true);
3969  sql << "select val from soci_test where id = 2", into(val);
3970  assert(val == 1);
3971  }
3972  std::cout << "test issue-154 passed - check memory debugger output for leaks" << std::endl;
3973 }
3974 
3975 }; // class common_tests
3976 
3977 } // namespace tests
3978 
3979 } // namespace soci
3980 
3981 #endif // SOCI_COMMON_TESTS_H_INCLUDED
column_properties const & get_properties(std::size_t pos) const
Definition: row.cpp:91
std::string getName() const
Definition: common-tests.h:48
const_iterator begin() const
Definition: rowset.h:220
static std::string lower_than_g(std::string query)
void test11()
bool got_data() const
T get(std::size_t pos) const
Definition: row.h:66
details::into_container< T, details::no_indicator > into(T &t)
Definition: into.h:51
std::string get_last_query() const
backend_factory const & backEnd
Definition: test-db2.cpp:22
void set(std::string const &name, T const &value, indicator indic=i_ok)
Definition: values.h:166
virtual table_creator_base * table_creator_4(session &) const =0
test_context_base const & tc_
Definition: common-tests.h:349
bool equal_approx(double const a, double const b)
Definition: common-tests.h:180
#define SOCI_TEST_ENSURE_CONNECTED(sql, method)
Definition: common-tests.h:164
data_type get_data_type() const
Definition: row.h:31
void run(bool dbSupportsTransactions=true)
Definition: common-tests.h:293
static void to_base(PhonebookEntry const &pe, values &v, indicator &ind)
Definition: common-tests.h:105
static std::string no_op_transform(std::string query)
Definition: row.h:41
void test12()
std::string get_name() const
Definition: row.h:30
void test9()
void run_query_transformation_test(session &sql)
void test10()
std::string phone_
Definition: common-tests.h:55
indicator get_indicator(std::size_t pos) const
Definition: values.cpp:20
std::size_t size() const
Definition: row.cpp:60
std::string name
Definition: common-tests.h:36
void undefine_and_bind()
Definition: statement.h:207
session & at(std::size_t pos)
std::string const connectString_
Definition: common-tests.h:351
virtual table_creator_base * table_creator_1(session &) const =0
std::string name_
Definition: common-tests.h:54
void skip(std::size_t num=1) const
Definition: row.h:119
const_iterator end() const
Definition: rowset.h:227
void prepare(std::string const &query, details::statement_type eType=details::st_repeatable_query)
Definition: statement.h:200
std::string phone
Definition: common-tests.h:37
void test3()
Definition: test-db2.cpp:339
static void from_base(values const &v, indicator, PhonebookEntry2 &pe)
Definition: common-tests.h:118
static void from_base(values const &v, indicator, PhonebookEntry &pe)
Definition: common-tests.h:98
int get() const
Definition: common-tests.h:65
std::string const connectString_
Definition: common-tests.h:281
virtual std::string to_date_time(std::string const &dateTime) const =0
long long get_affected_rows()
Definition: statement.h:214
void uppercase_column_names(bool forceToUpper)
void test8()
void test15()
Definition: test-mysql.cpp:842
backend_factory const & backEndFactory_
Definition: common-tests.h:280
void test2()
Definition: test-db2.cpp:293
indicator get_indicator(std::size_t pos) const
Definition: row.cpp:80
void setPhone(std::string const &p)
Definition: common-tests.h:50
void setName(std::string const &n)
Definition: common-tests.h:47
static void from_base(values const &v, indicator, PhonebookEntry3 &pe)
Definition: common-tests.h:139
std::string get_connect_string() const
Definition: common-tests.h:265
static void to_base(PhonebookEntry3 const &pe, values &v, indicator &ind)
Definition: common-tests.h:147
#define SOCI_TEST_ENSURE_CONNECTED2(sql, method)
Definition: common-tests.h:172
void set_log_stream(std::ostream *s)
void test4()
virtual table_creator_base * table_creator_3(session &) const =0
backend_factory const & get_backend_factory() const
Definition: common-tests.h:260
void test6()
void set(int i)
Definition: common-tests.h:64
void test5()
void set_query_transformation(T callback)
Definition: session.h:79
void define_and_bind()
Definition: statement.h:206
void open(connection_parameters const &parameters)
std::string getPhone() const
Definition: common-tests.h:51
int i_
Definition: common-tests.h:67
std::string connectString
Definition: test-db2.cpp:21
void test13()
static void to_base(PhonebookEntry2 const &pe, values &v, indicator &ind)
Definition: common-tests.h:127
std::auto_ptr< table_creator_base > auto_table_creator
Definition: common-tests.h:353
void test7()
common_tests(test_context_base const &tc)
Definition: common-tests.h:287
T get(std::size_t pos) const
Definition: values.h:58
result_type operator()(argument_type query) const
void test14()
Definition: test-mysql.cpp:823
where_condition(std::string const &where)
void test1()
Definition: test-db2.cpp:106
virtual table_creator_base * table_creator_2(session &) const =0
details::prepare_type prepare
Definition: session.h:69
void exchange(details::into_type_ptr const &i)
Definition: statement.h:192
void test_query_transformation_with_connection_pool()
test_context_base(backend_factory const &backEnd, std::string const &connectString)
Definition: common-tests.h:255
void test_placeholder_partial_matching_with_orm_type()
details::use_container< T, details::no_indicator > use(T &t, const std::string &name=std::string())
Definition: use.h:43
static void from_base(int i, indicator ind, MyInt &mi)
Definition: common-tests.h:78
MyInt(int i)
Definition: common-tests.h:63
bool execute(bool withDataExchange=false)
Definition: statement.h:208
static void to_base(MyInt const &mi, int &i, indicator &ind)
Definition: common-tests.h:86
backend_factory const & backEndFactory_
Definition: common-tests.h:350
virtual std::string dropstatement()
Definition: common-tests.h:239


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:40