/////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2010-2011 Artyom Beilis (Tonkikh) // // Distributed under: // // the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // // or (at your opinion) under: // // The MIT License // (See accompanying file MIT.txt or a copy at // http://www.opensource.org/licenses/mit-license.php) // /////////////////////////////////////////////////////////////////////////////// #define CPPDB_SOURCE #include #include #include #include #include namespace cppdb { namespace backend { //result struct result::data {}; result::result() {} result::~result() {} //statement struct statement::data {}; statement::statement() : cache_(0) { } statement::~statement() { } void statement::cache(statements_cache *c) { cache_ = c; } void statement::dispose(statement *p) { if(!p) return; statements_cache *cache = p->cache_; p->cache_ = 0; if(cache) cache->put(p); else delete p; } //statements cache////////////// struct statements_cache::data { data() : size(0), max_size(0) { } struct entry; typedef std::map statements_type; typedef std::list lru_type; struct entry { ref_ptr stat; lru_type::iterator lru_ptr; }; statements_type statements; lru_type lru; size_t size; size_t max_size; void insert(ref_ptr st) { statements_type::iterator p; if((p=statements.find(st->sql_query()))!=statements.end()) { p->second.stat = st; lru.erase(p->second.lru_ptr); lru.push_front(p); p->second.lru_ptr = lru.begin(); } else { if(size > 0 && size >= max_size) { statements.erase(lru.back()); lru.pop_back(); size--; } std::pair ins = statements.insert(std::make_pair(st->sql_query(),entry())); p = ins.first; p->second.stat = st; lru.push_front(p); p->second.lru_ptr = lru.begin(); size ++; } } ref_ptr fetch(std::string const &query) { ref_ptr st; statements_type::iterator p = statements.find(query); if(p==statements.end()) return st; st=p->second.stat; lru.erase(p->second.lru_ptr); statements.erase(p); size --; return st; } void clear() { lru.clear(); statements.clear(); size=0; } }; // data statements_cache::statements_cache() { } void statements_cache::set_size(size_t n) { if(n!=0 && !active()) { d.reset(new data()); d->max_size = n; } } void statements_cache::put(statement *p_in) { if(!active()) { delete p_in; } ref_ptr p(p_in); p->reset(); d->insert(p); } ref_ptr statements_cache::fetch(std::string const &q) { if(!active()) return 0; return d->fetch(q); } void statements_cache::clear() { d->clear(); } statements_cache::~statements_cache() { } bool statements_cache::active() { return d.get()!=0; } ////////////// //connection ////////////// struct connection::data { typedef std::list conn_specific_type; conn_specific_type conn_specific; ~data() { for(conn_specific_type::iterator p=conn_specific.begin();p!=conn_specific.end();++p) delete *p; } }; ref_ptr connection::prepare(std::string const &q) { if(default_is_prepared_) return get_prepared_statement(q); else return get_statement(q); } ref_ptr connection::get_statement(std::string const &q) { ref_ptr st = create_statement(q); return st; } ref_ptr connection::get_prepared_statement(std::string const &q) { ref_ptr st; if(!cache_.active()) { st = prepare_statement(q); return st; } st = cache_.fetch(q); if(!st) st = prepare_statement(q); st->cache(&cache_); return st; } ref_ptr connection::get_prepared_uncached_statement(std::string const &q) { ref_ptr st = prepare_statement(q); return st; } connection::connection(connection_info const &info) : d(new connection::data), pool_(0), once_called_(0), recyclable_(1) { int cache_size = info.get("@stmt_cache_size",64); if(cache_size > 0) { cache_.set_size(cache_size); } std::string def_is_prep = info.get("@use_prepared","on"); if(def_is_prep == "on") default_is_prepared_ = 1; else if(def_is_prep == "off") default_is_prepared_ = 0; else throw cppdb_error("cppdb::backend::connection: @use_prepared should be either 'on' or 'off'"); } connection::~connection() { } bool connection::once_called() const { return once_called_; } void connection::once_called(bool v) { once_called_ = v; } connection_specific_data *connection::connection_specific_get(std::type_info const &type) const { for(data::conn_specific_type::const_iterator p=d->conn_specific.begin();p!=d->conn_specific.end();++p) { if(typeid(**p) == type) return *p; } return 0; } connection_specific_data *connection::connection_specific_release(std::type_info const &type) { for(data::conn_specific_type::iterator p=d->conn_specific.begin();p!=d->conn_specific.end();++p) { if(typeid(**p) == type) { connection_specific_data *ptr = *p; d->conn_specific.erase(p); return ptr; } } return 0; } void connection::connection_specific_reset(std::type_info const &type,connection_specific_data *ptr) { std::auto_ptr tmp(ptr); if(ptr && typeid(*ptr)!=type) { throw cppdb_error( std::string("cppdb::connection_specific::Inconsistent pointer type") + typeid(*ptr).name() + " and std::type_info reference:" + type.name() ); } for(data::conn_specific_type::iterator p=d->conn_specific.begin();p!=d->conn_specific.end();++p) { if(typeid(**p) == type) { delete *p; if(ptr) *p = tmp.release(); else d->conn_specific.erase(p); return; } } if(ptr) { d->conn_specific.push_back(0); d->conn_specific.back() = tmp.release(); } } ref_ptr connection::get_pool() { return pool_; } void connection::set_pool(ref_ptr p) { pool_ = p; } void connection::set_driver(ref_ptr p) { driver_ = p; } void connection::clear_cache() { cache_.clear(); } void connection::recyclable(bool opt) { recyclable_ = opt; } bool connection::recyclable() { return recyclable_; } void connection::dispose(connection *c) { if(!c) return; ref_ptr p = c->pool_; c->pool_ = 0; if(p && c->recyclable()) p->put(c); else { c->clear_cache(); // Make sure that driver would not be // destoryed destructor of connection exits ref_ptr driver = c->driver_; delete c; driver.reset(); } } connection *driver::connect(connection_info const &cs) { return open(cs); } bool loadable_driver::in_use() { return use_count() > 1; } connection *loadable_driver::connect(connection_info const &cs) { connection *c = open(cs); c->set_driver(ref_ptr(this)); return c; } static_driver::static_driver(connect_function_type c) : connect_(c) { } static_driver::~static_driver() { } bool static_driver::in_use() { return true; } backend::connection *static_driver::open(connection_info const &ci) { return connect_(ci); } } // backend struct connection_specific_data::data {}; connection_specific_data::connection_specific_data() { } connection_specific_data::~connection_specific_data() { } } // cppdb