Changeset 1376
- Timestamp:
- 08/12/08 10:30:11 (5 months ago)
- Files:
-
- trunk/ChangeLog (modified) (1 diff)
- trunk/test/test011.cxx (modified) (2 diffs)
- trunk/test/test012.cxx (modified) (3 diffs)
- trunk/test/test013.cxx (modified) (6 diffs)
- trunk/test/test014.cxx (modified) (3 diffs)
- trunk/test/test015.cxx (modified) (3 diffs)
- trunk/test/test016.cxx (modified) (2 diffs)
- trunk/test/test_helpers.hxx (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/ChangeLog
r1375 r1376 1 2008-08-12 Jeroen T. Vermeulen <jtv@xs4all.nl> 2 test/test011.cxx, test/test012.cxx, test/test013.cxx, test/test014.cxx, 3 test/test015.cxx, test/test016.cxx, test/test_helpers.hxx: 4 - Converted to test framework 5 - Replaced assertions with test helpers 6 - Testing string conversions for result tuples & iterators 7 - Simplified testing string conversion for result 1 8 2008-08-10 Jeroen T. Vermeulen <jtv@xs4all.nl> 2 9 include/pqxx/connection.hxx, src/connection.cxx: trunk/test/test011.cxx
r1284 r1376 7 7 #include <pqxx/result> 8 8 9 #include "test_helpers.hxx" 10 9 11 using namespace PGSTD; 10 12 using namespace pqxx; … … 12 14 13 15 // Test program for libpqxx. Query a table and report its metadata. 14 // 15 // Usage: test011 [connect-string] [table] 16 // 17 // Where table is the table to be queried; if none is given, pg_tables is 18 // queried by default. 19 // 20 // The connect-string is a set of connection options in Postgresql's 21 // PQconnectdb() format, eg. "dbname=template1" to select from a database 22 // called template1, or "host=foo.bar.net user=smith" to connect to a 23 // backend running on host foo.bar.net, logging in as user smith. 24 int main(int argc, char *argv[]) 16 namespace 25 17 { 26 try 18 void test_011(connection_base &, transaction_base &T) 19 { 20 const string Table = "pg_tables"; 21 22 result R( T.exec("SELECT * FROM " + Table) ); 23 24 // Print column names 25 for (result::tuple::size_type c = 0; c < R.columns(); ++c) 27 26 { 28 const string Table = ((argc >= 3) ? argv[2] : "pg_tables"); 27 string N = R.column_name(c); 28 cout << c << ":\t" << N << endl; 29 PQXX_CHECK_EQUAL(R.column_number(N), c, "Inconsistent column numbers."); 30 } 29 31 30 connection C(argv[1]); 31 work T(C, "test11"); 32 // If there are rows in R, compare their metadata to R's. 33 if (!R.empty()) 34 { 35 PQXX_CHECK_EQUAL(R[0].rownumber(), 0u, "Row 0 has wrong number."); 32 36 33 result R( T.exec("SELECT * FROM " + Table) ); 37 if (R.size() < 2) 38 cout << "(Only one row in table.)" << endl; 39 else 40 PQXX_CHECK_EQUAL(R[1].rownumber(), 1u, "Row 1 has wrong number."); 34 41 35 // Print column names 36 for (result::tuple::size_type c = 0; c < R.columns(); ++c) 42 // Test tuple::swap() 43 const result::tuple T1(R[0]), T2(R[1]); 44 PQXX_CHECK_NOT_EQUAL(T1, T2, "Values are identical--can't test swap()."); 45 result::tuple T1s(T1), T2s(T2); 46 PQXX_CHECK_EQUAL(T1s, T1, "Tuple copy-construction incorrect."); 47 PQXX_CHECK_EQUAL(T2s, T2, "Tuple copy-construction inconsistently wrong."); 48 T1s.swap(T2s); 49 PQXX_CHECK_NOT_EQUAL(T1s, T1, "Tuple swap doesn't work."); 50 PQXX_CHECK_NOT_EQUAL(T2s, T2, "Tuple swap inconsistently wrong."); 51 PQXX_CHECK_EQUAL(T2s, T1, "Tuple swap is asymmetric."); 52 PQXX_CHECK_EQUAL(T1s, T2, "Tuple swap is inconsistently asymmetric."); 53 54 for (result::tuple::size_type c = 0; c < R[0].size(); ++c) 37 55 { 38 string N= R.column_name(c); 39 cout << c << ":\t" << N << endl; 40 if (R.column_number(N) != c) 41 throw logic_error("Expected column '" + N + 42 "' to be no. " + to_string(c) + ", " 43 "but it was no. " + to_string(R.column_number(N))); 44 } 56 string N = R.column_name(c); 45 57 46 // If there are rows in R, compare their metadata to R's. 47 if (!R.empty()) 48 { 49 if (R[0].rownumber() != 0) 50 throw logic_error("Row 0 said it was row " + R[0].rownumber()); 58 PQXX_CHECK_EQUAL( 59 string(R[0].at(c).c_str()), 60 R[0].at(N).c_str(), 61 "Field by name != field by number."); 51 62 52 if (R.size() < 2)53 cout << "(Only one row in table.)" << endl;54 else if (R[1].rownumber() != 1) 55 throw logic_error("Row 1 said it was row " + R[1].rownumber());63 PQXX_CHECK_EQUAL( 64 string(R[0][c].c_str()), 65 R[0][N].c_str(), 66 "at() is inconsistent with operator[]."); 56 67 57 // Test tuple::swap() 58 const result::tuple T1(R[0]), T2(R[1]); 59 if (T2 == T1) 60 throw runtime_error("Values are identical, can't test swap()!"); 61 result::tuple T1s(T1), T2s(T2); 62 if (T1s != T1 || !(T2s == T2)) 63 throw logic_error("Tuple copy-construction incorrect"); 64 T1s.swap(T2s); 65 if (T1s == T1 || !(T2s != T2)) 66 throw logic_error("Tuple swap doesn't work"); 67 if (T2s != T1 || !(T1s == T2)) 68 throw logic_error("Tuple swap is asymmetric"); 68 PQXX_CHECK_EQUAL(R[0][c].name(), N, "Field names are inconsistent."); 69 69 70 for (result::tuple::size_type c = 0; c < R[0].size(); ++c) 71 { 72 string N = R.column_name(c); 73 74 if (string(R[0].at(c).c_str()) != R[0].at(N).c_str()) 75 throw logic_error("Field " + to_string(c) + " contains " 76 "'" + R[0].at(c).c_str() + "'; " 77 "field '" + N + "' " 78 "contains '" + R[0].at(N).c_str() + "'"); 79 if (string(R[0][c].c_str()) != R[0][N].c_str()) 80 throw logic_error("Field " + to_string(c) + " ('" + N + "'): " 81 "at() inconsistent with operator[]!"); 82 83 if (R[0][c].name() != N) 84 throw logic_error("Field " + to_string(c) + " " 85 "called '" + N + "' by result, " 86 "but '" + R[0][c].name() + "' by Field object"); 87 88 if (size_t(R[0][c].size()) != strlen(R[0][c].c_str())) 89 throw logic_error("Field '" + N + "' " 90 "says its length is " + to_string(R[0][c].size()) + 91 ", " 92 "but its value is '" + R[0][c].c_str() + "' " 93 "(" + to_string(strlen(R[0][c].c_str())) + " " 94 "chars)"); 95 } 96 } 97 else 98 { 99 cout << "(Table is empty.)" << endl; 70 PQXX_CHECK_EQUAL( 71 size_t(R[0][c].size()), 72 strlen(R[0][c].c_str()), 73 "Field size is not what we expected."); 100 74 } 101 75 } 102 catch (const sql_error &e)76 else 103 77 { 104 // If we're interested in the text of a failed query, we can write separate 105 // exception handling code for this type of exception 106 cerr << "SQL error: " << e.what() << endl 107 << "Query was: '" << e.query() << "'" << endl; 108 return 1; 78 cout << "(Table is empty.)" << endl; 109 79 } 110 catch (const exception &e) 111 { 112 // All exceptions thrown by libpqxx are derived from std::exception 113 cerr << "Exception: " << e.what() << endl; 114 return 2; 115 } 116 catch (...) 117 { 118 // This is really unexpected (see above) 119 cerr << "Unhandled exception" << endl; 120 return 100; 121 } 80 } 81 } // namespace 122 82 123 return 0; 124 } 125 83 PQXX_REGISTER_TEST(test_011) trunk/test/test012.cxx
r1138 r1376 7 7 #include <pqxx/result> 8 8 9 #include "test_helpers.hxx" 10 9 11 using namespace PGSTD; 10 12 using namespace pqxx; … … 13 15 // Test program for libpqxx. See which fields in a query are null, and figure 14 16 // out whether any fields are lexicographically sorted. 15 //16 // Usage: test012 [connect-string] [table]17 //18 // Where table is the table to be queried; if none is given, pg_tables is19 // queried by default.20 //21 // The connect-string is a set of connection options in Postgresql's22 // PQconnectdb() format, eg. "dbname=template1" to select from a database23 // called template1, or "host=foo.bar.net user=smith" to connect to a24 // backend running on host foo.bar.net, logging in as user smith.25 17 26 18 namespace … … 32 24 for (typename VEC::iterator i = V.begin(); i != V.end(); ++i) *i = val; 33 25 } 26 27 void test_012(connection_base &C, transaction_base &orgT) 28 { 29 orgT.abort(); 30 31 const string Table = "pg_tables"; 32 33 // Tell C we won't be needing it for a while (not true, but let's pretend) 34 C.deactivate(); 35 36 // Now set up some data structures 37 vector<int> NullFields; // Maps column to no. of null fields 38 vector<bool> SortedUp, SortedDown; // Does column appear to be sorted? 39 40 // ...And reactivate C (not really needed, but it sounds more polite) 41 C.activate(); 42 43 work T(C, "test12"); 44 45 result R( T.exec("SELECT * FROM " + Table) ); 46 47 InitVector(NullFields, R.columns(), 0); 48 InitVector(SortedUp, R.columns(), true); 49 InitVector(SortedDown, R.columns(), true); 50 51 for (result::const_iterator i = R.begin(); i != R.end(); i++) 52 { 53 PQXX_CHECK_EQUAL( 54 (*i).rownumber(), 55 i->rownumber(), 56 "Inconsistent row numbers for operator*() and operator->()."); 57 58 PQXX_CHECK_EQUAL(i->size(), R.columns(), "Inconsistent row size."); 59 60 // Look for null fields 61 for (result::tuple::size_type f=0; f<i->size(); ++f) 62 { 63 NullFields[f] += i.at(f).is_null(); 64 65 string A, B; 66 PQXX_CHECK_EQUAL( 67 i[f].to(A), 68 i[f].to(B, string("")), 69 "Variants of to() disagree on nullness."); 70 71 PQXX_CHECK_EQUAL(A, B, "Inconsistent field contents."); 72 } 73 74 // Compare fields to those of preceding row 75 if (i != R.begin()) 76 { 77 const result::const_iterator j = i - 1; 78 79 // First perform some sanity checks on j vs. i and how libpqxx handles 80 // their interrelationship... 81 PQXX_CHECK_EQUAL(i - j, 1, "Iterator is wrong distance from successor."); 82 83 PQXX_CHECK(!(j == i), "Iterator equals its successor."); 84 PQXX_CHECK(j != i, "Iterator inequality is inconsistent."); 85 PQXX_CHECK(!(j >= i), "Iterator doesn't come before its successor."); 86 PQXX_CHECK(!(j > i), "Iterator is preceded by its successor."); 87 PQXX_CHECK(!(i <= j), "Iterator doesn't come after its predecessor."); 88 PQXX_CHECK(!(i < j), "Iterator is succeded by its predecessor."); 89 PQXX_CHECK(j <= i, "operator<=() doesn't mirror operator>=()."); 90 PQXX_CHECK(j < i, "operator<() doesn't mirror operator>()."); 91 92 PQXX_CHECK_EQUAL(1 + j, i, "Adding 1 doesn't reach successor."); 93 94 result::const_iterator k(i); 95 PQXX_CHECK_EQUAL(k--, i, "Post-increment returns wrong iterator."); 96 PQXX_CHECK_EQUAL(k, j, "Bad iterator position after post-increment."); 97 98 result::const_iterator l(i); 99 PQXX_CHECK_EQUAL(--l, j, "Pre-increment returns wrong iterator."); 100 PQXX_CHECK_EQUAL(l, j, "Pre-increment sets wrong iterator position."); 101 102 PQXX_CHECK_EQUAL(k += 1, i, "Wrong return value from +=."); 103 PQXX_CHECK_EQUAL(k, i, "Bad iterator position after +=."); 104 105 PQXX_CHECK_EQUAL(k -= 1, j, "Wrong return value from -=."); 106 PQXX_CHECK_EQUAL(k, j, "Bad iterator position after -=."); 107 108 // ...Now let's do meaningful stuff with j, such as finding out which 109 // fields may be sorted. Don't do anything fancy like trying to 110 // detect numbers and comparing them as such, just compare them as 111 // simple strings. 112 for (result::tuple::size_type f = 0; f < R.columns(); ++f) 113 { 114 if (!j[f].is_null()) 115 { 116 const bool U = SortedUp[f], 117 D = SortedDown[f]; 118 119 SortedUp[f] = U & (string(j[f].c_str()) <= string(i[f].c_str())); 120 SortedDown[f] = D & (string(j[f].c_str()) >= string(i[f].c_str())); 121 } 122 } 123 } 124 } 125 126 // Now report on what we've found 127 cout << "Read " << to_string(R.size()) << " rows." << endl; 128 cout << "Field \t Field Name\t Nulls\t Sorted" << endl; 129 130 for (result::tuple::size_type f = 0; f < R.columns(); ++f) 131 { 132 cout << to_string(f) << ":\t" 133 << R.column_name(f) << '\t' 134 << NullFields[f] << '\t' 135 << (SortedUp[f] ? 136 (SortedDown[f] ? "equal" : "up" ) : 137 (SortedDown[f] ? "down" : "no" ) ) 138 << endl; 139 140 PQXX_CHECK( 141 NullFields[f] <= int(R.size()), 142 "Found more nulls than there were rows."); 143 } 144 } 34 145 } // namespace 35 146 36 int main(int argc, char *argv[]) 37 { 38 try 39 { 40 const string Table = ((argc >= 3) ? argv[2] : "pg_tables"); 41 42 connection C(argv[1]); 43 44 // Tell C we won't be needing it for a while (not true, but let's pretend) 45 C.deactivate(); 46 47 // Now set up some data structures 48 vector<int> NullFields; // Maps column to no. of null fields 49 vector<bool> SortedUp, SortedDown; // Does column appear to be sorted? 50 51 // ...And reactivate C (not really needed, but it sounds more polite) 52 C.activate(); 53 54 work T(C, "test12"); 55 56 result R( T.exec("SELECT * FROM " + Table) ); 57 58 InitVector(NullFields, R.columns(), 0); 59 InitVector(SortedUp, R.columns(), true); 60 InitVector(SortedDown, R.columns(), true); 61 62 for (result::const_iterator i = R.begin(); i != R.end(); i++) 63 { 64 if ((*i).rownumber() != i->rownumber()) 65 throw logic_error("Inconsistent rows: operator*() says " + 66 to_string((*i).rownumber()) + ", " 67 "operator->() says " + 68 to_string(i->rownumber())); 69 70 if (i->size() != R.columns()) 71 throw logic_error("Row claims to have " + to_string(i->size()) + " " 72 "fields, but result claims to have " + 73 to_string(R.columns()) + " columns!"); 74 75 // Look for null fields 76 for (result::tuple::size_type f=0; f<i->size(); ++f) 77 { 78 NullFields[f] += i.at(f).is_null(); 79 80 string A, B; 81 if (i[f].to(A) != i[f].to(B, string(""))) 82 throw logic_error("Variants of to() disagree on nullness!"); 83 84 if (A != B) 85 throw logic_error("Field is '" + A + "' according to one to(), " 86 "but '" + B + "' to the other!"); 87 } 88 89 // Compare fields to those of preceding row 90 if (i != R.begin()) 91 { 92 const result::const_iterator j = i - 1; 93 94 // First perform some sanity checks on j vs. i and how libpqxx handles 95 // their interrelationship... 96 if ((i - j) != 1) 97 throw logic_error("Difference between iterator and successor is " + 98 to_string(j-i)); 99 100 if ((j == i) || !(j != i) || 101 (j >= i) || (j > i) || 102 (i <= j) || (i < j) || 103 !(j <= i) || !(j < i)) 104 throw logic_error("Something wrong in comparison between iterator " 105 "and its successor!"); 106 107 if ((1 + j) != i) 108 throw logic_error("Adding iterator's predecessor to 1 " 109 "doesn't bring us back to original iterator!"); 110 111 result::const_iterator k(i); 112 if ((k-- != i) || (k != j)) 113 throw logic_error("Something wrong with increment operator!"); 114 115 result::const_iterator l(i); 116 if ((--l != j) || (l != j)) 117 throw logic_error("Something wrong with pre-increment operator!"); 118 119 if ((k += 1) != i) 120 throw logic_error("Something wrong with += operator!"); 121 122 if ((k -= 1) != j) 123 throw logic_error("Something wrong with -= operator!"); 124 125 // ...Now let's do meaningful stuff with j, such as finding out which 126 // fields may be sorted. Don't do anything fancy like trying to 127 // detect numbers and comparing them as such, just compare them as 128 // simple strings. 129 for (result::tuple::size_type f = 0; f < R.columns(); ++f) 130 { 131 if (!j[f].is_null()) 132 { 133 const bool U = SortedUp[f], 134 D = SortedDown[f]; 135 136 SortedUp[f] = U & (string(j[f].c_str()) <= string(i[f].c_str())); 137 SortedDown[f] = D & (string(j[f].c_str()) >= string(i[f].c_str())); 138 } 139 } 140 } 141 } 142 143 // Now report on what we've found 144 cout << "Read " << to_string(R.size()) << " rows." << endl; 145 cout << "Field \t Field Name\t Nulls\t Sorted" << endl; 146 147 for (result::tuple::size_type f = 0; f < R.columns(); ++f) 148 { 149 cout << to_string(f) << ":\t" 150 << R.column_name(f) << '\t' 151 << NullFields[f] << '\t' 152 << (SortedUp[f] ? 153 (SortedDown[f] ? "equal" : "up" ) : 154 (SortedDown[f] ? "down" : "no" ) ) 155 << endl; 156 157 if (NullFields[f] > int(R.size())) 158 throw logic_error("Found more nulls than there were rows!"); 159 } 160 } 161 catch (const sql_error &e) 162 { 163 // If we're interested in the text of a failed query, we can write separate 164 // exception handling code for this type of exception 165 cerr << "SQL error: " << e.what() << endl 166 << "Query was: '" << e.query() << "'" << endl; 167 return 1; 168 } 169 catch (const exception &e) 170 { 171 // All exceptions thrown by libpqxx are derived from std::exception 172 cerr << "Exception: " << e.what() << endl; 173 return 2; 174 } 175 catch (...) 176 { 177 // This is really unexpected (see above) 178 cerr << "Unhandled exception" << endl; 179 return 100; 180 } 181 182 return 0; 183 } 184 147 PQXX_REGISTER_TEST_T(test_012, nontransaction) trunk/test/test013.cxx
r1175 r1376 9 9 #include <pqxx/result> 10 10 11 #include "test_helpers.hxx" 12 11 13 using namespace PGSTD; 12 14 using namespace pqxx; … … 15 17 // Test program for libpqxx. Verify abort behaviour of transactor. 16 18 // 17 // Usage: test013 [connect-string] [table]18 //19 // Where connect-string is a set of connection options in Postgresql's20 // PQconnectdb() format, eg. "dbname=template1" to select from a database21 // called template1, or "host=foo.bar.net user=smith" to connect to a22 // backend running on host foo.bar.net, logging in as user smith.23 //24 19 // The program will attempt to add an entry to a table called "pqxxevents", 25 20 // with a key column called "year"--and then abort the change. … … 27 22 // Note for the superstitious: the numbering for this test program is pure 28 23 // coincidence. 29 30 31 24 namespace 32 25 { … … 60 53 61 54 62 63 55 class FailedInsert : public transactor<> 64 56 { … … 77 69 "'yawn')") ); 78 70 79 assert(R.affected_rows() == 1);71 PQXX_CHECK_EQUAL(R.affected_rows(), 1u, "Bad affected_rows()."); 80 72 cout << "Inserted row with oid " << R.inserted_oid() << endl; 81 73 … … 100 92 101 93 94 void test_013(connection_base &C, transaction_base &T) 95 { 96 T.abort(); 97 98 const string Table = "pqxxevents"; 99 100 pair<int,int> Before; 101 C.perform(CountEvents(Table, Before)); 102 PQXX_CHECK_EQUAL( 103 Before.second, 104 0, 105 "Already have event for " + to_string(BoringYear) + "--can't test."); 106 107 const FailedInsert DoomedTransaction(Table); 108 disable_noticer d(C); 109 PQXX_CHECK_THROWS( 110 C.perform(DoomedTransaction), 111 runtime_error, 112 "Failing transactor failed to throw correct exception."); 113 114 pair<int,int> After; 115 C.perform(CountEvents(Table, After)); 116 117 PQXX_CHECK_EQUAL( 118 After.first, 119 Before.first, 120 "abort() didn't reset event count."); 121 122 PQXX_CHECK_EQUAL( 123 After.second, 124 Before.second, 125 "abort() didn't reset event count for " + to_string(BoringYear)); 126 } 127 102 128 } // namespace 103 129 104 105 int main(int argc, char *argv[]) 106 { 107 try 108 { 109 connection C(argv[1]); 110 111 const string Table = ((argc > 2) ? argv[2] : "pqxxevents"); 112 113 pair<int,int> Before; 114 C.perform(CountEvents(Table, Before)); 115 if (Before.second) 116 throw runtime_error("Table already has an event for " + 117 to_string(BoringYear) + ", " 118 "cannot run."); 119 120 const FailedInsert DoomedTransaction(Table); 121 122 try 123 { 124 disable_noticer d(C); 125 C.perform(DoomedTransaction); 126 } 127 catch (const exception &e) 128 { 129 cout << "(Expected) Doomed transaction failed: " << e.what() << endl; 130 } 131 132 pair<int,int> After; 133 C.perform(CountEvents(Table, After)); 134 135 if (After != Before) 136 throw logic_error("Event counts changed from " 137 "{" + to_string(Before.first) + "," + 138 to_string(Before.second) + "} " 139 "to " 140 "{" + to_string(After.first) + "," + 141 to_string(After.second) + "} " 142 "despite abort. This could be a bug in libpqxx, " 143 "or something else modified the table."); 144 } 145 catch (const sql_error &e) 146 { 147 // If we're interested in the text of a failed query, we can write separate 148 // exception handling code for this type of exception 149 cerr << "SQL error: " << e.what() << endl 150 << "Query was: '" << e.query() << "'" << endl; 151 return 1; 152 } 153 catch (const exception &e) 154 { 155 // All exceptions thrown by libpqxx are derived from std::exception 156 cerr << "Exception: " << e.what() << endl; 157 return 2; 158 } 159 catch (...) 160 { 161 // This is really unexpected (see above) 162 cerr << "Unhandled exception" << endl; 163 return 100; 164 } 165 166 return 0; 167 } 168 130 PQXX_REGISTER_TEST_T(test_013, nontransaction) trunk/test/test014.cxx
r1138 r1376 1 #include <cassert>2 1 #include <iostream> 3 2 … … 6 5 #include <pqxx/result> 7 6 7 #include "test_helpers.hxx" 8 8 9 using namespace PGSTD; 9 10 using namespace pqxx; 10 11 11 12 13 // Simple test program for libpqxx. Open connection to database, start 14 // a dummy transaction to gain nontransactional access, and perform a query. 15 16 namespace 17 { 12 18 // Define a pqxx::noticer to process warnings generated by the database 13 19 // connection and (in this case) pass them to cerr. This is optional. 14 namespace15 {16 20 struct ReportWarning : noticer 17 21 { … … 23 27 } 24 28 }; 25 }26 29 27 30 28 // Simple test program for libpqxx. Open connection to database, start 29 // a dummy transaction to gain nontransactional access, and perform a query. 30 // 31 // Usage: test014 [connect-string] 32 // 33 // Where connect-string is a set of connection options in Postgresql's 34 // PQconnectdb() format, eg. "dbname=template1" to select from a database 35 // called template1, or "host=foo.bar.net user=smith" to connect to a 36 // backend running on host foo.bar.net, logging in as user smith. 37 int main(int, char *argv[]) 31 void test_014(connection_base &C, transaction_base &orgT) 38 32 { 39 try 33 orgT.abort(); 34 35 // Tell C to report its warnings through std::cerr instead of the default 36 // (which is to print to stderr). This is done just to show that the way 37 // messages are processed can be changed by the client program. 38 noticer *MyNoticer = new ReportWarning; 39 // This is not a memory leak: C stores MyNoticer in an auto_ptr that will 40 // delete the object on destruction. 41 C.set_noticer(auto_ptr<noticer>(MyNoticer)); 42 43 PQXX_CHECK(C.get_noticer() == MyNoticer, "Lost noticer."); 44 45 // Now use our noticer to output a diagnostic message. Note that the 46 // message must end in a newline. 47 C.process_notice("Opened connection\n"); 48 49 // ProcessNotice() can take either a C++ string or a C-style const char *. 50 const string HostName = (C.hostname() ? C.hostname() : "<local>"); 51 C.process_notice(string() + 52 "database=" + C.dbname() + ", " 53 "username=" + C.username() + ", " 54 "hostname=" + HostName + ", " 55 "port=" + to_string(C.port()) + ", " 56 "options='" + static_cast<connection &>(C).options() + "', " 57 "backendpid=" + to_string(C.backendpid()) + "\n"); 58 59 // Begin a "non-transaction" acting on our current connection. This is 60 // really all the transactional integrity we need since we're only 61 // performing one query which does not modify the database. 62 nontransaction T(C, "test14"); 63 64 // The Transaction family of classes also has ProcessNotice() functions. 65 // These simply pass the notice through to their connection, but this may 66 // be more convenient in some cases. All ProcessNotice() functions accept 67 // C++ strings as well as C strings. 68 T.process_notice(string("Started nontransaction\n")); 69 70 result R( T.exec("SELECT * FROM pg_tables") ); 71 72 // Give some feedback to the test program's user prior to the real work 73 T.process_notice(to_string(R.size()) + " " 74 "result tuples in transaction " + 75 T.name() + "\n"); 76 77 for (result::const_iterator c = R.begin(); c != R.end(); ++c) 40 78 { 41 connection C(argv[1]); 79 string N; 80 c[0].to(N); 42 81 43 // Tell C to report its warnings through std::cerr instead of the default 44 // (which is to print to stderr). This is done just to show that the way 45 // messages are processed can be changed by the client program. 46 noticer *MyNoticer = new ReportWarning; 47 // This is not a memory leak: C stores MyNoticer in an auto_ptr that will 48 // delete the object on destruction. 49 C.set_noticer(auto_ptr<noticer>(MyNoticer)); 50 51 assert(C.get_noticer() == MyNoticer); 52 53 // Now use our noticer to output a diagnostic message. Note that the 54 // message must end in a newline. 55 C.process_notice("Opened connection\n"); 56 57 // ProcessNotice() can take either a C++ string or a C-style const char *. 58 const string HostName = (C.hostname() ? C.hostname() : "<local>"); 59 C.process_notice(string() + 60 "database=" + C.dbname() + ", " 61 "username=" + C.username() + ", " 62 "hostname=" + HostName + ", " 63 "port=" + to_string(C.port()) + ", " 64 "options='" + C.options() + "', " 65 "backendpid=" + to_string(C.backendpid()) + "\n"); 66 67 // Begin a "non-transaction" acting on our current connection. This is 68 // really all the transactional integrity we need since we're only 69 // performing one query which does not modify the database. 70 nontransaction T(C, "test14"); 71 72 // The Transaction family of classes also has ProcessNotice() functions. 73 // These simply pass the notice through to their connection, but this may 74 // be more convenient in some cases. All ProcessNotice() functions accept 75 // C++ strings as well as C strings. 76 T.process_notice(string("Started nontransaction\n")); 77 78 result R( T.exec("SELECT * FROM pg_tables") ); 79 80 // Give some feedback to the test program's user prior to the real work 81 T.process_notice(to_string(R.size()) + " " 82 "result tuples in transaction " + 83 T.name() + 84 "\n"); 85 86 for (result::const_iterator c = R.begin(); c != R.end(); ++c) 87 { 88 string N; 89 c[0].to(N); 90 91 cout << '\t' << to_string(c.num()) << '\t' << N << endl; 92 } 93 94 // "Commit" the non-transaction. This doesn't really do anything since 95 // NonTransaction doesn't start a backend transaction. 96 T.commit(); 97 } 98 catch (const sql_error &e) 99 { 100 // If we're interested in the text of a failed query, we can write separate 101 // exception handling code for this type of exception 102 cerr << "SQL error: " << e.what() << endl 103 << "Query was: '" << e.query() << "'" << endl; 104 return 1; 105 } 106 catch (const exception &e) 107 { 108 // All exceptions thrown by libpqxx are derived from std::exception 109 cerr << "Exception: " << e.what() << endl; 110 return 2; 111 } 112 catch (...) 113 { 114 // This is really unexpected (see above) 115 cerr << "Unhandled exception" << endl; 116 return 100; 82 cout << '\t' << to_string(c.num()) << '\t' << N << endl; 117 83 } 118 84 119 return 0; 85 // "Commit" the non-transaction. This doesn't really do anything since 86 // NonTransaction doesn't start a backend transaction. 87 T.commit(); 120 88 } 89 } // namespace 121 90 91 PQXX_REGISTER_TEST_T(test_014, nontransaction) trunk/test/test015.cxx
r1040 r1376 6 6 #include <pqxx/result> 7 7 8 #include "test_helpers.hxx" 9 8 10 using namespace PGSTD; 9 11 using namespace pqxx; … … 12 14 // Simple test program for libpqxx. Open connection to database, start 13 15 // a dummy transaction to gain nontransactional access, and perform a query. 14 //15 // Usage: test015 [connect-string]16 //17 // Where connect-string is a set of connection options in Postgresql's18 // PQconnectdb() format, eg. "dbname=template1" to select from a database19 // called template1, or "host=foo.bar.net user=smith" to connect to a20 // backend running on host foo.bar.net, logging in as user smith.21 16 17 namespace 18 { 22 19 class ReadTables : public transactor<nontransaction> 23 20 { … … 44 41 45 42 46 int main(int, char *argv[])43 void test_015(connection_base &C, transaction_base &ortT) 47 44 { 48 try 49 { 50 connection C(argv[1]); 45 ortT.abort(); 51 46 52 // See if Deactivate() behaves...53 C.deactivate();47 // See if Deactivate() behaves... 48 C.deactivate(); 54 49 55 C.perform(ReadTables()); 56 } 57 catch (const sql_error &e) 58 { 59 // If we're interested in the text of a failed query, we can write separate 60 // exception handling code for this type of exception 61 cerr << "SQL error: " << e.what() << endl 62 << "Query was: '" << e.query() << "'" << endl; 63 return 1; 64 } 65 catch (const exception &e) 66 { 67 // All exceptions thrown by libpqxx are derived from std::exception 68 cerr << "Exception: " << e.what() << endl; 69 return 2; 70 } 71 catch (...) 72 { 73 // This is really unexpected (see above) 74 cerr << "Unhandled exception" << endl; 75 return 100; 76 } 77 78 return 0; 50 C.perform(ReadTables()); 79 51 } 80 52 53 } // namespace 54 55 PQXX_REGISTER_TEST_T(test_015, nontransaction) trunk/test/test016.cxx
r1138 r1376 4 4 #include <pqxx/robusttransaction> 5 5 #include <pqxx/result> 6 7 #include "test_helpers.hxx" 6 8 7 9 using namespace PGSTD; … … 11 13 // Simple test program for libpqxx. Open connection to database, start 12 14 // a dummy transaction to gain nontransactional access, and perform a query. 13 // 14 // Usage: test016 [connect-string] 15 // 16 // Where connect-string is a set of connection options in Postgresql's 17 // PQconnectdb() format, eg. "dbname=template1" to select from a database 18 // called template1, or "host=foo.bar.net user=smith" to connect to a 19 // backend running on host foo.bar.net, logging in as user smith. 20 int main(int, char *argv[]) 15 namespace 21 16 { 22 try 17 18 void test_016(connection_base &, transaction_base &T) 19 { 20 result R( T.exec("SELECT * FROM pg_tables") ); 21 22 result::const_iterator c; 23 for (c = R.begin(); c != R.end(); ++c) 23 24 { 24 connection C(argv[1]); 25 string N; 26 c[0].to(N); 25 27 26 // Begin a "non-transaction" acting on our current connection. This is 27 // really all the transactional integrity we need since we're only 28 // performing one query which does not modify the database. 29 robusttransaction<> T(C, "test16"); 30 31 result R( T.exec("SELECT * FROM pg_tables") ); 32 33 result::const_iterator c; 34 for (c = R.begin(); c != R.end(); ++c) 35 { 36 string N; 37 c[0].to(N); 38 39 cout << '\t' << to_string(c.num()) << '\t' << N << endl; 40 } 41 42 // See if back() and tuple comparison work properly 43 if (R.size() < 2) 44 throw runtime_error("Not enough results in pg_tables to test, sorry!"); 45 --c; 46 if (c->size() != R.back().size()) 47 throw logic_error("Size mismatch between tuple iterator and back()"); 48 const string nullstr; 49 for (result::tuple::size_type i = 0; i < c->size(); ++i) 50 if (c[i].as(nullstr) != R.back()[i].as(nullstr)) 51 throw logic_error("Value mismatch in back()"); 52 if (c != R.back()) 53 throw logic_error("Something wrong with tuple inequality"); 54 if (!(c == R.back())) 55 throw logic_error("Something wrong with tuple equality"); 56 57 // "Commit" the non-transaction. This doesn't really do anything since 58 // NonTransaction doesn't start a backend transaction. 59 T.commit(); 60 } 61 catch (const sql_error &e) 62 { 63 // If we're interested in the text of a failed query, we can write separate 64 // exception handling code for this type of exception 65 cerr << "SQL error: " << e.what() << endl 66 << "Query was: '" << e.query() << "'" << endl; 67 return 1; 68 } 69 catch (const exception &e) 70 { 71 // All exceptions thrown by libpqxx are derived from std::exception 72 cerr << "Exception: " << e.what() << endl; 73 return 2; 74 } 75 catch (...) 76 { 77 // This is really unexpected (see above) 78 cerr << "Unhandled exception" << endl; 79 return 100; 28 cout << '\t' << to_string(c.num()) << '\t' << N << endl; 80 29 } 81 30 82 return 0; 31 // See if back() and tuple comparison work properly 32 if (R.size() < 2) 33 throw runtime_error("Not enough results in pg_tables to test, sorry!"); 34 --c; 35 if (c->size() != R.back().size()) 36 throw logic_error("Size mismatch between tuple iterator and back()"); 37 const string nullstr; 38 for (result::tuple::size_type i = 0; i < c->size(); ++i) 39 if (c[i].as(nullstr) != R.back()[i].as(nullstr)) 40 throw logic_error("Value mismatch in back()"); 41 if (c != R.back()) 42 throw logic_error("Something wrong with tuple inequality"); 43 if (!(c == R.back())) 44 throw logic_error("Something wrong with tuple equality"); 45 46 // "Commit" the non-transaction. This doesn't really do anything since 47 // NonTransaction doesn't start a backend transaction. 48 T.commit(); 83 49 } 50 } // namespace 84 51 52 PQXX_REGISTER_TEST_T(test_016, robusttransaction<>) trunk/test/test_helpers.hxx
r1375 r1376 295 295 296 296 297 // Support string conversion on result rows for debug output. 298 template<> struct string_traits<result::tuple> 299 { 300 static const char *name() { return "pqxx::result::tuple"; } 301 static bool has_null() { return false; } 302 static bool is_null(result::tuple) { return false; } 303 static result null(); // Not needed 304 static void from_string(const char Str[], result &Obj); // Not needed 305 static PGSTD::string to_string(result::tuple Obj) 306 { 307 return separated_list(", ", Obj.begin(), Obj.end(), deref_field); 308 } 309 }; 310 297 311 // Support string conversion on result objects for debug output. 298 312 template<> struct string_traits<result> … … 306 320 { 307 321 if (is_null(Obj)) return "<empty>"; 308 309 PGSTD::string out; 310 for (result::const_iterator row = Obj.begin(); row != Obj.end(); ++row) 311 { 312 out += "{" + 313 separated_list(", ", row.begin(), row.end(), deref_field) + 314 "}"; 315 } 316 return out; 317 } 318 }; 322 return "{" + separated_list("}\n{", Obj) + "}"; 323 } 324 }; 325 326 // Support string conversion on result::const_iterator for debug output. 327 template<> struct string_traits<result::const_iterator> 328 { 329 typedef result::const_iterator subject_type; 330 static const char *name() { return "pqxx::result::const_iterator"; } 331 static bool has_null() { return false; } 332 static bool is_null(subject_type) { return false; } 333 static result null(); // Not needed 334 static void from_string(const char Str[], subject_type &Obj); // Not needed 335 static PGSTD::string to_string(subject_type Obj) 336 { 337 return "<iterator at " + pqxx::to_string(Obj.rownumber()) + ">"; 338 } 339 }; 340 319 341 320 342 // Support string conversion on vector<string> for debug output.
