| /* Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include "apu.h" |
| #include "apr_pools.h" |
| #include "apr_dbd.h" |
| |
| #include <stdio.h> |
| |
| #define TEST(msg,func) \ |
| printf("======== %s ========\n", msg); \ |
| rv = func(pool, sql, driver); \ |
| if (rv != 0) { \ |
| printf("Error in %s: rc=%d\n\n", msg, rv); \ |
| } \ |
| else { \ |
| printf("%s test successful\n\n", msg); \ |
| } \ |
| fflush(stdout); |
| |
| static int create_table(apr_pool_t* pool, apr_dbd_t* handle, |
| const apr_dbd_driver_t* driver) |
| { |
| int rv = 0; |
| int nrows; |
| const char *statement = "CREATE TABLE apr_dbd_test (" |
| "col1 varchar(40) not null," |
| "col2 varchar(40)," |
| "col3 integer)" ; |
| rv = apr_dbd_query(driver, handle, &nrows, statement); |
| return rv; |
| } |
| static int drop_table(apr_pool_t* pool, apr_dbd_t* handle, |
| const apr_dbd_driver_t* driver) |
| { |
| int rv = 0; |
| int nrows; |
| const char *statement = "DROP TABLE apr_dbd_test" ; |
| rv = apr_dbd_query(driver, handle, &nrows, statement); |
| return rv; |
| } |
| static int insert_rows(apr_pool_t* pool, apr_dbd_t* handle, |
| const apr_dbd_driver_t* driver) |
| { |
| int i; |
| int rv = 0; |
| int nrows; |
| int nerrors = 0; |
| const char *statement = |
| "INSERT into apr_dbd_test (col1) values ('foo');" |
| "INSERT into apr_dbd_test values ('wibble', 'other', 5);" |
| "INSERT into apr_dbd_test values ('wibble', 'nothing', 5);" |
| "INSERT into apr_dbd_test values ('qwerty', 'foo', 0);" |
| "INSERT into apr_dbd_test values ('asdfgh', 'bar', 1);" |
| ; |
| rv = apr_dbd_query(driver, handle, &nrows, statement); |
| if (rv) { |
| const char* stmt[] = { |
| "INSERT into apr_dbd_test (col1) values ('foo');", |
| "INSERT into apr_dbd_test values ('wibble', 'other', 5);", |
| "INSERT into apr_dbd_test values ('wibble', 'nothing', 5);", |
| "INSERT into apr_dbd_test values ('qwerty', 'foo', 0);", |
| "INSERT into apr_dbd_test values ('asdfgh', 'bar', 1);", |
| NULL |
| }; |
| printf("Compound insert failed; trying statements one-by-one\n") ; |
| for (i=0; stmt[i] != NULL; ++i) { |
| statement = stmt[i]; |
| rv = apr_dbd_query(driver, handle, &nrows, statement); |
| if (rv) { |
| nerrors++; |
| } |
| } |
| if (nerrors) { |
| printf("%d single inserts failed too.\n", nerrors) ; |
| } |
| } |
| return rv; |
| } |
| static int invalid_op(apr_pool_t* pool, apr_dbd_t* handle, |
| const apr_dbd_driver_t* driver) |
| { |
| int rv = 0; |
| int nrows; |
| const char *statement = "INSERT into apr_dbd_test1 (col2) values ('foo')" ; |
| rv = apr_dbd_query(driver, handle, &nrows, statement); |
| printf("invalid op returned %d (should be nonzero). Error msg follows\n", rv); |
| printf("'%s'\n", apr_dbd_error(driver, handle, rv)); |
| statement = "INSERT into apr_dbd_test (col1, col2) values ('bar', 'foo')" ; |
| rv = apr_dbd_query(driver, handle, &nrows, statement); |
| printf("valid op returned %d (should be zero; error shouldn't affect subsequent ops)\n", rv); |
| return rv; |
| } |
| static int select_sequential(apr_pool_t* pool, apr_dbd_t* handle, |
| const apr_dbd_driver_t* driver) |
| { |
| int rv = 0; |
| int i = 0; |
| int n; |
| const char* entry; |
| const char* statement = "SELECT * FROM apr_dbd_test ORDER BY col1, col2"; |
| apr_dbd_results_t *res = NULL; |
| apr_dbd_row_t *row = NULL; |
| rv = apr_dbd_select(driver,pool,handle,&res,statement,0); |
| if (rv) { |
| printf("Select failed: %s", apr_dbd_error(driver, handle, rv)); |
| return rv; |
| } |
| for (rv = apr_dbd_get_row(driver, pool, res, &row, -1); |
| rv == 0; |
| rv = apr_dbd_get_row(driver, pool, res, &row, -1)) { |
| printf("ROW %d: ", ++i) ; |
| for (n = 0; n < apr_dbd_num_cols(driver, res); ++n) { |
| entry = apr_dbd_get_entry(driver, row, n); |
| if (entry == NULL) { |
| printf("(null) ") ; |
| } |
| else { |
| printf("%s ", entry); |
| } |
| } |
| fputs("\n", stdout); |
| } |
| return (rv == -1) ? 0 : 1; |
| } |
| static int select_random(apr_pool_t* pool, apr_dbd_t* handle, |
| const apr_dbd_driver_t* driver) |
| { |
| int rv = 0; |
| int n; |
| const char* entry; |
| const char* statement = "SELECT * FROM apr_dbd_test ORDER BY col1, col2"; |
| apr_dbd_results_t *res = NULL; |
| apr_dbd_row_t *row = NULL; |
| rv = apr_dbd_select(driver,pool,handle,&res,statement,1); |
| if (rv) { |
| printf("Select failed: %s", apr_dbd_error(driver, handle, rv)); |
| return rv; |
| } |
| rv = apr_dbd_get_row(driver, pool, res, &row, 5) ; |
| if (rv) { |
| printf("get_row failed: %s", apr_dbd_error(driver, handle, rv)); |
| return rv; |
| } |
| printf("ROW 5: "); |
| for (n = 0; n < apr_dbd_num_cols(driver, res); ++n) { |
| entry = apr_dbd_get_entry(driver, row, n); |
| if (entry == NULL) { |
| printf("(null) ") ; |
| } |
| else { |
| printf("%s ", entry); |
| } |
| } |
| fputs("\n", stdout); |
| rv = apr_dbd_get_row(driver, pool, res, &row, 1) ; |
| if (rv) { |
| printf("get_row failed: %s", apr_dbd_error(driver, handle, rv)); |
| return rv; |
| } |
| printf("ROW 1: "); |
| for (n = 0; n < apr_dbd_num_cols(driver, res); ++n) { |
| entry = apr_dbd_get_entry(driver, row, n); |
| if (entry == NULL) { |
| printf("(null) ") ; |
| } |
| else { |
| printf("%s ", entry); |
| } |
| } |
| fputs("\n", stdout); |
| rv = apr_dbd_get_row(driver, pool, res, &row, 11) ; |
| if (rv != -1) { |
| printf("Oops! get_row out of range but thinks it succeeded!\n%s\n", |
| apr_dbd_error(driver, handle, rv)); |
| return -1; |
| } |
| rv = 0; |
| |
| return rv; |
| } |
| static int test_transactions(apr_pool_t* pool, apr_dbd_t* handle, |
| const apr_dbd_driver_t* driver) |
| { |
| int rv = 0; |
| int nrows; |
| apr_dbd_transaction_t *trans = NULL; |
| const char* statement; |
| |
| /* trans 1 - error out early */ |
| printf("Transaction 1\n"); |
| rv = apr_dbd_transaction_start(driver, pool, handle, &trans); |
| if (rv) { |
| printf("Start transaction failed!\n%s\n", |
| apr_dbd_error(driver, handle, rv)); |
| return rv; |
| } |
| statement = "UPDATE apr_dbd_test SET col2 = 'failed'"; |
| rv = apr_dbd_query(driver, handle, &nrows, statement); |
| if (rv) { |
| printf("Update failed: '%s'\n", apr_dbd_error(driver, handle, rv)); |
| apr_dbd_transaction_end(driver, pool, trans); |
| return rv; |
| } |
| printf("%d rows updated\n", nrows); |
| |
| statement = "INSERT INTO apr_dbd_test1 (col3) values (3)"; |
| rv = apr_dbd_query(driver, handle, &nrows, statement); |
| if (!rv) { |
| printf("Oops, invalid op succeeded but shouldn't!\n"); |
| } |
| statement = "INSERT INTO apr_dbd_test values ('zzz', 'aaa', 3)"; |
| rv = apr_dbd_query(driver, handle, &nrows, statement); |
| printf("Valid insert returned %d. Should be nonzero (fail) because transaction is bad\n", rv) ; |
| |
| rv = apr_dbd_transaction_end(driver, pool, trans); |
| if (rv) { |
| printf("End transaction failed!\n%s\n", |
| apr_dbd_error(driver, handle, rv)); |
| return rv; |
| } |
| printf("Transaction ended (should be rollback) - viewing table\n" |
| "A column of \"failed\" indicates transaction failed (no rollback)\n"); |
| select_sequential(pool, handle, driver); |
| |
| /* trans 2 - complete successfully */ |
| printf("Transaction 2\n"); |
| rv = apr_dbd_transaction_start(driver, pool, handle, &trans); |
| if (rv) { |
| printf("Start transaction failed!\n%s\n", |
| apr_dbd_error(driver, handle, rv)); |
| return rv; |
| } |
| statement = "UPDATE apr_dbd_test SET col2 = 'success'"; |
| rv = apr_dbd_query(driver, handle, &nrows, statement); |
| if (rv) { |
| printf("Update failed: '%s'\n", apr_dbd_error(driver, handle, rv)); |
| apr_dbd_transaction_end(driver, pool, trans); |
| return rv; |
| } |
| printf("%d rows updated\n", nrows); |
| statement = "INSERT INTO apr_dbd_test values ('aaa', 'zzz', 3)"; |
| rv = apr_dbd_query(driver, handle, &nrows, statement); |
| printf("Valid insert returned %d. Should be zero (OK)\n", rv) ; |
| rv = apr_dbd_transaction_end(driver, pool, trans); |
| if (rv) { |
| printf("End transaction failed!\n%s\n", |
| apr_dbd_error(driver, handle, rv)); |
| return rv; |
| } |
| printf("Transaction ended (should be commit) - viewing table\n"); |
| select_sequential(pool, handle, driver); |
| return rv; |
| } |
| static int test_pselect(apr_pool_t* pool, apr_dbd_t* handle, |
| const apr_dbd_driver_t* driver) |
| { |
| int rv = 0; |
| int i, n; |
| const char *query = |
| "SELECT * FROM apr_dbd_test WHERE col3 <= %s or col1 = 'bar'" ; |
| const char *label = "lowvalues"; |
| apr_dbd_prepared_t *statement = NULL; |
| apr_dbd_results_t *res = NULL; |
| apr_dbd_row_t *row = NULL; |
| const char *entry = NULL; |
| |
| rv = apr_dbd_prepare(driver, pool, handle, query, label, &statement); |
| if (rv) { |
| printf("Prepare statement failed!\n%s\n", |
| apr_dbd_error(driver, handle, rv)); |
| return rv; |
| } |
| rv = apr_dbd_pvselect(driver, pool, handle, &res, statement, 0, "3", NULL); |
| if (rv) { |
| printf("Exec of prepared statement failed!\n%s\n", |
| apr_dbd_error(driver, handle, rv)); |
| return rv; |
| } |
| i = 0; |
| printf("Selecting rows where col3 <= 3 and bar row where it's unset.\nShould show four rows.\n"); |
| for (rv = apr_dbd_get_row(driver, pool, res, &row, -1); |
| rv == 0; |
| rv = apr_dbd_get_row(driver, pool, res, &row, -1)) { |
| printf("ROW %d: ", ++i) ; |
| for (n = 0; n < apr_dbd_num_cols(driver, res); ++n) { |
| entry = apr_dbd_get_entry(driver, row, n); |
| if (entry == NULL) { |
| printf("(null) ") ; |
| } |
| else { |
| printf("%s ", entry); |
| } |
| } |
| fputs("\n", stdout); |
| } |
| return (rv == -1) ? 0 : 1; |
| } |
| static int test_pquery(apr_pool_t* pool, apr_dbd_t* handle, |
| const apr_dbd_driver_t* driver) |
| { |
| int rv = 0; |
| const char *query = "INSERT INTO apr_dbd_test VALUES (%s, %s, %d)"; |
| apr_dbd_prepared_t *statement = NULL; |
| const char *label = "testpquery"; |
| int nrows; |
| apr_dbd_transaction_t *trans =0; |
| |
| rv = apr_dbd_prepare(driver, pool, handle, query, label, &statement); |
| /* rv = apr_dbd_prepare(driver, pool, handle, query, NULL, &statement); */ |
| if (rv) { |
| printf("Prepare statement failed!\n%s\n", |
| apr_dbd_error(driver, handle, rv)); |
| return rv; |
| } |
| apr_dbd_transaction_start(driver, pool, handle, &trans); |
| rv = apr_dbd_pvquery(driver, pool, handle, &nrows, statement, |
| "prepared", "insert", "2", NULL); |
| apr_dbd_transaction_end(driver, pool, trans); |
| if (rv) { |
| printf("Exec of prepared statement failed!\n%s\n", |
| apr_dbd_error(driver, handle, rv)); |
| return rv; |
| } |
| printf("Showing table (should now contain row \"prepared insert 2\")\n"); |
| select_sequential(pool, handle, driver); |
| return rv; |
| } |
| int main(int argc, char** argv) |
| { |
| const char *name; |
| const char *params; |
| apr_pool_t *pool = NULL; |
| apr_dbd_t *sql = NULL; |
| const apr_dbd_driver_t *driver = NULL; |
| int rv; |
| |
| apr_initialize(); |
| apr_pool_create(&pool, NULL); |
| |
| if (argc >= 2 && argc <= 3) { |
| name = argv[1]; |
| params = ( argc == 3 ) ? argv[2] : ""; |
| apr_dbd_init(pool); |
| setbuf(stdout,NULL); |
| rv = apr_dbd_get_driver(pool, name, &driver); |
| switch (rv) { |
| case APR_SUCCESS: |
| printf("Loaded %s driver OK.\n", name); |
| break; |
| case APR_EDSOOPEN: |
| printf("Failed to load driver file apr_dbd_%s.so\n", name); |
| goto finish; |
| case APR_ESYMNOTFOUND: |
| printf("Failed to load driver apr_dbd_%s_driver.\n", name); |
| goto finish; |
| case APR_ENOTIMPL: |
| printf("No driver available for %s.\n", name); |
| goto finish; |
| default: /* it's a bug if none of the above happen */ |
| printf("Internal error loading %s.\n", name); |
| goto finish; |
| } |
| rv = apr_dbd_open(driver, pool, params, &sql); |
| switch (rv) { |
| case APR_SUCCESS: |
| printf("Opened %s[%s] OK\n", name, params); |
| break; |
| case APR_EGENERAL: |
| printf("Failed to open %s[%s]\n", name, params); |
| goto finish; |
| default: /* it's a bug if none of the above happen */ |
| printf("Internal error opening %s[%s]\n", name, params); |
| goto finish; |
| } |
| TEST("create table", create_table); |
| TEST("insert rows", insert_rows); |
| TEST("invalid op", invalid_op); |
| TEST("select random", select_random); |
| TEST("select sequential", select_sequential); |
| TEST("transactions", test_transactions); |
| TEST("prepared select", test_pselect); |
| TEST("prepared query", test_pquery); |
| TEST("drop table", drop_table); |
| apr_dbd_close(driver, sql); |
| } |
| else { |
| fprintf(stderr, "Usage: %s driver-name [params]\n", argv[0]); |
| } |
| finish: |
| apr_pool_destroy(pool); |
| apr_terminate(); |
| return 0; |
| } |