test-firebird.cpp
Go to the documentation of this file.
1 //
2 // Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton, Rafal Bobrowski
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 
9 #include "soci.h"
10 #include "soci-firebird.h"
11 #include "error-firebird.h" // soci::details::Firebird::throw_iscerror()
12 #include "common-tests.h"
13 #include "common.h"
14 #include <iostream>
15 #include <string>
16 #include <cassert>
17 #include <ctime>
18 #include <cstring>
19 #include <cmath>
20 
21 using namespace soci;
22 
23 std::string connectString;
25 
26 // fundamental tests - transactions in Firebird
27 void test1()
28 {
29  {
30  session sql(backEnd, connectString);
31 
32  // In Firebird transaction is always required and is started
33  // automatically when session is opened. There is no need to
34  // call session::begin(); it will do nothing if there is active
35  // transaction.
36 
37  // sql.begin();
38 
39  try
40  {
41  sql << "drop table test1";
42  }
43  catch (soci_error const &)
44  {} // ignore if error
45 
46  sql << "create table test1 (id integer)";
47 
48  // After DDL statement transaction must be commited or changes
49  // won't be visible to active transaction.
50  sql.commit();
51 
52  // After commit or rollback, transaction must be started manually.
53  sql.begin();
54 
55  sql << "insert into test1(id) values(5)";
56  sql << "drop table test1";
57 
58  // Transaction is automatically commited in session's destructor
59  }
60 
61  std::cout << "test 1 passed" << std::endl;
62 }
63 
64 // character types
65 void test2()
66 {
67  session sql(backEnd, connectString);
68 
69  try
70  {
71  sql << "drop table test2";
72  }
73  catch (soci_error const &)
74  {} // ignore if error
75 
76  sql << "create table test2 (p1 char(10), p2 varchar(10))";
77  sql.commit();
78 
79  sql.begin();
80 
81  {
82  char a('a'), b('b'), c1, c2;
83 
84  sql << "insert into test2(p1,p2) values(?,?)", use(a), use(b);
85 
86  sql << "select p1,p2 from test2", into(c1), into(c2);
87  assert(c1 == 'a' && c2 == 'b');
88 
89  sql << "delete from test2";
90  }
91 
92 #if 0 // SOCI doesn't support binding into(char *, ...) anymore, use std::string
93  {
94  char msg[] = "Hello, Firebird!";
95  char buf1[100], buf2[100], buf3[100];
96  char *b1 = buf1, *b2 = buf2, *b3 = buf3;
97 
98  strcpy(b1, msg);
99 
100  sql << "insert into test2(p1, p2) values (?,?)", use(b1, 100), use(b1, 100);
101  sql << "select p1, p2 from test2", into(b2, 100), into(b3, 100);
102 
103  assert(!std::strcmp(buf2, buf3) && !std::strcmp(buf2, "Hello, Fir"));
104 
105  sql << "delete from test2";
106  }
107 
108  {
109  char msg[] = "Hello, Firebird!";
110  char buf1[100], buf2[100], buf3[100];
111  strcpy(buf1, msg);
112 
113  sql << "insert into test2(p1, p2) values (?,?)",
114  use(buf1), use(buf1);
115  sql << "select p1, p2 from test2", into(buf2), into(buf3);
116 
117  assert(!std::strcmp(buf2, buf3) && !std::strcmp(buf2, "Hello, Fir"));
118 
119  sql << "delete from test2";
120  }
121 #endif
122 
123  {
124  std::string b1("Hello, Firebird!"), b2, b3;
125 
126  sql << "insert into test2(p1, p2) values (?,?)", use(b1), use(b1);
127  sql << "select p1, p2 from test2", into(b2), into(b3);
128 
129  assert(b2 == b3 && b2 == "Hello, Fir");
130 
131  sql << "delete from test2";
132  }
133 
134  {
135  // verify blank padding in CHAR fields
136  // In Firebird, CHAR fields are always padded with whitespaces.
137  char msg[] = "Hello";
138  sql << "insert into test2(p1) values(\'" << msg << "\')";
139 
140  char buf[20];
141  std::string buf_str;
142  sql << "select p1 from test2", into(buf_str);
143  std::strcpy(buf, buf_str.c_str());
144 
145  assert(std::strncmp(buf, msg, 5) == 0);
146  assert(std::strncmp(buf+5, " ", 5) == 0);
147 
148  sql << "delete from test2";
149  }
150 
151  {
152  std::string str1("Hello, Firebird!"), str2, str3;
153  sql << "insert into test2(p1, p2) values (?, ?)",
154  use(str1), use(str1);
155 
156  sql << "select p1, p2 from test2", into(str2), into(str3);
157  assert(str2 == "Hello, Fir" && str3 == "Hello, Fir");
158 
159  sql << "delete from test2";
160  }
161 
162  sql << "drop table test2";
163  std::cout << "test 2 passed" << std::endl;
164 }
165 
166 // date and time
167 void test3()
168 {
169  session sql(backEnd, connectString);
170 
171  try
172  {
173  sql << "drop table test3";
174  }
175  catch (soci_error const &)
176  {} // ignore if error
177 
178  sql << "create table test3 (p1 timestamp, p2 date, p3 time)";
179  sql.commit();
180 
181  sql.begin();
182 
183  std::tm t1, t2, t3;
184  std::time_t now = std::time(NULL);
185  std::tm t = *std::localtime(&now);
186 
187  sql << "insert into test3(p1, p2, p3) "
188  << "values (?,?,?)", use(t), use(t), use(t);
189 
190  sql << "select p1, p2, p3 from test3", into(t1), into(t2), into(t3);
191 
192  // timestamp
193  assert(t1.tm_year == t.tm_year);
194  assert(t1.tm_mon == t.tm_mon);
195  assert(t1.tm_mday == t.tm_mday);
196  assert(t1.tm_hour == t.tm_hour);
197  assert(t1.tm_min == t.tm_min);
198  assert(t1.tm_sec == t.tm_sec);
199 
200  // date
201  assert(t2.tm_year == t.tm_year);
202  assert(t2.tm_mon == t.tm_mon);
203  assert(t2.tm_mday == t.tm_mday);
204  assert(t2.tm_hour == 0);
205  assert(t2.tm_min == 0);
206  assert(t2.tm_sec == 0);
207 
208  // time
209  assert(t3.tm_year == 0);
210  assert(t3.tm_mon == 0);
211  assert(t3.tm_mday == 0);
212  assert(t3.tm_hour == t.tm_hour);
213  assert(t3.tm_min == t.tm_min);
214  assert(t3.tm_sec == t.tm_sec);
215 
216  sql << "drop table test3";
217  std::cout << "test 3 passed" << std::endl;
218 }
219 
220 // floating points
221 void test4()
222 {
223  session sql(backEnd, connectString);
224 
225  try
226  {
227  sql << "drop table test4";
228  }
229  catch (soci_error const &)
230  {} // ignore if error
231 
232  sql << "create table test4 (p1 numeric(8,2), "
233  << "p2 decimal(14,8), p3 double precision, p4 integer)";
234  sql.commit();
235 
236  sql.begin();
237 
238  double d1 = 1234.23, d2 = 1e8, d3 = 1.0/1440.0,
239  d4, d5, d6;
240 
241  sql << "insert into test4(p1, p2, p3) values (?,?,?)",
242  use(d1), use(d2), use(d3);
243 
244  sql << "select p1, p2, p3 from test4",
245  into(d4), into(d5), into(d6);
246 
247  assert(d1 == d4 && d2 == d5 && d3 == d6);
248 
249  // test negative doubles too
250  sql << "delete from test4";
251  d1 = -d1;
252  d2 = -d2;
253  d3 = -d3;
254 
255  sql << "insert into test4(p1, p2, p3) values (?,?,?)",
256  use(d1), use(d2), use(d3);
257 
258  sql << "select p1, p2, p3 from test4",
259  into(d4), into(d5), into(d6);
260 
261  assert(d1 == d4 && d2 == d5 && d3 == d6);
262 
263  // verify an exception is thrown when fetching non-integral value
264  // to integral variable
265  try
266  {
267  int i;
268  sql << "select p1 from test4", into(i);
269 
270  // expecting error
271  assert(false);
272  }
273  catch (soci_error const &e)
274  {
275  std::string error = e.what();
276  assert(error ==
277  "Can't convert value with scale 2 to integral type");
278  }
279 
280  // verify an exception is thrown when inserting non-integral value
281  // to integral column
282  try
283  {
284  sql << "insert into test4(p4) values(?)", use(d1);
285 
286  // expecting error
287  assert(false);
288  }
289  catch (soci_error const &e)
290  {
291  std::string error = e.what();
292  assert(error ==
293  "Can't convert non-integral value to integral column type");
294  }
295 
296  sql << "drop table test4";
297  std::cout << "test 4 passed" << std::endl;
298 }
299 
300 // integer types and indicators
301 void test5()
302 {
303  session sql(backEnd, connectString);
304 
305  {
306  short sh(0);
307  sql << "select 3 from rdb$database", into(sh);
308  assert(sh == 3);
309  }
310 
311  {
312  int i(0);
313  sql << "select 5 from rdb$database", into(i);
314  assert(i == 5);
315  }
316 
317  {
318  unsigned long ul(0);
319  sql << "select 7 from rdb$database", into(ul);
320  assert(ul == 7);
321  }
322 
323  {
324  // test indicators
325  indicator ind;
326  int i;
327 
328  sql << "select 2 from rdb$database", into(i, ind);
329  assert(ind == i_ok);
330 
331  sql << "select NULL from rdb$database", into(i, ind);
332  assert(ind == i_null);
333 
334 #if 0 // SOCI doesn't support binding into(char *, ...) anymore, use std::string
335  char buf[4];
336  sql << "select \'Hello\' from rdb$database", into(buf, ind);
337  assert(ind == i_truncated);
338 #endif
339 
340  sql << "select 5 from rdb$database where 0 = 1", into(i, ind);
341  assert(sql.got_data() == false);
342 
343  try
344  {
345  // expect error
346  sql << "select NULL from rdb$database", into(i);
347  assert(false);
348  }
349  catch (soci_error const &e)
350  {
351  std::string error = e.what();
352  assert(error ==
353  "Null value fetched and no indicator defined.");
354  }
355 
356  // expect no data
357  sql << "select 5 from rdb$database where 0 = 1", into(i);
358  assert(!sql.got_data());
359  }
360 
361  std::cout << "test 5 passed" << std::endl;
362 }
363 
364 // repeated fetch and bulk operations for character types
365 void test6()
366 {
367  session sql(backEnd, connectString);
368 
369  try
370  {
371  sql << "drop table test6";
372  }
373  catch (soci_error const &)
374  {} // ignore if error
375 
376  sql << "create table test6 (p1 char(10), p2 varchar(10))";
377  sql.commit();
378 
379  sql.begin();
380 
381  for (char c = 'a'; c <= 'z'; ++c)
382  {
383  sql << "insert into test6(p1, p2) values(?,?)", use(c), use(c);
384  }
385 
386  {
387  char c, c1, c2;
388 
389  statement st = (sql.prepare <<
390  "select p1,p2 from test6 order by p1", into(c1), into(c2));
391 
392  // Verify that fetch after re-executing the same statement works.
393  for (int n = 0; n < 2; ++n)
394  {
395  st.execute();
396 
397  c='a';
398  while (st.fetch())
399  {
400  assert(c == c1 && c == c2);
401  ++c;
402  }
403  assert(c == 'z'+1);
404  }
405  }
406 
407  {
408  char c='a';
409 
410  std::vector<char> c1(10), c2(10);
411 
412  statement st = (sql.prepare <<
413  "select p1,p2 from test6 order by p1", into(c1), into(c2));
414 
415  st.execute();
416  while (st.fetch())
417  {
418  for (std::size_t i = 0; i != c1.size(); ++i)
419  {
420  assert(c == c1[i] && c == c2[i]);
421  ++c;
422  }
423  }
424  assert(c == 'z' + 1);
425  }
426 
427  {
428  // verify an exception is thrown when empty vector is used
429  std::vector<char> vec;
430  try
431  {
432  sql << "select p1 from test6", into(vec);
433  assert(false);
434  }
435  catch (soci_error const &e)
436  {
437  std::string msg = e.what();
438  assert(msg == "Vectors of size 0 are not allowed.");
439  }
440  }
441 
442  sql << "delete from test6";
443 
444  // verifying std::string
445  int const rowsToTest = 10;
446  for (int i = 0; i != rowsToTest; ++i)
447  {
448  std::ostringstream ss;
449  ss << "Hello_" << i;
450 
451  std::string const &x = ss.str();
452 
453  sql << "insert into test6(p1, p2) values(\'"
454  << x << "\', \'" << x << "\')";
455  }
456 
457  int count;
458  sql << "select count(*) from test6", into(count);
459  assert(count == rowsToTest);
460 
461  {
462  int i = 0;
463  std::string s1, s2;
464  statement st = (sql.prepare <<
465  "select p1, p2 from test6 order by p1", into(s1), into(s2));
466 
467  st.execute();
468  while (st.fetch())
469  {
470  std::ostringstream ss;
471  ss << "Hello_" << i;
472  std::string const &x = ss.str();
473 
474  // Note: CHAR fields are always padded with whitespaces
475  ss << " ";
476  assert(s1 == ss.str() && s2 == x);
477  ++i;
478  }
479  assert(i == rowsToTest);
480  }
481 
482  {
483  int i = 0;
484 
485  std::vector<std::string> s1(4), s2(4);
486  statement st = (sql.prepare <<
487  "select p1, p2 from test6 order by p1", into(s1), into(s2));
488  st.execute();
489  while (st.fetch())
490  {
491  for (std::size_t j = 0; j != s1.size(); ++j)
492  {
493  std::ostringstream ss;
494  ss << "Hello_" << i;
495  std::string const &x = ss.str();
496 
497  // Note: CHAR fields are always padded with whitespaces
498  ss << " ";
499  assert(ss.str() == s1[j] && x == s2[j]);
500  ++i;
501  }
502  }
503  assert(i == rowsToTest);
504  }
505 
506  sql << "drop table test6";
507  std::cout << "test 6 passed" << std::endl;
508 }
509 
510 // blob test
511 void test7()
512 {
513  session sql(backEnd, connectString);
514 
515  try
516  {
517  sql << "drop table test7";
518  }
519  catch (std::runtime_error &)
520  {} // ignore if error
521 
522  sql << "create table test7(id integer, img blob)";
523  sql.commit();
524 
525  sql.begin();
526  {
527  // verify empty blob
528  blob b(sql);
529  indicator ind;
530 
531  sql << "insert into test7(id, img) values(1,?)", use(b);
532  sql << "select img from test7 where id = 1", into(b, ind);
533 
534  assert(ind == i_ok);
535  assert(b.get_len() == 0);
536 
537  sql << "delete from test7";
538  }
539 
540  {
541  // create a new blob
542  blob b(sql);
543 
544  char str1[] = "Hello";
545  b.write(0, str1, strlen(str1));
546 
547  char str2[20];
548  std::size_t i = b.read(3, str2, 2);
549  str2[i] = '\0';
550  assert(str2[0] == 'l' && str2[1] == 'o' && str2[2] == '\0');
551 
552  char str3[] = ", Firebird!";
553  b.append(str3, strlen(str3));
554 
555  sql << "insert into test7(id, img) values(1,?)", use(b);
556  }
557 
558  {
559  // read & update blob
560  blob b(sql);
561 
562  sql << "select img from test7 where id = 1", into(b);
563 
564  std::vector<char> text(b.get_len());
565  b.read(0, &text[0], b.get_len());
566  assert(strncmp(&text[0], "Hello, Firebird!", b.get_len()) == 0);
567 
568  char str1[] = "FIREBIRD";
569  b.write(7, str1, strlen(str1));
570 
571  // after modification blob must be written to database
572  sql << "update test7 set img=? where id=1", use(b);
573  }
574 
575  {
576  // read blob from database, modify and write to another record
577  blob b(sql);
578 
579  sql << "select img from test7 where id = 1", into(b);
580 
581  std::vector<char> text(b.get_len());
582  b.read(0, &text[0], b.get_len());
583 
584  char str1[] = "HELLO";
585  b.write(0, str1, strlen(str1));
586 
587  b.read(0, &text[0], b.get_len());
588  assert(strncmp(&text[0], "HELLO, FIREBIRD!", b.get_len()) == 0);
589 
590  b.trim(5);
591  sql << "insert into test7(id, img) values(2,?)", use(b);
592  }
593 
594  {
595  blob b(sql);
596  statement st = (sql.prepare << "select img from test7", into(b));
597 
598  st.execute();
599 
600  st.fetch();
601  std::vector<char> text(b.get_len());
602  b.read(0, &text[0], b.get_len());
603  assert(strncmp(&text[0], "Hello, FIREBIRD!", b.get_len()) == 0);
604 
605  st.fetch();
606  text.resize(b.get_len());
607  b.read(0, &text[0], b.get_len());
608  assert(strncmp(&text[0], "HELLO", b.get_len()) == 0);
609  }
610 
611  {
612  // delete blob
613  blob b(sql);
614  indicator ind=i_null;
615  sql << "update test7 set img=? where id = 1", use(b, ind);
616 
617  sql << "select img from test7 where id = 2", into(b, ind);
618  assert(ind==i_ok);
619 
620  sql << "select img from test7 where id = 1", into(b, ind);
621  assert(ind==i_null);
622  }
623 
624  sql << "drop table test7";
625  std::cout << "test 7 passed" << std::endl;
626 }
627 
628 // named parameters
629 void test8()
630 {
631  session sql(backEnd, connectString);
632 
633  try
634  {
635  sql << "drop table test8";
636  }
637  catch (std::runtime_error &)
638  {} // ignore if error
639 
640  sql << "create table test8(id1 integer, id2 integer)";
641  sql.commit();
642 
643  sql.begin();
644 
645  int j = 13, k = 4, i, m;
646  sql << "insert into test8(id1, id2) values(:id1, :id2)",
647  use(k, "id2"), use(j, "id1");
648  sql << "select id1, id2 from test8", into(i), into(m);
649  assert(i == j && m == k);
650 
651  sql << "delete from test8";
652 
653  std::vector<int> in1(3), in2(3);
654  in1[0] = 3;
655  in1[1] = 2;
656  in1[2] = 1;
657  in2[0] = 4;
658  in2[1] = 5;
659  in2[2] = 6;
660 
661  {
662  statement st = (sql.prepare <<
663  "insert into test8(id1, id2) values(:id1, :id2)",
664  use(k, "id2"), use(j, "id1"));
665 
666  std::size_t s = in1.size();
667  for (std::size_t x = 0; x < s; ++x)
668  {
669  j = in1[x];
670  k = in2[x];
671  st.execute();
672  }
673  }
674 
675  {
676  statement st = (
677  sql.prepare << "select id1, id2 from test8", into(i), into(m));
678  st.execute();
679 
680  std::size_t x(0);
681  while (st.fetch())
682  {
683  assert(i = in1[x] && m == in2[x]);
684  ++x;
685  }
686  }
687 
688  sql << "delete from test8";
689 
690  // test vectors
691  sql << "insert into test8(id1, id2) values(:id1, :id2)",
692  use(in1, "id1"), use(in2, "id2");
693 
694  std::vector<int> out1(3), out2(3);
695 
696  sql << "select id1, id2 from test8", into(out1), into(out2);
697  std::size_t s = out1.size();
698  assert(s == 3);
699 
700  for (std::size_t x = 0; x<s; ++x)
701  {
702  assert(out1[x] == in1[x] && out2[x] == in2[x]);
703  }
704 
705  sql << "drop table test8";
706  std::cout << "test 8 passed" << std::endl;
707 }
708 
709 // Dynamic binding to row objects
710 void test9()
711 {
712  session sql(backEnd, connectString);
713 
714  try
715  {
716  sql << "drop table test9";
717  }
718  catch (std::runtime_error &)
719  {} // ignore if error
720 
721  sql << "create table test9(id integer, msg varchar(20), ntest numeric(10,2))";
722  sql.commit();
723 
724  sql.begin();
725 
726  {
727  row r;
728  sql << "select * from test9", into(r);
729  assert(sql.got_data() == false);
730  }
731 
732  std::string msg("Hello");
733  int i(1);
734  double d(3.14);
735  indicator ind(i_ok);
736 
737  {
738  statement st((sql.prepare << "insert into test9(id, msg, ntest) "
739  << "values(:id,:msg,:ntest)",
740  use(i, "id"), use(msg, "msg"), use(d, ind, "ntest")));
741 
742  st.execute(1);
743 
744  i = 2;
745  msg = "Firebird";
746  ind = i_null;
747  st.execute(1);
748  }
749 
750  row r;
751  statement st = (sql.prepare <<
752  "select * from test9", into(r));
753  st.execute(1);
754 
755  assert(r.size() == 3);
756 
757  // get properties by position
758  assert(r.get_properties(0).get_name() == "ID");
759  assert(r.get_properties(1).get_name() == "MSG");
760  assert(r.get_properties(2).get_name() == "NTEST");
761 
762  assert(r.get_properties(0).get_data_type() == dt_integer);
763  assert(r.get_properties(1).get_data_type() == dt_string);
764  assert(r.get_properties(2).get_data_type() == dt_double);
765 
766  // get properties by name
767  assert(r.get_properties("ID").get_name() == "ID");
768  assert(r.get_properties("MSG").get_name() == "MSG");
769  assert(r.get_properties("NTEST").get_name() == "NTEST");
770 
771  assert(r.get_properties("ID").get_data_type() == dt_integer);
772  assert(r.get_properties("MSG").get_data_type() == dt_string);
773  assert(r.get_properties("NTEST").get_data_type() == dt_double);
774 
775  // get values by position
776  assert(r.get<int>(0) == 1);
777  assert(r.get<std::string>(1) == "Hello");
778  assert(r.get<double>(2) == d);
779 
780  // get values by name
781  assert(r.get<int>("ID") == 1);
782  assert(r.get<std::string>("MSG") == "Hello");
783  assert(r.get<double>("NTEST") == d);
784 
785  st.fetch();
786  assert(r.get<int>(0) == 2);
787  assert(r.get<std::string>("MSG") == "Firebird");
788  assert(r.get_indicator(2) == i_null);
789 
790  // verify default values
791  assert(r.get<double>("NTEST", 2) == 2);
792  bool caught = false;
793  try
794  {
795  double d1 = r.get<double>("NTEST");
796  std::cout << d1 << std::endl; // just for compiler
797  }
798  catch (soci_error&)
799  {
800  caught = true;
801  }
802  assert(caught);
803 
804  // verify exception thrown on invalid get<>
805  caught = false;
806  try
807  {
808  r.get<std::string>(0);
809  }
810  catch (std::bad_cast const &)
811  {
812  caught = true;
813  }
814  assert(caught);
815 
816  sql << "drop table test9";
817  std::cout << "test 9 passed" << std::endl;
818 }
819 
820 // stored procedures
821 void test10()
822 {
823  session sql(backEnd, connectString);
824 
825  try
826  {
827  sql << "drop procedure sp_test10";
828  }
829  catch (std::runtime_error &)
830  {} // ignore if error
831 
832  try
833  {
834  sql << "drop procedure sp_test10a";
835  }
836  catch (std::runtime_error &)
837  {} // ignore if error
838 
839  try
840  {
841  sql << "drop table test10";
842  }
843  catch (std::runtime_error &)
844  {} // ignore if error
845 
846  sql << "create table test10(id integer, id2 integer)";
847 
848  sql << "create procedure sp_test10\n"
849  << "returns (rid integer, rid2 integer)\n"
850  << "as begin\n"
851  << "for select id, id2 from test10 into rid, rid2 do begin\n"
852  << "suspend;\n"
853  << "end\n"
854  << "end;\n";
855 
856  sql << "create procedure sp_test10a (pid integer, pid2 integer)\n"
857  << "as begin\n"
858  << "insert into test10(id, id2) values (:pid, :pid2);\n"
859  << "end;\n";
860 
861  sql.commit();
862 
863  sql.begin();
864 
865  row r;
866  int p1 = 3, p2 = 4;
867 
868  // calling procedures that do not return values requires
869  // 'execute procedure ...' statement
870  sql << "execute procedure sp_test10a ?, ?", use(p1), use(p2);
871 
872  // calling procedures that return values requires
873  // 'select ... from ...' statement
874  sql << "select * from sp_test10", into(r);
875 
876  assert(r.get<int>(0) == p1 && r.get<int>(1) == p2);
877 
878  sql << "delete from test10";
879 
880  p1 = 5;
881  p2 = 6;
882  {
883  procedure proc = (
884  sql.prepare << "sp_test10a :p1, :p2",
885  use(p2, "p2"), use(p1, "p1"));
886  proc.execute(1);
887  }
888 
889  {
890  row rw;
891  procedure proc = (sql.prepare << "sp_test10", into(rw));
892  proc.execute(1);
893 
894  assert(rw.get<int>(0) == p1 && rw.get<int>(1) == p2);
895  }
896 
897  sql << "delete from test10";
898 
899  // test vectors
900  std::vector<int> in1(3), in2(3);
901  in1[0] = 3;
902  in1[1] = 2;
903  in1[2] = 1;
904  in2[0] = 4;
905  in2[1] = 5;
906  in2[2] = 6;
907 
908  {
909  procedure proc = (
910  sql.prepare << "sp_test10a :p1, :p2",
911  use(in2, "p2"), use(in1, "p1"));
912  proc.execute(1);
913  }
914 
915  {
916  row rw;
917  procedure proc = (sql.prepare << "sp_test10", into(rw));
918 
919  proc.execute(1);
920  assert(rw.get<int>(0) == in1[0] && rw.get<int>(1) == in2[0]);
921  proc.fetch();
922  assert(rw.get<int>(0) == in1[1] && rw.get<int>(1) == in2[1]);
923  proc.fetch();
924  assert(rw.get<int>(0) == in1[2] && rw.get<int>(1) == in2[2]);
925  assert(proc.fetch() == false);
926  }
927 
928  {
929  std::vector<int> out1(3), out2(3);
930  procedure proc = (sql.prepare << "sp_test10", into(out1), into(out2));
931  proc.execute(1);
932 
933  std::size_t s = out1.size();
934  assert(s == 3);
935 
936  for (std::size_t x = 0; x < s; ++x)
937  {
938  assert(out1[x] == in1[x] && out2[x] == in2[x]);
939  }
940  }
941 
942  sql.rollback();
943 
944  sql.begin();
945  sql << "drop procedure sp_test10";
946  sql << "drop procedure sp_test10a";
947  sql << "drop table test10";
948 
949  std::cout << "test 10 passed" << std::endl;
950 }
951 
952 // direct access to Firebird using handles exposed by
953 // soci::FirebirdStatmentBackend
954 namespace soci
955 {
957  {
958  eRowsSelected = isc_info_req_select_count,
959  eRowsInserted = isc_info_req_insert_count,
960  eRowsUpdated = isc_info_req_update_count,
961  eRowsDeleted = isc_info_req_delete_count
962  };
963 
964  // Returns number of rows afected by last statement
965  // or -1 if there is no such counter available.
967  {
968  ISC_STATUS stat[20];
969  char cnt_req[2], cnt_info[128];
970 
971  cnt_req[0]=isc_info_sql_records;
972  cnt_req[1]=isc_info_end;
973 
974  firebird_statement_backend* statementBackEnd
975  = static_cast<firebird_statement_backend*>(statement.get_backend());
976 
977  // Note: This is very poorly documented function.
978  // It can extract number of rows returned by select statement,
979  // but it appears that this is only number of rows prefetched by
980  // client library, not total number of selected rows.
981  if (isc_dsql_sql_info(stat, &statementBackEnd->stmtp_, sizeof(cnt_req),
982  cnt_req, sizeof(cnt_info), cnt_info))
983  {
985  }
986 
987  long count = -1;
988  char type_ = static_cast<char>(type);
989  for (char *ptr = cnt_info + 3; *ptr != isc_info_end;)
990  {
991  char count_type = *ptr++;
992  int m = isc_vax_integer(ptr, 2);
993  ptr += 2;
994  count = isc_vax_integer(ptr, m);
995 
996  if (count_type == type_)
997  {
998  // this is requested number
999  break;
1000  }
1001  ptr += m;
1002  }
1003 
1004  return count;
1005  }
1006 
1007 } // namespace soci
1008 
1009 void test11()
1010 {
1011  session sql(backEnd, connectString);
1012 
1013  try
1014  {
1015  sql << "drop table test11";
1016  }
1017  catch (std::runtime_error &)
1018  {} // ignore if error
1019 
1020  sql << "create table test11(id integer)";
1021  sql.commit();
1022 
1023  sql.begin();
1024 
1025  {
1026  std::vector<int> in(3);
1027  in[0] = 3;
1028  in[1] = 2;
1029  in[2] = 1;
1030 
1031  statement st = (sql.prepare << "insert into test11(id) values(?)",
1032  use(in));
1033  st.execute(1);
1034 
1035  // Note: Firebird backend inserts every row with separate insert
1036  // statement to achieve the effect of inserting vectors of values.
1037  // Since getRowCount() returns number of rows affected by the *last*
1038  // statement, it will return 1 here.
1039  assert(getRowCount(st, eRowsInserted) == 1);
1040  }
1041 
1042  {
1043  int i = 5;
1044  statement st = (sql.prepare << "update test11 set id = ? where id<3",
1045  use(i));
1046  st.execute(1);
1047  assert(getRowCount(st, eRowsUpdated) == 2);
1048 
1049  // verify that no rows were deleted
1050  assert(getRowCount(st, eRowsDeleted) == 0);
1051  }
1052 
1053  {
1054  std::vector<int> out(3);
1055  statement st = (sql.prepare << "select id from test11", into(out));
1056  st.execute(1);
1057 
1058  assert(getRowCount(st, eRowsSelected) == 3);
1059  }
1060 
1061  {
1062  statement st = (sql.prepare << "delete from test11 where id=10");
1063  st.execute(1);
1064  assert(getRowCount(st, eRowsDeleted) == 0);
1065  }
1066 
1067  {
1068  statement st = (sql.prepare << "delete from test11");
1069  st.execute(1);
1070  assert(getRowCount(st, eRowsDeleted) == 3);
1071  }
1072 
1073  sql << "drop table test11";
1074  std::cout << "test 11 passed" << std::endl;
1075 }
1076 
1077 void test12()
1078 {
1079  session sql(backEnd, connectString);
1080 
1081  try
1082  {
1083  sql << "drop table test12";
1084  }
1085  catch (std::runtime_error &)
1086  {} // ignore if error
1087 
1088  sql << "create table test12(a decimal(10,3), b timestamp, c date, d time)";
1089  sql.commit();
1090  sql.begin();
1091 
1092  // Check if passing input parameters as strings works
1093  // for different column types.
1094  {
1095  std::string a = "-3.14150", b = "2013-02-28 23:36:01",
1096  c = "2013-02-28", d = "23:36:01";
1097  statement st = (sql.prepare <<
1098  "insert into test12(a, b, c, d) values (?, ?, ?, ?)",
1099  use(a), use(b), use(c), use(d));
1100  st.execute(1);
1101  assert(getRowCount(st, eRowsInserted) == 1);
1102  }
1103 
1104  {
1105  double a;
1106  std::tm b, c, d;
1107  sql << "select a, b, c, d from test12",
1108  into(a), into(b), into(c), into(d);
1109  assert(std::fabs(a - (-3.141)) < 0.000001);
1110  assert(b.tm_year + 1900 == 2013 && b.tm_mon + 1 == 2 && b.tm_mday == 28);
1111  assert(b.tm_hour == 23 && b.tm_min == 36 && b.tm_sec == 1);
1112  assert(c.tm_year + 1900 == 2013 && c.tm_mon + 1 == 2 && c.tm_mday == 28);
1113  assert(c.tm_hour == 0 && c.tm_min == 0 && c.tm_sec == 0);
1114  assert(d.tm_hour == 23 && d.tm_min == 36 && d.tm_sec == 1);
1115  }
1116 
1117  sql << "drop table test12";
1118  std::cout << "test 12 passed" << std::endl;
1119 }
1120 
1121 // Dynamic binding to row objects: decimals_as_strings
1122 void test13()
1123 {
1124  using namespace soci::details::firebird;
1125 
1126  int a = -12345678;
1127  assert(format_decimal<int>(&a, 1) == "-123456780");
1128  assert(format_decimal<int>(&a, 0) == "-12345678");
1129  assert(format_decimal<int>(&a, -3) == "-12345.678");
1130  assert(format_decimal<int>(&a, -8) == "-0.12345678");
1131  assert(format_decimal<int>(&a, -9) == "-0.012345678");
1132 
1133  a = 12345678;
1134  assert(format_decimal<int>(&a, 1) == "123456780");
1135  assert(format_decimal<int>(&a, 0) == "12345678");
1136  assert(format_decimal<int>(&a, -3) == "12345.678");
1137  assert(format_decimal<int>(&a, -8) == "0.12345678");
1138  assert(format_decimal<int>(&a, -9) == "0.012345678");
1139 
1140  session sql(backEnd, connectString + " decimals_as_strings=1");
1141 
1142  try
1143  {
1144  sql << "drop table test13";
1145  }
1146  catch (std::runtime_error &)
1147  {} // ignore if error
1148 
1149  sql << "create table test13(ntest1 decimal(10,2), "
1150  << "ntest2 decimal(4,4), ntest3 decimal(3,1))";
1151  sql.commit();
1152 
1153  sql.begin();
1154 
1155  {
1156  row r;
1157  sql << "select * from test13", into(r);
1158  assert(sql.got_data() == false);
1159  }
1160 
1161  std::string d_str0("+03.140"), d_str1("3.14"),
1162  d_str2("3.1400"), d_str3("3.1");
1163  indicator ind(i_ok);
1164 
1165  {
1166  statement st((sql.prepare <<
1167  "insert into test13(ntest1, ntest2, ntest3) "
1168  "values(:ntest1, :ntest2, :ntest3)",
1169  use(d_str0, ind, "ntest1"), use(d_str0, "ntest2"),
1170  use(d_str0, "ntest3")));
1171 
1172  st.execute(1);
1173 
1174  ind = i_null;
1175  st.execute(1);
1176  }
1177 
1178  row r;
1179  statement st = (sql.prepare << "select * from test13", into(r));
1180  st.execute(1);
1181 
1182  assert(r.size() == 3);
1183 
1184  // get properties by position
1185  assert(r.get_properties(0).get_name() == "NTEST1");
1186  assert(r.get_properties(0).get_data_type() == dt_string);
1187  assert(r.get_properties(1).get_name() == "NTEST2");
1188  assert(r.get_properties(1).get_data_type() == dt_string);
1189  assert(r.get_properties(2).get_name() == "NTEST3");
1190  assert(r.get_properties(2).get_data_type() == dt_string);
1191 
1192  // get properties by name
1193  assert(r.get_properties("NTEST1").get_name() == "NTEST1");
1194  assert(r.get_properties("NTEST1").get_data_type() == dt_string);
1195  assert(r.get_properties("NTEST2").get_name() == "NTEST2");
1196  assert(r.get_properties("NTEST2").get_data_type() == dt_string);
1197  assert(r.get_properties("NTEST3").get_name() == "NTEST3");
1198  assert(r.get_properties("NTEST3").get_data_type() == dt_string);
1199 
1200  // get values by position
1201  assert(r.get<std::string>(0) == d_str1);
1202  assert(r.get<std::string>(1) == d_str2);
1203  assert(r.get<std::string>(2) == d_str3);
1204 
1205  // get values by name
1206  assert(r.get<std::string>("NTEST1") == d_str1);
1207  assert(r.get<std::string>("NTEST2") == d_str2);
1208  assert(r.get<std::string>("NTEST3") == d_str3);
1209 
1210  st.fetch();
1211  assert(r.get_indicator(0) == i_null);
1212  assert(r.get_indicator(1) == i_ok);
1213  assert(r.get_indicator(2) == i_ok);
1214 
1215  sql << "drop table test13";
1216  std::cout << "test 13 passed" << std::endl;
1217 }
1218 
1219 //
1220 // Support for soci Common Tests
1221 //
1222 
1224 {
1226  : tests::table_creator_base(sql)
1227  {
1228  sql << "create table soci_test(id integer, val integer, c char, "
1229  "str varchar(20), sh smallint, ul bigint, d double precision, "
1230  "tm timestamp, i1 integer, i2 integer, i3 integer, name varchar(20))";
1231  sql.commit();
1232  sql.begin();
1233  }
1234 };
1235 
1237 {
1239  : tests::table_creator_base(sql)
1240  {
1241  sql << "create table soci_test(num_float float, num_int integer, "
1242  "name varchar(20), sometime timestamp, chr char)";
1243  sql.commit();
1244  sql.begin();
1245  }
1246 };
1247 
1249 {
1251  : tests::table_creator_base(sql)
1252  {
1253  sql << "create table soci_test(name varchar(100) not null, "
1254  "phone varchar(15))";
1255  sql.commit();
1256  sql.begin();
1257  }
1258 };
1259 
1261 {
1263  : tests::table_creator_base(sql)
1264  {
1265  sql << "create table soci_test(val integer)";
1266  sql.commit();
1267  sql.begin();
1268  }
1269 };
1270 
1272 {
1273  public:
1275  std::string const &connectString)
1276  : test_context_base(backEnd, connectString)
1277  {}
1278 
1280  {
1281  return new TableCreator1(s);
1282  }
1283 
1285  {
1286  return new TableCreator2(s);
1287  }
1288 
1290  {
1291  return new TableCreator3(s);
1292  }
1293 
1295  {
1296  return new TableCreator4(s);
1297  }
1298 
1299  std::string to_date_time(std::string const &datdt_string) const
1300  {
1301  return "'" + datdt_string + "'";
1302  }
1303 };
1304 
1305 
1306 int main(int argc, char** argv)
1307 {
1308 
1309 #ifdef _MSC_VER
1310  // Redirect errors, unrecoverable problems, and assert() failures to STDERR,
1311  // instead of debug message window.
1312  // This hack is required to run asser()-driven tests by Buildbot.
1313  // NOTE: Comment this 2 lines for debugging with Visual C++ debugger to catch assertions inside.
1314  _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
1315  _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
1316 #endif //_MSC_VER
1317 
1318  if (argc == 2)
1319  {
1320  connectString = argv[1];
1321  }
1322  else
1323  {
1324  std::cout << "usage: " << argv[0]
1325  << " connectstring\n"
1326  << "example: " << argv[0]
1327  << " \"service=/usr/local/firebird/db/test.fdb user=SYSDBA password=masterkey\"\n";
1328  return EXIT_FAILURE;
1329  }
1330 
1331  try
1332  {
1333  test_context tc(backEnd, connectString);
1334  tests::common_tests tests(tc);
1335  tests.run();
1336 
1337  std::cout << "\nSOCI Firebird Tests:\n\n";
1338  test1();
1339  test2();
1340  test3();
1341  test4();
1342  test5();
1343  test6();
1344  test7();
1345  test8();
1346  test9();
1347  test10();
1348  test11();
1349  test12();
1350  test13();
1351 
1352  std::cout << "\nOK, all tests passed.\n\n";
1353 
1354  return EXIT_SUCCESS;
1355  }
1356  catch (std::exception const & e)
1357  {
1358  std::cout << e.what() << '\n';
1359  }
1360  return EXIT_FAILURE;
1361 }
TableCreator2(session &sql)
column_properties const & get_properties(std::size_t pos) const
Definition: row.cpp:91
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
test_context(backend_factory const &backEnd, std::string const &connectString)
TableCreator4(session &sql)
int main(int argc, char **argv)
void test1()
data_type get_data_type() const
Definition: row.h:31
tests::table_creator_base * table_creator_2(session &s) const
void run(bool dbSupportsTransactions=true)
Definition: common-tests.h:293
SOCI_FIREBIRD_DECL backend_factory const * factory_firebird()
Definition: row.h:41
void test12()
std::string get_name() const
Definition: row.h:30
void trim(std::size_t newLen)
Definition: core/blob.cpp:47
void test9()
details::statement_backend * get_backend()
Definition: statement.h:243
void test10()
TableCreator1(session &sql)
void test2()
std::size_t size() const
Definition: row.cpp:60
std::size_t read(std::size_t offset, char *buf, std::size_t toRead)
Definition: core/blob.cpp:31
tests::table_creator_base * table_creator_4(session &s) const
soci::backend_factory const & backEnd
bool execute(bool withDataExchange=false)
Definition: procedure.h:65
void test8()
void throw_iscerror(ISC_STATUS *status_vector)
indicator get_indicator(std::size_t pos) const
Definition: row.cpp:80
tests::table_creator_base * table_creator_1(session &s) const
bool fetch()
Definition: procedure.h:71
std::size_t append(char const *buf, std::size_t toWrite)
Definition: core/blob.cpp:42
void test4()
std::string connectString
void test6()
void test5()
TableCreator3(session &sql)
tests::table_creator_base * table_creator_3(session &s) const
void test3()
void test13()
void test7()
long getRowCount(soci::statement &statement, eRowCountType type)
std::string to_date_time(std::string const &datdt_string) const
std::size_t get_len()
Definition: core/blob.cpp:26
details::prepare_type prepare
Definition: session.h:69
details::use_container< T, details::no_indicator > use(T &t, const std::string &name=std::string())
Definition: use.h:43
bool execute(bool withDataExchange=false)
Definition: statement.h:208
std::size_t write(std::size_t offset, char const *buf, std::size_t toWrite)
Definition: core/blob.cpp:36


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