aGrUM  0.20.2
a C++ library for (probabilistic) graphical models
DBInitializerFromSQL_tpl.h
Go to the documentation of this file.
1 /**
2  *
3  * Copyright 2005-2020 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__(
45  const std::string& connection_string,
46  long timeout) {
47  // analyze the connection string: either this is a user-defined connection
48  // string or this is an aGrUM-constructed one derived from a datasource,
49  // a login and a password
50  bool agrum_connection = (connection_string.size() > 4)
51  && (connection_string.compare(0, 4, "gum ") == 0);
52 
53  // perform the connection to the database
54  if (!agrum_connection) {
55  connection__.connect(connection_string, timeout);
56  } else {
57  std::size_t deb_index, end_index;
58  const std::string delimiter = "|";
59 
60  deb_index = connection_string.find(delimiter, 0);
61  if (deb_index == std::string::npos)
62  GUM_ERROR(DatabaseError,
63  "could not determine the datasource from string "
64  << connection_string);
65  deb_index += std::size_t(1);
66  end_index = connection_string.find(delimiter, deb_index);
67  if (end_index == std::string::npos)
68  GUM_ERROR(DatabaseError,
69  "could not determine the datasource from string "
70  << connection_string);
71  std::string dataSource
72  = connection_string.substr(deb_index, end_index - deb_index);
73 
74  deb_index = connection_string.find(delimiter, end_index + std::size_t(1));
75  if (deb_index == std::string::npos)
76  GUM_ERROR(DatabaseError,
77  "could not determine the database login from string "
78  << connection_string);
79  deb_index += std::size_t(1);
80  end_index = connection_string.find(delimiter, deb_index);
81  if (end_index == std::string::npos)
82  GUM_ERROR(DatabaseError,
83  "could not determine the database login from string "
84  << connection_string);
85  std::string login
86  = connection_string.substr(deb_index, end_index - deb_index);
87 
88  deb_index = connection_string.find(delimiter, end_index + std::size_t(1));
89  if (deb_index == std::string::npos)
90  GUM_ERROR(DatabaseError,
91  "could not determine the database password from string "
92  << connection_string);
93  deb_index += std::size_t(1);
94  end_index = connection_string.find(delimiter, deb_index);
95  if (end_index == std::string::npos)
96  GUM_ERROR(DatabaseError,
97  "could not determine the database password from string "
98  << connection_string);
99  std::string password
100  = connection_string.substr(deb_index, end_index - deb_index);
101 
102  connection__.connect(dataSource, login, password, timeout);
103  }
104  }
105 
106 
107  /// default constructor
108  template < template < typename > class ALLOC >
109  DBInitializerFromSQL< ALLOC >::DBInitializerFromSQL(
110  const std::string& connection_string,
111  const std::string& query,
112  long timeout,
113  const typename DBInitializerFromSQL< ALLOC >::allocator_type& alloc) :
114  IDBInitializer< ALLOC >(IDBInitializer< ALLOC >::InputType::STRING, alloc),
115  connection_string__(connection_string), query__(query), timeout__(timeout),
116  var_names__(alloc), parser__(alloc) {
117  // save the current locale because the connection to the database
118  // will change it
119  const std::string current_locale = std::setlocale(LC_NUMERIC, NULL);
120 
121  // perform the connection
122  connect__(connection_string, timeout);
123 
124  // restore the locale
125  std::setlocale(LC_NUMERIC, current_locale.c_str());
126 
127  // ask the parser to execute the query
128  parser__.useNewQuery(connection__, query__);
129 
130  // store the names of the columns into the intializer
131  const std::size_t nb_cols = std::size_t(parser__.nbColumns());
132  for (std::size_t i = 0; i < nb_cols; ++i) {
133  var_names__.push_back(parser__.columnName(i));
134  }
135 
136  GUM_CONSTRUCTOR(DBInitializerFromSQL);
137  }
138 
139 
140  /// default constructor
141  template < template < typename > class ALLOC >
142  DBInitializerFromSQL< ALLOC >::DBInitializerFromSQL(
143  const std::string& dataSource,
144  const std::string& login,
145  const std::string& password,
146  const std::string& query,
147  long timeout,
148  const typename DBInitializerFromSQL< ALLOC >::allocator_type& alloc) :
149  DBInitializerFromSQL< ALLOC >("gum datasource=|" + dataSource
150  + "|; login=|" + login + "|; password=|"
151  + password + "|",
152  query,
153  timeout,
154  alloc) {}
155 
156 
157  /// copy constructor with a given allocator
158  template < template < typename > class ALLOC >
159  DBInitializerFromSQL< ALLOC >::DBInitializerFromSQL(
160  const DBInitializerFromSQL< ALLOC >& from,
161  const typename DBInitializerFromSQL< ALLOC >::allocator_type& alloc) :
162  DBInitializerFromSQL< ALLOC >(from.connection_string__,
163  from.query__,
164  from.timeout__,
165  alloc) {}
166 
167 
168  /// copy constructor
169  template < template < typename > class ALLOC >
170  DBInitializerFromSQL< ALLOC >::DBInitializerFromSQL(
171  const DBInitializerFromSQL< ALLOC >& from) :
172  DBInitializerFromSQL< ALLOC >(from, from.getAllocator()) {}
173 
174 
175  /// move constructor with a given allocator
176  template < template < typename > class ALLOC >
177  DBInitializerFromSQL< ALLOC >::DBInitializerFromSQL(
178  DBInitializerFromSQL< ALLOC >&& from,
179  const typename DBInitializerFromSQL< ALLOC >::allocator_type& alloc) :
180  DBInitializerFromSQL< ALLOC >(from.connection_string__,
181  from.query__,
182  from.timeout__,
183  alloc) {}
184 
185  /// move constructor
186  template < template < typename > class ALLOC >
187  DBInitializerFromSQL< ALLOC >::DBInitializerFromSQL(
188  DBInitializerFromSQL< ALLOC >&& from) :
189  DBInitializerFromSQL< ALLOC >(std::move(from), from.getAllocator()) {}
190 
191 
192  /// virtual copy constructor with a given allocator
193  template < template < typename > class ALLOC >
194  DBInitializerFromSQL< ALLOC >* DBInitializerFromSQL< ALLOC >::clone(
195  const typename DBInitializerFromSQL< ALLOC >::allocator_type& alloc) const {
196  ALLOC< DBInitializerFromSQL< ALLOC > > allocator(alloc);
197  DBInitializerFromSQL< ALLOC >* new_initializer = allocator.allocate(1);
198  try {
199  allocator.construct(new_initializer, *this, alloc);
200  } catch (...) {
201  allocator.deallocate(new_initializer, 1);
202  throw;
203  }
204 
205  return new_initializer;
206  }
207 
208 
209  /// virtual copy constructor
210  template < template < typename > class ALLOC >
211  DBInitializerFromSQL< ALLOC >* DBInitializerFromSQL< ALLOC >::clone() const {
212  return clone(this->getAllocator());
213  }
214 
215 
216  /// destructor
217  template < template < typename > class ALLOC >
218  DBInitializerFromSQL< ALLOC >::~DBInitializerFromSQL() {
219  GUM_DESTRUCTOR(DBInitializerFromSQL);
220  }
221 
222 
223  /// copy operator
224  template < template < typename > class ALLOC >
225  DBInitializerFromSQL< ALLOC >& DBInitializerFromSQL< ALLOC >::operator=(
226  const DBInitializerFromSQL< ALLOC >& from) {
227  if (this != &from) {
228  IDBInitializer< ALLOC >::operator=(from);
229  // check if the connection parameters have changed
230  const bool connexion_changed
231  = (connection_string__ != from.connection_string__);
232 
233  // save the new connection parameters
234  connection_string__ = from.connection_string__;
235  query__ = from.query__;
236  timeout__ = from.timeout__;
237 
238  // recreate the connection if needed
239  if (connexion_changed) {
240  if (connection__.connected()) connection__.disconnect();
241  connect__(connection_string__, timeout__);
242  }
243 
244  // initiate the SQL parser
245  parser__.useNewQuery(connection__, query__);
246 
247  // store the names of the columns into the intializer
248  var_names__.clear();
249  const std::size_t nb_cols = std::size_t(parser__.nbColumns());
250  for (std::size_t i = 0; i < nb_cols; ++i) {
251  var_names__.push_back(parser__.columnName(i));
252  }
253  }
254 
255  return *this;
256  }
257 
258 
259  /// move operator
260  template < template < typename > class ALLOC >
261  DBInitializerFromSQL< ALLOC >& DBInitializerFromSQL< ALLOC >::operator=(
262  DBInitializerFromSQL< ALLOC >&& from) {
263  return operator=(from);
264  }
265 
266 
267  /// returns the names of the variables
268  template < template < typename > class ALLOC >
269  INLINE std::vector< std::string, ALLOC< std::string > >
270  DBInitializerFromSQL< ALLOC >::variableNames_() {
271  return var_names__;
272  }
273 
274 
275  /// returns the content of the current row using strings
276  template < template < typename > class ALLOC >
277  INLINE const std::vector< std::string, ALLOC< std::string > >&
278  DBInitializerFromSQL< ALLOC >::currentStringRow_() {
279  return parser__.current();
280  }
281 
282 
283  /// indicates whether there is a next row to read (and point on it)
284  template < template < typename > class ALLOC >
285  INLINE bool DBInitializerFromSQL< ALLOC >::nextRow_() {
286  return parser__.next();
287  }
288 
289 
290  } /* namespace learning */
291 
292 } /* namespace gum */
293 
294 # endif /* DOXYGEN_SHOULD_SKIP_THIS */
295 
296 #endif /* ODBC_ */