aGrUM  0.20.3
a C++ library for (probabilistic) graphical models
DBInitializerFromSQL_tpl.h
Go to the documentation of this file.
1 /**
2  *
3  * Copyright (c) 2005-2021 by Pierre-Henri WUILLEMIN(@LIP6) & Christophe GONZALES(@AMU)
4  * info_at_agrum_dot_org
5  *
6  * This library is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this library. If not, see <http://www.gnu.org/licenses/>.
18  *
19  */
20 
21 
22 /** @file
23  * @brief The class for initializing DatabaseTable and RawDatabaseTable
24  * instances from SQL databases
25  *
26  * @author Christophe GONZALES(@AMU) and Pierre-Henri WUILLEMIN(@LIP6)
27  */
28 
29 #ifdef ODBC_
30 # include <clocale>
31 
32 # ifndef DOXYGEN_SHOULD_SKIP_THIS
33 
34 # include <agrum/tools/database/DBInitializerFromSQL.h>
35 
36 
37 namespace gum {
38 
39  namespace learning {
40 
41 
42  /// perform a connection from a connection string
43  template < template < typename > class ALLOC >
44  void DBInitializerFromSQL< ALLOC >::_connect_(const std::string& connection_string,
45  long timeout) {
46  // analyze the connection string: either this is a user-defined connection
47  // string or this is an aGrUM-constructed one derived from a datasource,
48  // a login and a password
49  bool agrum_connection
50  = (connection_string.size() > 4) && (connection_string.compare(0, 4, "gum ") == 0);
51 
52  // perform the connection to the database
53  if (!agrum_connection) {
54  _connection_.connect(connection_string, timeout);
55  } else {
56  std::size_t deb_index, end_index;
57  const std::string delimiter = "|";
58 
59  deb_index = connection_string.find(delimiter, 0);
60  if (deb_index == std::string::npos)
61  GUM_ERROR(DatabaseError,
62  "could not determine the datasource from string " << connection_string);
63  deb_index += std::size_t(1);
64  end_index = connection_string.find(delimiter, deb_index);
65  if (end_index == std::string::npos)
66  GUM_ERROR(DatabaseError,
67  "could not determine the datasource from string " << connection_string);
68  std::string dataSource = connection_string.substr(deb_index, end_index - deb_index);
69 
70  deb_index = connection_string.find(delimiter, end_index + std::size_t(1));
71  if (deb_index == std::string::npos)
72  GUM_ERROR(DatabaseError,
73  "could not determine the database login from string " << connection_string);
74  deb_index += std::size_t(1);
75  end_index = connection_string.find(delimiter, deb_index);
76  if (end_index == std::string::npos)
77  GUM_ERROR(DatabaseError,
78  "could not determine the database login from string " << connection_string);
79  std::string login = connection_string.substr(deb_index, end_index - deb_index);
80 
81  deb_index = connection_string.find(delimiter, end_index + std::size_t(1));
82  if (deb_index == std::string::npos)
83  GUM_ERROR(DatabaseError,
84  "could not determine the database password from string " << connection_string);
85  deb_index += std::size_t(1);
86  end_index = connection_string.find(delimiter, deb_index);
87  if (end_index == std::string::npos)
88  GUM_ERROR(DatabaseError,
89  "could not determine the database password from string " << connection_string);
90  std::string password = connection_string.substr(deb_index, end_index - deb_index);
91 
92  _connection_.connect(dataSource, login, password, timeout);
93  }
94  }
95 
96 
97  /// default constructor
98  template < template < typename > class ALLOC >
99  DBInitializerFromSQL< ALLOC >::DBInitializerFromSQL(
100  const std::string& connection_string,
101  const std::string& query,
102  long timeout,
103  const typename DBInitializerFromSQL< ALLOC >::allocator_type& alloc) :
104  IDBInitializer< ALLOC >(IDBInitializer< ALLOC >::InputType::STRING, alloc),
105  _connection_string_(connection_string), _query_(query), _timeout_(timeout),
106  _var_names_(alloc), _parser_(alloc) {
107  // save the current locale because the connection to the database
108  // will change it
109  const std::string current_locale = std::setlocale(LC_NUMERIC, NULL);
110 
111  // perform the connection
112  _connect_(connection_string, timeout);
113 
114  // restore the locale
115  std::setlocale(LC_NUMERIC, current_locale.c_str());
116 
117  // ask the parser to execute the query
118  _parser_.useNewQuery(_connection_, _query_);
119 
120  // store the names of the columns into the intializer
121  const std::size_t nb_cols = std::size_t(_parser_.nbColumns());
122  for (std::size_t i = 0; i < nb_cols; ++i) {
123  _var_names_.push_back(_parser_.columnName(i));
124  }
125 
126  GUM_CONSTRUCTOR(DBInitializerFromSQL);
127  }
128 
129 
130  /// default constructor
131  template < template < typename > class ALLOC >
132  DBInitializerFromSQL< ALLOC >::DBInitializerFromSQL(
133  const std::string& dataSource,
134  const std::string& login,
135  const std::string& password,
136  const std::string& query,
137  long timeout,
138  const typename DBInitializerFromSQL< ALLOC >::allocator_type& alloc) :
139  DBInitializerFromSQL< ALLOC >("gum datasource=|" + dataSource + "|; login=|" + login
140  + "|; password=|" + password + "|",
141  query,
142  timeout,
143  alloc) {}
144 
145 
146  /// copy constructor with a given allocator
147  template < template < typename > class ALLOC >
148  DBInitializerFromSQL< ALLOC >::DBInitializerFromSQL(
149  const DBInitializerFromSQL< ALLOC >& from,
150  const typename DBInitializerFromSQL< ALLOC >::allocator_type& alloc) :
151  DBInitializerFromSQL< ALLOC >(from._connection_string_,
152  from._query_,
153  from._timeout_,
154  alloc) {}
155 
156 
157  /// copy constructor
158  template < template < typename > class ALLOC >
159  DBInitializerFromSQL< ALLOC >::DBInitializerFromSQL(const DBInitializerFromSQL< ALLOC >& from) :
160  DBInitializerFromSQL< ALLOC >(from, from.getAllocator()) {}
161 
162 
163  /// move constructor with a given allocator
164  template < template < typename > class ALLOC >
165  DBInitializerFromSQL< ALLOC >::DBInitializerFromSQL(
166  DBInitializerFromSQL< ALLOC >&& from,
167  const typename DBInitializerFromSQL< ALLOC >::allocator_type& alloc) :
168  DBInitializerFromSQL< ALLOC >(from._connection_string_,
169  from._query_,
170  from._timeout_,
171  alloc) {}
172 
173  /// move constructor
174  template < template < typename > class ALLOC >
175  DBInitializerFromSQL< ALLOC >::DBInitializerFromSQL(DBInitializerFromSQL< ALLOC >&& from) :
176  DBInitializerFromSQL< ALLOC >(std::move(from), from.getAllocator()) {}
177 
178 
179  /// virtual copy constructor with a given allocator
180  template < template < typename > class ALLOC >
181  DBInitializerFromSQL< ALLOC >* DBInitializerFromSQL< ALLOC >::clone(
182  const typename DBInitializerFromSQL< ALLOC >::allocator_type& alloc) const {
183  ALLOC< DBInitializerFromSQL< ALLOC > > allocator(alloc);
184  DBInitializerFromSQL< ALLOC >* new_initializer = allocator.allocate(1);
185  try {
186  allocator.construct(new_initializer, *this, alloc);
187  } catch (...) {
188  allocator.deallocate(new_initializer, 1);
189  throw;
190  }
191 
192  return new_initializer;
193  }
194 
195 
196  /// virtual copy constructor
197  template < template < typename > class ALLOC >
198  DBInitializerFromSQL< ALLOC >* DBInitializerFromSQL< ALLOC >::clone() const {
199  return clone(this->getAllocator());
200  }
201 
202 
203  /// destructor
204  template < template < typename > class ALLOC >
205  DBInitializerFromSQL< ALLOC >::~DBInitializerFromSQL() {
206  GUM_DESTRUCTOR(DBInitializerFromSQL);
207  }
208 
209 
210  /// copy operator
211  template < template < typename > class ALLOC >
212  DBInitializerFromSQL< ALLOC >&
213  DBInitializerFromSQL< ALLOC >::operator=(const DBInitializerFromSQL< ALLOC >& from) {
214  if (this != &from) {
215  IDBInitializer< ALLOC >::operator=(from);
216  // check if the connection parameters have changed
217  const bool connexion_changed = (_connection_string_ != from._connection_string_);
218 
219  // save the new connection parameters
220  _connection_string_ = from._connection_string_;
221  _query_ = from._query_;
222  _timeout_ = from._timeout_;
223 
224  // recreate the connection if needed
225  if (connexion_changed) {
226  if (_connection_.connected()) _connection_.disconnect();
227  _connect_(_connection_string_, _timeout_);
228  }
229 
230  // initiate the SQL parser
231  _parser_.useNewQuery(_connection_, _query_);
232 
233  // store the names of the columns into the intializer
234  _var_names_.clear();
235  const std::size_t nb_cols = std::size_t(_parser_.nbColumns());
236  for (std::size_t i = 0; i < nb_cols; ++i) {
237  _var_names_.push_back(_parser_.columnName(i));
238  }
239  }
240 
241  return *this;
242  }
243 
244 
245  /// move operator
246  template < template < typename > class ALLOC >
247  DBInitializerFromSQL< ALLOC >&
248  DBInitializerFromSQL< ALLOC >::operator=(DBInitializerFromSQL< ALLOC >&& from) {
249  return operator=(from);
250  }
251 
252 
253  /// returns the names of the variables
254  template < template < typename > class ALLOC >
255  INLINE std::vector< std::string, ALLOC< std::string > >
256  DBInitializerFromSQL< ALLOC >::variableNames_() {
257  return _var_names_;
258  }
259 
260 
261  /// returns the content of the current row using strings
262  template < template < typename > class ALLOC >
263  INLINE const std::vector< std::string, ALLOC< std::string > >&
264  DBInitializerFromSQL< ALLOC >::currentStringRow_() {
265  return _parser_.current();
266  }
267 
268 
269  /// indicates whether there is a next row to read (and point on it)
270  template < template < typename > class ALLOC >
271  INLINE bool DBInitializerFromSQL< ALLOC >::nextRow_() {
272  return _parser_.next();
273  }
274 
275 
276  } /* namespace learning */
277 
278 } /* namespace gum */
279 
280 # endif /* DOXYGEN_SHOULD_SKIP_THIS */
281 
282 #endif /* ODBC_ */