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.
 
 
 
 
 

250 lines
6.7 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/driver_manager.h>
  20. #include <cppdb/shared_object.h>
  21. #include <cppdb/backend.h>
  22. #include <cppdb/utils.h>
  23. #include <cppdb/mutex.h>
  24. #include <vector>
  25. #include <list>
  26. extern "C" {
  27. #ifdef CPPDB_WITH_SQLITE3
  28. cppdb::backend::connection *cppdb_sqlite3_get_connection(cppdb::connection_info const &cs);
  29. #endif
  30. #ifdef CPPDB_WITH_PQ
  31. cppdb::backend::connection *cppdb_postgresql_get_connection(cppdb::connection_info const &cs);
  32. #endif
  33. #ifdef CPPDB_WITH_ODBC
  34. cppdb::backend::connection *cppdb_odbc_get_connection(cppdb::connection_info const &cs);
  35. #endif
  36. #ifdef CPPDB_WITH_MYSQL
  37. cppdb::backend::connection *cppdb_mysql_get_connection(cppdb::connection_info const &cs);
  38. #endif
  39. }
  40. namespace cppdb {
  41. typedef backend::static_driver::connect_function_type connect_function_type;
  42. class so_driver : public backend::loadable_driver {
  43. public:
  44. so_driver(std::string const &name,std::vector<std::string> const &so_list) :
  45. connect_(0)
  46. {
  47. std::string symbol_name = "cppdb_" + name + "_get_connection";
  48. for(unsigned i=0;i<so_list.size();i++) {
  49. so_ = shared_object::open(so_list[i]);
  50. if(so_) {
  51. so_->safe_resolve(symbol_name,connect_);
  52. break;
  53. }
  54. }
  55. if(!so_ || !connect_) {
  56. throw cppdb_error("cppdb::driver failed to load driver " + name + " - no module found");
  57. }
  58. }
  59. virtual backend::connection *open(connection_info const &ci)
  60. {
  61. return connect_(ci);
  62. }
  63. private:
  64. connect_function_type connect_;
  65. ref_ptr<shared_object> so_;
  66. };
  67. backend::connection *driver_manager::connect(std::string const &str)
  68. {
  69. connection_info conn(str);
  70. return connect(conn);
  71. }
  72. backend::connection *driver_manager::connect(connection_info const &conn)
  73. {
  74. ref_ptr<backend::driver> drv_ptr;
  75. drivers_type::iterator p;
  76. { // get driver
  77. mutex::guard lock(lock_);
  78. p=drivers_.find(conn.driver);
  79. if(p!=drivers_.end()) {
  80. drv_ptr = p->second;
  81. }
  82. else {
  83. drv_ptr = load_driver(conn);
  84. drivers_[conn.driver] = drv_ptr;
  85. }
  86. }
  87. return drv_ptr->connect(conn);
  88. }
  89. void driver_manager::collect_unused()
  90. {
  91. std::list<ref_ptr<backend::driver> > garbage;
  92. {
  93. mutex::guard lock(lock_);
  94. drivers_type::iterator p=drivers_.begin(),tmp;
  95. while(p!=drivers_.end()) {
  96. if(!p->second->in_use()) {
  97. garbage.push_back(p->second);
  98. tmp=p;
  99. ++p;
  100. drivers_.erase(tmp);
  101. }
  102. else {
  103. ++p;
  104. }
  105. }
  106. }
  107. garbage.clear();
  108. }
  109. #if defined(WIN32) || defined(_WIN32) || defined(__WIN32) || defined(__CYGWIN__)
  110. # define CPPDB_LIBRARY_SUFFIX_V1 "-" CPPDB_SOVERSION CPPDB_LIBRARY_SUFFIX
  111. # define CPPDB_LIBRARY_SUFFIX_V2 CPPDB_LIBRARY_SUFFIX
  112. #elif defined(__APPLE__)
  113. # define CPPDB_LIBRARY_SUFFIX_V1 "." CPPDB_SOVERSION CPPDB_LIBRARY_SUFFIX
  114. # define CPPDB_LIBRARY_SUFFIX_V2 CPPDB_LIBRARY_SUFFIX
  115. #else
  116. # define CPPDB_LIBRARY_SUFFIX_V1 CPPDB_LIBRARY_SUFFIX "." CPPDB_SOVERSION
  117. # define CPPDB_LIBRARY_SUFFIX_V2 CPPDB_LIBRARY_SUFFIX
  118. #endif
  119. #if (defined(WIN32) || defined(_WIN32) || defined(__WIN32)) && !defined(__CYGWIN__)
  120. # define PATH_SEPARATOR ';'
  121. #else
  122. # define PATH_SEPARATOR ':'
  123. #endif
  124. ref_ptr<backend::driver> driver_manager::load_driver(connection_info const &conn)
  125. {
  126. std::vector<std::string> so_names;
  127. std::string module;
  128. std::vector<std::string> search_paths = search_paths_;
  129. std::string mpath=conn.get("@modules_path");
  130. if(!mpath.empty()) {
  131. size_t sep = mpath.find(PATH_SEPARATOR);
  132. search_paths.push_back(mpath.substr(0,sep));
  133. while(sep<mpath.size()) {
  134. size_t next = mpath.find(PATH_SEPARATOR,sep+1);
  135. search_paths.push_back(mpath.substr(sep+1,next - sep+1));
  136. sep = next;
  137. }
  138. }
  139. if(!(module=conn.get("@module")).empty()) {
  140. so_names.push_back(module);
  141. }
  142. else {
  143. std::string so_name1 = CPPDB_LIBRARY_PREFIX "cppdb_" + conn.driver + CPPDB_LIBRARY_SUFFIX_V1;
  144. std::string so_name2 = CPPDB_LIBRARY_PREFIX "cppdb_" + conn.driver + CPPDB_LIBRARY_SUFFIX_V2;
  145. for(unsigned i=0;i<search_paths.size();i++) {
  146. so_names.push_back(search_paths[i]+"/" + so_name1);
  147. so_names.push_back(search_paths[i]+"/" + so_name2);
  148. }
  149. if(!no_default_directory_) {
  150. so_names.push_back(so_name1);
  151. so_names.push_back(so_name2);
  152. }
  153. }
  154. ref_ptr<backend::driver> drv=new so_driver(conn.driver,so_names);
  155. return drv;
  156. }
  157. void driver_manager::install_driver(std::string const &name,ref_ptr<backend::driver> drv)
  158. {
  159. if(!drv) {
  160. throw cppdb_error("cppdb::driver_manager::install_driver: Can't install empty driver");
  161. }
  162. mutex::guard lock(lock_);
  163. drivers_[name]=drv;
  164. }
  165. driver_manager::driver_manager() :
  166. no_default_directory_(false)
  167. {
  168. }
  169. // Borland erros on hidden destructors in classes without only static methods.
  170. #ifndef __BORLANDC__
  171. driver_manager::~driver_manager()
  172. {
  173. }
  174. #endif
  175. void driver_manager::add_search_path(std::string const &p)
  176. {
  177. mutex::guard l(lock_);
  178. search_paths_.push_back(p);
  179. }
  180. void driver_manager::clear_search_paths()
  181. {
  182. mutex::guard l(lock_);
  183. search_paths_.clear();
  184. }
  185. void driver_manager::use_default_search_path(bool v)
  186. {
  187. mutex::guard l(lock_);
  188. no_default_directory_ = !v;
  189. }
  190. driver_manager &driver_manager::instance()
  191. {
  192. static driver_manager instance;
  193. return instance;
  194. }
  195. namespace {
  196. struct initializer {
  197. initializer() {
  198. driver_manager::instance();
  199. #ifdef CPPDB_WITH_SQLITE3
  200. driver_manager::instance().install_driver(
  201. "sqlite3",new backend::static_driver(cppdb_sqlite3_get_connection)
  202. );
  203. #endif
  204. #ifdef CPPDB_WITH_ODBC
  205. driver_manager::instance().install_driver(
  206. "odbc",new backend::static_driver(cppdb_odbc_get_connection)
  207. );
  208. #endif
  209. #ifdef CPPDB_WITH_PQ
  210. driver_manager::instance().install_driver(
  211. "postgresql",new backend::static_driver(cppdb_postgresql_get_connection)
  212. );
  213. #endif
  214. #ifdef CPPDB_WITH_MYSQL
  215. driver_manager::instance().install_driver(
  216. "mysql",new backend::static_driver(cppdb_mysql_get_connection)
  217. );
  218. #endif
  219. }
  220. } init;
  221. }
  222. } // cppdb