C++DB is the database layer that was designed to work with C++CMS. This customized version is used within Ye Ol' Pi Shack.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

381 lines
8.2 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (C) 2010-2011 Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com>
  4. //
  5. // Distributed under:
  6. //
  7. // the Boost Software License, Version 1.0.
  8. // (See accompanying file LICENSE_1_0.txt or copy at
  9. // http://www.boost.org/LICENSE_1_0.txt)
  10. //
  11. // or (at your opinion) under:
  12. //
  13. // The MIT License
  14. // (See accompanying file MIT.txt or a copy at
  15. // http://www.opensource.org/licenses/mit-license.php)
  16. //
  17. ///////////////////////////////////////////////////////////////////////////////
  18. #define CPPDB_SOURCE
  19. #include <cppdb/backend.h>
  20. #include <cppdb/utils.h>
  21. #include <cppdb/pool.h>
  22. #include <map>
  23. #include <list>
  24. namespace cppdb {
  25. namespace backend {
  26. //result
  27. struct result::data {};
  28. result::result() {}
  29. result::~result() {}
  30. //statement
  31. struct statement::data {};
  32. statement::statement() : cache_(0)
  33. {
  34. }
  35. statement::~statement()
  36. {
  37. }
  38. void statement::cache(statements_cache *c)
  39. {
  40. cache_ = c;
  41. }
  42. void statement::dispose(statement *p)
  43. {
  44. if(!p)
  45. return;
  46. statements_cache *cache = p->cache_;
  47. p->cache_ = 0;
  48. if(cache)
  49. cache->put(p);
  50. else
  51. delete p;
  52. }
  53. //statements cache//////////////
  54. struct statements_cache::data {
  55. data() :
  56. size(0),
  57. max_size(0)
  58. {
  59. }
  60. struct entry;
  61. typedef std::map<std::string,entry> statements_type;
  62. typedef std::list<statements_type::iterator> lru_type;
  63. struct entry {
  64. ref_ptr<statement> stat;
  65. lru_type::iterator lru_ptr;
  66. };
  67. statements_type statements;
  68. lru_type lru;
  69. size_t size;
  70. size_t max_size;
  71. void insert(ref_ptr<statement> st)
  72. {
  73. statements_type::iterator p;
  74. if((p=statements.find(st->sql_query()))!=statements.end()) {
  75. p->second.stat = st;
  76. lru.erase(p->second.lru_ptr);
  77. lru.push_front(p);
  78. p->second.lru_ptr = lru.begin();
  79. }
  80. else {
  81. if(size > 0 && size >= max_size) {
  82. statements.erase(lru.back());
  83. lru.pop_back();
  84. size--;
  85. }
  86. std::pair<statements_type::iterator,bool> ins =
  87. statements.insert(std::make_pair(st->sql_query(),entry()));
  88. p = ins.first;
  89. p->second.stat = st;
  90. lru.push_front(p);
  91. p->second.lru_ptr = lru.begin();
  92. size ++;
  93. }
  94. }
  95. ref_ptr<statement> fetch(std::string const &query)
  96. {
  97. ref_ptr<statement> st;
  98. statements_type::iterator p = statements.find(query);
  99. if(p==statements.end())
  100. return st;
  101. st=p->second.stat;
  102. lru.erase(p->second.lru_ptr);
  103. statements.erase(p);
  104. size --;
  105. return st;
  106. }
  107. void clear()
  108. {
  109. lru.clear();
  110. statements.clear();
  111. size=0;
  112. }
  113. }; // data
  114. statements_cache::statements_cache()
  115. {
  116. }
  117. void statements_cache::set_size(size_t n)
  118. {
  119. if(n!=0 && !active()) {
  120. d.reset(new data());
  121. d->max_size = n;
  122. }
  123. }
  124. void statements_cache::put(statement *p_in)
  125. {
  126. if(!active()) {
  127. delete p_in;
  128. }
  129. ref_ptr<statement> p(p_in);
  130. p->reset();
  131. d->insert(p);
  132. }
  133. ref_ptr<statement> statements_cache::fetch(std::string const &q)
  134. {
  135. if(!active())
  136. return 0;
  137. return d->fetch(q);
  138. }
  139. void statements_cache::clear()
  140. {
  141. d->clear();
  142. }
  143. statements_cache::~statements_cache()
  144. {
  145. }
  146. bool statements_cache::active()
  147. {
  148. return d.get()!=0;
  149. }
  150. //////////////
  151. //connection
  152. //////////////
  153. struct connection::data {
  154. typedef std::list<connection_specific_data *> conn_specific_type;
  155. conn_specific_type conn_specific;
  156. ~data()
  157. {
  158. for(conn_specific_type::iterator p=conn_specific.begin();p!=conn_specific.end();++p)
  159. delete *p;
  160. }
  161. };
  162. ref_ptr<statement> connection::prepare(std::string const &q)
  163. {
  164. if(default_is_prepared_)
  165. return get_prepared_statement(q);
  166. else
  167. return get_statement(q);
  168. }
  169. ref_ptr<statement> connection::get_statement(std::string const &q)
  170. {
  171. ref_ptr<statement> st = create_statement(q);
  172. return st;
  173. }
  174. ref_ptr<statement> connection::get_prepared_statement(std::string const &q)
  175. {
  176. ref_ptr<statement> st;
  177. if(!cache_.active()) {
  178. st = prepare_statement(q);
  179. return st;
  180. }
  181. st = cache_.fetch(q);
  182. if(!st)
  183. st = prepare_statement(q);
  184. st->cache(&cache_);
  185. return st;
  186. }
  187. ref_ptr<statement> connection::get_prepared_uncached_statement(std::string const &q)
  188. {
  189. ref_ptr<statement> st = prepare_statement(q);
  190. return st;
  191. }
  192. connection::connection(connection_info const &info) :
  193. d(new connection::data),
  194. pool_(0),
  195. once_called_(0),
  196. recyclable_(1)
  197. {
  198. int cache_size = info.get("@stmt_cache_size",64);
  199. if(cache_size > 0) {
  200. cache_.set_size(cache_size);
  201. }
  202. std::string def_is_prep = info.get("@use_prepared","on");
  203. if(def_is_prep == "on")
  204. default_is_prepared_ = 1;
  205. else if(def_is_prep == "off")
  206. default_is_prepared_ = 0;
  207. else
  208. throw cppdb_error("cppdb::backend::connection: @use_prepared should be either 'on' or 'off'");
  209. }
  210. connection::~connection()
  211. {
  212. }
  213. bool connection::once_called() const
  214. {
  215. return once_called_;
  216. }
  217. void connection::once_called(bool v)
  218. {
  219. once_called_ = v;
  220. }
  221. connection_specific_data *connection::connection_specific_get(std::type_info const &type) const
  222. {
  223. for(data::conn_specific_type::const_iterator p=d->conn_specific.begin();p!=d->conn_specific.end();++p) {
  224. if(typeid(**p) == type)
  225. return *p;
  226. }
  227. return 0;
  228. }
  229. connection_specific_data *connection::connection_specific_release(std::type_info const &type)
  230. {
  231. for(data::conn_specific_type::iterator p=d->conn_specific.begin();p!=d->conn_specific.end();++p) {
  232. if(typeid(**p) == type) {
  233. connection_specific_data *ptr = *p;
  234. d->conn_specific.erase(p);
  235. return ptr;
  236. }
  237. }
  238. return 0;
  239. }
  240. void connection::connection_specific_reset(std::type_info const &type,connection_specific_data *ptr)
  241. {
  242. std::auto_ptr<connection_specific_data> tmp(ptr);
  243. if(ptr && typeid(*ptr)!=type) {
  244. throw cppdb_error(
  245. std::string("cppdb::connection_specific::Inconsistent pointer type")
  246. + typeid(*ptr).name()
  247. + " and std::type_info reference:"
  248. + type.name()
  249. );
  250. }
  251. for(data::conn_specific_type::iterator p=d->conn_specific.begin();p!=d->conn_specific.end();++p) {
  252. if(typeid(**p) == type) {
  253. delete *p;
  254. if(ptr)
  255. *p = tmp.release();
  256. else
  257. d->conn_specific.erase(p);
  258. return;
  259. }
  260. }
  261. if(ptr) {
  262. d->conn_specific.push_back(0);
  263. d->conn_specific.back() = tmp.release();
  264. }
  265. }
  266. ref_ptr<pool> connection::get_pool()
  267. {
  268. return pool_;
  269. }
  270. void connection::set_pool(ref_ptr<pool> p)
  271. {
  272. pool_ = p;
  273. }
  274. void connection::set_driver(ref_ptr<loadable_driver> p)
  275. {
  276. driver_ = p;
  277. }
  278. void connection::clear_cache()
  279. {
  280. cache_.clear();
  281. }
  282. void connection::recyclable(bool opt)
  283. {
  284. recyclable_ = opt;
  285. }
  286. bool connection::recyclable()
  287. {
  288. return recyclable_;
  289. }
  290. void connection::dispose(connection *c)
  291. {
  292. if(!c)
  293. return;
  294. ref_ptr<pool> p = c->pool_;
  295. c->pool_ = 0;
  296. if(p && c->recyclable())
  297. p->put(c);
  298. else {
  299. c->clear_cache();
  300. // Make sure that driver would not be
  301. // destoryed destructor of connection exits
  302. ref_ptr<loadable_driver> driver = c->driver_;
  303. delete c;
  304. driver.reset();
  305. }
  306. }
  307. connection *driver::connect(connection_info const &cs)
  308. {
  309. return open(cs);
  310. }
  311. bool loadable_driver::in_use()
  312. {
  313. return use_count() > 1;
  314. }
  315. connection *loadable_driver::connect(connection_info const &cs)
  316. {
  317. connection *c = open(cs);
  318. c->set_driver(ref_ptr<loadable_driver>(this));
  319. return c;
  320. }
  321. static_driver::static_driver(connect_function_type c) : connect_(c)
  322. {
  323. }
  324. static_driver::~static_driver()
  325. {
  326. }
  327. bool static_driver::in_use()
  328. {
  329. return true;
  330. }
  331. backend::connection *static_driver::open(connection_info const &ci)
  332. {
  333. return connect_(ci);
  334. }
  335. } // backend
  336. struct connection_specific_data::data {};
  337. connection_specific_data::connection_specific_data()
  338. {
  339. }
  340. connection_specific_data::~connection_specific_data()
  341. {
  342. }
  343. } // cppdb