std::vector<MetadataStorage::UntypedTuple> MetadataStorage::select_query(const char* query) const { std::vector<UntypedTuple> tuples; apr_dbd_results_t *results = nullptr; int status = apr_dbd_select(driver_, pool_.get(), handle_.get(), &results, query, 0); if (status != 0) { (*logger_)(AKU_LOG_ERROR, "Error executing query"); throw std::runtime_error(apr_dbd_error(driver_, handle_.get(), status)); } // get rows int ntuples = apr_dbd_num_tuples(driver_, results); int ncolumns = apr_dbd_num_cols(driver_, results); for (int i = ntuples; i --> 0;) { apr_dbd_row_t *row = nullptr; status = apr_dbd_get_row(driver_, pool_.get(), results, &row, -1); if (status != 0) { (*logger_)(AKU_LOG_ERROR, "Error getting row from resultset"); throw std::runtime_error(apr_dbd_error(driver_, handle_.get(), status)); } UntypedTuple tup; for (int col = 0; col < ncolumns; col++) { const char* entry = apr_dbd_get_entry(driver_, row, col); if (entry) { tup.emplace_back(entry); } else { tup.emplace_back(); } } tuples.push_back(std::move(tup)); } return tuples; }
static int authz_dbd_group_query(request_rec *r, authz_dbd_cfg *cfg, apr_array_header_t *groups) { /* SELECT group FROM authz WHERE user = %s */ int rv; const char *message; ap_dbd_t *dbd; apr_dbd_prepared_t *query; apr_dbd_results_t *res = NULL; apr_dbd_row_t *row = NULL; if (cfg->query == NULL) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01649) "No query configured for dbd-group!"); return HTTP_INTERNAL_SERVER_ERROR; } dbd = dbd_handle(r); if (dbd == NULL) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02903) "No db handle available for dbd-query! " "Check your database access"); return HTTP_INTERNAL_SERVER_ERROR; } query = apr_hash_get(dbd->prepared, cfg->query, APR_HASH_KEY_STRING); if (query == NULL) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01650) "Error retrieving query for dbd-group!"); return HTTP_INTERNAL_SERVER_ERROR; } rv = apr_dbd_pvselect(dbd->driver, r->pool, dbd->handle, &res, query, 0, r->user, NULL); if (rv == 0) { for (rv = apr_dbd_get_row(dbd->driver, r->pool, res, &row, -1); rv != -1; rv = apr_dbd_get_row(dbd->driver, r->pool, res, &row, -1)) { if (rv == 0) { APR_ARRAY_PUSH(groups, const char *) = apr_pstrdup(r->pool, apr_dbd_get_entry(dbd->driver, row, 0)); } else { message = apr_dbd_error(dbd->driver, dbd->handle, rv); ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01651) "authz_dbd in get_row; group query for user=%s [%s]", r->user, message?message:noerror); return HTTP_INTERNAL_SERVER_ERROR; } } } else { message = apr_dbd_error(dbd->driver, dbd->handle, rv); ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01652) "authz_dbd, in groups query for %s [%s]", r->user, message?message:noerror); return HTTP_INTERNAL_SERVER_ERROR; } return OK; }
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; }
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; }
/** * Load the session by the key specified. */ static apr_status_t dbd_load(request_rec * r, const char *key, const char **val) { apr_status_t rv; ap_dbd_t *dbd = NULL; apr_dbd_prepared_t *statement = NULL; apr_dbd_results_t *res = NULL; apr_dbd_row_t *row = NULL; apr_int64_t expiry = (apr_int64_t) apr_time_now(); session_dbd_dir_conf *conf = ap_get_module_config(r->per_dir_config, &session_dbd_module); if (conf->selectlabel == NULL) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01853) "no SessionDBDselectlabel has been specified"); return APR_EGENERAL; } rv = dbd_init(r, conf->selectlabel, &dbd, &statement); if (rv) { return rv; } rv = apr_dbd_pvbselect(dbd->driver, r->pool, dbd->handle, &res, statement, 0, key, &expiry, NULL); if (rv) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01854) "query execution error saving session '%s' " "in database using query '%s': %s", key, conf->selectlabel, apr_dbd_error(dbd->driver, dbd->handle, rv)); return APR_EGENERAL; } for (rv = apr_dbd_get_row(dbd->driver, r->pool, res, &row, -1); rv != -1; rv = apr_dbd_get_row(dbd->driver, r->pool, res, &row, -1)) { if (rv != 0) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01855) "error retrieving results while saving '%s' " "in database using query '%s': %s", key, conf->selectlabel, apr_dbd_error(dbd->driver, dbd->handle, rv)); return APR_EGENERAL; } if (*val == NULL) { *val = apr_dbd_get_entry(dbd->driver, row, 0); } /* we can't break out here or row won't get cleaned up */ } return APR_SUCCESS; }
/* ============================================================================= db:query(statement): Executes the given database query and returns the number of rows affected. If an error is encountered, returns nil as the first parameter and the error message as the second. ============================================================================= */ int lua_db_query(lua_State *L) { /*~~~~~~~~~~~~~~~~~~~~~~~*/ lua_db_handle *db = 0; apr_status_t rc = 0; int x = 0; const char *statement; /*~~~~~~~~~~~~~~~~~~~~~~~*/ luaL_checktype(L, 3, LUA_TSTRING); statement = lua_tostring(L, 3); db = lua_get_db_handle(L); if (db && db->alive) rc = apr_dbd_query(db->driver, db->handle, &x, statement); else { rc = 0; x = -1; } if (rc == APR_SUCCESS) lua_pushnumber(L, x); else { /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ const char *err = apr_dbd_error(db->driver, db->handle, rc); /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ lua_pushnil(L); if (err) { lua_pushstring(L, err); return 2; } } return 1; }
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 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; }
int MetadataStorage::execute_query(std::string query) { int nrows = -1; int status = apr_dbd_query(driver_, handle_.get(), &nrows, query.c_str()); if (status != 0 && status != 21) { // generate error and throw (*logger_)(AKU_LOG_ERROR, "Error executing query"); throw std::runtime_error(apr_dbd_error(driver_, handle_.get(), status)); } return nrows; }
int mod_okioki_view_execute(request_rec *http_request, mod_okioki_dir_config *cfg, view_t *view, apr_hash_t *arguments, const apr_dbd_driver_t **db_driver, apr_dbd_results_t **db_result, char **error) { apr_pool_t *pool = http_request->pool; ap_dbd_t *db_conn; apr_dbd_prepared_t *db_statement; char *arg; int argc = view->nr_sql_params; char *argv[argc + 1]; off_t i; int ret; // Copy the pointers parameters in the right order for the SQL statement. for (i = 0; i < argc; i++) { ASSERT_NOT_NULL( arg = (char *)apr_hash_get(arguments, view->sql_params[i], view->sql_params_len[i]), HTTP_INTERNAL_SERVER_ERROR, "Could not find parameter '%s' in request.", view->sql_params[i] ) argv[i] = arg; } argv[i] = NULL; // Retrieve a database connection from the resource pool. ASSERT_NOT_NULL( db_conn = ap_dbd_acquire(http_request), HTTP_INTERNAL_SERVER_ERROR, "Can not get database connection." ) *db_driver = db_conn->driver; // Get the prepared statement. ASSERT_NOT_NULL( db_statement = apr_hash_get((db_conn)->prepared, view->sql, view->sql_len), HTTP_INTERNAL_SERVER_ERROR, "Can not find '%s'", view->sql ) // Execute the statement. *db_result = NULL; // Execute a select statement. We allow random access here as it allows easier configuration because the number // of columns and the name of the columns are known when random access is enabled. // Also because we use buckets and brigades everything is done in memory already, so streaming data would not // have worked anyway. ASSERT_APR_SUCCESS( ret = apr_dbd_pselect(db_conn->driver, db_conn->pool, db_conn->handle, db_result, db_statement, 1, argc, (const char **)argv), HTTP_BAD_GATEWAY, "%s", apr_dbd_error(db_conn->driver, db_conn->handle, ret) ) ASSERT_NOT_NULL( *db_result, HTTP_BAD_GATEWAY, "Result was not set by apr_dbd_pselect." ) return HTTP_OK; }
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; }
MetadataStorage::MetadataStorage(const char* db, aku_logger_cb_t logger) : pool_(nullptr, &delete_apr_pool) , driver_(nullptr) , handle_(nullptr, AprHandleDeleter(nullptr)) , logger_(logger) { apr_pool_t *pool = nullptr; auto status = apr_pool_create(&pool, NULL); if (status != APR_SUCCESS) { // report error (can't return error from c-tor) throw std::runtime_error("Can't create memory pool"); } pool_.reset(pool); status = apr_dbd_get_driver(pool, "sqlite3", &driver_); if (status != APR_SUCCESS) { (*logger_)(AKU_LOG_ERROR, "Can't load driver, maybe libaprutil1-dbd-sqlite3 isn't installed"); throw std::runtime_error("Can't load sqlite3 dirver"); } apr_dbd_t *handle = nullptr; status = apr_dbd_open(driver_, pool, db, &handle); if (status != APR_SUCCESS) { (*logger_)(AKU_LOG_ERROR, "Can't open database, check file path"); throw std::runtime_error("Can't open database"); } handle_ = HandleT(handle, AprHandleDeleter(driver_)); auto sqlite_handle = apr_dbd_native_handle(driver_, handle); sqlite3_trace((sqlite3*)sqlite_handle, callback_adapter, (void*)logger_); create_tables(); // Create prepared statement const char* query = "INSERT INTO akumuli_series (series_id, keyslist, storage_id) VALUES (%s, %s, %d)"; status = apr_dbd_prepare(driver_, pool_.get(), handle_.get(), query, "INSERT_SERIES_NAME", &insert_); if (status != 0) { (*logger_)(AKU_LOG_ERROR, "Error creating prepared statement"); throw std::runtime_error(apr_dbd_error(driver_, handle_.get(), status)); } }
APU_DECLARE(apr_status_t) apr_dbd_open_ex(const apr_dbd_driver_t *driver, apr_pool_t *pool, const char *params, apr_dbd_t **handle, const char **error) { apr_status_t rv; *handle = (driver->open)(pool, params, error); if (*handle == NULL) { return APR_EGENERAL; } rv = apr_dbd_check_conn(driver, pool, *handle); if ((rv != APR_SUCCESS) && (rv != APR_ENOTIMPL)) { /* XXX: rv is APR error code, but apr_dbd_error() takes int! */ if (error) { *error = apr_dbd_error(driver, *handle, rv); } apr_dbd_close(driver, *handle); return APR_EGENERAL; } return APR_SUCCESS; }
/* Run an insert query and return a categorized error or success */ static logsql_query_ret log_sql_dbd_query(request_rec *r,logsql_dbconnection *db, const char *query) { int ret; const char *err; int affected; // Acquire a DBD connection from mod_dbd ap_dbd_t *dbd = log_sql_dbd_getconnection(r); if (!dbd) return LOGSQL_QUERY_NOLINK; // Run the query ret = apr_dbd_query(dbd->driver, dbd->handle, &affected, query); if (ret == 0) { return LOGSQL_QUERY_SUCCESS; } else { // attempt to detect error message err = apr_dbd_error(dbd->driver, dbd->handle, ret); log_error(APLOG_MARK, APLOG_ERR, 0, r->server, "DB Returned error: (%d) %s", ret, err); // Unable to check if "NO SUCH TABLE" due to apr_dbd not mapping error codes to a standard set. return LOGSQL_QUERY_FAIL; } }
/* ============================================================================= statement:query(var1, var2, var3...): Injects variables into a prepared statement and returns the number of rows affected. ============================================================================= */ int lua_db_prepared_query(lua_State *L) { /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ lua_db_prepared_statement *st = 0; apr_status_t rc = 0; const char **vars; int x, have; /*~~~~~~~~~~~~~~~~~~~~~~~*/ /* Fetch the prepared statement and the vars passed */ luaL_checktype(L, 1, LUA_TTABLE); lua_rawgeti(L, 1, 0); luaL_checktype(L, -1, LUA_TUSERDATA); st = (lua_db_prepared_statement*) lua_topointer(L, -1); /* Check if we got enough variables passed on to us. * This, of course, only works for prepped statements made through lua. */ have = lua_gettop(L) - 2; if (st->variables != -1 && have < st->variables ) { lua_pushboolean(L, 0); lua_pushfstring(L, "Error in executing prepared statement: Expected %d arguments, got %d.", st->variables, have); return 2; } vars = apr_pcalloc(st->db->pool, have*sizeof(char *)); for (x = 0; x < have; x++) { vars[x] = lua_tostring(L, x + 2); } /* Fire off the query */ if (st->db && st->db->alive) { /*~~~~~~~~~~~~~~*/ int affected = 0; /*~~~~~~~~~~~~~~*/ rc = apr_dbd_pquery(st->db->driver, st->db->pool, st->db->handle, &affected, st->statement, have, vars); if (rc == APR_SUCCESS) { lua_pushinteger(L, affected); return 1; } else { /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ const char *err = apr_dbd_error(st->db->driver, st->db->handle, rc); /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ lua_pushnil(L); if (err) { lua_pushstring(L, err); return 2; } return 1; } } lua_pushboolean(L, 0); lua_pushliteral(L, "Database connection seems to be closed, please reacquire it."); return (2); }
/* ============================================================================= statement:select(var1, var2, var3...): Injects variables into a prepared statement and returns the number of rows matching the query. ============================================================================= */ int lua_db_prepared_select(lua_State *L) { /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ lua_db_prepared_statement *st = 0; apr_status_t rc = 0; const char **vars; int x, have; /*~~~~~~~~~~~~~~~~~~~~~~~*/ /* Fetch the prepared statement and the vars passed */ luaL_checktype(L, 1, LUA_TTABLE); lua_rawgeti(L, 1, 0); luaL_checktype(L, -1, LUA_TUSERDATA); st = (lua_db_prepared_statement*) lua_topointer(L, -1); /* Check if we got enough variables passed on to us. * This, of course, only works for prepped statements made through lua. */ have = lua_gettop(L) - 2; if (st->variables != -1 && have < st->variables ) { lua_pushboolean(L, 0); lua_pushfstring(L, "Error in executing prepared statement: Expected %d arguments, got %d.", st->variables, have); return 2; } vars = apr_pcalloc(st->db->pool, have*sizeof(char *)); for (x = 0; x < have; x++) { vars[x] = lua_tostring(L, x + 2); } /* Fire off the query */ if (st->db && st->db->alive) { /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ int cols; apr_dbd_results_t *results = 0; /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ rc = apr_dbd_pselect(st->db->driver, st->db->pool, st->db->handle, &results, st->statement, 0, have, vars); if (rc == APR_SUCCESS) { /*~~~~~~~~~~~~~~~~~~~~~*/ lua_db_result_set *resultset; /*~~~~~~~~~~~~~~~~~~~~~*/ cols = apr_dbd_num_cols(st->db->driver, results); lua_newtable(L); resultset = lua_newuserdata(L, sizeof(lua_db_result_set)); resultset->cols = cols; resultset->driver = st->db->driver; resultset->pool = st->db->pool; resultset->rows = apr_dbd_num_tuples(st->db->driver, results); resultset->results = results; luaL_newmetatable(L, "lua_apr.dbselect"); lua_pushliteral(L, "__call"); lua_pushcfunction(L, lua_db_get_row); lua_rawset(L, -3); lua_setmetatable(L, -3); lua_rawseti(L, -2, 0); return 1; } else { /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ const char *err = apr_dbd_error(st->db->driver, st->db->handle, rc); /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ lua_pushnil(L); if (err) { lua_pushstring(L, err); return 2; } return 1; } } lua_pushboolean(L, 0); lua_pushliteral(L, "Database connection seems to be closed, please reacquire it."); return (2); }
/* ============================================================================= db:select(statement): Queries the database for the given statement and returns the rows/columns found as a table. If an error is encountered, returns nil as the first parameter and the error message as the second. ============================================================================= */ int lua_db_select(lua_State *L) { /*~~~~~~~~~~~~~~~~~~~~~~~*/ lua_db_handle *db = 0; apr_status_t rc = 0; const char *statement; request_rec *r; /*~~~~~~~~~~~~~~~~~~~~~~~*/ r = ap_lua_check_request_rec(L, 2); if (r) { luaL_checktype(L, 3, LUA_TSTRING); statement = lua_tostring(L, 3); db = lua_get_db_handle(L); if (db && db->alive) { /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ int cols; apr_dbd_results_t *results = 0; lua_db_result_set* resultset = NULL; /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ rc = apr_dbd_select(db->driver, db->pool, db->handle, &results, statement, 0); if (rc == APR_SUCCESS) { cols = apr_dbd_num_cols(db->driver, results); if (cols > 0) { lua_newtable(L); resultset = lua_newuserdata(L, sizeof(lua_db_result_set)); resultset->cols = cols; resultset->driver = db->driver; resultset->pool = db->pool; resultset->rows = apr_dbd_num_tuples(db->driver, results); resultset->results = results; luaL_newmetatable(L, "lua_apr.dbselect"); lua_pushliteral(L, "__call"); lua_pushcfunction(L, lua_db_get_row); lua_rawset(L, -3); lua_setmetatable(L, -3); lua_rawseti(L, -2, 0); return 1; } return 0; } else { /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ const char *err = apr_dbd_error(db->driver, db->handle, rc); /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ lua_pushnil(L); if (err) { lua_pushstring(L, err); return 2; } } } lua_pushboolean(L, 0); return 1; } return 0; }
/** * Save the session by the key specified. */ static apr_status_t dbd_save(request_rec * r, const char *key, const char *val, apr_int64_t expiry) { apr_status_t rv; ap_dbd_t *dbd = NULL; apr_dbd_prepared_t *statement; int rows = 0; session_dbd_dir_conf *conf = ap_get_module_config(r->per_dir_config, &session_dbd_module); if (conf->updatelabel == NULL) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01856) "no SessionDBDupdatelabel has been specified"); return APR_EGENERAL; } rv = dbd_init(r, conf->updatelabel, &dbd, &statement); if (rv) { return rv; } rv = apr_dbd_pvbquery(dbd->driver, r->pool, dbd->handle, &rows, statement, val, &expiry, key, NULL); if (rv) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01857) "query execution error updating session '%s' " "using database query '%s': %s", key, conf->updatelabel, apr_dbd_error(dbd->driver, dbd->handle, rv)); return APR_EGENERAL; } /* * if some rows were updated it means a session existed and was updated, * so we are done. */ if (rows != 0) { return APR_SUCCESS; } if (conf->insertlabel == NULL) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01858) "no SessionDBDinsertlabel has been specified"); return APR_EGENERAL; } rv = dbd_init(r, conf->insertlabel, &dbd, &statement); if (rv) { return rv; } rv = apr_dbd_pvbquery(dbd->driver, r->pool, dbd->handle, &rows, statement, val, &expiry, key, NULL); if (rv) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01859) "query execution error inserting session '%s' " "in database with '%s': %s", key, conf->insertlabel, apr_dbd_error(dbd->driver, dbd->handle, rv)); return APR_EGENERAL; } /* * if some rows were inserted it means a session was inserted, so we are * done. */ if (rows != 0) { return APR_SUCCESS; } ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01860) "the session insert query did not cause any rows to be added " "to the database for session '%s', session not inserted", key); return APR_EGENERAL; }
static int authz_dbd_login(request_rec *r, authz_dbd_cfg *cfg, const char *action) { int rv; const char *newuri = NULL; int nrows; const char *message; ap_dbd_t *dbd; apr_dbd_prepared_t *query; apr_dbd_results_t *res = NULL; apr_dbd_row_t *row = NULL; if (cfg->query == NULL) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01642) "No query configured for %s!", action); return HTTP_INTERNAL_SERVER_ERROR; } dbd = dbd_handle(r); if (dbd == NULL) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02902) "No db handle available for %s! " "Check your database access", action); return HTTP_INTERNAL_SERVER_ERROR; } query = apr_hash_get(dbd->prepared, cfg->query, APR_HASH_KEY_STRING); if (query == NULL) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01643) "Error retrieving Query for %s!", action); return HTTP_INTERNAL_SERVER_ERROR; } rv = apr_dbd_pvquery(dbd->driver, r->pool, dbd->handle, &nrows, query, r->user, NULL); if (rv == 0) { if (nrows != 1) { ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01644) "authz_dbd: %s of user %s updated %d rows", action, r->user, nrows); } } else { message = apr_dbd_error(dbd->driver, dbd->handle, rv); ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01645) "authz_dbd: query for %s failed; user %s [%s]", action, r->user, message?message:noerror); return HTTP_INTERNAL_SERVER_ERROR; } if (cfg->redirect == 1) { newuri = apr_table_get(r->headers_in, "Referer"); } if (!newuri && cfg->redir_query) { query = apr_hash_get(dbd->prepared, cfg->redir_query, APR_HASH_KEY_STRING); if (query == NULL) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01646) "authz_dbd: no redirect query!"); /* OK, this is non-critical; we can just not-redirect */ } else if ((rv = apr_dbd_pvselect(dbd->driver, r->pool, dbd->handle, &res, query, 0, r->user, NULL)) == 0) { for (rv = apr_dbd_get_row(dbd->driver, r->pool, res, &row, -1); rv != -1; rv = apr_dbd_get_row(dbd->driver, r->pool, res, &row, -1)) { if (rv != 0) { message = apr_dbd_error(dbd->driver, dbd->handle, rv); ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01647) "authz_dbd in get_row; action=%s user=%s [%s]", action, r->user, message?message:noerror); } else if (newuri == NULL) { newuri = apr_pstrdup(r->pool, apr_dbd_get_entry(dbd->driver, row, 0)); } /* we can't break out here or row won't get cleaned up */ } } else { message = apr_dbd_error(dbd->driver, dbd->handle, rv); ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01648) "authz_dbd/redirect for %s of %s [%s]", action, r->user, message?message:noerror); } } if (newuri != NULL) { r->status = HTTP_MOVED_TEMPORARILY; apr_table_set(r->err_headers_out, "Location", newuri); } authz_dbd_run_client_login(r, OK, action); return OK; }
static int authz_dbd_query(request_rec *r, authz_dbd_cfg *cfg, const apr_array_header_t *query_parameters, apr_array_header_t *query_result_rows) { /* SELECT group FROM authz WHERE col = %s, col = %s, ... */ int rv; const char *message; ap_dbd_t *dbd = dbd_handle(r); apr_dbd_prepared_t *query; apr_dbd_results_t *res = NULL; apr_dbd_row_t *row = NULL; const char **query_result_row; if (cfg->query == NULL) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO() "No query configured for dbd-query!"); return HTTP_INTERNAL_SERVER_ERROR; } if (dbd == NULL) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO() "No db handle available for dbd-query! Check your database access"); return HTTP_INTERNAL_SERVER_ERROR; } query = apr_hash_get(dbd->prepared, cfg->query, APR_HASH_KEY_STRING); if (query == NULL) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO() "Error retrieving query for dbd-query!"); return HTTP_INTERNAL_SERVER_ERROR; } rv = apr_dbd_pselect(dbd->driver, r->pool, dbd->handle, &res, query, 0, query_parameters->nelts, (const char **)query_parameters->elts); if (rv == 0) { for (rv = apr_dbd_get_row(dbd->driver, r->pool, res, &row, -1); rv != -1; rv = apr_dbd_get_row(dbd->driver, r->pool, res, &row, -1)) { if (rv == 0) { query_result_row = apr_array_push(query_result_rows); *query_result_row = apr_dbd_get_entry(dbd->driver, row, 0); } else { message = apr_dbd_error(dbd->driver, dbd->handle, rv); ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO() "authz_dbd dbd_query in get_row; query for user=%s [%s]", r->user, message?message:noerror); return HTTP_INTERNAL_SERVER_ERROR; } } } else { message = apr_dbd_error(dbd->driver, dbd->handle, rv); ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO() "authz_dbd, in dbd_query query for %s [%s]", r->user, message?message:noerror); return HTTP_INTERNAL_SERVER_ERROR; } return OK; }
/* ============================================================================= db:prepare(statement): Prepares a statement for later query/select. Returns a table with a :query and :select function, same as the db funcs. ============================================================================= */ int lua_db_prepare(lua_State* L) { /*~~~~~~~~~~~~~~~~~~~~~~~~~~*/ lua_db_handle *db = 0; apr_status_t rc = 0; const char *statement, *at; request_rec *r; lua_db_prepared_statement* st; int need = 0; /*~~~~~~~~~~~~~~~~~~~~~~~~~~*/ r = ap_lua_check_request_rec(L, 2); if (r) { apr_dbd_prepared_t *pstatement = NULL; luaL_checktype(L, 3, LUA_TSTRING); statement = lua_tostring(L, 3); /* Count number of variables in statement */ at = ap_strchr_c(statement,'%'); while (at != NULL) { if (at[1] == '%') { at++; } else { need++; } at = ap_strchr_c(at+1,'%'); } db = lua_get_db_handle(L); rc = apr_dbd_prepare(db->driver, r->pool, db->handle, statement, NULL, &pstatement); if (rc != APR_SUCCESS) { /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ const char *err = apr_dbd_error(db->driver, db->handle, rc); /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ lua_pushnil(L); if (err) { lua_pushstring(L, err); return 2; } return 1; } /* Push the prepared statement table */ lua_newtable(L); st = lua_newuserdata(L, sizeof(lua_db_prepared_statement)); st->statement = pstatement; st->variables = need; st->db = db; lua_pushliteral(L, "select"); lua_pushcfunction(L, lua_db_prepared_select); lua_rawset(L, -4); lua_pushliteral(L, "query"); lua_pushcfunction(L, lua_db_prepared_query); lua_rawset(L, -4); lua_rawseti(L, -2, 0); return 1; } return 0; }
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; }
void * APR_THREAD_FUNC sync_dir(apr_thread_t* thread, void* ptr){ int files_synced = 0; int status; apr_status_t rv; const char* dbd_error; List* file_list; music_file* song; dir_sync_thread_t* dir_sync = (dir_sync_thread_t*) ptr; apr_pool_t* pool; db_config_t* db_config = dir_sync->db_config; char error_message[256]; //Create sub pool used for sync rv = apr_pool_create_ex(&pool, dir_sync->pool, NULL, NULL); if(rv != APR_SUCCESS){ error_messages_add(dir_sync->error_messages, ERROR ,"Memory Pool Error", apr_strerror(rv, error_message, sizeof(error_message))); return 0; } file_list = apr_pcalloc(pool, sizeof(List)); dir_sync->dir->stats->num_files = apr_pcalloc(pool, sizeof(int)); if(db_config->connected != 1){ error_messages_add(dir_sync->error_messages, ERROR, "Database not connected","ERROR ERROR"); return 0; } count_table_rows(); read_dir(pool, file_list, dir_sync->dir->path, dir_sync->dir->stats->num_files, dir_sync->error_messages); if ((file_list == NULL || dir_sync->dir->stats->num_files == NULL )&& (*dir_sync->dir->stats->num_files ) > 0 ){ error_messages_add(dir_sync->error_messages, ERROR, "Killing Sync Thread", ""); return 0; } status = apr_dbd_transaction_start(db_config->dbd_driver, pool, db_config->dbd_handle,&(db_config->transaction)); if(status != 0){ dbd_error = apr_dbd_error(db_config->dbd_driver, db_config->dbd_handle, status); error_messages_add(dir_sync->error_messages,ERROR, "Database error start transaction", dbd_error); return 0; } while(file_list->file.path){ song = apr_pcalloc(pool, sizeof(music_file)); song->file = &(file_list->file); switch(song->file->type){ #ifdef WITH_FLAC case FLAC:{ status = read_flac_level1(pool, song); if (status == 0){ song->file->type_string = "flac"; } break; } #endif #ifdef WITH_OGG case OGG:{ status = read_ogg(pool, song); if (status == 0){ song->file->type_string = "ogg"; } break; } #endif #ifdef WITH_MP3 case MP3:{ status = read_id3(pool,song); if (status == 0){ song->file->type_string = "mp3"; } break; } #endif default:{ status = -1; break; } } if (status == 0 && song){ //We have song get musicbrainz ids //status = get_musicbrainz_release_id(pool, song, dir_sync->error_messages); //Update or Insert song if (db_config->connected == 1){ status = sync_song(pool, db_config, song); if (status != 0){ error_messages_add(dir_sync->error_messages, ERROR, apr_psprintf(pool,"Failed to sync song:"), apr_psprintf(pool, "(%d) Song title: %s Song artist: %s song album:%s song file path: %s",status, song->title, song->artist, song->album, song->file->path)); } }else{ //Lost connection kill thread error_messages_add(dir_sync->error_messages, ERROR, "Failed to sync song:", "Lost connection to database"); return 0; } } //Calculate the percent of files synchronized dir_sync->dir->stats->sync_progress =(float) files_synced*100 / (*(dir_sync->dir->stats->num_files) - 1); dir_sync->dir->stats->files_scanned = files_synced; files_synced++; file_list = file_list->next; } status = apr_dbd_transaction_end(db_config->dbd_driver, pool, db_config->transaction); if(status != 0){ dbd_error = apr_dbd_error(db_config->dbd_driver, db_config->dbd_handle, status); error_messages_add(dir_sync->error_messages, ERROR, "Database error couldn't end transaction",dbd_error); return 0; } apr_pool_clear(pool); return 0; }
static authn_status authn_dbd_realm(request_rec *r, const char *user, const char *realm, char **rethash) { apr_status_t rv; const char *dbd_hash = NULL; apr_dbd_prepared_t *statement; apr_dbd_results_t *res = NULL; apr_dbd_row_t *row = NULL; int ret; authn_dbd_conf *conf = ap_get_module_config(r->per_dir_config, &authn_dbd_module); ap_dbd_t *dbd = authn_dbd_acquire_fn(r); if (dbd == NULL) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01658) "Failed to acquire database connection to look up " "user '%s:%s'", user, realm); return AUTH_GENERAL_ERROR; } if (conf->realm == NULL) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01659) "No AuthDBDUserRealmQuery has been specified"); return AUTH_GENERAL_ERROR; } statement = apr_hash_get(dbd->prepared, conf->realm, APR_HASH_KEY_STRING); if (statement == NULL) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01660) "A prepared statement could not be found for " "AuthDBDUserRealmQuery with the key '%s'", conf->realm); return AUTH_GENERAL_ERROR; } if ((ret = apr_dbd_pvselect(dbd->driver, r->pool, dbd->handle, &res, statement, 0, user, realm, NULL) != 0)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01661) "Query execution error looking up '%s:%s' " "in database [%s]", user, realm, apr_dbd_error(dbd->driver, dbd->handle, ret)); return AUTH_GENERAL_ERROR; } for (rv = apr_dbd_get_row(dbd->driver, r->pool, res, &row, -1); rv != -1; rv = apr_dbd_get_row(dbd->driver, r->pool, res, &row, -1)) { if (rv != 0) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01662) "Error retrieving results while looking up '%s:%s' " "in database", user, realm); return AUTH_GENERAL_ERROR; } if (dbd_hash == NULL) { #if APU_MAJOR_VERSION > 1 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 3) /* add the rest of the columns to the environment */ int i = 1; const char *name; for (name = apr_dbd_get_name(dbd->driver, res, i); name != NULL; name = apr_dbd_get_name(dbd->driver, res, i)) { char *str = apr_pstrcat(r->pool, AUTHN_PREFIX, name, NULL); int j = sizeof(AUTHN_PREFIX)-1; /* string length of "AUTHENTICATE_", excluding the trailing NIL */ while (str[j]) { if (!apr_isalnum(str[j])) { str[j] = '_'; } else { str[j] = apr_toupper(str[j]); } j++; } apr_table_set(r->subprocess_env, str, apr_dbd_get_entry(dbd->driver, row, i)); i++; } #endif dbd_hash = apr_dbd_get_entry(dbd->driver, row, 0); } /* we can't break out here or row won't get cleaned up */ } if (!dbd_hash) { return AUTH_USER_NOT_FOUND; } AUTHN_CACHE_STORE(r, user, realm, dbd_hash); *rethash = apr_pstrdup(r->pool, dbd_hash); return AUTH_USER_FOUND; }