| 14 | | void compare_results(string name, result lhs, result rhs) |
|---|
| 15 | | { |
|---|
| 16 | | if (lhs != rhs) |
|---|
| 17 | | throw logic_error("Executing " + name + " as prepared statement " |
|---|
| 18 | | "yields different results from direct execution"); |
|---|
| 19 | | |
|---|
| 20 | | if (lhs.empty()) |
|---|
| 21 | | throw logic_error("Results being compared are empty. Not much point!"); |
|---|
| 22 | | } |
|---|
| 23 | | |
|---|
| 24 | | |
|---|
| | 26 | /// Dereference result element as string |
|---|
| | 27 | struct deref_field |
|---|
| | 28 | { |
|---|
| | 29 | string operator()(const result::field &f) const { return f.c_str(); } |
|---|
| | 30 | }; |
|---|
| | 31 | } |
|---|
| | 32 | |
|---|
| | 33 | namespace pqxx |
|---|
| | 34 | { |
|---|
| | 35 | // Support string conversion for result objects for debug output. |
|---|
| | 36 | template<> struct string_traits<result> |
|---|
| | 37 | { |
|---|
| | 38 | static const char *name() { return "pqxx::result"; } |
|---|
| | 39 | static bool has_null() { return true; } |
|---|
| | 40 | static bool is_null(result r) { return r.empty(); } |
|---|
| | 41 | static result null() { return result(); } |
|---|
| | 42 | static void from_string(const char Str[], result &Obj); // Not needed |
|---|
| | 43 | static string to_string(result Obj) |
|---|
| | 44 | { |
|---|
| | 45 | if (is_null(Obj)) return "<empty>"; |
|---|
| | 46 | |
|---|
| | 47 | string out; |
|---|
| | 48 | for (result::const_iterator row = Obj.begin(); row != Obj.end(); ++row) |
|---|
| | 49 | { |
|---|
| | 50 | out += "{" + |
|---|
| | 51 | separated_list(", ", row.begin(), row.end(), deref_field()) + |
|---|
| | 52 | "}"; |
|---|
| | 53 | } |
|---|
| | 54 | return out; |
|---|
| | 55 | } |
|---|
| | 56 | }; |
|---|
| | 57 | } |
|---|
| | 58 | |
|---|
| | 59 | |
|---|
| | 60 | namespace |
|---|
| | 61 | { |
|---|
| 98 | | C.prepare(QN_readpgtables, Q_readpgtables); |
|---|
| 99 | | nontransaction T(C, "test85"); |
|---|
| 100 | | |
|---|
| 101 | | try |
|---|
| 102 | | { |
|---|
| 103 | | // See if a basic prepared statement works just like a regular query |
|---|
| 104 | | cout << "Basic correctness check on prepared statement..." << endl; |
|---|
| 105 | | compare_results(QN_readpgtables, |
|---|
| 106 | | T.prepared(QN_readpgtables).exec(), |
|---|
| | 126 | C.prepare("ReadPGTables", Q_readpgtables); |
|---|
| | 127 | |
|---|
| | 128 | // See if a basic prepared statement works just like a regular query |
|---|
| | 129 | cout << "Basic correctness check on prepared statement..." << endl; |
|---|
| | 130 | PQXX_CHECK_EQUAL( |
|---|
| | 131 | T.prepared(string("ReadPGTables")).exec(), |
|---|
| | 132 | T.exec(Q_readpgtables), |
|---|
| | 133 | "ReadPGTables"); |
|---|
| | 134 | |
|---|
| | 135 | // Try prepare_now() on an already prepared statement |
|---|
| | 136 | C.prepare_now("ReadPGTables"); |
|---|
| | 137 | |
|---|
| | 138 | // Pro forma check: same thing but with name passed as C-style string |
|---|
| | 139 | COMPARE_RESULTS("ReadPGTables_char", |
|---|
| | 140 | T.prepared("ReadPGTables").exec(), |
|---|
| 108 | | } |
|---|
| 109 | | catch (const exception &) |
|---|
| 110 | | { |
|---|
| 111 | | if (!C.supports(connection_base::cap_prepared_statements)) |
|---|
| 112 | | { |
|---|
| 113 | | cout << "Backend version does not support prepared statements. " |
|---|
| 114 | | "Skipping." |
|---|
| 115 | | << endl; |
|---|
| 116 | | return 0; |
|---|
| 117 | | } |
|---|
| 118 | | throw; |
|---|
| 119 | | } |
|---|
| 120 | | |
|---|
| 121 | | // Try prepare_now() on an already prepared statement |
|---|
| 122 | | C.prepare_now(QN_readpgtables); |
|---|
| 123 | | |
|---|
| 124 | | // Pro forma check: same thing but with name passed as C-style string |
|---|
| 125 | | compare_results(QN_readpgtables+"_char", |
|---|
| 126 | | T.prepared(QN_readpgtables.c_str()).exec(), |
|---|
| 127 | | T.exec(Q_readpgtables)); |
|---|
| 130 | | C.unprepare(QN_readpgtables); |
|---|
| 131 | | |
|---|
| 132 | | bool failed = true; |
|---|
| 133 | | try |
|---|
| 134 | | { |
|---|
| 135 | | disable_noticer d(C); |
|---|
| 136 | | C.prepare_now(QN_readpgtables); |
|---|
| 137 | | failed = false; |
|---|
| 138 | | } |
|---|
| 139 | | catch (const exception &e) |
|---|
| 140 | | { |
|---|
| 141 | | cout << "(Expected) " << e.what() << endl; |
|---|
| 142 | | } |
|---|
| 143 | | if (!failed) |
|---|
| 144 | | throw runtime_error("prepare_now() succeeded on dropped statement"); |
|---|
| 145 | | |
|---|
| | 144 | C.unprepare("ReadPGTables"); |
|---|
| | 145 | |
|---|
| | 146 | PQXX_CHECK_THROWS( |
|---|
| | 147 | C.prepare_now("ReadPGTables"), |
|---|
| | 148 | exception, |
|---|
| | 149 | "prepare_now() succeeded on dropped statement.") |
|---|
| 159 | | C.prepare(QN_readpgtables, Q_readpgtables); |
|---|
| 160 | | C.prepare_now(QN_readpgtables); |
|---|
| 161 | | compare_results(QN_readpgtables+"_2", |
|---|
| 162 | | T.prepared(QN_readpgtables).exec(), |
|---|
| | 163 | C.prepare("ReadPGTables", Q_readpgtables); |
|---|
| | 164 | C.prepare_now("ReadPGTables"); |
|---|
| | 165 | COMPARE_RESULTS("ReadPGTables_2", |
|---|
| | 166 | T.prepared("ReadPGTables").exec(), |
|---|
| 166 | | C.prepare(QN_readpgtables, Q_readpgtables); |
|---|
| 167 | | compare_results(QN_readpgtables+"_double", |
|---|
| 168 | | T.prepared(QN_readpgtables).exec(), |
|---|
| | 170 | C.prepare("ReadPGTables", Q_readpgtables); |
|---|
| | 171 | COMPARE_RESULTS("ReadPGTables_double", |
|---|
| | 172 | T.prepared("ReadPGTables").exec(), |
|---|
| 212 | | compare_results(QN_seetables+"_null2", |
|---|
| 213 | | T.prepared(QN_seetables)(ptrs[0])(ptrs[1]).exec(), |
|---|
| 214 | | T.prepared(QN_seetables)()(ptrs[1]).exec()); |
|---|
| 215 | | compare_results(QN_seetables+"_null3", |
|---|
| 216 | | T.prepared(QN_seetables)(ptrs[0])(ptrs[1]).exec(), |
|---|
| 217 | | T.prepared(QN_seetables)("somestring",false)(ptrs[1]).exec()); |
|---|
| 218 | | compare_results(QN_seetables+"_null4", |
|---|
| 219 | | T.prepared(QN_seetables)(ptrs[0])(ptrs[1]).exec(), |
|---|
| 220 | | T.prepared(QN_seetables)(42,false)(ptrs[1]).exec()); |
|---|
| 221 | | compare_results(QN_seetables+"_null5", |
|---|
| 222 | | T.prepared(QN_seetables)(ptrs[0])(ptrs[1]).exec(), |
|---|
| 223 | | T.prepared(QN_seetables)(0,false)(ptrs[1]).exec()); |
|---|
| | 208 | COMPARE_RESULTS("SeeTables_null2", |
|---|
| | 209 | T.prepared("SeeTables")(ptrs[0])(ptrs[1]).exec(), |
|---|
| | 210 | T.prepared("SeeTables")()(ptrs[1]).exec()); |
|---|
| | 211 | COMPARE_RESULTS("SeeTables_null3", |
|---|
| | 212 | T.prepared("SeeTables")(ptrs[0])(ptrs[1]).exec(), |
|---|
| | 213 | T.prepared("SeeTables")("somestring",false)(ptrs[1]).exec()); |
|---|
| | 214 | COMPARE_RESULTS("SeeTables_null4", |
|---|
| | 215 | T.prepared("SeeTables")(ptrs[0])(ptrs[1]).exec(), |
|---|
| | 216 | T.prepared("SeeTables")(42,false)(ptrs[1]).exec()); |
|---|
| | 217 | COMPARE_RESULTS("SeeTables_null5", |
|---|
| | 218 | T.prepared("SeeTables")(ptrs[0])(ptrs[1]).exec(), |
|---|
| | 219 | T.prepared("SeeTables")(0,false)(ptrs[1]).exec()); |
|---|
| 226 | | try |
|---|
| 227 | | { |
|---|
| 228 | | failsOK = true; |
|---|
| 229 | | T.prepared(QN_seetables)()()("hi mom!").exec(); |
|---|
| 230 | | failsOK = false; |
|---|
| 231 | | } |
|---|
| 232 | | catch (const exception &e) |
|---|
| 233 | | { |
|---|
| 234 | | cout << "(Expected) " << e.what() << endl; |
|---|
| 235 | | } |
|---|
| 236 | | if (!failsOK) |
|---|
| 237 | | throw logic_error("No error for too many parameters"); |
|---|
| 238 | | try |
|---|
| 239 | | { |
|---|
| 240 | | failsOK = true; |
|---|
| 241 | | T.prepared(QN_seetables)("who, me?").exec(); |
|---|
| 242 | | failsOK = false; |
|---|
| 243 | | } |
|---|
| 244 | | catch (const exception &e) |
|---|
| 245 | | { |
|---|
| 246 | | cout << "(Expected) " << e.what() << endl; |
|---|
| 247 | | } |
|---|
| 248 | | if (!failsOK) |
|---|
| 249 | | throw logic_error("No error for too few parameters"); |
|---|
| 250 | | |
|---|
| 251 | | cout << "Done." << endl; |
|---|
| | 222 | PQXX_CHECK_THROWS( |
|---|
| | 223 | T.prepared("SeeTables")()()("hi mom!").exec(), |
|---|
| | 224 | exception, |
|---|
| | 225 | "No error for too many parameters.") |
|---|
| | 226 | |
|---|
| | 227 | PQXX_CHECK_THROWS( |
|---|
| | 228 | T.prepared("SeeTables")("who, me?").exec(), |
|---|
| | 229 | exception, |
|---|
| | 230 | "No error for too few parameters.") |
|---|
| 257 | | return 0; |
|---|
| 258 | | } |
|---|
| 259 | | catch (const sql_error &e) |
|---|
| 260 | | { |
|---|
| 261 | | cerr << "SQL error: " << e.what() << endl |
|---|
| 262 | | << "Query was: " << e.query() << endl; |
|---|
| 263 | | return 1; |
|---|
| 264 | | } |
|---|
| 265 | | catch (const exception &e) |
|---|
| 266 | | { |
|---|
| 267 | | // All exceptions thrown by libpqxx are derived from std::exception |
|---|
| 268 | | cerr << "Exception: " << e.what() << endl; |
|---|
| 269 | | return 2; |
|---|
| 270 | | } |
|---|
| 271 | | catch (...) |
|---|
| 272 | | { |
|---|
| 273 | | // This is really unexpected (see above) |
|---|
| 274 | | cerr << "Unhandled exception" << endl; |
|---|
| 275 | | return 100; |
|---|
| 276 | | } |
|---|
| 277 | | |
|---|
| 278 | | return 0; |
|---|
| 279 | | } |
|---|
| 280 | | |
|---|
| 281 | | |
|---|
| | 236 | } |
|---|
| | 237 | } |
|---|
| | 238 | |
|---|
| | 239 | } // namespace |
|---|
| | 240 | |
|---|
| | 241 | |
|---|
| | 242 | int main() |
|---|
| | 243 | { |
|---|
| | 244 | test::TestCase<lazyconnection, nontransaction> test085("test_085", test_085); |
|---|
| | 245 | return test::pqxxtest(test085); |
|---|
| | 246 | } |
|---|
| | 247 | |
|---|