1/* Licensed to the Apache Software Foundation (ASF) under one or more 2 * contributor license agreements. See the NOTICE file distributed with 3 * this work for additional information regarding copyright ownership. 4 * The ASF licenses this file to You under the Apache License, Version 2.0 5 * (the "License"); you may not use this file except in compliance with 6 * the License. You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "apu.h" 18#include "apr_pools.h" 19#include "apr_dbd.h" 20 21#include <stdio.h> 22 23#define TEST(msg,func) \ 24 printf("======== %s ========\n", msg); \ 25 rv = func(pool, sql, driver); \ 26 if (rv != 0) { \ 27 printf("Error in %s: rc=%d\n\n", msg, rv); \ 28 } \ 29 else { \ 30 printf("%s test successful\n\n", msg); \ 31 } \ 32 fflush(stdout); 33 34static int create_table(apr_pool_t* pool, apr_dbd_t* handle, 35 const apr_dbd_driver_t* driver) 36{ 37 int rv = 0; 38 int nrows; 39 const char *statement = "CREATE TABLE apr_dbd_test (" 40 "col1 varchar(40) not null," 41 "col2 varchar(40)," 42 "col3 integer)" ; 43 rv = apr_dbd_query(driver, handle, &nrows, statement); 44 return rv; 45} 46static int drop_table(apr_pool_t* pool, apr_dbd_t* handle, 47 const apr_dbd_driver_t* driver) 48{ 49 int rv = 0; 50 int nrows; 51 const char *statement = "DROP TABLE apr_dbd_test" ; 52 rv = apr_dbd_query(driver, handle, &nrows, statement); 53 return rv; 54} 55static int insert_rows(apr_pool_t* pool, apr_dbd_t* handle, 56 const apr_dbd_driver_t* driver) 57{ 58 int i; 59 int rv = 0; 60 int nrows; 61 int nerrors = 0; 62 const char *statement = 63 "INSERT into apr_dbd_test (col1) values ('foo');" 64 "INSERT into apr_dbd_test values ('wibble', 'other', 5);" 65 "INSERT into apr_dbd_test values ('wibble', 'nothing', 5);" 66 "INSERT into apr_dbd_test values ('qwerty', 'foo', 0);" 67 "INSERT into apr_dbd_test values ('asdfgh', 'bar', 1);" 68 ; 69 rv = apr_dbd_query(driver, handle, &nrows, statement); 70 if (rv) { 71 const char* stmt[] = { 72 "INSERT into apr_dbd_test (col1) values ('foo');", 73 "INSERT into apr_dbd_test values ('wibble', 'other', 5);", 74 "INSERT into apr_dbd_test values ('wibble', 'nothing', 5);", 75 "INSERT into apr_dbd_test values ('qwerty', 'foo', 0);", 76 "INSERT into apr_dbd_test values ('asdfgh', 'bar', 1);", 77 NULL 78 }; 79 printf("Compound insert failed; trying statements one-by-one\n") ; 80 for (i=0; stmt[i] != NULL; ++i) { 81 statement = stmt[i]; 82 rv = apr_dbd_query(driver, handle, &nrows, statement); 83 if (rv) { 84 nerrors++; 85 } 86 } 87 if (nerrors) { 88 printf("%d single inserts failed too.\n", nerrors) ; 89 } 90 } 91 return rv; 92} 93static int invalid_op(apr_pool_t* pool, apr_dbd_t* handle, 94 const apr_dbd_driver_t* driver) 95{ 96 int rv = 0; 97 int nrows; 98 const char *statement = "INSERT into apr_dbd_test1 (col2) values ('foo')" ; 99 rv = apr_dbd_query(driver, handle, &nrows, statement); 100 printf("invalid op returned %d (should be nonzero). Error msg follows\n", rv); 101 printf("'%s'\n", apr_dbd_error(driver, handle, rv)); 102 statement = "INSERT into apr_dbd_test (col1, col2) values ('bar', 'foo')" ; 103 rv = apr_dbd_query(driver, handle, &nrows, statement); 104 printf("valid op returned %d (should be zero; error shouldn't affect subsequent ops)\n", rv); 105 return rv; 106} 107static int select_sequential(apr_pool_t* pool, apr_dbd_t* handle, 108 const apr_dbd_driver_t* driver) 109{ 110 int rv = 0; 111 int i = 0; 112 int n; 113 const char* entry; 114 const char* statement = "SELECT * FROM apr_dbd_test ORDER BY col1, col2"; 115 apr_dbd_results_t *res = NULL; 116 apr_dbd_row_t *row = NULL; 117 rv = apr_dbd_select(driver,pool,handle,&res,statement,0); 118 if (rv) { 119 printf("Select failed: %s", apr_dbd_error(driver, handle, rv)); 120 return rv; 121 } 122 for (rv = apr_dbd_get_row(driver, pool, res, &row, -1); 123 rv == 0; 124 rv = apr_dbd_get_row(driver, pool, res, &row, -1)) { 125 printf("ROW %d: ", ++i) ; 126 for (n = 0; n < apr_dbd_num_cols(driver, res); ++n) { 127 entry = apr_dbd_get_entry(driver, row, n); 128 if (entry == NULL) { 129 printf("(null) ") ; 130 } 131 else { 132 printf("%s ", entry); 133 } 134 } 135 fputs("\n", stdout); 136 } 137 return (rv == -1) ? 0 : 1; 138} 139static int select_random(apr_pool_t* pool, apr_dbd_t* handle, 140 const apr_dbd_driver_t* driver) 141{ 142 int rv = 0; 143 int n; 144 const char* entry; 145 const char* statement = "SELECT * FROM apr_dbd_test ORDER BY col1, col2"; 146 apr_dbd_results_t *res = NULL; 147 apr_dbd_row_t *row = NULL; 148 rv = apr_dbd_select(driver,pool,handle,&res,statement,1); 149 if (rv) { 150 printf("Select failed: %s", apr_dbd_error(driver, handle, rv)); 151 return rv; 152 } 153 rv = apr_dbd_get_row(driver, pool, res, &row, 5) ; 154 if (rv) { 155 printf("get_row failed: %s", apr_dbd_error(driver, handle, rv)); 156 return rv; 157 } 158 printf("ROW 5: "); 159 for (n = 0; n < apr_dbd_num_cols(driver, res); ++n) { 160 entry = apr_dbd_get_entry(driver, row, n); 161 if (entry == NULL) { 162 printf("(null) ") ; 163 } 164 else { 165 printf("%s ", entry); 166 } 167 } 168 fputs("\n", stdout); 169 rv = apr_dbd_get_row(driver, pool, res, &row, 1) ; 170 if (rv) { 171 printf("get_row failed: %s", apr_dbd_error(driver, handle, rv)); 172 return rv; 173 } 174 printf("ROW 1: "); 175 for (n = 0; n < apr_dbd_num_cols(driver, res); ++n) { 176 entry = apr_dbd_get_entry(driver, row, n); 177 if (entry == NULL) { 178 printf("(null) ") ; 179 } 180 else { 181 printf("%s ", entry); 182 } 183 } 184 fputs("\n", stdout); 185 rv = apr_dbd_get_row(driver, pool, res, &row, 11) ; 186 if (rv != -1) { 187 printf("Oops! get_row out of range but thinks it succeeded!\n%s\n", 188 apr_dbd_error(driver, handle, rv)); 189 return -1; 190 } 191 rv = 0; 192 193 return rv; 194} 195static int test_transactions(apr_pool_t* pool, apr_dbd_t* handle, 196 const apr_dbd_driver_t* driver) 197{ 198 int rv = 0; 199 int nrows; 200 apr_dbd_transaction_t *trans = NULL; 201 const char* statement; 202 203 /* trans 1 - error out early */ 204 printf("Transaction 1\n"); 205 rv = apr_dbd_transaction_start(driver, pool, handle, &trans); 206 if (rv) { 207 printf("Start transaction failed!\n%s\n", 208 apr_dbd_error(driver, handle, rv)); 209 return rv; 210 } 211 statement = "UPDATE apr_dbd_test SET col2 = 'failed'"; 212 rv = apr_dbd_query(driver, handle, &nrows, statement); 213 if (rv) { 214 printf("Update failed: '%s'\n", apr_dbd_error(driver, handle, rv)); 215 apr_dbd_transaction_end(driver, pool, trans); 216 return rv; 217 } 218 printf("%d rows updated\n", nrows); 219 220 statement = "INSERT INTO apr_dbd_test1 (col3) values (3)"; 221 rv = apr_dbd_query(driver, handle, &nrows, statement); 222 if (!rv) { 223 printf("Oops, invalid op succeeded but shouldn't!\n"); 224 } 225 statement = "INSERT INTO apr_dbd_test values ('zzz', 'aaa', 3)"; 226 rv = apr_dbd_query(driver, handle, &nrows, statement); 227 printf("Valid insert returned %d. Should be nonzero (fail) because transaction is bad\n", rv) ; 228 229 rv = apr_dbd_transaction_end(driver, pool, trans); 230 if (rv) { 231 printf("End transaction failed!\n%s\n", 232 apr_dbd_error(driver, handle, rv)); 233 return rv; 234 } 235 printf("Transaction ended (should be rollback) - viewing table\n" 236 "A column of \"failed\" indicates transaction failed (no rollback)\n"); 237 select_sequential(pool, handle, driver); 238 239 /* trans 2 - complete successfully */ 240 printf("Transaction 2\n"); 241 rv = apr_dbd_transaction_start(driver, pool, handle, &trans); 242 if (rv) { 243 printf("Start transaction failed!\n%s\n", 244 apr_dbd_error(driver, handle, rv)); 245 return rv; 246 } 247 statement = "UPDATE apr_dbd_test SET col2 = 'success'"; 248 rv = apr_dbd_query(driver, handle, &nrows, statement); 249 if (rv) { 250 printf("Update failed: '%s'\n", apr_dbd_error(driver, handle, rv)); 251 apr_dbd_transaction_end(driver, pool, trans); 252 return rv; 253 } 254 printf("%d rows updated\n", nrows); 255 statement = "INSERT INTO apr_dbd_test values ('aaa', 'zzz', 3)"; 256 rv = apr_dbd_query(driver, handle, &nrows, statement); 257 printf("Valid insert returned %d. Should be zero (OK)\n", rv) ; 258 rv = apr_dbd_transaction_end(driver, pool, trans); 259 if (rv) { 260 printf("End transaction failed!\n%s\n", 261 apr_dbd_error(driver, handle, rv)); 262 return rv; 263 } 264 printf("Transaction ended (should be commit) - viewing table\n"); 265 select_sequential(pool, handle, driver); 266 return rv; 267} 268static int test_pselect(apr_pool_t* pool, apr_dbd_t* handle, 269 const apr_dbd_driver_t* driver) 270{ 271 int rv = 0; 272 int i, n; 273 const char *query = 274 "SELECT * FROM apr_dbd_test WHERE col3 <= %s or col1 = 'bar'" ; 275 const char *label = "lowvalues"; 276 apr_dbd_prepared_t *statement = NULL; 277 apr_dbd_results_t *res = NULL; 278 apr_dbd_row_t *row = NULL; 279 const char *entry = NULL; 280 281 rv = apr_dbd_prepare(driver, pool, handle, query, label, &statement); 282 if (rv) { 283 printf("Prepare statement failed!\n%s\n", 284 apr_dbd_error(driver, handle, rv)); 285 return rv; 286 } 287 rv = apr_dbd_pvselect(driver, pool, handle, &res, statement, 0, "3", NULL); 288 if (rv) { 289 printf("Exec of prepared statement failed!\n%s\n", 290 apr_dbd_error(driver, handle, rv)); 291 return rv; 292 } 293 i = 0; 294 printf("Selecting rows where col3 <= 3 and bar row where it's unset.\nShould show four rows.\n"); 295 for (rv = apr_dbd_get_row(driver, pool, res, &row, -1); 296 rv == 0; 297 rv = apr_dbd_get_row(driver, pool, res, &row, -1)) { 298 printf("ROW %d: ", ++i) ; 299 for (n = 0; n < apr_dbd_num_cols(driver, res); ++n) { 300 entry = apr_dbd_get_entry(driver, row, n); 301 if (entry == NULL) { 302 printf("(null) ") ; 303 } 304 else { 305 printf("%s ", entry); 306 } 307 } 308 fputs("\n", stdout); 309 } 310 return (rv == -1) ? 0 : 1; 311} 312static int test_pquery(apr_pool_t* pool, apr_dbd_t* handle, 313 const apr_dbd_driver_t* driver) 314{ 315 int rv = 0; 316 const char *query = "INSERT INTO apr_dbd_test VALUES (%s, %s, %d)"; 317 apr_dbd_prepared_t *statement = NULL; 318 const char *label = "testpquery"; 319 int nrows; 320 apr_dbd_transaction_t *trans =0; 321 322 rv = apr_dbd_prepare(driver, pool, handle, query, label, &statement); 323 /* rv = apr_dbd_prepare(driver, pool, handle, query, NULL, &statement); */ 324 if (rv) { 325 printf("Prepare statement failed!\n%s\n", 326 apr_dbd_error(driver, handle, rv)); 327 return rv; 328 } 329 apr_dbd_transaction_start(driver, pool, handle, &trans); 330 rv = apr_dbd_pvquery(driver, pool, handle, &nrows, statement, 331 "prepared", "insert", "2", NULL); 332 apr_dbd_transaction_end(driver, pool, trans); 333 if (rv) { 334 printf("Exec of prepared statement failed!\n%s\n", 335 apr_dbd_error(driver, handle, rv)); 336 return rv; 337 } 338 printf("Showing table (should now contain row \"prepared insert 2\")\n"); 339 select_sequential(pool, handle, driver); 340 return rv; 341} 342int main(int argc, char** argv) 343{ 344 const char *name; 345 const char *params; 346 apr_pool_t *pool = NULL; 347 apr_dbd_t *sql = NULL; 348 const apr_dbd_driver_t *driver = NULL; 349 int rv; 350 351 apr_initialize(); 352 apr_pool_create(&pool, NULL); 353 354 if (argc >= 2 && argc <= 3) { 355 name = argv[1]; 356 params = ( argc == 3 ) ? argv[2] : ""; 357 apr_dbd_init(pool); 358 setbuf(stdout,NULL); 359 rv = apr_dbd_get_driver(pool, name, &driver); 360 switch (rv) { 361 case APR_SUCCESS: 362 printf("Loaded %s driver OK.\n", name); 363 break; 364 case APR_EDSOOPEN: 365 printf("Failed to load driver file apr_dbd_%s.so\n", name); 366 goto finish; 367 case APR_ESYMNOTFOUND: 368 printf("Failed to load driver apr_dbd_%s_driver.\n", name); 369 goto finish; 370 case APR_ENOTIMPL: 371 printf("No driver available for %s.\n", name); 372 goto finish; 373 default: /* it's a bug if none of the above happen */ 374 printf("Internal error loading %s.\n", name); 375 goto finish; 376 } 377 rv = apr_dbd_open(driver, pool, params, &sql); 378 switch (rv) { 379 case APR_SUCCESS: 380 printf("Opened %s[%s] OK\n", name, params); 381 break; 382 case APR_EGENERAL: 383 printf("Failed to open %s[%s]\n", name, params); 384 goto finish; 385 default: /* it's a bug if none of the above happen */ 386 printf("Internal error opening %s[%s]\n", name, params); 387 goto finish; 388 } 389 TEST("create table", create_table); 390 TEST("insert rows", insert_rows); 391 TEST("invalid op", invalid_op); 392 TEST("select random", select_random); 393 TEST("select sequential", select_sequential); 394 TEST("transactions", test_transactions); 395 TEST("prepared select", test_pselect); 396 TEST("prepared query", test_pquery); 397 TEST("drop table", drop_table); 398 apr_dbd_close(driver, sql); 399 } 400 else { 401 fprintf(stderr, "Usage: %s driver-name [params]\n", argv[0]); 402 } 403finish: 404 apr_pool_destroy(pool); 405 apr_terminate(); 406 return 0; 407} 408